20090429

Seam, EJB's and EAR-packaging in Maven

Lately I've been designing a new course on the splendid JBoss Seam (2.1) Web and Java EE framework. One thing that strikes me, being an enterprise Java developer, is that almost no good examples of setting up Seam using Maven exist. I realize that Seam's appeal comes from a tradition of wanting things to be nice and easy, so the seam-gen tool has absolute merits for creating your project but to me the downside of this approach is that you're bound to use Ant as a build tool and for a lot of reasons I won't go into here, I strongly prefer using Maven.

The examples of using Maven to build Seam applications that I have been able to track down have been limited in a variety of ways:

  • Most of them required to use a specific Maven archetype which altered the default project layout.
  • Almost all of them where out of date and was bound to a very "custom" maven repository which I don't think is suitable for enterprise application infrastructure.
  • Those that didn't fall within the former two points where restricted to web-applications (WAR-files) only and thus didn't support using EJB's in the Seam applications.
So this blog post is going to be a walk-through of how I managed (after quite some effort) to configure Maven to be able to build an EAR file containing EJB's and a web-application that is able to utilize these EJB's as Seam components. I'm only highlighting the most interesting parts - You can download the complete example for free - and in contrast to the examples I have seen, it's very bare-boned and won't take more than a few seconds to alter to your needs.

Project structure
OK - to meet the demand of packaging an EAR file I've created a Maven project consisting of three modules. It's possible that this part can be optimized a bit since I use a seperate module for doing all the packaging (which to my understanding is the way to do it). The modules are:
  • ejbs - containing the EJB's and possibly other "backend"-stuff like JPA-classes and so on.
  • web - containing the web application
  • packaging - for packaging the EAR file containg the two other modules (and Seam)
Which module depends on what?
One of the big issues that I faced was figuring out how to configure Maven's dependency management framework to generate a correct set of EAR, JAR and WAR files. If this is done wrong it won't work and you'll waste hours (or at least I did) trying to figure out what is wrong.

All provided dependencies go into the parent project. These are all the dependencies provided by your container (plus Seam itself which will be packaged within the EAR file). You will need to add JBoss's Maven repository to resolve these dependencies. Here are the important parts of my parent project pom:
<repositories>
   <repository>
     <id>repository.jboss.org</id>
     <name>JBoss Repository</name>
     <url>http://repository.jboss.org/maven2</url>
   </repository>
</repositories>
<modules>
   <module>ejbs</module>
   <module>web</module>
   <module>packaging</module>
</modules>
<dependencies>
   <dependency>
     <groupId>org.jboss.seam</groupid>
     <artifactId>jboss-seam</artifactid>
     <version>2.1.1.GA</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>javax.faces</groupid>
     <artifactId>jsf-api</artifactid>
     <version>1.2_02</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.hibernate</groupid>
     <artifactId>hibernate-entitymanager</artifactid>
     <version>3.4.0.GA</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>org.hibernate</groupid>
     <artifactId>hibernate-validator</artifactid>
     <version>3.1.0.GA</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>javax.servlet</groupid>
     <artifactId>servlet-api</artifactid>
     <version>2.5</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>javax.servlet.jsp</groupid>
     <artifactId>jsp-api</artifactid>
     <version>2.1</version>
     <scope>provided</scope>
   </dependency>
   <dependency>
     <groupId>javax.ejb</groupid>
     <artifactId>ejb-api</artifactid>
     <version>3.0</version>
   </dependency>
</dependencies>
In the ejbs module you will not need any dependencies!

In the web module you will need to add seam-ui (excluding the "core" seam, because it is provided within the EAR file), facelets and other web-dependencies such as RichFaces, seam-pdf or whatever. Here are the dependencies of my web module pom:
<dependencies>
   <dependency>
     <groupId>com.sun.facelets</groupid>
     <artifactId>jsf-facelets</artifactid>
     <version>1.1.11</version>
   </dependency>
   <dependency>
     <groupId>org.jboss.seam</groupid>
     <artifactId>jboss-seam-ui</artifactid>
     <version>2.1.1.GA</version>
     <exclusions>
       <exclusion>
         <groupId>org.jboss.seam</groupid>
         <artifactId>jboss-seam</artifactid>
       </exclusion>
     </exclusions>
   </dependency>
</dependencies>
If you want to write Seam components that pertain only to the web module, then you will probably also need to include the ejbs module as a dependency in the web module pom. But remember to set the scope as provided, because it's all within the same EAR.

Last but not least you will need to write the packaging module pom. The Seam Documentation have been used to guide how this pom is structured: The ejbs module needs to be a registered EJB module. The web module needs to be a registered WAR module. And Seam itself needs to be a registered EJB module as well! JBoss EL needs to be placed in the /lib directory of the EAR and you need to make sure to exclude the EL API dependency from several artifacts - otherwise you'll get weird classpath issues when deploying. The important parts of the packaging module pom looks like this (pay attention to the parts in bold):
<build>
   <plugins>
     <plugin>
       <artifactId>maven-ear-plugin</artifactid>
       <configuration>
         <modules>
           <jarmodule>
             <groupId>org.jboss.el</groupid>
             <artifactId>jboss-el</artifactid>
             <includeinapplicationxml>false</includeinapplicationxml>
             <bundledir>lib</bundledir>
           </jarmodule>
           <webmodule>
             <!-- add web module groupId and artifactId here -->
             <contextroot>/seam-ejb-ex</contextroot>
           </webmodule>
         </modules>
       </configuration>
     </plugin>
   </plugins>
</build>
<dependencies>
   <dependency>
     <!-- add ejbs module groupId, artifactId and version here -->
     <type>ejb</type>
   </dependency>
   <dependency>
     <!-- add web module groupId, artifactId and version here -->
     <type>war</type>
   </dependency>
   <dependency>
     <groupId>org.jboss.seam</groupid>
     <artifactId>jboss-seam</artifactid>
     <version>2.1.1.GA</version>
     <type>ejb</type>
     <exclusions>
       <exclusion>
         <groupId>javax.el</groupid>
         <artifactId>el-api</artifactid>
       </exclusion>
     </exclusions>
   </dependency>
   <dependency>
     <groupId>org.jboss.el</groupid>
     <artifactId>jboss-el</artifactid>
     <version>1.0_02.CR2</version>
     <type>jar</type>
     <exclusions>
       <exclusion>
         <groupId>javax.el</groupid>
         <artifactId>el-api</artifactid>
       </exclusion>
     </exclusions>
   </dependency>
</dependencies>
So that's all the Maven configuration. Now to some "gotchas" in regards to Seam configuration. A lot of these things are being "disguised" by seam-gen so consider this a list of things you might have forgotten if you're building the project from the bottom up:
  • Remember to put empty seam.properties files in to the resource folders of both the ejbs and web modules.
  • Remember to register the Seam interceptors (as described in the Seam Documentation) in the ejb-jar.xml file, located in the resources/META-INF folder ejbs module.
  • The components.xml file should be located in the web module's WEB-INF folder. But you can't just copy the file from a seam-gen project because seam-gen dynamically replaces some "magic strings" in it to see to container compliancy. Instead you will have to add this static entry to the components.xml file yourself:
    <core:init pattern="seam-ejb-ex/#{ejbName}/local"></core:init>
    Note the seam-ejb-ex part of that static jndi pattern string. You will have to replace this part of the string with the context root entry that was highlighted in the packaging module pom!

I hope this blog entry have cleared up some of the confusion that I met when I tried building Maven-based Seam/EJB projects. Please let me know if it works out and remember that you can download the full example and use it as a reference as you like.

20090420

DataCleaner 1.5.1 released

I'm happy to announce the release of DataCleaner version 1.5.1. This release is a minor release, nevertheless containing a few nice features - especially for the users who are enjoying the exporting features that was introduced in 1.5:

  • An additional HTML export format have been added to the built-in export formats (usable when exporting Profiler results in the desktop app and when executing the runjob command-line tool).
  • The export format is now choosable directly in the desktop app.
  • Four new measures where added to the String Analysis profile: avg. chars and max/min/avg white spaces.

The new version of DataCleaner is (as always) downloadable for free on the downloads page and feedback from users is also greatly appreciated, ie:

We hope that you all enjoy DataCleaner 1.5.1.