RIA applications allow client applications to absolve the back-end server from part of its activities, allowing a more equal balance between them. Using Flex, clients grow to become standalone applications, that connect to a server and perform the required operations. LiveCycle Data Services is a remarkable Adobe product as it allows Flex clients to easily connect to JavaEE based servers and manipulate data in many easy ways. In this post we will see how to use LiveCycle Data Services as an intermediary between a Flex client and a Hibernate server layer; the application domain will contain only a domain class, that will be persisted by Hibernate; we will define a named query in the Java layer and use the named query directly from a Flex client.
In the example we have a domain class Contact, with information such as name, surname, email, birth date. The Java server will have a Java bean class domain.Contact and also a Hibernate mapping file that defines how the domain class is persisted on a database.
The mapping file will also contain a named query, in HQL (Hibernate Query Language) for simplicity, that will return all the contacts.
Contact.hbm.xml:
<hibernate-mapping>
<class name=\"domain.Contact\" table=\"contact\">
<id name=\"id\"><generator class=\"native\" /></id>
<property name=\"name\" />
<property name=\"surname\" />
<property name=\"email\" />
<property name=\"birthDate\" column=\"birthDate\" type=â€date†/>
</class>
<query name=\"contact.all\">
<![CDATA[
FROM Contact
]]>
</query>
</hibernate-mapping>
The generated JAR archive will have to be deployed within a LiveCycle Data Services context, that is a LCDS web application deployed in the Tomcat webapps/ folder, configured for use with Hibernate. The JAR file will be part of the web application libraries and, on deploy, if well configured, will take care of connecting to the database and create or update the required tables.
For the client we have to create a Flex Data Services Project that points to the previously created LCDS web application and, before developing the Flex client, edit the LiveCycle Data Services configuration files to reflect the services we want to export from our LCDS enabled JavaEE server.
To use the data capabilities we need to add a data destination to data-management-config.xml, that will allow LiveCycle Data Services to handle our domain classes in a transparent and efficient way.
The destination added to data-management-config.xml:
<destination id=\"hibernateContact\">
<adapter ref=\"java-dao\" />
<properties>
<source>flex.data.assemblers.HibernateAssembler</source>
<scope>application</scope>
<metadata>
<identity property=\"id\"/>
</metadata>
<network>
<paging enabled=\"true\" pageSize=\"10\" />
<throttle-inbound policy=\"ERROR\" max-frequency=\"500\"/>
<throttle-outbound policy=\"REPLACE\" max-frequency=\"500\"/>
</network>
<server>
<hibernate-entity>domain.Contact</hibernate-entity>
<update-conflict-mode>PROPERTY</update-conflict-mode>
<delete-conflict-mode>OBJECT</delete-conflict-mode>
<fill-configuration>
<use-query-cache>false</use-query-cache>
<allow-hql-queries>true</allow-hql-queries>
</fill-configuration>
</server>
</properties>
</destination>
We can see in this last configuration sample part of what’s behind the curtains; for start, hibernate-entity holds the full name of the Java domain class and identity property is the property that is the unique id of the Java domain class. By providing flex.data.assemblers.HibernateAssembler as destination source we basically let LCDS handle almost everything about the domain classes, as long as related to data management. The HibernateAssembler provides full support for Hibernate entities as Flex data destinations. It can, of course, be extended to get a better control, but it can be used as is, allowing to forget about any persistence problems and head straight to the Flex client development.
The fill-configuration section contains configuration that defines how data fill is handled from server on client request. Additionally, the allow-hql-queries attribute allows to decide if the Flex client can have direct access to HQL queries related to the current destination. The client can send query strings or call named queries and then directly receive data, while the HibernateAssembler and LiveCycle Data Services deal internally with all other operations.
A Flex value object class needs to be defined, that reflects the Java domain class, with all of its properties:
package client.domain
{
[RemoteClass (alias="domain.Contact")]
public class ContactVO {
…
}
}
We can define an array collection, that will hold incoming data, as an array of ContactVO:
[Bindable]
var:ArrayCollection = new ArrayCollection();
a data service that will connect to the remote server, through LiveCycle DS:
var = new DataService("hibernateContact");
dataService.autoCommit = false;
dataService.autoMerge = false;
dataService.autoSyncEnabled = false;
The data service is created to connect to the specified destination, the one configured in the data-management-config.xml file.
Finally a data grid will display the data from the server:
<mx:DataGrid id=\"dg\" dataProvider=\"{arrayCollection}\" />
And to get all together and working, one line of code will connect the data service to the remote destination, call a remote named query and get the data into a local array collection:
dataService.fill(arrayCollection, "contact.all", []);
Calling fill() on the data service will use the fill configuration defined in the data management file, that permits the use of named queries, and ask for all Java Contact objects, that will arrive as Flex ContactVO objects and will be placed into the array collection.
If the named query would have required a parameter, for example it would be provided as third parameter of the fill() function, just inside the array that now is empty [].
LiveCycle Data Services and Hibernate can work together very well, after some configuration procedures, together they cover up everything from data persistence to data management in Flex clients.
Obviously, in order to hide server side logic and structure, it is better to use named queries instead of plain queries, just like the one defined in the hibernate-mapping snippet above. The Flex DataService class, like any AbstractService class, has the setRemoteCredentials() method that provides means to authenticate a request to a LiveCycle DS remote server, but this is subject for another blog entry.
Comments (4)
Hi -
I'm currently investigating the use of LCDS 2.5 and EJB3/JPA and am wondering about a couple of things.
First - would it be likely that in the near future we would have a JPAAssembler class, much like what Jeff has been doing with Hibernate?
Second - if not a JPAAssembler, what would be the best way of wiring data management to JPA?
Third - do I really need a DTO, can't I just 'return' domain objects, and how does this work with lazy loaded instances as set by JPA annotations.
Fourth - conceptually I've been thinking about this quite a lot. Looks to me that datamanagement is specifically geared towards CRUD like applications. But what if the use case at hand requires some more involved server side processing, most likely contained within a JTA transaction. Shoud I instead implement this as a RPC call and thus mix 'n match RPC and DM?
Thx,
-J.
Posted by Jan | July 28, 2007 12:41 AM
Posted on July 28, 2007 00:41
The HibernateAssembler that provides support for hibernate entities as flex destinations in Flex Data Management Services (flex.data.assemblers.AbstractAssembler)
HibernateAssembler deals mainly with data management operations such as fill collections of data or working with single items.
I am not aware if the existence of a JPAAssembler or alike; EJB entities and session beans are generally managed within the container while Hibernate POJOs can basically be deployed about anywhere.
There are, of course, ways of calling EJB3 session beans directly from the Flex client, through a LiveCycle Data Serivces layer, such as using the FlexFactory (flex.messaging.FlexFactory). The FlexFactory interface is implemented by factory components that provide instances to the Flex messaging framework.
LCDS can be configured to perform automatic EJB lookup. Or, instead of using a HibernateAssembler look alike, a solution might be creating ad hoc flex assemblers, by implementing the flex.data.assemblers.AbstractAssembler interface, but it depends on your particular scenario and use case. You can have a look at the example on the LiveCycle documentation that shows the source code for the CompanyAssembler class, which is part of the CRM application included in the samples web application :
http://livedocs.adobe.com/flex/201/html/wwhelp/wwhimpl/common/html/wwhelp.htm?context=LiveDocs_Book_Parts&file=data_collection_config_106_11.html
Using DTO or direct EJB3 POJO, again, depends on the application; if the EJBs use lazy fetching for their associations, it can create problems when sending one of those objects: if one sends only the POJO, the lazily fetched association is not being sent and an attempt to load it "later" will result in exceptions, as the request will come after the EJB session was closed. In this case it would be useful to use a DTO that packs all the data in the POJO together with the lazy collection, but it would be just like the collection were eagerly fetched.
Basically one could use lazy fetch for the operations within the container, defining a layer of business logic and creating session beans that can be accessed from the Flex client through the LiveCycle Data Services.
Posted by Constantin Moldovanu | July 31, 2007 4:09 PM
Posted on July 31, 2007 16:09
Uhhmmm, seems like LCDS doesn't support (de)serialization of Java 5 enums. This means that simply passing domain objects is only possible when restricting yourself to JDK1.4 features. You can use generics, since at runtime this information will be wiped out.
Kinda strange that LCDS 2.5, which if I'm not mistaken isn't production yet - doesn't support this and forces us to use DTOs in this case.
Posted by Jan | August 1, 2007 6:36 PM
Posted on August 1, 2007 18:36
Hello, I prefer use httpservice and XML, than AMF/remoting because the XML serialization can be resuse for another front end than flex and B to B application. Flex remoting is good for simple CRUD like applications. It could be a good way to make declarative profile graph fecthing strategy for entities in flex server side remoting to know what we need to serialize.
exemple :
entity Person profile 1:
field1, field2, collection1{field1}, collection2{field1,field2}
entity Person profile 2:
field1, field2
Posted by Edo_x7 | January 25, 2009 9:09 PM
Posted on January 25, 2009 21:09