Login | Register   
LinkedIn
Google+
Twitter
RSS Feed
Download our iPhone app
TODAY'S HEADLINES  |   ARTICLE ARCHIVE  |   FORUMS  |   TIP BANK
Browse DevX
Sign up for e-mail newsletters from DevX


advertisement
 

Taking a Java-Based App Offline Using Flash Builder, LiveCycle Data Services

This article builds a sample application that can seamlessly transition between online and offline connectivity status.


advertisement

There are many benefits to taking an enterprise application offline, especially in today's world, when everyone is seemingly connected to the Internet. Enterprise users often find themselves outside their corporate firewall. But rather than dealing with a slow-to-respond IT department and less-than-straightforward security concerns, they want their applications ready to deal with such situations. In the case of a complex application, a subset of the application's functionality should be available if the application's main server is not reachable for one reason or another.

 

The article builds a sample application that can seamlessly transition between online and offline connectivity status. While offline, users will still be able to use the application until connectivity is restored and the changes can be pushed back to the server.



 

Enterprise Considerations

 

Identifying the offline use cases is of course a core business concern. This article exemplifies a fairly simple use case in which an application needs to be taken offline and users should be able to comment, annotate, and rate field results for an existing project. This seems like a minimal use case for offline, but you soon realize that taking a feature offline presents many challenges, such as how to handle basic create, read, update, delete (CRUD) operations; how to deal with existing object relationships and synchronization issues caused by concurrent access to the same data; conflict resolution; and the list does not end there.

 

Improving a software product's usability should be a major factor here, so features like detection of online or offline status and seamlessly switching between the two, allowing the server to push updated data back to online clients, would constitute some nice touches to the application, consequently making it less prone to concurrent conflicts. In addition, such features prevent users from taking extra actions like manually starting synchronizations (the now-inactive Google Gears project comes to mind).

 

Glancing at the Adobe documentation, you quickly come to the realization that running the application in a browser (compiled as an Adobe Flash plug-in) would give the application little space for the local cache, which leaves you with one choice: running the offline application on top of the Adobe AIR runtime (which uses an embedded SQL-based database). One nice way of dealing with adaptation is to automatically redirect the user to the Adobe AIR application when the network status changes to offline and, if the runtime is not installed, informing the user that offline capabilities are not available and presenting the steps required perform the installation. You can address some of these challenges immediately by properly modeling your Document Object Model (DOM) and structuring the application with reusable components and application programming interfaces (APIs).

 

The Environment

 

Here are the minimum requirements for setting up this project:

  •  

       

      * Java 1.5.

       

      * Apache Maven 2.

       

      * Apache Tomcat 6 (or any other modern servlet container). In the context of this article, you're actually going to use the embedded version of Tomcat that ships with LCDS samples containing all the other dependent libraries and a memory-based HyperSQL (HSQL) database ready for use.

       

      * The Eclipse integrated development environment (IDE), as Adobe Flash Builder is also built as an Eclipse plug-in.

       

      * Adobe Flash Builder 4 beta 2, along with the Adobe Data Services 3 plug-in, as you are going to use the Fiber's code-generation capabilities. You manage integrating the two components and breaking the different online-offline states in the application life cycle with LCDS. Figure 1 shows the environment structure.
  • * The back end consists of a Java web application based on Adobe LiveCycle Data Services (LCDS), with simple plain old Java objects (POJOs) persisted using Hibernate. For this application, you need:

     

    * The front end is built using Flash Builder. For this application, you need:

 

 

Figure 1. The environment back end and front end structure

 

Back-end Code

 

Set up a simplistic back-end service consisting of a project model containing comments and ratings objects. You're going to use Hibernate for persisting objects into a database; for simplicity's sake, you'll annotate the POJOs using Java Persistence Architecture API (JPA) annotations that LCDS will make good use of later on.

 

The simplistic plain old Java domain objects are Project, which has names and a list of enclosing Comment objects. The Comment objects have subject, comment, and rating fields, each with a numeric value:



@Entity
@Table(name="projects")
@NamedQueries({
	@NamedQuery(name="project.all",query="from Project"),
	@NamedQuery(name="project.byId",query="from Project p where p.id = :id")
})
public class Project {
@Id @GeneratedValue
@Column(name="projectId")
private Long id;

@Column(name="name")
private String name;

@OneToMany(cascade=CascadeType.ALL,fetch=FetchType.LAZY)
private List<Comment> comments;
…

public class Comment {
@Id @GeneratedValue
@Column(name="commentId")
private Long id;

@Column(name="subject")
private String subject;
    
    	@Column(name="comment")
private String comment;

@Column(name="rating")
private int rating;

 

You've probably noticed the one-to-many association between the Project and Comment objects, having Hibernate cascading and lazy fetching. I also omitted the accessor methods for these POJOs; but by using Eclipse's built-in Generate Getters and Setters feature, you can easily generate them automatically, as shown in Figure 2.

 

 

Figure 2. Eclipse can automatically generate getter and setter methods.

 

Reference these getters and setters in your Hibernate mapping file (hibernate.cfg.xml):


<?xml version='1.0' encoding='utf-8'?> 
<!DOCTYPE hibernate-configuration PUBLIC 
    "-//Hibernate/Hibernate Configuration DTD 3.0//EN" 
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> 
<hibernate-configuration> 
    <session-factory> 
        <!-- Database connection settings. --> 
        <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> 
        <property name="connection.url"> 
            jdbc:hsqldb:hsql://localhost:9002/offline 
        </property> 
        <property name="connection.username">sa</property> 
        <property name="connection.password"></property> 
 
