Develop an environment-aware Maven build process

Extend Maven builds to port Java apps to multiple environments

1 2 3 4 5 Page 4
Page 4 of 5

Note also that for the purpose of this article, we'll only build for the development environment, which is why the App-Config project contains a dev.properties file but not a test.properties file. We can pass in the environment name (such as dev or test) upon executing a Maven build, via the JVM argument-passing construct -Dproperty key='property value'. Passing the environment property value in this manner overrides the property value specified in the pom.xml (the default in pom.xml is set to dev in this example).

Database inherits Parent-POM

Our next step is to modify the Database Maven project's pom.xml so that it references the Parent-POM project. During the Maven clean phase of the Database project, the entire contents of the App-Config project JAR file will then be extracted into the Database project’s target/alternate-resources directory. Listing 9 modifies the Database project’s pom.xml to incorporate the Parent-Pom project’s pom.xml.

Listing 9. Modifying the Database project pom.xml to inherit Parent-Pom

<parent>
    <groupId>com.foo</groupId>
    <artifactId>parent-pom</artifactId>
    <version>1.0-SNAPSHOT</version>
</parent>

<modelVersion>4.0.0</modelVersion>
<artifactId>database</artifactId>
<packaging>jar</packaging>
<name>database</name>
<version>${app.version}</version>
<description>Contains code to connect to MS SQL Server database.
</description>

<properties>
    <app.version>1.0-SNAPSHOT</app.version>
</properties>

Note that the version of the pom.xml is now captured as a property. This allows us to dynamically set the version of the resulting JAR during the Maven build phase. We do this not by modifying the <app.version> property value directly in the pom.xml, but by passing it in via a Java system variable, in this case –Dapp.version=1.0. The property value is passed in exactly how we’d pass in an environment variable. In a real-world project, we would make this change to all projects, including App-Config.

Filtering and copying property files

Another addition to the Database application’s pom.xml will allow the database.properties template property file to be modified with the property values for each environment. This process occurs during the Maven clean phase. The resulting property files are placed as follows:

target/alternate-resources/configs/dev/database/database.properties

Obviously we don’t want property files placed in the resources directory because then they will be included in the JAR artifact. Storing property files in JARs is not ideal because property values must change per environment. It is, however, still useful to include these resources in a separate directory for testing purposes. The directory will then be filtered for the target environment. Listing 10 shows the Database project's pom.xml filtering for the target/conf directory during the Maven clean phase.

Listing 10.Copying and filtering property files

<plugin>
    <artifactId>maven-resources-plugin</artifactId>
    <version>2.5</version>
    <executions>
        <execution>
            <id>filter-resources</id>
            <phase>process-resources</phase>
            <goals>
                <goal>copy-resources</goal>
            </goals>
            <configuration>
                <outputDirectory>target/conf</outputDirectory>
                <resources>
                    <resource>
                        <directory>target/alternate-resources/configs/${environment.name}/${project.artifactId}/</directory>
                        <includes>
                            <include>database.properties</include>
                        </includes>
                        <filtering>true</filtering>
                    </resource>
                </resources>
            </configuration>
        </execution>
    </executions>
</plugin>

Adding this plugin to the Database project's pom.xml ensures that every time the project is cleaned, the target/conf directory will contain the database.properties file. This file is populated with all of the development property values specific to the keys used in the database.properties template file.

If you are executing this application in standalone mode, you can manually copy the database.properties file from the target/conf directory to the src/main/resources directory and rebuild. That will cause the property file to be included in the resulting JAR. However, if the JAR is to be included as part of another application and has environment-specific properties (as database.properties has), including the property file in the JAR is not ideal. You may be wondering, given that property files are not included in the JAR, how the Mule ESB application will provide a database.properties file to the Database application at runtime. The answer lies in the Mule application's directory structures.

The Mule ESB application

In a typical Mule ESB application, all of your classes are packaged into JARs, which go in the lib directory. Everything else that you want in the application’s classpath (including classes not contained in a JAR as well as resources such as property files) goes under the classes directory. A generic Mule project directory structure is shown in Figure 6.

Figure 6. Generic Mule application directory structure

The setup for our environment-aware Mule project is slightly different because in this case, all of the property files for the Database project and the Web Service Client project will be copied during the Maven clean phase into the Mule project’s resources directory. During the Maven Install phase, all of those property files will be included in the resulting Mule ZIP deployable app’s classes directory. This will ensure that they are accessible as resources via the classpath. The change to the Mule project’s pom.xml is shown in Listing 11.

Listing 11. Additions to the Mule ESB project pom.xml

<plugin>
   <artifactId>maven-resources-plugin</artifactId>
   <version>2.5</version>
   <executions>    
      <execution>
         <id>filter-regional-resources-services</id>
         <phase>validate</phase>
         <goals>
            <goal>copy-resources</goal>
         </goals>
         <configuration>
            <outputDirectory>src/main/resources</outputDirectory>
            <resources>          
               <resource>
                  <directory>${basedir}/target/alternate-resources/configs/${environment.name}/database</directory>
                  <filtering>true</filtering>
                  <includes>
                     <include>database.properties</include>
                  </includes>
               </resource>
              <resource>
                  <directory>${basedir}/target/alternate-resources/configs/${environment.name}/web-service-client</directory>
                  <filtering>true</filtering>
                  <includes>
                     <include>web-service-client.properties</include>
                  </includes>
               </resource>
            </resources>
         </configuration>
      </execution>
   </executions>
</plugin>

Inspecting this change, you can see that the property files are placed in the Mule ESB project’s resources directory. The Mule Maven plugin will ensure that the property files are placed in the classes directory within the resulting ZIP file, making these property files accessible to the classpath.

1 2 3 4 5 Page 4
Page 4 of 5