Flex, Spring and BlazeDS: the full stack! (Part 3)

[UPDATE 2] If you are still having version issues with the sample application featured in this article, you can get a fully upgraded version here

[UPDATE] This article series has been reedited on the Adobe Developer Connection. For more information, see this post.

In the previous article in this series, I described the creation and configuration of a classic standalone Flex module built with flex-compiler-mojo. In this article I’m going to describe the creation of our back-end module, made up with Spring, Hibernate and MySQL. I’ll keep the most interesting part for the fourth and last episode, that is how to connect the frontend with the backend using BlazeDS.

Creating a WAR module

The first thing you have to do is to change directory to the root todolist project that we’ve created before and run the following command:

mvn archetype:create 
-DgroupId=org.epseelon.samples 
-DartifactId=todolist-web 
-DarchetypeArtifactId=maven-archetype-webapp

This command will create a new module under your root one and add todolist-web as a module to it. Now edit the POM of this newly created module and add the following dependencies:

<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring</artifactId>
  <version>2.5.2</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjrt</artifactId>
  <version>1.5.4</version>
</dependency>
<dependency>
  <groupId>org.aspectj</groupId>
  <artifactId>aspectjweaver</artifactId>
  <version>1.5.4</version>
</dependency>
<dependency>
  <groupId>org.hibernate</groupId>
  <artifactId>hibernate</artifactId>
  <version>3.2.6.ga</version>
</dependency>

Those are the dependencies required for Spring and Hibernate to work.

Last but not least, we’re going to add some configuration for the java compiler plugin in this module in order to be able to use generics and annotations in our code. So add the following plugin configuration to project/build/plugins node:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-compiler-plugin</artifactId>
  <configuration>
    <source>1.5</source>
    <target>1.5</target>
  </configuration>
</plugin>

Let’s write some Java code

Now let’s write the interface for our main service. In src/main/java, create a “org.epseelon.samples.todolist.business” package and create a TodoService interface therein, with the following content:

package org.epseelon.samples.todolist.business;

import java.util.List;
import org.epseelon.samples.todolist.domain.TodoItem;

public interface TodoService {
  void remove(TodoItem todoItem) throws Exception;
  TodoItem save(TodoItem todoItem) throws Exception;
  TodoItem findById(TodoItem todoItem) throws Exception;
  List<TodoItem> getList() throws Exception;
}

A very classical CRUD service. Note that we’re using TodoItem class as both a parameter and a return type of some of these methods. I hate to do this because when you have several entities with links between them, you end up with LazyInitializationException’s on the client side when you try to access linked entities since you are then outside of a Hibernate transaction. Bad! Bad! Bad! Normally, I’m a big fan of the value-object pattern, where I define data transfer objects for each entity and use only those as return types and parameters. But I’ve left that as a refactoring for later, since it’s not really the topic of this tutorial and there is only one entity in our domain.

Now let’s implement this service in the same package:

package org.epseelon.samples.todolist.business;

import java.util.List;

import org.epseelon.samples.todolist.domain.TodoItem;
import org.epseelon.samples.todolist.domain.TodoItemRepository;

public class TodoServiceImpl implements TodoService {
  private TodoItemRepository todoItemRepository;
  public void setTodoItemRepository(TodoItemRepository todoItemRepository) {
    this.todoItemRepository = todoItemRepository;
  }

  public TodoItem save(TodoItem item) throws Exception {
    try {
      this.todoItemRepository.save(item);
      return item;
    } catch (Exception e) {
      throw new Exception("Could not save item because: " + e.getCause());
    }
  }

  public void remove(TodoItem item) throws Exception {
    try {
      this.todoItemRepository.remove(item);
    } catch (Exception e) {
      throw new Exception("Could not delete item because " + e.getMessage());
    }
  }

  public TodoItem findById(TodoItem item) throws Exception {
    try {
      return this.todoItemRepository.findById(item);
    } catch (Exception e) {
      throw new Exception("Could not find item because " + e.getMessage());
    }
  }

  public List<TodoItem> getList() throws Exception {
    try {
      return this.todoItemRepository.getList();
    } catch (Exception e) {
      throw new Exception("Could not list items because " + e.getMessage());
    }
  }
}

As you can see, this implementation needs access to a TodoItemRepository in package “org.epseelon.samples.todolist.domain”. Here comes its interface:

package org.epseelon.samples.todolist.domain;

import org.epseelon.samples.todolist.domain.TodoItem;
import java.util.List;

