Building a LiveCycle Data Service Application with Spring and Hibernate

In order to gain a better understanding of Flex and data services with Java, I decided to build a simple order management application that demonstrates a number of capabilities. The application will be responsible for managing orders and the items in them. The UI itself is extremely simplistic and the use case for the application is very limited:

Flex Order Manager UI

For the rest of this article, I am going to focus primarily on the data services aspect of the application and how it is wired up from end-to-end. I do plan to cover other aspects of my sample application, particularly my lessons learned around Hibernate, in future posts though.

Download Sample Code (zip)

Data Model

To get started, we’ll take a quick look at the data model for the application. There are three data elements that we will deal with: (1) orders, (2) products, and (3) line items. An order contains one or more line items, each of which is associated with a single order.

Data Model Diagram

Data Service Application

When I initially started learning about Flex and data services, I found it difficult to understand exactly how LCDS integrated with my application. In the end LCDS is actually part of the web application – if you follow along with my earlier post on generating an LCDS application skeleton, you’ll find that the LCDS libraries are included in the WAR file.

In the end, LCDS acts as the controller for the application. It provides a set of servlets for receiving, sending, and interpreting messages in various formats. The web application’s descriptor file (web.xml) defines these servlets as endpoints in the application. On the Flex side, the services_config.xml file identifies these endpoints to the Flex application. For more details, I recommend reviewing the default versions of these files included in your LCDS distribution (although this does require some knowledge of web application configuration). Although there are other options, I have chosen to use Adobe’s Action Message Format (AMF) for communication.

LCDS Architecture

With the controller (LCDS) and view (Flex) layers of my application complete, I turned to the model layer. I decided to use Hibernate to provide object-relational mapping and data persistence and Spring to manage transactions and the Hibernate session factory (primarily to make my life easier). There are numerous references online that discuss integrating Spring and Hibernate as well as information on utilizing the power of these tools for a Flex data service. In the end, the model layer of my application flows as follows:

Flow Diagram

Beans

With our order management application service designed, we can start to work on building its various pieces. LCDS, Spring, and Hibernate handle much of the heavy lifting here, but we need to fill in a few gaps in the BO, DAO, and bean layers.

Being the simplest, I started by building the three Java beans that my application requires along with the associated ActionScript models (they are very similar).

There are a couple of key points to notice:

  • For each property in the Java bean, there is an associated public attribute in the ActionScript class (of the same name!). This allows LCDs to serialize and deserialize objects properly.
  • In the ActionScript class, I have included two metadata tags:
    • [Managed] – provides utility methods for objects managed by a data service
    • [RemoteClass(alias="iamjosh.samples.lcds.models.Order")] – maps this class directly to a remote Java class
  • One other items of note, particularly for the LineItem class, are the equals() and hashCode() method. These are extremely important for Hibernate, so much so that I will review them in a future post.

Flex-Spring Integration

Since Spring wil be managing Hibernate, we only need to wire Spring to Flex. Luckily, Christophe Coenraets provides detailed information of how to do so. Like Christophe, we will be utilizing Jeff Vroom’s SpringFactory to provide Flex with initialized instances of Spring beans. All we need to do is include the SpringFactory class (avaiable on Adobe Exchange), register it in services-config.xml, and install the Spring libraries.

WEB-INF/flex/services-config.xml – register the SpringFactory with Flex

<factories>
    <factory id="spring" class="iamjosh.samples.lcds.factories.SpringFactory"/>
</factories>

WEB-INF/web.xml – include Spring configuration in the web application

<!-- Application context configuration for Spring -->
<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<!-- listener for Spring -->
<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

From the Spring framework, there are two JAR files that need to be included in the application: (1) spring.jar and (2) spring-hibernate3.jar. The latter provides integration between Spring and Hibernate.

Flex Data Assembler

When a request is made from the client (Flex) side, they are sent to an object called an assembler. We will need to create a custom assembler class to provide the interface from the data service to our business layer (BO) or data access layer (DAO). The assembler class extends the flex.data.assemblers.AbstractAssembler abstract class. The custom assembler is responsible for providing a set of callback methods (essentially get, update, create, and delete) that can be invoked from the client application (actually, in the Flex application, you’ll see that we call these methods “directly”).

Once we have created this class, we need to wire it to a destination that can will be referenced by the Flex application:

WEB-INF/flex/data-management-config.xml

<destination id="order.spring">
    <adapter ref="java-dao"/>
        <properties>
            <source>orderAssemblerBean</source>
            <factory>spring</factory>
            <metadata>
                <identity property="id"/>
            </metadata>
        </properties>
        <channels>
            <channel ref="my-rtmp"/>
        </channels>
</destination>

The above XML essentially maps a destination (order.spring) to an assembler (orderAssemblerBean), which is contructed by the Spring factory.

The configuration to map the order assembler to an actual implementation is handled in the Spring configuration (WEB-INF/applicationContext.xml). We also point to a business object that is utilized by the assembler class here.

<bean id="orderAssemblerBean" class="iamjosh.samples.lcds.assemblers.OrderAssembler">
    <property name="orderDAO" ref="orderDAOBean"/>
</bean>

Spring-Hibernate Integration

The final step is to integrate Spring and Hibernate by configuring the Hibernate session factory that the DAO class will utilize (once again in applicationContext.xml):

<bean id="orderDAOBean" class="iamjosh.samples.lcds.dao.OrderDAOImpl">
    <property name="sessionFactory" ref="sessionFactory"/>
