Maven (build manager for Java projects) has a feature called "
filtering". As is generally known you can replace with Maven any variables defined with placeholders like
${my.variable}. Such variables can be placed in property files or any other resource files like CSS, JavaScript, (X)HTML. I normally place placeholders in
web.xml and replace them by real values while Maven runs with a certain profile. My default Maven profile is e.g. "
development". Another profile is "
release". To build artefacts with "
release" profile I run
mvn -Prelease clean install
Option
-P is for profile you want to build software with. How to set up filtering of
web.xml exactly? At first we need to create a directory "
filter" under "
src/main" and place two (or more) property files under "
src/main/filter". In order to demonstrate filtering for two profiles I'm going to create
development.properties and
release.properties. So, our structure looks now as follows:
Let us define the content of
development.properties as
jsf.faceletsRefreshPeriod=2
jsf.resourceUpdateCheckPeriod=2
and the content of
release.properties as
jsf.faceletsRefreshPeriod=-1
jsf.resourceUpdateCheckPeriod=-1
The next step is to modify
web.xml.
web.xml gets two placeholders:
...
<context-param>
<param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>${jsf.faceletsRefreshPeriod}</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.resourceUpdateCheckPeriod</param-name>
<param-value>${jsf.resourceUpdateCheckPeriod}</param-value>
</context-param>
...
The last step is to modify
pom.xml. Actually we don't need two profiles. Let us only define the "
release" profile and assume default case without any profiles as "
development".
<profiles>
<profile>
<id>release</id>
<properties>
<webapp.filter>release</webapp.filter>
</properties>
</profile>
</profiles>
Important thing is to define a property "
webapp.filter" for "
release" profile. For default case we have also to add this line to
pom.xml (somewhere at the end):
<properties>
<webapp.filter>development</webapp.filter>
</properties>
To make it working together with maven-war plugin (in this case) we need to activate filtering feature. That means, before WAR archive gets packed, placeholders in
web.xml should be already replaced by real values from property files. This task is simple:
<plugin>
<artifactId>maven-war-plugin</artifactId>
<executions>
<execution>
<id>war</id>
<phase>package</phase>
<goals>
<goal>war</goal>
</goals>
<configuration>
...
<filteringDeploymentDescriptors>true</filteringDeploymentDescriptors>
<filters>
<filter>${basedir}/src/main/filter/${webapp.filter}.properties</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
We leverages here the variable
${webapp.filter} which points to file name depends on currently active profile. That's all. You can now run builds with
// build for development
mvn clean install
// build for release
mvn -Prelease clean install
There is only one issue when using Jetty Maven plugin and let it runs with
mvn jetty:run
Jetty looks as default under source directory and scans
src/main/webapp/WEB-INF/web.xml. But located there
web.xml has placeholders. How to solve that? A solution is easy. This is a bonus part of this post. We can leverages
overrideDescriptor tag and specify a XML file with our own parts of
web.xml which overwrite the same parts in
src/main/webapp/WEB-INF/web.xml when Jetty running.
<plugin>
<groupId>org.mortbay.jetty</groupId>
<artifactId>maven-jetty-plugin</artifactId>
<configuration>
<webAppConfig>
...
<overrideDescriptor>src/main/resources/overrideweb.xml</overrideDescriptor>
</webAppConfig>
</configuration>
</plugin>
The content of
overrideweb.xml is (we normally need settings for default "
development" profile when Jetty running)
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="2.5"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">
<context-param>
<param-name>javax.faces.FACELETS_REFRESH_PERIOD</param-name>
<param-value>2</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.resourceUpdateCheckPeriod</param-name>
<param-value>2</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.injectionProvider</param-name>
<param-value>com.sun.faces.vendor.WebContainerInjectionProvider</param-value>
</context-param>
<context-param>
<param-name>com.sun.faces.spi.AnnotationProvider</param-name>
<param-value>com.sun.faces.config.AnnotationScanner</param-value>
</context-param>
<listener>
<listener-class>com.sun.faces.config.ConfigureListener</listener-class>
</listener>
</web-app>
Happy filtering!