public interface TodoItemRepository {
  void remove(TodoItem todoItem);
  TodoItem save(TodoItem todoItem);
  TodoItem findById(TodoItem todoItem) throws Exception;
  List</todoitem><todoitem> getList();
}

And here is its Hibernate-based implementation, in package “org.epseelon.samples.todolist.domain.hibernate”:

package org.epseelon.samples.todolist.domain.hibernate;

import java.util.List;
import org.epseelon.samples.todolist.domain.TodoItem;
import org.epseelon.samples.todolist.domain.TodoItemRepository;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

public class TodoItemHibernateDao extends HibernateDaoSupport implements TodoItemRepository {
  public TodoItem save(TodoItem todoItem) {
    getHibernateTemplate().saveOrUpdate(todoItem);
    return todoItem;
  }

  public void remove(TodoItem todoItem) {
    getHibernateTemplate().delete(todoItem);
  }

  public TodoItem findById(TodoItem todoItem) throws Exception {
    long id = todoItem.getId();
    todoItem = (TodoItem) getHibernateTemplate().get(TodoItem.class, todoItem.getId());

    if (todoItem == null)
      throw new Exception("Could not find an item with id " + id);
    return todoItem;
  }

  @SuppressWarnings("unchecked")
  public List<TodoItem> getList() {
    return (List<TodoItem>) getHibernateTemplate().loadAll(TodoItem.class);
  }
}

Now the last piece of the Java puzzle is the org.epseelon.samples.todolist.domain.TodoItem class:

package org.epseelon.samples.todolist.domain;

public class TodoItem {
  private long id;
  private String title;

  public long getId() {
    return id;
  }

  public void setId(long id) {
    this.id = id;
  }

  public String getTitle() {
    return title;
  }

  public void setTitle(String title) {
    this.title = title;
  }
}

Nothing special about it, pretty simple.

That’s it for the Java code. Now let’s run ‘mvn install’ to make sure that it all compiles before moving on to wiring all of that together.

Wiring things up

First things first, let’s create a database to store our application data. I create a todolist database and gave user todolist with password todolist all rights on this database. Here is the DDL script to create the one table that we need in this database:

CREATE TABLE `todoitem` (
  `id_todoitem` int(10) unsigned NOT NULL auto_increment,
  `title` varchar(256) NOT NULL,
  PRIMARY KEY  (`id_todoitem`)
) ENGINE=InnoDB;

Once you have created this database, let’s configure the object-relational mapping for Hibernate. In src/main/java/org/epseelon/samples/todolist/domain/hibernate/hbm, create a TodoItem.hbm.xml file with the following content:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-mapping PUBLIC
          "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
          "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
  <class name="org.epseelon.samples.todolist.domain.TodoItem" table="todoitem">
    <id name="id" column="ID_TODOITEM" type="long">
      <generator class="native" />
    </id>

    <property name="title" column="TITLE" type="string" not-null="true" length="50" />
  </class>
</hibernate-mapping>

By the way, I know I could have used JPA but I’m kind of a fan of XML files, so…
Now if we want this file to be included in our web application, we need to add some configuration to our POM. In the build element, add the following configuration:

<resources>
    <resource>
        <directory>src/main/resources</directory>
    </resource>
    <resource>
        <directory>src/main/java</directory>
        <excludes>
            <exclude>**/*.java</exclude>
        </excludes>
        <includes>
            <include>**/*.xml</include>
        </includes>
    </resource>
</resources>

Now that our entity is mapped, let’s move on to Spring configuration. In src/main/webapp/WEB-INF, create a file named applicationContext.xml with the following content:

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

    <!-- Properties file -->

    <context:property-placeholder location="/WEB-INF/jdbc.properties"/>

    <!-- Datasource -->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

    <!-- Hibernate SessionFactory -->
    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
        <property name="dataSource">
            <ref local="dataSource"/>
        </property>
        <property name="mappingDirectoryLocations">
            <list>
                <value>
                    classpath:org/epseelon/samples/todolist/domain/hibernate/hbm/
                </value>
            </list>
        </property>
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.dialect">
                    ${hibernate.dialect}
                </prop>
                <prop key="hibernate.show_sql">true</prop>
            </props>
        </property>
        <property name="eventListeners">
            <map>
                <entry key="merge">
                    <bean class="org.springframework.orm.hibernate3.support.IdTransferringMergeEventListener"/>
                </entry>
            </map>
        </property>
    </bean>

    <!-- ========================= BUSINESS OBJECT DEFINITIONS ========================= -->
    <bean id="todoService" class="org.epseelon.samples.todolist.business.TodoServiceImpl">
        <property name="todoItemRepository" ref="todoItemRepository"/>
    </bean>

    <bean id="todoItemRepository" class="org.epseelon.samples.todolist.domain.hibernate.TodoItemHibernateDao">
        <property name="sessionFactory" ref="sessionFactory"/>
    </bean>

    <!-- ========================= TRANSACTION MANAGEMENT ========================= -->
    <bean id="txManager"
          class="org.springframework.orm.hibernate3.HibernateTransactionManager">
        <property name="sessionFactory">
            <ref local="sessionFactory"/>
        </property>
    </bean>

    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <!-- all methods starting with 'get' are read-only -->
            <tx:method name="get*" read-only="true"/>
            <!-- other methods use the default transaction settings (see below) -->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>

    <aop:config>
        <aop:pointcut id="todoServiceOperation"
                      expression="execution(* org.epseelon.samples.todolist.business.TodoService.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="todoServiceOperation"/>
    </aop:config>

