Skip to content

Instantly share code, notes, and snippets.

@gissuebot
Created July 7, 2014 18:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gissuebot/d6ab8d55d9b6c53f020c to your computer and use it in GitHub Desktop.
Save gissuebot/d6ab8d55d9b6c53f020c to your computer and use it in GitHub Desktop.
Migrated attachment for Guice issue 288, comment 69
import java.lang.ref.PhantomReference;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Timer;
import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
public class GuiceLifecycleListener implements ServletContextListener {
private static final org.apache.juli.logging.Log log = org.apache.juli.logging.LogFactory.getLog( GuiceLifecycleListener.class );
public void contextInitialized(ServletContextEvent event) {}
public void contextDestroyed(ServletContextEvent event) {
Thread[] threads = getThreads();
String[] guicePrefixes = {
"com.google.inject.internal.", // google guice 2.0
"com.google.inject.internal.util.$" // google guice 3.0
};
for (String guicePrefix : guicePrefixes) {
for (Thread thread : threads) {
if (thread == null) continue;
// Try to shutdown the Finalizer Thread
try {
if (thread.getClass().getName().equals(guicePrefix + "Finalizer")) {
Class mapMakerClass = Class.forName(guicePrefix + "MapMaker");
Class[] classes = mapMakerClass.getDeclaredClasses();
for (Class clazz: classes) {
if (clazz.getName().equals(guicePrefix + "MapMaker$QueueHolder")) {
Object finalizableReferenceQueue = getFieldInstance(null, clazz, "queue");
Object referenceQueue = getFieldInstance(finalizableReferenceQueue, finalizableReferenceQueue.getClass(), "queue");
Object finalizerQueue = getFieldInstance(thread, thread.getClass(), "queue");
// Check that the thread is our instance
if (referenceQueue == finalizerQueue)
{
PhantomReference frqReference = (PhantomReference) getFieldInstance(thread, thread.getClass(), "frqReference");
// Notify the finalizer it can stop
Method enqueue = finalizerQueue.getClass().getDeclaredMethod("enqueue", new Class[] { java.lang.ref.Reference.class });
enqueue.setAccessible(true);
enqueue.invoke(finalizerQueue, new Object[] { frqReference });
log.info(thread.getClass().getName() + " successfully notified to shutdown.");
}
}
}
}
} catch (Exception e) {
log.warn(thread.getClass().getName() + " couldn't be notified to shutdown !", e);
}
// Try to cancel the Expiration Timer
try {
if (thread.getClass().getName().equals("java.util.TimerThread")) {
Class expirationTimerClass = null;
try {
expirationTimerClass = Class.forName(guicePrefix + "ExpirationTimer");
} catch (Exception e) {
// Silently fail
}
if (expirationTimerClass != null) {
Timer instance = (Timer) getFieldInstance(null, expirationTimerClass, "instance");
Thread instanceThread = (Thread) getFieldInstance(instance, instance.getClass(), "thread");
// Check that the thread is our instance
if (instanceThread == thread) {
instance.cancel();
log.info(expirationTimerClass.getName() + " successfully cancelled.");
}
}
}
} catch (Exception e) {
log.warn(thread.getClass().getName() + " couldn't be cancelled !", e);
}
}
}
}
private Object getFieldInstance(Object instance, Class clazz, String name) {
try {
Field field = clazz.getDeclaredField(name);
field.setAccessible(true);
return field.get(instance);
} catch (Exception e) {
return null;
}
}
/* Code from apache tomcat 6.0.32 */
private Thread[] getThreads() {
// Get the current thread group
ThreadGroup tg = Thread.currentThread( ).getThreadGroup();
// Find the root thread group
while (tg.getParent() != null) {
tg = tg.getParent();
}
int threadCountGuess = tg.activeCount() + 50;
Thread[] threads = new Thread[threadCountGuess];
int threadCountActual = tg.enumerate(threads);
// Make sure we don't miss any threads
while (threadCountActual == threadCountGuess) {
threadCountGuess *=2;
threads = new Thread[threadCountGuess];
// Note tg.enumerate(Thread[]) silently ignores any threads that
// can't fit into the array
threadCountActual = tg.enumerate(threads);
}
return threads;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment