Change to discovery process: testing whether various logging
libraries are available is now done by trying to actually create an instance. git-svn-id: https://svn.apache.org/repos/asf/jakarta/commons/proper/logging/trunk@179500 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
@@ -57,12 +57,12 @@ import org.apache.commons.logging.LogFactory;
|
||||
*
|
||||
* <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 LogFactory {
|
||||
*/
|
||||
private String diagnosticPrefix;
|
||||
|
||||
|
||||
/**
|
||||
* Configuration attributes.
|
||||
*/
|
||||
@@ -164,9 +165,9 @@ public class LogFactoryImpl extends LogFactory {
|
||||
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 LogFactory {
|
||||
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 LogFactory {
|
||||
return LogFactory.getClassLoader(clazz);
|
||||
}
|
||||
|
||||
|
||||
// ------------------------------------------------------ Protected Methods
|
||||
|
||||
/**
|
||||
@@ -352,6 +356,7 @@ public class LogFactoryImpl extends LogFactory {
|
||||
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 LogFactory {
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
;
|
||||
}
|
||||
discoverLogImplementation(getClass().getName());
|
||||
}
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
if (logClassName == null) {
|
||||
logClassName = "org.apache.commons.logging.impl.SimpleLog";
|
||||
}
|
||||
|
||||
logDiagnostic("Using log class " + logClassName);
|
||||
return (logClassName);
|
||||
|
||||
|
||||
return logClassName;
|
||||
}
|
||||
|
||||
|
||||
@@ -448,138 +396,23 @@ public class LogFactoryImpl extends LogFactory {
|
||||
* 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;
|
||||
if (logConstructor == null) {
|
||||
discoverLogImplementation(getClass().getName());
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// 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.
|
||||
*
|
||||
@@ -590,10 +423,14 @@ public class LogFactoryImpl extends LogFactory {
|
||||
* </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 LogFactory {
|
||||
|
||||
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 LogFactory {
|
||||
* <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 LogFactory {
|
||||
|
||||
|
||||
/**
|
||||
* 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 LogFactory {
|
||||
|
||||
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 LogFactory {
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user