It is a very common requirement to configure JEE web applications according to their current runtime environment. In JEE, web.xml file is aimed to be the configuration unit of those web applications. Unfortunately, it is not designed with such a requirement in mind.
For example, we use JSF and Facelets in our current project. In development environment, we need to turn on debugging feature of Facelets, but will turn it off when the target platform is production environment.
<context-param> <param-name>facelets.DEVELOPMENT</param-name> <param-value>true</param-value> </context-param>
Servlet containers provide a way to define some common elements in a global web.xml file, and let individual applications to inherit those common elements, but that’s it! It would be very nice to be able to bundle a war with more than one web.xml, and choose the one which is appropriate for the current runtime environment. It would even better if we could merge more than one web.xml file, or override some elements defined in one web.xml with those defined in another.
Java community has tried to develop several solutions to this old problem; “building or configuring web.xml according to runtime environment”. SmartFrog has a good overview of those efforts. Each effort has its pros and cons. We have preferred generating web.xml using a template engine. However, maintaining a template and generating web.xml each time a modification occurs while working within IDE makes me feel bad. It has a negative impact on development fluidness. I want to keep a single web.xml which is directly used during development, and will be used as template in order to generate environment specific web.xml file. We have come up with an idea, while we were searching and discussing about possible solutions. Let me illustrate it withas follows;
<context-param> <param-name>facelets.DEVELOPMENT</param-name> <param-value id=”facelets.development”>true</param-value> </context-param>
We decided to use id attribute of xml elements of which values need to be changed according to target platform. We put an id attribute with value “facelets.development” into param-value element, and define a property with same name in a properties file for target platform. All we need to write a post processor which will parse web.xml file, replace contents of those xml elements with id attributes with corresponding property values, and produce a new web.xml before deployment.
Let’s look at another case in which our approach works elegantly. If you don’t have an internet connection in one of your target environments, and one of your libraries tries to process your web xml with Apache Digester, it will fail with complaining that it cannot find or reach at web-app_2_4.xsd file over Internet.
<web-app id="WebApp_ID" version="2.4" xmlns=http://java.sun.com/xml/ns/j2ee xmlns:xsi=http://www.w3.org/2001/XMLSchema-instance xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd" >
In this case our post processor finds out that web-app xml element has an id, and there is a property with same prefix in properties file, as a result it decides to replace value of attribute corresponding to the rest of that property name.
We can as well remove some xml elements out of web.xml with this approach. For example, lets assume your development environment is JBoss, and you use Apache MyFaces. In that case, you will need to tell JBoss that your application comes with its own JSF implementation in your web.xml as follows.
<context-param id=” org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL.render”> <param-name>org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL</param-name> <param-value>true</param-value> </context-param>
However, unless your produdction environment is JBoss, above configuration element will do nothing except creating a mess.In order to remove it from final web.xml file, we just need to add an id attribute with value “org.jboss.jbossfaces.WAR_BUNDLES_JSF_IMPL.render”. Our post processor will remove that context-param xml element when it sees that there is a boolean property with render suffix in project.prod.properties file.
In summary, generating web.xml with a template engine would be more flexible than this approach, but above approach as well covers most of platform specific web.xml configuration requirements.