</beans>

Just a piece of advice, take some time to read this file as it uses a couple of intriguing but powerful features from Spring 2.5.

In the first line, we import properties from a properties file. Let’s create that jdbc.properties file in src/main/webapp/WEB-INF:

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/todolist
jdbc.username=todolist
jdbc.password=todolist
hibernate.dialect=org.hibernate.dialect.MySQL5InnoDBDialect

Next we configure the Hibernate session factory. Nothing special here.

After that, we create our service beans, todoService and todoItemRepository. And finally we configure everything needed to wrap service calls in transactions.

Once again, I could have used plenty of annotations to configure beans and their connections, but I just don’t like it. One of the main interests of Spring for me is to gather all the wiring configuration in one place. So prefer having it in an XML file rather than having to go to Java files to see how things are wired up.

Now of course, if we want our application context to be loaded with our web application, we have to edit src/main/webapp/WEB-INF/web.xml:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns="http://java.sun.com/xml/ns/javaee"
	xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
	id="WebApp_ID" version="2.5">

	<display-name>Todo List</display-name>

	<context-param>
		<param-name>contextConfigLocation</param-name>
		<param-value>/WEB-INF/applicationContext.xml</param-value>
	</context-param>

	<listener>
		<listener-class>
			org.springframework.web.context.ContextLoaderListener
		</listener-class>
	</listener>
	<listener>
		<listener-class>
			org.springframework.web.context.request.RequestContextListener
		</listener-class>
	</listener>

	<welcome-file-list>
		<welcome-file>index.html</welcome-file>
		<welcome-file>index.htm</welcome-file>
		<welcome-file>index.jsp</welcome-file>
	</welcome-file-list>

</web-app>

We still miss two things. First, you need to create a log4j.properties file in src/main/webapp/WEB-INF directory:

### direct log messages to stdout ###
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.Target=System.out
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n

# set root logger level to debug and its only appender to mtf
log4j.rootLogger=INFO,development

# only for development purposes
log4j.appender.development=org.apache.log4j.ConsoleAppender
log4j.appender.development.layout=org.apache.log4j.PatternLayout
log4j.appender.development.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %5p [%t] (%F:%L) - %m%n

log4j.logger.noModule=FATAL
log4j.logger.org.springframework=WARN

# Log JDBC bind parameter runtime arguments
log4j.logger.org.hibernate.type=DEBUG

And last but not least, you have to put the JDBC connector driver on the classpath of your application. In other words, if you’re using JBoss, you have to download mysql-connector-java-5.x.x.jar and place it in $JBOSS_HOME/server/default/lib. In Tomcat, I think you can place it directly in $TOMCAT_HOME/lib. Note that adding this connector to your module dependencies in order to bundle it with your application is not a good practice.

Checking that it… loads

We won’t check that services work, we’ll just make sure the application is successully started. So you can run ‘mvn install’ on the root module and copy todolist-web/target/todolist-web.war to to deployment directory ($JBOSS_HOME/server/default/deploy for JBoss, $TOMCAT_HOME/webapps for Tomcat). Then start up your server and look at the log. If you don’t have any error message, congratulations, you’re done. Otherwise, check that you’ve done everything described in this article, and if you have, please leave a comment to describe the error you get.

In the next article, we will develop our Flex UI and plug it onto our Spring backend using BlazeDS. Stay tuned!

PS: Here is the project with both modules.

