Unknown User (mattlangston)

Introduction

We use the Spring Framework to configure our J2EE applications. Additionally, we use Macromedia's Flash Player 7 for part of our User Interface (UI). In order for the Flash application embedded in the web page to access our J2EE service layer we use the Flash Remoting capabilities built into the Flash Player to communicate with our application server (we use Tomcat 5).

This article discusses using the Spring Framework to power a Flash based distributed application. We introduce three Flash Remoting Java libraries (two commercial and one OpenSource). Next, we describe integrating one of these libraries, FlashORB, with the Spring Framework. The SpringHandler class, which we wrote to integrate Spring and FlashORB, is described next.

We use the SpringHandler class to demonstrate how trivial it is to expose an existing Spring configured J2EE service layer, and provide an example of doing so. We also explain some possible security concerns when exposing a Spring configured bean using Flash Remoting.

We conclude by proposing possible extensions of our SpringHandler class in terms of Spring integration, suggest the ramifications these extensions may have for Flash Remoting RPC vendors, and encourage these vendors to add more Spring support to their products.

The Flash Remoting Elevator Speech

Flash Remoting is a proprietery HTTP (or HTTPS) based binary protocol developed by Macromedia so that their ubiquitous Flash Player can communicate with J2EE and .NET servers. It is a stateless request/response protocol just like your web browser uses, except that it is based on passing Action Message Format (AMF) packets back and forth instead of text and images. Flash Remoting is not the only RPC option for distributed Flash clients, but it is the most efficient. The two other RPC choices are SOAP based XML WebServices and good old HTTP query strings.

In order to use Flash Remoting to communicate with Flash clients, a J2EE server needs a Flash Remoting RPC stack. This RPC stack is simply a Java servlet that listens for AMF service requests from Flash clients, somehow locates and invokes the service, and sends the result back to the client serialized in AMF packets. It used to be that the only Flash Remoting RPC stack available was Macromedia's Flash Remoting MX product. However, in our research we found at least two other choices. One is an OpenSource project called OpenAMF, the other is a commercial product called FlashORB.

Choosing a Flash Remoting Servlet

In choosing a Flash Remoting RPC stack, we were unhappy with Macromedia's rather expensive and insecure Flash Remoting MX product, so we initially turned to OpenAMF, an excellent OpenSource project that fully supports the Flash Remoting AMF protocol. OpenAMF is infinately more configureable and secure than Flash Remoting MX, and supports Spring out of the box.

Also available is FlashORB, a commercial product about the same price as Macromedia's Flash Remoting MX product, but also much more configureable and secure. Both OpenAMF and FlashORB are easy to set up and use, and have a similar feature set. OpenAMF seemed more streamlined and "Spring like" in its architecture, and offered better and more fine grained configuration options than FlashORB. On the other hand, FlashORB had much better security features and monitoring capabilities.

Unfortunately, one of the features currently lacking in FlashORB is support for Spring. Our J2EE service layer, built on top of Spring, was already designed, implemented and tested. OpenAMF showed us that it was trivial to hook our Flash clients into our Spring service layer, and it seemed like we should be able to do this with FlashORB as well.

In fact, due to the flexible and well designed architecture of both Spring and FlashORB, it was relatively easy (about an hours worth of work) to tie the two together using just one class called SpringHandler which has just four methods.

The SpringHandler Class

FlashORB provides a flexible architecture to expose Java and .NET based services to Flash clients through its flashorb-config.xml configuration file. POJO's and EJB's, as well as Axis and GLUE web services, are all supported out of the box. However, there is also a FlashORB API developers can use to expose servies that are not explicitly supported, which is what we used to expose Spring Beans to Flash clients.

The SpringHandler class implements two FlashORB interfaces, flashorb.handler.IInspectionHandler and flashorb.handler.IInvocationHandler. The IInspectionHandler interface allows the Service Browser in Flash MX 2004 Professional to query the Spring Bean factory. The IInvocationHandler interface is what the ActionScript in the Flash client uses to call the service.

If you've already configured your J2EE service layer using Spring, simply install FlashORB and do the following to instantly expose your service layer to Flash clients:

  1. Compile our SpringHandler class and drop into your classpath.
  2. Add these two lines to your flashorb-config.xml:
<serviceInspector>edu.stanford.slac.glast.flash.flashorb.SpringHandler</serviceInspector>
<serviceInvoker>edu.stanford.slac.glast.flash.flashorb.SpringHandler</serviceInvoker>

Then bam, all of your Spring configured service layer beans are instantly accessible to your flash client. To get an idea of just what's in your Spring Bean factory, use the Service Browser in Flash MX 2004 Professional.

Visually Inspecting your Spring Bean Factory

We found the Service Browser, which is part of Flash MX 2004 Professional, very helpful in testing that our Spring configured J2EE service layer was being properly exposed to Flash clients by FlashORB. It not only verified that our Spring Bean factory was accessible to Flash clients (if the Flash authoring tool can see your Spring Beans, then so can your Flash clients), but it also gave us a visual que as to just what was in our Spring Bean factory.

The follwing figure shows where to find the Service Browser in Flash MX 2004 Professional.


Location of the Service Browser in Flash MX 2004 Professional


To our surprise, there were some Spring artifacts from the bean factory that were automatically exposed that shouldn't have been. This is the same problem that makes Flash Remoting MX so insecure (unless you go to extraordinaly efforts to lock it down). The following figure shows the content of our Spring Bean factory:


The Contents of our Spring Configured J2EE Service Layer


