Book Image

Apache Maven 2 Effective Implementation

By : Brett Porter, Maria Odea Ching
Book Image

Apache Maven 2 Effective Implementation

By: Brett Porter, Maria Odea Ching

Overview of this book

<p>By building up a sample application, this book guides developers painlessly through building a project with Maven. This book shows you how to combine Maven with Continuum and Archiva, which will allow you to build an efficient, secure application and make developing in a team easy.<br /><br />You may already be aware of the pitfalls of 'integration hell' caused by changed code being submitted to repositories by a number of developers. When you implement Continuum in your build, you can easily perform continuous integration, avoiding timely rework and reducing cost and valuable time. You will be able to use Maven more efficiently in a team after you learn how to set up Archiva, Apache's repository manager.<br /><br />It's easy to quickly get to work with Maven and get the most out of its related tools when you follow the sequential coverage of the sample application in this book. A focus on team environments ensures that you will avoid the pitfalls that are all too common when working in a team. Soon, by learning the best practices of working with Maven, you will have built an effective, secure Java application.</p>
Table of Contents (21 chapters)
Apache Maven 2 Effective Implementation
Credits
About the Authors
About the Reviewers
Preface
Free Chapter
1
Maven in a Nutshell
Index

Reactor project selection


Maven 2.1.0 introduced additional command line options for defining a subset of the modules to build in a multi-module project. These choices can make regularly building a part of a project much more efficient during development.

We will look at these examples in the context of the final application structure that we built in Chapter 3, Building an Application Using Maven. Refer to the sample code for that chapter to try these for yourself.

Resuming a failed build

The first mode of operation is when we want to resume a previous build. This is most helpful when a build fails after some time in the middle of the list of modules, where we fix the issue and then wish to continue from the same point, knowing that any previously built modules are not affected.

Consider the reactor build order for Centrepoint when all default modules are built:

[INFO] Reactor build order: 
[INFO]   Centrepoint
[INFO]   Centrepoint Documentation Skin
[INFO]   Centrepoint Java Modules
[INFO]   Centrepoint Data Model
[INFO]   Centrepoint Data Store API
[INFO]   Centrepoint Maven Project Importer
[INFO]   Centrepoint Data Store (Flat file)
[INFO]   Centrepoint Web Application
[INFO]   Centrepoint Documentation
[INFO]   Centrepoint Distribution

Now, let us say we encounter a broken test in the Maven Project Importer module. Rather than building all of the modules again, we can continue from the same point:

centrepoint$ mvn -rf modules/maven-importer install

The -rf argument (which is short-hand for the argument --resume-from), specifies a single directory of the module to continue building from. The order used in the next build will match the previous execution, as we can see:

[INFO] Reactor build order: 
[INFO]   Centrepoint Maven Project Importer
[INFO]   Centrepoint Data Store (Flat file)
[INFO]   Centrepoint Web Application
[INFO]   Centrepoint Documentation
[INFO]   Centrepoint Distribution

This option can also be used for building a subset of the modules when you know the others have not been affected during development. However, there is a better set of options. These do not require building all of the modules in the existing order if they are unaffected.

Building a subset of modules

The other mode of operation available allows the direct specification of the module(s) to build, and corresponding type of dependencies to include.

This is achieved using the -pl argument (or alternatively, --projects) followed by a comma-delimited list of directories of the modules to build.

Tip

You can also use the groupId:artifactId syntax instead of a directory to define a module to build (which also works in the --resume-from argument). However, this is typically going to be longer to type!

For example, to build just the model and documentation modules, you can run the following command:

centrepoint$ mvn -pl modules/model,documentation install

As you can see, only those modules are built:

[INFO] Reactor build order: 
[INFO]   Centrepoint Data Model
[INFO]   Centrepoint Documentation

However, this is rarely the complete build that you would want to run. Changing the model potentially affects the testing of the modules that depend on it such as the data store, and even more importantly, the web application and distribution need to be rebuilt to include the updated library.

To ensure that these modules are included, we can add the -amd (or --also-make-dependents) argument to Maven:

centrepoint$ mvn -amd -pl modules/model,documentation install

As you can see, all of the modules described above that depend on the model are now included in the reactor build:

[INFO] Reactor build order: 
[INFO]   Centrepoint Data Model
[INFO]   Centrepoint Data Store API
[INFO]   Centrepoint Maven Project Importer
[INFO]   Centrepoint Data Store (Flat file)
[INFO]   Centrepoint Web Application
[INFO]   Centrepoint Documentation
[INFO]   Centrepoint Distribution

