1
0

Minor AccessController-related tidyups:

* Use static initialiser block to initialise factories rather than variable initialiser.
* Add static member thisClassLoader to cache classloader for the LogFactory class;
  change all calls to LogFactory.class.getClassLoader() to just use thisClassLoader.
* Change getContextClassLoader to always use AccessController (actually, rename
  getContextClassLoader to directGetContextClassLoader, and make getContextClassLoader
  a wrapper around that).
* define a method getClassLoader(clazz) that just does clazz.getClassLoader for now;
  change all calls to clazz.getClassLoader into getClassLoader(clazz)


git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@170501 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Simon Kitching
2005-05-17 01:43:32 +00:00
parent 0a54560d5c
commit e985f2a051

View File

@@ -118,13 +118,23 @@ public abstract class LogFactory {
/** Name used to load the weak hashtable implementation by names */ /** Name used to load the weak hashtable implementation by names */
private static final String WEAK_HASHTABLE_CLASSNAME = "org.apache.commons.logging.impl.WeakHashtable"; private static final String WEAK_HASHTABLE_CLASSNAME = "org.apache.commons.logging.impl.WeakHashtable";
/**
* A reference to the classloader that loaded this class. This is the
* same as LogFactory.class.getClassLoader(). However computing this
* value isn't quite as simple as that, as we potentially need to use
* AccessControllers etc. It's more efficient to compute it once and
* cache it here.
*/
private static ClassLoader thisClassLoader;
// ----------------------------------------------------------- Constructors // ----------------------------------------------------------- Constructors
/** /**
* Protected constructor that is not available for public use. * Protected constructor that is not available for public use.
*/ */
protected LogFactory() { } protected LogFactory() {
}
// --------------------------------------------------------- Public Methods // --------------------------------------------------------- Public Methods
@@ -219,7 +229,7 @@ public abstract class LogFactory {
* The previously constructed <code>LogFactory</code> instances, keyed by * The previously constructed <code>LogFactory</code> instances, keyed by
* the <code>ClassLoader</code> with which it was created. * the <code>ClassLoader</code> with which it was created.
*/ */
protected static Hashtable factories = createFactoryStore(); protected static Hashtable factories = null;
/** /**
* Prevously constructed <code>LogFactory</code> instance as in the * Prevously constructed <code>LogFactory</code> instance as in the
@@ -293,13 +303,7 @@ public abstract class LogFactory {
public static LogFactory getFactory() throws LogConfigurationException { public static LogFactory getFactory() throws LogConfigurationException {
// Identify the class loader we will be using // Identify the class loader we will be using
ClassLoader contextClassLoader = ClassLoader contextClassLoader = getContextClassLoader();
(ClassLoader)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return getContextClassLoader();
}
});
// Return any previously registered factory for this class loader // Return any previously registered factory for this class loader
LogFactory factory = getCachedFactory(contextClassLoader); LogFactory factory = getCachedFactory(contextClassLoader);
@@ -390,7 +394,8 @@ public abstract class LogFactory {
// Fourth, try the fallback implementation class // Fourth, try the fallback implementation class
if (factory == null) { if (factory == null) {
factory = newFactory(FACTORY_DEFAULT, LogFactory.class.getClassLoader()); ClassLoader logFactoryClassLoader = getClassLoader(LogFactory.class);
factory = newFactory(FACTORY_DEFAULT, logFactoryClassLoader);
} }
if (factory != null) { if (factory != null) {
@@ -508,16 +513,87 @@ public abstract class LogFactory {
/** /**
* Return the thread context class loader if available. * Safely get access to the classloader for the specified class.
* Otherwise return null. * <p>
* * Theoretically, calling Class.getClassLoader can throw a security
* The thread context class loader is available for JDK 1.2 * exception, and so should be done under an AccessController in order
* or later, if certain security conditions are met. * to provide maximum flexibility.
* * <p>
* @exception LogConfigurationException if a suitable class loader * However in practice people don't appear to use security policies that
* cannot be identified. * forbid getClassLoader calls, so for the moment this method doesn't
* bother to actually do that. As all code is written to call this
* method rather than Class.getClassLoader, AccessController stuff could
* be put in this method without any disruption later if needed.
* <p>
* Even when using an AccessController, however, this method can still
* throw SecurityException. Commons-logging basically relies on the
* ability to access classloaders, ie a policy that forbids all
* classloader access will also prevent commons-logging from working:
* currently this method will throw an exception preventing the entire app
* from starting up. Maybe it would be good to detect this situation and
* just disable all commons-logging? Not high priority though - as stated
* above, security policies that prevent classloader access aren't common.
*
*/
protected static ClassLoader getClassLoader(Class clazz) {
try {
return clazz.getClassLoader();
} catch(SecurityException ex) {
throw ex;
}
}
/**
* Calls LogFactory.directGetContextClassLoader under the control of an
* AccessController class. This means that java code running under a
* security manager that forbids access to ClassLoaders will still work
* if this class is given appropriate privileges, even when the caller
* doesn't have such privileges. Without using an AccessController, the
* the entire call stack must have the privilege before the call is
* allowed.
*
* @return the context classloader associated with the current thread,
* or null if security doesn't allow it.
*
* @throws LogConfigurationException if there was some weird error while
* attempting to get the context classloader.
*
* @throws SecurityException if the current java security policy doesn't
* allow this class to access the context classloader.
*/ */
protected static ClassLoader getContextClassLoader() protected static ClassLoader getContextClassLoader()
throws LogConfigurationException {
return (ClassLoader)AccessController.doPrivileged(
new PrivilegedAction() {
public Object run() {
return directGetContextClassLoader();
}
});
}
/**
* Return the thread context class loader if available; otherwise return
* null.
* <p>
* Most/all code should call getContextClassLoader rather than calling
* this method directly.
* <p>
* The thread context class loader is available for JDK 1.2
* or later, if certain security conditions are met.
* <p>
* Note that no internal logging is done within this method because
* this method is called every time LogFactory.getLogger() is called,
* and we don't want too much output generated here.
*
* @exception LogConfigurationException if a suitable class loader
* cannot be identified.
*
* @exception SecurityException if the java security policy forbids
* access to the context classloader from one of the classes in the
* current call stack.
*/
protected static ClassLoader directGetContextClassLoader()
throws LogConfigurationException throws LogConfigurationException
{ {
ClassLoader classLoader = null; ClassLoader classLoader = null;
@@ -560,7 +636,7 @@ public abstract class LogFactory {
} }
} catch (NoSuchMethodException e) { } catch (NoSuchMethodException e) {
// Assume we are running on JDK 1.1 // Assume we are running on JDK 1.1
classLoader = LogFactory.class.getClassLoader(); classLoader = getClassLoader(LogFactory.class);
} }
// Return the selected class loader // Return the selected class loader
@@ -666,20 +742,20 @@ public abstract class LogFactory {
return (LogFactory) logFactoryClass.newInstance(); return (LogFactory) logFactoryClass.newInstance();
} catch (ClassNotFoundException ex) { } catch (ClassNotFoundException ex) {
if (classLoader == LogFactory.class.getClassLoader()) { if (classLoader == thisClassLoader) {
// Nothing more to try, onwards. // Nothing more to try, onwards.
throw ex; throw ex;
} }
// ignore exception, continue // ignore exception, continue
} catch (NoClassDefFoundError e) { } catch (NoClassDefFoundError e) {
if (classLoader == LogFactory.class.getClassLoader()) { if (classLoader == thisClassLoader) {
// Nothing more to try, onwards. // Nothing more to try, onwards.
throw e; throw e;
} }
} catch(ClassCastException e){ } catch(ClassCastException e){
if (classLoader == LogFactory.class.getClassLoader()) { if (classLoader == thisClassLoader) {
// Nothing more to try, onwards (bug in loader implementation). // Nothing more to try, onwards (bug in loader implementation).
throw e; throw e;
} }
@@ -729,4 +805,28 @@ public abstract class LogFactory {
} }
}); });
} }
// ----------------------------------------------------------------------
// Static initialiser block to perform initialisation at class load time.
//
// We can't do this in the class constructor, as there are many
// static methods on this class that can be called before any
// LogFactory instances are created, and they depend upon this
// stuff having been set up.
//
// Note that this block must come after any variable declarations used
// by any methods called from this block, as we want any static initialiser
// associated with the variable to run first. If static initialisers for
// variables run after this code, then (a) their value might be needed
// by methods called from here, and (b) they might *override* any value
// computed here!
//
// So the wisest thing to do is just to place this code at the very end
// of the class file.
// ----------------------------------------------------------------------
static {
thisClassLoader = getClassLoader(LogFactory.class);
factories = createFactoryStore();
}
} }