by Paul Spinelli

Develop an environment-aware Maven build process

how-to
Feb 2, 201226 mins

Extend Maven builds to port Java apps to multiple environments

Traditional Java applications capture runtime variables in property files, then package them into individual JARs for various software environments. But for users of Maven, it could make better sense to include environment variables in the build process. In this article, Paul Spinelli shows you how to extend the standard Maven build in order to port any Java application to multiple environments.

A Java application hosted within an application server usually requires access to a set of key-value pairs that provide environment-specific runtime variables, such as a JDBC connection URL. In this article, I demonstrate a different approach to developing environment-aware applications, by making environment variables part of the Maven build process.

Developing an environment-aware build process involves introducing two Maven plugins and two small projects to your code. Specifying the build environment as a JVM argument during the Maven build phase will dynamically set property files to reflect the correct values for the given environment. All of the property files will be placed in a directory accessible to the classpath instead of being bundled into JARs.

An environment-aware Maven build process can be customized to support any software environment. The potential benefits of such a build process extend to developers, configuration managers, and administrators involved in building and deploying application artifacts.

About environment variables

A runtime variable is any variable that may change in the environment to which the software is deployed. For example, most Java applications utilize a relational database to persist state, and the database’s JDBC connection URL and associated user credentials will differ between environments. The JDBC connection URL and credentials are runtime variables.

As a software developer, you cannot completely avoid runtime-variable dependencies. But you do have options as to how your software will obtain the information required to interact with those dependent systems in different environments. A common approach is to use the operating system hosting the software in order to discover its dependencies. In Windows, for example, you could use the Registry to capture environment-specific runtime variables upon the installation of your application. Another option would be to encapsulate environment variables as key-value pairs in property files bundled with your application. These property files would then be made accessible to developers and administrators.

In addition to the runtime environment variables, applications usually also externalize certain software configurations that are not required for the software to execute (such as the default values included with a typical install). These software configurations allow users and the installer some control over the software’s runtime behavior. Often these are stored in a database or, again, in property files.

When deciding whether to include property files as part of a software project, you must consider not only how the properties will be accessed and modified during the install and runtime phases of the application lifecycle, but also during the development and test phases. These decisions can have a significant impact on the maintainability of your product.

Environment-aware dependency management in Maven

You may be familiar with using Maven build profiles to load variables into the build process for different environments. Variables defined within a build profile are available within each pom.xml intended for use in building deployable artifacts. Build profiles are powerful, but using them requires manually deploying a settings.xml file to the build machine’s $USERHOME.m2 directory or $M2_HOME/conf/settings.xml directory. This makes the resulting application less portable than we would like. Build profiles also do not easily handle deploying different sets of property files on a per-application and per-environment basis.

In this article I’ll demonstrate an alternative to using Maven build profiles to develop an environment-aware build. Working in an environment-aware build environment means that when software is compiled and/or built into a deployable package, all of the property files will exist as part of the project and will be properly configured for the target environment.

While this might not be so important to developers focused on working within a development environment, it does become important during other phases of the software development life cycle (SDLC). For example, it’s normal during a software maintenance cycle for the configuration-management team to re-package software for a test environment, prior to any release to a production environment. A test environment usually mirrors the production environment, so it must be connected to all of the external systems required to properly host and test all functions provided by the software. Configuring the software’s property files for use during deployment, even under test, should be a smooth and easy process, and it should not require the assistance of the development team.

For projects already using Maven, it makes sense to enhance the existing Maven build system rather than introducing a different system or set of dependency management tools.

Project setup

In order to follow the examples, you’ll need the following setup in your development environment:

  1. App-Config: A Maven project that contains all of the property files as templates for three environments: development, testing, and production. App-Config also contains a master property file for each environment, which contains property key-value pairs for all application variables used at runtime.
  2. Parent-Pom: A Maven project hosting a parent POM for inheritance by other Maven projects.
  3. The maven-dependency-plugin and maven-resources-plugin. These will be used by the Parent-Pom project’s POM and by individual project POMs to copy and filter property-file templates.

Demonstration setup and source code

The Maven projects used for this article build a Mule ESB 3.2 application using the Eclipse m2eclipse Maven plugin and the Eclipse Maven Mule plugin. The Maven projects were built within Eclipse Indigo. While you do not need to download the projects to follow the examples, doing so could be helpful. See Resources for more about the development environment setup.

The example application: Mule ESB

