Automating Maven project builds using the jetspeed:mvn Maven Plugin

The jetspeed:mvn Maven Plugin is a general purpose plugin for automating and coordinating specific integration tasks using the Maven build environment itself. This plugin provides support for "running" one or more custom Maven project build definitions using predefined set of goals, profiles, Maven settings and runtime properties.

The rationale for running custom Maven project build definitions besides the standard Maven project definitions and build lifecycle is described in The need for a custom Maven lifecycle.

The jetspeed:mvn plugin is based upon and adapted from the standard Maven Invoker Plugin, which is (only) targetted at running integration test projects as attached to the integration-test lifecycle phase.

The jetspeed:mvn expands upon the Invoker Plugin by allowing to be invoked directly from the commandline as well as providing a more generic and configurable chain of execution targets, similar to Apache Ant build scripts, but fully using and delegating to standard Maven-2 project build lifecycle handling for the actually execution of the individual target tasks.

Other than allowing execution from the commandline and the enhanced configuration options, the jetspeed:mvn doesn't really provide new behavior compared to the standard Maven Invoker Plugin and uses the same Maven API and components (the shared maven-invoker component).

This plugin doesn't depend in any way on Jetspeed-2 itself and as such is equally usable for other type of projects with similar need for performing tasks besides the normal Maven build lifecycle. Additionally, this plugin can also be used for "just" automating the standard Maven build tasks accross multiple projects using the Apache Ant like chained target definition configurations.

Quick Overview

The jetspeed:mvn plugin when invoked will execute a single target task defined in its plugin configuration. But, because a target can have a "depends" configuration itself, this might actually result in a chain of targets to be executed up the originally specified target itself.

This is a listing of all the elements which can be configured for the jetspeed:mvn plugin:

<plugin>
  <groupId>org.apache.portals.jetspeed-2</groupId>
  <artifactId>jetspeed-mvn-maven-plugin</artifactId>
  <version>${org.apache.portals.jetspeed.version}</version>
  <configuration>

    <targets combine.children="append">
      ...
      <target>
        <id>...</id>
        <depends>...</depends>
        <name>...</name>
        <dir>...</dir>
        <goals>...</goals>
        <profiles>...</profiles>
        <properties>
          ...
        </properties>
        <settingsFile>...</settingsFile>
        <mavenOpts>...</mavenOpts>
      </target>
      ...
    </targets>
    <defaultTarget>...</defaultTarget>
    <useSettings>...</useSettings>
    <properties>
      ...
    </properties>
    <mavenOpts>...</mavenOpts>

  </configuration>
</plugin>

Default plugin configuration

As can be seen from the above configuration overview, the primary configuration element is the list of targets and the target elements themselves.

<targets combine.children="append">

One important and essential part of the configuration is the combine.children="append" attribute specified for the targets element.

Maven 2 plugin configuration parsing (using Xpp3) by default merges configuration elements for children elements if not defined! This default behavior allows to only define overriding properties for a certain configuration element.

But, for the target configurations this is not very convenient because it requires to specify all optional properties for a task element to prevent "merging in" property values from unrelated previously defined target elements.

To solve this inconvenience, a combine.children="append" attribute can be specified on a parent element to use append instead of merge when parsing the child elements.

So, make sure to always use <targets combine.children="append"> to ensure a target configuration is actually parsed as specified!

General options

Besides the targets, a few additional (all optional) configuration elements can be specified:

Element Description
defaultTarget The intended usage of the jetspeed:mvn is to specify a target on the commandline using $mvn jetspeed:mvn -Dtarget=<target id>.
If there is a real need for a default (and thereby very common) target, its id property can be specified here which will then be used if no commandline parameter is specified.
useSettings default: true
The optional usage of custom Maven settings for the execution of a specific target will be explained further below, but this setting determines the default lookup and usage of a jetspeed-mvn-settings.xml file if for a target no specific settingsFile itself is configured.
properties The usage of runtime properties provided to the Maven execution environment of a specific target will be explained further below, but global properties (which can be overridden) to be used for all targets can be configured here.
The format for definining properties is the same as used for standard Maven project properties:
                <property-name>value</property-name>
mavenOpts default: none
Default Maven runtime options to be set for a target execution environment can be specified here. For a specific target these can be overrridden with its own mavenOpts configuration.

Target configuration

The execution of a target in a separate Maven environment requires three different sets of parameters:

  • the target itself and the possible other targets it depends on
  • the (custom) Maven project file to be invoked
  • the goals, profiles, settings and runtime properties to be used

