clime.messadmin.providers.lifecycle.EvilSingletonsUnregisterer Maven / Gradle / Ivy
/**
*
*/
package clime.messadmin.providers.lifecycle;
import java.beans.Introspector;
import java.lang.reflect.Method;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.Enumeration;
import javax.servlet.ServletContext;
import clime.messadmin.providers.spi.ApplicationLifeCycleProvider;
/**
* Takes care of deregistering (some of) the evil Singletons
* when the app shuts down, thereby avoiding (well, trying to avoid)
* OOM (java.lang.OutOfMemoryError) on hot restart...
*
* see http://opensource2.atlassian.com/confluence/spring/pages/viewpage.action?pageId=2669
*
* @author Cédrik LIME
*/
public class EvilSingletonsUnregisterer implements ApplicationLifeCycleProvider {
/**
*
*/
public EvilSingletonsUnregisterer() {
super();
}
/**
* {@inheritDoc}
*/
public int getPriority() {
return Integer.MAX_VALUE;
}
/**
* {@inheritDoc}
*/
public void contextDestroyed(ServletContext servletContext) {
// ThreadLocals - With Great Power, comes Great Responsibility
// Can't do anything here. You need to manually set all your ThreadLocals to null yourself (myThreadLocal.remove() or myThreadLocal.set(null))...
// java.beans.Introspector - Slightly less Evil singleton
// Flushes the cache of classes
// Note this is going to clear ALL the classes, regardless of what ClassLoader or application they came from, but its all that available.
Introspector.flushCaches();
// Jakarta Commons Logging <= 1.0.4
// org.apache.commons.logging.LogFactory.release(Thread.currentThread().getContextClassLoader());
try {
Class logFactoryClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.commons.logging.LogFactory");//$NON-NLS-1$
Method releaseMethod = logFactoryClass.getMethod("release", new Class[] {ClassLoader.class});//$NON-NLS-1$
releaseMethod.invoke(null, new Object[] {Thread.currentThread().getContextClassLoader()});
} catch (Throwable t) {
// ignore
}
// Apache Logging Log4J 1.x
// org.apache.log4j.NDC.remove();
try {
Class ndcClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.log4j.NDC");//$NON-NLS-1$
Method removeMethod = ndcClass.getMethod("remove", null);//$NON-NLS-1$
removeMethod.invoke(null, null);
} catch (Throwable t) {
// ignore
}
// org.apache.log4j.LogManager.shutdown();
try {
Class lmClass = Thread.currentThread().getContextClassLoader().loadClass("org.apache.log4j.LogManager");//$NON-NLS-1$
Method shutdownMethod = lmClass.getMethod("shutdown", null);//$NON-NLS-1$
shutdownMethod.invoke(null, null);
} catch (Throwable t) {
// ignore
}
// java.sql.DriverManager - Evil Singleton
// Although registering the JDBC driver in your web app is a horrible, horrible thing to do (the container should always manage your connections), some apps do just that.
// Unregister JDBC drivers during shutdown: remove any drivers that were loaded by the same classloader that loaded the web app.
Enumeration drivers = DriverManager.getDrivers();
ClassLoader thisClassLoader = Thread.currentThread().getContextClassLoader();//this.getClass().getClassLoader();
while (drivers.hasMoreElements()) {
Driver o = (Driver) drivers.nextElement();
if (o.getClass().getClassLoader() == thisClassLoader){
// Current driver 'o' is being deregistered
try {
DriverManager.deregisterDriver(o);
} catch (SQLException sqle) {
//throw new RuntimeException(sqle.getMessage());//new RuntimeException(sqle);
System.err.println("Failed to cleanup DriverManager for webapp:");
sqle.printStackTrace();
}
} else {
// Driver 'o' wasn't loaded by this webapp, so no touching it
}
}
}
/**
* {@inheritDoc}
*/
public void contextInitialized(ServletContext servletContext) {
}
}