Return-Path: Delivered-To: apmail-jakarta-commons-dev-archive@www.apache.org Received: (qmail 18460 invoked from network); 2 Jun 2005 04:09:27 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 2 Jun 2005 04:09:27 -0000 Received: (qmail 67383 invoked by uid 500); 2 Jun 2005 04:09:22 -0000 Delivered-To: apmail-jakarta-commons-dev-archive@jakarta.apache.org Received: (qmail 67307 invoked by uid 500); 2 Jun 2005 04:09:22 -0000 Mailing-List: contact commons-dev-help@jakarta.apache.org; run by ezmlm Precedence: bulk List-Unsubscribe: List-Help: List-Post: List-Id: "Jakarta Commons Developers List" Reply-To: "Jakarta Commons Developers List" Delivered-To: mailing list commons-dev@jakarta.apache.org Received: (qmail 67292 invoked by uid 500); 2 Jun 2005 04:09:21 -0000 Received: (qmail 67282 invoked by uid 99); 2 Jun 2005 04:09:21 -0000 X-ASF-Spam-Status: No, hits=-9.8 required=10.0 tests=ALL_TRUSTED,NO_REAL_NAME X-Spam-Check-By: apache.org Received: from minotaur.apache.org (HELO minotaur.apache.org) (209.237.227.194) by apache.org (qpsmtpd/0.28) with SMTP; Wed, 01 Jun 2005 21:09:20 -0700 Received: (qmail 18439 invoked by uid 65534); 2 Jun 2005 04:09:18 -0000 Message-ID: <20050602040918.18438.qmail@minotaur.apache.org> Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Subject: svn commit: r179500 - /jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java Date: Thu, 02 Jun 2005 04:09:18 -0000 To: commons-cvs@jakarta.apache.org From: skitching@apache.org X-Mailer: svnmailer-1.0.0-dev X-Virus-Checked: Checked X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Author: skitching Date: Wed Jun 1 21:09:16 2005 New Revision: 179500 URL: http://svn.apache.org/viewcvs?rev=3D179500&view=3Drev Log: Change to discovery process: testing whether various logging libraries are available is now done by trying to actually create an instance. Modified: jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/loggin= g/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=3D179500&r1= =3D179499&r2=3D179500&view=3Ddiff =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D --- jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/loggin= g/impl/LogFactoryImpl.java (original) +++ jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/loggin= g/impl/LogFactoryImpl.java Wed Jun 1 21:09:16 2005 @@ -57,12 +57,12 @@ * *

This factory will remember previously created Log insta= nces * for the same name, and will return them on repeated requests to the - * getInstance() method. This implementation ignores any - * configured attributes.

+ * getInstance() method. * * @author Rod Waldhoff * @author Craig R. McClanahan * @author Richard A. Sitze + * @author Brian Stansberry * @version $Revision$ $Date$ */ =20 @@ -115,6 +115,7 @@ */ private String diagnosticPrefix; =20 + /** * Configuration attributes. */ @@ -164,9 +165,9 @@ protected Class logMethodSignature[] =3D { LogFactory.class }; =20 - // --------------------------------------------------------- Public Me= thods =20 + /** * Return the configuration attribute with the specified name (if any), * or null if there is no such attribute. @@ -309,14 +310,16 @@ return LogFactory.getContextClassLoader(); } =20 + =20 /** * 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(); } =20 + =20 /** * Workaround for bug in Java1.2; in theory this method is not needed. * See LogFactory.getClassLoader. @@ -325,6 +328,7 @@ return LogFactory.getClassLoader(clazz); } =20 + // ------------------------------------------------------ Protected Me= thods =20 /** @@ -352,6 +356,7 @@ diagnosticPrefix =3D clazz.getName() + "@" + classLoader.toString(= ) + ":"; } =20 + =20 /** * Output a diagnostic message to a user-specified destination (if the * user has enabled diagnostic logging). @@ -366,75 +371,18 @@ =20 /** * Return the fully qualified Java classname of the {@link Log} - * implementation we will be using. - *

- * This method looks in the following places: - *

    - *
  • Looks for an attribute LOG_PROPERTY or LOG_PROPERTY_OLD in the=20 - * "attributes" associated with this class, as set earlier by method=20 - * setAttribute. - *
  • Looks for a property LOG_PROPERTY or LOG_PROPERTY_OLD in the - * system properties. - *
  • Looks for log4j, jdk logging and jdk13lumberjack classes in - * the classpath. - *
