Configuration and usage of the jetspeed-unpack:unpack Maven Plugin

The Jetspeed Unpack Maven Plugin provides one goal: jetspeed-unpack:unpack, which can be used to extract selected resources from a (remote) Maven artifact or an local (archive) file.

At the time this plugin was written, none of the required features was fully available from other (standard) Maven plugins.

Now, some of these features are also possible using the standard Maven Dependency Plugin dependency:unpack goal or the Remote Resources Plugin remote-resources:process goal.

However, this wasn't yet the case initially, and still the jetspeed-unpack plugin is easier to configure and use.
Furthermore, the same functionallity as provided by this plugin is also available embedded within the jetspeed-db:iniit plugin using exactly the same configuration.

This plugin is intended to be used as attached to the Maven process-resources or possibly generate-resources lifecycle phase for embedding pre-defined resources in a final Maven artifact like a war file, or use such resources for integration tasks like deploying (possibly filtered) configuration files to a target environment application server.

Side track: the jetspeed-portal-resources artifact

While this plugin is not dependent on the jetspeed-portal-resources artifact in anyway (nor on any other part of Jetspeed-2 for that matter), it is primarily written and used for unpacking specific pre-packaged Jetspeed-2 Portal resources.

The Jetspeed Portal Resources page further describes the jetspeed-portal-resources artifact and its intended usage.

Quick Overview

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

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

    <unpack>
      <artifact>...</artifact>
      <file>...</file>
      <targetDirectory>...</targetDirectory>
      <overwrite>...</overwrite>            
      <resources combine.children="append">

        <resource>
          <path>...</path>
          <destination>...</destination>
          <overwrite>...</overwrite>
          <flat>...</flat>
          <include>...</include>
          <exclude>...</exclude>
          <name>...</name>
        </resource>
        ...
      </resources>
    </unpack>

    <skip>...</skip>
    <verbose>...</verbose>

  </configuration>
</plugin>

Configuration

Resource archive specification and references

Using Maven artifacts as resource archive

As with the jetspeed-db:init plugin and the jetspeed-deploy:deploy plugin, the jetspeed-unpack plugin can (and primarily is intended to) use Maven Artifacts retrieved from the local Maven repository as resource (archives).

To use Maven artifacts as resource archive they need to be specified as plugin dependencies:

<plugin>
  <groupId>org.apache.portals.jetspeed-2</groupId>
  <artifactId>jetspeed-unpack-maven-plugin</artifactId>
  <version>${org.apache.portals.jetspeed.version}</version>
  ...
  <dependencies>
    <dependency>
      <groupId>org.apache.portals.jetspeed-2</groupId>
      <artifactId>jetspeed-portal-resources</artifactId>
      <version>${org.apache.portals.jetspeed.version}</version>
    </dependency>
  </dependencies>
</plugin>
Note: Maven 2.0 (as of now, version 2.0.9) requires that for a plugin dependency its <version/> is defined, even if a default version is configured in the project <dependencyManagement/> section for the same artifact.

As standard Maven functionality, if such a dependency isn't available yet from the local Maven repository, it will automatically (try to) download it from a remote Maven repository.

Referencing a plugin dependency as resource archive

To actually use a specific resource archive specified as a plugin dependency it can be referenced with:

<artifact>${groupId}:${artifactId}:${packaging}</artifact>
Note: the default packaging of a dependency is jar

Using the jetspeed-portal-resources artifact as example, its artifact reference configuration would be:

<artifact>org.apache.portals.jetspeed-2:jetspeed-portal-resources:jar</artifact>

Note: the same type of definition and usage of (remote) Maven repository artifacts is also used by the jetspeed-db:init and jetspeed-deploy:deploy plugins.

Using a local file archive

Alternatively, it is also possible to directly use local archive files, in which case a file element should be specified instead of an artifact element:

<file>localArchiveFilePath</file>

Plugin configuration

The jetspeed-unpack plugin allows two general options to be configured besides specific unpack configurations:

Element Description
skip default: false
This optional element is primarly intended to allow skipping plugin execution under certain conditions, like not extracting resources which are only needed when actually performing unit tests:
<phase>process-test-resources</phase>
  <configuration
    <skip>${maven.test.skip}</skip>
    ...
  </configuration>
