You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by rd...@apache.org on 2006/03/07 22:54:58 UTC

svn commit: r384025 - /jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/LogFactory.java

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: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Re: svn commit: r384025 - /jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/LogFactory.java

Posted by robert burrell donkin <ro...@blueyonder.co.uk>.
please take a look and check for typo's, bugs etc. 

i'm working on something for the troubleshooting documentation about
this.

- robert

On Tue, 2006-03-07 at 21:54 +0000, rdonkin@apache.org wrote:
> 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: commons-dev-unsubscribe@jakarta.apache.org
> For additional commands, e-mail: commons-dev-help@jakarta.apache.org
> 
> 


---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org