Showing posts with label maven. Show all posts
Showing posts with label maven. Show all posts

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.

20080417

Maven-ing your way around DataCleaner

There seems to be quite some frustrations for old ANT-users switching to use Maven so I thought I would make a small post about the main differences and various hacks that are useful to know as a Maven user. The good thing about ANT is that you can always hack your way around a problem and it's quite easy to find the problems that are stopping you. The bad thing is of course that the build-files seem to grow enormously and that you have to enforce your project infrastructure with some kind of common JAR-download area like a FTP or something similar. In contrast Maven focuses not on the build as a process, but more on the content of the build, because in 99% of the times the process of building a java project is pretty much the same, so why not omit the "how" completely and only focus on the "what" of your build? This "what" is configured in the pom.xml file!

Admitted, that was not my primary reason for choosing Maven! :) The thing that won me over was of course the dependency handling system which I really love and loathe a bit at the same time. What you need to be aware of about the dependencies is this:


  • Maven automagically creates a local repository for all the JARs you use in your projects.

  • There's also a central repository where maven will download the JARs from, if they are not found in the local one.

  • If you are working offline or behind a proxy and you need a new JAR you're bound to mess this up :( When Maven can't find it's JARs in the central repository or locally it will blacklist it!

  • You can however delete the blacklisting by removing (part of) the local repository, it is found in ~/.m2/repository...

    windows: C:/Documents and Settings/[username]/.m2/repository

    or linux: /home/[username]/.m2/repository).


OK, so that was the background-knowledge you had to know - now for some of the build goals. The mostly used maven goal is "install", oftenly prefixed with "clean", like this:

mvn clean install

The install goal will build the project, run the unittests, verify that everything worked and then install the resulting JAR/WAR/Whatever into your local repository. This means that you can then use the project as a dependency to another project, smart eh?
And now for some other commonly goals:

mvn site

Create a nifty project site with all sorts of nice information and reports (javadoc, unittests, codecoverage etc. depending on your configuration).

mvn install -Dmaven.test.skip=true

Ah, the "skip test" parameter. I spent a long time figuring that one out. This is handy if you're working with several projects at the same time and you've (consciously) broken the build and want to keep on using the dependency.

mvn jetty:run

My new DataCleaner-webmonitor favourite. This will bring up a Jetty container with DataCleaner-webmonitor running on localhost. This of course requires a little configuration in pom.xml, I'm sure you can figure it out, just find the plugin-elements that has to do with jetty :)