Spelling
This commit is contained in:
@@ -190,7 +190,7 @@ public abstract class LogFactory {
|
|||||||
"org.apache.commons.logging.impl.WeakHashtable";
|
"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
|
* same as LogFactory.class.getClassLoader(). However computing this
|
||||||
* value isn't quite as simple as that, as we potentially need to use
|
* 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
|
* AccessControllers etc. It's more efficient to compute it once and
|
||||||
@@ -219,9 +219,9 @@ public abstract class LogFactory {
|
|||||||
* This can happen when:
|
* This can happen when:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li>using JDK1.1 and the calling code is loaded via the system
|
* <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
|
* <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>
|
* </ul>
|
||||||
* Note that {@code factories} is a <i>Hashtable</i> (not a HashMap),
|
* Note that {@code factories} is a <i>Hashtable</i> (not a HashMap),
|
||||||
* and hashtables don't allow null as a key.
|
* 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
|
// In order to avoid confusion where multiple instances of JCL are
|
||||||
// being used via different class loaders within the same app, we
|
// being used via different class loaders within the same app, we
|
||||||
// ensure each logged message has a prefix of form
|
// 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
|
// Note that this prefix should be kept consistent with that
|
||||||
// in LogFactoryImpl. However here we don't need to output info
|
// 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
|
* can return the previously created object (together with all its
|
||||||
* cached Log objects).
|
* 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.
|
* this can be null under some circumstances; this is ok.
|
||||||
* @param factory should be the factory to cache. This should never be null.
|
* @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);
|
logFactoryClass = classLoader.loadClass(factoryClassName);
|
||||||
if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
|
if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
logDiagnostic("Loaded class " + logFactoryClass.getName() + " from classloader " + objectId(classLoader));
|
logDiagnostic("Loaded class " + logFactoryClass.getName() + " from class loader " + objectId(classLoader));
|
||||||
}
|
}
|
||||||
} else //
|
} else //
|
||||||
// This indicates a problem with the ClassLoader tree.
|
// This indicates a problem with the ClassLoader tree.
|
||||||
@@ -322,8 +322,8 @@ public abstract class LogFactory {
|
|||||||
// ClassLoader hierarchy.
|
// ClassLoader hierarchy.
|
||||||
//
|
//
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
logDiagnostic("Factory class " + logFactoryClass.getName() + " loaded from classloader " + objectId(logFactoryClass.getClassLoader())
|
logDiagnostic("Factory class " + logFactoryClass.getName() + " loaded from class loader " + objectId(logFactoryClass.getClassLoader())
|
||||||
+ " does not extend '" + LogFactory.class.getName() + "' as loaded by this classloader.");
|
+ " does not extend '" + LogFactory.class.getName() + "' as loaded by this class loader.");
|
||||||
logHierarchy("[BAD CL TREE] ", classLoader);
|
logHierarchy("[BAD CL TREE] ", classLoader);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -333,7 +333,7 @@ public abstract class LogFactory {
|
|||||||
if (classLoader == thisClassLoaderRef.get()) {
|
if (classLoader == thisClassLoaderRef.get()) {
|
||||||
// Nothing more to try, onwards.
|
// Nothing more to try, onwards.
|
||||||
if (isDiagnosticsEnabled()) {
|
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;
|
throw ex;
|
||||||
}
|
}
|
||||||
@@ -342,7 +342,7 @@ public abstract class LogFactory {
|
|||||||
if (classLoader == thisClassLoaderRef.get()) {
|
if (classLoader == thisClassLoaderRef.get()) {
|
||||||
// Nothing more to try, onwards.
|
// Nothing more to try, onwards.
|
||||||
if (isDiagnosticsEnabled()) {
|
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.");
|
+ " - it depends on some other class that cannot be found.");
|
||||||
}
|
}
|
||||||
throw e;
|
throw e;
|
||||||
@@ -389,12 +389,12 @@ public abstract class LogFactory {
|
|||||||
throw new ClassCastException(msg.toString());
|
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.
|
// TCCL; the code below will try to load the class via thisClassLoaderRef.
|
||||||
// This will handle the case where the original calling class is in
|
// 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
|
// a shared classpath but the TCCL has a copy of LogFactory and the
|
||||||
// specified LogFactory implementation; we will fall back to using 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
|
// Issue: this doesn't handle the reverse case, where this LogFactory
|
||||||
// is in the webapp, and the specified LogFactory implementation is
|
// 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.
|
* 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
|
* 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 classloader associated with this class. See the Javadoc for the newFactory method for
|
* 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.
|
* 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
|
// Warning: must typecast here & allow exception
|
||||||
// to be generated/caught & recast properly.
|
// to be generated/caught & recast properly.
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
logDiagnostic(
|
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);
|
logFactoryClass = Class.forName(factoryClassName);
|
||||||
return logFactoryClass.newInstance();
|
return logFactoryClass.newInstance();
|
||||||
@@ -436,7 +436,7 @@ public abstract class LogFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Create the hashtable which will be used to store a map of
|
* 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
|
* supports "weak references", allowing a custom Hashtable class
|
||||||
* to be used which uses only weak references to its keys. Using weak
|
* 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
|
* 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
|
* @throws LogConfigurationException if a suitable class loader
|
||||||
* cannot be identified.
|
* cannot be identified.
|
||||||
* @return the thread's context classloader or {@code null} if the java security
|
* @return the thread's context class loader or {@code null} if the java security
|
||||||
* policy forbids access to the context classloader from one of the classes
|
* policy forbids access to the context class loader from one of the classes
|
||||||
* in the current call stack.
|
* in the current call stack.
|
||||||
* @since 1.1
|
* @since 1.1
|
||||||
*/
|
*/
|
||||||
@@ -535,16 +535,16 @@ public abstract class LogFactory {
|
|||||||
/**
|
/**
|
||||||
* Check cached factories (keyed by contextClassLoader)
|
* 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
|
* with the current thread. This allows separate LogFactory objects
|
||||||
* per component within a container, provided each component has
|
* 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
|
* in JDK1.1, and in embedded systems where jcl-using code is
|
||||||
* placed in the bootclasspath.
|
* 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
|
* 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) {
|
private static LogFactory getCachedFactory(final ClassLoader contextClassLoader) {
|
||||||
if (contextClassLoader == null) {
|
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>
|
* <p>
|
||||||
* Theoretically, calling getClassLoader can throw a security exception,
|
* Theoretically, calling getClassLoader can throw a security exception,
|
||||||
* and so should be done under an AccessController in order to provide
|
* 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
|
* Even when using an AccessController, however, this method can still
|
||||||
* throw SecurityException. Commons Logging basically relies on the
|
* throw SecurityException. Commons Logging basically relies on the
|
||||||
* ability to access class loaders. A policy that forbids all
|
* 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
|
* currently this method will throw an exception preventing the entire app
|
||||||
* from starting up. Maybe it would be good to detect this situation and
|
* from starting up. Maybe it would be good to detect this situation and
|
||||||
* just disable all commons-logging? Not high priority though - as stated
|
* 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>
|
||||||
* <p>
|
* <p>
|
||||||
* Note that returning an object fetched via an AccessController would
|
* Note that returning an object fetched via an AccessController would
|
||||||
* technically be a security flaw anyway; untrusted code that has access
|
* 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.
|
* a class even when forbidden to do so directly.
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
@@ -595,7 +595,7 @@ public abstract class LogFactory {
|
|||||||
return clazz.getClassLoader();
|
return clazz.getClassLoader();
|
||||||
} catch (final SecurityException ex) {
|
} catch (final SecurityException ex) {
|
||||||
if (isDiagnosticsEnabled()) {
|
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;
|
throw ex;
|
||||||
}
|
}
|
||||||
@@ -604,7 +604,7 @@ public abstract class LogFactory {
|
|||||||
/**
|
/**
|
||||||
* Locate a user-provided configuration file.
|
* Locate a user-provided configuration file.
|
||||||
* <p>
|
* <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,
|
* 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
|
* 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
|
* 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>
|
* <p>
|
||||||
* In versions prior to 1.1, this method did not use an AccessController.
|
* In versions prior to 1.1, this method did not use an AccessController.
|
||||||
* In version 1.1, an AccessController wrapper was incorrectly added to
|
* In version 1.1, an AccessController wrapper was incorrectly added to
|
||||||
* this method, causing a minor security flaw.
|
* this method, causing a minor security flaw.
|
||||||
* <p>
|
* <p>
|
||||||
* In version 1.1.1 this change was reverted; this method no longer uses
|
* 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
|
* must invoke this method via AccessController.doPrivileged if it needs
|
||||||
* support for that.
|
* 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.
|
* or null if security doesn't allow it.
|
||||||
* @throws LogConfigurationException if there was some weird error while
|
* @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 {
|
protected static ClassLoader getContextClassLoader() throws LogConfigurationException {
|
||||||
return directGetContextClassLoader();
|
return directGetContextClassLoader();
|
||||||
@@ -720,10 +720,10 @@ public abstract class LogFactory {
|
|||||||
* the entire call stack must have the privilege before the call is
|
* the entire call stack must have the privilege before the call is
|
||||||
* allowed.
|
* 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.
|
* or null if security doesn't allow it.
|
||||||
* @throws LogConfigurationException if there was some weird error while
|
* @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 {
|
private static ClassLoader getContextClassLoaderInternal() throws LogConfigurationException {
|
||||||
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) LogFactory::directGetContextClassLoader);
|
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.
|
* this file will be set as configuration attributes on the corresponding {@code LogFactory} instance.
|
||||||
* </p>
|
* </p>
|
||||||
* <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>
|
* </p>
|
||||||
*
|
*
|
||||||
* @return a {@code LogFactory}.
|
* @return a {@code LogFactory}.
|
||||||
@@ -760,7 +760,7 @@ public abstract class LogFactory {
|
|||||||
// output will be a nuisance on JDK1.1, as the system
|
// output will be a nuisance on JDK1.1, as the system
|
||||||
// class loader is null in that environment.
|
// class loader is null in that environment.
|
||||||
if (contextClassLoader == null && isDiagnosticsEnabled()) {
|
if (contextClassLoader == null && isDiagnosticsEnabled()) {
|
||||||
logDiagnostic("Context classloader is null.");
|
logDiagnostic("Context class loader is null.");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return any previously registered factory for this class loader
|
// Return any previously registered factory for this class loader
|
||||||
@@ -771,7 +771,7 @@ public abstract class LogFactory {
|
|||||||
|
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
logDiagnostic(
|
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));
|
objectId(contextClassLoader));
|
||||||
logHierarchy("[LOOKUP] ", contextClassLoader);
|
logHierarchy("[LOOKUP] ", contextClassLoader);
|
||||||
}
|
}
|
||||||
@@ -947,13 +947,13 @@ public abstract class LogFactory {
|
|||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
logDiagnostic(
|
logDiagnostic(
|
||||||
"[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT +
|
"[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT +
|
||||||
"' via the same classloader that loaded this LogFactory" +
|
"' via the same class loader that loaded this LogFactory" +
|
||||||
" class (ie not looking in the context classloader).");
|
" class (ie not looking in the context class loader).");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: unlike the above code which can try to load custom LogFactory
|
// 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
|
// 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)
|
// * that can cause problems (see comments in newFactory method)
|
||||||
// * no-one should be customising the code of the default class
|
// * 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
|
// 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}.
|
* Determines whether the given class actually implements {@code LogFactory}.
|
||||||
* Diagnostic information is also logged.
|
* Diagnostic information is also logged.
|
||||||
* <p>
|
* <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
|
* 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}
|
* @param logFactoryClass {@code Class} which may implement {@code LogFactory}
|
||||||
* @return true if the {@code logFactoryClass} does extend
|
* @return true if the {@code logFactoryClass} does extend
|
||||||
* {@code LogFactory} when that class is loaded via the same
|
* {@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) {
|
private static boolean implementsLogFactory(final Class<?> logFactoryClass) {
|
||||||
boolean implementsLogFactory = false;
|
boolean implementsLogFactory = false;
|
||||||
@@ -1131,14 +1131,14 @@ public abstract class LogFactory {
|
|||||||
try {
|
try {
|
||||||
final ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader();
|
final ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader();
|
||||||
if (logFactoryClassLoader == null) {
|
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 {
|
} else {
|
||||||
logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader);
|
logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader);
|
||||||
final Class<?> factoryFromCustomLoader = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader);
|
final Class<?> factoryFromCustomLoader = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader);
|
||||||
implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass);
|
implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass);
|
||||||
final String logFactoryClassName = logFactoryClass.getName();
|
final String logFactoryClassName = logFactoryClass.getName();
|
||||||
if (implementsLogFactory) {
|
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 {
|
} else {
|
||||||
logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClassName + " does not implement LogFactory.");
|
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());
|
+ "the compatibility was caused by a class loader conflict: " + e.getMessage());
|
||||||
} catch (final ClassNotFoundException e) {
|
} 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.
|
// 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
|
// Running with diagnostics on should give information about the class loaders used
|
||||||
// to load the custom factory.
|
// 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.
|
* the specified class.
|
||||||
* <p>
|
* <p>
|
||||||
* As an example, if the specified class was loaded via a webapp's
|
* 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>
|
* <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
|
* ClassLoader tree: 11111 -> 22222 (SYSTEM) -> 33333 -> BOOT
|
||||||
* </pre>
|
* </pre>
|
||||||
* <p>
|
* <p>
|
||||||
* This method returns immediately if isDiagnosticsEnabled()
|
* This method returns immediately if isDiagnosticsEnabled()
|
||||||
* returns false.
|
* 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.
|
* output.
|
||||||
*/
|
*/
|
||||||
private static void logClassLoaderEnvironment(final Class<?> clazz) {
|
private static void logClassLoaderEnvironment(final Class<?> clazz) {
|
||||||
@@ -1274,12 +1274,12 @@ public abstract class LogFactory {
|
|||||||
classLoader = getClassLoader(clazz);
|
classLoader = getClassLoader(clazz);
|
||||||
} catch (final SecurityException ex) {
|
} catch (final SecurityException ex) {
|
||||||
// not much useful diagnostics we can print here!
|
// 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;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
logDiagnostic("[ENV] Class " + className + " was loaded via classloader " + objectId(classLoader));
|
logDiagnostic("[ENV] Class " + className + " was loaded via class loader " + objectId(classLoader));
|
||||||
logHierarchy("[ENV] Ancestry of classloader which loaded " + className + " is ", 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 it's hierarchy. The prefix is prepended to the message
|
||||||
* and is intended to make it easier to understand the logs.
|
* and is intended to make it easier to understand the logs.
|
||||||
* @param prefix
|
* @param prefix
|
||||||
@@ -1328,7 +1328,7 @@ public abstract class LogFactory {
|
|||||||
try {
|
try {
|
||||||
systemClassLoader = ClassLoader.getSystemClassLoader();
|
systemClassLoader = ClassLoader.getSystemClassLoader();
|
||||||
} catch (final SecurityException ex) {
|
} catch (final SecurityException ex) {
|
||||||
logDiagnostic(prefix + "Security forbids determining the system classloader.");
|
logDiagnostic(prefix + "Security forbids determining the system class loader.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (classLoader != null) {
|
if (classLoader != null) {
|
||||||
@@ -1401,24 +1401,24 @@ public abstract class LogFactory {
|
|||||||
* <b>ClassLoader conflicts</b>
|
* <b>ClassLoader conflicts</b>
|
||||||
* </p>
|
* </p>
|
||||||
* <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
|
* 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 classloader.
|
* LogFactory subclass via a context class loader.
|
||||||
* </p>
|
* </p>
|
||||||
* <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>
|
||||||
* <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
|
* 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
|
* 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 classloader, then LogFactoryYYYY will be bound to LogFactory@childloader. It cannot be cast to LogFactory@parentloader, that is,
|
* 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 classloader is identical to
|
* 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 classloader, they are not compatible.
|
* the LogFactory class in the parent class loader, they are not compatible.
|
||||||
* </p>
|
* </p>
|
||||||
* <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
|
* 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
|
* 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 classloader.
|
* 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>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param factoryClass Fully qualified name of the {@code LogFactory} implementation class
|
* @param factoryClass Fully qualified name of the {@code LogFactory} implementation class
|
||||||
@@ -1446,7 +1446,7 @@ public abstract class LogFactory {
|
|||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
logDiagnostic("Created object " + objectId(result) + " to manage classloader " +
|
logDiagnostic("Created object " + objectId(result) + " to manage class loader " +
|
||||||
objectId(contextClassLoader));
|
objectId(contextClassLoader));
|
||||||
}
|
}
|
||||||
return (LogFactory) result;
|
return (LogFactory) result;
|
||||||
@@ -1482,7 +1482,7 @@ public abstract class LogFactory {
|
|||||||
*/
|
*/
|
||||||
public static void release(final ClassLoader classLoader) {
|
public static void release(final ClassLoader classLoader) {
|
||||||
if (isDiagnosticsEnabled()) {
|
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.
|
// factories is not final and could be replaced in this block.
|
||||||
final Hashtable<ClassLoader, LogFactory> factories = LogFactory.factories;
|
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})
|
* The name ({@code org.apache.commons.logging.Log.allowFlawedContext})
|
||||||
* of the system property which can be set true/false to
|
* 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
|
* 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).
|
* should never happen in sane systems).
|
||||||
*
|
*
|
||||||
* Default behavior: true (tolerates bad context class loaders)
|
* 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
|
* the entire call stack must have the privilege before the call is
|
||||||
* allowed.
|
* 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.
|
* or null if security doesn't allow it.
|
||||||
*
|
*
|
||||||
* @throws LogConfigurationException if there was some weird error while
|
* @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
|
* @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()
|
private static ClassLoader getContextClassLoaderInternal()
|
||||||
throws LogConfigurationException {
|
throws LogConfigurationException {
|
||||||
@@ -234,7 +234,7 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines whether logging classes should be loaded using the thread-context
|
* 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;
|
private boolean useTCCL = true;
|
||||||
|
|
||||||
@@ -341,14 +341,14 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
ClassLoader currentCL = getBaseClassLoader();
|
ClassLoader currentCL = getBaseClassLoader();
|
||||||
|
|
||||||
for(;;) {
|
for(;;) {
|
||||||
// Loop through the classloader hierarchy trying to find
|
// Loop through the class loader hierarchy trying to find
|
||||||
// a viable classloader.
|
// a viable class loader.
|
||||||
logDiagnostic("Trying to load '" + logAdapterClassName + "' from classloader " + objectId(currentCL));
|
logDiagnostic("Trying to load '" + logAdapterClassName + "' from class loader " + objectId(currentCL));
|
||||||
try {
|
try {
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
// Show the location of the first occurrence of the .class file
|
// Show the location of the first occurrence of the .class file
|
||||||
// in the classpath. This is the location that ClassLoader.loadClass
|
// 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.
|
// something weird.
|
||||||
URL url;
|
URL url;
|
||||||
final String resourceName = logAdapterClassName.replace('.', '/') + ".class";
|
final String resourceName = logAdapterClassName.replace('.', '/') + ".class";
|
||||||
@@ -369,14 +369,14 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
try {
|
try {
|
||||||
clazz = Class.forName(logAdapterClassName, true, currentCL);
|
clazz = Class.forName(logAdapterClassName, true, currentCL);
|
||||||
} catch (final ClassNotFoundException originalClassNotFoundException) {
|
} catch (final ClassNotFoundException originalClassNotFoundException) {
|
||||||
// The current classloader was unable to find the log adapter
|
// The current class loader was unable to find the log adapter
|
||||||
// in this or any ancestor classloader. There's no point in
|
// in this or any ancestor class loader. There's no point in
|
||||||
// trying higher up in the hierarchy in this case..
|
// trying higher up in the hierarchy in this case..
|
||||||
String msg = originalClassNotFoundException.getMessage();
|
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));
|
objectId(currentCL) + ": " + trim(msg));
|
||||||
try {
|
try {
|
||||||
// Try the class classloader.
|
// Try the class class loader.
|
||||||
// This may work in cases where the TCCL
|
// This may work in cases where the TCCL
|
||||||
// does not contain the code executed or JCL.
|
// does not contain the code executed or JCL.
|
||||||
// This behavior indicates that the application
|
// This behavior indicates that the application
|
||||||
@@ -388,7 +388,7 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
// no point continuing: this adapter isn't available
|
// no point continuing: this adapter isn't available
|
||||||
msg = secondaryClassNotFoundException.getMessage();
|
msg = secondaryClassNotFoundException.getMessage();
|
||||||
logDiagnostic("The log adapter '" + logAdapterClassName +
|
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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -421,11 +421,11 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
// We were able to load the adapter but it had references to
|
// We were able to load the adapter but it had references to
|
||||||
// other classes that could not be found. This simply means that
|
// other classes that could not be found. This simply means that
|
||||||
// the underlying logger library is not present in this or any
|
// 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..
|
// in the hierarchy in this case..
|
||||||
final String msg = e.getMessage();
|
final String msg = e.getMessage();
|
||||||
logDiagnostic("The log adapter '" + logAdapterClassName +
|
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));
|
": " + trim(msg));
|
||||||
break;
|
break;
|
||||||
} catch (final ExceptionInInitializerError e) {
|
} catch (final ExceptionInInitializerError e) {
|
||||||
@@ -437,7 +437,7 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
// library could not be found.
|
// library could not be found.
|
||||||
final String msg = e.getMessage();
|
final String msg = e.getMessage();
|
||||||
logDiagnostic("The log adapter '" + logAdapterClassName +
|
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));
|
": " + trim(msg));
|
||||||
break;
|
break;
|
||||||
} catch (final LogConfigurationException e) {
|
} catch (final LogConfigurationException e) {
|
||||||
@@ -456,7 +456,7 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// try the parent classloader
|
// try the parent class loader
|
||||||
// currentCL = currentCL.getParent();
|
// currentCL = currentCL.getParent();
|
||||||
currentCL = getParentClassLoader(currentCL);
|
currentCL = getParentClassLoader(currentCL);
|
||||||
}
|
}
|
||||||
@@ -473,11 +473,11 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
} catch (final Throwable t) {
|
} catch (final Throwable t) {
|
||||||
handleThrowable(t); // may re-throw t
|
handleThrowable(t); // may re-throw t
|
||||||
this.logMethod = null;
|
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)");
|
" 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.");
|
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
|
// expect method createLogFromClass to loop over the possible source
|
||||||
// class loaders. The effect is:
|
// class loaders. The effect is:
|
||||||
// for each discoverable log adapter
|
// for each discoverable log adapter
|
||||||
// for each possible classloader
|
// for each possible class loader
|
||||||
// see if it works
|
// see if it works
|
||||||
//
|
//
|
||||||
// It appears reasonable at first glance to do the opposite:
|
// It appears reasonable at first glance to do the opposite:
|
||||||
// for each possible classloader
|
// for each possible class loader
|
||||||
// for each discoverable log adapter
|
// for each discoverable log adapter
|
||||||
// see if it works
|
// see if it works
|
||||||
//
|
//
|
||||||
// The latter certainly has advantages for user-installable logging
|
// The latter certainly has advantages for user-installable logging
|
||||||
// libraries such as log4j; in a webapp for example this code should
|
// libraries such as log4j; in a webapp for example this code should
|
||||||
// first check whether the user has provided any of the possible
|
// 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,
|
// Unfortunately, however, Jdk14Logger will always work in jvm>=1.4,
|
||||||
// and SimpleLog will always work in any JVM. So the loop would never
|
// and SimpleLog will always work in any JVM. So the loop would never
|
||||||
// ever look for logging libraries in the parent classpath. Yet many
|
// 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.
|
* adapter classes.
|
||||||
* <p>
|
* <p>
|
||||||
* This method usually returns the context classloader. However if it
|
* This method usually returns the context class loader. However if it
|
||||||
* is discovered that the classloader which loaded this class is a child
|
* is discovered that the class loader which loaded this class is a child
|
||||||
* of the context classloader <i>and</i> the allowFlawedContext option
|
* of the context class loader <i>and</i> the allowFlawedContext option
|
||||||
* has been set then the classloader which loaded this class is returned
|
* has been set then the class loader which loaded this class is returned
|
||||||
* instead.
|
* instead.
|
||||||
* <p>
|
* <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
|
* descendant (rather than the same as or an ancestor of the context
|
||||||
* classloader) is when an app has created custom class loaders but
|
* class loader) is when an app has created custom class loaders but
|
||||||
* failed to correctly set the context classloader. This is a bug in
|
* failed to correctly set the context class loader. This is a bug in
|
||||||
* the calling application; however we provide the option for JCL to
|
* the calling application; however we provide the option for JCL to
|
||||||
* simply generate a warning rather than fail outright.
|
* 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
|
// UnifiedLoaderRepository) this can still work, so if user hasn't
|
||||||
// forbidden it, just return the contextClassLoader.
|
// forbidden it, just return the contextClassLoader.
|
||||||
if (!allowFlawedContext) {
|
if (!allowFlawedContext) {
|
||||||
throw new LogConfigurationException("Bad classloader hierarchy; LogFactoryImpl was loaded via" +
|
throw new LogConfigurationException("Bad class loader hierarchy; LogFactoryImpl was loaded via" +
|
||||||
" a classloader that is not related to the current context" +
|
" a class loader that is not related to the current context" +
|
||||||
" classloader.");
|
" class loader.");
|
||||||
}
|
}
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
logDiagnostic("[WARNING] the context classloader is not part of a" +
|
logDiagnostic("[WARNING] the context class loader is not part of a" +
|
||||||
" parent-child relationship with the classloader that" +
|
" parent-child relationship with the class loader that" +
|
||||||
" loaded LogFactoryImpl.");
|
" loaded LogFactoryImpl.");
|
||||||
}
|
}
|
||||||
// If contextClassLoader were null, getLowestClassLoader() would
|
// 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
|
// We really should just use the contextClassLoader as the starting
|
||||||
// point for scanning for log adapter classes. However it is expected
|
// point for scanning for log adapter classes. However it is expected
|
||||||
// that there are a number of broken systems out there which create
|
// 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.
|
// we handle those flawed systems anyway.
|
||||||
if (!allowFlawedContext) {
|
if (!allowFlawedContext) {
|
||||||
throw new LogConfigurationException(
|
throw new LogConfigurationException(
|
||||||
"Bad classloader hierarchy; LogFactoryImpl was loaded via" +
|
"Bad class loader hierarchy; LogFactoryImpl was loaded via" +
|
||||||
" a classloader that is not related to the current context" +
|
" a class loader that is not related to the current context" +
|
||||||
" classloader.");
|
" class loader.");
|
||||||
}
|
}
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
logDiagnostic(
|
logDiagnostic(
|
||||||
"Warning: the context classloader is an ancestor of the" +
|
"Warning: the context class loader is an ancestor of the" +
|
||||||
" classloader that loaded LogFactoryImpl; it should be" +
|
" class loader that loaded LogFactoryImpl; it should be" +
|
||||||
" the same or a descendant. The application using" +
|
" 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.");
|
" 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
|
* Given two related class loaders, return the one which is a child of
|
||||||
* the other.
|
* the other.
|
||||||
* <p>
|
* <p>
|
||||||
* @param c1 is a classloader (including the null classloader)
|
* @param c1 is a class loader (including the null class loader)
|
||||||
* @param c2 is a classloader (including the null classloader)
|
* @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,
|
* @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.
|
* 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>
|
* <p>
|
||||||
* If a SecurityException occurs, null is returned.
|
* If a SecurityException occurs, null is returned.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -949,7 +949,7 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
try {
|
try {
|
||||||
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> cl.getParent());
|
return AccessController.doPrivileged((PrivilegedAction<ClassLoader>) () -> cl.getParent());
|
||||||
} catch (final SecurityException ex) {
|
} catch (final SecurityException ex) {
|
||||||
logDiagnostic("[SECURITY] Unable to obtain parent classloader");
|
logDiagnostic("[SECURITY] Unable to obtain parent class loader");
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,7 +962,7 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
*
|
*
|
||||||
* @param logAdapterClassName is the class name of the Log implementation
|
* @param logAdapterClassName is the class name of the Log implementation
|
||||||
* that could not be instantiated. Cannot be {@code null}.
|
* 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
|
* @throws LogConfigurationException ALWAYS
|
||||||
*/
|
*/
|
||||||
@@ -1015,13 +1015,13 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
* <li>the specific class just doesn't implement the Log interface
|
* <li>the specific class just doesn't implement the Log interface
|
||||||
* (user screwed up), or
|
* (user screwed up), or
|
||||||
* <li> the specified class has bound to a Log class loaded by some other
|
* <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>
|
* </ol>
|
||||||
* <p>
|
* <p>
|
||||||
* Here we try to figure out which case has occurred so we can give the
|
* Here we try to figure out which case has occurred so we can give the
|
||||||
* user some reasonable feedback.
|
* 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().
|
* ie it is equivalent to badClass.getClassLoader().
|
||||||
*
|
*
|
||||||
* @param badClass is a Class object with the desired name, but which
|
* @param badClass is a Class object with the desired name, but which
|
||||||
@@ -1045,13 +1045,13 @@ public class LogFactoryImpl extends LogFactory {
|
|||||||
|
|
||||||
if (implementsLog) {
|
if (implementsLog) {
|
||||||
// the class does implement an interface called Log, but
|
// the class does implement an interface called Log, but
|
||||||
// it is in the wrong classloader
|
// it is in the wrong class loader
|
||||||
if (isDiagnosticsEnabled()) {
|
if (isDiagnosticsEnabled()) {
|
||||||
try {
|
try {
|
||||||
final ClassLoader logInterfaceClassLoader = getClassLoader(Log.class);
|
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" +
|
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) {
|
} catch (final Throwable t) {
|
||||||
handleThrowable(t); // may re-throw t
|
handleThrowable(t); // may re-throw t
|
||||||
logDiagnostic("Error while trying to output diagnostics about" + " bad class '" + badClass + "'");
|
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,
|
* 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>
|
* <p>
|
||||||
* This string will later be prefixed to each "internal logging" message
|
* This string will later be prefixed to each "internal logging" message
|
||||||
* emitted, so that users can clearly see any unexpected behavior.
|
* 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.
|
* its own unique prefix for log messages.
|
||||||
*/
|
*/
|
||||||
private void initDiagnostics() {
|
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
|
// that this LogFactoryImpl object is responsible for. However that
|
||||||
// isn't possible as that information isn't available. It is possible
|
// isn't possible as that information isn't available. It is possible
|
||||||
// to figure this out by looking at the logging from LogFactory to
|
// 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
|
* To use this class, configure the webapp deployment descriptor to call
|
||||||
* this class on webapp undeploy; the contextDestroyed method will tell
|
* this class on webapp undeploy; the contextDestroyed method will tell
|
||||||
* every accessible LogFactory class that the entry in its map for the
|
* 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
|
* @since 1.1
|
||||||
*/
|
*/
|
||||||
@@ -78,18 +78,18 @@ public class ServletContextCleaner implements ServletContextListener {
|
|||||||
// holding any data associated with the tccl being released.
|
// holding any data associated with the tccl being released.
|
||||||
//
|
//
|
||||||
// When there are multiple LogFactory classes in the classpath and
|
// 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
|
// 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
|
// and that class calls LogFactory the tccl gets registered in
|
||||||
// the LogFactory instance that is visible from the ancestor
|
// 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
|
// to is expected to have been loaded via the TCCL, so the
|
||||||
// underlying logging lib is only initialized/configured once.
|
// underlying logging lib is only initialized/configured once.
|
||||||
// These references from ancestor LogFactory classes down to
|
// These references from ancestor LogFactory classes down to
|
||||||
// TCCL class loaders are held via weak references and so should
|
// TCCL class loaders are held via weak references and so should
|
||||||
// be released but there are circumstances where they may not.
|
// 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
|
// the current tccl at each level tree, though, will definitely
|
||||||
// clear any problem references.
|
// clear any problem references.
|
||||||
ClassLoader loader = tccl;
|
ClassLoader loader = tccl;
|
||||||
|
|||||||
@@ -65,18 +65,18 @@ import java.util.Set;
|
|||||||
* The reason all this is necessary is due to a issue which
|
* The reason all this is necessary is due to a issue which
|
||||||
* arises during hot deploy in a J2EE-like containers.
|
* arises during hot deploy in a J2EE-like containers.
|
||||||
* Each component running in the container owns one or more class loaders; when
|
* 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,
|
* 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
|
* 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
|
* 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()}
|
* {@code LogFactory}'s factories member! If {@code LogFactory.release()}
|
||||||
* is called whenever component is unloaded, the class loaders will be correctly
|
* is called whenever component is unloaded, the class loaders will be correctly
|
||||||
* garbage collected; this <i>should</i> be done by any container that
|
* garbage collected; this <i>should</i> be done by any container that
|
||||||
* bundles commons-logging by default. However, holding the classloader
|
* bundles commons-logging by default. However, holding the class loader
|
||||||
* references weakly ensures that the classloader will be garbage collected
|
* references weakly ensures that the class loader will be garbage collected
|
||||||
* without the container performing this step.
|
* without the container performing this step.
|
||||||
* <p>
|
* <p>
|
||||||
* <strong>Limitations:</strong>
|
* <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.
|
* are used for its keys, it is necessary to use strong references for its values.
|
||||||
* <p>
|
* <p>
|
||||||
* If the abstract class {@code LogFactory} is
|
* 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
|
* {@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
|
* base LogFactory class, then there is a strong reference from the LogFactory
|
||||||
* class to the LogFactory1 instance (as normal) and a strong reference from
|
* 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
|
* {@code getClass().getClassLoader()}. This chain of references will prevent
|
||||||
* collection of the child classloader.
|
* collection of the child class loader.
|
||||||
* <p>
|
* <p>
|
||||||
* Such a situation occurs when the commons-logging.jar is
|
* 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
|
* 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>
|
* <p>
|
||||||
* To avoid this scenario, ensure
|
* 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,
|
* the base {@code LogFactory}. Creating custom LogFactory subclasses is,
|
||||||
* however, rare. The standard LogFactoryImpl class should be sufficient
|
* however, rare. The standard LogFactoryImpl class should be sufficient
|
||||||
* for most or all users.
|
* for most or all users.
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ import junit.framework.TestCase;
|
|||||||
/**
|
/**
|
||||||
* Test the ability to force the LogFactory class to use some
|
* Test the ability to force the LogFactory class to use some
|
||||||
* arbitrary Hashtable implementation to store its mapping from
|
* arbitrary Hashtable implementation to store its mapping from
|
||||||
* context-classloader -> LogFactory object.
|
* context class loader -> LogFactory object.
|
||||||
*/
|
*/
|
||||||
public class AltHashtableTestCase extends TestCase {
|
public class AltHashtableTestCase extends TestCase {
|
||||||
|
|
||||||
@@ -61,7 +61,7 @@ public class AltHashtableTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that when LogFactory sees a context-classloader for the
|
* Verify that when LogFactory sees a context class loader for the
|
||||||
* first time that it creates a new entry in the LogFactory.factories
|
* first time that it creates a new entry in the LogFactory.factories
|
||||||
* hashmap. In particular, this checks that this process works ok when
|
* hashmap. In particular, this checks that this process works ok when
|
||||||
* a system property has been used to specify an alternative Hashtable
|
* a system property has been used to specify an alternative Hashtable
|
||||||
@@ -86,7 +86,7 @@ public class AltHashtableTestCase extends TestCase {
|
|||||||
// Here, the reference to the LogFactory class should cause the
|
// Here, the reference to the LogFactory class should cause the
|
||||||
// class to be loaded and initialized. It will see the property
|
// class to be loaded and initialized. It will see the property
|
||||||
// set and use the AltHashtable class. If other tests in this
|
// set and use the AltHashtable class. If other tests in this
|
||||||
// class have already been run within the same classloader then
|
// class have already been run within the same class loader then
|
||||||
// LogFactory will already have been initialized, but that
|
// LogFactory will already have been initialized, but that
|
||||||
// doesn't change the effectiveness of this test.
|
// doesn't change the effectiveness of this test.
|
||||||
assertTrue(LogFactory.factories instanceof AltHashtable);
|
assertTrue(LogFactory.factories instanceof AltHashtable);
|
||||||
|
|||||||
@@ -26,13 +26,13 @@ import junit.framework.TestCase;
|
|||||||
public class LoadTestCase extends TestCase {
|
public class LoadTestCase extends TestCase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A custom classloader which "duplicates" logging classes available
|
* A custom class loader which "duplicates" logging classes available
|
||||||
* in the parent classloader into itself.
|
* in the parent class loader into itself.
|
||||||
* <p>
|
* <p>
|
||||||
* When asked to load a class that is in one of the LOG_PCKG packages,
|
* When asked to load a class that is in one of the LOG_PCKG packages,
|
||||||
* it loads the class itself (child-first). This class doesn't need
|
* it loads the class itself (child-first). This class doesn't need
|
||||||
* to be set up with a classpath, as it simply uses the same classpath
|
* to be set up with a classpath, as it simply uses the same classpath
|
||||||
* as the classloader that loaded it.
|
* as the class loader that loaded it.
|
||||||
*/
|
*/
|
||||||
static class AppClassLoader extends ClassLoader {
|
static class AppClassLoader extends ClassLoader {
|
||||||
|
|
||||||
@@ -79,7 +79,7 @@ public class LoadTestCase extends TestCase {
|
|||||||
@Override
|
@Override
|
||||||
public Class loadClass(final String name) throws ClassNotFoundException {
|
public Class loadClass(final String name) throws ClassNotFoundException {
|
||||||
|
|
||||||
// isolates all logging classes, application in the same classloader too.
|
// isolates all logging classes, application in the same class loader too.
|
||||||
// filters exceptions to simplify handling in test
|
// filters exceptions to simplify handling in test
|
||||||
for (final String element : LOG_PCKG) {
|
for (final String element : LOG_PCKG) {
|
||||||
if (name.startsWith(element) && name.indexOf("Exception") == -1) {
|
if (name.startsWith(element) && name.indexOf("Exception") == -1) {
|
||||||
@@ -103,8 +103,8 @@ public class LoadTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Load class UserClass via a temporary classloader which is a child of
|
* Load class UserClass via a temporary class loader which is a child of
|
||||||
* the classloader used to load this test class.
|
* the class loader used to load this test class.
|
||||||
*/
|
*/
|
||||||
private Class reload() throws Exception {
|
private Class reload() throws Exception {
|
||||||
Class testObjCls = null;
|
Class testObjCls = null;
|
||||||
@@ -129,7 +129,7 @@ public class LoadTestCase extends TestCase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Call the static setAllowFlawedContext method on the specified class
|
* Call the static setAllowFlawedContext method on the specified class
|
||||||
* (expected to be a UserClass loaded via a custom classloader), passing
|
* (expected to be a UserClass loaded via a custom class loader), passing
|
||||||
* it the specified state parameter.
|
* it the specified state parameter.
|
||||||
*/
|
*/
|
||||||
private void setAllowFlawedContext(final Class c, final String state) throws Exception {
|
private void setAllowFlawedContext(final Class c, final String state) throws Exception {
|
||||||
@@ -151,7 +151,7 @@ public class LoadTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test what happens when we play various classloader tricks like those
|
* Test what happens when we play various class loader tricks like those
|
||||||
* that happen in web and j2ee containers.
|
* that happen in web and j2ee containers.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that this test assumes that commons-logging.jar and log4j.jar
|
* Note that this test assumes that commons-logging.jar and log4j.jar
|
||||||
@@ -166,19 +166,19 @@ public class LoadTestCase extends TestCase {
|
|||||||
// 1. Thread.currentThread().setContextClassLoader(appLoader);
|
// 1. Thread.currentThread().setContextClassLoader(appLoader);
|
||||||
// 2. Thread.currentThread().setContextClassLoader(null);
|
// 2. Thread.currentThread().setContextClassLoader(null);
|
||||||
|
|
||||||
// Context classloader is same as class calling into log
|
// Context class loader is same as class calling into log
|
||||||
Class cls = reload();
|
Class cls = reload();
|
||||||
Thread.currentThread().setContextClassLoader(cls.getClassLoader());
|
Thread.currentThread().setContextClassLoader(cls.getClassLoader());
|
||||||
execute(cls);
|
execute(cls);
|
||||||
|
|
||||||
// Context classloader is the "bootclassloader". This is technically
|
// Context class loader is the "bootclass loader". This is technically
|
||||||
// bad, but LogFactoryImpl.ALLOW_FLAWED_CONTEXT defaults to true so
|
// bad, but LogFactoryImpl.ALLOW_FLAWED_CONTEXT defaults to true so
|
||||||
// this test should pass.
|
// this test should pass.
|
||||||
cls = reload();
|
cls = reload();
|
||||||
Thread.currentThread().setContextClassLoader(null);
|
Thread.currentThread().setContextClassLoader(null);
|
||||||
execute(cls);
|
execute(cls);
|
||||||
|
|
||||||
// Context classloader is the "bootclassloader". This is same as above
|
// Context class loader is the "bootclass loader". This is same as above
|
||||||
// except that ALLOW_FLAWED_CONTEXT is set to false; an error should
|
// except that ALLOW_FLAWED_CONTEXT is set to false; an error should
|
||||||
// now be reported.
|
// now be reported.
|
||||||
cls = reload();
|
cls = reload();
|
||||||
@@ -186,27 +186,27 @@ public class LoadTestCase extends TestCase {
|
|||||||
try {
|
try {
|
||||||
setAllowFlawedContext(cls, "false");
|
setAllowFlawedContext(cls, "false");
|
||||||
execute(cls);
|
execute(cls);
|
||||||
fail("Logging config succeeded when context classloader was null!");
|
fail("Logging config succeeded when context class loader was null!");
|
||||||
} catch (final InvocationTargetException ex) {
|
} catch (final InvocationTargetException ex) {
|
||||||
final Throwable targetException = ex.getTargetException();
|
final Throwable targetException = ex.getTargetException();
|
||||||
// LogConfigurationException is expected; the boot classloader doesn't *have* JCL available
|
// LogConfigurationException is expected; the boot class loader doesn't *have* JCL available
|
||||||
if (!(targetException instanceof LogConfigurationException)) {
|
if (!(targetException instanceof LogConfigurationException)) {
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Context classloader is the system classloader.
|
// Context class loader is the system class loader.
|
||||||
//
|
//
|
||||||
// This is expected to cause problems, as LogFactoryImpl will attempt
|
// This is expected to cause problems, as LogFactoryImpl will attempt
|
||||||
// to use the system classloader to load the Log4JLogger class, which
|
// to use the system class loader to load the Log4JLogger class, which
|
||||||
// will then be unable to cast that object to the Log interface loaded
|
// will then be unable to cast that object to the Log interface loaded
|
||||||
// via the child classloader. However as ALLOW_FLAWED_CONTEXT defaults
|
// via the child class loader. However as ALLOW_FLAWED_CONTEXT defaults
|
||||||
// to true this test should pass.
|
// to true this test should pass.
|
||||||
cls = reload();
|
cls = reload();
|
||||||
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
|
Thread.currentThread().setContextClassLoader(ClassLoader.getSystemClassLoader());
|
||||||
execute(cls);
|
execute(cls);
|
||||||
|
|
||||||
// Context classloader is the system classloader. This is the same
|
// Context class loader is the system class loader. This is the same
|
||||||
// as above except that ALLOW_FLAWED_CONTEXT is set to false; an error
|
// as above except that ALLOW_FLAWED_CONTEXT is set to false; an error
|
||||||
// should now be reported.
|
// should now be reported.
|
||||||
cls = reload();
|
cls = reload();
|
||||||
@@ -214,8 +214,8 @@ public class LoadTestCase extends TestCase {
|
|||||||
try {
|
try {
|
||||||
setAllowFlawedContext(cls, "false");
|
setAllowFlawedContext(cls, "false");
|
||||||
execute(cls);
|
execute(cls);
|
||||||
fail("Error: somehow downcast a Logger loaded via system classloader"
|
fail("Error: somehow downcast a Logger loaded via system class loader"
|
||||||
+ " to the Log interface loaded via a custom classloader");
|
+ " to the Log interface loaded via a custom class loader");
|
||||||
} catch (final InvocationTargetException ex) {
|
} catch (final InvocationTargetException ex) {
|
||||||
final Throwable targetException = ex.getTargetException();
|
final Throwable targetException = ex.getTargetException();
|
||||||
// LogConfigurationException is expected
|
// LogConfigurationException is expected
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ import junit.framework.TestCase;
|
|||||||
/**
|
/**
|
||||||
* Test cases for situations where getClassLoader or getContextClassLoader
|
* Test cases for situations where getClassLoader or getContextClassLoader
|
||||||
* return null. This can happen when using JDK 1.1. It can also happen when
|
* return null. This can happen when using JDK 1.1. It can also happen when
|
||||||
* JCL is deployed via the bootclassloader - something that could be done when
|
* JCL is deployed via the bootclass loader - something that could be done when
|
||||||
* using java in embedded systems.
|
* using java in embedded systems.
|
||||||
*/
|
*/
|
||||||
public class NullClassLoaderTestCase extends TestCase {
|
public class NullClassLoaderTestCase extends TestCase {
|
||||||
@@ -35,7 +35,7 @@ public class NullClassLoaderTestCase extends TestCase {
|
|||||||
*/
|
*/
|
||||||
public void testSameLogObject() throws Exception {
|
public void testSameLogObject() throws Exception {
|
||||||
// unfortunately, there just isn't any way to emulate JCL being
|
// unfortunately, there just isn't any way to emulate JCL being
|
||||||
// accessible via the null classloader in "standard" systems, so
|
// accessible via the null class loader in "standard" systems, so
|
||||||
// we can't include this test in our standard unit tests.
|
// we can't include this test in our standard unit tests.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ import junit.framework.Assert;
|
|||||||
* A ClassLoader which sees only specified classes, and which can be
|
* A ClassLoader which sees only specified classes, and which can be
|
||||||
* set to do parent-first or child-first path lookup.
|
* set to do parent-first or child-first path lookup.
|
||||||
* <p>
|
* <p>
|
||||||
* Note that this classloader is not "industrial strength"; users
|
* Note that this class loader is not "industrial strength"; users
|
||||||
* looking for such a class may wish to look at the Tomcat sourcecode
|
* looking for such a class may wish to look at the Tomcat sourcecode
|
||||||
* instead. In particular, this class may not be threadsafe.
|
* instead. In particular, this class may not be threadsafe.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -54,16 +54,16 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* A map of package-prefix to ClassLoader. Any class which is in
|
* A map of package-prefix to ClassLoader. Any class which is in
|
||||||
* this map is looked up via the specified classloader instead of
|
* this map is looked up via the specified class loader instead of
|
||||||
* the classpath associated with this classloader or its parents.
|
* the classpath associated with this class loader or its parents.
|
||||||
* <p>
|
* <p>
|
||||||
* This is necessary in order for the rest of the world to communicate
|
* This is necessary in order for the rest of the world to communicate
|
||||||
* with classes loaded via a custom classloader. As an example, junit
|
* with classes loaded via a custom class loader. As an example, junit
|
||||||
* tests which are loaded via a custom classloader needs to see
|
* tests which are loaded via a custom class loader needs to see
|
||||||
* the same junit classes as the code invoking the test, otherwise
|
* the same junit classes as the code invoking the test, otherwise
|
||||||
* they can't pass result objects back.
|
* they can't pass result objects back.
|
||||||
* <p>
|
* <p>
|
||||||
* Normally, only a classloader created with a null parent needs to
|
* Normally, only a class loader created with a null parent needs to
|
||||||
* have any lookasides defined.
|
* have any lookasides defined.
|
||||||
*/
|
*/
|
||||||
private HashMap lookasides;
|
private HashMap lookasides;
|
||||||
@@ -81,7 +81,7 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
* totally clean; nothing but the standard java library will be
|
* totally clean; nothing but the standard java library will be
|
||||||
* present.
|
* present.
|
||||||
* <p>
|
* <p>
|
||||||
* When using a null parent classloader with a junit test, it *is*
|
* When using a null parent class loader with a junit test, it *is*
|
||||||
* necessary for the junit library to also be visible. In this case, it
|
* necessary for the junit library to also be visible. In this case, it
|
||||||
* is recommended that the following code be used:
|
* is recommended that the following code be used:
|
||||||
* <pre>
|
* <pre>
|
||||||
@@ -91,7 +91,7 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
* </pre>
|
* </pre>
|
||||||
* Note that this works regardless of whether junit is on the system
|
* Note that this works regardless of whether junit is on the system
|
||||||
* classpath, or whether it has been loaded by some test framework that
|
* classpath, or whether it has been loaded by some test framework that
|
||||||
* creates its own classloader to run unit tests in (eg maven2's
|
* creates its own class loader to run unit tests in (eg maven2's
|
||||||
* Surefire plugin).
|
* Surefire plugin).
|
||||||
*/
|
*/
|
||||||
public PathableClassLoader(final ClassLoader parent) {
|
public PathableClassLoader(final ClassLoader parent) {
|
||||||
@@ -108,9 +108,9 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
* be found. Typically this is the name of a jar file, or a directory
|
* be found. Typically this is the name of a jar file, or a directory
|
||||||
* containing class files.
|
* containing class files.
|
||||||
* <p>
|
* <p>
|
||||||
* If there is no system property, but the classloader that loaded
|
* If there is no system property, but the class loader that loaded
|
||||||
* this class is a URLClassLoader then the set of URLs that the
|
* this class is a URLClassLoader then the set of URLs that the
|
||||||
* classloader uses for its classpath is scanned; any jar in the
|
* class loader uses for its classpath is scanned; any jar in the
|
||||||
* URL set whose name starts with the specified string is added to
|
* URL set whose name starts with the specified string is added to
|
||||||
* the classpath managed by this instance.
|
* the classpath managed by this instance.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -225,14 +225,14 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
final ClassLoader parent = getParent();
|
final ClassLoader parent = getParent();
|
||||||
if (parent == null) {
|
if (parent == null) {
|
||||||
// Alas, there is no method to get matching resources
|
// Alas, there is no method to get matching resources
|
||||||
// from a null (BOOT) parent classloader. Calling
|
// from a null (BOOT) parent class loader. Calling
|
||||||
// ClassLoader.getSystemClassLoader isn't right. Maybe
|
// ClassLoader.getSystemClassLoader isn't right. Maybe
|
||||||
// calling Class.class.getResources(name) would do?
|
// calling Class.class.getResources(name) would do?
|
||||||
//
|
//
|
||||||
// However for the purposes of unit tests, we can
|
// However for the purposes of unit tests, we can
|
||||||
// simply assume that no relevant resources are
|
// simply assume that no relevant resources are
|
||||||
// loadable from the parent; unit tests will never be
|
// loadable from the parent; unit tests will never be
|
||||||
// putting any of their resources in a "boot" classloader
|
// putting any of their resources in a "boot" class loader
|
||||||
// path!
|
// path!
|
||||||
return localUrls;
|
return localUrls;
|
||||||
}
|
}
|
||||||
@@ -245,15 +245,15 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If the classloader that loaded this class has this logical lib in its
|
* If the class loader that loaded this class has this logical lib in its
|
||||||
* path, then return the matching URL otherwise return null.
|
* path, then return the matching URL otherwise return null.
|
||||||
* <p>
|
* <p>
|
||||||
* This only works when the classloader loading this class is an instance
|
* This only works when the class loader loading this class is an instance
|
||||||
* of URLClassLoader and thus has a getURLs method that returns the classpath
|
* of URLClassLoader and thus has a getURLs method that returns the classpath
|
||||||
* it uses when loading classes. However in practice, the vast majority of the
|
* it uses when loading classes. However in practice, the vast majority of the
|
||||||
* time this type is the classloader used.
|
* time this type is the class loader used.
|
||||||
* <p>
|
* <p>
|
||||||
* The classpath of the classloader for this instance is scanned, and any
|
* The classpath of the class loader for this instance is scanned, and any
|
||||||
* jarfile in the path whose name starts with the logicalLib string is
|
* jarfile in the path whose name starts with the logicalLib string is
|
||||||
* considered a match. For example, passing "foo" will match a url
|
* considered a match. For example, passing "foo" will match a url
|
||||||
* of {@code file:///some/where/foo-2.7.jar}.
|
* of {@code file:///some/where/foo-2.7.jar}.
|
||||||
@@ -301,7 +301,7 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
* <p>
|
* <p>
|
||||||
* For each explicitly mapped package prefix, if the name matches the
|
* For each explicitly mapped package prefix, if the name matches the
|
||||||
* prefix associated with that entry then attempt to load the class via
|
* prefix associated with that entry then attempt to load the class via
|
||||||
* that entries' classloader.
|
* that entries' class loader.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
protected Class loadClass(final String name, final boolean resolve)
|
protected Class loadClass(final String name, final boolean resolve)
|
||||||
@@ -341,7 +341,7 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify whether this classloader should ask the parent classloader
|
* Specify whether this class loader should ask the parent class loader
|
||||||
* to resolve a class first, before trying to resolve it via its own
|
* to resolve a class first, before trying to resolve it via its own
|
||||||
* classpath.
|
* classpath.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -380,13 +380,13 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Specify a classloader to use for specific java packages.
|
* Specify a class loader to use for specific java packages.
|
||||||
* <p>
|
* <p>
|
||||||
* The specified classloader is normally a loader that is NOT
|
* The specified class loader is normally a loader that is NOT
|
||||||
* an ancestor of this classloader. In particular, this loader
|
* an ancestor of this class loader. In particular, this loader
|
||||||
* may have the bootloader as its parent, but be configured to
|
* may have the bootloader as its parent, but be configured to
|
||||||
* see specific other classes (eg the junit library loaded
|
* see specific other classes (eg the junit library loaded
|
||||||
* via the system classloader).
|
* via the system class loader).
|
||||||
* <p>
|
* <p>
|
||||||
* The differences between using this method, and using
|
* The differences between using this method, and using
|
||||||
* addLogicalLib are:
|
* addLogicalLib are:
|
||||||
@@ -394,11 +394,11 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
* <li>If code calls getClassLoader on a class loaded via
|
* <li>If code calls getClassLoader on a class loaded via
|
||||||
* "lookaside", then traces up its inheritance chain, it
|
* "lookaside", then traces up its inheritance chain, it
|
||||||
* will see the "real" class loaders. When the class is remapped
|
* will see the "real" class loaders. When the class is remapped
|
||||||
* into this classloader via addLogicalLib, the classloader
|
* into this class loader via addLogicalLib, the class loader
|
||||||
* chain seen is this object plus ancestors.
|
* chain seen is this object plus ancestors.
|
||||||
* <li>If two different jars contain classes in the same
|
* <li>If two different jars contain classes in the same
|
||||||
* package, then it is not possible to load both jars into
|
* package, then it is not possible to load both jars into
|
||||||
* the same "lookaside" classloader (eg the system classloader)
|
* the same "lookaside" class loader (eg the system class loader)
|
||||||
* then map one of those subsets from here. Of course they could
|
* then map one of those subsets from here. Of course they could
|
||||||
* be loaded into two different "lookaside" class loaders and
|
* be loaded into two different "lookaside" class loaders and
|
||||||
* then a prefix used to map from here to one of those class loaders.
|
* then a prefix used to map from here to one of those class loaders.
|
||||||
@@ -421,7 +421,7 @@ public class PathableClassLoader extends URLClassLoader {
|
|||||||
* </pre>
|
* </pre>
|
||||||
* <p>
|
* <p>
|
||||||
* Of course, this assumes that the classes of interest are already
|
* Of course, this assumes that the classes of interest are already
|
||||||
* in the classpath of the system classloader.
|
* in the classpath of the system class loader.
|
||||||
*/
|
*/
|
||||||
public void useSystemLoader(final String prefix) {
|
public void useSystemLoader(final String prefix) {
|
||||||
useExplicitLoader(prefix, ClassLoader.getSystemClassLoader());
|
useExplicitLoader(prefix, ClassLoader.getSystemClassLoader());
|
||||||
|
|||||||
@@ -23,10 +23,10 @@ import junit.framework.TestResult;
|
|||||||
import junit.framework.TestSuite;
|
import junit.framework.TestSuite;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Custom TestSuite class that can be used to control the context classloader
|
* Custom TestSuite class that can be used to control the context class loader
|
||||||
* in operation when a test runs.
|
* in operation when a test runs.
|
||||||
* <p>
|
* <p>
|
||||||
* For tests that need to control exactly what the classloader hierarchy is
|
* For tests that need to control exactly what the class loader hierarchy is
|
||||||
* like when the test is run, something like the following is recommended:
|
* like when the test is run, something like the following is recommended:
|
||||||
* <pre>
|
* <pre>
|
||||||
* class SomeTestCase extends TestCase {
|
* class SomeTestCase extends TestCase {
|
||||||
@@ -57,18 +57,18 @@ import junit.framework.TestSuite;
|
|||||||
* is expected that using the two classes together is common practice.
|
* is expected that using the two classes together is common practice.
|
||||||
* <p>
|
* <p>
|
||||||
* This class will run each test methods within the specified TestCase using
|
* This class will run each test methods within the specified TestCase using
|
||||||
* the specified context classloader and system classloader. If different
|
* the specified context class loader and system class loader. If different
|
||||||
* tests within the same class require different context class loaders,
|
* tests within the same class require different context class loaders,
|
||||||
* then the context classloader passed to the constructor should be the
|
* then the context class loader passed to the constructor should be the
|
||||||
* "lowest" one available, and tests that need the context set to some parent
|
* "lowest" one available, and tests that need the context set to some parent
|
||||||
* of this "lowest" classloader can call
|
* of this "lowest" class loader can call
|
||||||
* <pre>
|
* <pre>
|
||||||
* // NB: pseudo-code only
|
* // NB: pseudo-code only
|
||||||
* setContextClassLoader(getContextClassLoader().getParent());
|
* setContextClassLoader(getContextClassLoader().getParent());
|
||||||
* </pre>
|
* </pre>
|
||||||
* This class ensures that any context classloader changes applied by a test
|
* This class ensures that any context class loader changes applied by a test
|
||||||
* is undone after the test is run, so tests don't need to worry about
|
* is undone after the test is run, so tests don't need to worry about
|
||||||
* restoring the context classloader on exit. This class also ensures that
|
* restoring the context class loader on exit. This class also ensures that
|
||||||
* the system properties are restored to their original settings after each
|
* the system properties are restored to their original settings after each
|
||||||
* test, so tests that manipulate those don't need to worry about resetting them.
|
* test, so tests that manipulate those don't need to worry about resetting them.
|
||||||
* <p>
|
* <p>
|
||||||
@@ -87,14 +87,14 @@ import junit.framework.TestSuite;
|
|||||||
* <p>
|
* <p>
|
||||||
* <h2>Limitations</h2>
|
* <h2>Limitations</h2>
|
||||||
* <p>
|
* <p>
|
||||||
* This class cannot control the system classloader (ie what method
|
* This class cannot control the system class loader (ie what method
|
||||||
* ClassLoader.getSystemClassLoader returns) because Java provides no
|
* ClassLoader.getSystemClassLoader returns) because Java provides no
|
||||||
* mechanism for setting the system classloader. In this case, the only
|
* mechanism for setting the system class loader. In this case, the only
|
||||||
* option is to invoke the unit test in a separate JVM with the appropriate
|
* option is to invoke the unit test in a separate JVM with the appropriate
|
||||||
* settings.
|
* settings.
|
||||||
* <p>
|
* <p>
|
||||||
* The effect of using this approach in a system that uses junit's
|
* The effect of using this approach in a system that uses junit's
|
||||||
* "reloading classloader" behavior is unknown. This junit feature is
|
* "reloading class loader" behavior is unknown. This junit feature is
|
||||||
* intended for junit GUI apps where a test may be run multiple times
|
* intended for junit GUI apps where a test may be run multiple times
|
||||||
* within the same JVM - and in particular, when the .class file may
|
* within the same JVM - and in particular, when the .class file may
|
||||||
* be modified between runs of the test. How junit achieves this is
|
* be modified between runs of the test. How junit achieves this is
|
||||||
@@ -105,7 +105,7 @@ import junit.framework.TestSuite;
|
|||||||
public class PathableTestSuite extends TestSuite {
|
public class PathableTestSuite extends TestSuite {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The classloader that should be set as the context classloader
|
* The class loader that should be set as the context class loader
|
||||||
* before each test in the suite is run.
|
* before each test in the suite is run.
|
||||||
*/
|
*/
|
||||||
private final ClassLoader contextLoader;
|
private final ClassLoader contextLoader;
|
||||||
@@ -130,7 +130,7 @@ public class PathableTestSuite extends TestSuite {
|
|||||||
* Note that a Test may itself be a TestSuite object (ie a collection
|
* Note that a Test may itself be a TestSuite object (ie a collection
|
||||||
* of tests).
|
* of tests).
|
||||||
* <p>
|
* <p>
|
||||||
* The context classloader and system properties are saved before each
|
* The context class loader and system properties are saved before each
|
||||||
* test, and restored after the test completes to better isolate tests.
|
* test, and restored after the test completes to better isolate tests.
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -22,9 +22,9 @@ public class UserClass {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the ALLOW_FLAWED_CONTEXT feature on the LogFactoryImpl object
|
* Sets the ALLOW_FLAWED_CONTEXT feature on the LogFactoryImpl object
|
||||||
* associated with this class' classloader.
|
* associated with this class' class loader.
|
||||||
* <p>
|
* <p>
|
||||||
* Don't forget to set the context classloader to whatever it will be
|
* Don't forget to set the context class loader to whatever it will be
|
||||||
* when an instance of this class is actually created <i>before</i> calling
|
* when an instance of this class is actually created <i>before</i> calling
|
||||||
* this method!
|
* this method!
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ public class FirstPriorityConfigTestCase extends TestCase {
|
|||||||
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
||||||
final URL baseUrl = dummy.findResource(thisClassPath);
|
final URL baseUrl = dummy.findResource(thisClassPath);
|
||||||
|
|
||||||
// Now set up the desired classloader hierarchy. We'll put JCL
|
// Now set up the desired class loader hierarchy. We'll put JCL
|
||||||
// in the container path, the test in a webapp path, and
|
// in the container path, the test in a webapp path, and
|
||||||
// both config files into the webapp path too.
|
// both config files into the webapp path too.
|
||||||
final PathableClassLoader containerLoader = new PathableClassLoader(null);
|
final PathableClassLoader containerLoader = new PathableClassLoader(null);
|
||||||
@@ -111,10 +111,10 @@ public class FirstPriorityConfigTestCase extends TestCase {
|
|||||||
final ClassLoader lfClassLoader = instance.getClass().getClassLoader();
|
final ClassLoader lfClassLoader = instance.getClass().getClassLoader();
|
||||||
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
// context classloader should be thisClassLoader
|
// context class loader should be thisClassLoader
|
||||||
assertEquals(thisClassLoader, contextClassLoader);
|
assertEquals(thisClassLoader, contextClassLoader);
|
||||||
|
|
||||||
// lfClassLoader should be parent of this classloader
|
// lfClassLoader should be parent of this class loader
|
||||||
assertEquals(lfClassLoader, thisClassLoader.getParent());
|
assertEquals(lfClassLoader, thisClassLoader.getParent());
|
||||||
assertEquals(PathableClassLoader.class.getName(),
|
assertEquals(PathableClassLoader.class.getName(),
|
||||||
lfClassLoader.getClass().getName());
|
lfClassLoader.getClass().getName());
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ public class PriorityConfigTestCase extends TestCase {
|
|||||||
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
||||||
final URL baseUrl = dummy.findResource(thisClassPath);
|
final URL baseUrl = dummy.findResource(thisClassPath);
|
||||||
|
|
||||||
// Now set up the desired classloader hierarchy. We'll put a config
|
// Now set up the desired class loader hierarchy. We'll put a config
|
||||||
// file of priority=10 in the container path, and ones of both
|
// file of priority=10 in the container path, and ones of both
|
||||||
// "no priority" and priority=20 in the webapp path.
|
// "no priority" and priority=20 in the webapp path.
|
||||||
//
|
//
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ public class CustomConfigAPITestCase extends CustomConfigTestCase {
|
|||||||
final PathableClassLoader parent = new PathableClassLoader(null);
|
final PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
|
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
|
||||||
|
|
||||||
// the TestHandler class must be accessible from the System classloader
|
// the TestHandler class must be accessible from the System class loader
|
||||||
// in order for java.util.logging.LogManager.readConfiguration to
|
// in order for java.util.logging.LogManager.readConfiguration to
|
||||||
// be able to instantiate it. And this test case must see the same
|
// be able to instantiate it. And this test case must see the same
|
||||||
// class in order to be able to access its data. Yes this is ugly
|
// class in order to be able to access its data. Yes this is ugly
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ public class CustomConfigFullTestCase extends CustomConfigTestCase {
|
|||||||
final PathableClassLoader parent = new PathableClassLoader(null);
|
final PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
|
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
|
||||||
|
|
||||||
// the TestHandler class must be accessible from the System classloader
|
// the TestHandler class must be accessible from the System class loader
|
||||||
// in order for java.util.logging.LogManager.readConfiguration to
|
// in order for java.util.logging.LogManager.readConfiguration to
|
||||||
// be able to instantiate it. And this test case must see the same
|
// be able to instantiate it. And this test case must see the same
|
||||||
// class in order to be able to access its data. Yes this is ugly
|
// class in order to be able to access its data. Yes this is ugly
|
||||||
|
|||||||
@@ -48,15 +48,15 @@ public class CustomConfigTestCase extends DefaultConfigTestCase {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Make a class available in the system classloader even when its classfile is
|
* Make a class available in the system class loader even when its classfile is
|
||||||
* not present in the classpath configured for that classloader. This only
|
* not present in the classpath configured for that class loader. This only
|
||||||
* works for classes for which all dependencies are already loaded in
|
* works for classes for which all dependencies are already loaded in
|
||||||
* that classloader.
|
* that class loader.
|
||||||
*/
|
*/
|
||||||
protected static void loadTestHandler(final String className, final ClassLoader targetCL) {
|
protected static void loadTestHandler(final String className, final ClassLoader targetCL) {
|
||||||
try {
|
try {
|
||||||
targetCL.loadClass(className);
|
targetCL.loadClass(className);
|
||||||
// fail("Class already in target classloader");
|
// fail("Class already in target class loader");
|
||||||
return;
|
return;
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
// ok, go ahead and load it
|
// ok, go ahead and load it
|
||||||
@@ -87,7 +87,7 @@ public class CustomConfigTestCase extends DefaultConfigTestCase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the name of a class that is somewhere in the classpath of the provided
|
* Given the name of a class that is somewhere in the classpath of the provided
|
||||||
* classloader, return the contents of the corresponding .class file.
|
* class loader, return the contents of the corresponding .class file.
|
||||||
*/
|
*/
|
||||||
protected static byte[] readClass(final String name, final ClassLoader srcCL) throws Exception {
|
protected static byte[] readClass(final String name, final ClassLoader srcCL) throws Exception {
|
||||||
final String resName = name.replace('.', '/') + ".class";
|
final String resName = name.replace('.', '/') + ".class";
|
||||||
@@ -115,7 +115,7 @@ public class CustomConfigTestCase extends DefaultConfigTestCase {
|
|||||||
final PathableClassLoader cl = new PathableClassLoader(null);
|
final PathableClassLoader cl = new PathableClassLoader(null);
|
||||||
cl.useExplicitLoader("junit.", Test.class.getClassLoader());
|
cl.useExplicitLoader("junit.", Test.class.getClassLoader());
|
||||||
|
|
||||||
// the TestHandler class must be accessible from the System classloader
|
// the TestHandler class must be accessible from the System class loader
|
||||||
// in order for java.util.logging.LogManager.readConfiguration to
|
// in order for java.util.logging.LogManager.readConfiguration to
|
||||||
// be able to instantiate it. And this test case must see the same
|
// be able to instantiate it. And this test case must see the same
|
||||||
// class in order to be able to access its data. Yes this is ugly
|
// class in order to be able to access its data. Yes this is ugly
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ import junit.framework.Test;
|
|||||||
import junit.framework.TestCase;
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for Log4J logging when there is only one classloader and everything
|
* Tests for Log4J logging when there is only one class loader and everything
|
||||||
* is in it, as would be the situation for a standalone application.
|
* is in it, as would be the situation for a standalone application.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|||||||
@@ -45,12 +45,12 @@ public class ChildFirstTestCase extends TestCase {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up a custom classloader hierarchy for this test case.
|
* Sets up a custom class loader hierarchy for this test case.
|
||||||
* The hierarchy is:
|
* The hierarchy is:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li> contextloader: child-first.
|
* <li> contextloader: child-first.
|
||||||
* <li> childloader: child-first, used to load test case.
|
* <li> childloader: child-first, used to load test case.
|
||||||
* <li> parentloader: child-first, parent is the bootclassloader.
|
* <li> parentloader: child-first, parent is the bootclass loader.
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public static Test suite() throws Exception {
|
public static Test suite() throws Exception {
|
||||||
@@ -64,7 +64,7 @@ public class ChildFirstTestCase extends TestCase {
|
|||||||
|
|
||||||
// Make the junit classes visible as a special case, as junit
|
// Make the junit classes visible as a special case, as junit
|
||||||
// won't be able to call this class at all without this. The
|
// won't be able to call this class at all without this. The
|
||||||
// junit classes must be visible from the classloader that loaded
|
// junit classes must be visible from the class loader that loaded
|
||||||
// this class, so use that as the source for future access to classes
|
// this class, so use that as the source for future access to classes
|
||||||
// from the junit package.
|
// from the junit package.
|
||||||
parent.useExplicitLoader("junit.", thisClassLoader);
|
parent.useExplicitLoader("junit.", thisClassLoader);
|
||||||
@@ -73,20 +73,20 @@ public class ChildFirstTestCase extends TestCase {
|
|||||||
// Make the commons-logging.jar classes visible via the parent
|
// Make the commons-logging.jar classes visible via the parent
|
||||||
parent.addLogicalLib("commons-logging");
|
parent.addLogicalLib("commons-logging");
|
||||||
|
|
||||||
// Create a child classloader to load the test case through
|
// Create a child class loader to load the test case through
|
||||||
final PathableClassLoader child = new PathableClassLoader(parent);
|
final PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
child.setParentFirst(false);
|
child.setParentFirst(false);
|
||||||
|
|
||||||
// Obviously, the child classloader needs to have the test classes
|
// Obviously, the child class loader needs to have the test classes
|
||||||
// in its path!
|
// in its path!
|
||||||
child.addLogicalLib("testclasses");
|
child.addLogicalLib("testclasses");
|
||||||
child.addLogicalLib("commons-logging-adapters");
|
child.addLogicalLib("commons-logging-adapters");
|
||||||
|
|
||||||
// Create a third classloader to be the context classloader.
|
// Create a third class loader to be the context class loader.
|
||||||
final PathableClassLoader context = new PathableClassLoader(child);
|
final PathableClassLoader context = new PathableClassLoader(child);
|
||||||
context.setParentFirst(false);
|
context.setParentFirst(false);
|
||||||
|
|
||||||
// reload this class via the child classloader
|
// reload this class via the child class loader
|
||||||
final Class testClass = child.loadClass(thisClass.getName());
|
final Class testClass = child.loadClass(thisClass.getName());
|
||||||
|
|
||||||
// and return our custom TestSuite class
|
// and return our custom TestSuite class
|
||||||
@@ -122,56 +122,56 @@ public class ChildFirstTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the classloader hierarchy is as expected, and that
|
* Test that the class loader hierarchy is as expected, and that
|
||||||
* calling loadClass() on various class loaders works as expected.
|
* calling loadClass() on various class loaders works as expected.
|
||||||
* Note that for this test case, parent-first classloading is
|
* Note that for this test case, parent-first classloading is
|
||||||
* in effect.
|
* in effect.
|
||||||
*/
|
*/
|
||||||
public void testPaths() throws Exception {
|
public void testPaths() throws Exception {
|
||||||
// the context classloader is not expected to be null
|
// the context class loader is not expected to be null
|
||||||
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
assertNotNull("Context classloader is null", contextLoader);
|
assertNotNull("Context class loader is null", contextLoader);
|
||||||
assertEquals("Context classloader has unexpected type",
|
assertEquals("Context class loader has unexpected type",
|
||||||
PathableClassLoader.class.getName(),
|
PathableClassLoader.class.getName(),
|
||||||
contextLoader.getClass().getName());
|
contextLoader.getClass().getName());
|
||||||
|
|
||||||
// the classloader that loaded this class is obviously not null
|
// the class loader that loaded this class is obviously not null
|
||||||
final ClassLoader thisLoader = this.getClass().getClassLoader();
|
final ClassLoader thisLoader = this.getClass().getClassLoader();
|
||||||
assertNotNull("thisLoader is null", thisLoader);
|
assertNotNull("thisLoader is null", thisLoader);
|
||||||
assertEquals("thisLoader has unexpected type",
|
assertEquals("thisLoader has unexpected type",
|
||||||
PathableClassLoader.class.getName(),
|
PathableClassLoader.class.getName(),
|
||||||
thisLoader.getClass().getName());
|
thisLoader.getClass().getName());
|
||||||
|
|
||||||
// the suite method specified that the context classloader's parent
|
// the suite method specified that the context class loader's parent
|
||||||
// is the loader that loaded this test case.
|
// is the loader that loaded this test case.
|
||||||
assertSame("Context classloader is not child of thisLoader",
|
assertSame("Context class loader is not child of thisLoader",
|
||||||
thisLoader, contextLoader.getParent());
|
thisLoader, contextLoader.getParent());
|
||||||
|
|
||||||
// thisLoader's parent should be available
|
// thisLoader's parent should be available
|
||||||
final ClassLoader parentLoader = thisLoader.getParent();
|
final ClassLoader parentLoader = thisLoader.getParent();
|
||||||
assertNotNull("Parent classloader is null", parentLoader);
|
assertNotNull("Parent class loader is null", parentLoader);
|
||||||
assertEquals("Parent classloader has unexpected type",
|
assertEquals("Parent class loader has unexpected type",
|
||||||
PathableClassLoader.class.getName(),
|
PathableClassLoader.class.getName(),
|
||||||
parentLoader.getClass().getName());
|
parentLoader.getClass().getName());
|
||||||
|
|
||||||
// parent should have a parent of null
|
// parent should have a parent of null
|
||||||
assertNull("Parent classloader has non-null parent", parentLoader.getParent());
|
assertNull("Parent class loader has non-null parent", parentLoader.getParent());
|
||||||
|
|
||||||
// getSystemClassloader is not a PathableClassLoader; it's of a
|
// getSystemClassloader is not a PathableClassLoader; it's of a
|
||||||
// built-in type. This also verifies that system classloader is none of
|
// built-in type. This also verifies that system class loader is none of
|
||||||
// (context, child, parent).
|
// (context, child, parent).
|
||||||
final ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
|
final ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
|
||||||
assertNotNull("System classloader is null", systemLoader);
|
assertNotNull("System class loader is null", systemLoader);
|
||||||
assertFalse("System classloader has unexpected type",
|
assertFalse("System class loader has unexpected type",
|
||||||
PathableClassLoader.class.getName().equals(
|
PathableClassLoader.class.getName().equals(
|
||||||
systemLoader.getClass().getName()));
|
systemLoader.getClass().getName()));
|
||||||
|
|
||||||
// junit classes should be visible; their classloader is not
|
// junit classes should be visible; their class loader is not
|
||||||
// in the hierarchy of parent class loaders for this class,
|
// in the hierarchy of parent class loaders for this class,
|
||||||
// though it is accessible due to trickery in the PathableClassLoader.
|
// though it is accessible due to trickery in the PathableClassLoader.
|
||||||
final Class junitTest = contextLoader.loadClass("junit.framework.Test");
|
final Class junitTest = contextLoader.loadClass("junit.framework.Test");
|
||||||
final Set ancestorCLs = getAncestorCLs();
|
final Set ancestorCLs = getAncestorCLs();
|
||||||
assertFalse("Junit not loaded by ancestor classloader",
|
assertFalse("Junit not loaded by ancestor class loader",
|
||||||
ancestorCLs.contains(junitTest.getClassLoader()));
|
ancestorCLs.contains(junitTest.getClassLoader()));
|
||||||
|
|
||||||
// jcl api classes should be visible only via the parent
|
// jcl api classes should be visible only via the parent
|
||||||
@@ -199,9 +199,9 @@ public class ChildFirstTestCase extends TestCase {
|
|||||||
// ok
|
// ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// String class classloader is null
|
// String class class loader is null
|
||||||
final Class stringClass = contextLoader.loadClass("java.lang.String");
|
final Class stringClass = contextLoader.loadClass("java.lang.String");
|
||||||
assertNull("String class classloader is not null!",
|
assertNull("String class class loader is not null!",
|
||||||
stringClass.getClassLoader());
|
stringClass.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,11 +218,11 @@ public class ChildFirstTestCase extends TestCase {
|
|||||||
resource = childLoader.getResource("nosuchfile");
|
resource = childLoader.getResource("nosuchfile");
|
||||||
assertNull("Non-null URL returned for invalid resource name", resource);
|
assertNull("Non-null URL returned for invalid resource name", resource);
|
||||||
|
|
||||||
// getResource where it is accessible only to parent classloader
|
// getResource where it is accessible only to parent class loader
|
||||||
resource = childLoader.getResource("org/apache/commons/logging/Log.class");
|
resource = childLoader.getResource("org/apache/commons/logging/Log.class");
|
||||||
assertNotNull("Unable to locate Log.class resource", resource);
|
assertNotNull("Unable to locate Log.class resource", resource);
|
||||||
|
|
||||||
// getResource where it is accessible only to child classloader
|
// getResource where it is accessible only to child class loader
|
||||||
resource = childLoader.getResource("org/apache/commons/logging/PathableTestSuite.class");
|
resource = childLoader.getResource("org/apache/commons/logging/PathableTestSuite.class");
|
||||||
assertNotNull("Unable to locate PathableTestSuite.class resource", resource);
|
assertNotNull("Unable to locate PathableTestSuite.class resource", resource);
|
||||||
|
|
||||||
@@ -242,12 +242,12 @@ public class ChildFirstTestCase extends TestCase {
|
|||||||
public void testResourceAsStream() throws Exception {
|
public void testResourceAsStream() throws Exception {
|
||||||
java.io.InputStream is;
|
java.io.InputStream is;
|
||||||
|
|
||||||
// verify the classloader hierarchy
|
// verify the class loader hierarchy
|
||||||
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
final ClassLoader childLoader = contextLoader.getParent();
|
final ClassLoader childLoader = contextLoader.getParent();
|
||||||
final ClassLoader parentLoader = childLoader.getParent();
|
final ClassLoader parentLoader = childLoader.getParent();
|
||||||
final ClassLoader bootLoader = parentLoader.getParent();
|
final ClassLoader bootLoader = parentLoader.getParent();
|
||||||
assertNull("Unexpected classloader hierarchy", bootLoader);
|
assertNull("Unexpected class loader hierarchy", bootLoader);
|
||||||
|
|
||||||
// getResourceAsStream where no instances exist
|
// getResourceAsStream where no instances exist
|
||||||
is = childLoader.getResourceAsStream("nosuchfile");
|
is = childLoader.getResourceAsStream("nosuchfile");
|
||||||
@@ -271,12 +271,12 @@ public class ChildFirstTestCase extends TestCase {
|
|||||||
Enumeration resources;
|
Enumeration resources;
|
||||||
URL[] urls;
|
URL[] urls;
|
||||||
|
|
||||||
// verify the classloader hierarchy
|
// verify the class loader hierarchy
|
||||||
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
final ClassLoader childLoader = contextLoader.getParent();
|
final ClassLoader childLoader = contextLoader.getParent();
|
||||||
final ClassLoader parentLoader = childLoader.getParent();
|
final ClassLoader parentLoader = childLoader.getParent();
|
||||||
final ClassLoader bootLoader = parentLoader.getParent();
|
final ClassLoader bootLoader = parentLoader.getParent();
|
||||||
assertNull("Unexpected classloader hierarchy", bootLoader);
|
assertNull("Unexpected class loader hierarchy", bootLoader);
|
||||||
|
|
||||||
// getResources where no instances exist
|
// getResources where no instances exist
|
||||||
resources = childLoader.getResources("nosuchfile");
|
resources = childLoader.getResources("nosuchfile");
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import junit.framework.TestCase;
|
|||||||
public class GeneralTestCase extends TestCase {
|
public class GeneralTestCase extends TestCase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that the context classloader is a custom one, then reset it to
|
* Verify that the context class loader is a custom one, then reset it to
|
||||||
* a non-custom one.
|
* a non-custom one.
|
||||||
*/
|
*/
|
||||||
private static void checkAndSetContext() {
|
private static void checkAndSetContext() {
|
||||||
@@ -57,7 +57,7 @@ public class GeneralTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up a custom classloader hierarchy for this test case.
|
* Sets up a custom class loader hierarchy for this test case.
|
||||||
*/
|
*/
|
||||||
public static Test suite() throws Exception {
|
public static Test suite() throws Exception {
|
||||||
final Class thisClass = GeneralTestCase.class;
|
final Class thisClass = GeneralTestCase.class;
|
||||||
@@ -67,7 +67,7 @@ public class GeneralTestCase extends TestCase {
|
|||||||
loader.useExplicitLoader("junit.", thisClassLoader);
|
loader.useExplicitLoader("junit.", thisClassLoader);
|
||||||
loader.addLogicalLib("testclasses");
|
loader.addLogicalLib("testclasses");
|
||||||
|
|
||||||
// reload this class via the child classloader
|
// reload this class via the child class loader
|
||||||
final Class testClass = loader.loadClass(thisClass.getName());
|
final Class testClass = loader.loadClass(thisClass.getName());
|
||||||
|
|
||||||
// and return our custom TestSuite class
|
// and return our custom TestSuite class
|
||||||
@@ -75,7 +75,7 @@ public class GeneralTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that when a test method modifies the context classloader it is
|
* Verify that when a test method modifies the context class loader it is
|
||||||
* reset before the next test is run.
|
* reset before the next test is run.
|
||||||
* <p>
|
* <p>
|
||||||
* This method works in conjunction with testResetContext2. There is no
|
* This method works in conjunction with testResetContext2. There is no
|
||||||
|
|||||||
@@ -46,12 +46,12 @@ import junit.framework.TestCase;
|
|||||||
public class ParentFirstTestCase extends TestCase {
|
public class ParentFirstTestCase extends TestCase {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets up a custom classloader hierarchy for this test case.
|
* Sets up a custom class loader hierarchy for this test case.
|
||||||
* The hierarchy is:
|
* The hierarchy is:
|
||||||
* <ul>
|
* <ul>
|
||||||
* <li> contextloader: parent-first.
|
* <li> contextloader: parent-first.
|
||||||
* <li> childloader: parent-first, used to load test case.
|
* <li> childloader: parent-first, used to load test case.
|
||||||
* <li> parentloader: parent-first, parent is the bootclassloader.
|
* <li> parentloader: parent-first, parent is the boot class loader.
|
||||||
* </ul>
|
* </ul>
|
||||||
*/
|
*/
|
||||||
public static Test suite() throws Exception {
|
public static Test suite() throws Exception {
|
||||||
@@ -64,7 +64,7 @@ public class ParentFirstTestCase extends TestCase {
|
|||||||
|
|
||||||
// Make the junit classes visible as a special case, as junit
|
// Make the junit classes visible as a special case, as junit
|
||||||
// won't be able to call this class at all without this. The
|
// won't be able to call this class at all without this. The
|
||||||
// junit classes must be visible from the classloader that loaded
|
// junit classes must be visible from the class loader that loaded
|
||||||
// this class, so use that as the source for future access to classes
|
// this class, so use that as the source for future access to classes
|
||||||
// from the junit package.
|
// from the junit package.
|
||||||
parent.useExplicitLoader("junit.", thisClassLoader);
|
parent.useExplicitLoader("junit.", thisClassLoader);
|
||||||
@@ -73,18 +73,18 @@ public class ParentFirstTestCase extends TestCase {
|
|||||||
// make the commons-logging.jar classes visible via the parent
|
// make the commons-logging.jar classes visible via the parent
|
||||||
parent.addLogicalLib("commons-logging");
|
parent.addLogicalLib("commons-logging");
|
||||||
|
|
||||||
// create a child classloader to load the test case through
|
// create a child class loader to load the test case through
|
||||||
final PathableClassLoader child = new PathableClassLoader(parent);
|
final PathableClassLoader child = new PathableClassLoader(parent);
|
||||||
|
|
||||||
// obviously, the child classloader needs to have the test classes
|
// obviously, the child class loader needs to have the test classes
|
||||||
// in its path!
|
// in its path!
|
||||||
child.addLogicalLib("testclasses");
|
child.addLogicalLib("testclasses");
|
||||||
child.addLogicalLib("commons-logging-adapters");
|
child.addLogicalLib("commons-logging-adapters");
|
||||||
|
|
||||||
// create a third classloader to be the context classloader.
|
// create a third class loader to be the context class loader.
|
||||||
final PathableClassLoader context = new PathableClassLoader(child);
|
final PathableClassLoader context = new PathableClassLoader(child);
|
||||||
|
|
||||||
// reload this class via the child classloader
|
// reload this class via the child class loader
|
||||||
final Class testClass = child.loadClass(thisClass.getName());
|
final Class testClass = child.loadClass(thisClass.getName());
|
||||||
|
|
||||||
// and return our custom TestSuite class
|
// and return our custom TestSuite class
|
||||||
@@ -120,55 +120,55 @@ public class ParentFirstTestCase extends TestCase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the classloader hierarchy is as expected, and that
|
* Test that the class loader hierarchy is as expected, and that
|
||||||
* calling loadClass() on various class loaders works as expected.
|
* calling loadClass() on various class loaders works as expected.
|
||||||
* Note that for this test case, parent-first classloading is
|
* Note that for this test case, parent-first classloading is
|
||||||
* in effect.
|
* in effect.
|
||||||
*/
|
*/
|
||||||
public void testPaths() throws Exception {
|
public void testPaths() throws Exception {
|
||||||
// the context classloader is not expected to be null
|
// the context class loader is not expected to be null
|
||||||
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
assertNotNull("Context classloader is null", contextLoader);
|
assertNotNull("Context class loader is null", contextLoader);
|
||||||
assertEquals("Context classloader has unexpected type",
|
assertEquals("Context class loader has unexpected type",
|
||||||
PathableClassLoader.class.getName(),
|
PathableClassLoader.class.getName(),
|
||||||
contextLoader.getClass().getName());
|
contextLoader.getClass().getName());
|
||||||
|
|
||||||
// the classloader that loaded this class is obviously not null
|
// the class loader that loaded this class is obviously not null
|
||||||
final ClassLoader thisLoader = this.getClass().getClassLoader();
|
final ClassLoader thisLoader = this.getClass().getClassLoader();
|
||||||
assertNotNull("thisLoader is null", thisLoader);
|
assertNotNull("thisLoader is null", thisLoader);
|
||||||
assertEquals("thisLoader has unexpected type",
|
assertEquals("thisLoader has unexpected type",
|
||||||
PathableClassLoader.class.getName(),
|
PathableClassLoader.class.getName(),
|
||||||
thisLoader.getClass().getName());
|
thisLoader.getClass().getName());
|
||||||
|
|
||||||
// the suite method specified that the context classloader's parent
|
// the suite method specified that the context class loader's parent
|
||||||
// is the loader that loaded this test case.
|
// is the loader that loaded this test case.
|
||||||
assertSame("Context classloader is not child of thisLoader",
|
assertSame("Context class loader is not child of thisLoader",
|
||||||
thisLoader, contextLoader.getParent());
|
thisLoader, contextLoader.getParent());
|
||||||
|
|
||||||
// thisLoader's parent should be available
|
// thisLoader's parent should be available
|
||||||
final ClassLoader parentLoader = thisLoader.getParent();
|
final ClassLoader parentLoader = thisLoader.getParent();
|
||||||
assertNotNull("Parent classloader is null", parentLoader);
|
assertNotNull("Parent class loader is null", parentLoader);
|
||||||
assertEquals("Parent classloader has unexpected type",
|
assertEquals("Parent class loader has unexpected type",
|
||||||
PathableClassLoader.class.getName(),
|
PathableClassLoader.class.getName(),
|
||||||
parentLoader.getClass().getName());
|
parentLoader.getClass().getName());
|
||||||
|
|
||||||
// parent should have a parent of null
|
// parent should have a parent of null
|
||||||
assertNull("Parent classloader has non-null parent", parentLoader.getParent());
|
assertNull("Parent class loader has non-null parent", parentLoader.getParent());
|
||||||
|
|
||||||
// getSystemClassloader is not a PathableClassLoader; it's of a
|
// getSystemClassloader is not a PathableClassLoader; it's of a
|
||||||
// built-in type. This also verifies that system classloader is none of
|
// built-in type. This also verifies that system class loader is none of
|
||||||
// (context, child, parent).
|
// (context, child, parent).
|
||||||
final ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
|
final ClassLoader systemLoader = ClassLoader.getSystemClassLoader();
|
||||||
assertNotNull("System classloader is null", systemLoader);
|
assertNotNull("System class loader is null", systemLoader);
|
||||||
assertNotEquals("System classloader has unexpected type", PathableClassLoader.class.getName(),
|
assertNotEquals("System class loader has unexpected type", PathableClassLoader.class.getName(),
|
||||||
systemLoader.getClass().getName());
|
systemLoader.getClass().getName());
|
||||||
|
|
||||||
// junit classes should be visible; their classloader is not
|
// junit classes should be visible; their class loader is not
|
||||||
// in the hierarchy of parent class loaders for this class,
|
// in the hierarchy of parent class loaders for this class,
|
||||||
// though it is accessible due to trickery in the PathableClassLoader.
|
// though it is accessible due to trickery in the PathableClassLoader.
|
||||||
final Class junitTest = contextLoader.loadClass("junit.framework.Test");
|
final Class junitTest = contextLoader.loadClass("junit.framework.Test");
|
||||||
final Set ancestorCLs = getAncestorCLs();
|
final Set ancestorCLs = getAncestorCLs();
|
||||||
assertFalse("Junit not loaded by ancestor classloader",
|
assertFalse("Junit not loaded by ancestor class loader",
|
||||||
ancestorCLs.contains(junitTest.getClassLoader()));
|
ancestorCLs.contains(junitTest.getClassLoader()));
|
||||||
|
|
||||||
// jcl api classes should be visible only via the parent
|
// jcl api classes should be visible only via the parent
|
||||||
@@ -196,9 +196,9 @@ public class ParentFirstTestCase extends TestCase {
|
|||||||
// ok
|
// ok
|
||||||
}
|
}
|
||||||
|
|
||||||
// String class classloader is null
|
// String class class loader is null
|
||||||
final Class stringClass = contextLoader.loadClass("java.lang.String");
|
final Class stringClass = contextLoader.loadClass("java.lang.String");
|
||||||
assertNull("String class classloader is not null!",
|
assertNull("String class class loader is not null!",
|
||||||
stringClass.getClassLoader());
|
stringClass.getClassLoader());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -215,11 +215,11 @@ public class ParentFirstTestCase extends TestCase {
|
|||||||
resource = childLoader.getResource("nosuchfile");
|
resource = childLoader.getResource("nosuchfile");
|
||||||
assertNull("Non-null URL returned for invalid resource name", resource);
|
assertNull("Non-null URL returned for invalid resource name", resource);
|
||||||
|
|
||||||
// getResource where it is accessible only to parent classloader
|
// getResource where it is accessible only to parent class loader
|
||||||
resource = childLoader.getResource("org/apache/commons/logging/Log.class");
|
resource = childLoader.getResource("org/apache/commons/logging/Log.class");
|
||||||
assertNotNull("Unable to locate Log.class resource", resource);
|
assertNotNull("Unable to locate Log.class resource", resource);
|
||||||
|
|
||||||
// getResource where it is accessible only to child classloader
|
// getResource where it is accessible only to child class loader
|
||||||
resource = childLoader.getResource("org/apache/commons/logging/PathableTestSuite.class");
|
resource = childLoader.getResource("org/apache/commons/logging/PathableTestSuite.class");
|
||||||
assertNotNull("Unable to locate PathableTestSuite.class resource", resource);
|
assertNotNull("Unable to locate PathableTestSuite.class resource", resource);
|
||||||
|
|
||||||
@@ -239,12 +239,12 @@ public class ParentFirstTestCase extends TestCase {
|
|||||||
public void testResourceAsStream() throws Exception {
|
public void testResourceAsStream() throws Exception {
|
||||||
java.io.InputStream is;
|
java.io.InputStream is;
|
||||||
|
|
||||||
// verify the classloader hierarchy
|
// verify the class loader hierarchy
|
||||||
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
final ClassLoader childLoader = contextLoader.getParent();
|
final ClassLoader childLoader = contextLoader.getParent();
|
||||||
final ClassLoader parentLoader = childLoader.getParent();
|
final ClassLoader parentLoader = childLoader.getParent();
|
||||||
final ClassLoader bootLoader = parentLoader.getParent();
|
final ClassLoader bootLoader = parentLoader.getParent();
|
||||||
assertNull("Unexpected classloader hierarchy", bootLoader);
|
assertNull("Unexpected class loader hierarchy", bootLoader);
|
||||||
|
|
||||||
// getResourceAsStream where no instances exist
|
// getResourceAsStream where no instances exist
|
||||||
is = childLoader.getResourceAsStream("nosuchfile");
|
is = childLoader.getResourceAsStream("nosuchfile");
|
||||||
@@ -268,12 +268,12 @@ public class ParentFirstTestCase extends TestCase {
|
|||||||
Enumeration resources;
|
Enumeration resources;
|
||||||
URL[] urls;
|
URL[] urls;
|
||||||
|
|
||||||
// verify the classloader hierarchy
|
// verify the class loader hierarchy
|
||||||
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader contextLoader = Thread.currentThread().getContextClassLoader();
|
||||||
final ClassLoader childLoader = contextLoader.getParent();
|
final ClassLoader childLoader = contextLoader.getParent();
|
||||||
final ClassLoader parentLoader = childLoader.getParent();
|
final ClassLoader parentLoader = childLoader.getParent();
|
||||||
final ClassLoader bootLoader = parentLoader.getParent();
|
final ClassLoader bootLoader = parentLoader.getParent();
|
||||||
assertNull("Unexpected classloader hierarchy", bootLoader);
|
assertNull("Unexpected class loader hierarchy", bootLoader);
|
||||||
|
|
||||||
// getResources where no instances exist
|
// getResources where no instances exist
|
||||||
resources = childLoader.getResources("nosuchfile");
|
resources = childLoader.getResources("nosuchfile");
|
||||||
|
|||||||
@@ -37,9 +37,9 @@ import junit.framework.TestCase;
|
|||||||
* <p>
|
* <p>
|
||||||
* This class has only one unit test, as we are (in part) checking behavior in
|
* This class has only one unit test, as we are (in part) checking behavior in
|
||||||
* the static block of the LogFactory class. As that class cannot be unloaded after
|
* the static block of the LogFactory class. As that class cannot be unloaded after
|
||||||
* being loaded into a classloader, the only workaround is to use the
|
* being loaded into a class loader, the only workaround is to use the
|
||||||
* PathableClassLoader approach to ensure each test is run in its own
|
* PathableClassLoader approach to ensure each test is run in its own
|
||||||
* classloader, and use a separate test class for each test.
|
* class loader, and use a separate test class for each test.
|
||||||
*/
|
*/
|
||||||
public class SecurityAllowedTestCase extends TestCase {
|
public class SecurityAllowedTestCase extends TestCase {
|
||||||
|
|
||||||
|
|||||||
@@ -42,9 +42,9 @@ import junit.framework.TestCase;
|
|||||||
* <p>
|
* <p>
|
||||||
* This class has only one unit test, as we are (in part) checking behavior in
|
* This class has only one unit test, as we are (in part) checking behavior in
|
||||||
* the static block of the LogFactory class. As that class cannot be unloaded after
|
* the static block of the LogFactory class. As that class cannot be unloaded after
|
||||||
* being loaded into a classloader, the only workaround is to use the
|
* being loaded into a class loader, the only workaround is to use the
|
||||||
* PathableClassLoader approach to ensure each test is run in its own
|
* PathableClassLoader approach to ensure each test is run in its own
|
||||||
* classloader, and use a separate test class for each test.
|
* class loader, and use a separate test class for each test.
|
||||||
*/
|
*/
|
||||||
public class SecurityForbiddenTestCase extends TestCase {
|
public class SecurityForbiddenTestCase extends TestCase {
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ public class SecurityForbiddenTestCase extends TestCase {
|
|||||||
private ClassLoader otherClassLoader;
|
private ClassLoader otherClassLoader;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Loads a class with the given classloader.
|
* Loads a class with the given class loader.
|
||||||
*/
|
*/
|
||||||
private Object loadClass(final String name, final ClassLoader classLoader) {
|
private Object loadClass(final String name, final ClassLoader classLoader) {
|
||||||
try {
|
try {
|
||||||
@@ -167,8 +167,8 @@ public class SecurityForbiddenTestCase extends TestCase {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Test what happens when JCL is run with absolutely no security
|
* Test what happens when JCL is run with absolutely no security
|
||||||
* privileges at all and a class loaded with a different classloader
|
* privileges at all and a class loaded with a different class loader
|
||||||
* than the context classloader of the current thread tries to log something.
|
* than the context class loader of the current thread tries to log something.
|
||||||
*/
|
*/
|
||||||
public void testContextClassLoader() {
|
public void testContextClassLoader() {
|
||||||
// Ignore on Java 21
|
// Ignore on Java 21
|
||||||
@@ -183,7 +183,7 @@ public class SecurityForbiddenTestCase extends TestCase {
|
|||||||
System.setSecurityManager(mySecurityManager);
|
System.setSecurityManager(mySecurityManager);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// load a dummy class with another classloader
|
// load a dummy class with another class loader
|
||||||
// to force a SecurityException when the LogFactory calls
|
// to force a SecurityException when the LogFactory calls
|
||||||
// Thread.getCurrentThread().getContextClassLoader()
|
// Thread.getCurrentThread().getContextClassLoader()
|
||||||
loadClass("org.apache.commons.logging.security.DummyClass", otherClassLoader);
|
loadClass("org.apache.commons.logging.security.DummyClass", otherClassLoader);
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
package org.apache.commons.logging.serviceloader.internal;
|
package org.apache.commons.logging.serviceloader.internal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A common ServiceLoader error is finding a class that implements LogFactory from a different classloader.
|
* A common ServiceLoader error is finding a class that implements LogFactory from a different class loader.
|
||||||
* This class should emulate that behavior.
|
* This class should emulate that behavior.
|
||||||
*/
|
*/
|
||||||
public class ThrowingLogFactory {
|
public class ThrowingLogFactory {
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ public class BasicServletTestCase extends TestCase {
|
|||||||
//
|
//
|
||||||
// Having the test loaded via a loader above the tccl emulates the situation
|
// Having the test loaded via a loader above the tccl emulates the situation
|
||||||
// where a web.xml file specifies ServletContextCleaner as a listener, and
|
// where a web.xml file specifies ServletContextCleaner as a listener, and
|
||||||
// that class is deployed via a shared classloader.
|
// that class is deployed via a shared class loader.
|
||||||
|
|
||||||
final PathableClassLoader parent = new PathableClassLoader(null);
|
final PathableClassLoader parent = new PathableClassLoader(null);
|
||||||
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
|
parent.useExplicitLoader("junit.", Test.class.getClassLoader());
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ import junit.framework.TestCase;
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that by default LogFactoryImpl is loaded from the tccl classloader.
|
* Verify that by default LogFactoryImpl is loaded from the tccl class loader.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class TcclDisabledTestCase extends TestCase {
|
public class TcclDisabledTestCase extends TestCase {
|
||||||
@@ -61,10 +61,10 @@ public class TcclDisabledTestCase extends TestCase {
|
|||||||
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
||||||
final URL baseUrl = dummy.findResource(thisClassPath);
|
final URL baseUrl = dummy.findResource(thisClassPath);
|
||||||
|
|
||||||
// Now set up the desired classloader hierarchy. Everything goes into
|
// Now set up the desired class loader hierarchy. Everything goes into
|
||||||
// the parent classpath, but we exclude the custom Log class.
|
// the parent classpath, but we exclude the custom Log class.
|
||||||
//
|
//
|
||||||
// We then create a tccl classloader that can see the custom
|
// We then create a tccl class loader that can see the custom
|
||||||
// Log class. Therefore if that class can be found, then the
|
// Log class. Therefore if that class can be found, then the
|
||||||
// TCCL must have been used to load it.
|
// TCCL must have been used to load it.
|
||||||
final PathableClassLoader emptyLoader = new PathableClassLoader(null);
|
final PathableClassLoader emptyLoader = new PathableClassLoader(null);
|
||||||
@@ -73,7 +73,7 @@ public class TcclDisabledTestCase extends TestCase {
|
|||||||
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
|
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
|
||||||
parentLoader.addLogicalLib("commons-logging");
|
parentLoader.addLogicalLib("commons-logging");
|
||||||
parentLoader.addLogicalLib("testclasses");
|
parentLoader.addLogicalLib("testclasses");
|
||||||
// hack to ensure that the test classloader can't see
|
// hack to ensure that the test class loader can't see
|
||||||
// the custom MyLog
|
// the custom MyLog
|
||||||
parentLoader.useExplicitLoader(MY_LOG_PKG + ".", emptyLoader);
|
parentLoader.useExplicitLoader(MY_LOG_PKG + ".", emptyLoader);
|
||||||
|
|
||||||
@@ -113,12 +113,12 @@ public class TcclDisabledTestCase extends TestCase {
|
|||||||
final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
// the tccl loader should NOT be the same as the loader that loaded this test class.
|
// the tccl loader should NOT be the same as the loader that loaded this test class.
|
||||||
assertNotSame("tccl not same as test classloader", thisClassLoader, tcclLoader);
|
assertNotSame("tccl not same as test class loader", thisClassLoader, tcclLoader);
|
||||||
|
|
||||||
// MyLog should not be loadable via parent loader
|
// MyLog should not be loadable via parent loader
|
||||||
try {
|
try {
|
||||||
final Class clazz = thisClassLoader.loadClass(MY_LOG_IMPL);
|
final Class clazz = thisClassLoader.loadClass(MY_LOG_IMPL);
|
||||||
fail("Unexpectedly able to load MyLog via test class classloader");
|
fail("Unexpectedly able to load MyLog via test class class loader");
|
||||||
assertNotNull(clazz); // silence warnings about unused var
|
assertNotNull(clazz); // silence warnings about unused var
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
// ok, expected
|
// ok, expected
|
||||||
@@ -129,7 +129,7 @@ public class TcclDisabledTestCase extends TestCase {
|
|||||||
final Class clazz = tcclLoader.loadClass(MY_LOG_IMPL);
|
final Class clazz = tcclLoader.loadClass(MY_LOG_IMPL);
|
||||||
assertNotNull(clazz);
|
assertNotNull(clazz);
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
fail("Unexpectedly unable to load MyLog via tccl classloader");
|
fail("Unexpectedly unable to load MyLog via tccl class loader");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -61,10 +61,10 @@ public class TcclEnabledTestCase extends TestCase {
|
|||||||
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
||||||
final URL baseUrl = dummy.findResource(thisClassPath);
|
final URL baseUrl = dummy.findResource(thisClassPath);
|
||||||
|
|
||||||
// Now set up the desired classloader hierarchy. Everything goes into
|
// Now set up the desired class loader hierarchy. Everything goes into
|
||||||
// the parent classpath, but we exclude the custom Log class.
|
// the parent classpath, but we exclude the custom Log class.
|
||||||
//
|
//
|
||||||
// We then create a tccl classloader that can see the custom
|
// We then create a tccl class loader that can see the custom
|
||||||
// Log class. Therefore if that class can be found, then the
|
// Log class. Therefore if that class can be found, then the
|
||||||
// TCCL must have been used to load it.
|
// TCCL must have been used to load it.
|
||||||
final PathableClassLoader emptyLoader = new PathableClassLoader(null);
|
final PathableClassLoader emptyLoader = new PathableClassLoader(null);
|
||||||
@@ -73,7 +73,7 @@ public class TcclEnabledTestCase extends TestCase {
|
|||||||
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
|
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
|
||||||
parentLoader.addLogicalLib("commons-logging");
|
parentLoader.addLogicalLib("commons-logging");
|
||||||
parentLoader.addLogicalLib("testclasses");
|
parentLoader.addLogicalLib("testclasses");
|
||||||
// hack to ensure that the test classloader can't see
|
// hack to ensure that the test class loader can't see
|
||||||
// the custom MyLogFactoryImpl
|
// the custom MyLogFactoryImpl
|
||||||
parentLoader.useExplicitLoader(MY_LOG_PKG + ".", emptyLoader);
|
parentLoader.useExplicitLoader(MY_LOG_PKG + ".", emptyLoader);
|
||||||
|
|
||||||
@@ -113,12 +113,12 @@ public class TcclEnabledTestCase extends TestCase {
|
|||||||
final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
// the tccl loader should NOT be the same as the loader that loaded this test class.
|
// the tccl loader should NOT be the same as the loader that loaded this test class.
|
||||||
assertNotSame("tccl not same as test classloader", thisClassLoader, tcclLoader);
|
assertNotSame("tccl not same as test class loader", thisClassLoader, tcclLoader);
|
||||||
|
|
||||||
// MyLog should not be loadable via parent loader
|
// MyLog should not be loadable via parent loader
|
||||||
try {
|
try {
|
||||||
final Class clazz = thisClassLoader.loadClass(MY_LOG_IMPL);
|
final Class clazz = thisClassLoader.loadClass(MY_LOG_IMPL);
|
||||||
fail("Unexpectedly able to load MyLog via test class classloader");
|
fail("Unexpectedly able to load MyLog via test class class loader");
|
||||||
assertNotNull(clazz); // silence warnings about unused var
|
assertNotNull(clazz); // silence warnings about unused var
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
// ok, expected
|
// ok, expected
|
||||||
@@ -129,7 +129,7 @@ public class TcclEnabledTestCase extends TestCase {
|
|||||||
final Class clazz = tcclLoader.loadClass(MY_LOG_IMPL);
|
final Class clazz = tcclLoader.loadClass(MY_LOG_IMPL);
|
||||||
assertNotNull(clazz);
|
assertNotNull(clazz);
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
fail("Unexpectedly unable to load MyLog via tccl classloader");
|
fail("Unexpectedly unable to load MyLog via tccl class loader");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import junit.framework.TestCase;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that a commons-logging.properties file can prevent a custom
|
* Verify that a commons-logging.properties file can prevent a custom
|
||||||
* LogFactoryImpl being loaded from the tccl classloader.
|
* LogFactoryImpl being loaded from the tccl class loader.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class TcclDisabledTestCase extends TestCase {
|
public class TcclDisabledTestCase extends TestCase {
|
||||||
@@ -61,11 +61,11 @@ public class TcclDisabledTestCase extends TestCase {
|
|||||||
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
||||||
final URL baseUrl = dummy.findResource(thisClassPath);
|
final URL baseUrl = dummy.findResource(thisClassPath);
|
||||||
|
|
||||||
// Now set up the desired classloader hierarchy. Everything goes into
|
// Now set up the desired class loader hierarchy. Everything goes into
|
||||||
// the parent classpath, but we exclude the custom LogFactoryImpl
|
// the parent classpath, but we exclude the custom LogFactoryImpl
|
||||||
// class.
|
// class.
|
||||||
//
|
//
|
||||||
// We then create a tccl classloader that can see the custom
|
// We then create a tccl class loader that can see the custom
|
||||||
// LogFactory class. Therefore if that class can be found, then the
|
// LogFactory class. Therefore if that class can be found, then the
|
||||||
// TCCL must have been used to load it.
|
// TCCL must have been used to load it.
|
||||||
final PathableClassLoader emptyLoader = new PathableClassLoader(null);
|
final PathableClassLoader emptyLoader = new PathableClassLoader(null);
|
||||||
@@ -74,7 +74,7 @@ public class TcclDisabledTestCase extends TestCase {
|
|||||||
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
|
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
|
||||||
parentLoader.addLogicalLib("commons-logging");
|
parentLoader.addLogicalLib("commons-logging");
|
||||||
parentLoader.addLogicalLib("testclasses");
|
parentLoader.addLogicalLib("testclasses");
|
||||||
// hack to ensure that the test classloader can't see
|
// hack to ensure that the test class loader can't see
|
||||||
// the custom MyLogFactoryImpl
|
// the custom MyLogFactoryImpl
|
||||||
parentLoader.useExplicitLoader(
|
parentLoader.useExplicitLoader(
|
||||||
MY_LOG_FACTORY_PKG + ".", emptyLoader);
|
MY_LOG_FACTORY_PKG + ".", emptyLoader);
|
||||||
@@ -115,12 +115,12 @@ public class TcclDisabledTestCase extends TestCase {
|
|||||||
final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
// the tccl loader should NOT be the same as the loader that loaded this test class.
|
// the tccl loader should NOT be the same as the loader that loaded this test class.
|
||||||
assertNotSame("tccl not same as test classloader", thisClassLoader, tcclLoader);
|
assertNotSame("tccl not same as test class loader", thisClassLoader, tcclLoader);
|
||||||
|
|
||||||
// MyLogFactoryImpl should not be loadable via parent loader
|
// MyLogFactoryImpl should not be loadable via parent loader
|
||||||
try {
|
try {
|
||||||
final Class clazz = thisClassLoader.loadClass(MY_LOG_FACTORY_IMPL);
|
final Class clazz = thisClassLoader.loadClass(MY_LOG_FACTORY_IMPL);
|
||||||
fail("Unexpectedly able to load MyLogFactoryImpl via test class classloader");
|
fail("Unexpectedly able to load MyLogFactoryImpl via test class class loader");
|
||||||
assertNotNull(clazz); // silence warning about unused var
|
assertNotNull(clazz); // silence warning about unused var
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
// ok, expected
|
// ok, expected
|
||||||
@@ -131,7 +131,7 @@ public class TcclDisabledTestCase extends TestCase {
|
|||||||
final Class clazz = tcclLoader.loadClass(MY_LOG_FACTORY_IMPL);
|
final Class clazz = tcclLoader.loadClass(MY_LOG_FACTORY_IMPL);
|
||||||
assertNotNull(clazz);
|
assertNotNull(clazz);
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
fail("Unexpectedly unable to load MyLogFactoryImpl via tccl classloader");
|
fail("Unexpectedly unable to load MyLogFactoryImpl via tccl class loader");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import junit.framework.TestCase;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify that by default a custom LogFactoryImpl is loaded from the
|
* Verify that by default a custom LogFactoryImpl is loaded from the
|
||||||
* tccl classloader.
|
* tccl class loader.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
public class TcclEnabledTestCase extends TestCase {
|
public class TcclEnabledTestCase extends TestCase {
|
||||||
@@ -55,11 +55,11 @@ public class TcclEnabledTestCase extends TestCase {
|
|||||||
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
final String thisClassPath = thisClass.getName().replace('.', '/') + ".class";
|
||||||
final URL baseUrl = dummy.findResource(thisClassPath);
|
final URL baseUrl = dummy.findResource(thisClassPath);
|
||||||
|
|
||||||
// Now set up the desired classloader hierarchy. Everything goes into
|
// Now set up the desired class loader hierarchy. Everything goes into
|
||||||
// the parent classpath, but we exclude the custom LogFactoryImpl
|
// the parent classpath, but we exclude the custom LogFactoryImpl
|
||||||
// class.
|
// class.
|
||||||
//
|
//
|
||||||
// We then create a tccl classloader that can see the custom
|
// We then create a tccl class loader that can see the custom
|
||||||
// LogFactory class. Therefore if that class can be found, then the
|
// LogFactory class. Therefore if that class can be found, then the
|
||||||
// TCCL must have been used to load it.
|
// TCCL must have been used to load it.
|
||||||
final PathableClassLoader emptyLoader = new PathableClassLoader(null);
|
final PathableClassLoader emptyLoader = new PathableClassLoader(null);
|
||||||
@@ -68,7 +68,7 @@ public class TcclEnabledTestCase extends TestCase {
|
|||||||
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
|
parentLoader.useExplicitLoader("junit.", Test.class.getClassLoader());
|
||||||
parentLoader.addLogicalLib("commons-logging");
|
parentLoader.addLogicalLib("commons-logging");
|
||||||
parentLoader.addLogicalLib("testclasses");
|
parentLoader.addLogicalLib("testclasses");
|
||||||
// hack to ensure that the test classloader can't see
|
// hack to ensure that the test class loader can't see
|
||||||
// the cust MyLogFactoryImpl
|
// the cust MyLogFactoryImpl
|
||||||
parentLoader.useExplicitLoader(
|
parentLoader.useExplicitLoader(
|
||||||
"org.apache.commons.logging.tccl.custom.", emptyLoader);
|
"org.apache.commons.logging.tccl.custom.", emptyLoader);
|
||||||
@@ -109,13 +109,13 @@ public class TcclEnabledTestCase extends TestCase {
|
|||||||
final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
|
final ClassLoader tcclLoader = Thread.currentThread().getContextClassLoader();
|
||||||
|
|
||||||
// the tccl loader should NOT be the same as the loader that loaded this test class.
|
// the tccl loader should NOT be the same as the loader that loaded this test class.
|
||||||
assertNotSame("tccl not same as test classloader", thisClassLoader, tcclLoader);
|
assertNotSame("tccl not same as test class loader", thisClassLoader, tcclLoader);
|
||||||
|
|
||||||
// MyLogFactoryImpl should not be loadable via parent loader
|
// MyLogFactoryImpl should not be loadable via parent loader
|
||||||
try {
|
try {
|
||||||
final Class clazz = thisClassLoader.loadClass(
|
final Class clazz = thisClassLoader.loadClass(
|
||||||
"org.apache.commons.logging.tccl.custom.MyLogFactoryImpl");
|
"org.apache.commons.logging.tccl.custom.MyLogFactoryImpl");
|
||||||
fail("Unexpectedly able to load MyLogFactoryImpl via test class classloader");
|
fail("Unexpectedly able to load MyLogFactoryImpl via test class class loader");
|
||||||
assertNotNull(clazz); // silence warning about unused var
|
assertNotNull(clazz); // silence warning about unused var
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
// ok, expected
|
// ok, expected
|
||||||
@@ -127,7 +127,7 @@ public class TcclEnabledTestCase extends TestCase {
|
|||||||
"org.apache.commons.logging.tccl.custom.MyLogFactoryImpl");
|
"org.apache.commons.logging.tccl.custom.MyLogFactoryImpl");
|
||||||
assertNotNull(clazz);
|
assertNotNull(clazz);
|
||||||
} catch (final ClassNotFoundException ex) {
|
} catch (final ClassNotFoundException ex) {
|
||||||
fail("Unexpectedly unable to load MyLogFactoryImpl via tccl classloader");
|
fail("Unexpectedly unable to load MyLogFactoryImpl via tccl class loader");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user