Tuesday, June 10, 2008

Targeting JBoss Seam for Multiple Application Servers

Not all application servers are equal - something you realize quickly in a consultant's life working in different customer environments. The "developer friendliness" varies broadly here - I guess waiting for the container to deploy, go down and up again is a phenomenon many of the web developers out there know too well...

A stack that works for me very efficient is JBoss Seam on JBoss application server. Since its integration with JBoss Tools, the code-deploy cycle goes extremely smooth. But how can we leverage this while targeting other application servers?

After some experiments, I came up with a solution based on Maven. In general, the deployment of Seam distinguishes in library dependencies and some config files. For example is Hibernate the default persistence provider on JBoss, but not on WebLogic - but using Hibernate has the advantage of using Hibernate Validators, which integrates in Seam very comfortable with JSF validation. Maven allows to create different profiles, which contain different dependency sets tailored for another application server. The differences for running Seam in different containers are well described in the Seam documentation.

pom.xml:
<profiles>
<profile>
<id>weblogic10</id>
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate</artifactId>
<version>${hibernate.version}</version>
<exclusions> ... </exclusions>

...

</profile>
</profiles>
Integrating this in JBoss Tools turnes out to be a little trickier. The best approach seemed to be to start with a Seam project wizard in the Maven source structure:
  • Java Source Directory: src/main/java
  • Content Directory: src/main/webapp
The project needs then to be 'mavenized' by adding the Eclipse Maven 2 plugin if not already installed and a POM to the project. Getting the dependencies correct can be a little tedious with all the exclusions - best is to add just one by one and compare with the Web App Libraries that come out of the wizard. Once this is done, the libraries in WEB-INF/lib can be deleted and the Maven dependencies added in the Project J2EE Dependencies dialog. As a nice side-effect, this Maven setup makes it extremely easy to upgrade your libraries. For example, upgrading RichFaces from 3.2.0 to 3.2.1 was just a 1-character change in the POM!

We have now a clean separation between dependencies, but still the config files need different treatments. I went for a solution on adding three subfolders to src/main/resources:
  • common for, well, common resource files like message bundles and Drools rule files
  • jboss and e.g. weblogic for the files requiring different versions for applications servers, namely the components.xml and persistence.xml files (using Hibernate on WebLogic 10 requires a different configuration - the transaction manager lookup and the query factory class need to be changed).
This works now fine in JBoss Tools and you can start coding. Still, to run the Maven build we need some additional fixes as we changed the Maven default structure on the source files (JBoss Tools uses src/main/java/action and src/main/java/model) and on the resources:

pom.xml:
<build>
<sourceDirectory>
${basedir}/src/main/java/model
</sourceDirectory>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>${basedir}/src/main/java/action</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
This configures the two source folders in JBoss Tools - a little verbose, but Maven usually knows only one source folder. For the resource folders, we need to configure the build settings in the distinct Maven profiles:

pom.xml:
<build>
<resources>
<resource>
<directory>src/main/resources/common</directory>
</resource>
<resource>
<directory>src/main/resources/weblogic</directory>
</resource>
</resources>
</build>
We can now test for example the WebLogic profile in a continuous build, deploying the WAR file on an integration server.

The resulting project structure in Eclipse is shown in the screenshot below: