JAM Plugin - Maven-to-Ant Bridge

The JAM plugin transforms low-level procedural Ant into a high-level descriptive build framework by providing a Maven-to-Ant bridge. The plugin automatically handles:

  • Classpath, resource and deployment descriptor details.
  • Library storage and version management in a local repository.
  • Automatically downloading libraries from Maven's remote repository to your local repository.

For each build file (build.xml), you maintain a corresponding POM file (project.xml) which is used to generate properties, classpath and distribution files (props-maven.xml, classpath.xml and application.xml). You only need to generate these files when your POM file changes, after which you can work in a pure Ant environment.

Plugin Goals

The most useful plugin command or goal in Maven-speak is

	maven jam

which produces the most frequently used generated modules: props-maven.xml and classpath.xml.

There are several commands to generate application.xml deployment descriptors, but the most flexible is

	maven jam:appxml-filter

The resulting EAR deployment descriptor contains a @TARGET-MODULE@ replacement tag which is then automatically processed by JAM or can be customized to suite your requirements. This file is placed in the src-gen/META-INF sub-directory and can be moved to src/META-INF to avoid being overwritten.

See the goals page for the complete list or from the command prompt type

	maven -P jam

Plugin Customization

The plugin's behavior can be customized by setting various plugin properties.

Automatic POM Synchronization

When you update your POM, the files generated by JAM's plugin must be updated as well. This can be done automatically by importing maven-synch.mxl into your build file and adding the appropriate target dependency early in the build process.

...
<!-- ===================================================================== -->
<!-- import properties and ant modules -->
<!-- ===================================================================== -->
<import file="${basedir}/src/jam/props-maven.xml"/>
<import file="${jam.home}/props-global.xml"/>
<import file="${basedir}/src/jam/classpath.xml"/>
<import file="${jam.home}/appserver-tomcat5.xml"/>
<import file="${jam.home}/webapp.xml"/>
<import file="${jam.home}/maven.xml"/>
<import file="${jam.home}/maven-synch.xml"/>
<!-- =================================================================== -->
<!-- Override public targets: -->
<!-- =================================================================== -->
<target name="gen" depends="jam.synch, appxml-filter.synch, init, webdoclet"/>
...

The one limitation of maven-synch.mxl is that when it regenerates props-maven.xml or classpath.xml it forces the build to fail because it can not re-import these files once execution has begun. The build will execute normally on subsequent calls.

In continous integration envirenments this behaivor is probably not exceptable. The work-around is to call your build from a master build file (say build-synch.xml) separating the synchronization and build steps into separate calls. This example achieves this by wrapping the jam.synch target in a subant call with failonerror set to false:

...
<target name="synch">
	<subant buildpath ="." target="jam.synch" failonerror="false"/>
</target>
<target name="dist" depends="synch">
	<subant buildpath ="." target="dist"/>
</target>
...