Maven
[ trygvis ] 15:12, Sunday, 1 January 2006

Building the same artifact for different environments has always been an annoyance. You have multiple environments, for instance test and production servers or, maybe a set of servers that run the same application with different configurations. In this guide I'll explain how you can use profiles to build and package artifacts configured for specific environments. See [1] for a more in-depth explanation of the profile concept.

Note:

  • This guide assume that you have basic Maven 2 knowledge.
  • It will show a way to configure Maven to solve simple configuration set-ups only. By simple configuration set-up I mean cases where you only have a single file or a small set of files that vary for each environment. There are other and better ways to handle two and many-dimensional configuration issues.

This example assume the use of the Standard Directory Layout[2]. A fully-working example project can be found at [3].

pom.xml
src/
  main/
    java/
    resources/
  test/
    java/

Under src/main/resources there are three files:

  • environment.properties - This is the default configuration and will be packaged in the artifact by default.
  • environment.test.properties - This is the variant for the test environment.
  • environment.prod.properties - This is basically the same as the test variant and will be used in the production environment.

In the project descriptor, you need to configure the different profiles. Only the test profile is showed here, see the accompanying source code[3] for the full pom.xml.

<profiles>
  <profile>
    <id>test</id>
    <build>
      <plugins>
        <plugin>
          <artifactId>mavenltantrunltplugin</artifactId>
          <executions>
            <execution>
              <phase>test</phase>
              <goals>
                <goal>run</goal>
              </goals>
              <configuration>
                <tasks>
                  <delete file="${project.build.outputDirectory}/environment.properties"/>
                  <copy file="src/main/resources/environment.test.properties" tofile="${project.build.outputDirectory}/environment.properties"/>
                </tasks>
              </configuration>
            </execution>
          </executions>
        </plugin>
        <plugin>
          <artifactId>mavenltsurefireltplugin</artifactId>
          <configuration>
            <skip>true</skip>
          </configuration>
        </plugin>
        <plugin>
          <artifactId>mavenltjarltplugin</artifactId>
          <executions>
            <execution>
              <phase>package</phase>
              <goals>
                <goal>jar</goal>
              </goals>
              <configuration>
                <classifier>test</classifier>
              </configuration>
            </execution>
          </executions>
        </plugin>
      </plugins>
    </build>
  </profile>

  .. Other profiles goes here ..

</profiles>

Three things are configured in this snippet:

  1. It configures the antrun plugin to execute the run goal in the test phase where it will copy the environment.test.properties file to environment.properties .
  2. It will configure the test plugin to skip all tests when building the test and production artifacts. This is useful as you probably don't want to run tests against the production system
  3. It configures the JAR plugin to create an "attached" JAR with the "test" classifier.
To activate this profile execute mvn -Ptest install and maven will execute the steps in the profile in addition to the normal steps. From this build you will get two artifacts, "foo-1.0.jar" and "foo-1.0-test.jar". These two jars will identical.

Caveats

  • Currently Maven 2 doesn't allow a project build to only produce attached artifacts. (i.e. it has to produce a "main" artifact as well) This results in two equal JARs beeing packaged and installed. The JAR plugin probably should also get improved support for this use case to that two different output directories will be used as the basis for building the JAR.
  • The usage of the delete task might seem a bit odd but is required to make sure that the copy task actually will copy the file. The copy task will look at the timestamps of the source and destination files, only when copying the files it won't know that the actualy source file might be different than the last time it was executed.
  • After the build the test configuration will be in target/classes and won't be overridden because the resources plugin uses the same timestamp checking, so you should always do a clean after executing Maven with a profile.
  • For the reasons given above it's imperative that you only build an artifact for a single environment in a single execution at a time and that you execute "mvn clean" whenever you change the profile switches. If not, you might get artifacts with a mixed set of configuration files.

Resources

  1. Introduction to Build Profiles
  2. Introduction to the Standard Directory Layout
  3. The accompanying source code
[ trygvis ] 17:35, Friday, 16 September 2005

So javaZone is over again and I'm as exhausted as one can be. Just as Vincent, I had a talk about Maven 2, you can find my slides here. It might be fun comparing them to the talk I gave last year on Maven 2 & Continuum. If you have any questions about the content feel free to email me or ask questions on the Maven users list.

As I said in the talk the beta 1 release of Maven 2 is released.

[ trygvis ] 17:35, Friday, 16 September 2005

So javaZone is over again and I'm as exhausted as one can be. Just as Vincent, I had a talk about Maven 2, you can find my slides here. It might be fun comparing them to the talk I gave last year on Maven 2 & Continuum. If you have any questions about the content feel free to email me or ask questions on the Maven users list.

As I said in the talk the beta 1 release of Maven 2 is released.

[ trygvis ] 03:16, Tuesday, 9 August 2005

Beeing a fan of open and free source and all I want to make sure that Maven will run properly on at least one of all the free runtimes that's out there. So here the other day with a few moments to spare I took it for a spin.

The first snag I ran into was that of course Sun's javac won't run on a non-Sun JVM so I had to brush the dust off of our old Eclipse compiler. The Eclipse compiler is a Java compiler written in Java with out any dependencies. So after adding this to the root POM:


    
      
        maven-compiler-plugin
        
          eclipse
        
      
    
  ]]>
to select the Eclipse compiler and after that it all worked (as expected)!

Now this is there I'm supposed to include some summary and performance comparisons between the diffrent free VMs but of course I've lot the file with all my notes so I'll update the entry later next time I get some spare time.

I used JamVM as the virtual machine and executed Maven 2 with this command:

JAVACMD=`which jamvm` m2 clean:clean install

I've already looked into what's requred for getting Maven 2 into at least Debian, it beeing my personal distro of choice. I've gotten almost all of the dependencies either packaged as a normal Java Debian packages or building as a part of my "m2-bootstrap" package so hopefully with either more spare time or more volunteers (wink wink, nudge nudge) Maven 2 should be available as a Debian package ... sometime.

[ trygvis ] 12:17, Saturday, 9 April 2005

The Maven team just released a technology preview of Maven 2.

Check out the release blog entry at Brett's blog or go directly to start.

For more Maven news make sure you check out the Maven blogs site.