</bean>

Our DAO implementation (OrderDAOImpl) is responsible for making calls to the database via the Hibernate package. You will also need to download and include the hibernate3 library as well.

Accessing the Data Service from Flex

The last step in building our sample application is to call the data service from the Flex application. I chose to use the DataService object to do so:

<mx:DataService id="orderService" destination="order.spring" autoCommit="true" />
<mx:ArrayCollection id="_orders"/>

<mx:Script>
    <![CDATA[
        private function onCreationComplete() : void
        {
            // call the method we want from the OrderAssembler (our service)
            this.orderService.fill(this._orders);
        }
    ]]>
</mx:Script>

As you can see above, we are referencing the data service destination defined in data-management-config.xml and the fill() method, one of the four standard methods provided by a data service. The fill() method is defined in the OrderAssembler. Other methods in the Assembler (e.g. createItem) can also be called in the same manner (orderService.createItem(newItem)).

Final Thoughts

Of course there is a great deal more depth to this subject than I am able to cover here, but my goal was to document how I built a basic working LCDS application and bring together information that I found in a number of different sources.

References

Advertisements

Debugging LCDS in Eclipse

I found a very helpful tidbit this afternoon…how to via AMF traffic as part of your debug logging stream. In the WEB-INF/flex/services-config.xml file, change “Error” to “Debug” in the following line:

    <logging>
        <target class="flex.messaging.log.ConsoleTarget" level="Debug">
        …
    </logging>

After restarting your application, you should see the console fill with output such as:

15:06:11,652 INFO  [STDOUT] [Flex] Deserializing AMF/RTMP request
Version: 0
  (Command method=connect (2) trxId=1.0)
    (Object #0)
      app = ""
      flashVer = "WIN 9,0,60,235"
      swfUrl = "http://localhost:8080/LCDS-Sample/bin/Main.swf"
      tcUrl = "rtmp://localhost:2038"
      fpad = false
      capabilities = 15.0
      audioCodecs = 1639.0
      videoCodecs = 252.0
      videoFunction = 1.0
      pageUrl = "http://localhost:8080/LCDS-Sample/bin/Main.html"
      objectEncoding = 3.0
    false
    "nil"

References:


Trouble with LCDS Object Deserialization

Found something interesting today in the course of trying to solve a problem in my sample LCDS application:

Why are my ValueObject member variables undefined in the results from my RemoteObject requests?

The Flash Player deserializes objects in a special order that can confuse developers used to object serialization from other RPC systems. When a strongly typed object is returned to the player it first creates an instance from the prototype of the registered class without calling the constructor. It then populates the object with the properties sent in the result and finally, it calls the constructor without arguments. If your ValueObject constructor expects arguments to initialize an instance be sure to check whether arguments were actually sent to the constructor before overriding member variable values. Note that the Flash Player does not currently honor getter/setter properties in object serialization or deserialization.

I have been dealing with this exact problem – an object referenced (Product) by the objects returned from my data service (LineItem) are not typed, but are instead only of type Object. This was not an easy problem to track down because it did manifest itself as I would have expected. Will post an update with a solution when I find one.

Update:

I ran into this problem again while testing a new application that we are building and I found a “fix” of sorts. If the class is referenced somewhere in the Flex application (instead of just including it), the class will be compiled into the application.  Once compiled, the Flash player will deserialize the object to a strongly typed object instead of a weak one (e.g. of type “Product” instead of “Object”).

This is not the most of elegant solutions, so please comment with better options. I hope the Flex team takes a look at this problem soon.

Reference


Update: Creating the Skeleton for a New LCDS Application

First, the good news…my LCDS development environment and server have been running since yesterday afternoon (15+ hours) without a failure yet.  If you missed the set-up, check my earlier post Finally…A Working LCDS Development Environment.

Since getting the development environment set-up, I’ve been working on building a sample LCDS application, which I will post on this site when finished.  The first step is building the application skeleton to support both Flex and Java development.  I posted an article on this earlier in the week (Creating the Skeleton for a New LCDS Application), but my current approach turned out to be slightly different.  The major differences were: (1) included the web app in an EAR project for deployment and (2) utilized JBoss 4.0 instead of 4.2.

In the end, you should have a project structure similar to the following, with the exception of the Spring (applicationContext.xml) and Hibernate (hibernate.cfg.xml) configuration files.  These files were added as part of my web app development and I will cover their purpose in my next post.

LCDS Application Structure

I also needed to modify my project’s Flex and Java compiler settings to get everything working properly.  In the project properties menu (right click on project name and select “Properties”), do the following:

  1. Select “Project Facets” and the click on the “Add/Remove Project Facets” button.
  2. Select the Java facet version and select “6.0.”  Java 6 is not necessary at this point, but some of the Hibernate code that I will be using requires it.
  3. Click “Finish”
  4. Select “Java Compiler” from the left hand menu and set the “Compiler Compliance Level” to 6.0.
  5. Select “Flex Compiler” from the left menu and set the “Flex SDK Version” to “Use the server’s SDK.”

You may notice that the server’s Flex SDK is version 2.0.1 and not 3.0.  Because of changes to resource bundle handling in 3.0, Flex will not compile our application as-is with the 3.0 SDK.  I am still working to resolve this issue, but for now, Flex 2.0 is sufficient for our purposes (please feel free to share insights via comments).

Next up, building the sample application.