Maven, Flex, and LiveCycle DS (Part 2)

May 22, 2008

Core module (with Hibernate)

I created a new module called core and added it to my existing Java/Flex multi-module Maven project. It just has a regular JAR packaging type. I moved the following entity classes and DAOs to the new core module:

  • flex.samples.crm.company.Company
  • flex.samples.crm.company.CompanyDAO
  • flex.samples.crm.employee.Employee
  • flex.samples.crm.employee.EmployeeDAO
  •  

I modified the entity classes to use JPA annotations, like so:

import javax.persistence.Entity;
. . .
@Entity
public class Company {. . .}
. . .
@Entity
public class Employee {. . .}

I modified the DAO classes by extracting the interface and creating an implementation that uses Hibernate (via AppFuse’s GenericDaoHibernate). The resulting interface and implementation class looks like this:

import org.appfuse.dao.GenericDao;
import flex.samples.crm.model.Company;

/**
 * Data access object interface for company entity.
 */
public interface CompanyDao extends GenericDao {
    List findCompanies(String name, String industry) throws DaoException;
    Company getCompany(int companyId) throws DaoException;
    Company create(Company company) throws DaoException;
    void update(Company newVersion, Company previousVersion, List changes)
        throws DaoException, ConcurrencyException;
    void delete(Company company) throws DaoException, ConcurrencyException;
}
. . .
import org.appfuse.dao.hibernate.GenericDaoHibernate;
import flex.samples.crm.dao.CompanyDao;
import flex.samples.crm.dao.ConcurrencyException;
import flex.samples.crm.dao.DaoException;
import flex.samples.crm.model.Company;
/**
 * Company DAO implementation using Hibernate.
 */
public class CompanyDaoHibernate extends GenericDaoHibernate
    implements CompanyDao {
    . . .
} 

After the above changes, I now have the following classes (note the slight modification in the location/package of the classes).

  • flex.samples.crm.model.Company
  • flex.samples.crm.model.Employee
  • flex.samples.crm.dao.CompanyDao
  • flex.samples.crm.dao.EmployeeDao
  • flex.samples.crm.dao.hibernate.CompanyDaoHibernate
  • flex.samples.crm.dao.hibernate.EmployeeDaoHibernate
  •  

I added the following dependencies to my POM.

    <dependencies>
        <dependency>
            <groupId>org.appfuse</groupId>
            <artifactId>appfuse-hibernate</artifactId>
            <version>2.0.1</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>hibernate3-maven-plugin</artifactId>
        <version>2.1</version>
        <configuration>
            <components>
                <component>
                    <name>hbm2ddl</name>
                    <implementation>
                         annotationconfiguration
                    </implementation>
                </component>
            </components>
            <componentProperties>
                <drop>true</drop>
                <jdk5>true</jdk5>
                <namingstrategy>
                    ${hibernate.naming.strategy}
                </namingstrategy>
                <propertyfile>
                    target/test-classes/jdbc.properties
                </propertyfile>
            </componentProperties>
        </configuration>
        <executions>
            <execution>
                <phase>process-test-resources</phase>
                <goals>
            <goal>hbm2ddl</goal>
                </goals>
            </execution>
        </executions>
        <dependencies>
            <dependency>
                <groupId>${jdbc.groupId}</groupId>
                <artifactId>${jdbc.artifactId}</artifactId>
                <version>${jdbc.version}</version>
            </dependency>
        </dependencies>
            </plugin>
        </plugins>
    </build>

    <properties>
        <hibernate.naming.strategy>
            org.hibernate.cfg.ImprovedNamingStrategy
        </hibernate.naming.strategy>
        <hibernate.annotations.version>
            3.3.0.ga
        </hibernate.annotations.version>
        <hibernate.version>3.2.5.ga</hibernate.version>

        <hibernate.dialect>
            org.hibernate.dialect.MySQLInnoDBDialect
        </hibernate.dialect>
        <jdbc.groupId>mysql</jdbc.groupId>
        <jdbc.artifactId>mysql-connector-java</jdbc.artifactId>
        <jdbc.version>5.0.5</jdbc.version>
        <jdbc.driverClassName>com.mysql.jdbc.Driver</jdbc.driverClassName>
        <jdbc.url>
            <![CDATA[jdbc:mysql://localhost/crm?
            createDatabaseIfNotExist=true&
            useUnicode=true&characterEncoding=utf-8]]>
        </jdbc.url>
        <jdbc.username>username</jdbc.username>
        <jdbc.password>password</jdbc.password>
        <jdbc.databaseName>MySQL</jdbc.databaseName>
    </properties>

