Maven: Configuration For Multipe Environments

I have often heard that it is not possible to create a number of artifacts out of a single Maven module with different configurations. An example from the wild is to have a web-app (or whatever app) which should be running in development, test, q&a and production environment. So you need different configurations for the different environments for example the database connection or whatever. At first glance that seems to be a contradiction cause Maven's paradigm is "One Module One Artifact"?

Now let us start with a webapp project (packaging war) where the pom.xml looks more or less lilke the following:

 1<project
 2  xmlns="http://maven.apache.org/POM/4.0.0"
 3  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 4  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
 5
 6  <modelVersion>4.0.0</modelVersion>
 7
 8  <groupId>com.soebes.maven.multiple.artifacts</groupId>
 9  <artifactId>solution3</artifactId>
10  <version>0.1.0-SNAPSHOT</version>
11  <packaging>war</packaging>
12  ....
13</project>

If you call Maven on command line via mvn clean package you will get a war-file within the target folder which contains your webapp incl. web.xml and your compiled classes etc. The contents of the war file will be created based on the compiled classes coming from src/main/java, the resources src/main/resources plus src/main/webapp folder with the supplemental dependencies which you have defined inside your pom file.

1.
2|-- pom.xml
3`-- src
4    |-- main
5    |   |-- java
6    |   |-- resources
7    |   `-- webapp

Ok. Now let us come to the point to have some kind of configuration for our web application. We put the configuration into the appropriate folders like test, q&a and production which results into the following structure of the project:

 1.
 2|-- pom.xml
 3`-- src
 4    |-- main
 5    |   |-- java
 6    |   |-- resources
 7    |   |-- environment
 8    |   |   |-- test
 9    |   |   |   `-- database.properties
10    |   |   |-- qa
11    |   |   |   `-- database.properties
12    |   |   `-- production
13    |   |       `-- database.properties
14    |   `-- webapp

So we have to create a war file for test, q&a and production. The simplest way to achieve this is by using the Maven Assembly Plugin You need to create an assembly descriptor for every environment. Let us start with the test environment which looks like the following and should be named test.xml and put into src/main/assembly folder:

 1<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
 2  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
 4
 5  <id>test</id>
 6  <formats>
 7    <format>war</format>
 8  </formats>
 9  <includeBaseDirectory>false</includeBaseDirectory>
10  <dependencySets>
11    <dependencySet>
12      <unpack>true</unpack>
13      <useProjectArtifact>true</useProjectArtifact>
14    </dependencySet>
15  </dependencySets>
16  <fileSets>
17    <fileSet>
18      <outputDirectory>WEB-INF</outputDirectory>
19      <directory>${basedir}/src/main/environment/test/</directory>
20      <includes>
21        <include>**</include>
22      </includes>
23    </fileSet>
24  </fileSets>
25</assembly>

And finally you need a part in your pom file to use the assembly descriptors:

 1<plugin>
 2  <groupId>org.apache.maven.plugins</groupId>
 3  <artifactId>maven-assembly-plugin</artifactId>
 4  <executions>
 5    <execution>
 6      <id>test</id>
 7      <phase>package</phase>
 8      <goals>
 9        <goal>single</goal>
10      </goals>
11      <configuration>
12        <descriptors>
13          <descriptor>${project.basedir}/src/main/assembly/test.xml</descriptor>
14        </descriptors>
15      </configuration>
16    </execution>
17    <execution>
18      <id>qa</id>
19      <phase>package</phase>
20      <goals>
21        <goal>single</goal>
22      </goals>
23      <configuration>
24        <descriptors>
25          <descriptor>${project.basedir}/src/main/assembly/qa.xml</descriptor>
26        </descriptors>
27      </configuration>
28    </execution>
29    <execution>
30      <id>production</id>
31      <phase>package</phase>
32      <goals>
33        <goal>single</goal>
34      </goals>
35      <configuration>
36        <descriptors>
37          <descriptor>${project.basedir}/src/main/assembly/production.xml</descriptor>
38        </descriptors>
39      </configuration>
40    </execution>
41  </executions>
42</plugin>

Now the result is that by using a simple mvn package you get in the target folder three different war files, named like artifactId-version-test.war, artifactId-version-qa.war and artifactId-version-production.war which are packaged for the different environments.