A Mule ESB application consists of a ZIP file that contains classes and JARs, resources, and a mule-config.xml file. These contents are placed in specific areas of the ZIP file, much like a WAR file dictates a specific directory structure. The Maven Mule plugin constructs the ZIP artifact during the package phase, as well as copying the files into the correct directory locations within the ZIP. The Mule plugin also includes dependent JAR files within the ZIP.

To demonstrate the environment-aware build process, we’ll construct a Mule ESB application that contains two other applications (bundled as JARs), each containing its own property files. One of the JARs will contain JDBC MS SQL Server database connection code, which reads the database connection information from a property file called database.properties. The other JAR will contain a SOAP Web Service client, which uses a property file to load the information required to connect to a server hosting the Web services.

It should be noted that the choice of using the Mule ESB was made only because its resulting Maven build artifact is a ZIP and the ZIP folder structure lends itself cleanly to this example. A project that builds a WAR artifact would have been just as valid. Also note that usually, you’d let your ESB handle establishing and managing database and Web service connections but again, the Mule ESB was chosen for the artifact it generates.

The entire solution as applied to this example consists of three applications, each configured as a Maven project:

  1. The Mule ESB Maven project
  2. The Database Maven project
  3. The SOAP Web Service Client Maven project

For the purposes of this article, it’s not that important why or how the Mule ESB app uses the other two projects, so I won’t spend time on the details of their functionality. Instead, we’ll focus on properly configuring the property files for all three projects. When the Mule ESB project is built into its ZIP artifact, all of the property files bundled within the ZIP must contain properties specific to the given deployment environment. Since the Mule app’s two JARs connect to external systems and use property files to obtain information about these external systems, we can assume that this information may change per environment.

Figure 1 is an overview of the extended Maven build system.

Figure 1. A diagram of the proposed Maven build solution (click to enlarge)

Unpacking the example applications

Let’s take a look at the pom files for each of our applications, starting with the Mule app in Listing 1.

Listing 1. Mule ESB application pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.techflow.bcs3.ldp.mule-esb</groupId>
    <artifactId>mule-app</artifactId>
    <packaging>mule</packaging>
    <name>Mule Application</name>
    <description>Mule application that connects to both a database and Web service.</description>
    <version>${app.version}</version>
    
    <properties>
        <app.version>1.0-SNAPSHOT</app.version>
        <mule.version>3.2.0</mule.version>
        <database.version>1.0-SNAPSHOT</database.version>
        <web-service-client.version>1.0-SNAPSHOT</web-service-client.version>       
    </properties>
    
    <build>
        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-install-plugin</artifactId>
                    <version>2.3.1</version>
                </plugin>
                <!--This plugin's configuration is used to store Eclipse m2e settings 
                    only. It has no influence on the Maven build itself. -->
                <plugin>
                    <groupId>org.eclipse.m2e</groupId>
                    <artifactId>lifecycle-mapping</artifactId>
                    <version>1.0.0</version>
                    <configuration>
                    <!-- Content not displayed in this article for brevity purposes. -->
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <plugins>
            <plugin>
                <groupId>org.mule.tools</groupId>
                <artifactId>maven-mule-plugin</artifactId>
                <version>1.7</version>
                <extensions>true</extensions>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
        </plugins>
    </build>
    !-- Mule Dependencies -->
    <dependencies>
        <dependency>
            <groupId>xalan</groupId>
            <artifactId>xalan</artifactId>
            <version>2.7.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>xerces</groupId>
            <artifactId>xercesImpl</artifactId>
            <version>2.9.1</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>xml-apis</groupId>
            <artifactId>xml-apis</artifactId>
            <version>1.3.04</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.foo</groupId>
            <artifactId>database</artifactId>
            <version>${database.version}</version>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>com.foo</groupId>
            <artifactId>web-service-client</artifactId>
            <version>${web-service-client.version}</version>
            <scope>compile</scope>
        </dependency>
    </dependencies>
</project>

Figure 2 shows the Mule ESB application’s Maven project directory structure as viewed in Eclipse Indigo.

Figure 2. Mule ESB directory structure

Listing 2 shows the pom.xml for the Database application.

Listing 2. Database application pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.foo</groupId>
    <artifactId>database</artifactId>
    <packaging>jar</packaging>
    <name>database</name>
    <version>1.0-SNAPSHOT</version>
    <description>
        Contains code to connect to MS SQL Server database.</
        description>

        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-compiler-plugin</artifactId>
                    <version>2.3.2</version>
                </plugin>
            </plugins>
        </build>
</project>

Figure 3 shows the Database application’s Maven project project directory structure as viewed in Eclipse Indigo.

