views:

73

answers:

3

I'm using Tomcat as a servlet container, and have many WARs deployed. Many of the WARs share common base classes, which are replicated in each context due to the different classloaders, etc.

How can I ensure resource cleanup on context destruction, without hooking each and every web.xml file to add context listeners?

Ideally, I'd like something along the lines of

class MyResourceHolder implements SomeListenerInterface {
    private SomeResource resource;
    {
        SomeContextThingie.registerDestructionListener(this);
    }
    public void onDestroy() { resource.close(); }
}

I could put something in each web.xml, but since there are potentially many WARs and only ones that actually initialize the resource need to clean it up, it seems more natural to register for cleanup when the resource is initialized rather than duplicating a lot of XML configuration and then maybe cleaning up.

(In this particular case, I'm initiating an orderly shutdown of a SQL connection pool. But I see this being useful in many other situations as well...)

I'm sure there's some blisteringly obvious solution out there, but my Google-fu is failing me right now. Thanks!

+1  A: 

You could put the resources in a shared-classloader and make them available as JNDI resources - you'd have to be very careful to keep your apps in sync by doing that though - though it's an option.

Might depend on what kind of resources you're cleaning, and what kind of churn you expect to see in your API.

Note: Classloader issues can be very difficult to debug - "Class XClass is not an instance of XClass" can drive you nuts.

Edit1: Another options: you could use finalizers on your pool or other object - this should allow you to execute code (say when a webapp is unloaded and the pool is recycled) - this is how many JDK classes clean up native resources. If you do this though, be very careful as deadlocking on the finalizer queue will block all kinds of important cleanup, and likely crash your JVM, since nothing which uses finalizers will get gc'd.

jayshao
Yeah, classloaders are a pain. I'd do this but I would prefer not to introduce the additional complexity of JNDI and actually sharing the resources, as the system is already complex and hard to understand!
Steven Schlansker
Well, barring a shared class-loader, trying to handle resource cleanup in multiple classloaders is very unclean. You could also use finalizers - be *very careful* - deadlocking on the finalizer queue will kill your system - I'll edit the answer to include that.
jayshao
+2  A: 

There's no other feasible option than ServletContextListener.

If you're already on Servlet 3.0, then you could just annotate it with @WebListener, ship it with the webapp and it will be automagically loaded. But with Servlet 2.5 and older you really need to hassle with the web.xml.

BalusC
Darn. Not using 3.0 yet, and in fact Tomcat 6 doesn't seem to support it. Looks like in a few years it'll be much easier :-p
Steven Schlansker
Tomcat 7.0 supports it. It's almost final. You can get RC's by SVN [here](http://svn.apache.org/repos/asf/tomcat/tc7.0.x/tags/).
BalusC
@BalusC, Tomcat 7 went beta on June 29th. Hence an official download page: http://tomcat.apache.org/download-70.cgi
Thorbjørn Ravn Andersen
@Thor: Hey, thanks, going to check it out :)
BalusC
A: 

Move your SQL Connection pool out of the web application and into the web container, and access it through JNDI.

Thorbjørn Ravn Andersen