Maven always invokes plugins attached to the process-test-resources phase, regardless if it actually is going to execute unit tests.
verbose default: false
When unpacking resources, the verbose setting controls if detailed logging is performed which files are extracted.

unpack configuration

As already described above, the actual resource archive to unpack from has to be specified either as artifact reference or local file.

Additionally, two other optional unpack configuration elements can be speficied:

Element Description
targetDirectory default: ${project.build.directory}
The targetDirectory is used as base directory under which the selected resources from the resource archive will be extracted.
If this directory does not yet exist, it will be created by the plugin automatically before (possibly) extracting resources.
overwrite default: true
When a selected resource from the resource archive already exists in its target directory, the overwrite setting will determine if the existing resource is overwritten, even if it has a more recent timestamp than the archived resource.
Note: if the archived resource has a more recent timestamp the existing resource will always be overwritten.
This setting can also be overruled for specific resource configurations (see below).

<resources combine.children="append">

A potentially very important part of the configuration is the combine.children="append" attribute specified for the resources 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 resources configurations this is not very convenient because it requires to specify all optional properties for a resource element to prevent "merging in" property values from unrelated previously defined resource 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.

For the jetspeed-unpack plugin defining this attribute is recommended unless only one, or exactly similar resource child elements are configured (e.g. using all the same set of elements).

resource configuration

The final part of the jetspeed-unpack plugin configuration concern the actual resoure(s) to unpack:

<resource>
  <path>/conf/tomcat</path>
  <destination>tomcat</destination>
  <include>context.xml</include>
</resource>
The above example will extract the context.xml resource from the conf/tomcat folder within the resource archive and write it to a sub directory tomcat of the project build directory or otherwise specified (base) targetDirectory.

Note: it is not required to specify any resource configuration. If none is specified all resources from the resource archive will be extracted!

The following (all optional) elements can be defined for a specific resource configuration:

Element Description
path default: /
The path specifies the sub folder within the resource archive as (base) path to search resources to extract.
destination default: ${configuration.targetDirectory}
If defined, the destination specifies the sub directory of the default project build directory or the otherwise specified targetDirectory of the plugin where the matched resource(s) will be unpacked.
overwrite default: ${unpack.overwrite} If defined, overwrite overrules the default overwrite setting of the unpack element (see above).
flat default: false
By default resources to be extracted from the resource archive are written out to a sub directory of the target destination directory (see above) using their relative position of the (base) path within the resource archive where they have been looked up against.
For example, with the following (probably incorrect) resource configuration:
<resource>
  <path>conf</path>
  <destination>tomcat</destination>
  <include>tomcat/context.xml</include>
</resource>
the matched context.xml resource will be written out to: ${targetDirectory}/tomcat/tomcat/context.xml

For this kind of configurations (and sometimes these are needed), defining <flat>true<flat> will "drop" the relative position of the resource.
Then, only its entry name will be used, resulting in (the probably desired): ${targetDirectory}/tomcat/context.xml

Of course the same result can also (and even simpler) be achieved using:
<resource>
  <path>conf</path>
  <include>tomcat/context.xml</include>