Listing 3 shows the pom.xml for the SOAP Web Service Client application.

Listing 3. Web Service Client application pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.foo</groupId>
    <artifactId>web-service-client</artifactId>
    <packaging>jar</packaging>
    <name>web-service-client</name>
    <version>1.0-SNAPSHOT</version>
    <description>Contains code to connect to a SOAP Web service.</description>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
        </plugins>
    </build>
</project>


Figure 4 shows Web Service Client’s Maven project directory structure as viewed in Eclipse Indigo.

Figure 4. Web Service Client’s directory structure

Note

As the pom.xml files for the Database and Web Service Client Maven projects show, the property files are automatically included in the JARs when they are built, as is usual for Maven projects. There are two ramifications to this automatic inclusion:

  1. The JARs themselves become environmentally specific.
  2. It is difficult to quickly see and modify the property values once the application has been deployed.

Neither of these outcomes is desirable. In fact, a process that did not include the property files bundled into the JARs would be more practical. We’ll deal with that a bit later in the article.

App Config

Now that we have the pom.xmls and the project directory structure for each project laid out we can begin to extend our Maven build to be environment-aware. Our first task is to create a new Maven project that contains all of the property files in a templatized format. The App Config project’s pom.xml is shown in Listing 4.

Listing 4. App-Config pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/ 2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.foo</groupId>
    <artifactId>app-config</artifactId>
    <packaging>jar</packaging>
    <name>app-config</name>
    <version>1.0-SNAPSHOT</version>
    <description>Contains config files</description>
</project>

Figure 5 shows App-Config’s Maven project directory structure as viewed in Eclipse Indigo.

Figure 5. App-Config Maven project directory structure

Notice that the directory structure for this project contains not only the templatized property files for both the Database project and the Web Service Client project, but also a property file called dev.properties. Listings 5 through 7 display the contents of all three of these property files.

Listing 5. Property file: database.properties

database.name=${database.name}
database.connection.url=${database.connection.url}
database.connection.username=${database.connection.username}
database.connection.password=${database.connection.password}
database.connection.driver.class=${database.connection.driver.class}



Listing 6. Property file: web-service-client.properties

web.service.server.wsdl.url=${web.service.server.wsdl.url}

Listing 7. Property file: dev.properties

###### WEB SERVICE SERVER ###############
web.service.server.hostname=dev-web-server.foo.com
web.service.server.wsdl.url=http://${web.service.server.hostname}/foo.svc?wsdl

###### SQL SERVER 2008 #################
database.name=foodb
database.connection.url=jdbc:jtds:sqlserver://dev-sql-server-db.foo.com:1433
database.connection.username=test
database.connection.password=password123!
database.connection.driver.class=net.sourceforge.jtds.jdbc.Driver

With the App-Config Maven project set up, we can begin on the next phase of our solution, building Parent-Pom.

Parent-Pom

Parent-POM is a new parent Maven project that utilizes App-Config. It will provide each Maven project that inherits the Parent-POM with its own set of property files, but configured for a particular environment: development, testing, or production. Like other Maven projects, Parent-POM contains a pom.xml; however, unlike the other Maven projects, the packaging type is not JAR but POM. Below is Parent-POM’s pom.xml.

Listing 8. Parent-POM’s pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>
    <groupId>com.foo</groupId>
    <artifactId>parent-pom</artifactId>
    <packaging>pom</packaging>
    <name>parent-pom</name>
    <version>1.0-SNAPSHOT</version>
    <description>Contains the parent pom configurations</description>

    <properties>
        <environment.name>dev</environment.name>
    </properties>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
            </plugin>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <version>2.3</version>
                <executions>
                    <execution>
                        <id>unpack-app-config</id>
                        <phase>clean</phase>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>com.foo</groupId>
                                    <artifactId>app-config</artifactId>
                                    <version>1.0-SNAPSHOT</version>
                                    <type>jar</type>
                                    <overWrite>true</overwrite>
                                    <outputDirectory>${project.build.directory}/alternate-resources</outputDirectory>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
        <pluginManagement>
            <plugins>
                <!--This plugin's configuration is used to store Eclipse m2e settings 
                    only. It has no influence on the Maven build itself. -->
                <plugin>
                    <groupId>org.eclipse.m2e</groupId>
                    <artifactId>lifecycle-mapping</artifactId>
                    <version>1.0.0</version>
                    <configuration>
                    <!-- Content not displayed in this article for brevity purposes. -->
                    </configuration>
                </plugin>
            </plugins>
        </pluginManagement>
        <filters>
            <filter>${project.build.directory}/alternate-resources/configs/${environment.name}/${environment.name}.properties
        </filter>
        </filters>
    </build>
