Useful Maven Plugins: Part 2

Exclusive offer: get 50% off this eBook here
Apache Maven 2 Effective Implementation

Apache Maven 2 Effective Implementation — Save 50%

Build and Manage Applications with Maven, Continuum, and Archiva

£14.99    £7.50
by Brett Porter Maria Odea Ching | September 2009 | Java Open Source

Read Part One of Useful Maven Plugins.

The Build Helper plugin

Within Maven, there are a number of common tasks which plugins can perform to alter the current project for changes occurring during the build. We have seen the inclusion of new resources in the Remote Resources plugin, and the attachment of a new artifact from the Shade plugin. It is also possible to have a plugin generate new source code and include it for compilation, even though the directory is not included in the POM file.

The role of the Build Helper plugin is to provide a set of goals that can help achieve a collection of small but common tasks for which it would not be worth writing a custom plugin.

Adding source directories

Maven's inability to have multiple source directories in the project model has often been called into question. However, as time has progressed the request has died down as the idea of a standardized source structure took hold.

The Build Helper plugin offers the ability to add another source directory or test source directory to that configured in the POM. This is not necessarily to allow a workaround for the deliberate limitation in the project model, but rather to facilitate other use cases that require it. The most common need to use this technique is to assist with the migration of a project in an existing layout to Maven temporarily.

Even with this capability it is still recommended not to add multiple source directories without a particular reason—apart from breaking with convention, you may find that some tools that operate based on the values in the POM will not recognize the additional directories as containing source code.

The following example illustrates the addition of a source directory:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>add-source</id>
<phase>generate-sources</phase>
<goals>
<goal>add-source</goal>
</goals>
<configuration>
<sources>
<source>src/main/more-java</source>
</sources>
</configuration>
</execution>
</executions>
</plugin>

The need to use the Build Helper plugin for adding sources is now becoming more rare. Maven plugins that generate source code would be likely to add the extra directory to the project internally without the need for additional configuration. If some other means is used to generate the sources—for example, from a scripting plugin—it is common for the scripting plugin to have a way to add the source directory with fewer configurations than using the Build Helper plugin. However, if the need does arise, the Build Helper plugin will prove itself useful.

Attaching arbitrary artifacts

A similar scenario that can occur is the generation of additional artifacts that need to be attached to the build process. This means they use the same POM to define them, but are different types of related build artifacts, with their own classifier. The artifacts are installed and deployed to the repository alongside the original.

Typically, this will be in the form of another JAR file, possibly generated by one of the scripting plugins that did not attach the artifact itself.

However, it could be used for any number of files that need to be stored in the repository alongside the main artifact. Consider the example of deploying the license to the repository—if you were to run the install phase on the given project, you would be able to have the license installed into the local repository alongside the main artifact and its POM.

In reality, this particular configuration may be overkill, especially if the licenses are identical across many projects, or can be derived from the POM. However, depending on your deployment needs this possibility can be helpful in ensuring the repository contains the information about an artifact that you need, at the time it was deployed, in addition to any extra build artifacts that might be generated.

In our example application, we generated the license in two places—in all the Java modules, and the final distribution. Deploying it along with the final distribution makes some sense, so let's add it to the distribution/pom.xml file:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.1</version>
<configuration>
<artifacts>
<artifact>
<file>
target/maven-shared-archive-resources/LICENSE
</file>
<type>txt</type>
<classifier>license</classifier>
</artifact>
</artifacts>
</configuration>
<executions>
<execution>
<goals>
<goal>attach-artifact</goal>
</goals>
</execution>
</executions>
</plugin>

This goal will execute after the packaging has occurred, but before installation so that it can be attached to the installation (and deployment) process. The file to attach is the license generated earlier by the Remote Resources plugin and is given an extension of .txt and classifier of -license. When running the install phase, we now see the file being processed:

