Flash Remoting for J2EE Developers
Pages: 1, 2, 3
Create a Business Delegate on the Server
To use a Service-Oriented Architecture with Flash Remoting, simply create an object in your web application to expose services to Flash. In the terminology of Sun J2EE Blueprints, this object is a Business Delegate. It presents a Flash-friendly interface, exposed through Flash Remoting, to invoke methods on EJBs or any other object in the application server.
Using a Business Delegate addresses the fact that when Flash Remoting
deserializes an AMF message into Java objects, it only knows a
limited set of Java objects to use in the deserialization. Any
developer-defined ActionScript object becomes a
flashgateway.io.ASObject in Java. Methods invokable through Flash
Remoting must use flashgateway.io.ASObject in their method
signatures. An ASObject represents an ActionScript object in Java.
It is basically a HashMap with case-insensitive keys and an extra
field named type.
ActionScript code that invokes savePlayer() on
com.server.Server (the Business Delegate) would look like:
#include "NetServices.as"
NetServices.setDefaultGatewayUrl("http://localhost/gateway");
var gatewayConnection = NetServices.createGatewayConnection();
var service = gatewayConnection.getService("com.server.Service", this);
Player = function() {}
var player = new Player();
player.name = "Joe";
service.savePlayer(player);
The corresponding Java Business Delegate class might be:
package com.server;
import flashgateway.io.ASObject;
public class Service {
public void savePlayer(ASObject asPlayer) {
Player player = new Player();
player.setName((String) asPlayer.get("name"));
Roster.savePlayer(player);
}
}
Using a Business Delegate in this manner provides a single place where Flash-Remoting-specific code is centralized. The Business Delegate is completely stateless and performs no work directly, delegating requests to other objects. For small applications, a single Business Delegate can expose all needed services to Flash. In larger application, it makes sense to create different Business Delegates for different service categories.
I recommend not implementing java.io.Serializable in the
Business Delegate. If an object accessed through Flash Remoting implements
java.io.Serializable, the Flash gateway will save an instance of
it in the user session to use for subsequent service invocations. Since the
Business Delegate is stateless and the Flash client is available to maintain
state, there is no reason to maintain an instance of the Business Delegate in
each user's session.
Map ActionScript Objects to Java Objects
As discussed above, when sending ActionScript objects to the server through
Flash Remoting service method calls, the Java service class will either receive
one of the known Java object types or an ASObject, if the object
type is not known. Converting these ASObjects to model objects in
the application server can be tedious and brittle:
package com.server;
import flashgateway.io.ASObject;
public class Service {
public void savePlayer(ASObject asPlayer) {
Player player = new Player();
player.setName((String) asPlayer.get("name"));
player.setEmail((String) asPlayer.get("email"));
player.setAge(((Integer) asPlayer.get("age")).intValue());
Roster.savePlayer(player);
}
}
At Carbon Five, we have created an open source library for addressing this issue. ASTranslator (ActionScript Translator) is hosted on SourceForge.net at carbonfive.sourceforge.net/astranslator/, is at its 1.0 release, and has been used in several production applications.
ASTranslator has two methods. ASTranslator.toActionScript()
translates Java objects in your application to ASObjects to send to Flash.
We'll discuss this method shortly. ASTranslator.fromActionScript()
translates ASObjects sent to Remoting service methods from Flash to Java
objects, as shown here:
import flashgateway.io.ASObject;
import com.carbonfive.flash.ASTranslator;
public class Service {
public void savePlayer(ASObject asPlayer) {
Player player = (Player) new ASTranslator().fromActionScript(asPlayer);
Roster.savePlayer(player);
}
}
Note that you must cast the result of this method call to the expected
return type. fromActionScript() can take any object as an
argument. It will translate any object and its composite objects as deeply as
possible, maintaining references as it goes.
In order for ASTranslator to know what Java class an ASObject
should become, you must register your ActionScript objects in Flash MX with the
Java class name to which the ActionScript object maps.
// Object definition
Player = function() {}
// Player in Flash maps to com.server.Player in Java
Object.registerClass("com.server.Player", Player);
The value with which you register the class in ActionScript--com.server.Player, in this case--is set to the value of the
ASObject type field by Flash Remoting when
deserializing the object from AMF. ASTranslator uses this field to know what
Java object to create from the ASObject.
Use ASTranslator to Return Objects to Flash
We created ASTranslator because of an issue we found with Flash Remoting MX
for J2EE. When returning Java objects from service calls to Flash, Flash
Remoting serializes Java objects according to their member variable state
(private, protected, or public), ignoring the publicly-declared property
accessors you'd expect it to use. If you have a Java class:
package com.server;
public class Player {
private String _name;
public getName() {
return _name;
}
}
and a service class:
package com.server;
public class Service {
public Player getPlayer(String name) {
Player player = Roster.getPlayer(name);
return player;
}
}
calling Service.getPlayer() from Flash MX would return an
ActionScript object with a property _name instead of
name. This removes one of the primary values of object-oriented
programming: encapsulation. ActionScript programmers in Flash can see
the internal state of Java objects on the server that even other Java objects
running on the server cannot see. This is bad. It can be really bad (both for
performance and security) if the internal state includes more information than
the object was designed to expose through its public interface.
ASTranslator uses JavaBean-style introspection to serialize Java objects for remoting. To use ASTranslator in the above example, we would change the Business Delegate Service class as follows.
package com.server;
import flashgateway.io.ASObject;
import com.carbonfive.flash.ASTranslator;
public class Service {
public ASObject getPlayer(String name) {
Player player = Roster.getPlayer(name);
ASObject aso = (ASObject) new ASTranslator().toActionScript(player);
return aso;
}
}
Flash will now receive an ActionScript object with the property
name.
Additionally, ASTranslator sets the type field of the ASObject
as the class name of the translated Java object. If the Flash developer has
registered an ActionScript class with the class name of the Java object to which it maps, the object Flash receives will be of the right object type in ActionScript
(a Player, in our example). If it has not been registered, the
object Flash received will just be an ActionScript Object. Using ASTranslator
in this way creates a tight binding between ActionScript objects in Flash and
Java objects in the application server. We have found this to be a very
effective way to use Flash Remoting.