+ * implementation we will be using. =20 + *=20 + * @deprecated Never invoked by this class; subclasses should not ass= ume + * it will be. */ protected String getLogClassName() { =20 - // Return the previously identified class name (if any) - if (logClassName !=3D null) { - return logClassName; - } - - logDiagnostic("Determining the name for the Log implementation."); - - logDiagnostic("Trying to get log class from attribute " + LOG_PROP= ERTY); - logClassName =3D (String) getAttribute(LOG_PROPERTY); - - if (logClassName =3D=3D null) { // @deprecated - logDiagnostic("Trying to get log class from attribute " + LOG_= PROPERTY_OLD); - logClassName =3D (String) getAttribute(LOG_PROPERTY_OLD); - } - if (logClassName =3D=3D null) { - try { - logDiagnostic("Trying to get log class from system propert= y " + LOG_PROPERTY); - logClassName =3D System.getProperty(LOG_PROPERTY); - } catch (SecurityException e) { - ; - } - } - - if (logClassName =3D=3D null) { // @deprecated - try { - logDiagnostic("Trying to get log class from system propert= y " + LOG_PROPERTY_OLD); - logClassName =3D System.getProperty(LOG_PROPERTY_OLD); - } catch (SecurityException e) { - ; - } - } - - // no need for internalLog calls below; they are done inside the - // various isXXXAvailable methods. - if ((logClassName =3D=3D null) && isLog4JAvailable()) { - logClassName =3D "org.apache.commons.logging.impl.Log4JLogger"; - } - - if ((logClassName =3D=3D null) && isJdk14Available()) { - logClassName =3D "org.apache.commons.logging.impl.Jdk14Logger"; - } - - if ((logClassName =3D=3D null) && isJdk13LumberjackAvailable()) { - logClassName =3D "org.apache.commons.logging.impl.Jdk13Lumberj= ackLogger"; + discoverLogImplementation(getClass().getName()); } - - if (logClassName =3D=3D null) { - logClassName =3D "org.apache.commons.logging.impl.SimpleLog"; - } - - logDiagnostic("Using log class " + logClassName); - return (logClassName); - + =20 + return logClassName; } =20 =20 @@ -448,139 +396,24 @@ * in all circumstances.

* * @exception LogConfigurationException if a suitable constructor - * cannot be returned + * cannot be returned =20 + *=20 + * @deprecated Never invoked by this class; subclasses should not ass= ume + * it will be. */ protected Constructor getLogConstructor() throws LogConfigurationException { =20 // Return the previously identified Constructor (if any) - if (logConstructor !=3D null) { - return logConstructor; - } - - String logClassName =3D 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 =3D Log.class; - =20 - Class logClass =3D null; - Class logInterface =3D null; - try { - ClassLoader cl =3D getClassLoader(this.getClass()); - if (cl =3D=3D null) { - // we are probably in Java 1.1, but may also be running in - // some sort of embedded system.. - logInterface =3D loadClass(LOG_INTERFACE); - } else { - // normal situation - logInterface =3D cl.loadClass(LOG_INTERFACE); - } - - logClass =3D loadClass(logClassName); - if (logClass =3D=3D 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); - } - =20 - 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 =3D=20 - 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 setLogFactory method (if there is one) - try { - logMethod =3D logClass.getMethod("setLogFactory", - logMethodSignature); - } catch (Throwable t) { - logMethod =3D null; + if (logConstructor =3D=3D null) { + discoverLogImplementation(getClass().getName()); } =20 - // Identify the corresponding constructor to be used - try { - logConstructor =3D logClass.getConstructor(logConstructorSigna= ture); - return (logConstructor); - } catch (Throwable t) { - throw new LogConfigurationException - ("No suitable Log constructor " + - logConstructorSignature+ " for " + logClassName, t); - } + return logConstructor; } + =20 =20 /** - * Report a problem loading the log adapter, then always throw - * a LogConfigurationException. - *

- * There are two possible reasons why we successfully loaded the=20 - * specified log adapter class then failed to cast it to a Log object: - *

    - *
  1. the specific class just doesn't implement the Log interface=20 - * (user screwed up), or - *
  2. the specified class has bound to a Log class loaded by some ot= her - * classloader; Log@classloaderX cannot be cast to Log@classloade= rY. - *
- *

- * Here we try to figure out which case has occurred so we can give the - * user some reasonable feedback. - *=20 - * @param logInterface is the class that this LogFactoryImpl class nee= ds - * to return the adapter as. - * @param logClass is the adapter class we successfully loaded (but wh= ich - * could not be cast to type logInterface). - */ - private LogConfigurationException reportInvalidLogAdapter( - Class logInterface, Class logClass) {=20 - - Class interfaces[] =3D logClass.getInterfaces(); - for (int i =3D 0; i < interfaces.length; i++) { - if (LOG_INTERFACE.equals(interfaces[i].getName())) { - - if (isDiagnosticsEnabled()) { - ClassLoader logInterfaceClassLoader =3D getClassLoader= (logInterface); - ClassLoader logAdapterClassLoader =3D getClassLoader(l= ogClass); - Class logAdapterInterface =3D interfaces[i]; - ClassLoader logAdapterInterfaceClassLoader =3D getClas= sLoader(logAdapterInterface); - logDiagnostic( - "Class " + logClassName + " was found in classload= er "=20 - + objectId(logAdapterClassLoader) - + " but it implements the Log interface as loaded" - + " from classloader " + objectId(logAdapterInterf= aceClassLoader) - + " not the one loaded by this class's classloader= " - + objectId(logInterfaceClassLoader)); - } - =20 - throw new LogConfigurationException - ("Invalid class loader hierarchy. " + - "You have more than one version of '" + - LOG_INTERFACE + "' visible, which is " + - "not allowed."); - } - } - =20 - return new LogConfigurationException - ("Class " + logClassName + " does not implement '" + - LOG_INTERFACE + "'."); - } - =20 - /** * MUST KEEP THIS METHOD PRIVATE. * *

Exposing this method outside of @@ -590,10 +423,14 @@ *

* * 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=20 - * child of the classloader that loaded this class, the fallback should - * never be used.=20 + * if it fails use the loader that loaded this class. + *=20 + * @param name fully qualified class name of the class to load + * =20 + * @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 @@ =20 if (result instanceof Class) return (Class)result; - + =20 throw (ClassNotFoundException)result; } =20 =20 /** - * Is JDK 1.3 with Lumberjack logging available? + * Is JDK 1.3 with Lumberjack logging available? =20 + *=20 + * @deprecated Never invoked by this class; subclasses should not ass= ume + * it will be. */ protected boolean isJdk13LumberjackAvailable() { - - // note: the algorithm here is different from isLog4JAvailable. - // I think isLog4JAvailable is correct....see bugzilla#31597 + =20 logDiagnostic("Checking for Jdk13Lumberjack."); try { - loadClass("java.util.logging.Logger"); - loadClass("org.apache.commons.logging.impl.Jdk13LumberjackLogg= er"); + createLogFromClass("org.apache.commons.logging.impl.Jdk13Lumbe= rjackLogger", + getClass().getName(), + false); + // No exception means success logDiagnostic("Found Jdk13Lumberjack."); return true; } catch (Throwable t) { logDiagnostic("Did not find Jdk13Lumberjack."); return false; } - + =20 } =20 =20 @@ -649,20 +489,19 @@ *

Return true if JDK 1.4 or later logging * is available. Also checks that the Throwable class * supports getStackTrace(), which is required by - * Jdk14Logger.

+ * Jdk14Logger.

=20 + *=20 + * @deprecated Never invoked by this class; subclasses should not ass= ume + * it will be. */ protected boolean isJdk14Available() { =20 - // 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 =3D loadClass("java.lang.Throwable"); - if (throwable.getDeclaredMethod("getStackTrace", (Class[]) nul= l) =3D=3D null) { - return (false); - } + createLogFromClass("org.apache.commons.logging.impl.Jdk14Logge= r", + getClass().getName(), + false); + // No exception means success logDiagnostic("Found Jdk14."); return true; } catch (Throwable t) { @@ -673,16 +512,20 @@ =20 =20 /** - * Is a Log4J implementation available? + * Is a Log4J implementation available?=20 + *=20 + * @deprecated Never invoked by this class; subclasses should not ass= ume + * it will be. */ protected boolean isLog4JAvailable() { =20 logDiagnostic("Checking for Log4J"); try { - Class adapterClass =3D loadClass("org.apache.commons.logging.i= mpl.Log4JLogger"); - ClassLoader cl =3D getClassLoader(adapterClass); - Class loggerClass =3D cl.loadClass("org.apache.log4j.Logger" ); - logDiagnostic("Found Log4J"); + createLogFromClass("org.apache.commons.logging.impl.Log4JLogge= r", + getClass().getName(), + false); + // No exception means success + logDiagnostic("Found Log4J."); return true; } catch (Throwable t) { logDiagnostic("Did not find Log4J"); @@ -704,15 +547,31 @@ =20 Log instance =3D null; try { - Object params[] =3D new Object[1]; - params[0] =3D name; - instance =3D (Log) getLogConstructor().newInstance(params); + if (logConstructor =3D=3D null) { + instance =3D discoverLogImplementation(name); + } + else { + Object params[] =3D { name }; + instance =3D (Log) logConstructor.newInstance(params); + } + =20 if (logMethod !=3D null) { - params[0] =3D this; + Object params[] =3D { this }; logMethod.invoke(instance, params); } + =20 return (instance); + =20 + } catch (LogConfigurationException lce) { + =20 + // this type of exception means there was a problem in discove= ry + // and we've already output diagnostics about the issue, etc.;=20 + // just pass it on + throw (LogConfigurationException) lce; + =20 } catch (InvocationTargetException e) { + // A problem occurred invoking the Constructor or Method=20 + // previously discovered Throwable c =3D e.getTargetException(); if (c !=3D null) { throw new LogConfigurationException(c); @@ -720,10 +579,393 @@ throw new LogConfigurationException(e); } } catch (Throwable t) { + // A problem occurred invoking the Constructor or Method=20 + // previously discovered throw new LogConfigurationException(t); } + } + =20 + + // ------------------------------------------------------ Private Met= hods + =20 + /** + * Attempts to create a Log instance for the given category name. + * Follows the discovery process described in the class javadoc. + *=20 + * @param logCategory the name of the log category + *=20 + * @throws LogConfigurationException if an error in discovery occurs,=20 + * or if no adapter at all can be=20 + * instantiated + */ + private Log discoverLogImplementation(String logCategory) + { + logDiagnostic("Attempting to discover a Log implementation."); + =20 + Log result =3D null; + =20 + // See if the user specified the Log implementation to use + String specifiedLogClassName =3D findUserSpecifiedLogClassName(); + + if (specifiedLogClassName !=3D null) { + try { + // note: createLogFromClass never returns null.. + result =3D 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); + =20 + // 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= " + + specifiedLogClassNam= e, + t); + } + + // this if-statement never exits! + } + =20 + // No user specified log; try to discover what's on the classpath + =20 + // Try Log4j + try { + result =3D createLogFromClass("org.apache.commons.logging.impl= .Log4JLogger", + logCategory, + true); + } catch (LogConfigurationException lce) { + =20 + // LCE means we had a flawed discovery and already + // output diagnostics; just pass it on=20 + throw (LogConfigurationException) lce; + =20 + } catch (Throwable t) { + // Other throwables just mean couldn't load the adapter=20 + // or log4j; continue with discovery + } =20 + + if (result =3D=3D null) { + // Try JDK 1.4 Logging + try { + result =3D createLogFromClass("org.apache.commons.logging.= impl.Jdk14Logger", + logCategory, + true); + } catch (LogConfigurationException lce) { + =20 + // LCE means we had a flawed discovery and already + // output diagnostics; just pass it on=20 + throw (LogConfigurationException) lce; + =20 + } catch (Throwable t) { + // Other throwables just mean couldn't load the adapter=20 + // or j.u.l; continue with discovery + } + } =20 + if (result =3D=3D null) { + // Try Lumberjack + try { + result =3D createLogFromClass("org.apache.commons.logging.= impl.Jdk13LumberjackLogger", + logCategory, + true); + } catch (LogConfigurationException lce) { + =20 + // LCE means we had a flawed discovery and already + // output diagnostics; just pass it on=20 + throw (LogConfigurationException) lce; + =20 + } catch (Throwable t) { + // Other throwables just mean couldn't load the adapter=20 + // or j.u.l; continue with discovery + } + } + + if (result =3D=3D null) { + // Try SimpleLog + try { + result =3D createLogFromClass("org.apache.commons.logging.= impl.SimpleLog", + logCategory, + true); + } catch (LogConfigurationException lce) { + =20 + // LCE means we had a flawed discovery and already + // output diagnostics; just pass it up=20 + throw (LogConfigurationException) lce; + =20 + } catch (Throwable t) { + // Other throwables just mean couldn't load the adapter=20 + } + } + =20 + if (result =3D=3D null) { + throw new LogConfigurationException + ("No suitable Log implementation"); + } + =20 + return result; =20 } + =20 + =20 + /** + * Checks system properties and the attribute map for=20 + * a Log implementation specified by the user under the=20 + * property names {@link #LOG_PROPERTY} or {@link #LOG_PROPERTY_OLD}. + *=20 + * @return classname specified by the user, or null + */ + private String findUserSpecifiedLogClassName() + { + logDiagnostic("Trying to get log class from attribute " + LOG_PROP= ERTY); + String specifiedClass =3D (String) getAttribute(LOG_PROPERTY); + + if (specifiedClass =3D=3D null) { // @deprecated + logDiagnostic("Trying to get log class from attribute " +=20 + LOG_PROPERTY_OLD); + specifiedClass =3D (String) getAttribute(LOG_PROPERTY_OLD); + } + + if (specifiedClass =3D=3D null) { + logDiagnostic("Trying to get log class from system property " = +=20 + LOG_PROPERTY); + try { + specifiedClass =3D System.getProperty(LOG_PROPERTY); + } catch (SecurityException e) { + ; + } + } + + if (specifiedClass =3D=3D null) { // @deprecated + logDiagnostic("Trying to get log class from system property " = +=20 + LOG_PROPERTY_OLD); + try { + specifiedClass =3D System.getProperty(LOG_PROPERTY_OLD); + } catch (SecurityException e) { + ; + } + } + =20 + return specifiedClass; + =20 + } + + =20 + /** + * Attempts to load the given class, find a suitable constructor, + * and instantiate an instance of Log. + *=20 + * @param logAdapterClass classname of the Log implementation + * @param logCategory argument to pass to the Log implementation's + * constructor + * @param affectState true if this object's state shou= ld + * be affected by this method call, false<= /code> + * otherwise. + *=20 + * @return an instance of the given class. Will not return=20 + * null. + * =20 + * @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 logImplClass could be + * loaded but the logging implementation = it + * relies on could not be located + * @throws LogConfigurationException if the class was loaded but no su= itable + * logger could be created and this = object + * is configured to fail in such a + * situation + */ =20 + private Log createLogFromClass(String logAdapterClass, + String logCategory, + boolean affectState)=20 + throws Throwable { =20 =20 + logDiagnostic("Attempting to instantiate " + logAdapterClass); + =20 + Class logClass =3D loadClass(logAdapterClass); + =20 + Object[] params =3D { logCategory }; + Log result =3D null; + Constructor constructor =3D null; + try { + constructor =3D logClass.getConstructor(logConstructorSignatur= e); + result =3D (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 fou= nd + // but there was a problem creating an instance. + // This is a "flawed discovery" =20 + =20 + handleFlawedDiscovery(logAdapterClass, logClass, t); + // handleFlawedDiscovery should have thrown an LCE, but + // in case it didn't we'll throw one + throw new LogConfigurationException(t); + } =20 + =20 + if (affectState) { + // We've succeeded, so set instance fields + this.logClassName =3D logClass.getName(); + this.logConstructor =3D constructor; + =20 + // Identify the setLogFactory method (if there is= one) + try { + this.logMethod =3D logClass.getMethod("setLogFactory", + logMethodSignature); + logDiagnostic("Found method setLogFactory(LogFactory) in "=20 + + logClassName); + } catch (Throwable t) { + this.logMethod =3D null; + logDiagnostic(logAdapterClass + " does not declare method " + + "setLogFactory(LogFactory)"); + } + } + =20 + return result; =20 + =20 + } + =20 + =20 + /** + * Generates an internal diagnostic logging of the discovery failure a= nd=20 + * then throws a LogConfigurationException that wraps=20 + * the passed Throwable. + *=20 + * @param logClassName the class name of the Log implementation + * that could not be instantiated. Cannot be + * null. + * @param adapterClass Code whose name is + * logClassName, or null if + * discovery was unable to load the class. + * @param discoveryFlaw Throwable thrown during discovery. + *=20 + * @throws LogConfigurationException ALWAYS + */ + private void handleFlawedDiscovery(String logClassName, + Class adapterClass, + Throwable discoveryFlaw) { + =20 + // Output diagnostics + =20 + // For ClassCastException use the more complex diagnostic + // that analyzes the classloader hierarchy + if ( discoveryFlaw instanceof ClassCastException + && adapterClass !=3D null) { + // reportInvalidAdapter returns a LogConfigurationException + // that wraps the ClassCastException; replace variable=20 + // 'discoveryFlaw' with that so we can rethrow the LCE + discoveryFlaw =3D reportInvalidLogAdapter(adapterClass,=20 + discoveryFlaw); + } + else { + logDiagnostic("Could not instantiate Log " + + logClassName + " -- " + + discoveryFlaw.getLocalizedMessage()); =20 + } + =20 + =20 + if (discoveryFlaw instanceof LogConfigurationException) { + throw (LogConfigurationException) discoveryFlaw; + } + else { + throw new LogConfigurationException(discoveryFlaw); + } + =20 + } + + =20 + /** + * Report a problem loading the log adapter, then return + * a LogConfigurationException. + *

+ * There are two possible reasons why we successfully loaded the=20 + * specified log adapter class then failed to cast it to a Log object: + *

    + *
  1. the specific class just doesn't implement the Log interface=20 + * (user screwed up), or + *
  2. the specified class has bound to a Log class loaded by some ot= her + * classloader; Log@classloaderX cannot be cast to Log@classloade= rY. + *
+ *

+ * Here we try to figure out which case has occurred so we can give the + * user some reasonable feedback. + *=20 + * @param logClass is the adapter class we successfully loaded (but wh= ich + * could not be cast to type logInterface). Cannot be null=2E + * @param cause is the Throwable to wrap. + *=20 + * @return LogConfigurationException that wraps=20 + * cause and includes a diagnostic message. + */ + private LogConfigurationException reportInvalidLogAdapter(Class logCla= ss, + Throwable ca= use) { + =20 + Class interfaces[] =3D logClass.getInterfaces(); + for (int i =3D 0; i < interfaces.length; i++) { + if (LOG_INTERFACE.equals(interfaces[i].getName())) { + + if (isDiagnosticsEnabled()) { =20 + =20 + try { + // Need to load the log interface so we know its + // classloader for diagnostics + Class logInterface =3D null; + ClassLoader cl =3D getClassLoader(this.getClass()); + if (cl =3D=3D null) { + // we are probably in Java 1.1, but may also b= e=20 + // running in some sort of embedded system.. + logInterface =3D loadClass(LOG_INTERFACE); + } else { + // normal situation + logInterface =3D cl.loadClass(LOG_INTERFACE); + } + + ClassLoader logInterfaceClassLoader =3D getClassLo= ader(logInterface); + ClassLoader logAdapterClassLoader =3D getClassLoad= er(logClass); + Class logAdapterInterface =3D interfaces[i]; + ClassLoader logAdapterInterfaceClassLoader =3D get= ClassLoader(logAdapterInterface); + logDiagnostic( + "Class " + logClass.getName() + + " was found in classloader "=20 + + objectId(logAdapterClassLoader) + + " but it implements the Log interface as loa= ded" + + " from classloader "=20 + + objectId(logAdapterInterfaceClassLoader) + + " not the one loaded by this class's classlo= ader " + + objectId(logInterfaceClassLoader)); + } catch (Throwable t) { + ; + } + } + =20 + return new LogConfigurationException + ("Invalid class loader hierarchy. " + + "You have more than one version of '" + + LOG_INTERFACE + "' visible, which is " + + "not allowed.", cause); + } + } + =20 + return new LogConfigurationException + ("Class " + logClassName + " does not implement '" + + LOG_INTERFACE + "'.", cause); + } =20 } --------------------------------------------------------------------- To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org For additional commands, e-mail: commons-dev-help@jakarta.apache.org