Author: rdonkin Date: Tue Mar 7 13:54:57 2006 New Revision: 384025 URL: http://svn.apache.org/viewcvs?rev=384025&view=rev Log: Improved diagnostics and added more information to the message thrown when a custom LogFactory cannot be loaded due to classloader incompatibilities.
Modified: jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/LogFactory.java Modified: jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/LogFactory.java URL: http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/LogFactory.java?rev=384025&r1=384024&r2=384025&view=diff ============================================================================== --- jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/LogFactory.java (original) +++ jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/LogFactory.java Tue Mar 7 13:54:57 2006 @@ -1101,13 +1101,29 @@ // 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. + // String msg = + "The application has specified that a custom LogFactory implementation should be used but " + "Class '" + factoryClass + "' cannot be converted to '" - + LogFactory.class.getName() + "'." - + " Perhaps you have multiple copies of LogFactory in" - + " the classpath? If so, consider using the" - + " commons-logging-adapters.jar file."; - + + LogFactory.class.getName() + "'. "; + if (implementsLogFactory) { + msg = msg + "The conflict is caused by the presence of multiple LogFactory classes in incompatible classloaders. " + + "Background can be found in http://jakarta.apache.org/commons/logging/tech.html. " + + "If you have not explicitly specified a custom LogFactory then it is likely that " + + "the container has set one without your knowledge. " + + "In this case, consider using the commons-logging-adapters.jar file or " + + "specifying the standard LogFactory from the command line. "; + } else { + msg = msg + "Please check the custom implementation. "; + } + msg = msg + "Help can be found @http://jakarta.apache.org/commons/logging/troubleshooting.html."; + if (isDiagnosticsEnabled()) { logDiagnostic(msg); } @@ -1171,6 +1187,70 @@ return new LogConfigurationException(e); } } + + /** + * Determines whether the given class actually implements <code>LogFactory</code>. + * Diagnostic information is also logged. + * <p> + * <strong>Usage:</strong> to diagnose whether a classloader conflict is the cause + * of incompatibility. The test used is whether the class is assignable from + * the <code>LogFactory</code> class loaded by the class's classloader. + * @param logFactoryClass <code>Class</code> which may implement <code>LogFactory</code> + * @return true if the <code>Class</code> is assignable from the + */ + private static boolean implementsLogFactory(Class logFactoryClass) { + boolean implementsLogFactory = false; + if (logFactoryClass != null) { + try { + ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader(); + if (logFactoryClassLoader == null) { + logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot classloader"); + } else { + logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader); + Class factoryFromCustomLoader + = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader); + implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass); + if (implementsLogFactory) { + logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName() + + " implements LogFactory but was loaded by an incompatible classloader."); + } else { + logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName() + + " does not implement LogFactory."); + } + } + } catch (SecurityException e) { + // + // The application is running within a hostile security environment. + // This will make it very hard to diagnose issues with JCL. + // Consider running less securely whilst debugging this issue. + // + logDiagnostic("[CUSTOM LOG FACTORY] SecurityException thrown whilst trying to determine whether " + + "the compatibility was caused by a classloader conflict: " + + e.getMessage()); + } catch (LinkageError e) { + // + // This should be an unusual circumstance. + // LinkageError's usually indicate that a dependent class has incompatibly changed. + // Another possibility may be an exception thrown by an initializer. + // Time for a clean rebuild? + // + logDiagnostic("[CUSTOM LOG FACTORY] LinkageError thrown whilst trying to determine whether " + + "the compatibility was caused by a classloader conflict: " + + e.getMessage()); + } catch (ClassNotFoundException e) { + // + // LogFactory cannot be loaded by the classloader which loaded the custom factory implementation. + // The custom implementation is not viable until this is corrected. + // Ensure that the JCL jar and the custom class are available from the same classloader. + // Running with diagnostics on should give information about the classloaders used + // to load the custom factory. + // + logDiagnostic("[CUSTOM LOG FACTORY] LogFactory class cannot be loaded by classloader which loaded the " + + "custom LogFactory implementation. Is the custom factory in the right classloader?"); + } + } + return implementsLogFactory; + } /** * Applets may run in an environment where accessing resources of a loader is --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]