This argument is quite helpful in consistently building a subset of the application when one or more modules have been changed and not everything is needed again. In this example, we have just skipped the parent modules and skin, but if we were building a module with fewer dependencies then the list would be much shorter.

Note

If we were to remove the documentation from the project list in this command, it would not be built, as it has no dependency (direct or indirect) on the model.

Now, consider the opposite use case. Let us say that we had just checked out the project and wanted to build the Maven Project Importer library. That depends on some other libraries, but we do not want to build the web application and distribution that are later in the chain.

For this purpose, we have the -am (or --also-make) argument. When added to the project list argument, it will add to the reactor any modules that are required to build the requested projects.

To illustrate the example stated above, run the following command:

centrepoint$ mvn -am -pl modules/maven-importer install

As you can see, the parent projects and dependencies of the importer module are built, but no other modules are:

[INFO]   Centrepoint
[INFO]   Centrepoint Java Modules
[INFO]   Centrepoint Data Model
[INFO]   Centrepoint Data Store API
[INFO]   Centrepoint Maven Project Importer

A final note: the -am and -amd options can also be used together to include the dependencies in both directions in the reactor build. Consider the following command:

centrepoint$ mvn -am -amd -pl modules/maven-importer install

When this is executed, the union of the above two lists of modules are included:

[INFO]   Centrepoint
[INFO]   Centrepoint Java Modules
[INFO]   Centrepoint Data Model
[INFO]   Centrepoint Data Store API
[INFO]   Centrepoint Maven Project Importer
[INFO]   Centrepoint Data Store (Flat file)
[INFO]   Centrepoint Web Application
[INFO]   Centrepoint Distribution

Modules that are unrelated to the importer module such as the documentation and skin are not built in this scenario.

The Reactor plugin

For those using versions earlier than Maven 2.1.0, the above functionality is available through the Reactor plugin. As you'll see below, the plugin also offers an additional goal (reactor:make-scm-changes) that is not available above and which will still be of use to users of Maven 2.1.0 and above.

A complete reference to the plugin can also be found at http://maven.apache.org/plugins/maven-reactor-plugin/.

While the plugin can still be used in newer releases of Maven, it has some drawbacks in comparison to its command line counterpart:

  • It is slower as it has to run Maven to find the modules to build, then run a new Maven instance with the restricted number of modules

  • Longer syntax to type

  • The ordering used for resumed builds can sometimes be different to the one used originally

Let us take a look at the examples from above and how they would be applied using the Reactor plugin.

The corresponding goal to resume a failed build is reactor:resume, passing a from parameter that specifies the directory of the module to resume from. Our example above for the -rf argument would instead be run using:

centrepoint$ mvn reactor:resume -Dfrom=modules/maven-importer

As you can see, this is a considerably longer command to type than the example presented earlier if it is available!

We should note that as we are running a goal from Maven, we can't select the goals to run as we did with the command line version. To address this, all of the goals in the Reactor plugin support passing in the goals argument, which defaults to install. For example, to resume using the clean deploy goals instead, use the following:

centrepoint$ mvn reactor:resume -Dfrom=modules/maven-importer \
               -Dgoals="clean deploy"

There is no direct goal that represents the -pl option from the command line on its own, but rather two goals reactor:make-dependents and reactor:make that represent the two alternative switches -amd and -am respectively. To supply the projects that would be specified by the -pl argument, both goals take the argument -Dmake.folders.

Therefore, we have the following example corresponding to that of -amd above which will build the model and documentation modules and everything that depends on them:

centrepoint$ mvn reactor:make-dependents \
               -Dmake.folders=modules/model,documentation

Likewise, there is the following corresponding to the -am argument that builds the importer and everything that it depends on:

centrepoint$ mvn reactor:make \
               -Dmake.folders=modules/maven-importer

There is no corresponding command available to build both lists simultaneously as was possible with the combination of the -am and -amd arguments shown previously.

Building modules with local changes

The additional goal that exists in the Reactor plugin, but not the command line, is the reactor:make-scm-changes goal. The purpose of this goal is straightforward – to rebuild all modules that have had some local changes that are not committed.

The goal is simply run as:

centrepoint$ mvn reactor:make-scm-changes

To determine what to build, the plugin uses the Maven SCM library to run a status check, much like the Release plugin does before proceeding with a release. These are then collapsed into the list of modules affected, which form the project list to build. The build then continues with these modules, and any modules that depend on them.

Note

At present, changes to the POM in the directory where the goal is run are not detected. If this is the case, assuming all modules use that POM as the parent, then you can simply run mvn install to get the same behavior!

As with the previous goals, it is possible to customize the goals that are run using the goals command line parameter. The default is to run install.