Author: skitching
Date: Sun May 22 03:43:52 2005
New Revision: 171301

URL: http://svn.apache.org/viewcvs?rev=171301&view=rev
Log:
Added internal diagnostics

Modified:
    
jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java

Modified: 
jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java
URL: 
http://svn.apache.org/viewcvs/jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java?rev=171301&r1=171300&r2=171301&view=diff
==============================================================================
--- 
jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java
 (original)
+++ 
jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java
 Sun May 22 03:43:52 2005
@@ -76,6 +76,8 @@
      */
     public LogFactoryImpl() {
         super();
+        initDiagnostics();  // method on this object
+        logDiagnostic("Instance created.");
     }
 
 
@@ -109,6 +111,11 @@
 
 
     /**
+     * The string prefixed to every message output by the logDiagnostic method.
+     */
+    private String diagnosticPrefix;
+
+    /**
      * Configuration attributes.
      */
     protected Hashtable attributes = new Hashtable();
@@ -160,7 +167,6 @@
 
     // --------------------------------------------------------- Public Methods
 
-
     /**
      * Return the configuration attribute with the specified name (if any),
      * or <code>null</code> if there is no such attribute.
@@ -250,6 +256,7 @@
      */
     public void release() {
 
+        logDiagnostic("Releasing all known loggers");
         instances.clear();
     }
 
@@ -287,13 +294,90 @@
     }
 
 
+    // ------------------------------------------------------ 
+    // Static Methods
+    //
+    // These methods only defined as workarounds for a java 1.2 bug;
+    // theoretically none of these are needed.
+    // ------------------------------------------------------ 
+    
+    /**
+     * Gets the context classloader.
+     * This method is a workaround for a java 1.2 compiler bug.
+     */
+    protected static ClassLoader getContextClassLoader() throws 
LogConfigurationException {
+        return LogFactory.getContextClassLoader();
+    }
+
+    /**
+     * Workaround for bug in Java1.2; in theory this method is not needed.
+     * See LogFactory.isInternalLoggingEnabled.
+     */
+    protected static boolean isDiagnosticsEnabled() {
+        return LogFactory.isDiagnosticsEnabled();
+    }
+
+    /**
+     * Workaround for bug in Java1.2; in theory this method is not needed.
+     * See LogFactory.getClassLoader.
+     */
+    protected static ClassLoader getClassLoader(Class clazz) {
+        return LogFactory.getClassLoader(clazz);
+    }
+
     // ------------------------------------------------------ Protected Methods
 
+    /**
+     * Calculate and cache a string that uniquely identifies this instance,
+     * including which classloader the object was loaded from.
+     * <p>
+     * This string will later be prefixed to each "internal logging" message
+     * emitted, so that users can clearly see any unexpected behaviour.
+     * <p>
+     * Note that this method does not detect whether internal logging is 
+     * enabled or not, nor where to output stuff if it is; that is all
+     * handled by the parent LogFactory class. This method just computes
+     * its own unique prefix for log messages.
+     */
+    private void initDiagnostics() {
+        // It would be nice to include an identifier of the context classloader
+        // that this LogFactoryImpl object is responsible for. However that
+        // isn't possible as that information isn't available. It is possible
+        // to figure this out by looking at the logging from LogFactory to
+        // see the context & impl ids from when this object was instantiated,
+        // in order to link the impl id output as this object's prefix back to
+        // the context it is intended to manage.
+        Class clazz = this.getClass();
+        ClassLoader classLoader = getClassLoader(clazz);
+        diagnosticPrefix = clazz.getName() + "@" + classLoader.toString() + 
":";
+    }
 
+    /**
+     * Output a diagnostic message to a user-specified destination (if the
+     * user has enabled diagnostic logging).
+     * 
+     * @param msg
+     */
+    protected void logDiagnostic(String msg) {
+        if (isDiagnosticsEnabled()) {
+            logRawDiagnostic(diagnosticPrefix + msg);
+        }
+    }
 
     /**
      * Return the fully qualified Java classname of the [EMAIL PROTECTED] 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>
      */
     protected String getLogClassName() {
 
@@ -302,14 +386,19 @@
             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) {
                 ;
@@ -318,12 +407,15 @@
 
         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";
         }
@@ -340,6 +432,7 @@
             logClassName = "org.apache.commons.logging.impl.SimpleLog";
         }
 
+        logDiagnostic("Using log class " + logClassName);
         return (logClassName);
 
     }
@@ -368,24 +461,48 @@
         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 = this.getClass().getClassLoader();
-            // handle the case if getClassLoader() returns null
-            // It may mean this class was loaded from the bootstrap classloader
-            logInterface = (cl == null) ? loadClass(LOG_INTERFACE) : 
-                                          cl.loadClass(LOG_INTERFACE);
+            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)) {
-                LogConfigurationException ex = 
reportInvalidLogAdapter(logInterface, 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);
         }
 
@@ -411,9 +528,23 @@
     /**
      * Report a problem loading the log adapter, then <i>always</i> throw
      * a LogConfigurationException.
-     *  
-     * @param logInterface
-     * @param logClass
+     *  <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; [EMAIL PROTECTED] cannot be cast to [EMAIL PROTECTED]
+     * </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) { 
@@ -421,6 +552,21 @@
         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 '" +
@@ -433,16 +579,7 @@
             ("Class " + logClassName + " does not implement '" +
                     LOG_INTERFACE + "'.");
     }
-    
-    /**
-     * Gets the context classloader.
-     * This method is a workaround for a java 1.2 compiler bug.
-     */
-    protected static ClassLoader getContextClassLoader() throws 
LogConfigurationException {
-        return LogFactory.getContextClassLoader();
-    }
-
-
+        
     /**
      * MUST KEEP THIS METHOD PRIVATE.
      *
@@ -453,7 +590,10 @@
      * </p>
      *
      * Load a class, try first the thread class loader, and
-     * if it fails use the loader that loaded this class.
+     * 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. 
      */
     private static Class loadClass( final String name )
         throws ClassNotFoundException
@@ -489,12 +629,17 @@
      */
     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");
-            return (true);
+            logDiagnostic("Found Jdk13Lumberjack.");
+            return true;
         } catch (Throwable t) {
-            return (false);
+            logDiagnostic("Did not find Jdk13Lumberjack.");
+            return false;
         }
 
     }
@@ -508,6 +653,9 @@
      */
     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");
@@ -515,9 +663,11 @@
             if (throwable.getDeclaredMethod("getStackTrace", null) == null) {
                 return (false);
             }
-            return (true);
+            logDiagnostic("Found Jdk14.");
+            return true;
         } catch (Throwable t) {
-            return (false);
+            logDiagnostic("Did not find Jdk14.");
+            return false;
         }
     }
 
@@ -527,12 +677,16 @@
      */
     protected boolean isLog4JAvailable() {
 
+        logDiagnostic("Checking for Log4J");
         try {
-            
loadClass("org.apache.commons.logging.impl.Log4JLogger").getClassLoader()
-                .loadClass("org.apache.log4j.Logger" );
-            return (true);
+            Class adapterClass = 
loadClass("org.apache.commons.logging.impl.Log4JLogger");
+            ClassLoader cl = getClassLoader(adapterClass);
+            Class loggerClass = cl.loadClass("org.apache.log4j.Logger" );
+            logDiagnostic("Found Log4J");
+            return true;
         } catch (Throwable t) {
-            return (false);
+            logDiagnostic("Did not find Log4J");
+            return false;
         }
     }
 



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to