For no apparent reason whatsoever, connections got dropped in our Tomcat clustered environment running Blaze DS. The dreaded “Login required before authorization can proceed” message was popping up everywhere, requiring our users to reload the flex application and login again.
We never discovered why this happened and we might never will. However, we fabricated a solution that will rid our users’ experience of this dreaded popup message.
The solution involves a bit of dynamic method invocation and handling the actual fault string.
The solution
Every call to the RemoteObject is delegated to a class, which handles the execution. Included in the call is the actual ResultEvent handler function which you use to handle the results from the RemoteObject method call.
The delegate handles the call, and when the method results in a fault event, the faultString determines whether closing the ChannelSet and re-login is required.
The delegate handles the call, and when the method results in a fault event, the faultString determines whether closing the ChannelSet and re-login is required.
In short the class handles the following:
- · Executes the remote object method call using reflection
- · Listeners via the ItemResponder mechanism for a fault event and a result event
- · If the result event is triggered, the class’ work is done, and the delegated function is then handled
- · However, when a fault is detected, the class faults each fault string other than the Login required message.
- · The fault function disconnects the channels and reconnects again before the method is executed again.
public function getAddressses (contactId:int, handler:Function): void {
var token:AsyncToken = remoteObject.getAddresses(contactId);
token.addResponder(new ItemResponder(handler, faultHandler));
token.addResponder(new ItemResponder(handler, faultHandler));
}
Follows this pattern now.
public function getAddresses (contactId:int, handler:Function): void {
var connector:RemoteConnecter = new RemoteConnecter(remoteObject);
connector.method = “getAddresses”;
connector.parameters = [ contactId];
connection.handler = handler;
connector.method = “getAddresses”;
connector.parameters = [ contactId];
connection.handler = handler;
connector.invoke();
}
This is the connector class that handles the call
package scripts
{
import flash.utils.Proxy;
import flash.utils.flash_proxy;
import mx.collections.ItemResponder;
import mx.messaging.ChannelSet;
import mx.messaging.config.ServerConfig;
import mx.rpc.AsyncToken;
import mx.rpc.events.FaultEvent;
import mx.rpc.events.ResultEvent;
import mx.rpc.remoting.RemoteObject;
public class RemoteConnecter
{
private var _remote:RemoteObject;
public var method:String;
public var parameters:Array;
public var handler:Function;
private var _numberTries:int = 0;
public function RemoteConnecter ( remote:RemoteObject)
{
this._remote = remote;
}
public function invoke(): void {
_numberTries++;
var args:Array = [_method];
if (_params != null && _params.length != 0) {
args["push"].apply(args, parameters);
}
var token:* = Proxy(_remote).flash_proxy::callProperty.apply(_remote, args);
AsyncToken(token).addResponder(new ItemResponder(handler, faultFunction));
}
private function faultFunction(event:FaultEvent, token:Object = null): void {
if (event.fault.faultString.indexOf("Login required before ") != -1 &&
_numberTries < 3 ) {
var t:AsyncToken;
var cs:ChannelSet = ServerConfig.getChannelSet( _remote.destination);
if (cs.connected) {
t = cs.logout();
t.addResponder(new ItemResponder(logoutHandler, faultFunction));
return;
}
t = cs.login(“loginname”,"retry");
t.addResponder(new ItemResponder(reloadHandler, faultFunction));
} else {
BBWAlert.error(event.fault.faultString);
}
}
private function logoutHandler(event:ResultEvent, token:Object = null) : void {
var cs:ChannelSet = ServerConfig.getChannelSet( _remote.destination);
var t:AsyncToken = cs.login(“loginname”,"retry");
t.addResponder(new ItemResponder(reloadHandler, faultFunction));
}
private function reloadHandler(event:ResultEvent, token:Object = null) : void {
invoke();
}
}
}