</project>

The pom.xml in Listing 8 utilizes the maven-dependency-plugin to pull from the Maven repository the App-Config project’s JAR, extract the contents of the JAR, and place them in ${project.build.directory}/alternate-resources.

Note that the path itself utilizes an implicit Maven property key, project.build.directory, which has a value of whatever project references the Parent-POM project. At the very bottom of the pom.xml, the <filter> element automatically loads all of the property keys and values in the dev.properties property file, and makes those values available during the property-filtering process of the maven-resources-plugin.

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.

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.

Once in the classpath, the property files and the properties they contain can be retrieved within any of the applications contained in the Mule ESB project. The code in Listing 12 will load all properties accessible from the classpath.

Listing 12. Loading properties accessible from the classpath

String fileName = “<YOUR PROPERTY FILE NAME>”;
InputStream propertyFile = null;
Properties properties = new Properties();
    
try
{
   ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
   URL propertyFileUrl = classLoader.getResource(fileName);
   if (propertyFileUrl != null)
   {
      propertyFile = propertyFileUrl.openStream();
            
      if (propertyFile != null)
      {
         if (fileName.toUpperCase().endsWith(".XML"))
         {
              properties.loadFromXML(propertyFile);
         }
         else
         {
            properties.load(propertyFile);
         }
      }
      else
      {
         System.err.println("The property file [" + fileName + "] could not " +   
                            "be opened for reading.");
      }
   }
   else
   {
      System.err.println("The property file [" + fileName + "] could not " +   
                         "be found in the classpath.");
      }
}
catch (IOException e)
{
   System.err.println ("The property file [" + fileName + "] could not " +
                  "be loaded. The error is: " + e.toString());
}
finally
{
   if (propertyFile != null)
   {
      try
      {
         propertyFile.close();
      }
      catch (IOException e)
      {
         e.printStackTrace();
      } 
   }
}

In conclusion

In this article we’ve walked through the steps to develop an environment-aware Maven build process. The resulting Maven project contains all of the properties and property-file templates for all of your Java applications, and is useable by all your Java applications for any target environment. The benefits to using this architecture are as follows:

  • Environment properties are centralized into a single project (App-Config), making them easier to manage over the lifespan of Java projects that use them.
  • Building software for multiple environments is as easy as providing a variable to the build process; e.g., –Denvironment.name=test.
  • All of the property files used within the final deployable artifact (ZIP/WAR), once exploded, are not contained within individual JARs. This enables developers and administrators to easily access and modify them.
  • It’s easy to add property files that must be included in some environments but not others. This feature may be useful if you interact with differing systems in each environment.

This last feature of the environment-aware build process is particularly useful. For example, your development environment might not require a failover server, but your test environment might. If your code handled the failover process, you could clone your primary server’s property file and simply modify the property values to reflect the redundant server. That cloned property file would then be used to connect to the redundant server when conditions were appropriate for failover.

Since your development environment does not need this extra property file but your test environment does, you can simply clone the correct property file template in the App-Config project, but only in the test directory tree, and configure it with the failover server connection information.

There are some downsides to this architecture, which are also worth noting:

  • Whenever a new property file is added to an application, the property file must be templatized and added to the App-Config project in each directory tree (dev,test,prod). In addition, the project’s pom.xml must be modified so that the property file is copied to target/conf.
  • Every Maven project you build will be dependent on two other Maven projects: Parent-POM and App-Config. Projects will therefore not be self-contained with respect to the build process. This is somewhat mitigated by setting up a shared Maven repository for your projects, such as Archiva. The build process would then use the shared repository to find the App-Config and Parent-POM artifacts.
  • During the clean phase, each project has a copy of every property file, property key, and property value for all environments in its target/alternate-resources directory. In practice, this has not been shown to cause any significant performance degradation, but it’s still not ideal.

I believe the benefits of the environment-aware Maven build process (that is, having a uniform strategy and solution for managing all properties across environments for every Java project) outweigh its few downsides. You are welcome to download the source files that come along with this project and use them to set up your own environment-aware build process.

Paul Spinelli is currently CTO of the San Diego-based startup Tactical Edge. Since graduating from the University of Virginia with a bachelor’s degree in computer science, Paul has worked as a software developer for over 13 years. His experience has brought him an in-depth knowledge of various programming languages, OOP techniques, and security technologies.