Note that I’ve added a Hibernate3 Maven plugin, and using it to create the database schema via hbm2ddl goal.

After successfully building the core module, I’m now ready to move back to the web module and instantiate the DAOs and assemblers as Spring configured beans.

Web module (with Spring)

I added some new dependencies to my web module.

        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>crm-sample-config</artifactId>
            <version>1.0-SNAPSHOT</version>
            <classifier>resources</classifier>
            <type>zip</type>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>${project.groupId}</groupId>
            <artifactId>crm-sample-core</artifactId>
            <version>1.0-SNAPSHOT</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.transaction</groupId>
                    <artifactId>jta</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring</artifactId>
            <version>2.5.4</version>
            <exclusions>
                <exclusion>
                    <groupId>javax.transaction</groupId>
                    <artifactId>jta</artifactId>
                </exclusion>
            </exclusions>
        </dependency>
        <dependency>
            <groupId>commons-dbcp</groupId>
            <artifactId>commons-dbcp</artifactId>
            <version>1.2.2</version>
        </dependency>

        <dependency>
            <groupId>${jdbc.groupId}</groupId>
            <artifactId>${jdbc.artifactId}</artifactId>
            <version>${jdbc.version}</version>
        </dependency>

Note that we’ve added the new core module as a dependency. We also added Spring and Commons DBCP. Also note that we’ve excluded the JTA dependencies to avoid conflicts with the web container. Otherwise, we’ll end up with the same “unable to access a UserTransaction” problem.

To use Spring as the factory, I followed the instructions at Christophe Coenraets’ blog and used the SpringFactory written by Jeff Vroom (LiveCycle Data Services architect). Note that this changes the services-config.xml and data-management-config.xml files in the config module.

My Spring configuration looks something like this.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-2.0.xsd">

    <!-- For JDBC settings and future properties files -->
    <bean id="propertyConfigurer"
        class="org.springframework...PropertyPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>classpath:jdbc.properties</value>
            </list>
        </property>
    </bean>

    <!-- JNDI DataSource for J2EE environments -->
    <!--<jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/xxx"/>-->

    <bean id="dataSource"
        class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="100"/>
        <property name="maxIdle" value="30"/>
        <property name="maxWait" value="1000"/>
        <property name="defaultAutoCommit" value="true"/>
        <property name="removeAbandoned" value="true"/>
        <property name="removeAbandonedTimeout" value="60"/>
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory"
        class="org.springframework...AnnotationSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
        <property name="hibernateProperties">
            <value>
                hibernate.dialect=${hibernate.dialect}
                hibernate.query.substitutions=true 'Y', false 'N'
                hibernate.cache.use_second_level_cache=true
                hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
            </value>
        </property>
        <property name="namingStrategy">
            <bean class="${hibernate.naming.strategy}" />
        </property>
    </bean>

    <bean id="companyDao"
        class="flex.samples.crm.dao.hibernate.CompanyDaoHibernate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="companyAssembler"
        class="flex.samples.crm.company.CompanyAssembler">
        <property name="companyDao" ref="companyDao"/>
    </bean>

    <bean id="employeeDao"
        class="flex.samples.crm.dao.hibernate.EmployeeDaoHibernate">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <bean id="employeeAssembler"
        class="flex.samples.crm.employee.EmployeeAssembler">
        <property name="employeeDao" ref="employeeDao"/>
    </bean>

</beans>

Note that I’ve modified the assembler classes (CompanyAssembler and EmployeeAssembler) slightly to use the CompanyDao and EmployeeDao interfaces.

And that’s it! I now have a Maven-based build of the CRM app (from LCDS samples) that uses Flex, Hibernate (annotations), Spring, and LCDS. Next, I’ll try to use Cairngorm in the ria module, and some AS3 code generation via Granite DS AS3 code generator.

If you would like to get a copy of the entire source, just let me know (by posting a comment).

This is my first try in using Maven to build a Flex app. Comments and suggestions are very welcome.

Maven, Flex, and LiveCycle DS

May 22, 2008

I finally got back to continuing my experiments with Java and Flex. I wish Adobe would bundle some build files (like ant build.xml, maven pom.xml) with their LiveCycle DS (LCDS) examples.

