Thursday, May 1, 2008

Using Maven War Overlays to extend Hudson

I just recently found out about one of the neatest features of the maven-war-plugin called WAR Overlays. Basically it provides a very simple way to merge multiple WARs together to create an Uber WAR. You simply add a WAR as a dependency in your POM verses adding a JAR, and the maven-war-plugin will take care of the rest. My team uses this ability to extend the JSPWiki WAR to add in our wiki pages. The result is an Uber WAR including the JSPWiki stuff and our wiki pages. Then when a new JSPWiki WAR is available we just update the dependency version in our POM.

So for an example, I am going to demonstrate extending my favorite CI tool Hudson since it's freaking awesome and is downloaded as a WAR. Don't try this at home since hudson already provides the ability to extend it using plugins (which also rocks by the way).

Create a Simple WAR Project
First, create a war project using maven-archetypes. Execute mvn archetype:generate and select #18. Run mvn clean install to ensure it builds correctly (I am using maven v2.0.9).

Install hudson into local repository
Next we need to be able to consume the hudson war in our pom and since I am unware of the hudson war being available on any external repository we are going to just install it manually into our local m2 repository.

  • Download the latest hudson war
  • Install hudson.war into your local repository using the mvn install plugin by running: mvn install:install-file -Dfile=hudson.war -DgroupId=hudson -DartifactId=hudson -Dversion=1.0 -Dpackaging=war
Consume the hudson.war in your pom
Open up your war's parent pom and add the hudson war as a dependency.
<dependency>
<groupId>hudson</groupId>
<artifactId>hudson</artifactId>
<version>1.0</version>
<type>war</type>
<scope>runtime</scope>
</dependency>
Next, since we want to run hudson in embedded mode without a container we need to add to the generated manifest file the Main class since I am too lazy to figure out how to include the original hudson manifest file (even though I am sure its possible). Include the following in your build section:
<build>
<finalName>mywar</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifestEntries>
<Main-Class>Main</Main-Class>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
Build and Run it
Now build the war again: mvn clean install. And your WAR should be merged with the hudson war. In fact for verification, your simple war contained an index.jsp under src/main/webapp and if you extract the war under target you will see your index.jsp.

Run: java -jar target/mywar.war
and go to: http://localhost:8080/index.jsp

If you are doing this on a serious level, you might want to look into the maven-cargo-plugins ability to create Uber wars.

2 comments:

Brian Fox said...

Instead of copying the files to your repo by hand, you should use install:install-file (and deploy:deploy-file for remote repos)

This way is quicker, and can make a valid pom at the same time.

jlorenzen said...

Yep, you are absolutely correct. I will update accordingly thanks.