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.

17 comments:

Dan Allen said...

Thanks for putting together this sample. The Seam project just never got around to doing a nice Maven archetype in Seam 2. Archetypes will be created for Seam 3 (and maybe backported to Seam 2 at some point). You can see a really nice example of an EAR setup in the booking example.

http://anonsvn.jboss.org/repos/seam/examples/trunk/booking/

Kasper Sørensen said...

Hi Mojavelinux,

Although the booking example of Seam 3 might work nicely I certainly think it has one major drawback - it looks overly complex! The idea of my "recipe" for Maven-based Seam projects is to have a structure that easy to understand and maintain. I've been looking at the POM's of the booking example and I would guess that they are at least 5 times the size of a stripped down project - which is what I advocate for.

Anonymous said...

Okay for really simple projects, but it's missing some significant features: Testing, Deployment, Documentation and site generation.

Kasper Sørensen said...

The point isn't to include all possible feaures - quite the opposite. If you have a minimal but flexible project structure then it's very easy to plug these things in. This is totally in line with the Convention-over-Configuration philosophy of Maven.

The default testing, documentation and site generation are available but you can plug in your own as you like. The point is that a project structure or archetype shouldn't make these decisions for you - the POM's become confusing and you can't figure out the implifications of adding, reconfiguring or removing a maven-plugin to the project.

I disagree that my proposal is only fitting for simple projects - in deed I recommend it as an initial structure for enterprise projects. It's very unintrusive and IMO that's one of the most important things for a project strucure.

Misc said...

I'm not good at Maven, but I think what I'm going to suggest is very easy to do.

It'll be nice if you add some lines to your pom.xml so that an exploded version of the ear can be created (i.e. the war, the ejb jar and jboss-seam.jar are all in exploded format). The reason I need an exploded war is I can change xhtml files and have them effective without re-packaging.

Elio Marcolino said...

Hi Kasper!
Nice tutorial! I will try to use it to create a new project when i arrive at home.
I agree with you on your comment about "Convention-over-Configuration philosophy". Its a very clean structure and can be improved on demand.
Thank you for the good work!
See you!

Wouter Mouw said...

Thank you very much for the clear example. It was very helpful in starting a Seam/Maven project.

We had to make two adjustments to get the example to work:
1. Change sayHello in ejb-hello.xhtml to sayHello() (with the parentheses)
2. Change version of facelets dependency in web/pom.xml from 1.1.11 to 1.1.15.B1 to work with JBoss AS 5

Yaroslav Klymko said...

This sample works well with jsf 1.2. However I can't setup it using jsf 2.0

I'm getting ConfigurationException: Factory 'javax.faces.application.ApplicationFactory' was not configured properly.

com.sun.faces.config.ConfigurationException: Factory 'javax.faces.application.ApplicationFactory' was not configured properly.

Is there any way to fix this?

Kasper Sørensen said...

Must be a Seam and JSF 2.0 issue (not related to the Maven packaging). I haven't tried using Seam and JSF 2.0 together - is it even possible? It seems that a lot of the features of Seam have been implemented in the JSF 2 spec also so I think a mismatch is to be expected.

Bambitroll said...

I allowed myself to improve on your good work and added some persistence unit so one can actually save something to a DB table, and some sot of hot deploy (basic!). More here: http://minibiti.blogspot.com/2010/03/seam-20-and-maven.html

Unknown said...

Hi Kasper!

Thank you for mentioning all points of Seam-EJB-Maven configuration in one place.
It's really not that easy to figure out such tricky moments like packaging jboss-seam library as ejb.

Unknown said...

My colleague has pointed to http://code.google.com/p/open-archetypes/wiki/seamEarArchetype

It's a Java EE Seam archetype for Maven.

Website Design said...

Nice Blog I like it
Thanks from
osenu Technology Solutionz
Website Design

zcocorporation said...
This comment has been removed by the author.
Jan Groth said...

Thanks for putting this together, definitely a good help!

rayd said...

This was really helpful, thanks a lot. I've noticed a problem when using Maven 2 however -- if you build with "mvn package", the build fails because it could not resolve: dk.lungogbendsen.seam:SeamExample-packaging:ear:1.0

This seems to be a Maven 2 (Reactor?) problem of not being smart enough to resolve the dependency with one of the just-built sub-modules. I was wondering if anyone had a solution to this with Maven 2? (I know it works if I update to Maven 3, but in some of my environments I'm stuck with Maven 2. And it will work if I do a "mvn install" build -- though I was trying to avoid doing an install for every incremental little change to my project.) So any thoughts on getting this to work with "mvn package" with Maven 2?

André Lourenço said...

I have started working with JBoss Seam a couple of months ago and noticed that it's really hard to find simple and neat maven-seam-archetype. While searching for simple but complete archetypes, I stumbled with your article (http://kasper.eobjects.org/2009/04/seam-ejbs-and-ear-packaging-in-maven.html) which presented the closest archetype (that met my desires) that I could find.

So, based on your archetype, I developed the "Maven2-Seam-Generator", a jar that can easily generate a new maven2-seam project. It also provides instructions on how to import and deploy the generated EAR bundle to a JBoss AS using Eclipse.

I believe that this program could help a lot of people, so I would like to ask you to include it in your post (Please provide me an e-mail contact or contact me andrefigueiralourenco@gmail.com).

Thank you,


André Lourenço.