Avg. Rating 2.7

Problem

Too much redundancy and overhead for declaring the remote methods in your flex application. I don't want to receive the same ResultEvent object, I want to receive my own objects I also want to centralize my error handling code for both Flex Error or explicit error return by the remote server

Solution

Using a singleton Service class to centralize your remote invocation. Using closure to execute your onResult function and return what you're interested in

Detailed explanation

Note: The below code is particularly implemented on the context of using BlazeDS and Spring Framework.

Here is my Service class

package service {
    import flash.display.Sprite;
    
    import mx.controls.Alert;
    import mx.core.Application;
    import mx.rpc.AbstractOperation;
    import mx.rpc.events.FaultEvent;
    import mx.rpc.events.ResultEvent;
    import mx.rpc.remoting.mxml.RemoteObject;
    import vo.MessageServiceResponse;
    import vo.ServiceResponse;
    
    public class Service {
    
        /**
         * Singleton
         */
        private var _this:Service = null;
        
        /**
         * Map operation->Function
         */
        private static var listeners:Dictionary = new Dictionary();
        
        /**
         * The remote object to do remote invocation
         */
        private var remoteObject:RemoteObject = new RemoteObject("myRemoteObject");

        public function Service() {
            new SingletonEnforcer();
        }
        
        public static function instance():Service {
            
            if (_this == null) {
                _this = new Service();
                // Initialize the remote object
                remoteObject.addEventListener(FaultEvent.FAULT, _this.onFault);
                remoteObject.showBusyCursor = true;
            }
            
            return _this;
        }
        
        /**
         * Wrapper for onResult function, to resolve any internal error that is returned by remoteObject
         */
        private function onResultWrapper(event:ResultEvent, onResult:Function):void {
            var serviceResponse:ServiceResponse = event.result as ServiceResponse;
            if (serviceResponse != null) {
                if (serviceResponse.status == -1) {
                    alertFault(serviceResponse.message);
                } else {
                    onResult(serviceResponse);
                }
            } else {
                alertFault("Invalid response object");
            }
        }
        
        /**
         * Mainly communication fault
         */
        private function onFault(event:FaultEvent = null):void {
            alertFault("Server communication failed");
        } 
        
        /**
         * Display error message
         */
        public function alertFault(msg:String):void {
            Alert.show(msg, "ERROR", 4, Sprite(Application.application), null, null);
        }
        
        /**
         * Sample remote method
         */
        public function helloWorld(onResult:Function):void {
            getOperation("helloWorld", function(resp:MessageServiceResponse):void {
                // return only what I want
                onResult(resp.msg);
            }).send();
        }
                 
        private function getOperation(methodName:String, onResult:Function):AbstractOperation {        
            var op:AbstractOperation = remoteObject.getOperation(methodName);
            if (op == null) throw new Error("No such remote method name: " + methodName);
            
            if (!op.hasEventListener(FaultEvent.FAULT)) {            
                op.addEventListener(FaultEvent.FAULT, onFault);
            }
            var listenerFunction:Function = listeners[methodName];
            // remove the old listener
            if (listenerFunction != null) {
                if (op.hasEventListener(ResultEvent.RESULT)) op.removeEventListener(ResultEvent.RESULT, listenerFunction);
                else delete listeners[methodName];
            }
            listenerFunction = function(event:ResultEvent):void {
                    onResultWrapper(event, onResult);                
            };            
            listeners[methodName] = listenerFunction;
            op.addEventListener(ResultEvent.RESULT, listenerFunction);                
            return op;
        }
    }
}
class SingletonEnforcer {}

The ServiceResponse class is as follow

package vo {
    [Bindable]
    [RemoteClass(alias="myapp.mypackage.ServiceResponse")]
    public class ServiceResponse  {
        public var status:int;
	public var message:String;
 	public function ServiceResponse() {}
    }
}

It's a good practice that any other service response must extend this class. E.g.: MessageServiceResponse, UsersServiceResponse, RolesServiceResponse ....

package vo {
    [Bindable]
    [RemoteClass(alias="myapp.mypackage.MessageServiceResponse")]
    public class MessageServiceResponse extends ServiceResponse {
        public var msg:String;
 	public function MessageServiceResponse() {}
    }
}

 

And this is how to call the method

Service.instance().helloWorld(service_onResult);

service_onResult is an user-defined function to process the results that are returned successfully

/**
 * Accept only what i need
 */
private function service_onResult(msg:String):void {
    Alert.show(msg);
}

Cons: One of the potential pitfalls is if the operation is invoked twice and simultaneously then it may cause unexpected result.

Report abuse

Related recipes