ServiceConnector
The ServiceConnector class follows the Singleton design pattern in order to avoid having multiple instances of the class in the same application, and provides the public methods a developer needs in order to perform authenticated and anonymous calls against java services deployed under Blaze DS. The ServiceConnector class can also perform a user’s login and logout, handle the queue for multiple calls following a FIFO style (the first element pushed into the queue is the first to be popped out) and recover a service using the name of the method to be called. The ServiceConnector class implements the IEventDispatcher interface and is therefore responsible for the notification of all the events fired during the server side interaction.
The dependencies of this class outside the flex framework are:
The RemoteObjectWrapperEvent? class is a custom Event that uses two public static constants in order to define the FAULT and RESULT type of the event. This class is responsible for propagating the data recovered from a remote method invocation and the current operation performed through the two public properties eventData and currentService.
public class RemoteObjectWrapperEvent extends Event {
//----------------------------------------------------------------------
// Class constants
//----------------------------------------------------------------------
public static const RESULT:String = "result";
public static const FAULT:String = "fault";
//----------------------------------------------------------------------
// Class properties
//----------------------------------------------------------------------
public var eventData:Object;
public var currentService:AbstractService;
//----------------------------------------------------------------------
// Constructor
//----------------------------------------------------------------------
public function RemoteObjectWrapperEvent(type:String, data:Object, service:AbstractService = null, bubbles:Boolean = false, cancelable:Boolean = false) {
super(type, bubbles, cancelable);
eventData = data;
currentService = service;
}
}
The IRemoteLoggedMethod is the interface implemented by the remote method called through the ServiceConnector class. Each method has to define the following accessor methods:
function set returnObject(value:Class):void; function get returnObject():Class; function set source(value:String):void; function get source():String; function set destination(value:String):void; function get destination():String; function set isList(value:Boolean):void; function get isList():Boolean;
The source and the destination are used to define the service to be called, the returnObject is the class type of the object / objects returned from the method invocation and the isList is used to understand whether the remote method returns a single value or an array of values. The MethodsQueue? class follows the Singleton design pattern and can store, remove and retry a queued method. When the application calls more than one method from different components, the queue of results is handled through this class and the results are sent to the appropriate component. Each item stored in the MethodQueue? class is an instance of the MethodsQueueElement? class that defines the method and abstract operation performed:
public function MethodsQueueElement(method:IRemoteLoggedMethod, operation:AbstractOperation){
_remoteMethod = method;
_abstractOperation = operation;
}
The ServiceConnector class definition contains a set of constants:
// Admitted channel services public static const SERVICE_REMOTEOBJECT:String = "mx.messaging.channels.AMFChannel"; public static const SERVICE_NETCONNECTION:String = "mx.messaging.channels.NetConnectionChannel"; public static const SERVICE_HTTPSERVICE:String = "mx.messaging.channels.HTTPChannel"; // Default ServiceConnector settings private const MAX_ALLOWED_CHANNELS:int = 1; // Service status inforrmations public static const SERVICE_RUNNING:String = "running"; public static const SERVICE_STARTING:String = "starting"; public static const SERVICE_READY:String = "ready"; public static const SERVICE_LOGGED_READY:String = "loggedReady"; public static const SERVICE_FAULT:String = "fault"; // Channel information protected const CHANNEL_ID:String = "xxxxx-amf"; protected const CHANNEL_CHARSET:String = "UTF-8";
The first set of constants is used by the class in the public method initializeConnector in order to determine, by means of composition, the kind of channel (AMFChannel, HTTPChannel, NetConnectionChannel?) that the class needs to use in order to communicate with the server
public function initializeConnector(url:String, serviceType:String, username:String = "", password:String = ""):void{
…………………………………………………………………
var channelClass:Class = getDefinitionByName(serviceType) as Class; channel = new channelClass(CHANNEL_ID, url);
…………………………………………………………………
}
The other constants define the status of the service and are used to dispatch an event with the current class status and to determine the ID of the channel opened and the encoding of the communication.
The class variables are self-explanatory and are used inside the public and private methods:
// Singleton private static var connector:ServiceConnector; // IEventDispatcher on which the events are sent private static var handler:IEventDispatcher; // EventDsipatcher instance used in order to implement IEventDispatcher private var eventDispatcher:EventDispatcher; // Channels fields private var channelSet:ChannelSet; private var channel:Channel; private var channelSetToken:AsyncToken; private var channelSetConnected:Boolean; private var defaultServiceConnected:Boolean; private var channelMessageAgent:MessageAgent; // Default call object private var defaultServiceRemoteObject:RemoteObject; // Default call configuration [Bindable] public static var defaultSource:String; [Bindable] public static var defaultDestination:String; // Methods queue private var methodsQueue:MethodsQueue; private var processingQueue:Boolean;
I’d like to draw your attention to the handler property used in the static method getConnector to define the object on which the events are fired by the ServiceConnector class
public static function getConnector(handler:IEventDispatcher = null):ServiceConnector{
…………………………………………………………………
}
Come back for a moment to the initializeConnector method: this is the one on which the communication with Blaze DS is initialized. If the method arguments username and password are not an empty string, authentication on the channel is performed and the responder for the login result is defined
public function initializeConnector(url:String, serviceType:String, username:String = "", password:String = ""):void{
…………………………………………………………………
// If username and password are provided
if(username != "" && password != ""){
// The channelSet is logged in
channelSetToken = channelSet.login(username, password, CHANNEL_CHARSET);
channelSetToken.addResponder(new AsyncResponder(onChannelReady, onChannelFault));
CursorManager.setBusyCursor();
}
…………………………………………………………………
}
If the login is performed correctly, the private methods onChannelReady or onChannelFault fire an event against the connector or against the handler if defined:
private function onChannelReady(e:ResultEvent, t:Object):void{
// The default channel is connected
channelSetConnected = true;
// The event is sent
if(ServiceConnector.handler){
ServiceConnector.handler.dispatchEvent(new Event(ServiceConnector.SERVICE_LOGGED_READY, true, true));
}else{
ServiceConnector.connector.dispatchEvent(new Event(ServiceConnector.SERVICE_LOGGED_READY, true, true));
}
CursorManager.removeBusyCursor();
}
In order to make remote calls with the ServiceConnector class there are two public methods:
- makeAnonymousCall
- makeLoggedCall
The first one requires the name of the service to be called and the optional arguments you may need in order to execute the method. The second one requires an object that implements the IRemoteLoggedMethod interface; both methods return an instance of the AbstractService? class.