Joel's RemoteObjectFactory with Zend_Amf_Server?

derekdon's Avatar

derekdon

09 Jul, 2010 01:47 PM

Was using a bespoke class previously that used raw NetConnections to handle remoting with Zend_Amf_Server. This worked fine, but I wanted to try Joel's RemoteObjectFactory approach. However I keep getting an mx.rpc.Fault error telling me that the method I use to check service availability, ping, does not exist?
mx.rpc.Fault : faultString : Method "ping" does not exist.

The fault detail in mx.rpc.Fault shows the call stack, and I know the channel is connecting successfully. It's the NULL reference for "source" that might be the problem.

#0 ...lib\Zend\Amf\Server.php(550): Zend_Amf_Server->_dispatch('ping', Array, NULL)
#1 ...lib\Zend\Amf\Server.php(626): Zend_Amf_Server->_handle(Object(Zend_Amf_Request_Http))
#2 ...app\code\local\DerekDonnelly\Software\controllers\LicenseController.php(19): Zend_Amf_Server->handle()
...
#9 {main}

This is how the Zend_Amf_Server dispatch method looks...

/**
 * Loads a remote class or method and executes the function and returns
 * the result
 *
 * @param  string $method Is the method to execute
 * @param  mixed $param values for the method
 * @return mixed $response the result of executing the method
 * @throws Zend_Amf_Server_Exception
 */
protected function _dispatch($method, $params = null, $source = null)
{
    if($source) {
        if(($mapped = Zend_Amf_Parse_TypeLoader::getMappedClassName($source)) !== false) {
            $source = $mapped;
        }
    }
    $qualifiedName = empty($source) ? $method : $source.".".$method;

    if (!isset($this->_table[$qualifiedName])) {
        // if source is null a method that was not defined was called.
        if ($source) {
            $className = str_replace(".", "_", $source);
            if(class_exists($className, false) && !isset($this->_classAllowed[$className])) {
                #require_once 'Zend/Amf/Server/Exception.php';
                throw new Zend_Amf_Server_Exception('Can not call "' . $className . '" - use setClass()');
            }
            try {
                $this->getLoader()->load($className);
            } catch (Exception $e) {
                #require_once 'Zend/Amf/Server/Exception.php';
                throw new Zend_Amf_Server_Exception('Class "' . $className . '" does not exist: '.$e->getMessage());
            }
            // Add the new loaded class to the server.
            $this->setClass($className, $source);
        } else {
            #require_once 'Zend/Amf/Server/Exception.php';
            throw new Zend_Amf_Server_Exception('Method "' . $method . '" does not exist');
        }
    }

    $info = $this->_table[$qualifiedName];
    $argv = $info->getInvokeArguments();

    if (0 < count($argv)) {
        $params = array_merge($params, $argv);
    }

    if ($info instanceof Zend_Server_Reflection_Function) {
        $func = $info->getName();
        $this->_checkAcl(null, $func);
        $return = call_user_func_array($func, $params);
    } elseif ($info instanceof Zend_Server_Reflection_Method) {
        // Get class
        $class = $info->getDeclaringClass()->getName();
        if ('static' == $info->isStatic()) {
            // for some reason, invokeArgs() does not work the same as
            // invoke(), and expects the first argument to be an object.
            // So, using a callback if the method is static.
            $this->_checkAcl($class, $info->getName());
            $return = call_user_func_array(array($class, $info->getName()), $params);
        } else {
            // Object methods
            try {
                $object = $info->getDeclaringClass()->newInstance();
            } catch (Exception $e) {
                #require_once 'Zend/Amf/Server/Exception.php';
                throw new Zend_Amf_Server_Exception('Error instantiating class ' . $class . ' to invoke method ' . $info->getName() . ': '.$e->getMessage(), 621);
            }
            $this->_checkAcl($object, $info->getName());
            $return = $info->invokeArgs($object, $params);
        }
    } else {
        #require_once 'Zend/Amf/Server/Exception.php';
        throw new Zend_Amf_Server_Exception('Method missing implementation ' . get_class($info));
    }

    return $return;
}

This is how the Robotlegs setup looks...

(In ConfigureServicesCommand)

var gateway:String;
var ROFactory:RemoteObjectFactory;
...
var hasLicenseGateway:Boolean = FlashVarUtil.hasKey(LicenseService.FLASHVAR_GATEWAY);
if(hasLicenseGateway)
{
    gateway = FlashVarUtil.getValue(LicenseService.FLASHVAR_GATEWAY);
    ROFactory = new RemoteObjectFactory();
    ROFactory.addChannel("license-amf", gateway);
    injector.mapSingletonOf(ILicenseService, LicenseService);
    injector.mapValue(RemoteObject, ROFactory.getRemoteObjectForService(LicenseService.REMOTE_DESTINATION), LicenseService.REMOTE_DESTINATION);
}
else
{
    dispatchToModules(new LicenseServiceEvent(LicenseServiceEvent.NO_GATEWAY, LicenseServiceState.NO_GATEWAY));
    dispatchToModules(new LoggingEvent(LoggingEvent.MESSAGE, LicenseServiceState.NO_GATEWAY, LoggingEvent.TRACE));
    throw new Error(LicenseServiceState.NO_GATEWAY);
}
...

(In LoadResourcesCommand)

...
[Inject]
public var licenseService:ILicenseService;
..
var loadupMonitor:LoadupMonitor = new LoadupMonitor(eventDispatcher); // use context eventDispatcher
loadupMonitor.addResource(licenseService as IResource);
...

if(loadupMonitor.resourcesToLoadCount) 
    loadupMonitor.startResourceLoading();

load() calls on these services call a service.ping() method... but the ping fails and is handled by an _onPingFault method which dispatches ResourceEvent.RESOURCE_LOAD_FAILED.

(In AbstractAMFService)

protected function _ping():void
{
    var res:Responder = new Responder(_onPing, _onPingFault);
    var token:AsyncToken = service.ping();
    token.addResponder(res);
}

protected function _onPing(obj:*):void
{
    _sendLoadupEvent(ResourceEvent.RESOURCE_LOADED);
}

protected function _onPingFault(obj:*):void
{
    _sendLoadupEvent(ResourceEvent.RESOURCE_LOAD_FAILED);
}

Any ideas? This is driving me nuts!

Cheers,

Derek.

  1. 1 Posted by derekdon on 09 Jul, 2010 02:06 PM

    derekdon's Avatar

    Okay got it working...

    (In RemoteObjectFactory)

    ...
    public function getRemoteObjectForService(destination:String, concurrency:String = "multiple", showBusyCursor:Boolean = true, makeObjectsBindable:Boolean = true):RemoteObject
    {
    var service:RemoteObject = new RemoteObject(destination); // <-- destination here should match a destination name in the services-config.xml file... but I'm not using one.
    service.channelSet = this.channelSet;
    service.concurrency = concurrency;
    service.showBusyCursor = showBusyCursor;
    service.makeObjectsBindable = true; 
    service.source = destination; // <-- Added this line
    return service;
    }
    ...
    

    Do you guys think this is okay?

  2. Stray closed this discussion on 10 Feb, 2011 05:29 PM.

Comments are currently closed for this discussion. You can start a new one.

Keyboard shortcuts

Generic

? Show this help
ESC Blurs the current field

Comment Form

r Focus the comment reply box
^ + ↩ Submit the comment

You can use Command ⌘ instead of Control ^ on Mac