target identification and its dependencies

A target is uniquely identified (within the scope of the current project) by its required <id/> element:

<target>
  <id>aTarget</id>
  ...
</target>

Optionally, dependencies on other targets can be specified with a <depends/> element using a comma separated list of other target id values:

<target>
  <id>target1</id>
  <depends/>
  ...
</target>
<target>
  <id>target2</id>
  <depends>target1</depends>
  ...
</target>
<target>
  <id>target3</id>
  <depends>target1,target2</depends>
  ...
</target>

The above example specifies that target2 depends on target1 and target3 depends on both target1 and target2.

This indicates that when target3 is to be executed, target1 and target2 need to be executed first (and in that order).

When a target dependency chain is resolved, the dependencies will be invoked in order as defined, whereby a single target will only be executed once, even if multiple dependent targets define a dependency on the same other target.

With the above example, the actual execution order thus will be: target1,target2,target3, not: target1,target1,target2,target3

This means that for the above example target3 actually can be defined even simpler as target2 already depends on target1:

<target>
  <id>target3</id>
  <depends>target2</depends>
  ...
</target>

target Maven project file

Which (custom) Maven project file is to be invoked for a target is determined from the (both optional) name and dir elements:

<target>
  <id>dbInit</id>
  <name>db</name>
  <dir>@rootdir@/my-portal</dir>
  ...
</target>

The name element is used to resolve a custom Maven project file named: jetspeed-mvn-${name}-pom.xml.

The dir element is used to resolve the location of the determined target Maven project file.

name and dir not defined

If both name and dir are not defined, jetspeed:mvn will do nothing for this target, but will execute the targets which it depends on, e.g. executing:

$mvn jetspeed:mvn -Dtarget=target3
using the following configuration:
<target>
  <id>target1</id>
  <depends/>
  <name>pomA</name>
  ...
</target>
<target>
  <id>target2</id>
  <depends>target1</depends>
  <name>pomB</name>
  ...
</target>
<target>
  <id>target3</id>
  <depends>target2</depends>
</target>
will still result in pomA and pomB to be invoked.

only dir defined

If only dir is defined, jetspeed:mvn will lookup the standard Maven pom.xml in the specified directory.

The file lookup is done relative to the current working directory, e.g. the Maven project in which jetspeed:mvn is invoked.

Alternatively, an absolute directory can be specified too, or the special @rootdir@ variable can be used (see below).

Hint: to invoke the default Maven pom.xml in the current directory, specify <dir>./</dir>.

only name defined

If only name is defined, jetspeed:mvn will look for a custom Maven project file named jetspeed-mvn-${name}-pom.xml first in the current Maven project directory, and if not found search for it upwards in the parent project(s) of the current Maven project.

both name and dir defined

When both name and dir are defined, the custom Maven project file named jetspeed-mvn-${name}-pom.xml has to exist in the specified dir.

@rootdir@

The special variable @rootdir@ can be used to refer to the (absolute) path of the topmost Maven project of the current project.

If however a property rootdir already is defined for the current Maven project (or in one of its parent projects), its value will be used instead.

execution working directory

Important to note is that before the resolved (custom) Maven project file is invoked, the current working directory will be (temporarily) changed to the directory containing the project file. So all relative file and resource references will be resolved relative to this directory as well!

target execution parameters and environment

Once a target its target Maven project file is determined, its execution environment and runtime parameters are determined based on the following (all optional) elements and the default/global elements defined for all targets (see above):

<target>
  <id>aTarget</id>
  <name>db</name>
  <dir>@rootdir@</dir>
  
  <goals>process-resources</goals>
  <profiles>proddb</profiles>
  <properties>
    <!-- (default) production target specific properties -->
  </properties>
  <settingsFile>@rootdir@/prod-settings.xml</settingsFile>
  <mavenOpts>-Xms128m -Xmx256m</mavenOpts>

</target>

goals

The (custom) target Maven project file can be invoked to run or or more goals using one or more profiles and even a specific Maven settings file.

The goals element can optionally be defined to specify a comma separated list of goals to run:

<goals>goal1,goal2,goal3</goals>
. If the goals element is not defined, the target Maven project file must have a defaultGoal build element:
<build>
  <defaultGoal>process-resources</defaultGoal>
</build>

profiles

Like with goals, optionally one or more profiles to be used (by all the goals to be run) can be specified as comma separated list:

<profiles>profile1,profile2,profile3</profiles>

