Flex and Hibernate

For the past month or so I’ve been working on a new example that shows how to use the Hibernate data assembler in LiveCycle Data Services ES. If you aren’t familiar with Hibernate, it is a way to easily persist Java objects – either singularly or in collections and with complex relationships. For example, if you have a data base of employees using several tables, you can make a single Java class that represents the employees and tell Hibernate how to bring it all together. You can load and save these objects using Hibernate and all of the tables will be updated properly.

LiveCycle Data Services ES includes Hibernate. Using the AMF protocol between the Flex client and LC DS you can persist ActionScript objects, too. You can create an Employee ActionScript class and point to a LC DS destination which maps to Hibernate and save and load your ActionScript objects. There’s a bit more to it than that, of course, which is why I wanted to make an example.

This example is complex enough that I have broken it into two parts. This is the first part and shows how to use Hibernate with LC DS along with a simple Flex application. The next part focuses a bit more on the Flex side with a more complex application but still using the same example code from this part.

Here are the basic steps:

  1. You need a database. I’ve used MySQL 5 for the example. You need to create tables and foreign key relationships. The schema which accompanies this article includes that.
  2. You need LiveCycle Data Services ES. Once that’s installed you follow a few more steps to turn on Hibernate. There is nothing else to download.
  3. You make some Java beans that represent your objects. There is a Hibernate tool and Eclipse plugin which can do this but I did it all by hand. If this were a larger project I would opt for the tool. Hibernate persists Java objects, not ActionScript objects, which is why you need these Java classes. LC DS will take care of mapping your ActionScript classes to the Java classes.
  4. You make Hibernate configuration files which maps the Java classes to the database tables. The example I’ve written keeps these pretty minimal, which is good the first time out. In reading a Hibernate book I can see that very complex things can be done using these files.
  5. You make corresponding ActionScript classes. When you request data through the remote data service in LC DS you get back ActionScript objects. There are special ActionScript metadata tags which tell the compiler to expect this.
  6. You make a Flex application.

You also might want to visit this blog to get a more rapid introduction to Hibernate and Flex: Mind the Gap

About the Data

Before going further I should explain the data being used. I work in the Flex support group and so I modeled this example on some of the tools we use to open and track questions from our customers.

The tables include one for Accounts (customer companies), AccountContacts (people who have questions), Consultants (people like me), Cases (the questions asked), and CaseNotes (the progress of the Case). Accounts can also have a Consultant assigned to them and a Consultant can have multiple Accounts assigned. This is a one-to-many relationship. The Java and ActionScript classes reflect this: you’ll see Sets in the Java classes and ArrayCollections in the ActionScript classes.

Setup and Installation

DownloadArrow.png Click arrow to download sample code
The download contains 2 zip files of Flex Builder 2 projects. If you cannot load the projects, unzip them into a clean directory and use the sources and assets directly.

To begin this example, install your database and create the tables from my schema. Create a database called “support” and if you are using MySQL 5 you should get no errors when you run the SQL statements. If you are using a different database you may have to change the SQL. This is one good reason to use Hibernate as it masks the database peculiarities from you.

Now install LC DS if you haven’t already. Install it using the embedded JRun instance. This will make debugging and development simple.

Active the Hibernate components in LC DS as follows: (steps from documentation here).

