ONJava.com    
 Published on ONJava.com (http://www.onjava.com/)
 See this if you're having trouble printing code examples


Integrating Macromedia Flex with Java

by Mark Eagle
12/01/2004

Developing Internet applications with J2EE servers today usually consists of a presentation layer such as Struts, Tapestry, WebWork, or Spring. These tools generally follow Model-View-Controller (MVC) architecture and output HTML to a browser. The typical programming model for web development is to allow users to issue requests to an application server for each action in the application. For every action the user requests in the application, the server generates a new response that allows the user to submit a new request for more information. A browser typically is used to render the user interface to the user. However, browsers are thin clients with limitations that affect both development and the end-user experience.

Rich Internet Application (RIA) technologies are emerging to handle the limitations of the presentation layer. This article will take a pragmatic approach to understanding what a Rich Internet Application is and how to integrate an RIA into your architecture. It will also identify potential challenges when integrating with some popular open source frameworks.

Browser Limitations

So what is the problem with the current solutions? Maybe nothing is wrong if the application behaves correctly and allows the user to be productive. At one time or another, however, most web developers have complained about the limited capabilities when using a browser as a client. Here are some current problems when developing web applications using a browser:

These examples reiterate what most web developers already know: current toolsets have limitations. Developers have to find workaround solutions for some of these challenges when working through a browser. Developers and users are outgrowing the current capabilities of a thin client.

Rich Internet Applications

As a way to overcome some of the limitations defined above, consider Rich Internet Application development. An RIA gives the user a thick client with extended capabilities not available in browsers today. The most common RIA clients for J2EE are Java and Flash. When it comes to developing large, data-centric applications, RIAs are generally strong . Several solutions are available for developing Rich Internet Applications including JDNC (JDesktop Network Components), Laszlo, Thinlet, Java Web Start, and Macromedia Flex.

Rich Internet Applications can help address the problems described in the previous section. Here is a list of features that RIAs can provide:

Rich Internet Applications are fairly new technologies and introduce new concerns for those developing these types of applications. They are not a silver bullet solution for all applications, and depending on the implementation, can be experimental. However, if you think your application can benefit from a richer UI design, then an RIA might be for you. This article will now focus on one RIA solution, Macromedia Flex, and will discuss integration concerns.

Macromedia Flex

Macromedia Flex is a commercial presentation layer server that produces Rich Internet Applications. The Flash plug-in is required to be installed since this is the runtime environment for Flex applications. Most browsers already come equipped with the Flash plug-in, which helps justify using Flex for RIA. We will discuss what it means to use the Flash plug-in instead of a Java plug-in to communicate with a J2EE application server.

Developers use two core languages to create Flex applications. The first core language is MXML, the Macromedia Flex Markup Language, which includes a rich set of XML tags that allows developers to layout user interfaces. MXML can also be referred to as an XUL, or XML UI Language. These tags can be extended, unlike HTML, with additional capabilities that the application requires. Other MXML constructs allow you to call remote objects, store data returned in a model, and customize your own look and feel to MXML components.

The second core language for Flex development is ActionScript 2.0, which is an ECMA-compliant language similar to JavaScript. ActionScript elements are coded inside MXML pages. This is a strongly typed object-oriented language that should be familiar to Java developers. ActionScript also has robust event handling capabilities to allow the application to respond to dynamic user interactions. Because ActionScript runs inside the Flash plug-in, there is no need to rewrite several versions of the same code to support different browsers. This may not be the case with JavaScript code in a browser.

Both MXML and ActionScript are text-based languages and can be written in a simple text editor, an IDE tool such as Eclipse, or a more sophisticated tool like the Flex Builder from Macromedia. If you have experience with Java, XML, and a scripting language such as JavaScript, you will experience a small learning curve to Flex development.

The Flex server is responsible for translating the MXML and ActionScript components into Flash bytecode in the form of .SWF files. This process is similar to compiling JSP files into servlets by a Java web application container. The SWF file is executed on the client in the Flash runtime environment. The Flex server provides other services such as caching, concurrency, and handling remote object requests.

Introducing an RIA Framework to Your Existing Architecture

Now that you have an understanding of some RIA concepts, let's look at how to introduce an RIA into your existing architecture. This will include a discussion about how an RIA should behave in a layered application with an emphasis on decoupling. Furthermore, this discussion will highlight some potential pitfalls when developing with Flex in combination with some popular open source frameworks. These examples should help identify potential concerns when introducing an RIA within your architecture.

Let's begin by identifying a layered architecture. An example of this architecture might include the following layers: presentation layer, business delegate layer, business integration/service layer, and persistence layer. Here is a potential implementation for these respective layers:

Flex + Business Delegates + Spring Framework + Hibernate

The remainder of this article will concentrate on integration with each of these layers.

What About My Existing MVC Presentation Layer?

The presentation layer in a web application is designed to render a user interface for users, handle requests to backend services, and store data models of information. Developers who are new to RIA development have an initial natural tendency to want to reuse existing Struts components. However, products like Flex provide their own MVC architecture within them. Do you really need to maintain a presentation layer that consists of two MVC frameworks?

Let's look at a practical example of what happens when a Flex client makes a request through a Struts component to a Java service on the application server. A request made from the Flex client is sent to the Struts presentation framework before being received by higher layers in the application. Figure 1 shows an example of what not to do:

How not to integrate Flex and Struts with other Java components
Figure 1. How not to integrate Flex and Struts with other Java components.

Presentation frameworks such as Struts operate by transmitting HTML requests over HTTP. While it is possible to use the HTTP protocol with a Flex client, developers are encouraged to use remote object invocations over HTTP as opposed to posting HTTP requests for performance and object-oriented gains. Therefore, using these two presentation frameworks serially can provide a protocol mismatch. Unless you have a specific need to integrate Struts directly with an RIA, avoid this. Figure 2 shows a better solution when using Flex and Struts:

Introducing Flex and Struts in parallel with other Java components
Figure 2. Introducing Flex and Struts in parallel with other Java components.

Figure 2 suggests how to have separate Struts components and Flex components coexist. This satisfies a need when the application requires parallel RIA components and lighter-weight Struts-like components.

Developers should utilize the RIA client for what it was intended to do. This is definitely a shift in thinking for traditional web developers for whom the page request/response paradigm has been familiar. RIA products like Flex are not request- or response-driven like Struts. The RIA client is responsible for updating the UI without having to go back to the server in all instances.

Struts will not be the only thing you have to think about when using an RIA. It will take a while to become familiar with this type of technology. Following this learning curve, the biggest issue is integration of the Java server-side components. The bottom line is not to fight against the Rich Internet Application concepts.

Integrating Flex with the Business Layer

Now that we have addressed some presentation layer concerns let's discuss how other layers in our application architecture are affected. We have repositioned our presentation layer components; how do we integrate with our business layer?

Flex is an extensible RIA framework that provides several ways to communicate with your J2EE components. Flex offers HTTP communication, Web service communication, and Macromedia's proprietary AMF (ActionScript Messaging Format) gateway. The AMF gateway is a high-performance binary protocol that is synonymous with the Flash remoting protocol. Remote objects that are sent through the AMF gateway use the HTTP protocol. Flex offers MXML tags for each of these communication protocols, which significantly reduces the coding complexities. Furthermore, Flex allows you to invoke remote calls to your business tier in either an asynchronous or synchronous manner. By using an asynchronous remote call, the user has the ability to perform some action on the client and not be blocked as happens in traditional web applications. You can block the user from interacting with the UI using synchronous calls where appropriate.

Let's consider how Flex might be integrated with our business/integration layer. For this discussion we will use the Spring framework as our integration layer, but there are no restrictions to the integration layer you choose to implement. Let's assume you have your services in objects that operate in a Spring microcontainer, and you need to make remote object calls from Flex.

Since Flex knows nothing about Spring directly you might consider adding a separate, thin layer that acts as a delegate to your service components. Also, since Spring makes good use of Java interfaces it might be a good idea to build delegate objects that implement the same interfaces as your Spring services. These delegate objects will provide a decoupled gateway from Flex to the integration layer. The only thing you need to do is configure these objects in the Flex configuration file so they can interoperate with the AMF gateway. Here is an example of how a delegate object can be configured inside the server-side flex-config.xml Flex configuration file:


<object name="OrderBusinessDelegate">
   <source>
      com.meagle.flexro.FlexBusinessDelegate
   </source>
   <type>stateless-class</type>
   <use-custom-authentication>
      true
   </use-custom-authentication>
   <allow-unnamed-access>
      false
   </allow-unnamed-access>
   <roles>
      <role>OrderUser</role>
      <role>Admin</role>
   </roles>
</object>

At first glance you can see some additional capabilities of Flex such as configuring security and determining if the delegate object is stateful or stateless. When a remote object call is made from Flex to the integration layer it will be intercepted in a Flex delegate Java object. Delegates will be responsible for making the call to the integration, or service, layer (in our case, Spring). Resultant objects are sent back through the AMF gateway to the Flex client where they can be interpreted as ActionScript objects. Here is an example of the MXML code that will be used by the Flex client to make the remote call invocation and store results in a data model:


<mx:RemoteObject id="soapro"
   named="OrderBusinessDelegate"
   protocol="https"
   showBusyCursor="true">
   <mx:method name="saveNewOrder"
              result="saveNewOrder_result(event)"
              fault="faultHandler(event.fault)"/>
   <mx:method name="findOrderById"
              result="findOrderById_result(event)"
              fault="faultHandler(event.fault)"/>
   <mx:method name="updateOrder"
              result="updateOrder_result(event)"
              fault="faultHandler(event.fault)"/>
</mx:RemoteObject>

<mx:Model id="roModel" >
   <!-- The object graph for the Order object
           will be stored here -->
   <Order/>
</mx:Model>

Domain objects written in Java with ActionScript equivalents are passed back and forth through the AMF gateway. This process starts with a request from the Flex client through the AMF gateway to other layers in the application. A resultant object graph will be sent back through the other Java layers and eventually through the AMF gateway back to the client. Once the objects pass through the gateway they are converted back to ActionScript equivalents. Figure 3 shows what this looks like:

Overview of the AMF gateway
Figure 3. Overview of the AMF gateway.

One more note about passing objects back and forth between Flex and your Java tier: Since ActionScript 2.0 is an object-oriented language, it is possible to create ActionScript objects that have Java equivalents. This makes things easier and consistent when passing these objects back and forth over the AMF gateway. The ActionScript objects that are sent back to the Flash plug-in resemble data transfer objects (DTO). This is necessary because the Flash plug-in does not have any Java runtime components. Here is a familiar example of an Order domain object using Java:


package com.meagle.bo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * This object represents an order.
 * @hibernate.class table="TestOrder"
 * @author meagle
 */
public class Order {
   private int id;
   private double total;
   private int version;
   private String userName;
   private List orderLineItems = new ArrayList();

  // other fields and getter/setter methods not
  // shown to save space
}

Here is the ActionScript equivalent:


/**
 * Generated Action Script Object
 * for com.meagle.bo.Order. Do not edit!
 */
class com.meagle.bo.Order extends Object {

   public function Order(){}

   public static var regClass =
      Object.registerClass("com.meagle.bo.Order",
                            com.meagle.bo.Order);

   var id : Number;
   var orderLineItems : Array = new Array();
   var total : Number;
   var userName : String;
   var version : Number;

   // other fields and getter/setter methods not
   //shown to save space
}

You should notice a special method in the ActionScript Order object called Object.registerClass. This Object.registerClass method is used by the AMF gateway to know how to marshal and unmarshal objects between Java and ActionScript. This method registers the client-side ActionScript classes to the server-side Java classes. Since these objects are so similar it is understandable that you would not want to rewrite your domain objects in a slightly different format. Tools such as XDoclet and Ant allow you to generate these ActionScript objects automatically rather than hand code them. Now you can manipulate your Java objects as ActionScript equivalents in the Flex client.

Integrating Flex with the Persistence Layer

In applications that use a well defined decoupled architecture over the Web you do not communicate with your persistence layer directly. Using Flex should not change this architecture. The integration layer typically will communicate to your persistence layer in most cases. This is usually done using a Data Access Object (DAO) that is responsible for accessing data in a persistent store such as a database. The Flex client should not communicate directly to the persistence layer or even know about this layer because it forms a tight coupling. Let's use Hibernate as an example of our persistence layer.

There are a couple of pitfalls when using Hibernate and remote objects with Macromedia's AMF gateway. Hibernate users know you cannot access a lazy loaded collection that has not been initialized with a Hibernate Session object. Accessing a collection of dynamic proxy objects that has not been initialized will result in a runtime exception. The AMF gateway does not know how to specifically look for Hibernate dynamic proxy objects. A potential solution is an aspect-oriented programming (AOP) interceptor that can take the object that is about to be sent over the AMF gateway in the delegate object and remove the dynamic proxies. This process involves sending the resultant object through the interceptor class, which recursively looks for proxy objects that use reflection and that are not initialized. If any lazy proxy objects or collections are found then they are set to null. This is a cross-cutting concern that can be applied as an aspect using an AOP language such as JBoss AOP, AspectJ, Spring AOP, and so on. The AOP interceptor should be applied to objects in the business delegate layer. Figure 4 shows what this looks like in the application architecture:

Introducing AOP interceptors/advice to delegate objects before they pass through the AMF gateway
Figure 4. Introducing AOP interceptors/advice to delegate objects before they pass through the AMF gateway. This further reduces coupling from components in higher layers such as the integration layer, persistence layer, and so on.

The good news is the AMF gateway does know how to cache bidirectional objects so infinite recursion does not occur when transforming the objects. Therefore, you can keep these relationships intact when transmitting them back and forth over the AMF gateway. Also, because the objects are disconnected and made into copies, you will need to use the Session.saveOrUpdateCopy(Object object) method to persist results into the database. This method has to be used because the object that will be sent back through the AMF gateway will not have any enhanced bytecode information that Hibernate can take advantage of.

Authentication

Typical J2EE web applications have some kind of authentication scheme. This might be a container-based authentication scheme or it might be some custom code that authenticates the user. RIA servers such as Flex allow you to use custom authentication forms on the Flash client and container-based authentication in most application servers. Furthermore, if you look at the business delegate configuration in the example above you will notice that you can assign roles to these objects for security. There are even hooks in the AMF gateway that allow developers to grab the HttpRequest, HttpResponse, and ServletConfig objects to refine the security you want to use within a method of a delegate object.

Summary

This article introduced a number of concepts with the intention of exposing you to some of the tradeoffs and potential pitfalls when using a RIA such as Flex. Whether you use Flex or another RIA implementation, there are major considerations to take into account when architecting an application with this technology. When evaluating an RIA framework make sure it is extensible enough to meet the demands of the application. Furthermore, carefully evaluate integration issues that might need attention when transmitting objects between and RIA and a Java backend.

Resources

Mark Eagle is a Senior Software Engineer at MATRIX Resources, Inc. in Atlanta, GA.


Return to ONJava.com

Copyright © 2009 O'Reilly Media, Inc.