This page last changed on May 09, 2010 by alitokmen.
Using Maven2 and Cargo to merge WAR files
If you have an application that you are building with maven2 that you wish to merge two WAR files together, then you may wish to use the 'uberwar' mojo present in the cargo maven2 plugin.
An "uberwar" is a war file constructed from 2 or more War files, where the deployment descriptors in files such as web.xml have been combined.
Setting up your project to output an uberwar
Create a maven2 project whose output artifact is going to be the uberwar. Don't forget to add as dependencies the War files you're going to make the uberwar from.
Your packaging type should be uberwar:
<project xmlns="http:
xmlns:xsi="http:
xsi:schemaLocation="http:>
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycorp</groupId>
<artifactId>myproj</artifactId>
<packaging>uberwar</packaging>
<version>1.0-SNAPSHOT</version>
<!-- etc, etc -->
<dependencies>
<dependency>
<groupId>com.mycorp</groupId>
<artifactId>baseWarFile</artifactId>
<version>1.0</version>
<type>war</type>
</dependency>
<dependency>
<groupId>com.mycorp</groupId>
<artifactId>funkyApp</artifactId>
<version>1.0</version>
<type>war</type>
</dependency>
</dependencies>
</project>
Next, you need to add the cargo maven plugin to your plugins section, and set it up with the path to a merging descriptor:
<plugin>
<groupId>org.codehaus.cargo</groupId>
<artifactId>cargo-maven2-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<descriptor>src/assemble/merge.xml</descriptor>
</configuration>
</plugin>
PS: If you're experiencing issues with the plugin because Maven is telling you that some Xerces classes cannot be found, please also add xerces:xercesImpl to the plugin's dependencies. That error should not be happening as of Java 6.
The src/assemble/merge.xml is the descriptor of how you want the merge to work. For example:
<uberwar>
<wars>
<war>com.mycorp:baseWarFile</war>
<war>com.mycorp:funkyApp</war>
</wars>
<merges>
<merge>
<document>WEB-INF/classes/properties.xml</document>
<classname>org.codehaus.cargo.module.webapp.DocumentMerger</classname>
</merge>
</merges>
<webXml>
<contextParams>
<strategy name="ChooseByName">
<default>
<strategy name="Preserve"/>
</default>
<choice name="contextConfigLocation">
<strategy name="NodeMerge">
<context-param>
<param-name>$left:param-name</param-name>
<param-value>$left:param-value $right:param-value</param-value>
</context-param>
</strategy>
</choice>
</strategy>
</contextParams>
</webXml>
</uberwar>
The sections are described as follows:
wars
In order to know which war files to merge, and in which order (this is significant - for example, when you choose overwrite strategy), specify them in the <wars> section
merges
If you have files that need to be merged together by some kind of processor, then specify it here. The classname can be org.codehaus.cargo.module.webapp.DocumentMerger, which is a simple class that will merge by copying all xml nodes from the descriptor files. Alternatively, you can provide any class that is available on the classpath, provided it implements org.codehaus.cargo.module.merge.MergeProcessor.
You can have as many merge subsections as you need.
webXml
The webXml setting defines how the various sections in web.xml files will be merged. There can only be one webXml setting.
For each section, the descriptor is defining how you want the merge to happen (the 'strategy'). There are 4 out-of-the-box strategies, and you can provide your own by passing the name of a class that implements org.codehaus.cargo.module.merge.strategy.MergeStrategy. These strategies define what should happen if an entry is just in one file, or what to do if there is a conflict. When merging, each successive file is merged in sequence - so if there are 3 merges to do, the 1st two files will be merged together, then the result will be merged with the last file.
In each merge operation, the 1st of the two files is the 'left hand side', and the 2nd of the two files is the 'right hand side' (think of source code merge utilities).
The defaults supplied are:
Preserve
Preserve means "if there is a conflict, then preserve the original". Preserve is the default for any section if nothing else is specified.
Overwrite
Overwrite means "if there is a conflict, then use the values in the right-hand side".
ChooseByName
ChooseByName means "most of the time, I want to use one strategy, but for a particular named item, I want to do something else. In the above example, it is saying 'by default, I want to "Preserve" any context-params. But for the 'contextConfigLocation' parameter, I want to do something different (Node Merge).
You may only have one default strategy, but can have as many choices as you need.
NodeMerge
NodeMerge means "I want to do some merge resolution". The contents of this strategy is the XML that the conflicting node will be replaced with. Anything starting with $left: will be translated as an XPath expression, executed against the left-hand descriptor. The effect of $right: is the same, for the right-hand side.
In the example it is being used to append the config files specified in the right-hand descriptor into the config file (for example, spring configuration files).
Sections
Currently only the contextParams collection can be controlled for merging - this will be eventually extended to all the sections within the web.xml file.
Known Problems
If you build as a part of a multiproject build, maven2 may incorrectly store your output war file in the repository with a .uberwar extension. It does not do this if the project is built on its own.
|