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.
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)
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>In the ejbs module you will not need any dependencies!
<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 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>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.
<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>
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>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:
<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>
- 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.