/[Apache-SVN]/jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java
ViewVC logotype

Diff of /jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java

Parent Directory Parent Directory | Revision Log Revision Log | View Patch 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);
+    }
 
 }

 

infrastructure at apache.org
ViewVC Help
Powered by ViewVC 1.1.26