Spelling
This commit is contained in:
@@ -190,7 +190,7 @@ public abstract class LogFactory {
|
||||
"org.apache.commons.logging.impl.WeakHashtable";
|
||||
|
||||
/**
|
||||
* A reference to the classloader that loaded this class. This is the
|
||||
* A reference to the class loader 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
|
||||
@@ -219,9 +219,9 @@ public abstract class LogFactory {
|
||||
* This can happen when:
|
||||
* <ul>
|
||||
* <li>using JDK1.1 and the calling code is loaded via the system
|
||||
* classloader (very common)</li>
|
||||
* class loader (very common)</li>
|
||||
* <li>using JDK1.2+ and the calling code is loaded via the boot
|
||||
* classloader (only likely for embedded systems work).</li>
|
||||
* class loader (only likely for embedded systems work).</li>
|
||||
* </ul>
|
||||
* Note that {@code factories} is a <i>Hashtable</i> (not a HashMap),
|
||||
* and hashtables don't allow null as a key.
|
||||
@@ -238,7 +238,7 @@ public abstract class LogFactory {
|
||||
// In order to avoid confusion where multiple instances of JCL are
|
||||
// being used via different class loaders within the same app, we
|
||||
// ensure each logged message has a prefix of form
|
||||
// [LogFactory from classloader OID]
|
||||
// [LogFactory from class loader OID]
|
||||
//
|
||||
// Note that this prefix should be kept consistent with that
|
||||
// in LogFactoryImpl. However here we don't need to output info
|
||||
@@ -268,7 +268,7 @@ public abstract class LogFactory {
|
||||
* can return the previously created object (together with all its
|
||||
* cached Log objects).
|
||||
*
|
||||
* @param classLoader should be the current context classloader. Note that
|
||||
* @param classLoader should be the current context class loader. Note that
|
||||
* this can be null under some circumstances; this is ok.
|
||||
* @param factory should be the factory to cache. This should never be null.
|
||||
*/
|
||||
@@ -308,7 +308,7 @@ public abstract class LogFactory {
|
||||
logFactoryClass = classLoader.loadClass(factoryClassName);
|
||||
if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic("Loaded class " + logFactoryClass.getName() + " from classloader " + objectId(classLoader));
|
||||
logDiagnostic("Loaded class " + logFactoryClass.getName() + " from class loader " + objectId(classLoader));
|
||||
}
|
||||
} else //
|
||||
// This indicates a problem with the ClassLoader tree.
|
||||
@@ -322,8 +322,8 @@ public abstract class LogFactory {
|
||||
// ClassLoader hierarchy.
|
||||
//
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic("Factory class " + logFactoryClass.getName() + " loaded from classloader " + objectId(logFactoryClass.getClassLoader())
|
||||
+ " does not extend '" + LogFactory.class.getName() + "' as loaded by this classloader.");
|
||||
logDiagnostic("Factory class " + logFactoryClass.getName() + " loaded from class loader " + objectId(logFactoryClass.getClassLoader())
|
||||
+ " does not extend '" + LogFactory.class.getName() + "' as loaded by this class loader.");
|
||||
logHierarchy("[BAD CL TREE] ", classLoader);
|
||||
}
|
||||
|
||||
@@ -333,7 +333,7 @@ public abstract class LogFactory {
|
||||
if (classLoader == thisClassLoaderRef.get()) {
|
||||
// Nothing more to try, onwards.
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic("Unable to locate any class called '" + factoryClassName + "' via classloader " + objectId(classLoader));
|
||||
logDiagnostic("Unable to locate any class called '" + factoryClassName + "' via class loader " + objectId(classLoader));
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
@@ -342,7 +342,7 @@ public abstract class LogFactory {
|
||||
if (classLoader == thisClassLoaderRef.get()) {
|
||||
// Nothing more to try, onwards.
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic("Class '" + factoryClassName + "' cannot be loaded" + " via classloader " + objectId(classLoader)
|
||||
logDiagnostic("Class '" + factoryClassName + "' cannot be loaded" + " via class loader " + objectId(classLoader)
|
||||
+ " - it depends on some other class that cannot be found.");
|
||||
}
|
||||
throw e;
|
||||
@@ -389,12 +389,12 @@ public abstract class LogFactory {
|
||||
throw new ClassCastException(msg.toString());
|
||||
}
|
||||
|
||||
// Ignore exception, continue. Presumably the classloader was the
|
||||
// Ignore exception, continue. Presumably the class loader was the
|
||||
// TCCL; the code below will try to load the class via thisClassLoaderRef.
|
||||
// This will handle the case where the original calling class is in
|
||||
// a shared classpath but the TCCL has a copy of LogFactory and the
|
||||
// specified LogFactory implementation; we will fall back to using the
|
||||
// LogFactory implementation from the same classloader as this class.
|
||||
// LogFactory implementation from the same class loader as this class.
|
||||
//
|
||||
// Issue: this doesn't handle the reverse case, where this LogFactory
|
||||
// is in the webapp, and the specified LogFactory implementation is
|
||||
@@ -407,17 +407,17 @@ public abstract class LogFactory {
|
||||
/*
|
||||
* At this point, either classLoader == null, OR classLoader was unable to load factoryClass.
|
||||
*
|
||||
* In either case, we call Class.forName, which is equivalent to LogFactory.class.getClassLoader().load(name), that is, we ignore the classloader
|
||||
* parameter the caller passed, and fall back to trying the classloader associated with this class. See the Javadoc for the newFactory method for
|
||||
* In either case, we call Class.forName, which is equivalent to LogFactory.class.getClassLoader().load(name), that is, we ignore the class loader
|
||||
* parameter the caller passed, and fall back to trying the class loader associated with this class. See the Javadoc for the newFactory method for
|
||||
* more info on the consequences of this.
|
||||
*
|
||||
* Notes: * LogFactory.class.getClassLoader() may return 'null' if LogFactory is loaded by the bootstrap classloader.
|
||||
* Notes: * LogFactory.class.getClassLoader() may return 'null' if LogFactory is loaded by the bootstrap class loader.
|
||||
*/
|
||||
// Warning: must typecast here & allow exception
|
||||
// to be generated/caught & recast properly.
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic(
|
||||
"Unable to load factory class via classloader " + objectId(classLoader) + " - trying the classloader associated with this LogFactory.");
|
||||
"Unable to load factory class via class loader " + objectId(classLoader) + " - trying the class loader associated with this LogFactory.");
|
||||
}
|
||||
logFactoryClass = Class.forName(factoryClassName);
|
||||
return logFactoryClass.newInstance();
|
||||
@@ -436,7 +436,7 @@ public abstract class LogFactory {
|
||||
|
||||
/**
|
||||
* Create the hashtable which will be used to store a map of
|
||||
* (context-classloader -> logfactory-object). Version 1.2+ of Java
|
||||
* (context class loader -> logfactory-object). Version 1.2+ of Java
|
||||
* supports "weak references", allowing a custom Hashtable class
|
||||
* to be used which uses only weak references to its keys. Using weak
|
||||
* references can fix memory leaks on webapp unload in some cases (though
|
||||
@@ -504,8 +504,8 @@ public abstract class LogFactory {
|
||||
*
|
||||
* @throws LogConfigurationException if a suitable class loader
|
||||
* cannot be identified.
|
||||
* @return the thread's context classloader or {@code null} if the java security
|
||||
* policy forbids access to the context classloader from one of the classes
|
||||
* @return the thread's context class loader or {@code null} if the java security
|
||||
* policy forbids access to the context class loader from one of the classes
|
||||
* in the current call stack.
|
||||
* @since 1.1
|
||||
*/
|
||||
@@ -535,16 +535,16 @@ public abstract class LogFactory {
|
||||
/**
|
||||
* Check cached factories (keyed by contextClassLoader)
|
||||
*
|
||||
* @param contextClassLoader is the context classloader associated
|
||||
* @param contextClassLoader is the context class loader associated
|
||||
* with the current thread. This allows separate LogFactory objects
|
||||
* per component within a container, provided each component has
|
||||
* a distinct context classloader set. This parameter may be null
|
||||
* a distinct context class loader set. This parameter may be null
|
||||
* in JDK1.1, and in embedded systems where jcl-using code is
|
||||
* placed in the bootclasspath.
|
||||
*
|
||||
* @return the factory associated with the specified classloader if
|
||||
* @return the factory associated with the specified class loader if
|
||||
* one has previously been created, or null if this is the first time
|
||||
* we have seen this particular classloader.
|
||||
* we have seen this particular class loader.
|
||||
*/
|
||||
private static LogFactory getCachedFactory(final ClassLoader contextClassLoader) {
|
||||
if (contextClassLoader == null) {
|
||||
@@ -558,7 +558,7 @@ public abstract class LogFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely get access to the classloader for the specified class.
|
||||
* Safely get access to the class loader for the specified class.
|
||||
* <p>
|
||||
* Theoretically, calling getClassLoader can throw a security exception,
|
||||
* and so should be done under an AccessController in order to provide
|
||||
@@ -572,16 +572,16 @@ public abstract class LogFactory {
|
||||
* Even when using an AccessController, however, this method can still
|
||||
* throw SecurityException. Commons Logging basically relies on the
|
||||
* ability to access class loaders. A policy that forbids all
|
||||
* classloader access will also prevent commons-logging from working:
|
||||
* class loader 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.
|
||||
* above, security policies that prevent class loader access aren't common.
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that returning an object fetched via an AccessController would
|
||||
* technically be a security flaw anyway; untrusted code that has access
|
||||
* to a trusted JCL library could use it to fetch the classloader for
|
||||
* to a trusted JCL library could use it to fetch the class loader for
|
||||
* a class even when forbidden to do so directly.
|
||||
* </p>
|
||||
*
|
||||
@@ -595,7 +595,7 @@ public abstract class LogFactory {
|
||||
return clazz.getClassLoader();
|
||||
} catch (final SecurityException ex) {
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic("Unable to get classloader for class '" + clazz + "' due to security restrictions - " + ex.getMessage());
|
||||
logDiagnostic("Unable to get class loader for class '" + clazz + "' due to security restrictions - " + ex.getMessage());
|
||||
}
|
||||
throw ex;
|
||||
}
|
||||
@@ -604,7 +604,7 @@ public abstract class LogFactory {
|
||||
/**
|
||||
* Locate a user-provided configuration file.
|
||||
* <p>
|
||||
* The classpath of the specified classLoader (usually the context classloader)
|
||||
* The classpath of the specified classLoader (usually the context class loader)
|
||||
* is searched for properties files of the specified name. If none is found,
|
||||
* null is returned. If more than one is found, then the file with the greatest
|
||||
* value for its PRIORITY property is returned. If multiple files have the
|
||||
@@ -691,21 +691,21 @@ public abstract class LogFactory {
|
||||
|
||||
|
||||
/**
|
||||
* Returns the current context classloader.
|
||||
* Returns the current context class loader.
|
||||
* <p>
|
||||
* In versions prior to 1.1, this method did not use an AccessController.
|
||||
* In version 1.1, an AccessController wrapper was incorrectly added to
|
||||
* this method, causing a minor security flaw.
|
||||
* <p>
|
||||
* In version 1.1.1 this change was reverted; this method no longer uses
|
||||
* an AccessController. User code wishing to obtain the context classloader
|
||||
* an AccessController. User code wishing to obtain the context class loader
|
||||
* must invoke this method via AccessController.doPrivileged if it needs
|
||||
* support for that.
|
||||
*
|
||||
* @return the context classloader associated with the current thread,
|
||||
* @return the context class loader 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.
|
||||
* attempting to get the context class loader.
|
||||
*/
|
||||
protected static ClassLoader getContextClassLoader() throws LogConfigurationException {
|
||||
return directGetContextClassLoader();
|
||||
@@ -720,10 +720,10 @@ public abstract class LogFactory {
|
||||
* the entire call stack must have the privilege before the call is
|
||||
* allowed.
|
||||
*
|
||||
* @return the context classloader associated with the current thread,
|
||||
* @return the context class loader 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.
|
||||
* attempting to get the context class loader.
|
||||
*/
|
||||
private static ClassLoader getContextClassLoaderInternal() throws LogConfigurationException {
|
||||
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) LogFactory::directGetContextClassLoader);
|
||||
@@ -745,7 +745,7 @@ public abstract class LogFactory {
|
||||
* this file will be set as configuration attributes on the corresponding {@code LogFactory} instance.
|
||||
* </p>
|
||||
* <p>
|
||||
* <em>NOTE</em> - In a multi-threaded environment it is possible that two different instances will be returned for the same classloader environment.
|
||||
* <em>NOTE</em> - In a multi-threaded environment it is possible that two different instances will be returned for the same class loader environment.
|
||||
* </p>
|
||||
*
|
||||
* @return a {@code LogFactory}.
|
||||
@@ -760,7 +760,7 @@ public abstract class LogFactory {
|
||||
// output will be a nuisance on JDK1.1, as the system
|
||||
// class loader is null in that environment.
|
||||
if (contextClassLoader == null && isDiagnosticsEnabled()) {
|
||||
logDiagnostic("Context classloader is null.");
|
||||
logDiagnostic("Context class loader is null.");
|
||||
}
|
||||
|
||||
// Return any previously registered factory for this class loader
|
||||
@@ -771,7 +771,7 @@ public abstract class LogFactory {
|
||||
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic(
|
||||
"[LOOKUP] LogFactory implementation requested for the first time for context classloader " +
|
||||
"[LOOKUP] LogFactory implementation requested for the first time for context class loader " +
|
||||
objectId(contextClassLoader));
|
||||
logHierarchy("[LOOKUP] ", contextClassLoader);
|
||||
}
|
||||
@@ -947,13 +947,13 @@ public abstract class LogFactory {
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic(
|
||||
"[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT +
|
||||
"' via the same classloader that loaded this LogFactory" +
|
||||
" class (ie not looking in the context classloader).");
|
||||
"' via the same class loader that loaded this LogFactory" +
|
||||
" class (ie not looking in the context class loader).");
|
||||
}
|
||||
|
||||
// Note: unlike the above code which can try to load custom LogFactory
|
||||
// implementations via the TCCL, we don't try to load the default LogFactory
|
||||
// implementation via the context classloader because:
|
||||
// implementation via the context class loader because:
|
||||
// * that can cause problems (see comments in newFactory method)
|
||||
// * no-one should be customising the code of the default class
|
||||
// Yes, we do give up the ability for the child to ship a newer
|
||||
@@ -1117,13 +1117,13 @@ public abstract class LogFactory {
|
||||
* Determines whether the given class actually implements {@code LogFactory}.
|
||||
* Diagnostic information is also logged.
|
||||
* <p>
|
||||
* <strong>Usage:</strong> to diagnose whether a classloader conflict is the cause
|
||||
* <strong>Usage:</strong> to diagnose whether a class loader conflict is the cause
|
||||
* of incompatibility. The test used is whether the class is assignable from
|
||||
* the {@code LogFactory} class loaded by the class's classloader.
|
||||
* the {@code LogFactory} class loaded by the class's class loader.
|
||||
* @param logFactoryClass {@code Class} which may implement {@code LogFactory}
|
||||
* @return true if the {@code logFactoryClass} does extend
|
||||
* {@code LogFactory} when that class is loaded via the same
|
||||
* classloader that loaded the {@code logFactoryClass}.
|
||||
* class loader that loaded the {@code logFactoryClass}.
|
||||
*/
|
||||
private static boolean implementsLogFactory(final Class<?> logFactoryClass) {
|
||||
boolean implementsLogFactory = false;
|
||||
@@ -1131,14 +1131,14 @@ public abstract class LogFactory {
|
||||
try {
|
||||
final ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader();
|
||||
if (logFactoryClassLoader == null) {
|
||||
logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot classloader");
|
||||
logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot class loader");
|
||||
} else {
|
||||
logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader);
|
||||
final Class<?> factoryFromCustomLoader = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader);
|
||||
implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass);
|
||||
final String logFactoryClassName = logFactoryClass.getName();
|
||||
if (implementsLogFactory) {
|
||||
logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClassName + " implements LogFactory but was loaded by an incompatible classloader.");
|
||||
logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClassName + " implements LogFactory but was loaded by an incompatible class loader.");
|
||||
} else {
|
||||
logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClassName + " does not implement LogFactory.");
|
||||
}
|
||||
@@ -1162,9 +1162,9 @@ public abstract class LogFactory {
|
||||
+ "the compatibility was caused by a class loader conflict: " + e.getMessage());
|
||||
} catch (final ClassNotFoundException e) {
|
||||
//
|
||||
// LogFactory cannot be loaded by the classloader which loaded the custom factory implementation.
|
||||
// LogFactory cannot be loaded by the class loader which loaded the custom factory implementation.
|
||||
// The custom implementation is not viable until this is corrected.
|
||||
// Ensure that the JCL jar and the custom class are available from the same classloader.
|
||||
// Ensure that the JCL jar and the custom class are available from the same class loader.
|
||||
// Running with diagnostics on should give information about the class loaders used
|
||||
// to load the custom factory.
|
||||
//
|
||||
@@ -1236,20 +1236,20 @@ public abstract class LogFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate useful diagnostics regarding the classloader tree for
|
||||
* Generate useful diagnostics regarding the class loader tree for
|
||||
* the specified class.
|
||||
* <p>
|
||||
* As an example, if the specified class was loaded via a webapp's
|
||||
* classloader, then you may get the following output:
|
||||
* class loader, then you may get the following output:
|
||||
* <pre>
|
||||
* Class com.acme.Foo was loaded via classloader 11111
|
||||
* Class com.acme.Foo was loaded via class loader 11111
|
||||
* ClassLoader tree: 11111 -> 22222 (SYSTEM) -> 33333 -> BOOT
|
||||
* </pre>
|
||||
* <p>
|
||||
* This method returns immediately if isDiagnosticsEnabled()
|
||||
* returns false.
|
||||
*
|
||||
* @param clazz is the class whose classloader + tree are to be
|
||||
* @param clazz is the class whose class loader + tree are to be
|
||||
* output.
|
||||
*/
|
||||
private static void logClassLoaderEnvironment(final Class<?> clazz) {
|
||||
@@ -1274,12 +1274,12 @@ public abstract class LogFactory {
|
||||
classLoader = getClassLoader(clazz);
|
||||
} catch (final SecurityException ex) {
|
||||
// not much useful diagnostics we can print here!
|
||||
logDiagnostic("[ENV] Security forbids determining the classloader for " + className);
|
||||
logDiagnostic("[ENV] Security forbids determining the class loader for " + className);
|
||||
return;
|
||||
}
|
||||
|
||||
logDiagnostic("[ENV] Class " + className + " was loaded via classloader " + objectId(classLoader));
|
||||
logHierarchy("[ENV] Ancestry of classloader which loaded " + className + " is ", classLoader);
|
||||
logDiagnostic("[ENV] Class " + className + " was loaded via class loader " + objectId(classLoader));
|
||||
logHierarchy("[ENV] Ancestry of class loader which loaded " + className + " is ", classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1309,7 +1309,7 @@ public abstract class LogFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs diagnostic messages about the given classloader
|
||||
* Logs diagnostic messages about the given class loader
|
||||
* and it's hierarchy. The prefix is prepended to the message
|
||||
* and is intended to make it easier to understand the logs.
|
||||
* @param prefix
|
||||
@@ -1328,7 +1328,7 @@ public abstract class LogFactory {
|
||||
try {
|
||||
systemClassLoader = ClassLoader.getSystemClassLoader();
|
||||
} catch (final SecurityException ex) {
|
||||
logDiagnostic(prefix + "Security forbids determining the system classloader.");
|
||||
logDiagnostic(prefix + "Security forbids determining the system class loader.");
|
||||
return;
|
||||
}
|
||||
if (classLoader != null) {
|
||||
@@ -1401,24 +1401,24 @@ public abstract class LogFactory {
|
||||
* <b>ClassLoader conflicts</b>
|
||||
* </p>
|
||||
* <p>
|
||||
* Note that there can be problems if the specified ClassLoader is not the same as the classloader that loaded this class, that is, when loading a concrete
|
||||
* LogFactory subclass via a context classloader.
|
||||
* Note that there can be problems if the specified ClassLoader is not the same as the class loader that loaded this class, that is, when loading a concrete
|
||||
* LogFactory subclass via a context class loader.
|
||||
* </p>
|
||||
* <p>
|
||||
* The problem is the same one that can occur when loading a concrete Log subclass via a context classloader.
|
||||
* The problem is the same one that can occur when loading a concrete Log subclass via a context class loader.
|
||||
* </p>
|
||||
* <p>
|
||||
* The problem occurs when code running in the context classloader calls class X which was loaded via a parent classloader, and class X then calls
|
||||
* The problem occurs when code running in the context class loader calls class X which was loaded via a parent class loader, and class X then calls
|
||||
* LogFactory.getFactory (either directly or via LogFactory.getLog). Because class X was loaded via the parent, it binds to LogFactory loaded via the
|
||||
* parent. When the code in this method finds some LogFactoryYYYY class in the child (context) classloader, and there also happens to be a LogFactory class
|
||||
* defined in the child classloader, then LogFactoryYYYY will be bound to LogFactory@childloader. It cannot be cast to LogFactory@parentloader, that is,
|
||||
* this method cannot return the object as the desired type. Note that it doesn't matter if the LogFactory class in the child classloader is identical to
|
||||
* the LogFactory class in the parent classloader, they are not compatible.
|
||||
* parent. When the code in this method finds some LogFactoryYYYY class in the child (context) class loader, and there also happens to be a LogFactory class
|
||||
* defined in the child class loader, then LogFactoryYYYY will be bound to LogFactory@childloader. It cannot be cast to LogFactory@parentloader, that is,
|
||||
* this method cannot return the object as the desired type. Note that it doesn't matter if the LogFactory class in the child class loader is identical to
|
||||
* the LogFactory class in the parent class loader, they are not compatible.
|
||||
* </p>
|
||||
* <p>
|
||||
* The solution taken here is to simply print out an error message when this occurs then throw an exception. The deployer of the application must ensure
|
||||
* they remove all occurrences of the LogFactory class from the child classloader in order to resolve the issue. Note that they do not have to move the
|
||||
* custom LogFactory subclass; that is ok as long as the only LogFactory class it can find to bind to is in the parent classloader.
|
||||
* they remove all occurrences of the LogFactory class from the child class loader in order to resolve the issue. Note that they do not have to move the
|
||||
* custom LogFactory subclass; that is ok as long as the only LogFactory class it can find to bind to is in the parent class loader.
|
||||
* </p>
|
||||
*
|
||||
* @param factoryClass Fully qualified name of the {@code LogFactory} implementation class
|
||||
@@ -1446,7 +1446,7 @@ public abstract class LogFactory {
|
||||
throw ex;
|
||||
}
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic("Created object " + objectId(result) + " to manage classloader " +
|
||||
logDiagnostic("Created object " + objectId(result) + " to manage class loader " +
|
||||
objectId(contextClassLoader));
|
||||
}
|
||||
return (LogFactory) result;
|
||||
@@ -1482,7 +1482,7 @@ public abstract class LogFactory {
|
||||
*/
|
||||
public static void release(final ClassLoader classLoader) {
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic("Releasing factory for classloader " + objectId(classLoader));
|
||||
logDiagnostic("Releasing factory for class loader " + objectId(classLoader));
|
||||
}
|
||||
// factories is not final and could be replaced in this block.
|
||||
final Hashtable<ClassLoader, LogFactory> factories = LogFactory.factories;
|
||||
|
||||
@@ -97,9 +97,9 @@ public class LogFactoryImpl extends LogFactory {
|
||||
/**
|
||||
* The name ({@code org.apache.commons.logging.Log.allowFlawedContext})
|
||||
* of the system property which can be set true/false to
|
||||
* determine system behavior when a bad context-classloader is encountered.
|
||||
* determine system behavior when a bad context class loader is encountered.
|
||||
* When set to false, a LogConfigurationException is thrown if
|
||||
* LogFactoryImpl is loaded via a child classloader of the TCCL (this
|
||||
* LogFactoryImpl is loaded via a child class loader of the TCCL (this
|
||||
* should never happen in sane systems).
|
||||
*
|
||||
* Default behavior: true (tolerates bad context class loaders)
|
||||
@@ -186,14 +186,14 @@ public class LogFactoryImpl extends LogFactory {
|
||||
* the entire call stack must have the privilege before the call is
|
||||
* allowed.
|
||||
*
|
||||
* @return the context classloader associated with the current thread,
|
||||
* @return the context class loader 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.
|
||||
* attempting to get the context class loader.
|
||||
*
|
||||
* @throws SecurityException if the current java security policy doesn't
|
||||
* allow this class to access the context classloader.
|
||||
* allow this class to access the context class loader.
|
||||
*/
|
||||
private static ClassLoader getContextClassLoaderInternal()
|
||||
throws LogConfigurationException {
|
||||
@@ -234,7 +234,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
|
||||
/**
|
||||
* Determines whether logging classes should be loaded using the thread-context
|
||||
* classloader, or via the classloader that loaded this LogFactoryImpl class.
|
||||
* class loader, or via the class loader that loaded this LogFactoryImpl class.
|
||||
*/
|
||||
private boolean useTCCL = true;
|
||||
|
||||
@@ -341,14 +341,14 @@ public class LogFactoryImpl extends LogFactory {
|
||||
ClassLoader currentCL = getBaseClassLoader();
|
||||
|
||||
for(;;) {
|
||||
// Loop through the classloader hierarchy trying to find
|
||||
// a viable classloader.
|
||||
logDiagnostic("Trying to load '" + logAdapterClassName + "' from classloader " + objectId(currentCL));
|
||||
// Loop through the class loader hierarchy trying to find
|
||||
// a viable class loader.
|
||||
logDiagnostic("Trying to load '" + logAdapterClassName + "' from class loader " + objectId(currentCL));
|
||||
try {
|
||||
if (isDiagnosticsEnabled()) {
|
||||
// Show the location of the first occurrence of the .class file
|
||||
// in the classpath. This is the location that ClassLoader.loadClass
|
||||
// will load the class from -- unless the classloader is doing
|
||||
// will load the class from -- unless the class loader is doing
|
||||
// something weird.
|
||||
URL url;
|
||||
final String resourceName = logAdapterClassName.replace('.', '/') + ".class";
|
||||
@@ -369,14 +369,14 @@ public class LogFactoryImpl extends LogFactory {
|
||||
try {
|
||||
clazz = Class.forName(logAdapterClassName, true, currentCL);
|
||||
} catch (final ClassNotFoundException originalClassNotFoundException) {
|
||||
// The current classloader was unable to find the log adapter
|
||||
// in this or any ancestor classloader. There's no point in
|
||||
// The current class loader was unable to find the log adapter
|
||||
// in this or any ancestor class loader. There's no point in
|
||||
// trying higher up in the hierarchy in this case..
|
||||
String msg = originalClassNotFoundException.getMessage();
|
||||
logDiagnostic("The log adapter '" + logAdapterClassName + "' is not available via classloader " +
|
||||
logDiagnostic("The log adapter '" + logAdapterClassName + "' is not available via class loader " +
|
||||
objectId(currentCL) + ": " + trim(msg));
|
||||
try {
|
||||
// Try the class classloader.
|
||||
// Try the class class loader.
|
||||
// This may work in cases where the TCCL
|
||||
// does not contain the code executed or JCL.
|
||||
// This behavior indicates that the application
|
||||
@@ -388,7 +388,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
// no point continuing: this adapter isn't available
|
||||
msg = secondaryClassNotFoundException.getMessage();
|
||||
logDiagnostic("The log adapter '" + logAdapterClassName +
|
||||
"' is not available via the LogFactoryImpl class classloader: " + trim(msg));
|
||||
"' is not available via the LogFactoryImpl class class loader: " + trim(msg));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -421,11 +421,11 @@ public class LogFactoryImpl extends LogFactory {
|
||||
// We were able to load the adapter but it had references to
|
||||
// other classes that could not be found. This simply means that
|
||||
// the underlying logger library is not present in this or any
|
||||
// ancestor classloader. There's no point in trying higher up
|
||||
// ancestor class loader. There's no point in trying higher up
|
||||
// in the hierarchy in this case..
|
||||
final String msg = e.getMessage();
|
||||
logDiagnostic("The log adapter '" + logAdapterClassName +
|
||||
"' is missing dependencies when loaded via classloader " + objectId(currentCL) +
|
||||
"' is missing dependencies when loaded via class loader " + objectId(currentCL) +
|
||||
": " + trim(msg));
|
||||
break;
|
||||
} catch (final ExceptionInInitializerError e) {
|
||||
@@ -437,7 +437,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
// library could not be found.
|
||||
final String msg = e.getMessage();
|
||||
logDiagnostic("The log adapter '" + logAdapterClassName +
|
||||
"' is unable to initialize itself when loaded via classloader " + objectId(currentCL) +
|
||||
"' is unable to initialize itself when loaded via class loader " + objectId(currentCL) +
|
||||
": " + trim(msg));
|
||||
break;
|
||||
} catch (final LogConfigurationException e) {
|
||||
@@ -456,7 +456,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
break;
|
||||
}
|
||||
|
||||
// try the parent classloader
|
||||
// try the parent class loader
|
||||
// currentCL = currentCL.getParent();
|
||||
currentCL = getParentClassLoader(currentCL);
|
||||
}
|
||||
@@ -473,11 +473,11 @@ public class LogFactoryImpl extends LogFactory {
|
||||
} catch (final Throwable t) {
|
||||
handleThrowable(t); // may re-throw t
|
||||
this.logMethod = null;
|
||||
logDiagnostic("[INFO] '" + logAdapterClassName + "' from classloader " + objectId(currentCL) +
|
||||
logDiagnostic("[INFO] '" + logAdapterClassName + "' from class loader " + objectId(currentCL) +
|
||||
" does not declare optional method " + "setLogFactory(LogFactory)");
|
||||
}
|
||||
|
||||
logDiagnostic("Log adapter '" + logAdapterClassName + "' from classloader " +
|
||||
logDiagnostic("Log adapter '" + logAdapterClassName + "' from class loader " +
|
||||
objectId(logAdapterClass.getClassLoader()) + " has been selected for use.");
|
||||
}
|
||||
|
||||
@@ -543,18 +543,18 @@ public class LogFactoryImpl extends LogFactory {
|
||||
// expect method createLogFromClass to loop over the possible source
|
||||
// class loaders. The effect is:
|
||||
// for each discoverable log adapter
|
||||
// for each possible classloader
|
||||
// for each possible class loader
|
||||
// see if it works
|
||||
//
|
||||
// It appears reasonable at first glance to do the opposite:
|
||||
// for each possible classloader
|
||||
// for each possible class loader
|
||||
// for each discoverable log adapter
|
||||
// see if it works
|
||||
//
|
||||
// The latter certainly has advantages for user-installable logging
|
||||
// libraries such as log4j; in a webapp for example this code should
|
||||
// first check whether the user has provided any of the possible
|
||||
// logging libraries before looking in the parent classloader.
|
||||
// logging libraries before looking in the parent class loader.
|
||||
// Unfortunately, however, Jdk14Logger will always work in jvm>=1.4,
|
||||
// and SimpleLog will always work in any JVM. So the loop would never
|
||||
// ever look for logging libraries in the parent classpath. Yet many
|
||||
@@ -666,19 +666,19 @@ public class LogFactoryImpl extends LogFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the classloader from which we should try to load the logging
|
||||
* Return the class loader from which we should try to load the logging
|
||||
* adapter classes.
|
||||
* <p>
|
||||
* This method usually returns the context classloader. However if it
|
||||
* is discovered that the classloader which loaded this class is a child
|
||||
* of the context classloader <i>and</i> the allowFlawedContext option
|
||||
* has been set then the classloader which loaded this class is returned
|
||||
* This method usually returns the context class loader. However if it
|
||||
* is discovered that the class loader which loaded this class is a child
|
||||
* of the context class loader <i>and</i> the allowFlawedContext option
|
||||
* has been set then the class loader which loaded this class is returned
|
||||
* instead.
|
||||
* <p>
|
||||
* The only time when the classloader which loaded this class is a
|
||||
* The only time when the class loader which loaded this class is a
|
||||
* descendant (rather than the same as or an ancestor of the context
|
||||
* classloader) is when an app has created custom class loaders but
|
||||
* failed to correctly set the context classloader. This is a bug in
|
||||
* class loader) is when an app has created custom class loaders but
|
||||
* failed to correctly set the context class loader. This is a bug in
|
||||
* the calling application; however we provide the option for JCL to
|
||||
* simply generate a warning rather than fail outright.
|
||||
*
|
||||
@@ -701,13 +701,13 @@ public class LogFactoryImpl extends LogFactory {
|
||||
// UnifiedLoaderRepository) this can still work, so if user hasn't
|
||||
// forbidden it, just return the contextClassLoader.
|
||||
if (!allowFlawedContext) {
|
||||
throw new LogConfigurationException("Bad classloader hierarchy; LogFactoryImpl was loaded via" +
|
||||
" a classloader that is not related to the current context" +
|
||||
" classloader.");
|
||||
throw new LogConfigurationException("Bad class loader hierarchy; LogFactoryImpl was loaded via" +
|
||||
" a class loader that is not related to the current context" +
|
||||
" class loader.");
|
||||
}
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic("[WARNING] the context classloader is not part of a" +
|
||||
" parent-child relationship with the classloader that" +
|
||||
logDiagnostic("[WARNING] the context class loader is not part of a" +
|
||||
" parent-child relationship with the class loader that" +
|
||||
" loaded LogFactoryImpl.");
|
||||
}
|
||||
// If contextClassLoader were null, getLowestClassLoader() would
|
||||
@@ -720,20 +720,20 @@ public class LogFactoryImpl extends LogFactory {
|
||||
// We really should just use the contextClassLoader as the starting
|
||||
// point for scanning for log adapter classes. However it is expected
|
||||
// that there are a number of broken systems out there which create
|
||||
// custom class loaders but fail to set the context classloader so
|
||||
// custom class loaders but fail to set the context class loader so
|
||||
// we handle those flawed systems anyway.
|
||||
if (!allowFlawedContext) {
|
||||
throw new LogConfigurationException(
|
||||
"Bad classloader hierarchy; LogFactoryImpl was loaded via" +
|
||||
" a classloader that is not related to the current context" +
|
||||
" classloader.");
|
||||
"Bad class loader hierarchy; LogFactoryImpl was loaded via" +
|
||||
" a class loader that is not related to the current context" +
|
||||
" class loader.");
|
||||
}
|
||||
if (isDiagnosticsEnabled()) {
|
||||
logDiagnostic(
|
||||
"Warning: the context classloader is an ancestor of the" +
|
||||
" classloader that loaded LogFactoryImpl; it should be" +
|
||||
"Warning: the context class loader is an ancestor of the" +
|
||||
" class loader that loaded LogFactoryImpl; it should be" +
|
||||
" the same or a descendant. The application using" +
|
||||
" commons-logging should ensure the context classloader" +
|
||||
" commons-logging should ensure the context class loader" +
|
||||
" is used correctly.");
|
||||
}
|
||||
}
|
||||
@@ -896,8 +896,8 @@ public class LogFactoryImpl extends LogFactory {
|
||||
* Given two related class loaders, return the one which is a child of
|
||||
* the other.
|
||||
* <p>
|
||||
* @param c1 is a classloader (including the null classloader)
|
||||
* @param c2 is a classloader (including the null classloader)
|
||||
* @param c1 is a class loader (including the null class loader)
|
||||
* @param c2 is a class loader (including the null class loader)
|
||||
*
|
||||
* @return c1 if it has c2 as an ancestor, c2 if it has c1 as an ancestor,
|
||||
* and null if neither is an ancestor of the other.
|
||||
@@ -939,7 +939,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the parent classloader of a specified classloader.
|
||||
* Fetch the parent class loader of a specified class loader.
|
||||
* <p>
|
||||
* If a SecurityException occurs, null is returned.
|
||||
* <p>
|
||||
@@ -949,7 +949,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
try {
|
||||
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> cl.getParent());
|
||||
} catch (final SecurityException ex) {
|
||||
logDiagnostic("[SECURITY] Unable to obtain parent classloader");
|
||||
logDiagnostic("[SECURITY] Unable to obtain parent class loader");
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -962,7 +962,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
*
|
||||
* @param logAdapterClassName is the class name of the Log implementation
|
||||
* that could not be instantiated. Cannot be {@code null}.
|
||||
* @param discoveryFlaw is the Throwable created by the classloader
|
||||
* @param discoveryFlaw is the Throwable created by the class loader
|
||||
*
|
||||
* @throws LogConfigurationException ALWAYS
|
||||
*/
|
||||
@@ -1015,13 +1015,13 @@ public class LogFactoryImpl extends LogFactory {
|
||||
* <li>the specific class just doesn't implement the Log interface
|
||||
* (user screwed up), or
|
||||
* <li> the specified class has bound to a Log class loaded by some other
|
||||
* classloader; Log@classloaderX cannot be cast to Log@classloaderY.
|
||||
* class loader; Log@ClassLoaderX cannot be cast to Log@ClassLoaderY.
|
||||
* </ol>
|
||||
* <p>
|
||||
* Here we try to figure out which case has occurred so we can give the
|
||||
* user some reasonable feedback.
|
||||
*
|
||||
* @param badClassLoader is the classloader we loaded the problem class from,
|
||||
* @param badClassLoader is the class loader we loaded the problem class from,
|
||||
* ie it is equivalent to badClass.getClassLoader().
|
||||
*
|
||||
* @param badClass is a Class object with the desired name, but which
|
||||
@@ -1045,13 +1045,13 @@ public class LogFactoryImpl extends LogFactory {
|
||||
|
||||
if (implementsLog) {
|
||||
// the class does implement an interface called Log, but
|
||||
// it is in the wrong classloader
|
||||
// it is in the wrong class loader
|
||||
if (isDiagnosticsEnabled()) {
|
||||
try {
|
||||
final ClassLoader logInterfaceClassLoader = getClassLoader(Log.class);
|
||||
logDiagnostic("Class '" + badClass.getName() + "' was found in classloader " +
|
||||
logDiagnostic("Class '" + badClass.getName() + "' was found in class loader " +
|
||||
objectId(badClassLoader) + ". It is bound to a Log interface which is not" +
|
||||
" the one loaded from classloader " + objectId(logInterfaceClassLoader));
|
||||
" the one loaded from class loader " + objectId(logInterfaceClassLoader));
|
||||
} catch (final Throwable t) {
|
||||
handleThrowable(t); // may re-throw t
|
||||
logDiagnostic("Error while trying to output diagnostics about" + " bad class '" + badClass + "'");
|
||||
@@ -1144,7 +1144,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
|
||||
/**
|
||||
* Calculate and cache a string that uniquely identifies this instance,
|
||||
* including which classloader the object was loaded from.
|
||||
* including which class loader the object was loaded from.
|
||||
* <p>
|
||||
* This string will later be prefixed to each "internal logging" message
|
||||
* emitted, so that users can clearly see any unexpected behavior.
|
||||
@@ -1155,7 +1155,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
* its own unique prefix for log messages.
|
||||
*/
|
||||
private void initDiagnostics() {
|
||||
// It would be nice to include an identifier of the context classloader
|
||||
// It would be nice to include an identifier of the context class loader
|
||||
// that this LogFactoryImpl object is responsible for. However that
|
||||
// isn't possible as that information isn't available. It is possible
|
||||
// to figure this out by looking at the logging from LogFactory to
|
||||
|
||||
@@ -42,7 +42,7 @@ import org.apache.commons.logging.LogFactory;
|
||||
* To use this class, configure the webapp deployment descriptor to call
|
||||
* this class on webapp undeploy; the contextDestroyed method will tell
|
||||
* every accessible LogFactory class that the entry in its map for the
|
||||
* current webapp's context classloader should be cleared.
|
||||
* current webapp's context class loader should be cleared.
|
||||
*
|
||||
* @since 1.1
|
||||
*/
|
||||
@@ -78,18 +78,18 @@ public class ServletContextCleaner implements ServletContextListener {
|
||||
// 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
|
||||
// child-first classloading is used in any class loader, then multiple
|
||||
// LogFactory instances may hold info about this TCCL; whenever the
|
||||
// webapp makes a call into a class loaded via an ancestor classloader
|
||||
// webapp makes a call into a class loaded via an ancestor class loader
|
||||
// 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
|
||||
// class loader. However the concrete logging library it points
|
||||
// to is expected to have been loaded via the TCCL, so the
|
||||
// underlying logging lib is only initialized/configured once.
|
||||
// These references from ancestor LogFactory classes down to
|
||||
// TCCL class loaders 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
|
||||
// Walking up the class loader ancestry ladder releasing
|
||||
// the current tccl at each level tree, though, will definitely
|
||||
// clear any problem references.
|
||||
ClassLoader loader = tccl;
|
||||
|
||||
@@ -65,18 +65,18 @@ import java.util.Set;
|
||||
* The reason all this is necessary is due to a issue which
|
||||
* arises during hot deploy in a J2EE-like containers.
|
||||
* Each component running in the container owns one or more class loaders; when
|
||||
* the component loads a LogFactory instance via the component classloader
|
||||
* the component loads a LogFactory instance via the component class loader
|
||||
* a reference to it gets stored in the static LogFactory.factories member,
|
||||
* keyed by the component's classloader so different components don't
|
||||
* keyed by the component's class loader so different components don't
|
||||
* stomp on each other. When the component is later unloaded, the container
|
||||
* sets the component's classloader to null with the intent that all the
|
||||
* sets the component's class loader to null with the intent that all the
|
||||
* component's classes get garbage-collected. However there's still a
|
||||
* reference to the component's classloader from a key in the "global"
|
||||
* reference to the component's class loader from a key in the "global"
|
||||
* {@code LogFactory}'s factories member! If {@code LogFactory.release()}
|
||||
* is called whenever component is unloaded, the class loaders will be correctly
|
||||
* garbage collected; this <i>should</i> be done by any container that
|
||||
* bundles commons-logging by default. However, holding the classloader
|
||||
* references weakly ensures that the classloader will be garbage collected
|
||||
* bundles commons-logging by default. However, holding the class loader
|
||||
* references weakly ensures that the class loader will be garbage collected
|
||||
* without the container performing this step.
|
||||
* <p>
|
||||
* <strong>Limitations:</strong>
|
||||
@@ -85,22 +85,22 @@ import java.util.Set;
|
||||
* are used for its keys, it is necessary to use strong references for its values.
|
||||
* <p>
|
||||
* If the abstract class {@code LogFactory} is
|
||||
* loaded by the container classloader but a subclass of
|
||||
* loaded by the container class loader but a subclass of
|
||||
* {@code LogFactory} [LogFactory1] is loaded by the component's
|
||||
* classloader and an instance stored in the static map associated with the
|
||||
* class loader and an instance stored in the static map associated with the
|
||||
* base LogFactory class, then there is a strong reference from the LogFactory
|
||||
* class to the LogFactory1 instance (as normal) and a strong reference from
|
||||
* the LogFactory1 instance to the component classloader via
|
||||
* the LogFactory1 instance to the component class loader via
|
||||
* {@code getClass().getClassLoader()}. This chain of references will prevent
|
||||
* collection of the child classloader.
|
||||
* collection of the child class loader.
|
||||
* <p>
|
||||
* Such a situation occurs when the commons-logging.jar is
|
||||
* loaded by a parent classloader (e.g. a server level classloader in a
|
||||
* loaded by a parent class loader (e.g. a server level class loader in a
|
||||
* servlet container) and a custom {@code LogFactory} implementation is
|
||||
* loaded by a child classloader (e.g. a web app classloader).
|
||||
* loaded by a child class loader (e.g. a web app class loader).
|
||||
* <p>
|
||||
* To avoid this scenario, ensure
|
||||
* that any custom LogFactory subclass is loaded by the same classloader as
|
||||
* that any custom LogFactory subclass is loaded by the same class loader as
|
||||
* the base {@code LogFactory}. Creating custom LogFactory subclasses is,
|
||||
* however, rare. The standard LogFactoryImpl class should be sufficient
|
||||
* for most or all users.
|
||||
|
||||
Reference in New Issue
Block a user