10 comments

  1. This is a very useful set of posts! Thanks! Would you be interested in turning this into an article for the Adobe Developer Connection? Email me if you are: jaward at adobe dot com

    -James

  2. A couple of comments

    (1) There seems to be slight inconsistency between the package structure you quote on the site and the downloadable code (which seems to be more up to date).

    for example the instructions say to create TodoService and TodoServiceImpl in the org.epseelon.samples.todolist.business package, when the hibernate file is looking for the classes in org.epseelon.samples.todolist.model.service

    Not a big deal at all, but definitely some minutia to fix, and I’d love to hear your opinion on what the best practice is for creating your packages for an application like this.

    Otherwise.. GREAT GREAT GUIDE!!! Thank you so much for putting in the work to assemble all this stuff in one place. Many of the “tutorials” that i’ve seen for Flex-Spring-Hibernate-LCDS (or Blaze DS) dont work at all or leave too much out.

    Kudos on a great job

  3. Hi there

    Okay.. using everything as directed (MySQL 5.5.51b, JBoss 4.2.2) When I take the code from the attached zip file, I run ~mvn install~ successfully but when I deploy I get class not found exception

    java.lang.ClassNotFoundException: flex.messaging.MessageBrokerServlet

    could this be the result of some part of the repository not downloading?

    Here’s a bit more of the stack trace…

    13:40:32,610 INFO [[/todolist-web]] Marking servlet MessageBrokerServlet as unavailable
    13:40:32,610 ERROR [[/todolist-web]] Error loading WebappClassLoader
    delegate: false
    repositories:
    /WEB-INF/classes/
    ———-> Parent Classloader:
    java.net.FactoryURLClassLoader@1aabc29
    flex.messaging.MessageBrokerServlet
    java.lang.ClassNotFoundException: flex.messaging.MessageBrokerServlet

  4. Hi John, you are right, the project was not in sync with the article. I corrected the project so you can download it again.

    Concerning your ClassNotFoundException, check that you have all three blazeds libraries in WEB-INF/lib in your web application. If you don’t, double check your Maven dependencies.

  5. I get a NullPointerException when creating war file for web module

    I had little changes actually i changed artifactId’s and groupId’s of modules (also change corresponding package namings) could it be a problem there?

    here is the error

    [INFO] ————————————————————————
    [ERROR] FATAL ERROR
    [INFO] ————————————————————————
    [INFO] null
    [INFO] ————————————————————————
    [INFO] Trace
    java.lang.NullPointerException
    at org.apache.maven.plugin.war.util.WebappStructure.getDependencies(Weba
    ppStructure.java:109)
    at org.apache.maven.plugin.war.util.WebappStructure.analyseDependencies(
    WebappStructure.java:288)
    at org.apache.maven.plugin.war.packaging.DependenciesAnalysisPackagingTa
    sk.performPackaging(DependenciesAnalysisPackagingTask.java:46)
    at org.apache.maven.plugin.war.AbstractWarMojo.buildWebapp(AbstractWarMo
    jo.java:439)
    at org.apache.maven.plugin.war.AbstractWarMojo.buildExplodedWebapp(Abstr
    actWarMojo.java:375)
    at org.apache.maven.plugin.war.WarMojo.performPackaging(WarMojo.java:181
    )
    at org.apache.maven.plugin.war.WarMojo.execute(WarMojo.java:143)
    at org.apache.maven.plugin.DefaultPluginManager.executeMojo(DefaultPlugi
    nManager.java:453)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoals(Defa
    ultLifecycleExecutor.java:559)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalWithLi
    fecycle(DefaultLifecycleExecutor.java:500)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoal(Defau
    ltLifecycleExecutor.java:479)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeGoalAndHan
    dleFailures(DefaultLifecycleExecutor.java:331)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.executeTaskSegmen
    ts(DefaultLifecycleExecutor.java:292)
    at org.apache.maven.lifecycle.DefaultLifecycleExecutor.execute(DefaultLi
    fecycleExecutor.java:142)
    at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:336)
    at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:129)
    at org.apache.maven.cli.MavenCli.main(MavenCli.java:301)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
    java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
    sorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.codehaus.classworlds.Launcher.launchEnhanced(Launcher.java:315)
    at org.codehaus.classworlds.Launcher.launch(Launcher.java:255)
    at org.codehaus.classworlds.Launcher.mainWithExitCode(Launcher.java:430)

    at org.codehaus.classworlds.Launcher.main(Launcher.java:375)

    Great tutorial by the way…

Leave a Reply to Albulescu Cosmin Cancel reply