So here’s what I’ve done so far. After following the steps in Flex, Spring and BlazeDS: the full stack blog, I made some modifications to make it use LCDS (instead of BlazeDS).

    <properties>
        <flex.dataservices.groupId>com.adobe.flex</flex.dataservices.groupId>
        <flex.dataservices.artifactId>flex-messaging</flex.dataservices.artifactId>
        <flex.dataservices.version>2.6-beta2</flex.dataservices.version>
    </properties>

    <dependencies>
        <!-- LiveCycle Data Services compile dependencies -->
        <dependency>
            <groupId>${flex.dataservices.groupId}</groupId>
            <artifactId>${flex.dataservices.artifactId}-data</artifactId>
            <version>${flex.dataservices.version}</version>
        </dependency>
        <dependency>
            <groupId>${flex.dataservices.groupId}</groupId>
            <artifactId>${flex.dataservices.artifactId}-core</artifactId>
            <version>${flex.dataservices.version}</version>
        </dependency>
        <dependency>
            <groupId>${flex.dataservices.groupId}</groupId>
            <artifactId>${flex.dataservices.artifactId}-common</artifactId>
            <version>${flex.dataservices.version}</version>
        </dependency>

        <!-- LiveCycle Data Services runtime dependencies -->
        <dependency>
            <groupId>${flex.dataservices.groupId}</groupId>
            <artifactId>${flex.dataservices.artifactId}-data-req</artifactId>
            <version>${flex.dataservices.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>${flex.dataservices.groupId}</groupId>
            <artifactId>${flex.dataservices.artifactId}-opt</artifactId>
            <version>${flex.dataservices.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>${flex.dataservices.groupId}</groupId>
            <artifactId>${flex.dataservices.artifactId}-proxy</artifactId>
            <version>${flex.dataservices.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>${flex.dataservices.groupId}</groupId>
            <artifactId>${flex.dataservices.artifactId}-remoting</artifactId>
            <version>${flex.dataservices.version}</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>backport-util-concurrent</groupId>
            <artifactId>backport-util-concurrent</artifactId>
            <version>3.1</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>concurrent</groupId>
            <artifactId>concurrent</artifactId>
            <version>1.3.4</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>commons-httpclient</groupId>
            <artifactId>commons-httpclient</artifactId>
            <version>3.0.1</version>
            <scope>runtime</scope>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

        <!--
        <dependency>
            <groupId>com.adobe.blazeds</groupId>
            <artifactId>blazeds-core</artifactId>
            <version>${blazeds.version}</version>
        </dependency>
        <dependency>
            <groupId>com.adobe.blazeds</groupId>
            <artifactId>blazeds-remoting</artifactId>
            <version>${blazeds.version}</version>
        </dependency>
        <dependency>
            <groupId>backport-util-concurrent</groupId>
            <artifactId>backport-util-concurrent</artifactId>
            <version>3.1</version>
            <scope>runtime</scope>
        </dependency>
        -->
    </dependencies>

Since the LCDS JARs are not available in the remote Maven repository, I had to load them into my local repository manually (via mvn install:install-file). The LCDS JARs are found under the resources/libs folder of the LCDS installation.

Note that I’m using LCDS version 2.6 beta 2. It’s a bit different from version 2.5.x (called Flex Data Services).

After a successful build, I moved on to adding Hibernate and Spring. I looked at the samples that come with LCDS. I was sad to see that there was no sample that uses the Spring Framework. I remember seeing it when it was still called Flex Data Services.

I decided to use the CRM sample as a starting point. I copied the corresponding Java source files into my web module, and the Flex source files into my ria module. I also copied the necessary elements (i.e. <destination id="crm-company"> and <destination id="crm-employee">) into my config module’s data-management-config.xml file.

I tried to run the CRM sample using Maven via jetty plugin (mvn clean package jetty:run). The Flex client keeps on saying “unable to access UserTransaction”. So, I did some research and came up with a change in my web module’s POM to have Jetty create a UserTransaction for me.

    <build>
        <plugins>
            . . .
            <plugin>
                <groupId>org.mortbay.jetty</groupId>
                <artifactId>maven-jetty-plugin</artifactId>
                <version>6.1.9</version>
                <configuration>
                    <scanIntervalSeconds>30</scanIntervalSeconds>
                    <webAppSourceDirectory>
                        ${project.build.directory}/${project.build.finalName}
                    </webAppSourceDirectory>
                    <!-- jettyEnvXml only works with jetty:run, 
                          but not jetty:run-war -->
                    <jettyEnvXml>
                        src/test/resources/jetty-env.xml
                    </jettyEnvXml>
                </configuration>
                <dependencies>
                    <dependency>
                        <groupId>commons-logging</groupId>
                        <artifactId>commons-logging</artifactId>
                        <version>1.1</version>
                    </dependency>
                    <dependency>
                        <groupId>log4j</groupId>
                        <artifactId>log4j</artifactId>
                        <version>1.2.13</version>
                    </dependency>
                    <dependency>
                        <groupId>jotm</groupId>
                        <artifactId>jotm</artifactId>
                        <version>2.0.10</version>
                    </dependency>
                    <dependency>
                        <groupId>javax.resource</groupId>
                        <artifactId>connector</artifactId>
                        <version>1.5</version>
                    </dependency>
                </dependencies>
            </plugin>
        </plugins>
    </build>

And here’s how my src/test/resources/jetty-env.xml looks like.

<?xml version="1.0"  encoding="ISO-8859-1"?>
<!DOCTYPE Configure PUBLIC "-//Mort Bay Consulting//DTD Configure//EN"
  "http://jetty.mortbay.org/configure.dtd">

<Configure class="org.mortbay.jetty.webapp.WebAppContext">

  <!-- Ensure Jetty Plus features are enabled for this webapp -->
  <Set name="configurationClasses">
    <Array type="java.lang.String">
      <Item>org.mortbay.jetty.webapp.WebInfConfiguration</Item>
      <Item>org.mortbay.jetty.plus.webapp.EnvConfiguration</Item>
      <Item>org.mortbay.jetty.plus.webapp.Configuration</Item>
      <Item>org.mortbay.jetty.webapp.JettyWebXmlConfiguration</Item>
      <Item>org.mortbay.jetty.webapp.TagLibConfiguration</Item>
    </Array>
  </Set>

  <New id="jotm" class="org.objectweb.jotm.Jotm">
    <Arg type="boolean">True</Arg>
    <Arg type="boolean">False</Arg>
    <Call id="ut" name="getUserTransaction"/>
    <Call id="tm" name="getTransactionManager"/>
  </New>
  <Call name="setAttribute">
    <Arg>txmgr</Arg>
    <Arg><Ref id="tm"/></Arg>
  </Call>
  <New class="org.mortbay.jetty.plus.naming.Resource">
    <Arg>javax.transaction.TransactionManager</Arg>
    <Arg><Ref id="ut"/></Arg>
  </New>
  <New id="tx" class="org.mortbay.jetty.plus.naming.Transaction">
    <Arg><Ref id="ut"/></Arg>
  </New>

</Configure>

Boy, the above took me about two (2) days to get it working. I’m not even sure if it’s the best of way of doing it! All I know is that LCDS Assemblers need to access a UserTransaction (JTA) via JNDI (just like the tomcat that comes bundled with the LCDS 2.6 beta 2 download). If you have an easier way to make it work with the Maven Jetty plugin, please let me know.

I also found out that I can set <use-transactions> to false in the data-management-config.xml file in the config module. But remember to re-build the ria module to pick up the new config settings. With <use-transactions> set to false, a UserTransaction is no longer required. It expects that the DAOs will do its own transaction handling.

Note that I had to package the web app first (to get all the xml and swf files into a folder under target) before using Jetty plugin. So I’m doing a mvn clean package jetty:run to test if the web app works. So far, it’s working fine.

In my next post, I’ll move the DAOs and entity classes into a separate module. I’ll use Hibernate annotations (instead of JDBC) to re-write the DAOs and entity classes. I want to use hbm2ddl in my Maven build to create the database schema.

Java and Flex

April 30, 2008

I’ve been developing software using Java for several years now. I’ve always wanted to try something in the RIA world. This entry is part of my journey in learning Adobe’s Flex.

After reading a book on Flex Programming, I wanted to see if I could use Maven to build a Flex application with a Java backend. I simply love to use Maven in building my Java programs. So, I set out to see if there are Maven archetypes for Flex. Luckily, I found this and this.

I’m still playing around with it. So far, I have four modules (in a multi-module build):

  • config (pom/zip)
  • core (jar)
  • ria (swf)
  • web (war)

My goal is to create Maven-based build that uses LiveCycle DS (LCDS), Flex, Hibernate/EJB3/JPA, and Cairngorm. If someone else has done this before, please let me know.

For the build, I’ve used GraniteDS AS3 code generator to generate AS3 value objects from Java entities/value-objects.

I’ll blog more about this as I proceed.

That’s all for now.