Java – Specifying runtime configuration parameters to a Maven built Web Application

configurationdeploymentjavamavenwar

I am a newcomer to Maven, and I was wondering if there was a reasonable way of specifying configuration information parameters to a web application at buildtime.

What I mean by this is the following. With Ant, I usually create a folder (e.g. config-params) and in that folder I place some property files or whatever other necessary files with the right settings for the environments in which my application will run.

For example:

- test.jdbc.properties
- cert.jdbc.properties
- prod.jdbc.properties
- test.log4j.properties
- test.myapplication.properties
- test.web.xml

... ad nauseum

Then, in my ant build script I just read a profile configuration variable from a project.properties file which simply indicates the set of files that I'd like to use (test, cert or prod).

This way, I don't have to worry about checking every possible framework configuration parameter when I build the application for a known environment.

So two questions:

  1. Is this possible to achieve with a Maven POM in a non hackish way? Is there a piece of Maven documentation, book or reference which deals with this stage of an application build?

  2. Is there a more sensible way to target my application build profile towards a specific execution evironment (test, prod, etc)? I guess this one might be more open to debate but if there's a simpler, more elegant way of dealing with this, I'm all ears :P.

I thank you for any help you can provide. Cheers!

Best Answer

The first thing i would suggest to put your configuration for the test env into src/test/resources which can be used for test automatically by Maven. The production configuration should be located into src/main/resources which means that the production configuration will automatically be used during the packaging and releasing. The other configuration target like cert means you need to build your application a second time for a different environment.

Do you build by a CI environment which produces artifacts for the different environments ? Yes than a solution based on profiles is not a good choice simply based on the need to build your application for every environment separately. It would be better to build only once having artifacts which represent the different environments. Lets start with something like this:

.
|-- pom.xml
`-- src
    |-- main
    |   |-- java
    |   |-- resources
    |   |-- environment
    |   |   |-- test
    |   |   |   `-- database.properties
    |   |   |-- qa
    |   |   |   `-- database.properties
    |   |   `-- production
    |   |       `-- database.properties
    |   `-- webapp

For every environment you have a folder which contains the different configuration parts (in this case property files). You need a configuration file (for every environment) for the maven-assembly-plugin like the following:

<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">

  <id>test</id>
  <formats>
    <format>war</format>
  </formats>
  <includeBaseDirectory>false</includeBaseDirectory>
  <dependencySets>
    <dependencySet>
      <unpack>true</unpack>
      <useProjectArtifact>true</useProjectArtifact>
    </dependencySet>
  </dependencySets>
  <fileSets>
    <fileSet>
      <outputDirectory>WEB-INF</outputDirectory>
      <directory>${basedir}/src/main/environment/test/</directory>
      <includes>
        <include>**</include>
      </includes>
    </fileSet>
  </fileSets>
</assembly>

And of course a configuration for the maven-assembly-plugin like this:

 <plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <executions>
      <execution>
        <id>test</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
        <configuration>
          <descriptors>
            <descriptor>${project.basedir}/src/main/assembly/test.xml</descriptor>
          </descriptors>
        </configuration>
      </execution>
      <execution>
        <id>qa</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
        <configuration>
          <descriptors>
            <descriptor>${project.basedir}/src/main/assembly/qa.xml</descriptor>
          </descriptors>
        </configuration>
      </execution>
      <execution>
        <id>production</id>
        <phase>package</phase>
        <goals>
          <goal>single</goal>
        </goals>
        <configuration>
          <descriptors>
            <descriptor>${project.basedir}/src/main/assembly/production.xml</descriptor>
          </descriptors>
        </configuration>
      </execution>
    </executions>
  </plugin>

The result is having just a single build which produces a single artifact for each environment like this:

  1. artifactId-version-test.war

  2. artifactId-version-qa.war

  3. artifactId-version-production.war