/* * JBoss, Home of Professional Open Source. * Copyright 2006, Red Hat Middleware LLC, and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ /* * Copyright 2005 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.test.classloader.leak.web; import javax.servlet.ServletContextEvent; import javax.servlet.ServletContextListener; public class ClassloaderLeakContextListener implements ServletContextListener { // private Class[] RELEASE_SIGNATURE = {ClassLoader.class}; public void contextInitialized(ServletContextEvent arg0) { org.jboss.test.classloader.leak.clstore.ClassLoaderStore.getInstance().storeClassLoader("WEBAPP", ClassloaderLeakContextListener.class.getClassLoader()); } public void contextDestroyed(ServletContextEvent arg0) { // 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). // // When there is only one LogFactory in the classpath, and it // is within the webapp being undeployed then there is no problem; // garbage collection works fine. // // When there are multiple LogFactory classes in the classpath but // parent-first classloading is used everywhere, this loop is really // short. The first instance of LogFactory found will // be the highest in the classpath, and then no more will be found. // This is ok, as with this setup this will be the only LogFactory // holding any data associated with the tccl being released. // // When there are multiple LogFactory classes in the classpath and // child-first classloading is used in any classloader, then multiple // LogFactory instances may hold info about this TCCL; whenever the // webapp makes a call into a class loaded via an ancestor classloader // and that class calls LogFactory the tccl gets registered in // the LogFactory instance that is visible from the ancestor // classloader. However the concrete logging library it points // to is expected to have been loaded via the TCCL, so the // underlying logging lib is only initialised/configured once. // These references from ancestor LogFactory classes down to // TCCL classloaders are held via weak references and so should // be released but there are circumstances where they may not. // Walking up the classloader ancestry ladder releasing // the current tccl at each level tree, though, will definitely // clear any problem references. // 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 { // System.out.println("Calling LogFactory.release() for " + loader); // 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); } }