7.7 Invoking Service Methods

Once the gateway has successfully located the service identified by the Flash client, it tries to invoke the service method called by the client. The gateway must first get a reference to an instance of the service. It uses introspection to locate the service method and then call it.

For each service type, the gateway uses a different technique to get a reference to an instance of the service. Regardless of the service type, once the gateway has a reference to the service it invokes the service method in the same manner. It looks for a method that has the same case-insensitive name and parameters that match the converted parameters from ActionScript. If it can not find a matching service method, the gateway throws a java.lang.Exception with the message "Service [service name] does not have a method [method name] that matches the name and parameters provided." Refer to Section 7.5.1 earlier in this chapter for an example of how to remedy this error.

If the gateway finds the service method, it invokes the method using introspection and returns the result to the Flash client after converting the Java objects in the result to ActionScript objects. If the result implements flashgateway.sql.PageableResultSet, the gateway saves a reference to the result in the user session so that the Flash client can use the paging features of the RecordSet component.

7.7.1 Invoking Service Methods on JavaBeans

For JavaBean services, the gateway first looks to see if an instance of the service is already in the user session. It looks for the JavaBean instance using the service class name as the attribute name in the user session. If the service is not already there, the gateway creates a new instance using Class.forName("JavaBeanService").newInstance( ) and the service identifier, "JavaBeanService" in this example, as the name of the class to instantiate and puts the new instance in the user session.

7.7.2 Invoking Service Methods on Java Classes

To get a reference to a Java class service method, the Remoting gateway simply creates a new instance of the Java class using Class.forName("JavaClassService").newInstance( ) and the service identifier, "JavaClassService" in this example, as the name of the class to instantiate.

7.7.3 Invoking Service Methods on EJBs

The Remoting gateway gets a reference to an EJB service by looking it up in JNDI using the service identifier as the EJB name to look up.

In addition to the standard handling of method invocation, if the result of a method call on an EJB service implements javax.ejb.EJBObject or javax.ejb.EJBLocalObject, the gateway stores a reference to it in the user session and returns the EJB to the Flash client, wrapped as a NetServices object that may then be used to call methods directly on the EJB. This process is shown in Example 7-1.

7.7.4 Invoking Service Methods on Servlets

As described earlier under Section 7.6.2, the gateway obtains a reference to a servlet service by first locating a ServletContext with the same name as the service identifier provided by Flash and then looking for a servlet in that context with a name that matches the method name called by Flash. As with other service types, the gateway throws a flashgateway.adapter.NoSuchServiceException if it cannot find the servlet; however, the error message identifies the web application name and the service identifier it cannot find, not the servlet name.

The gateway puts the method parameters in the FLASH.PARAMS attribute of the request property and forwards the request and response to the servlet. The servlet's service( ) method is invoked as a result of this forwarding action, not as a result of using introspection.

When the servlet's service( ) method completes, the gateway returns to Flash the object that the servlet has set in the FLASH.RESULT attribute of the request property. Refer to the discussion following Example 7-3 under Section 7.4.4.

7.7.5 Invoking Service Methods on MBeans

When running in JRun, the Remoting gateway invokes a service method on a JMX MBean using the standard JMX APIs. It creates a standard JMX server invocation from the service identifier and method parameters provided by the Flash client.

7.7.6 Exceptions

Regardless of the service type, if a service method call throws an exception, the Remoting gateway returns the exception of type java.lang.reflect.InvocationTargetException to the Flash client. This example shows a service method, throwException( ), that always throws an exception of type java.lang.Exception:

public class JavaClassService {
  public void throwException( )
    throws Exception
    throw new Exception("This is a service exception.");

The exception is returned to the onStatus( ) method of the ActionScript responder object as an error object. See Chapter 4 for information on handling errors returned from Flash Remoting. Tracing the contents of the error returned to the Flash client when it calls the throwException( ) service method, we get:

 level:       error
 type:        java.lang.reflect.InvocationTargetException
 description: Service threw an exception during method invocation: null
 details:     java.lang.reflect.InvocationTargetException
   at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   at flashgateway.Gateway.invoke(Gateway.java:194)
   at flashgateway.controller.GatewayServlet.service(GatewayServlet.java:56)
   at java.lang.Thread.run(Thread.java:536)
Caused by: java.lang.Exception: This is a service exception.
   at com.oreilly.frdg.java.service.JavaClassService.throwException
   ...           ...

Note that the preceding listing shows the exception type property as the string "java.lang.reflect.InvocationTargetException" and not "java.lang.Exception". This discrepancy is an oversight in the design of the Remoting gateway. The InvocationTargetException is created when a method called using introspection throws an exception. The InvocationTargetException wraps the source exception (in this case, java.lang.Exception) and makes it available in Java via InvocationTargetException.getTargetException( ). We can see the nested target exception under Caused by: in the details of the error. However the type, description, and details fields of the error object are populated by the properties of the InvocationTargetException, not the exception thrown by the service method. The Remoting gateway should return an error object to Flash populated by the target exception, not by the InvocationTargetException.

This behavior is unfortunate. Throwing exceptions is a well-established way of handling exceptional cases in Java applications. Code that is using an object that can throw exceptions can inspect the exception to determine what went wrong and what to do about it.

A Flash client could make a decision based on the type of exception if it were passed the real exception thrown by the service method as an error object. If the type field were the class name of the exception thrown by the service (in this case, java.lang.Exception), not an InvocationTargetException, the Flash client could perform its own error handling based on the type of exception.

The Remoting gateway's behavior of throwing an InvocationTargetException when a service method throws an exception doesn't pertain when using servlet services. Since servlet services are invoked using standard servlet dispatching and not introspection, exceptions thrown by servlet services are returned directly to the Flash client.

    Part III: Advanced Flash Remoting