[INFO] [build-helper:attach-artifact {execution: default}]
[INFO] [enforcer:enforce {execution: default}]
[INFO] [install:install]
[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/
pom-transformed.xml to /Users/brett/.m2/repository/com/effectivemaven/
centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-SNAPSHOT.pom
[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/
centrepoint-1.0-SNAPSHOT-bin.zip to /Users/brett/.m2/repository/com/
effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-
SNAPSHOT-bin.zip
[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/
centrepoint-1.0-SNAPSHOT-bin.tar.gz to /Users/brett/.m2/repository/com/
effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-1.0-
SNAPSHOT-bin.tar.gz
[INFO] Installing /Users/brett/code/06/centrepoint/distribution/target/
maven-shared-archive-resources/LICENSE to /Users/brett/.m2/repository/
com/effectivemaven/centrepoint/distribution/1.0-SNAPSHOT/distribution-
1.0-SNAPSHOT-license.txt

Other goals

The Build Helper plugin also contains some other goals in the latest release at the time of writing (v1.1) of more specific interest:

  • remove-project-artifact: To clean the local repository of artifacts from the project being built to preserve space and remove outdated files. This may occur if the build no longer produces those files, or if it is necessary to remove older versions.
  • reserve-network-port: Many networked applications may want to use a network port that doesn't conflict with other test cases. This goal can help reserve unique ports to use in the tests. This is useful for starting servers in integration tests and then referencing them in the test cases. However, note that it won't be available when running such tests in a non-Maven environment such as the IDE.

The goals available in the Build Helper plugin may increase over time, so if you have some small, common adjustments to make it is a good place to look to first for those utilities.

The AntRun plugin and scripting languages

Maven was designed to be extended through plugins. Because of the fact that this is so strongly encouraged, there are now many plugins available for a variety of tasks, and the need to write your own customizations, particularly for common tasks, is reduced. However, no two projects are the same, and in some projects, there are likely to be some customizations that will need to be made that are not covered by an existing plugin.

While it is virtuous to write a plugin for such cases so that it can be reused in multiple projects, it is also very reasonable to use some form of scripting for short, one off customizations.

One simple option is to use the AntRun plugin. Ant still contains the largest available set of build tasks to cover the types of customizations that you might need in your build, and through this plugin you can quickly string together some of these tasks within the Maven life cycle to achieve the outcome that you need.

Running simple tasks

We have already used the AntRun plugin in the distribution module of the example application. This snippet was used to copy some configuration files into place and create a logs directory, ready for the Assembly plugin to create the archive from:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.1</version>
<executions>
<execution>
<id>config</id>
<phase>process-resources</phase>
<configuration>
<tasks>
<copy todir="${project.build.directory}/generated-
resources/appassembler/jsw/centrepoint/conf">
<fileset dir="src/main/conf" />
</copy>
<mkdir dir="${project.build.directory}/generated-
resources/appassembler/jsw/centrepoint/logs" />
</tasks>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
</plugin>

This shows how quick and useful the AntRun plugin can be for simple tasks. However, it also contains a number of other features that can be of benefit to the build for more significant tasks.

Interacting with the Maven project

As we mentioned in the section, The Build Helper plugin, you can tell the plugin to map some directories to new source directories. This functionality is identical to that of the Build Helper plugin, but is more conveniently located when the directories are being generated by Ant tasks.

This can be useful because even though tools are increasingly supplying native Maven plugins in addition to Ant tasks, you might come across a source generation tool that only has an Ant task. In this scenario, you can use the AntRun plugin to run the tool, generate the source code, and use the sourceRoot parameter to have that directory added back into the build life cycle.

In addition to injecting source directories back into the life cycle, the AntRun plugin also injects Maven project information into Ant's context. Probably the most important of these is the availability of the project's and plugin's dependencies as Ant path references:

  • maven.compile.classpath: The dependencies in the compile scope (this syntax will look familiar to those that used Maven 1's built in Ant-based files)
  • maven.runtime.classpath: The dependencies in the runtime scope (including the above)
  • maven.test.classpath: The dependencies in the test scope (including both of the above)
  • maven.plugin.classpath: The dependencies of the AntRun plugin itself, including any added via the POM

Though we have not needed it in the example application, to illustrate how these two options would work, consider if you needed to use the XJC Ant task from JAXB to generate some sources.

JAXB is a Java-to-XML binding framework that can be used to generate Java source code from XML schema (among many other things), using its XJC tool. Though it serves as a suitable example here, you would not be faced with this issue with JAXB itself, as it now offers a Maven plugin.

In this example, you might add the following configuration to an AntRun execution in a POM file:

<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<id>xjc</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<taskdef name="xjc"
classname="com.sun.tools.xjc.XJCTask"
classpathref="maven.plugin.classpath" />
<xjc destdir="${project.build.directory}/xjc"
schema="src/main/jaxb/schema.xsd">
<classpath refid="maven.compile.classpath" />
</xjc>
</tasks>
<sourceRoot>${project.build.directory}/xjc</sourceRoot>
</configuration>
<goals>
<goal>run</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-xjc</artifactId>
<version>2.1.9</version>
</dependency>
</dependencies>
</plugin>

We see here that the XJC Task is defined using the plugin classpath to locate the task and its dependencies (and that task's artifact is added as a plugin dependency to accommodate this). Additional built-in Ant tasks would also be added as plugin dependencies (such as ant-nodeps).

AntRun and Ant versions

While in some cases they might be compatible, generally you should use the same version of the Ant optional tasks as the version of Ant itself. The version of Ant used by the plugin is predetermined by what it has been built against. In AntRun v1.3, that is Ant 1.7.1. To use a different version of Ant, consider a different version of the AntRun plugin.

Next, the task is run—being passed the project's dependencies and schema to generate the source code from. The source code is output to target/xjc, which is also added as a source directory by the AntRun plugin because of the configuration specified. As the task runs in the generate-sources phase, it is available for compilation in the same way as any other source code.

Again, the configuration of AntRun here has been relatively simple, and is completely integrated with the Maven artifact handling and build life cycle such that it would not likely be needed to write a plugin to wrap the tool completely if you were faced with this decision in your environment.

Apache Maven 2 Effective Implementation Build and Manage Applications with Maven, Continuum, and Archiva
Published: September 2009
eBook Price: £14.99
Book Price: £24.99
See more
Select your format and quantity:

Converting Ant or Maven 1 builds

The AntRun plugin can be most useful when it comes to converting an existing build from Ant or Maven 1 (if it used custom Ant-based plugins or maven.xml heavily).

The approach to converting such a build varies depending on the project. For some projects, it is easier to start over on the build and map in modules one by one, interacting via the repository. For others, it might be a matter of gradually turning the existing script into a POM file and using AntRun to execute the existing code for the unconverted parts, keeping the flow wrapped in the new Maven life cycle.

The topic of build conversion is available at http://www.maestrodev.com/better-build-maven.

Let's look at another example. The following execution might be added to the AntRun plugin, with the same pattern repeated for other such examples in different parts of the life cycle:

<execution>
<id>gen-src</id>
<phase>generate-sources</phase>
<configuration>
<tasks>
<ant antfile="build-migration.xml" target="gen-src" />
</tasks>
</configuration>
<sourceRoot>${project.build.directory}/gen-src</sourceRoot>
<goals>
<goal>run</goal>
</goals>
</execution>

In this source generation example, the previous build file is executed to perform a certain task. As before, the resultant directory is added back into the Maven project so that Maven can continue to control the build.

You will notice that the original script (perhaps broken up) is retained and called rather than pasting the script fragment into the POM. While either is acceptable (as long as the script does not contain multiple targets), it is a good idea to keep the POM as trim as possible. Unless the Ant script is just one or two lines long, it is better to put those commands into an external build file to execute.

This advice applies even if not performing a build conversion. If your Maven build contains script fragments that are longer than a few lines, consider placing them outside of the POM file. However, bear in mind that in doing so it will not be available when reading the POM from the repository later.

In some conversions, a particular task may be reusable in multiple places or projects (particularly if migrating a Maven 1 plugin). In this case, instead of the AntRun plugin, you may consider writing your own plugin for the task. Luckily, to reduce the work involved Maven also offers the ability to run plugins written in Ant.

Maven plugins written in Ant

While the AntRun plugin offers a convenient way to string some simple tasks together, as with any part of the build process in Maven it is worth taking into consideration a simple rule of thumb: if you might use it twice, consider writing a plugin.

Of course, if you do take that step, it is not required to write the plugin in Ant. However, having the option available is useful as:

  • It will be easier to use for converting from a previous Ant/Maven 1 build
  • Ant tasks may be more familiar to your team than writing Maven plugins in another language
  • It can be easier to put together a set of Ant tasks for certain procedures than to write the corresponding code in another language such as Java

The process for creating Ant plugins involves the following steps:

  1. Create a Maven project of type maven-plugin.
  2. Add the maven-plugin-plugin to the build section, including a plugin dependency on maven-plugin-tools-ant.
  3. Add an Ant build script for each goal to src/main/scripts directory under the name goalName.build.xml. This should be a completely executable Ant script containing one target definition.
  4. Add a Mojo definition for each goal to src/main/scripts directory under the name goalName.mojo.xml. This defines the mapping of Maven information to the Ant target.

Plugin authoring (in Ant or other languages) is not something we will go into detail on in this article. For more information on writing plugins in Ant, see the documentation: http://maven.apache.org/guides/plugin/guide-ant-plugindevelopment.html.

Other scripting languages

While this section has focused on Ant as one of the most common scripting tools for builds, it is worth noting that other scripting languages can be used both for executable fragments (such as the fragments that AntRun is used for) and whole plugins (such as the Ant plugin tools are used for).

If you have expertise in a particular scripting language, and would like to use that for your own plugins or to add fragments to the build, you might consider one or more of the following projects:

  • GMaven: This is a mature solution for writing plugins in Groovy, and running Groovy scripts from the POM. For more information, see http://groovy.codehaus.org/GMaven.
  • JRuby Maven Plugin: This is an early but functional tool for writing plugins in JRuby, or running Ruby scripts from the POM. For more information, see http://mojo.codehaus.org/jruby-maven-plugin/howto.html.
  • Script Maven Plugin: This uses BSF (Bean Scripting Framework) for running scripts in other languages directly from the POM. Supports a larger number of languages, but does not allow the creation of native Maven plugins from the source. For more information, see http://mojo.codehaus.org/script-maven-plugin.
  • At the time of writing, the Script Maven Plugin has not had an official release and needs to be built from source.

The Exec plugin

In some build situations, the best (or only!) way to get something done might be to run an external application, or a piece of Java code. It was for this purpose that the Exec plugin was created.

The plugin contains two goals: exec:exec and exec:java. They are similar in purpose, however the java goal sets up an easier way to pass Java configuration and execution parameters to a forked JVM instance, whereas the exec goal simply runs any executable available on the system.

To use the exec goal, you pass the path of the executable program in the executable configuration option, and optionally can add the environmentVariables or arguments configuration to run the command as desired.

Portability

Keep in mind the question of portability when using the exec goal. Some executables may not be available on all platforms that the build will run on. You may need to clearly state the requirement in the build's documentation, gracefully degrade the functionality, or use a profile to run a different executable on a different platform.

In contrast, the java goal automatically locates the JVM executable to run, and instead you provide the mainClass configuration option. The arguments configuration can again be given, but can also include a classpath option that helps construct Java -classpath arguments from the Maven build (though it is also possible to pass this to the exec goal if you happen to be running a particular java executable with it). You may also configure systemProperties for the plugin to pass to the forked JVM instance.

By default, the java goal will construct its base classpath from the current project's dependencies, though it is also possible to have it pass the plugin's dependencies as well or instead of the project dependencies. For more information on configuring either of the plugin goals, refer to the plugin website at: http://mojo.codehaus.org/exec-maven-plugin.

Both of these goals provide a useful way to run external processes, depending on what type of application it is. However, the context that it will be used in is also important. For execution there are often two scenarios—integrating the external process into the build life cycle (much like the examples we have seen with AntRun previously), or pre-configuring the plugin to be able to be run from the command line for a given project.

Adding the Exec plugin to the Build life cycle

In the first scenario, there may be an external tool or Java application that needs to be run at a certain point in the build for which the plugin should be configured. This occurs in the same way as for any other plugin, using a particular execution.

In The AntRun plugin and scripting languages, we looked at running the XJC tool from Ant. Another alternative could be to run the tool from the command line (assuming it had been pre-installed in the path):

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<executions>
<execution>
<id>xjc</id>
<phase>generate-sources</phase>
<goals>
<goal>exec</goal>
</goals>
<configuration>
<executable>xjc</executable>
<arguments>
<argument>-d</argument>
<argument>${project.build.directory}/xjc</argument>
<argument>src/main/jaxb/schema.xsd</argument>
</arguments>
<sourceRoot>${project.build.directory}/xjc</sourceRoot>
</configuration>
</execution>
</executions>
</plugin>

For this particular scenario of source generation, the Exec plugin also contains a sourceRoot and testSourceRoot parameter for adding any generated sources into the build for later—exactly like the AntRun plugin.

Notice in the example that the confi guration is inside the execution element, and therefore will not be able to be run from the command line. This is usually the best course of action when binding to the life cycle so that multiple instances are possible.

Running the Exec plugin standalone

There are also a number of uses for running the Exec plugin directly from the command line. This might be used with a particular project, or run independently.

A common reason to use this approach is if a particular Maven project produces an executable JAR—we looked at such an example with the Shade plugin earlier. By pre-configuring the Exec plugin with the necessary information, the JAR can be easily run by Maven itself. The following POM snippet from the Archiva XMLRPC Client illustrates this:

<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.1.1</version>
<configuration>
<mainClass>
org.apache.archiva.web.xmlrpc.client.SampleClient
</mainClass>
<arguments>
<argument>http://127.0.0.1:8081/xmlrpc</argument>
<argument>admin</argument>
<argument>${password}</argument>
</arguments>
</configuration>
</plugin>

Here, the project dependencies are included and the given arguments passed to the main function of the class specified. Notice that in contrast to the previous example, the configuration is not in an execution, both because it is not bound to the life cycle, but also so that it can be run from the command line.

Executing this is now a matter of running the following command:

$ mvn exec:java -Dpassword=ADMIN_PASSWORD

Clearly, this is much easier to remember than the full set of arguments!

In similar scenarios, the Exec plugin can become very useful in being able to give a simple demonstration or quick use of an application while in development. In some ways, it can be compared to jetty:run for web applications as bringing the same functionality to executable standalone applications.

Summary

Once you have the right framework in place with Maven, it is a matter of finding and selecting the right combination of plugins to assemble your build from there on. Here, we have seen a selection of such plugins to help achieve some common builds goals.

The list doesn't stop here though. If you are looking to integrate a particular tool or framework into your build, see if a plugin is already available for it. A number of plugins such as the Dependency plugin, Enforcer plugin, Assembly and App Assembler plugins, have more goals and configurations that are worth investigating as well. If you have some other needs that might apply to multiple builds, search for a plugin to serve that case, or beyond that write one yourself in a scripting language, as a set of Ant tasks, or your own Maven plugin. Online Maven repository search engines can be helpful in finding other plugins to use.

[ 1 | 2 ]
Apache Maven 2 Effective Implementation Build and Manage Applications with Maven, Continuum, and Archiva
Published: September 2009
eBook Price: £14.99
Book Price: £24.99
See more
Select your format and quantity:

About the Author :


Brett Porter

Brett Porter is a software developer from Sydney, Australia with a passion for development tooling, and automation. Seeking a more standardized and reproducible solution to organize, build, and deploy a number of software projects across teams, he discovered an early beta of Maven 1.0 in 2003, and has been heavily involved in the development of the project since. He is a member of the Apache Maven Project Management Committee, and has conducted presentations and training on Maven and related tooling at several conferences and events. He founded the Archiva project in 2005. Brett is also a member of the Apache Software Foundation.

Brett is currently VP, Product Development at G2iX, in charge of the Maestro division. He and his team seek to make developers more efficient by offering support and services for development and automation tools including Apache Maven, Apache Continuum, Apache Archiva, and Selenium.

Brett was co-author of the book Better Builds with Maven, the first book to be written about the Maven 2.0 release in 2005, and has been involved in reviewing Maven: A Developer's Notebook and Java Power Tools.

Maria Odea Ching

Maria Ching grew up in a small town called Daet, then moved to Manila when she went to college. She took up Computer Studies at De La Salle University and graduated in 2005. She started using open source tools from her first job after graduating and from then on, got interested in everything open source. When she came to work for Exist, she got assigned in a project doing a lot of development work in open source projects, specifically Maven, Continuum, and Archiva. Back then, Continuum and Archiva (formerly named Maven Repository Manager) were still sub-projects of Maven. Eventually, she became a committer, then a PMC member of Maven. In 2008, Continuum and Archiva became top-level projects at the ASF and Deng was elected as PMC Chair of Archiva. She is still currently serving as PMC Chair of the project and as PMC members of Continuum and Maven.

Books From Packt

 

Drupal 6 Site Blueprints
Drupal 6 Site Blueprints

Solr 1.4 Enterprise Search Server
Solr 1.4 Enterprise Search Server

Papervision3D Essentials
Papervision3D Essentials

Pentaho Reporting 3.5 for Java Developers
Pentaho Reporting 3.5 for Java Developers

Joomla! 1.5x Customization: Make Your Site Adapt to Your Needs
Joomla! 1.5x Customization: Make Your Site Adapt to Your Needs

JasperReports 3.5 for Java Developers
JasperReports 3.5 for Java Developers

LWUIT 1.1 for Java ME Developers
LWUIT 1.1 for Java ME Developers

WebSphere Application Server 7.0 Administration Guide
WebSphere Application Server 7.0 Administration Guide

 

Code Download and Errata
Packt Anytime, Anywhere
Register Books
Print Upgrades
eBook Downloads
Video Support
Contact Us
Awards Voting Nominations Previous Winners
Judges Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software
Resources
Open Source CMS Hall Of Fame CMS Most Promising Open Source Project Open Source E-Commerce Applications Open Source JavaScript Library Open Source Graphics Software