in src/main/java/org/apache/commons/logging/LogFactory.java [291:418]
protected static Object createFactory(final String factoryClassName, 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(factoryClassName);
if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
if (isDiagnosticsEnabled()) {
logDiagnostic("Loaded class " + logFactoryClass.getName() + " from class loader " + 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 class loader " + objectId(logFactoryClass.getClassLoader())
+ " does not extend '" + LogFactory.class.getName() + "' as loaded by this class loader.");
logHierarchy("[BAD CL TREE] ", classLoader);
}
// Force a ClassCastException
return LogFactory.class.cast(logFactoryClass.getConstructor().newInstance());
} catch (final ClassNotFoundException ex) {
if (classLoader == thisClassLoaderRef.get()) {
// Nothing more to try, onwards.
if (isDiagnosticsEnabled()) {
logDiagnostic("Unable to locate any class called '" + factoryClassName + "' via class loader " + objectId(classLoader));
}
throw ex;
}
// ignore exception, continue
} catch (final NoClassDefFoundError e) {
if (classLoader == thisClassLoaderRef.get()) {
// Nothing more to try, onwards.
if (isDiagnosticsEnabled()) {
logDiagnostic("Class '" + factoryClassName + "' cannot be loaded" + " via class loader " + 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 should be used but Class '");
msg.append(factoryClassName);
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 in incompatible class loaders. Background can");
msg.append(" be found in https://commons.apache.org/logging/tech.html. If you have not explicitly specified a custom LogFactory");
msg.append(" then it is likely that the container has set one without your knowledge. In this case, consider using the ");
msg.append("commons-logging-adapters.jar file or specifying the standard LogFactory from the command line. ");
} else {
msg.append("Please check the custom implementation. ");
}
msg.append("Help can be found at https://commons.apache.org/logging/troubleshooting.html.");
logDiagnostic(msg.toString());
throw new ClassCastException(msg.toString());
}
// Ignore exception, continue. Presumably the class loader was the
// TCCL; the code below will try to load the class via thisClassLoaderRef.
// This will handle the case where the original calling class is in
// a shared classpath but the TCCL has a copy of LogFactory and the
// specified LogFactory implementation; we will fall back to using the
// LogFactory implementation from the same class loader as this class.
//
// Issue: this doesn't handle the reverse case, where this LogFactory
// is in the webapp, and the specified LogFactory implementation is
// 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), that is, we ignore the class loader
* parameter the caller passed, and fall back to trying the class loader associated with this class. See the Javadoc for the newFactory method for
* more info on the consequences of this.
*
* Notes: * LogFactory.class.getClassLoader() may return 'null' if LogFactory is loaded by the bootstrap class loader.
*/
// Warning: must typecast here & allow exception
// to be generated/caught & recast properly.
if (isDiagnosticsEnabled()) {
logDiagnostic(
"Unable to load factory class via class loader " + objectId(classLoader) + " - trying the class loader associated with this LogFactory.");
}
logFactoryClass = Class.forName(factoryClassName);
// Force a ClassCastException
return LogFactory.class.cast(logFactoryClass.getConstructor().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);
}
}