Return-Path:
This factory will remember previously created
- * This method looks in the following places:
- * 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.
- *
- *
+ * 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.
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: - *
- * 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.
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:
+ *
+ * - the specific class just doesn't implement the Log interface=20
+ * (user screwed up), or
+ *
- 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