in src/main/java/org/apache/commons/logging/LogFactory.java [1011:1162]
protected static Object createFactory(final String factoryClass, final ClassLoader classLoader) {
// This will be used to diagnose bad configurations
// and allow a useful message to be sent to the user
Class logFactoryClass = null;
try {
if (classLoader != null) {
try {
// First the given class loader param (thread class loader)
// Warning: must typecast here & allow exception
// to be generated/caught & recast properly.
logFactoryClass = classLoader.loadClass(factoryClass);
if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
if (isDiagnosticsEnabled()) {
logDiagnostic("Loaded class " + logFactoryClass.getName() +
" from classloader " + objectId(classLoader));
}
} else {
//
// This indicates a problem with the ClassLoader tree.
// An incompatible ClassLoader was used to load the
// implementation.
// As the same classes
// must be available in multiple class loaders,
// it is very likely that multiple JCL jars are present.
// The most likely fix for this
// problem is to remove the extra JCL jars from the
// ClassLoader hierarchy.
//
if (isDiagnosticsEnabled()) {
logDiagnostic("Factory class " + logFactoryClass.getName() +
" loaded from classloader " + objectId(logFactoryClass.getClassLoader()) +
" does not extend '" + LogFactory.class.getName() +
"' as loaded by this classloader.");
logHierarchy("[BAD CL TREE] ", classLoader);
}
}
return (LogFactory) logFactoryClass.newInstance();
} catch (final ClassNotFoundException ex) {
if (classLoader == thisClassLoaderRef.get()) {
// Nothing more to try, onwards.
if (isDiagnosticsEnabled()) {
logDiagnostic("Unable to locate any class called '" + factoryClass +
"' via classloader " + objectId(classLoader));
}
throw ex;
}
// ignore exception, continue
} catch (final NoClassDefFoundError e) {
if (classLoader == thisClassLoaderRef.get()) {
// Nothing more to try, onwards.
if (isDiagnosticsEnabled()) {
logDiagnostic("Class '" + factoryClass + "' cannot be loaded" +
" via classloader " + objectId(classLoader) +
" - it depends on some other class that cannot be found.");
}
throw e;
}
// ignore exception, continue
} catch (final ClassCastException e) {
if (classLoader == thisClassLoaderRef.get()) {
// There's no point in falling through to the code below that
// tries again with thisClassLoaderRef, because we've just tried
// loading with that loader (not the TCCL). Just throw an
// appropriate exception here.
final boolean implementsLogFactory = implementsLogFactory(logFactoryClass);
//
// Construct a good message: users may not actual expect that a custom implementation
// has been specified. Several well known containers use this mechanism to adapt JCL
// to their native logging system.
//
final StringBuilder msg = new StringBuilder();
msg.append("The application has specified that a custom LogFactory implementation ");
msg.append("should be used but Class '");
msg.append(factoryClass);
msg.append("' cannot be converted to '");
msg.append(LogFactory.class.getName());
msg.append("'. ");
if (implementsLogFactory) {
msg.append("The conflict is caused by the presence of multiple LogFactory classes ");
msg.append("in incompatible classloaders. ");
msg.append("Background can be found in http://commons.apache.org/logging/tech.html. ");
msg.append("If you have not explicitly specified a custom LogFactory then it is likely ");
msg.append("that the container has set one without your knowledge. ");
msg.append("In this case, consider using the commons-logging-adapters.jar file or ");
msg.append("specifying the standard LogFactory from the command line. ");
} else {
msg.append("Please check the custom implementation. ");
}
msg.append("Help can be found @http://commons.apache.org/logging/troubleshooting.html.");
if (isDiagnosticsEnabled()) {
logDiagnostic(msg.toString());
}
throw new ClassCastException(msg.toString());
}
// Ignore exception, continue. Presumably the classloader was the
// TCCL; the code below will try to load the class via thisClassLoaderRef.
// This will handle the case where the original calling class is in
// a shared classpath but the TCCL has a copy of LogFactory and the
// specified LogFactory implementation; we will fall back to using the
// LogFactory implementation from the same classloader as this class.
//
// Issue: this doesn't handle the reverse case, where this LogFactory
// is in the webapp, and the specified LogFactory implementation is
// in a shared classpath. In that case:
// (a) the class really does implement LogFactory (bad log msg above)
// (b) the fallback code will result in exactly the same problem.
}
}
/* 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), ie we ignore
* the classloader parameter the caller passed, and fall back
* to trying the classloader associated with this class. See the
* javadoc for the newFactory method for more info on the
* consequences of this.
*
* Notes:
* * LogFactory.class.getClassLoader() may return 'null'
* if LogFactory is loaded by the bootstrap classloader.
*/
// Warning: must typecast here & allow exception
// to be generated/caught & recast properly.
if (isDiagnosticsEnabled()) {
logDiagnostic("Unable to load factory class via classloader " + objectId(classLoader) +
" - trying the classloader associated with this LogFactory.");
}
logFactoryClass = Class.forName(factoryClass);
return (LogFactory) logFactoryClass.newInstance();
} catch (final Exception e) {
// Check to see if we've got a bad configuration
if (isDiagnosticsEnabled()) {
logDiagnostic("Unable to create LogFactory instance.");
}
if (logFactoryClass != null && !LogFactory.class.isAssignableFrom(logFactoryClass)) {
return new LogConfigurationException(
"The chosen LogFactory implementation does not extend LogFactory." +
" Please check your configuration.", e);
}
return new LogConfigurationException(e);
}
}