</resource>
include default: ${resource.path}/**
The include element can define a comma separated list of resources to extract.
These may contain (standard Ant like) wildcards and sub folder references relative to the (base) path sub folder within the resource archive:
<include>profile.xml,security*.xml,boot/*.xml</include>
exclude default: none
Potentially mached resources to extract (see include above) may be excluded from extraction using the exclude element.
Like with the include element, the exclude element can define a comma separated list of resources to exclude. These also may contain (standard Ant like) wildcards and sub folder references relative to the (base) path sub folder within the resource archive:
<exclude>security-spi*.xml,security-managers.xml</exclude>
name default: none
New file name for single resource extracted from the resource archive:
<name>j2-seed.xml</name>

As can be determined from the above, as all resource configuration elements are optional, specifying an empty <resource/> definition will simply extract all the resources from the archive to the targetDirectory.

Examples

Unpacking of jetspeed unit test resources

The following example taken from the Maven project file for the jetspeed-profiler component extracts several Spring assembly files, all files from the db-ojb folder and the seed/min/j2-seed.xml file to the project testOutputDirectory as needed for running the unit tests:

<plugin>
  <groupId>${pom.groupId}</groupId>
  <artifactId>jetspeed-unpack-maven-plugin</artifactId>
  <version>${pom.version}</version>
  <executions>
    <execution>
      <id>unpack-test-resources</id>
      <goals>
        <goal>unpack</goal>
      </goals>
      <phase>process-test-resources</phase>
      <configuration>
        <skip>${maven.test.skip}</skip>
        <unpack>
          <artifact>org.apache.portals.jetspeed-2:jetspeed-portal-resources:jar</artifact>
          <targetDirectory>${project.build.testOutputDirectory}</targetDirectory>
          <resources>
            <resource>
              <path>assembly</path>
              <include>profiler.xml,transaction.xml,cache.xml,security-*.xml,boot/datasource.xml</include>
            </resource>
            <resource>
              <path>db-ojb</path>
            </resource>
            <resource>
              <path>seed/min</path>
              <include>j2-seed.xml</include>
            </resource>
          </resources>
        </unpack>
      </configuration>
    </execution>
  </executions>
</plugin
The interesting part of this example is that NO resource archive is specified!

But the above example actually does work because the root Maven project file for the Jetspeed-2 Portal project already defined the jetspeed-portal-resources artifact as default dependency for the jetspeed-unpack plugin in its dependencyManagement section:

<plugin>
  <groupId>org.apache.portals.jetspeed-2</groupId>
  <artifactId>jetspeed-unpack-maven-plugin</artifactId>
  <version>${pom.version}</version>
  <dependencies>
    <dependency>
      <groupId>${groupId}</groupId>
      <artifactId>jetspeed-portal-resources</artifactId>
      <version>${pom.version}</version>
    </dependency>
  </dependencies>
</plugin>
But please note: this is a special use-case which only works when only one dependency is (pre)configured.

Unpacking the tomcat context.xml to be filtered before deployment

A more elaborate and common use-case is extracting a specific resource during the generate-resources lifecycle phase so that it can be filtered (using the standard Maven resources plugin):

<plugins>
  <plugin>
    <groupId>org.apache.portals.jetspeed-2</groupId>
    <artifactId>jetspeed-unpack-maven-plugin</artifactId>
    <version>${org.apache.portals.jetspeed.version}</version>
    <executions>
      <execution>
        <id>unpack-appserver</id>
        <goals>
          <goal>unpack</goal>
        </goals>
        <phase>generate-resources</phase>
        <configuration>
          <unpack>
            <artifact>org.apache.portals.jetspeed-2:jetspeed-portal-resources:jar</artifact>
            <resources>
              <resource>
                <path>conf</path>
                <include>tomcat/context.xml</include>
              </resource>
            </resources>
          </unpack>
        </configuration>
      </execution>
    </executions>
  <dependencies>
    <dependency>
      <groupId>org.apache.portals.jetspeed-2</groupId>
      <artifactId>jetspeed-portal-resources</artifactId>
      <version>${org.apache.portals.jetspeed.version}</version>
    </dependency>
  </dependencies>
  </plugin>
  <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <executions>
      <execution>
        <id>resources</id>
        <goals>
          <goal>resources</goal>
        </goals>
        <phase>process-resources</phase>
      </execution>
    </executions>
  </plugin>
</plugins>
...
<resources>
  <resource>
    <directory>${project.build.directory}/tomcat</directory>
    <targetPath>../resources</targetPath>
    <filtering>true</filtering>
  </resource>
</resources>
This example is taken from a custom Maven project file invoked with the jetspeed-mvn plugin for deploying a custom Jetspeed-2 Portal on a Tomcat server.

The standard Maven Resources Plugin is also configured in this example because a custom jetspeed-mvn Maven project file is commonly configured using <packaging>pom</packaging>.
Such custom jetspeed-mvn project files are used for executing specific integration tasks, not for producing a "normal" artifact like a jar or war file.
But as a pom project doesn't have the maven-resources-plugin attached to its lifecycle it needs to be configured directly to have it perform the needed resource filtering during the process-resources phase.