properties

A very important requirement for the execution of a target is providing the Maven execution environment with the right set of runtime parameters.

The jetspeed:mvn plugin will accumulate the set of properties to be provided as runtime (e.g. -D) parameters for each target execution individually in the following order:

Order Source Lookup
1 <configuration><properties/></configuration the jetspeed:mvn default configuration properties
2 <target><properties/></target> the target specific properties
3 current Maven project properties Note: this includes properties defined in the parent project(s) of the current project and even the default Maven settings
4 jetspeed-mvn.properties This file is searched for in the current Maven project directory or else upwards in its parent project(s) directory.
The properties file found will be interpolated with the already resolved properties using ${} variable replacements.
5 jetspeed-mvn-${target name}.properties This file is searched for in the current Maven project directory or else upwards in its parent project(s) directory.
The properties file found will be interpolated with the already resolved properties using ${} variable replacements.
6 jetspeed-mvn-${target name}-${target id}.properties This file is searched for in the current Maven project directory or else upwards in its parent project(s) directory.
The properties file found will be interpolated with the already resolved properties using ${} variable replacements.

The jetspeed:mvn specific property files are individually looked up, e.g. the location of one doesn't depict the location of another.

Warning: be careful depending on properties resolved from the current Maven project as these might be different depending on from which project folder the jetspeed:mvn is invoked.

useSettings and settingsFile

Certain Maven configuration elements and properties can or should only be specified in a Maven settings file, like security sensitive server parameters (username, password etc.).

While Maven will by default lookup the settings.xml file from the user's home directory: ${user.home}/.m2/settings.xml, this isn't always very inconvenient, especially not if one is involved in many different projects each with its own specific settings requirements.

Sometimes it is more convenient or even required to maintain project specific settings with or within the project source (control) environment itself.

The jetspeed:mvn plugin can use a custom setttings file (by default) which is controlled by the optional configuration useSettings element, a target specific settingsFile element or a specific property jetspeed.mvn.settings.xml.

When the jetspeed:mvn configuration element <useSettings>true</useSettings> is specified (which it is by default), jetspeed:mvn will look for a custom Maven settings file named jetspeed-mvn-settings.xml first in the current Maven project directory, and if not found search for it upwards in the parent project(s) of the current Maven project.

Alternatively, a target settingsFile element can be used to use a target specific settings file, as shown in the full example target configuration above.

Finally, a (target specific) settings file can also be defined as property either for the current Maven project or one of its parents, or in the resolved target specific properties (which do incorparate the current Maven project properties) using the property name: jetspeed.mvn.settings.xml.

A custom Maven settings file specified as jetspeed.mvn.settings.xml property overrules a target specific settingsFile, and these both overrule a jetspeed:mvn default useSettings configuration and lookup.

Advanced: Maven project and settings file variables interpolation

An advanced feature to even further configuring the target Maven project and/or settings file is inherited from the Maven Invoker Plugin from which the jetspeed:mvn plugin was derived.

Before the resolved Maven project and optional settings file are actually executed and used, an interpolated version of these files are temporarily written to disk in which variables between @ markers are filtered using the resolved target properties (see above).

The Jetspeed-2 Portal project itself uses this feature in its jetspeed-mvn-db-init-pom.xml for initializing either a test or production database.

The actually database configuration properties used by Jetspeed have a common prefix: either org.apache.jetspeed.test.database or org.apache.jetspeed.production.database.

For the initialization of the two different target (test|production) databases, the jetspeed-mvn-db-init-pom.xml references these configuration parameters using the following prefix: org.apache.jetspeed.@database.type@.database:

<plugin>
  <groupId>${pom.groupId}</groupId>
  <artifactId>jetspeed-db-maven-plugin</artifactId>
  <version>${pom.version}</version>
  <configuration>
    <connection>
      <username>${org.apache.jetspeed.@database.type@.database.user}</username>
      <password>${org.apache.jetspeed.@database.type@.database.password}</password>
      <url>${org.apache.jetspeed.@database.type@.database.url}</url>
      <driver>${org.apache.jetspeed.@database.type@.database.driver}</driver>
    </connection>
  </configuration>
  ...
The separate jetspeed-mvn targets used for the initialization each define a different value for property database.type:
<target>
  <id>testdb</id>
  <name>db-init</name>
  <properties>
    <database.type>test</database.type>
  </properties>
</target>
<target>
  <id>proddb</id>
  <name>db-init</name>
  <properties>
    <database.type>production</database.type>
  </properties>