Copy
<install root>/resources/hibernate/*.jar
to your web application’s WEB-INF/lib directory (for example, on windows, this might be C:\lcds\jrun4\servers\default\samples\WEB-INF\lib\

Create a new Flex Builder Java project. Have the bin directory point to the WEB-INF/classes directory. Copy the contents of the classes directory to the WEB-INF/classes directory in LC DS. You’ll see that there are both .class and .hbm.xml files. It is best if the Hibernate configuration files shadow the Java class files.

Modify your data-management-config.xml file that is in WEB-INF/flex directory. Here’s a tip: in Flex Builder, add a new folder to your Java project, but click the Advanced button to make it a link to an existing folder. Browse to the WEB-INF/flex directory. Now you can edit the configuration files right from Flex Builder.

Start LC DS. You should see a lot of output, but no errors. If you do get errors, double-check your work.

Create a new Flex Builder Flex project. Indicate that you want to use LC DS, but compile locally in Flex Builder. You can compile on the server, too if you like. I prefer to leave my source files off the server.

Import the Flex sources into this new project. Notice how the bin directory points to the LC DS flex context root directory. Your compiled files will go right out to the server so all you need to do is run it.

In fact, all you need to do is run the TestingApp application. This is what you should see:

TestingAppScreenShot_thumb.jpg Click to enlarge

So how does all this work?

If you open the Flex application you’ll see a couple of DataService tags. Note the destination values. Then open the data-management-config.xml file on the LC DS server and find the destination with the same name. Notice how this destination is tied to the Hibernate entity description.

When the Flex application requests all of the Account objects, LC DS uses the Hibernate adapter to get Hibernate to fulfill the query. Hibernate queries the database and assembles a collection of Java Account objects. LC DS then converts the Java classes into an AMF binary stream, including the class name meta data.

The AMF stream arrives at the Flash Player and the Flex code examines the metadata and matches it with ActionScript classes with the same metadata and creates the ActionScript objects.

What you get back in your Flex application is an ArrayCollection of ActionScript Account objects. But there is more than that. Notice how the Account class also defines a collection of AccountContacts. Hibernate has gone and fetches them, too.

I hope this is enough detail to get you going. Leave me some comments if there are parts I could explain better and I’ll follow with another article. Once this part is well understood, I’ll publish the next part which details a Flex application that makes use of this data.

Hibernate Mapping in Detail

Let’s take a closer look at the Hibernate mapping files and how they relate to the application as a whole.

First open the data-management-config.xml file and locate the destination for account.hibernate:

<destination id="account.hibernate">
<adapter ref="java-dao" />
<properties>
<use-transactions>true</use-transactions>
<source>flex.data.assemblers.HibernateAssembler</source>
<scope>application</scope>
 2.         <metadata>
<identity property="id"/>
<one-to-many property="accountContacts" destination="accountContact.hibernate" read-only="true" lazy="true" />
<many-to-one property="consultant"
destination="consultant.hibernate" lazy="true" />
</metadata> 
<server>1.
<hibernate-entity>support.Account</hibernate-entity>
<fill-configuration>
<use-query-cache>false</use-query-cache>
<allow-hql-queries>true</allow-hql-queries>
</fill-configuration>
</server>
</properties>
</destination>

#1: Notice in the <server> section the <hibernate-entity>? The value supplied is the name of the Hibernate entity class to use with this destination. Since it is “support.Account” you’ll want to look into the support package for the entity configuration file. Open WEB-INF/classes/support/Account.hbm.xml:

<class name=”support.Account” table=”accounts”> This names the Java class associated with this Hibernate class entity and the database table it maps to.

<id name="id" column="accountid">
<generator class="native"/>
</id>

If you examine the database table description for “accounts” you’ll see that its primary key is the account column. The Hibernate entity element, <id>, shows that the id property of the Java class maps to the accountid column of the “accounts” table.

Look back at the data-management-config.xml destination at #2, the <metadata> for the destination description. See how the <identity> element names the same property.

The data-management-config.xml destination <metadata> also names some associations:

<one-to-many property="accountContacts"
destination="accountContact.hibernate"
read-only="true" lazy="true" />
<many-to-one property="consultant"
destination="consultant.hibernate"
lazy="true" />

Go back to the Account.hbm.xml file and you’ll see corresponding relationship mappings:

<set name="accountContacts" inverse="true"  >
<key column="accountid" />
<one-to-many class="support.AccountContact" />
</set>

<many-to-one name="consultant"
column="consultantid"
class="support.Consultant"
not-null="false" />

Since an Account can have zero or more AccountContacts, the first association declares a one-to-many relationship (one Account to many AccountContacts). In Hibernate, this is represented as a Set and corresponds to the java.util.Set class in the Account java class. The Set’s name (accountContacts) is the name of the property in the Java class; the set names the column to key off of and the one-to-many element identifies which Hibernate entity class to use for those elements.

Back in the data-management-config.xml file, the one-to-many association is repeated to let the Data Services Hibernate Assembler know the relationships should be formed.

The relationship between a Consultant and an Account is the reverse: many Accounts to one Consultant. So a many-to-one association is used. When Hibernate sees the many-to-one element it knows that the Java class property, “consultant” will be of the type, support.Consultant and be a single element, not a collection.

Where’s the ActionScript?

When dealing with the server-side there is no ActionScript – that’s in the Flex client. Hibernate uses Java classes. For example, support.Account.

The Data Services Hibernate Assembler takes the Java class instances returned by Hibernate (eg, support.Account) and creates a byte stream in AMF format. Part of the byte stream (or serialization) of the class instances contains the name of the Java class.

Back in the Flex client, the receipt of the byte stream causes a look-up of an ActionScript class with metadata that maps the Java class name to an ActionScript class. The Flex client code then instantiates an ActionScript class (eg, support.Account) and fills its properties with the corresponding values from the byte stream.