JNDI and the Tomcat Deployer
Tomcat’s Deployer can be a blessing and/or a curse. The documtation is lacking and some configurations don’t play nice with WAR files that are installed or deployed with the deployer tasks.
The particular issue I’m addressing here is the use of JNDI resources. If you expect to have environment-agnositc JNDI resources in a context fragment and still use the deployer, you are out of luck. But there is a solution.
My preferred configuration has always been one that results in a completely generic WAR distrubution of my web app. What I mean by this is that nothing server-specific is packaged with the app. This includes data sources, configurable paths, mail server addresses and all the like — things typically stored in JNDI resources. If you use properties files to accomplish the above, you’ve already learned that you can’t ship the properties file with the app if you intend on having different values for each server you deploy to.
To make the WAR file generic and also leave the Tomcat instance’s server.xml unmodified, we can store our JNDI resource configuration inside a Context Fragment — an XML snippet consisting of only the node which would normally be a child of in the server.xml. The context fragment is stored in the conf/[engine]/[host] directory of the server and is typically named [webapp_name].xml. The manager and admin webapps use context fragments in just such a manner.
The problem arises when we attempt to deploy a WAR to the server using the client Ant tasks — a deployed WAR is installed on the server and deletes any Context Fragment present! I believe this is by design, but I wish it were configurable.
If we move the contents of our context fragment’s XML file into the server.xml, we have a similar issue. In this case, the container won’t physically delete the node, but it will remove its in-memory copy and replace it with an on-the-fly copy with no specific attributes. Bugger.
The solution is livable, but possibly not obvious up front. The strategy is to include any necessary JNDI resources in server.xml in the section, and reference them with nodes in our own context fragment. This keeps the definition on the server, but what about our “transient” context fragment? Easy — we provide an “exmaple” context fragment with our WAR file. This file is an exact copy of what we want the context fragment to look like and it is packaged in /META-INF/context.xml relative to the root of the webapp. Since the resources are defined in server.xml, no actual values are stored here, only links to them.
I’ve tested this on Tomcat 5.0.28 and it works like a champ. I’ve had to sacrifice the ability to leave my server.xml unharmed, but I can live with that.