</target>
As result of the automatic interpolation of the target project (and settings) file, only a single definition for the jetspeed-db:init plugin is needed handling both initializing test and production databases.

This feature also makes it very easy to later add even more target databases, like for staging purposes: just add another target with value "staging" for the database.type property (and of course provide the corresponding org.apache.jetspeed.staging.database.* properties in the jetspeed-mvn-settings.xml).

mavenOpts

Finally, the special overriding Maven MAVEN_OPTS environment variable can also be specified for a specific target using a mavenOpts element, or if not defined, also a default for all targets as jetspeed:mvn configuration element (see above).

target configuration summary

The following table summarizes the configuration elements for a target:

Element Description
id The only required element to uniquely identify a target.
depends The optional comma separated list of other target ids this target depends upon and which will be automatically executed beforehand
name The optional name of the target which is used to lookup a custom Maven project file named: jetspeed-mvn-${name}-pom.xml.
If only element dir is defined, the standard Maven pom.xml project file from the dir will be used.
dir The optional directory where to lookup a custom Maven project file (using the name) of the target.
If name is not defined the standard Maven pom.xml project file will be used from this directory.
goals The optional comma separated list of Maven goals to be invoked on the resolved (custom) Maven project file.
If not defined, the target Maven project file must have a <defaultGoal/> build element configured.
profiles The optional comma separated list of profiles to be provided when the resolved (custom) Maven project file is executed.
properties The optional target specific properties to be provided as runtime (-D) parameters.
These properties can be overruled by jetspeed:mvn specific property files, see previous section.
settingsFile The location of an optional custom Maven settings file to be used when executing this target.
If not defined, the default <useSettings/> configuration element value (true by default) determines if a jetspeed-mvn-settings.xml file is looked up instead. Note: This settingsFile can also be overruled with a property jetspeed.mvn.settings.xml, see previous section.
mavenOpts The optional value for the special Maven MAVEN_OPTS Maven environment variable to be used.
If not defined, the (also optional) default <mavenOpts/> configuration element value will be used.

Usage

Showing the available targets

A very useful feature of the jetspeed:mvn plugin is that it can show the currently available targets, within the scope of the current Maven (sub) project, using the optional commandline parameter -Dlist:

$mvn jetspeed:mvn -Dlist

As an example, for the Jetspeed project itself (2.2.1 release) the following output will be shown:

[INFO] [jetspeed:mvn]

Available jetspeed:mvn targets:
  testdb             [testdb]
  test               [test]
  proddb             [proddb]
  demo-install       [demo-install]
  demo-seed          [demo-seed]
  min-seed           [min-seed]
  demo-deploy        [demo-deploy]
  demo-deploy-min    [demo-deploy-min]
  demo-deploy-dbpsml [demo-deploy-dbpsml]
  test-install       [testdb, test-install]
  demo-seed-dbpsml   [proddb, demo-seed, demo-db, demo-seed-dbpsml]
  min-seed-dbpsml    [proddb, demo-seed, demo-db, min-seed-dbpsml]
  demo-db            [proddb, demo-seed, demo-db]
  min-db             [proddb, min-seed, min-db]
  demo-db-psml       [proddb, demo-seed, demo-db, demo-seed-dbpsml, demo-db-psml]
  demo               [demo-install, proddb, demo-seed, demo-db, demo-deploy, demo]
  min                [demo-install, proddb, demo-seed, demo-db, demo-deploy-min, min]
  min-dbpsml         [demo-install, proddb, demo-seed, demo-db, demo-deploy-min, demo-deploy-dbpsml, min-seed-dbpsml, min-dbpsml]
  demo-dbpsml        [proddb, demo-seed, demo-db, demo-seed-dbpsml, demo-db-psml, demo-deploy, demo-deploy-dbpsml, demo-dbpsml]

The left column above shows the available targets to be executed using the -Dtarget=<target id> commandline parameter.
The right column shows the actual chained set of targets which will be executed in order as result.

Complete documentation about these actual jetspeed project target definitions is provided on the Building from Source page.

Finally, actually using the jetspeed:mvn plugin and invoking a specific target will be very simple:

$mvn jetspeed:mvn -Dtarget=<target id>

Optionally, if also a defaultTarget is configured for the jetspeed:mvn plugin, even the following will work:

$mvn jetspeed:mvn
but usually more than one target will be needed for a specific (Jetspeed Portal) project in which case defining and using a defaultTarget is not really recommended.

Executing a target