ContextClassLoaderSwitcher.java |
/*************************************** * * * JBoss: The OpenSource J2EE WebOS * * * * Distributable under LGPL license. * * See terms of license at gnu.org. * * * ***************************************/ package org.jboss.util.loading; import java.security.AccessController; import java.security.PrivilegedAction; import org.jboss.logging.Logger; /** * A helper for context classloading switching.<p> * * When a security manager is installed, the * constructor checks for the runtime permissions * "getClassLoader" and "setContextClassLoader". * This allows the methods of this class to be used later without * having to run in privileged blocks. * * There are optimized methods to perform the operations within * a switch context. This avoids retrieving the current thread * on every operation. * * @version <tt>$Revision: 1.4 $</tt> * @author <a href="mailto:adrian@jboss.org">Adrian Brock</a> */ public class ContextClassLoaderSwitcher extends ContextClassLoader { /** * Set the context classloader permission */ public static final RuntimePermission SETCONTEXTCLASSLOADER = new RuntimePermission("setContextClassLoader"); /** * Instantiate a new context class loader switcher */ public static final NewInstance INSTANTIATOR = new NewInstance(); /** * Constructor. * @throws SecurityException when not authroized to get/set the context classloader */ private ContextClassLoaderSwitcher() { super(); SecurityManager manager = System.getSecurityManager(); if (manager != null) manager.checkPermission(SETCONTEXTCLASSLOADER); } /** * Set the context classloader * * @param the new context classloader */ public void setContextClassLoader(final ClassLoader cl) { setContextClassLoader(Thread.currentThread(), cl); } /** * Set the context classloader for the given thread * * @param thread the thread * @param the new context classloader */ public void setContextClassLoader(final Thread thread, final ClassLoader cl) { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { thread.setContextClassLoader(cl); return null; } }); } /** * Retrieve a switch context * * @return the switch context */ public SwitchContext getSwitchContext() { return new SwitchContext(); } /** * Retrieve a switch context and set the new context classloader * * @param cl the new classloader * @return the switch context */ public SwitchContext getSwitchContext(final ClassLoader cl) { return new SwitchContext(cl); } /** * Retrieve a switch context for the classloader of a given class * * @deprecated using a class to determine the classloader is a * bad idea, it has the same problems as Class.forName() * @param clazz the class whose classloader should be set * as the context classloader * @return the switch context */ public SwitchContext getSwitchContext(final Class clazz) { return new SwitchContext(clazz.getClassLoader()); } /** * A helper class to remember the original classloader and * avoid continually retrieveing the current thread. */ public class SwitchContext { /** * The original classloader */ private ClassLoader origCL; /** * The current classloader */ private ClassLoader currentCL; /** * The current thread */ private Thread currentThread; private SwitchContext() { currentThread = Thread.currentThread(); origCL = getContextClassLoader(currentThread); currentCL = origCL; } private SwitchContext(ClassLoader cl) { this(); setClassLoader(cl); } /** * Retrieve the current thread */ public Thread getThread() { return currentThread; } /** * Retrieve the original classloader */ public ClassLoader getOriginalClassLoader() { return origCL; } /** * Retrieve the current classloader * (as set through this class). */ public ClassLoader getCurrentClassLoader() { return currentCL; } /** * Change the context classloader<p> * * The operation is ignored if the classloader is null * or has not changed * * @param cl the new classloader */ public void setClassLoader(ClassLoader cl) { if (cl != null && cl != currentCL) { setContextClassLoader(currentThread, cl); currentCL = cl; } } /** * Reset back to the original classloader, * only when it has changed. */ public void reset() { if (currentCL != null && currentCL != origCL) setContextClassLoader(currentThread, origCL); } /** * Force a reset back to the original classloader, * useful when somebody else might have changed * the thread context classloader so we cannot optimize */ public void forceReset() { setContextClassLoader(currentThread, origCL); } } private static class NewInstance implements PrivilegedAction { public Object run() { return new ContextClassLoaderSwitcher(); } } }
ContextClassLoaderSwitcher.java |