Diff of /jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java
Parent Directory
| Revision Log
| Patch
--- jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java 2005/06/02 03:48:26 179499
+++ jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java 2005/06/02 04:09:16 179500
@@ -57,12 +57,12 @@ import org.apache.commons.logging.LogFac
*
* <p>This factory will remember previously created <code>Log</code> instances
* for the same name, and will return them on repeated requests to the
- * <code>getInstance()</code> method. This implementation ignores any
- * configured attributes.</p>
+ * <code>getInstance()</code> method.
*
* @author Rod Waldhoff
* @author Craig R. McClanahan
* @author Richard A. Sitze
+ * @author Brian Stansberry
* @version $Revision$ $Date$
*/
@@ -115,6 +115,7 @@ public class LogFactoryImpl extends LogF
*/
private String diagnosticPrefix;
+
/**
* Configuration attributes.
*/
@@ -164,9 +165,9 @@ public class LogFactoryImpl extends LogF
protected Class logMethodSignature[] =
{ LogFactory.class };
-
// --------------------------------------------------------- Public Methods
+
/**
* Return the configuration attribute with the specified name (if any),
* or <code>null</code> if there is no such attribute.
@@ -309,14 +310,16 @@ public class LogFactoryImpl extends LogF
return LogFactory.getContextClassLoader();
}
+
/**
* Workaround for bug in Java1.2; in theory this method is not needed.
- * See LogFactory.isInternalLoggingEnabled.
+ * See LogFactory.isDiagnosticsEnabled.
*/
protected static boolean isDiagnosticsEnabled() {
return LogFactory.isDiagnosticsEnabled();
}
+
/**
* Workaround for bug in Java1.2; in theory this method is not needed.
* See LogFactory.getClassLoader.
@@ -325,6 +328,7 @@ public class LogFactoryImpl extends LogF
return LogFactory.getClassLoader(clazz);
}
+
// ------------------------------------------------------ Protected Methods
/**
@@ -352,6 +356,7 @@ public class LogFactoryImpl extends LogF
diagnosticPrefix = clazz.getName() + "@" + classLoader.toString() + ":";
}
+
/**
* Output a diagnostic message to a user-specified destination (if the
* user has enabled diagnostic logging).
@@ -366,75 +371,18 @@ public class LogFactoryImpl extends LogF
/**
* Return the fully qualified Java classname of the {@link Log}
- * implementation we will be using.
- * <p>
- * This method looks in the following places:
- * <ul>
- * <li>Looks for an attribute LOG_PROPERTY or LOG_PROPERTY_OLD in the
- * "attributes" associated with this class, as set earlier by method
- * setAttribute.
- * <li>Looks for a property LOG_PROPERTY or LOG_PROPERTY_OLD in the
- * system properties.
- * <li>Looks for log4j, jdk logging and jdk13lumberjack classes in
- * the classpath.
- * </ul>
+ * implementation we will be using.
+ *
+ * @deprecated Never invoked by this class; subclasses should not assume
+ * it will be.
*/
protected String getLogClassName() {
- // Return the previously identified class name (if any)
- if (logClassName != null) {
- return logClassName;
- }
-
- logDiagnostic("Determining the name for the Log implementation.");
-
- logDiagnostic("Trying to get log class from attribute " + LOG_PROPERTY);
- logClassName = (String) getAttribute(LOG_PROPERTY);
-
- if (logClassName == null) { // @deprecated
- logDiagnostic("Trying to get log class from attribute " + LOG_PROPERTY_OLD);
- logClassName = (String) getAttribute(LOG_PROPERTY_OLD);
- }
-
if (logClassName == null) {
- try {
- logDiagnostic("Trying to get log class from system property " + LOG_PROPERTY);
- logClassName = System.getProperty(LOG_PROPERTY);
- } catch (SecurityException e) {
- ;
- }
- }
-
- if (logClassName == null) { // @deprecated
- try {
- logDiagnostic("Trying to get log class from system property " + LOG_PROPERTY_OLD);
- logClassName = System.getProperty(LOG_PROPERTY_OLD);
- } catch (SecurityException e) {
- ;
- }
- }
-
- // no need for internalLog calls below; they are done inside the
- // various isXXXAvailable methods.
- if ((logClassName == null) && isLog4JAvailable()) {
- logClassName = "org.apache.commons.logging.impl.Log4JLogger";
- }
-
- if ((logClassName == null) && isJdk14Available()) {
- logClassName = "org.apache.commons.logging.impl.Jdk14Logger";
- }
-
- if ((logClassName == null) && isJdk13LumberjackAvailable()) {
- logClassName = "org.apache.commons.logging.impl.Jdk13LumberjackLogger";
+ discoverLogImplementation(getClass().getName());
}
-
- if (logClassName == null) {
- logClassName = "org.apache.commons.logging.impl.SimpleLog";
- }
-
- logDiagnostic("Using log class " + logClassName);
- return (logClassName);
-
+
+ return logClassName;
}
@@ -448,139 +396,24 @@ public class LogFactoryImpl extends LogF
* in all circumstances.</p>
*
* @exception LogConfigurationException if a suitable constructor
- * cannot be returned
+ * cannot be returned
+ *
+ * @deprecated Never invoked by this class; subclasses should not assume
+ * it will be.
*/
protected Constructor getLogConstructor()
throws LogConfigurationException {
// Return the previously identified Constructor (if any)
- if (logConstructor != null) {
- return logConstructor;
- }
-
- String logClassName = getLogClassName();
-
- // Attempt to load the Log implementation class
- //
- // Question: why is the loginterface being loaded dynamically?
- // Isn't the code below exactly the same as this?
- // Class logInterface = Log.class;
-
- Class logClass = null;
- Class logInterface = null;
- try {
- ClassLoader cl = getClassLoader(this.getClass());
- if (cl == null) {
- // we are probably in Java 1.1, but may also be running in
- // some sort of embedded system..
- logInterface = loadClass(LOG_INTERFACE);
- } else {
- // normal situation
- logInterface = cl.loadClass(LOG_INTERFACE);
- }
-
- logClass = loadClass(logClassName);
- if (logClass == null) {
- logDiagnostic(
- "Unable to find any class named [" + logClassName + "]"
- + " in either the context classloader"
- + " or the classloader that loaded this class.");
-
- throw new LogConfigurationException
- ("No suitable Log implementation for " + logClassName);
- }
-
- if (!logInterface.isAssignableFrom(logClass)) {
- // oops, we need to cast this logClass we have loaded into
- // a Log object in order to return it. But we won't be
- // able to. See method reportInvalidLogAdapter for more
- // information.
- LogConfigurationException ex =
- reportInvalidLogAdapter(logInterface, logClass);
- throw ex;
- }
- } catch (Throwable t) {
- logDiagnostic(
- "An unexpected problem occurred while loading the"
- + " log adapter class: " + t.getMessage());
- throw new LogConfigurationException(t);
- }
-
- // Identify the <code>setLogFactory</code> method (if there is one)
- try {
- logMethod = logClass.getMethod("setLogFactory",
- logMethodSignature);
- } catch (Throwable t) {
- logMethod = null;
+ if (logConstructor == null) {
+ discoverLogImplementation(getClass().getName());
}
- // Identify the corresponding constructor to be used
- try {
- logConstructor = logClass.getConstructor(logConstructorSignature);
- return (logConstructor);
- } catch (Throwable t) {
- throw new LogConfigurationException
- ("No suitable Log constructor " +
- logConstructorSignature+ " for " + logClassName, t);
- }
+ return logConstructor;
}
+
/**
- * Report a problem loading the log adapter, then <i>always</i> throw
- * a LogConfigurationException.
- * <p>
- * There are two possible reasons why we successfully loaded the
- * specified log adapter class then failed to cast it to a Log object:
- * <ol>
- * <li>the specific class just doesn't implement the Log interface
- * (user screwed up), or
- * <li> the specified class has bound to a Log class loaded by some other
- * classloader; Log@classloaderX cannot be cast to Log@classloaderY.
- * </ol>
- * <p>
- * Here we try to figure out which case has occurred so we can give the
- * user some reasonable feedback.
- *
- * @param logInterface is the class that this LogFactoryImpl class needs
- * to return the adapter as.
- * @param logClass is the adapter class we successfully loaded (but which
- * could not be cast to type logInterface).
- */
- private LogConfigurationException reportInvalidLogAdapter(
- Class logInterface, Class logClass) {
-
- Class interfaces[] = logClass.getInterfaces();
- for (int i = 0; i < interfaces.length; i++) {
- if (LOG_INTERFACE.equals(interfaces[i].getName())) {
-
- if (isDiagnosticsEnabled()) {
- ClassLoader logInterfaceClassLoader = getClassLoader(logInterface);
- ClassLoader logAdapterClassLoader = getClassLoader(logClass);
- Class logAdapterInterface = interfaces[i];
- ClassLoader logAdapterInterfaceClassLoader = getClassLoader(logAdapterInterface);
- logDiagnostic(
- "Class " + logClassName + " was found in classloader "
- + objectId(logAdapterClassLoader)
- + " but it implements the Log interface as loaded"
- + " from classloader " + objectId(logAdapterInterfaceClassLoader)
- + " not the one loaded by this class's classloader "
- + objectId(logInterfaceClassLoader));
- }
-
- throw new LogConfigurationException
- ("Invalid class loader hierarchy. " +
- "You have more than one version of '" +
- LOG_INTERFACE + "' visible, which is " +
- "not allowed.");
- }
- }
-
- return new LogConfigurationException
- ("Class " + logClassName + " does not implement '" +
- LOG_INTERFACE + "'.");
- }
-
- /**
* MUST KEEP THIS METHOD PRIVATE.
*
* <p>Exposing this method outside of
@@ -590,10 +423,14 @@ public class LogFactoryImpl extends LogF
* </p>
*
* Load a class, try first the thread class loader, and
- * if it fails use the loader that loaded this class. Actually, as
- * the thread (context) classloader should always be the same as or a
- * child of the classloader that loaded this class, the fallback should
- * never be used.
+ * if it fails use the loader that loaded this class.
+ *
+ * @param name fully qualified class name of the class to load
+ *
+ * @throws LinkageError if the linkage fails
+ * @throws ExceptionInInitializerError if the initialization provoked
+ * by this method fails
+ * @throws ClassNotFoundException if the class cannot be located
*/
private static Class loadClass( final String name )
throws ClassNotFoundException
@@ -619,29 +456,32 @@ public class LogFactoryImpl extends LogF
if (result instanceof Class)
return (Class)result;
-
+
throw (ClassNotFoundException)result;
}
/**
- * Is <em>JDK 1.3 with Lumberjack</em> logging available?
+ * Is <em>JDK 1.3 with Lumberjack</em> logging available?
+ *
+ * @deprecated Never invoked by this class; subclasses should not assume
+ * it will be.
*/
protected boolean isJdk13LumberjackAvailable() {
-
- // note: the algorithm here is different from isLog4JAvailable.
- // I think isLog4JAvailable is correct....see bugzilla#31597
+
logDiagnostic("Checking for Jdk13Lumberjack.");
try {
- loadClass("java.util.logging.Logger");
- loadClass("org.apache.commons.logging.impl.Jdk13LumberjackLogger");
+ createLogFromClass("org.apache.commons.logging.impl.Jdk13LumberjackLogger",
+ getClass().getName(),
+ false);
+ // No exception means success
logDiagnostic("Found Jdk13Lumberjack.");
return true;
} catch (Throwable t) {
logDiagnostic("Did not find Jdk13Lumberjack.");
return false;
}
-
+
}
@@ -649,20 +489,19 @@ public class LogFactoryImpl extends LogF
* <p>Return <code>true</code> if <em>JDK 1.4 or later</em> logging
* is available. Also checks that the <code>Throwable</code> class
* supports <code>getStackTrace()</code>, which is required by
- * Jdk14Logger.</p>
+ * Jdk14Logger.</p>
+ *
+ * @deprecated Never invoked by this class; subclasses should not assume
+ * it will be.
*/
protected boolean isJdk14Available() {
- // note: the algorithm here is different from isLog4JAvailable.
- // I think isLog4JAvailable is correct....
logDiagnostic("Checking for Jdk14.");
try {
- loadClass("java.util.logging.Logger");
- loadClass("org.apache.commons.logging.impl.Jdk14Logger");
- Class throwable = loadClass("java.lang.Throwable");
- if (throwable.getDeclaredMethod("getStackTrace", (Class[]) null) == null) {
- return (false);
- }
+ createLogFromClass("org.apache.commons.logging.impl.Jdk14Logger",
+ getClass().getName(),
+ false);
+ // No exception means success
logDiagnostic("Found Jdk14.");
return true;
} catch (Throwable t) {
@@ -673,16 +512,20 @@ public class LogFactoryImpl extends LogF
/**
- * Is a <em>Log4J</em> implementation available?
+ * Is a <em>Log4J</em> implementation available?
+ *
+ * @deprecated Never invoked by this class; subclasses should not assume
+ * it will be.
*/
protected boolean isLog4JAvailable() {
logDiagnostic("Checking for Log4J");
try {
- Class adapterClass = loadClass("org.apache.commons.logging.impl.Log4JLogger");
- ClassLoader cl = getClassLoader(adapterClass);
- Class loggerClass = cl.loadClass("org.apache.log4j.Logger" );
- logDiagnostic("Found Log4J");
+ createLogFromClass("org.apache.commons.logging.impl.Log4JLogger",
+ getClass().getName(),
+ false);
+ // No exception means success
+ logDiagnostic("Found Log4J.");
return true;
} catch (Throwable t) {
logDiagnostic("Did not find Log4J");
@@ -704,15 +547,31 @@ public class LogFactoryImpl extends LogF
Log instance = null;
try {
- Object params[] = new Object[1];
- params[0] = name;
- instance = (Log) getLogConstructor().newInstance(params);
+ if (logConstructor == null) {
+ instance = discoverLogImplementation(name);
+ }
+ else {
+ Object params[] = { name };
+ instance = (Log) logConstructor.newInstance(params);
+ }
+
if (logMethod != null) {
- params[0] = this;
+ Object params[] = { this };
logMethod.invoke(instance, params);
}
+
return (instance);
+
+ } catch (LogConfigurationException lce) {
+
+ // this type of exception means there was a problem in discovery
+ // and we've already output diagnostics about the issue, etc.;
+ // just pass it on
+ throw (LogConfigurationException) lce;
+
} catch (InvocationTargetException e) {
+ // A problem occurred invoking the Constructor or Method
+ // previously discovered
Throwable c = e.getTargetException();
if (c != null) {
throw new LogConfigurationException(c);
@@ -720,10 +579,393 @@ public class LogFactoryImpl extends LogF
throw new LogConfigurationException(e);
}
} catch (Throwable t) {
+ // A problem occurred invoking the Constructor or Method
+ // previously discovered
throw new LogConfigurationException(t);
}
+ }
+
+
+ // ------------------------------------------------------ Private Methods
+
+ /**
+ * Attempts to create a Log instance for the given category name.
+ * Follows the discovery process described in the class javadoc.
+ *
+ * @param logCategory the name of the log category
+ *
+ * @throws LogConfigurationException if an error in discovery occurs,
+ * or if no adapter at all can be
+ * instantiated
+ */
+ private Log discoverLogImplementation(String logCategory)
+ {
+ logDiagnostic("Attempting to discover a Log implementation.");
+
+ Log result = null;
+
+ // See if the user specified the Log implementation to use
+ String specifiedLogClassName = findUserSpecifiedLogClassName();
+
+ if (specifiedLogClassName != null) {
+ try {
+ // note: createLogFromClass never returns null..
+ result = createLogFromClass(specifiedLogClassName,
+ logCategory,
+ true);
+ return result;
+ } catch (LogConfigurationException ex) {
+ // this type of exception means we've already output
+ // diagnostics about this issue, etc.; just pass it on
+ throw ex;
+ } catch (Throwable t) {
+ // log problem, and throw a LogConfigurationException
+ // wrapping the Throwable
+ handleFlawedDiscovery(specifiedLogClassName, null, t);
+
+ // handleFlawedDiscovery should have thrown an LCE, but
+ // in case it didn't we'll throw one. Inability to
+ // instantiate a user specified class is a fatal error
+ throw new LogConfigurationException("Unable to instantiate "
+ + specifiedLogClassName,
+ t);
+ }
+
+ // this if-statement never exits!
+ }
+
+ // No user specified log; try to discover what's on the classpath
+
+ // Try Log4j
+ try {
+ result = createLogFromClass("org.apache.commons.logging.impl.Log4JLogger",
+ logCategory,
+ true);
+ } catch (LogConfigurationException lce) {
+
+ // LCE means we had a flawed discovery and already
+ // output diagnostics; just pass it on
+ throw (LogConfigurationException) lce;
+
+ } catch (Throwable t) {
+ // Other throwables just mean couldn't load the adapter
+ // or log4j; continue with discovery
+ }
+
+ if (result == null) {
+ // Try JDK 1.4 Logging
+ try {
+ result = createLogFromClass("org.apache.commons.logging.impl.Jdk14Logger",
+ logCategory,
+ true);
+ } catch (LogConfigurationException lce) {
+
+ // LCE means we had a flawed discovery and already
+ // output diagnostics; just pass it on
+ throw (LogConfigurationException) lce;
+
+ } catch (Throwable t) {
+ // Other throwables just mean couldn't load the adapter
+ // or j.u.l; continue with discovery
+ }
+ }
+ if (result == null) {
+ // Try Lumberjack
+ try {
+ result = createLogFromClass("org.apache.commons.logging.impl.Jdk13LumberjackLogger",
+ logCategory,
+ true);
+ } catch (LogConfigurationException lce) {
+
+ // LCE means we had a flawed discovery and already
+ // output diagnostics; just pass it on
+ throw (LogConfigurationException) lce;
+
+ } catch (Throwable t) {
+ // Other throwables just mean couldn't load the adapter
+ // or j.u.l; continue with discovery
+ }
+ }
+
+ if (result == null) {
+ // Try SimpleLog
+ try {
+ result = createLogFromClass("org.apache.commons.logging.impl.SimpleLog",
+ logCategory,
+ true);
+ } catch (LogConfigurationException lce) {
+
+ // LCE means we had a flawed discovery and already
+ // output diagnostics; just pass it up
+ throw (LogConfigurationException) lce;
+
+ } catch (Throwable t) {
+ // Other throwables just mean couldn't load the adapter
+ }
+ }
+
+ if (result == null) {
+ throw new LogConfigurationException
+ ("No suitable Log implementation");
+ }
+
+ return result;
}
+
+
+ /**
+ * Checks system properties and the attribute map for
+ * a Log implementation specified by the user under the
+ * property names {@link #LOG_PROPERTY} or {@link #LOG_PROPERTY_OLD}.
+ *
+ * @return classname specified by the user, or <code>null</code>
+ */
+ private String findUserSpecifiedLogClassName()
+ {
+ logDiagnostic("Trying to get log class from attribute " + LOG_PROPERTY);
+ String specifiedClass = (String) getAttribute(LOG_PROPERTY);
+
+ if (specifiedClass == null) { // @deprecated
+ logDiagnostic("Trying to get log class from attribute " +
+ LOG_PROPERTY_OLD);
+ specifiedClass = (String) getAttribute(LOG_PROPERTY_OLD);
+ }
+
+ if (specifiedClass == null) {
+ logDiagnostic("Trying to get log class from system property " +
+ LOG_PROPERTY);
+ try {
+ specifiedClass = System.getProperty(LOG_PROPERTY);
+ } catch (SecurityException e) {
+ ;
+ }
+ }
+
+ if (specifiedClass == null) { // @deprecated
+ logDiagnostic("Trying to get log class from system property " +
+ LOG_PROPERTY_OLD);
+ try {
+ specifiedClass = System.getProperty(LOG_PROPERTY_OLD);
+ } catch (SecurityException e) {
+ ;
+ }
+ }
+
+ return specifiedClass;
+
+ }
+
+
+ /**
+ * Attempts to load the given class, find a suitable constructor,
+ * and instantiate an instance of Log.
+ *
+ * @param logAdapterClass classname of the Log implementation
+ * @param logCategory argument to pass to the Log implementation's
+ * constructor
+ * @param affectState <code>true</code> if this object's state should
+ * be affected by this method call, <code>false</code>
+ * otherwise.
+ *
+ * @return an instance of the given class. Will not return
+ * <code>null</code>.
+ *
+ * @throws LinkageError if any linkage provoked by this method fails
+ * @throws ExceptionInInitializerError if any initialization provoked
+ * by this method fails
+ * @throws ClassNotFoundException if the class cannot be located
+ * @throws NoClassDefFoundError if <code>logImplClass</code> could be
+ * loaded but the logging implementation it
+ * relies on could not be located
+ * @throws LogConfigurationException if the class was loaded but no suitable
+ * logger could be created and this object
+ * is configured to fail in such a
+ * situation
+ */
+ private Log createLogFromClass(String logAdapterClass,
+ String logCategory,
+ boolean affectState)
+ throws Throwable {
+ logDiagnostic("Attempting to instantiate " + logAdapterClass);
+
+ Class logClass = loadClass(logAdapterClass);
+
+ Object[] params = { logCategory };
+ Log result = null;
+ Constructor constructor = null;
+ try {
+ constructor = logClass.getConstructor(logConstructorSignature);
+ result = (Log) constructor.newInstance(params);
+ } catch (NoClassDefFoundError e) {
+ // We were able to load the adapter but its underlying
+ // logger library could not be found. This is normal and not
+ // a "flawed discovery", so just throw the error on
+ logDiagnostic("Unable to load logging library used by "
+ + logAdapterClass);
+ throw e;
+ } catch (Throwable t) {
+ // ExceptionInInitializerError
+ // NoSuchMethodException
+ // InvocationTargetException
+ // ClassCastException
+ // All mean the adapter and underlying logger library were found
+ // but there was a problem creating an instance.
+ // This is a "flawed discovery"
+
+ handleFlawedDiscovery(logAdapterClass, logClass, t);
+ // handleFlawedDiscovery should have thrown an LCE, but
+ // in case it didn't we'll throw one
+ throw new LogConfigurationException(t);
+ }
+
+ if (affectState) {
+ // We've succeeded, so set instance fields
+ this.logClassName = logClass.getName();
+ this.logConstructor = constructor;
+
+ // Identify the <code>setLogFactory</code> method (if there is one)
+ try {
+ this.logMethod = logClass.getMethod("setLogFactory",
+ logMethodSignature);
+ logDiagnostic("Found method setLogFactory(LogFactory) in "
+ + logClassName);
+ } catch (Throwable t) {
+ this.logMethod = null;
+ logDiagnostic(logAdapterClass + " does not declare method "
+ + "setLogFactory(LogFactory)");
+ }
+ }
+
+ return result;
+
+ }
+
+
+ /**
+ * Generates an internal diagnostic logging of the discovery failure and
+ * then throws a <code>LogConfigurationException</code> that wraps
+ * the passed <code>Throwable</code>.
+ *
+ * @param logClassName the class name of the Log implementation
+ * that could not be instantiated. Cannot be
+ * <code>null</code>.
+ * @param adapterClass <code>Code</code> whose name is
+ * <code>logClassName</code>, or <code>null</code> if
+ * discovery was unable to load the class.
+ * @param discoveryFlaw Throwable thrown during discovery.
+ *
+ * @throws LogConfigurationException ALWAYS
+ */
+ private void handleFlawedDiscovery(String logClassName,
+ Class adapterClass,
+ Throwable discoveryFlaw) {
+
+ // Output diagnostics
+
+ // For ClassCastException use the more complex diagnostic
+ // that analyzes the classloader hierarchy
+ if ( discoveryFlaw instanceof ClassCastException
+ && adapterClass != null) {
+ // reportInvalidAdapter returns a LogConfigurationException
+ // that wraps the ClassCastException; replace variable
+ // 'discoveryFlaw' with that so we can rethrow the LCE
+ discoveryFlaw = reportInvalidLogAdapter(adapterClass,
+ discoveryFlaw);
+ }
+ else {
+ logDiagnostic("Could not instantiate Log "
+ + logClassName + " -- "
+ + discoveryFlaw.getLocalizedMessage());
+ }
+
+
+ if (discoveryFlaw instanceof LogConfigurationException) {
+ throw (LogConfigurationException) discoveryFlaw;
+ }
+ else {
+ throw new LogConfigurationException(discoveryFlaw);
+ }
+
+ }
+
+
+ /**
+ * Report a problem loading the log adapter, then return
+ * a LogConfigurationException.
+ * <p>
+ * There are two possible reasons why we successfully loaded the
+ * specified log adapter class then failed to cast it to a Log object:
+ * <ol>
+ * <li>the specific class just doesn't implement the Log interface
+ * (user screwed up), or
+ * <li> the specified class has bound to a Log class loaded by some other
+ * classloader; Log@classloaderX cannot be cast to Log@classloaderY.
+ * </ol>
+ * <p>
+ * Here we try to figure out which case has occurred so we can give the
+ * user some reasonable feedback.
+ *
+ * @param logClass is the adapter class we successfully loaded (but which
+ * could not be cast to type logInterface). Cannot be <code>null</code>.
+ * @param cause is the <code>Throwable</code> to wrap.
+ *
+ * @return <code>LogConfigurationException</code> that wraps
+ * <code>cause</code> and includes a diagnostic message.
+ */
+ private LogConfigurationException reportInvalidLogAdapter(Class logClass,
+ Throwable cause) {
+
+ Class interfaces[] = logClass.getInterfaces();
+ for (int i = 0; i < interfaces.length; i++) {
+ if (LOG_INTERFACE.equals(interfaces[i].getName())) {
+
+ if (isDiagnosticsEnabled()) {
+
+ try {
+ // Need to load the log interface so we know its
+ // classloader for diagnostics
+ Class logInterface = null;
+ ClassLoader cl = getClassLoader(this.getClass());
+ if (cl == null) {
+ // we are probably in Java 1.1, but may also be
+ // running in some sort of embedded system..
+ logInterface = loadClass(LOG_INTERFACE);
+ } else {
+ // normal situation
+ logInterface = cl.loadClass(LOG_INTERFACE);
+ }
+
+ ClassLoader logInterfaceClassLoader = getClassLoader(logInterface);
+ ClassLoader logAdapterClassLoader = getClassLoader(logClass);
+ Class logAdapterInterface = interfaces[i];
+ ClassLoader logAdapterInterfaceClassLoader = getClassLoader(logAdapterInterface);
+ logDiagnostic(
+ "Class " + logClass.getName()
+ + " was found in classloader "
+ + objectId(logAdapterClassLoader)
+ + " but it implements the Log interface as loaded"
+ + " from classloader "
+ + objectId(logAdapterInterfaceClassLoader)
+ + " not the one loaded by this class's classloader "
+ + objectId(logInterfaceClassLoader));
+ } catch (Throwable t) {
+ ;
+ }
+ }
+
+ return new LogConfigurationException
+ ("Invalid class loader hierarchy. " +
+ "You have more than one version of '" +
+ LOG_INTERFACE + "' visible, which is " +
+ "not allowed.", cause);
+ }
+ }
+
+ return new LogConfigurationException
+ ("Class " + logClassName + " does not implement '" +
+ LOG_INTERFACE + "'.", cause);
+ }
}