10.3. Common Lifecycle Goals

Many of the packaging lifecycles have similar goals. If you look at the goals bound to the WAR and JAR lifecycles, you'll see that they differ only in the package phase. The package phase of the WAR lifecycle calls war:war and the package phase of the JAR lifecycle calls jar:jar. Most of the lifecycles you will come into contact share some common lifecycle goals for managing resources, running tests, and compiling source code. In this section, we'll explore some of these common lifecycle goals in detail.

10.3.1. Process Resources

Most lifecycles bind the resources:resources goal to the process-resources phase. The process-resources phase "processes" resources and copies them to the output directory. If you haven't customized the default directory locations defined in the Super POM, this means that Maven will copy the files from ${basedir}/src/main/resources to ${basedir}/target/classes or the directory defined in ${project.build.outputDirectory}. In addition to copying the resources to the output directory, Maven can also apply a filter to the resources that allows you to replace tokens within resource file. Just like variables are referenced in a POM using ${...} notation, you can reference variables in your project's resources using the same syntax. Coupled with build profiles, such a facility can be used to produce build artifacts which target different deployment platforms. This is something that is common in environments which need to produce output for development, testing, staging, and production platforms from the same project. For more information about build profiles, see Chapter 11, Build Profiles.

To illustrate resource filtering, assume that you have a project with an XML file in src/main/resources/META-INF/service.xml. You want to externalize some configuration variables to a properties file. In other words, you might want to reference a JDBC URL, username, and password for your database, and you don't want to put these values directly into the service.xml file. Instead, you would like to use a properties file to capture all of the configuration points for your program. Doing this will allow you to consolidate all configuration into a single properties file and make it easier to change configuration values when you need to target a new deployment environment. First, take a look at the contents of service.xml in src/main/resources/META-INF.

Example 10.4. Using Properties in Project Resources

<service>
  <!-- This URL was set by project version ${project.version} -->
  <url>${jdbc.url}</url>
  <user>${jdbc.username}</user>
  <password>${jdbc.password}</password>
</service>


This XML file uses the same property reference syntax you can use in the POM. In fact, the first variable referenced is the project variable which is also an implicit variable made available in the POM. The project variable provides access to POM information. The next three variable references are jdbc.url, jdbc.username, and jdbc.password. These custom variables are defined in a properties file src/main/filters/default.properties.

Example 10.5. default.properties in src/main/filters

jdbc.url=jdbc:hsqldb:mem:mydb
jdbc.username=sa
jdbc.password=

To configure resource filtering with this default.properties file, we need to specify two things in a project's POM: a list of properties files in the filters element of the build configuration, and a flag to Maven that the resources directory is to be filtered. The default Maven behavior is to skip filtering and just copy the resources to the output directory; you'll need to explicitly configure resource filter, or Maven will skip the step altogether. This default ensures that Maven's resource filtering feature doesn't surprise you out of nowhere and clobbering any ${...} references you didn't want it to replace.

Example 10.6. Filter Resources (Replacing Properties)

<build>
  <filters>
    <filter>src/main/filters/default.properties</filter>
  </filters>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
      <filtering>true</filtering>
    </resource>
  </resources>
</build>


As with all directories in Maven, the resources directory does not need to be in src/main/resources. This is just the default value defined in the Super POM. You should also note that you don't need to consolidate all of your resources into a single directory. You can always separate resources into separate directories under src/main. Assume that you have project which contains hundreds of XML documents and hundreds of images. Instead of mixing the resources in the src/main/resources directory, you might want to create two directories src/main/xml and src/main/images to hold this content. To add directories to the list of resource directories, you would add the following resource elements to your build configuration.

Example 10.7. Configuring Additional Resource Directories

<build>
  ...
  <resources>
    <resource>
      <directory>src/main/resources</directory>
    </resource>
    <resource>
      <directory>src/main/xml</directory>
    </resource>
    <resource>
      <directory>src/main/images</directory>
    </resource>
  </resources>
  ...
</build>

When you are building a project that produces a console application or a command-line tool, you'll often find yourself writing simple shell scripts that need to reference the JAR produced by a build. When you are using the assembly plugin to produce a distribution for an application as a ZIP or TAR, you might place all of you scripts in a directory like src/main/command. In the following POM resource configuration, you'll see how we can use resource filtering and a reference to the project variable to capture the final output name of the JAR. For more information about the Maven Assembly plugin, see Chapter 12, Maven Assemblies.

Example 10.8. Filtering Script Resources

<build>
  <groupId>org.sonatype.mavenbook</groupId>
  <artifactId>simple-cmd</artifactId>
  <version>2.3.1</version>
  ...
  <resources>
    <resource>
      <filtering>true</filtering>
      <directory>${basedir}/src/main/command</directory>
      <includes>
        <include>run.bat</include>
        <include>run.sh</include>
      </includes>
      <targetPath>${basedir}</targetPath>
    </resource>
    <resource>
      <directory>${basedir}/src/main/resources</directory>
    </resource>
  </resources>
  ...
</build>


If you run mvn process-resources in this project, you will end up with two files, run.sh and run.bat, in ${basedir}. We've singled out these two files in a resource element, configuring filtering, and set the targetPath to be ${basedir}. In a second resource element, we've configured the default resources path to be copied to the default output directory without any filtering. Example 10.8, “Filtering Script Resources” shows you how to declare two resource directories and supply them with different filtering and target directory preferences. The project from Example 10.8, “Filtering Script Resources” would contain a run.bat file in src/main/command with the following content:

@echo off
java -jar ${project.build.finalName}.jar %*

After running mvn process-resources, a file named run.bat would appear in ${basedir} with the following content:

@echo off
java -jar simple-cmd-2.3.1.jar %*

The ability to customize filtering for specific subsets of resources is another reason why complex projects with many different kinds of resources often find it advantageous to separate resources into multiple directories. The alternative to storing different kinds of resources with different filtering requirements in different directories is to use a more complex set of include and exclude patterns to match all resource files which match a certain pattern.