Monday, August 22, 2011

Configuring a Web Application in Tomcat

Suppose you have a web application configured for Tomcat using a context configuration file (META-INF/context.xml), as I mentioned in this post. You read Tomcat's documentation saying (not exactly in these words though):
If your .war file contains META-INF/context.xml it will be copied into $CATALINA_HOME/conf/[enginename]/[hostname]/[appname].xml and if there is such a file it won't be overwritten.

You happily created .war packages and shipped to the production, just to start receiving complaints about context configuration being overwritten. This is when you go and read another part of Tomcat's documentation saying:
An update to a WAR which has been expanded will trigger an undeploy (with a removal of the expanded webapp), followed by a deployment.

If we combine these two together, we can conclude that: If you install an application via copying a .war file into the webapp folder, then you are gonna end up losing changes made to the context configuration. There is a bug report associated with this problem, which is marked as WON'T FIX by Tomcat development team. So, if you still insist not to use Application Server's administrative interface, keep reading for a possible fix.

What I have come up with is this:

1- Install an exploded WAR directory somewhere outside Tomcat's appBase, let's assume it is in /usr/local/MyApp. 2- Copy the context configuration file into [tomcat.conf]/[engine]/[hostname] directory, let's call it MyApp.xml. This file will point to the location of the application:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Context configuration file for my web application -->
<Context docBase="/usr/local/MyApp" privileged="true" antiResourceLocking="false" antiJARLocking="false">
<Resource name="jdbc/myapp-ds" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="XXX" password="XXX" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/mydb" />
</Context>


3- You are now free to go and modify the configuration file.

4- Update the application by copying new version of your application in /usr/local/MyApp

Notes:

a) This solution applies to an unexpanded .war file, but since we use Spring's Log4JConfigListener it wouldn't run from an unexploded .war file. Tomcat doesn't explode .war files put outside appBase (webapps) folder.

b) This approach doesn't prevent you from having context.xml in /usr/local/MyApp/META-INF/context.xml since it will not be used by Tomcat in this configuration. You can use it in your dev environment, where you dump your .war file into the appBase (webapps) folder.

I am still looking out for simpler solutions, though.