        <!-- JDBC connection pool (use the built-in). --> 
        <property name="connection.pool_size">1</property> 
 
        <!-- SQL dialect. --> 
        <property name="dialect">org.hibernate.dialect.HSQLDialect</property> 
 
        <!-- Enable the Hibernate automatic session context management. --> 
        <property name="current_session_context_class">thread</property> 
 
        <!-- Disable the second-level cache. --> 
        <property name="cache.provider_class"> 
            org.hibernate.cache.NoCacheProvider 
        </property>  
 
        <!-- Echo all executed SQL to stdout. --> 
        <property name="show_sql">true</property> 
 
        <!-- Drop and recreate schema --> 
        <property name="hbm2ddl.auto">create</property> 
 
        <!-- Load the annotated Java class. --> 
        <mapping class="examples.offline.Project"/>
        <mapping class="examples.offline.Comment"/>  
    </session-factory> 
</hibernate-configuration>
</xml>

For convenience, I generated the database schema using the hibernate3-maven-plugin, which has the smarts to create it using the previous JPA annotations. A simple Maven package command creates a file located at target/hibernate3/sql/schema.ddl by using the following Maven declaration in the build phase:


<plugin>
	<groupId>org.codehaus.mojo</groupId>
	<artifactId>hibernate3-maven-plugin</artifactId>
	<version>2.2</version>
	<executions>
		<execution>
			<phase>process-classes</phase>
			<goals>
				<goal>hbm2ddl</goal>
			</goals>
		</execution>
	</executions>
	<configuration>
		<components>
			<component>
				<name>hbm2ddl</name>
				<implementation>jpaconfiguration</implementation>
			</component>
		</components>
		<componentProperties>
			<persistenceunit>Default</persistenceunit>
			<outputfilename>schema.ddl</outputfilename>
			<drop>false</drop>
			<create>true</create>
			<export>false</export>
			<format>true</format>
		</componentProperties>
	</configuration>
</plugin>

And this is how the schema looks after feeding it into the LCDS HSQLDB utility:



CREATE MEMORY TABLE COMMENTS(COMMENTID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT
NULL PRIMARY KEY,COMMENT VARCHAR(255),RATING INTEGER,SUBJECT VARCHAR(255))
CREATE MEMORY TABLE PROJECTS(PROJECTID INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1) NOT NULL
PRIMARY KEY,NAME VARCHAR(255))
CREATE MEMORY TABLE PROJECTS_COMMENTS(PROJECTS_PROJECTID INTEGER NOT NULL,COMMENTS_COMMENTID
INTEGER NOT NULL,CONSTRAINT SYS_CT_50 UNIQUE(COMMENTS_COMMENTID),CONSTRAINT FK62BEE019928A30BE
FOREIGN KEY(COMMENTS_COMMENTID) REFERENCES COMMENTS(COMMENTID),CONSTRAINT FK62BEE019CE90EEB8
FOREIGN KEY(PROJECTS_PROJECTID) REFERENCES PROJECTS(PROJECTID))

To avoid creating separate assemblers for domain objects, use the LCDS-standard HibernateAnnotationsAssembler, because your POJOs already have Hibernate annotations. (You might want to implement the assembler interface if you need a custom solution or if you are architecting an application that uses data transfer objects that are different from your domain model, usually to address performance or scalability issues.) Here is the LCDS configuration file containing the destinations directives using the HibernateAnnotationsAssembler (data-management-config.xml):




<destination id="projectDestination">
	<adapter ref="java-dao" />
	<properties>
		<use-transactions>true</use-transactions>
		<auto-sync-enabled>true</auto-sync-enabled>
		<source>flex.data.assemblers.HibernateAnnotationsAssembler</source>
		<scope>application</scope>
		<network>
			<paging enabled="false" pageSize="10" />
		</network>
		<item-class>example.offline.Project</item-class>
		<metadata>
			<one-to-many property="comments" destination="hibernate-comment"
				lazy="true" />
		</metadata>
		<server>
			<fill-method>
				<name>fill</name>
				<params>java.util.List</params>
			</fill-method>
			<fill-configuration>
				<use-query-cache>false</use-query-cache>
				<allow-hql-queries>true</allow-hql-queries>
			</fill-configuration>
		</server>
	</properties>
</destination>

<destination id="commentDestination">
	<adapter ref="java-dao" />
	<properties>
		<use-transactions>true</use-transactions>
		<source>flex.data.assemblers.HibernateAnnotationsAssembler</source>
		<scope>application</scope>
		<item-class>example.offline.Comment</item-class>
	</properties>
</destination>


Comment and Contribute

 

 

 

 

 


(Maximum characters: 1200). You have 1200 characters left.

 

 

Sitemap