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.
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.