The boxes labeled Spring Artifacts are the parts of our Spring configured JavaBean service layer that we didn't intend to expose to Flash clients. These artifacts are dynamically added by Spring at run time, and provide all of the extra functionality that is why we use Spring in the first place. I don't know that these artifacts pose a security threat to my application server, but I don't know that they don't. In any event, they shouldn't be there.

FlashORB allowed me to hide these Spring artifacts using a combination of <secure-resources> and <access-constraints> elements configured in flashorb-config.xml. See the Security Section of the FlashORB manual for details. OpenAMF offers similiar capabilities through the <service> stanzas of its openamf-config.xml configuration file.

SpringHandler.java

To gain access to the Spring WebApplicationContext, one needs access to the ServletContext. FlashORB supplies the flashorb.util.ThreadContext class which provides access to the HttpSession, which indirectly allows access to the ServletContext, but it would be nice if flashorb.util.ThreadContext also provided a static flashorb.util.ThreadContext.servletContext member for easier integration with Spring. If this existed, all of the functionality in SpringHandler.getSpringWebApplicationContext() could be moved to the SpringHandler constructor.

This is the full listing of the SpringHandler class, which you can also download .

SpringHandler.java
package edu.stanford.slac.glast.flash.flashorb;

import javax.servlet.http.HttpSession;

import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.context.support.WebApplicationContextUtils;

import flashorb.exceptions.ServiceException;
import flashorb.handler.IInspectionHandler;
import flashorb.handler.IInvocationHandler;
import flashorb.inspection.ServiceDescriptor;
import flashorb.util.ClassInspector;
import flashorb.util.Invocation;
import flashorb.util.Value;

/*
 * Copyright 2004 Matthew D. Langston.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/**
 * FlashORB Inspection and Invocation Handler for the Spring Framework.
 * 
 * @author Matthew D. Langston <langston@SLAC.Stanford.EDU>
 */
public class SpringHandler implements IInvocationHandler, IInspectionHandler {

    private WebApplicationContext springWebApplicationContext;

    public WebApplicationContext getSpringWebApplicationContext() {
        if (springWebApplicationContext == null) {
            HttpSession session = (HttpSession) flashorb.util.ThreadContext.httpSession
                    .get();
            springWebApplicationContext = WebApplicationContextUtils
                    .getWebApplicationContext(session.getServletContext());
        }

        return springWebApplicationContext;
    }

    public SpringHandler() {
    }

    public ServiceDescriptor inspect(String targetObject)
            throws ServiceException {
        try {
            WebApplicationContext springContext = getSpringWebApplicationContext();
            if (!springContext.containsBean(targetObject)) {
                return null;
            }
            Object springBean = springContext.getBean(targetObject);
            return ClassInspector.inspectClass(springBean.getClass());
        } catch (Exception e) {
            String message = "error inspecting Spring Bean " + targetObject;
            System.out.println(message);
            e.printStackTrace();
            throw new ServiceException(message, e);
        }
    }

    public Value invoke(String targetObject, String function, Object[] arguments)
            throws Exception {
        try {
            WebApplicationContext springContext = getSpringWebApplicationContext();
            if (!springContext.containsBean(targetObject)) {
                return null;
            }
            Object springBean = springContext.getBean(targetObject);
            return new Value(Invocation.invoke(springBean, function, arguments));
        } catch (Exception e) {
            String message = "error invoking method " + function
                    + " on the Spring Bean " + targetObject;
            System.out.println(message);
            e.printStackTrace();
            throw new ServiceException(message, e);
        }
    }

    public String getName() {
        return "Spring Framework Bean Inspector and Invoker";
    }
}

References


1. Joe Orbman, FlashORB's Chief Architect, showed in his blog how he could shut down a Flash Remoting server in just three lines of code:

Shutting Down a Flash Remoting Site
var conx  = NetServices.createGatewayConnection("http://remoting-server-to-shut-down");
var service = conx.getService("java.lang.System", this);
service.exit( -1 );


2. The OpenAMF developers should probably move SpringBeanInvoker from the org.openamf.optional.invoker package to org.openamf.invoker, as it has worked fine for us and appears very stable.

To use Spring with OpenAMF, simply add this stanza to your openamf-config.xml file.

<invoker>
	<name>SpringBeanInvoker</name>
	<class>org.openamf.invoker.SpringBeanInvoker</class>
</invoker>

Then, assuming you have used Spring to wire up a service called gino, you would

<service>
	<name>gino</name>
	<!-- For Spring, the service-location is the bean name. -->
	<service-location>gino</service-location>
	<invoker-ref>SpringBeanInvoker</invoker-ref>

	<method>
		<name>getRunSummaryList</name>
		<parameter>
			<type>*</type>
		</parameter>
		<result-filter>
			<class>org.openamf.filter.BeanListToRecordSet</class>
		</result-filter>
	</method>

	...

</service>

Conclusion


3. Simple Instructions to set up FlashORB.

  1. Obtain a FlashORB trial license from Midnight Coders, LLC. The license file, which will be emailed to you and is called flashorb-license.xml, must be copied to your web application's classpath (for example, this is typically WEB-INF/classes/).
  2. Download flashorb1.0.1.zip and unzip it.
  3. Copy the following files from the distribution, which are located in flashorb1.0.1/flashorb/webapp/WEB-INF/classes/, to your web applications classpath:
    1. flashorb-config.xml
    2. flashorb-acl.xml
  4. Copy flashorb1.0.1/flashorb/flashorb.jar to your web application's WEB-INF/lib, or whatever is appropriate for your application server.
  5. Add the FlashORB adjustments to your web.xml file.
  6. Optionally edit the flashorb-config.xml file.
  • No labels