Saturday, September 27, 2008

Building enterprise applications with Maven to use optional packages


The Java 1.3 feature of optional packages introduced support for an expanded set of Jar-file manifest attributes that enable an application jar to specify its list of dependencies on other jars. Maven can generate a jar and build a manifest automatically for you so that you can leverage optional packages deployed in your environment (whether it be the classpath or jars deployed in an application container). If you are looking to build and deploy an application EAR that has dependencies on a slew of 3rd party libraries, you can deploy the 3rd party libraries as optional packages and cut down on the size of your EAR file across many applications. The reuse of these 3rd party jars across multiple Web or enterprise application deployments becomes really handy if you want all these applications to do a common upgrade to a different version for their dependent library. So how do you tell Maven to do this? Here's an example of a Web application POM file. Within the build section, specify the following snippet -

<plugins>
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addExtensions>true</addExtensions>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>


However, while building this WAR file, the dependencies will still get pulled in unless you specify another attribute on your dependencies. Example here - if you have a dependency on aspectj and aspectj is deployed to your container, say Weblogic10, as an optional package, then in your POM for your WAR file, you would specify the following -

<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.6.0</version>
<!-- <scope>provided</scope> -->
<optional>true</optional>
</dependency>

The attribute that's important in this snippet is the "optional" attribute, the presence of which will omit the file from being included in the WAR file. The omission of the file is not the only thing that is important here. The "scope" element is also important. There are some specific rules that Maven follows when generating the manifest based on the "scope" and "optional" tags that you need to understand. Here's their docs that shows a table that helps clearly explain the relationship between these 2 attributes. In the above example, while the optional element will will exclude the jar from being added to the WAR file, the scope element will also cause the jar's extension name to be omitted from the MANIFEST - something you probably do not want if you are looking to leverage optional packages deployed.

A jar file deployed as an optional package essentially needs to have 3 properties in its manifest file -

Extension-Name: asjpectj
Specification-Version: 1.6.0
Implementation-Version: 1.6.0

The manifest file built by Maven will put the extension name of the dependent jar in the "Extension-List" property of the manifest of your WAR file. It will also put the implementation version. You have to make sure that both these attributes match with those of the deployed optional package (i.e. in this example the aspectj jar). Otherwise, you'll probably get a ClassNotFoundException. As long as you get the extension name and implementation version of the optional package the same as what Maven generates in the manifest of the dependent WAR, everything will work and deploy without a problem. Take a look at this article for Weblogic to understand the constraints on naming for optional packages.

While the above is tedious at first, it becomes a very efficient way of managing application dependencies in enterprise production systems once you get everything working and lined up. I actually created a Swing tool that takes an EAR file that has all the dependencies in it and spits out the jars converted into optional packages that Maven understands. All you really have to do is take the version information from the name of the jar and put it into the Specification(as long as this contains only digits eg. "1.1.2" ) and implementation properties of the jar's manifest.

Though your initial effort to get everything setup will take a little bit of time, it will be well worth it. So give this operational efficiency a try.....