ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Flash Remoting for J2EE Developers
Pages: 1, 2, 3

Create a Service Proxy on the Client

Just as the Business Delegate defines a single entry point for communication coming from Flash through Flash Remoting, a Service Proxy implemented in Flash provides a single place where server-side services are exposed to the Flash application. To an ActionScript developer, the Service Proxy looks like the service provided by your application. The Service Proxy provides a central place to:



  • Connect to the Flash Remoting gateway.
  • Connect to an application service.
  • Handle errors.
  • Perform other tasks before and/or after each Flash Remoting call.
  • Define the service API for the Flash developers
  • Handle changes in the service interface without affecting ActionScript client code.

A Service Proxy for the example in the previous section may resemble:

#include "NetServices.as"

// define service proxy
function Service(client) {
   this.client = client;
  
   // set global status to call this
   _global.System.server = this;
   _global.System.onStatus = function(status) {
      this.server.onStatus(status);
   }
}

// initialize the service
Service.prototype.init = function(gatewayUrl) {
   NetServices.setDefaultGatewayUrl(gatewayUrl);
   var gatewayConnection = NetServices.createGatewayConnection();
   this.service = gatewayConnection.getService("com.server.Service", this.client);
}

// define status handler
Service.prototype.onStatus = function(status) {
   this.client.onStatus(status);
}

// save user service
Service.prototype.saveUser = function(user) {
   this.service.saveUser(user);
}

and the ActionScript code to use it would be:

var service = new Service(this);
service.init("http://localhost/gateway");

Player = function() {}

var player = new Player();
player.name = "Joe";

service.savePlayer(player);

For many development teams, the Service Proxy will be the place where J2EE developers and Flash developers get together to agree on the service API. We have found that creating a stubbed-out Service Proxy with methods that return the same results for each call is a great way to define the integration point between Flash and a J2EE application. Both teams can work knowing that the integration is already well-defined.

Throw Exceptions to the Client

A Flash developer handles the results of a remoting call (e.g., service.doCall()) by implementing a doCall_onResult(result) callback method for service calls that execute successfully and a doCall_onStatus(error) callback method for exceptions thrown by the Remoting gateway. The Remoting gateway will throw exceptions when it encounters problems locating, loading, or creating the service class and the method to invoke on it, or when the service class itself throws an exception.

Given this behavior and my recommendation to use a service-oriented architecture with Flash Remoting, I recommend having the service implementation throw exceptions to be handled by the Flash MX client. In the simplest case, I recommend having all service methods simply throw Exception.

package com.server;

import flashgateway.io.ASObject;
import com.carbonfive.flash.ASTranslator;

public class Service {
   public ASObject getPlayer(String name) throws Exception {
      ...
   }
}

This allows the Flash MX client to inspect all exceptions thrown during the service invocation and determine what to do about it at runtime. This strategy is discussed in the Flash Remoting documentation at livedocs.macromedia.com/frdocs/Using_Flash_Remoting_MX/UseActionScript8.jsp.

The type field of the error object returned to getPlayer_onStatus() should provide the class name of the thrown exception, allowing us to implement the callback in Flash as:

getPlayer_onStatus = function (error) {
   if (error.type == "com.server.PlayerNotFoundException") {
      trace("unable to find the player");
   } else {
      trace("an unknown error occurred");
   }
}

This approach is limited in that inheritance is not taken into account. A thrown exception that extends com.server.PlayerNotFoundException is an instance of a com.server.PlayerNotFoundException in Java, but would not be handled as one in the above ActionScript code. The type field of the error object would be the class name of the thrown exception.

A more significant limitation is that Flash Remoting MX for J2EE does not actually send exceptions thrown by a service class to the XXX_onStatus callback method. Because the Flash Remoting gateway uses introspection to invoke the service methods, all exceptions thrown by service calls are nested within a java.lang.reflect.InvocationTargetException. Tracing the properties of an exception thrown by a service call results in output that looks something like:

 code:     SERVER.PROCESSING
 level:    error
 description: Service threw an exception during method invocation: null
 type:     java.lang.reflect.InvocationTargetException
 rootcause: 
 details:  java.lang.reflect.InvocationTargetException
           at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
           ...
           at flashgateway.Gateway.invoke(Gateway.java:184)
           ...
           at java.lang.Thread.run(Thread.java:536)
             Caused by: com.server.PlayerNotFoundException: 
             There is no player with name 'bob'
             at com.server.Roster.getPlayer(Roster.java:45)
           ...

We would like the nested com.server.PlayerNotFoundException to be used as exception upon which the error object is based, but it is not. This is a known issue in the implementation of Flash Remoting for J2EE. We have not come up with a great solution to this problem.

The best solution we have is to build a new error object in the Service Proxy that inspects the detail field of the error returned by Remoting to determine the correct values for description, type, and details before calling the onStatus method in the client. Unfortunately, the formatting of the stack trace as provided by the details field differs, depending on the JVM version being used on the server. Specifically, between Java 1.3 and Java 1.4, the way in which nested exceptions are printed in a stack trace is different. This makes inspecting the detail field brittle.

I feel strongly that having the XXX_onResult method handle successful Remoting calls and XXX_onStatus handle the failure cases is the best way to use Flash Remoting, but am not satisfied by with the presented workaround. I am interested in hearing other recommendations for dealing with this issue.

Think About Security

Because Flash Remoting uses introspection to locate, create, and invoke methods on any class in your application server, it is important to think about the security implications of using Flash Remoting in your application. Without any security restrictions, a Flash movie can invoke any method on any class that has a no-argument constructor or any object that can be found in JNDI. This is a serious security issue. Theoretically, a Flash movie could shut down the application server, if it knew the right object to access. At the very least, a Flash movie could create an ArrayList and fill it until the server runs out of memory.

There is very little information from Macromedia on this issue. Their recommended strategy for dealing with it is to modify the Java security policy file for your application server to grant or deny access to vulnerable packages in your server and application. Macromedia describes doing this for JRun 4.

Depending on your application server, you may need to edit the server's Java security policy file to grant or deny Flash Remoting access to specific classes. This Macromedia Designer and Developer Center article includes an example of editing the WebLogic security policy file to allow Flash Remoting to access classes in a specific package.

Implications

At Carbon Five, we have found that using Flash Remoting to create Flash interfaces to applications providing services through a Services-Oriented Architecture is a fun and clean way to work. It simplifies application development by removing tedious presentation-layer coding. It enables parallel development of the user experience and application functionality. It streamlines integration of work done by front-end and back-end development teams. Most importantly, it enables us to deliver powerful interfaces to the users of our enterprise Java applications.

As Web-based application development matures, we will see a proliferation of smart, stateful, feature-rich clients using Service-Oriented Applications to do the heavy hitting on the back end. Flash MX, Flash Remoting, and J2EE are powerful tools for creating these applications today.

Resources

Alon Salant is an owner and co-founder of Carbon Five and a co-author of Flash Remoting: The Definitive Guide.


Return to ONJava.com.