📄 logfactoryimpl.java
字号:
* or a configuration property has been set in a commons-logging.properties
* file.
*
* @return the value associated with the property, or null.
*/
private String getConfigurationValue(String property) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] Trying to get configuration for item " + property);
}
Object valueObj = getAttribute(property);
if (valueObj != null) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] Found LogFactory attribute [" + valueObj + "] for " + property);
}
return valueObj.toString();
}
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] No LogFactory attribute found for " + property);
}
try {
// warning: minor security hole here, in that we potentially read a system
// property that the caller cannot, then output it in readable form as a
// diagnostic message. However it's only ever JCL-specific properties
// involved here, so the harm is truly trivial.
String value = getSystemProperty(property, null);
if (value != null) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] Found system property [" + value + "] for " + property);
}
return value;
}
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] No system property found for property " + property);
}
} catch (SecurityException e) {
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] Security prevented reading system property " + property);
}
}
if (isDiagnosticsEnabled()) {
logDiagnostic("[ENV] No configuration defined for item " + property);
}
return null;
}
/**
* Get the setting for the user-configurable behaviour specified by key.
* If nothing has explicitly been set, then return dflt.
*/
private boolean getBooleanConfiguration(String key, boolean dflt) {
String val = getConfigurationValue(key);
if (val == null)
return dflt;
return Boolean.valueOf(val).booleanValue();
}
/**
* Initialize a number of variables that control the behaviour of this
* class and that can be tweaked by the user. This is done when the first
* logger is created, not in the constructor of this class, because we
* need to give the user a chance to call method setAttribute in order to
* configure this object.
*/
private void initConfiguration() {
allowFlawedContext = getBooleanConfiguration(ALLOW_FLAWED_CONTEXT_PROPERTY, true);
allowFlawedDiscovery = getBooleanConfiguration(ALLOW_FLAWED_DISCOVERY_PROPERTY, true);
allowFlawedHierarchy = getBooleanConfiguration(ALLOW_FLAWED_HIERARCHY_PROPERTY, true);
}
/**
* 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)
throws LogConfigurationException
{
if (isDiagnosticsEnabled()) {
logDiagnostic("Discovering a Log implementation...");
}
initConfiguration();
Log result = null;
// See if the user specified the Log implementation to use
String specifiedLogClassName = findUserSpecifiedLogClassName();
if (specifiedLogClassName != null) {
if (isDiagnosticsEnabled()) {
logDiagnostic("Attempting to load user-specified log class '" +
specifiedLogClassName + "'...");
}
result = createLogFromClass(specifiedLogClassName,
logCategory,
true);
if (result == null) {
StringBuffer messageBuffer = new StringBuffer("User-specified log class '");
messageBuffer.append(specifiedLogClassName);
messageBuffer.append("' cannot be found or is not useable.");
// Mistyping or misspelling names is a common fault.
// Construct a good error message, if we can
if (specifiedLogClassName != null) {
informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LOG4J_LOGGER);
informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_JDK14_LOGGER);
informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_LUMBERJACK_LOGGER);
informUponSimilarName(messageBuffer, specifiedLogClassName, LOGGING_IMPL_SIMPLE_LOGGER);
}
throw new LogConfigurationException(messageBuffer.toString());
}
return result;
}
// No user specified log; try to discover what's on the classpath
//
// Note that we deliberately loop here over classesToDiscover and
// expect method createLogFromClass to loop over the possible source
// classloaders. The effect is:
// for each discoverable log adapter
// for each possible classloader
// see if it works
//
// It appears reasonable at first glance to do the opposite:
// for each possible classloader
// for each discoverable log adapter
// see if it works
//
// The latter certainly has advantages for user-installable logging
// libraries such as log4j; in a webapp for example this code should
// first check whether the user has provided any of the possible
// logging libraries before looking in the parent classloader.
// Unfortunately, however, Jdk14Logger will always work in jvm>=1.4,
// and SimpleLog will always work in any JVM. So the loop would never
// ever look for logging libraries in the parent classpath. Yet many
// users would expect that putting log4j there would cause it to be
// detected (and this is the historical JCL behaviour). So we go with
// the first approach. A user that has bundled a specific logging lib
// in a webapp should use a commons-logging.properties file or a
// service file in META-INF to force use of that logging lib anyway,
// rather than relying on discovery.
if (isDiagnosticsEnabled()) {
logDiagnostic(
"No user-specified Log implementation; performing discovery" +
" using the standard supported logging implementations...");
}
for(int i=0; (i<classesToDiscover.length) && (result == null); ++i) {
result = createLogFromClass(classesToDiscover[i], logCategory, true);
}
if (result == null) {
throw new LogConfigurationException
("No suitable Log implementation");
}
return result;
}
/**
* Appends message if the given name is similar to the candidate.
* @param messageBuffer <code>StringBuffer</code> the message should be appended to,
* not null
* @param name the (trimmed) name to be test against the candidate, not null
* @param candidate the candidate name (not null)
*/
private void informUponSimilarName(final StringBuffer messageBuffer, final String name,
final String candidate) {
if (name.equals(candidate)) {
// Don't suggest a name that is exactly the same as the one the
// user tried...
return;
}
// If the user provides a name that is in the right package, and gets
// the first 5 characters of the adapter class right (ignoring case),
// then suggest the candidate adapter class name.
if (name.regionMatches(true, 0, candidate, 0, PKG_LEN + 5)) {
messageBuffer.append(" Did you mean '");
messageBuffer.append(candidate);
messageBuffer.append("'?");
}
}
/**
* 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()
{
if (isDiagnosticsEnabled()) {
logDiagnostic("Trying to get log class from attribute '" + LOG_PROPERTY + "'");
}
String specifiedClass = (String) getAttribute(LOG_PROPERTY);
if (specifiedClass == null) { // @deprecated
if (isDiagnosticsEnabled()) {
logDiagnostic("Trying to get log class from attribute '" +
LOG_PROPERTY_OLD + "'");
}
specifiedClass = (String) getAttribute(LOG_PROPERTY_OLD);
}
if (specifiedClass == null) {
if (isDiagnosticsEnabled()) {
logDiagnostic("Trying to get log class from system property '" +
LOG_PROPERTY + "'");
}
try {
specifiedClass = getSystemProperty(LOG_PROPERTY, null);
} catch (SecurityException e) {
if (isDiagnosticsEnabled()) {
logDiagnostic("No access allowed to system property '" +
LOG_PROPERTY + "' - " + e.getMessage());
}
}
}
if (specifiedClass == null) { // @deprecated
if (isDiagnosticsEnabled()) {
logDiagnostic("Trying to get log class from system property '" +
LOG_PROPERTY_OLD + "'");
}
try {
specifiedClass = getSystemProperty(LOG_PROPERTY_OLD, null);
} catch (SecurityException e) {
if (isDiagnosticsEnabled()) {
logDiagnostic("No access allowed to system property '" +
LOG_PROPERTY_OLD + "' - " + e.getMessage());
}
}
}
// Remove any whitespace; it's never valid in a classname so its
// presence just means a user mistake. As we know what they meant,
// we may as well strip the spaces.
if (specifiedClass != null) {
specifiedClass = specifiedClass.trim();
}
return specifiedClass;
}
/**
* Attempts to load the given class, find a suitable constructor,
* and instantiate an instance of Log.
*
* @param logAdapterClassName 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, or null if the logging
* library associated with the specified adapter is not available.
*
* @throws LogConfigurationException if there was a serious error with
* configuration and the handleFlawedDiscovery method decided this
* problem was fatal.
*/
private Log createLogFromClass(String logAdapterClassName,
String logCategory,
boolean affectState)
throws LogConfigurationException {
if (isDiagnosticsEnabled()) {
logDiagnostic("Attempting to instantiate '" + logAdapterClassName + "'");
}
Object[] params = { logCategory };
Log logAdapter = null;
Constructor constructor = null;
Class logAdapterClass = null;
ClassLoader currentCL = getBaseClassLoader();
for(;;) {
// Loop through the classloader hierarchy trying to find
// a viable classloader.
logDiagnostic(
"Trying to load '"
+ logAdapterClassName
+ "' from classloader "
+ objectId(currentCL));
try {
if (isDiagnosticsEnabled()) {
// Show the location of the first occurrence of the .class file
// in the classpath. This is the location that ClassLoader.loadClass
// will load the class from -- unless the classloader is doing
// something weird.
URL url;
String resourceName = logAdapterClassName.replace('.', '/') + ".class";
if (currentCL != null) {
url = currentCL.getResource(resourceName );
} else {
url = ClassLoader.getSystemResource(resourceName + ".class");
}
if (url == null) {
logDiagnostic("Class '" + logAdapterClassName + "' [" + resourceName + "] cannot be found.");
} else {
logDiagnostic("Class '" + logAdapterClassName + "' was found at '" + url + "'");
}
}
Class c = null;
try {
c = Class.forName(logAdapterClassName, true, currentCL);
} catch (ClassNotFoundException originalClassNotFoundException) {
// The current classloader was unable to find the log adapter
// in this or any ancestor classloader. There's no point in
// trying higher up in the hierarchy in this case..
String msg = "" + originalClassNotFoundException.getMessage();
logDiagnostic(
"The log adapter '"
+ logAdapterClassName
+ "' is not available via classloader "
+ objectId(currentCL)
+ ": "
+ msg.trim());
try {
// Try the class classloader.
// This may work in cases where the TCCL
// does not contain the code executed or JCL.
// This behaviour indicates that the application
// classloading strategy is not consistent with the
// Java 1.2 classloading guidelines but JCL can
// and so should handle this case.
c = Class.forName(logAdapterClassName);
} catch (ClassNotFoundException secondaryClassNotFoundException) {
// no point continuing: this adapter isn't available
msg = "" + secondaryClassNotFoundException.getMessage();
logDiagnostic(
"The log adapter '"
+ logAdapterClassName
+ "' is not available via the LogFactoryImpl class classloader: "
+ msg.trim());
break;
}
}
constructor = c.getConstructor(logConstructorSignature);
Object o = constructor.newInstance(params);
// Note that we do this test after trying to create an instance
// [rather than testing Log.class.isAssignableFrom(c)] so that
// we don't complain about Log hierarchy problems when the
// adapter couldn't be instantiated anyway.
if (o instanceof Log) {
logAdapterClass = c;
logAdapter = (Log) o;
break;
}
// Oops, we have a potential problem here. An adapter class
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -