Author: skitching Date: Thu Jan 19 04:16:56 2006 New Revision: 370464 URL: http://svn.apache.org/viewcvs?rev=370464&view=rev Log: Walk the entire hierarchy of ClassLoaders, releasing memory for the current webapp from each copy of LogFactory found.
Modified: jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/ServletContextCleaner.java Modified: jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/ServletContextCleaner.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/ServletContextCleaner.java?rev=370464&r1=370463&r2=370464&view=diff ============================================================================== --- jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/ServletContextCleaner.java (original) +++ jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/ServletContextCleaner.java Thu Jan 19 04:16:56 2006 @@ -17,8 +17,11 @@ package org.apache.commons.logging.impl; -import javax.servlet.ServletContextListener; +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + import javax.servlet.ServletContextEvent; +import javax.servlet.ServletContextListener; import org.apache.commons.logging.LogFactory; @@ -48,6 +51,8 @@ */ public class ServletContextCleaner implements ServletContextListener { + + private Class[] RELEASE_SIGNATURE = {ClassLoader.class}; /** * Invoked when a webapp is undeployed, this tells the LogFactory @@ -55,7 +60,47 @@ * contextClassloader. */ public void contextDestroyed(ServletContextEvent sce) { - LogFactory.release(Thread.currentThread().getContextClassLoader()); + ClassLoader tccl = Thread.currentThread().getContextClassLoader(); + + Object[] params = new Object[1]; + params[0] = tccl; + + // Walk up the tree of classloaders, finding all the available + // LogFactory classes and releasing any objects associated with + // the tccl (ie the webapp). + ClassLoader loader = tccl; + while (loader != null) { + // Load via the current loader. Note that if the class is not accessable + // via this loader, but is accessable via some ancestor then that class + // will be returned. + try { + Class logFactoryClass = loader.loadClass("org.apache.commons.logging.LogFactory"); + Method releaseMethod = logFactoryClass.getMethod("release", RELEASE_SIGNATURE); + releaseMethod.invoke(null, params); + loader = logFactoryClass.getClassLoader().getParent(); + } catch(ClassNotFoundException ex) { + // Neither the current classloader nor any of its ancestors could find + // the LogFactory class, so we can stop now. + loader = null; + } catch(NoSuchMethodException ex) { + // This is not expected; every version of JCL has this method + System.err.println("LogFactory instance found which does not support release method!"); + loader = null; + } catch(IllegalAccessException ex) { + // This is not expected; every ancestor class should be accessable + System.err.println("LogFactory instance found which is not accessable!"); + loader = null; + } catch(InvocationTargetException ex) { + // This is not expected + System.err.println("LogFactory instance release method failed!"); + loader = null; + } + } + + // Just to be sure, invoke release on the LogFactory that is visible from + // this ServletContextCleaner class too. This should already have been caught + // by the above loop but just in case... + LogFactory.release(tccl); } /** --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]