Sergio Pio Alvarez Sergio Pio Alvarez - 2 months ago 11
Java Question

Simplifying web.xml configuration in Tomcat 7

I need some ideas about how to simplify a web app configuration with Tomcat 7.

I have a web app which uses two resources defined in Tomcat's context.xml config file: a Mail Session and a JDBC Datasource.

<Resource name="mail/MailService" ...
<Resource name="jdbc/JDBCDatasource" ...


In order to use them in the web app I have to declare two references in the web.xml deployment descriptor, specifying the same name:

<resource-ref>
<res-ref-name>mail/MailService</res-ref-name>
...
<resource-ref>
<res-ref-name>jdbc/JDBCDatasource</res-ref-name>
....


Then, in the app code, I have to lookup the resources, again with their names:

Context ctx = new InitialContext();
Session sn = (Session) ctx.lookup("java:comp/env/mail/MailService");
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/JDBCDatasource");


The thing is that the name of the resources may be changed by the sysadmins; so, I cannot hardcode the name of the resources. I could use a context-param, or something like that to allow to the sysadmins to specify the chosen name for each resource, but considering that I have to use the resource-ref part, I would like not to have to specify the same name twice in the web.xml file (one for the param and another for the ref). Duplicating the configuration is kind of duplicating the chances someone make a mistake, and I want to minimize chances of missconfigurations..

I searched the web for things like variables in the web.xml but I did not find anything.. does someone have some ideas about this?

=== RESOLUTION ===

Following the lines pointed out by Brett, this what I did to avoid duplicate the configuration:

First, moved out the resources configuration from Tomcat's context.xml to Tomcat's server.xml, inside the GlobalNamingResources area, using general names:

<GlobalNamingResources>
...
<Resource name="mail/MailService1" ...
<Resource name="jdbc/JDBCDatasource1" ...
...


Then, I created two ResourceLink in the app context.xml file (note is not the Tomcat one), where each links has the exact name used by the app, and point, through the global attribute, to the resource:



<ResourceLink name="jdbc/MyAppJDBCService" global="jdbc/JDBCDatasource1" type="javax.sql.DataSource"/>
<ResourceLink name="mail/MyAppMailService" global="mail/MailService1" type="javax.mail.Session"
/>


With that, the references to the resources in the app's web.xml is not necessary any more.

Finally, in the app source code I changed the lookup part to use the names specified in the context.xml (and not the ones used in the server.xml):

Context ctx = new InitialContext();
Session sn = (Session) ctx.lookup("java:comp/env/mail/MyAppMailService");
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/MyAppJDBCService");


With this setup, the admin is responsable for configuring the resources in the Tomcat's server.xml file, using the names he/she wants, and the deployer just have to map that names to the ones used by the app just modifing the app's context.xml.

It is pretty simple now, but I was doint it badly before.

Answer

The thing is that the name of the resources may be changed by the sysadmins; so, I cannot hardcode the name of the resources

This is either wrong or is using the wrong terminology. In the Java EE architecture, the application owns the resource reference name, and the system administrator must ensure the resource reference is satisfied. If the application requires a resource reference named mail/MailService, then it should declare the reference name via <res-ref-name> or @Resource. The administrator must then ensure the resource reference with that name is satisfied by linking it to a resource. In Tomcat, you can either directly declare the resource using the resource reference name, or you can declare a global resource with whatever name and then link the resource reference to the global resource (in other application servers, this "linking" is often referred to as "binding").