A common need in projects id to use Maven build profiles in order to customize the produced application for different environments. For instance, you might want to use an in-memory database with schema created and test data inserted at webapp startup in your development environment whereas you will use a "normal" database in production.
This article is about introducing different build profiles to tackle down this problem. Using a standard Jspresso project structure, we will define 2 Maven build profiles, dev an prod. The dev build profile should be the default one, whereas the prod profile should be activated (using -Pprod on the command line) to produce a production-specific, deployable webapp.
The first step is to introduce an environment variable that will have its value assigned depending on the activated profile. Edit your project root pom.xml and add the following section (before the <build> tag for instance) :
<properties>
<environment>dev</environment>
</properties>
<profiles>
<profile>
<id>prod</id>
<properties>
<environment>prod</environment>
</properties>
</profile>
</profiles>
This asssigns "dev" as the value of the environment property, unless the prod profile is activated in the Maven build, in which case the environment property is valued with "prod".
In order to adapt the produced webapp to the targeted platform, we will create 2 extra webapp resource directories :
All other common webapp resources will go in the standard webapp/src/main/resources directory.
For the sake of our example, let's say that we want to :
So we will :
We now have to tell Maven to include the different webapp resources directories based on the activated profile. This is done by adding the following xml fragment in the <build> section of the webapp/pom.xml :
<build>
...
<resources>
<resource>
<directory>${basedir}/src/main/resources</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>${basedir}/src/main/${environment}/resources</directory>
<filtering>false</filtering>
</resource>
</resources>
...
</build>
One common use case consists in customizing the built package depending on the target environement. For instance, you can run your development environment using Tomcat and your pre-production / production environment using JBoss. In that case, there are some libraries that have to be packaged in your development webapp war but not in your production war. Most of the time this is because the target environment provides them as part of their runtime infrastructure and packaging them in the application itself can lead to unexpected results (mainly linked to the classloading architecture). In the example above, JBoss will provide several jars that have to be excluded from the war. This is achieved by marking those dependencies as provided in the prod profile, e.g. :
<build>
...
</build>
<profiles>
<profile>
<id>prod</id>
<dependencies>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jboss</groupId>
<artifactId>jbosssx</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>jboss</groupId>
<artifactId>jboss-common</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
</profile>
<profiles>
One last thing we would like to variabilize depending on the targeted environment is the packaged webapp descriptor. For instance, we might want to use different session timeouts for both profiles, disable the insertion of test data on webapp startup for the production war, ...
The standard Jspresso project already contains 2 different web.xml :
In order to further variabilize the used web.xml based on the targeted environment, we will :
We will now tell Maven to package the right web.xml depending on the environment build profile. Edit webapp/pom.xml and look for the 2 <webXml> sections. Replace :
This way, depending on the environment property value, the right web.xml will be picked up for packaging.
Of course, this profile-base build customization can be extended to include different customizations for other domains (e.g. a platform-specific build).
Following our example, everytime you need to create a production artifact, just activate the prod build profile, i.e. :
mvn clean package -Pprod