You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@commons.apache.org by sk...@apache.org on 2006/01/17 08:56:03 UTC
svn commit: r369712 -
/jakarta/commons/proper/logging/trunk/src/java/org/apache/commons/logging/LogFactory.java
Author: skitching
Date: Mon Jan 16 23:56:00 2006
New Revision: 369712
URL: http://svn.apache.org/viewcvs?rev=369712&view=rev
Log:
Implement feature to load the commons-logging.properties file with the highest priority value,
not just the first one found on the classpath.
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=369712&r1=369711&r2=369712&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 Mon Jan 16 23:56:00 2006
@@ -1,5 +1,5 @@
/*
- * Copyright 2001-2004 The Apache Software Foundation.
+ * Copyright 2001-2006 The Apache Software Foundation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -18,13 +18,14 @@
import java.io.BufferedReader;
+import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
-import java.io.FileOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
+import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Enumeration;
@@ -52,10 +53,17 @@
// ----------------------------------------------------- Manifest Constants
+ /**
+ * The name of the key in the config file used to specify the priority of
+ * that particular config file. The associated value is a floating-point
+ * number; higher values take priority over lower values.
+ */
+ public static final String PRIORITY_KEY = "priority";
/**
* The name of the property used to identify the LogFactory implementation
- * class name.
+ * class name. This can be used as a system property, or as an entry in a
+ * configuration properties file.
*/
public static final String FACTORY_PROPERTY =
"org.apache.commons.logging.LogFactory";
@@ -325,7 +333,6 @@
// --------------------------------------------------------- Static Methods
-
/**
* <p>Construct (if necessary) and return a <code>LogFactory</code>
* instance, using the following ordered lookup procedure to determine
@@ -352,7 +359,6 @@
* available or cannot be instantiated.
*/
public static LogFactory getFactory() throws LogConfigurationException {
-
// Identify the class loader we will be using
ClassLoader contextClassLoader = getContextClassLoader();
@@ -383,23 +389,9 @@
// As the properties file (if it exists) will be used one way or
// another in the end we may as well look for it first.
- Properties props=null;
- try {
- InputStream stream = getResourceAsStream(contextClassLoader,
- FACTORY_PROPERTIES);
-
- if (stream != null) {
- props = new Properties();
- props.load(stream);
- stream.close();
- }
- } catch (IOException e) {
- ; // ignore
- } catch (SecurityException e) {
- ; // ignore
- }
-
+ Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES);
+ // Determine which concrete LogFactory subclass to use.
// First, try a global system property
logDiagnostic(
"Looking for system property [" + FACTORY_PROPERTY
@@ -513,8 +505,9 @@
+ " via the same classloader that loaded this LogFactory"
+ " class (ie not looking in the context classloader).");
- // Note: we don't try to load the LogFactory implementation
- // via the context classloader here because:
+ // Note: unlike the above code which can try to load custom LogFactory
+ // implementations via the TCCL, we don't try to load the default LogFactory
+ // implementation via the context classloader because:
// * that can cause problems (see comments in newFactory method)
// * no-one should be customising the code of the default class
// Yes, we do give up the ability for the child to ship a newer
@@ -879,6 +872,8 @@
* @param factoryClass Fully qualified name of the <code>LogFactory</code>
* implementation class
* @param classLoader ClassLoader from which to load this class
+ * @param contextClassLoader is the context that this new factory will
+ * manage logging for.
*
* @exception LogConfigurationException if a suitable instance
* cannot be created
@@ -1016,6 +1011,12 @@
}
}
+ /**
+ * Applets may run in an environment where accessing resources of a loader is
+ * a secure operation, but where the commons-logging library has explicitly
+ * been granted permission for that operation. In this case, we need to
+ * run the operation using an AccessController.
+ */
private static InputStream getResourceAsStream(final ClassLoader loader,
final String name)
{
@@ -1029,6 +1030,129 @@
}
}
});
+ }
+
+ /**
+ * Given a filename, return an enumeration of URLs pointing to
+ * all the occurrences of that filename in the classpath.
+ * <p>
+ * This is just like ClassLoader.getResources except that the
+ * operation is done under an AccessController so that this method will
+ * succeed when this jarfile is privileged but the caller is not.
+ * This method must therefore remain private to avoid security issues.
+ * <p>
+ * If no instances are found, an Enumeration is returned whose
+ * hasMoreElements method returns false (ie an "empty" enumeration).
+ * If resources could not be listed for some reason, null is returned.
+ */
+ private static Enumeration getResources(final ClassLoader loader,
+ final String name)
+ {
+ PrivilegedAction action =
+ new PrivilegedAction() {
+ public Object run() {
+ try {
+ if (loader != null) {
+ return loader.getResources(name);
+ } else {
+ return ClassLoader.getSystemResources(name);
+ }
+ } catch(IOException e) {
+ logDiagnostic(
+ "Exception while trying to find configuration file "
+ + name + ":" + e.getMessage());
+ return null;
+ }
+ }
+ };
+ Object result = AccessController.doPrivileged(action);
+ return (Enumeration) result;
+ }
+
+ /**
+ * Given a URL that refers to a .properties file, load that file.
+ * This is done under an AccessController so that this method will
+ * succeed when this jarfile is privileged but the caller is not.
+ * This method must therefore remain private to avoid security issues.
+ * <p>
+ * Null is returned if the URL cannot be opened.
+ */
+ private static Properties getProperties(final URL url) {
+ PrivilegedAction action =
+ new PrivilegedAction() {
+ public Object run() {
+ try {
+ InputStream stream = url.openStream();
+ if (stream != null) {
+ Properties props = new Properties();
+ props.load(stream);
+ stream.close();
+ return props;
+ }
+ } catch(IOException e) {
+ logDiagnostic("Unable to read URL " + url);
+ }
+
+ return null;
+ }
+ };
+ return (Properties) AccessController.doPrivileged(action);
+ }
+
+ /**
+ * Locate a user-provided configuration file.
+ * <p>
+ * The classpath of the specified classLoader (usually the context classloader)
+ * is searched for properties files of the specified name. If none is found,
+ * null is returned. If more than one is found, then the file with the greatest
+ * value for its PRIORITY property is returned. If multiple files have the
+ * same PRIORITY value then the first in the classpath is returned.
+ * <p>
+ * This differs from the 1.0.x releases; those always use the first one found.
+ * However as the priority is a new field, this change is backwards compatible.
+ * <p>
+ * The purpose of the priority field is to allow a webserver administrator to
+ * override logging settings in all webapps by placing a commons-logging.properties
+ * file in a shared classpath location with a priority > 0; this overrides any
+ * commons-logging.properties files without priorities which are in the
+ * webapps. Webapps can also use explicit priorities to override a configuration
+ * file in the shared classpath if needed.
+ */
+ private static final Properties getConfigurationFile(
+ ClassLoader classLoader, String fileName) {
+
+ Properties props = null;
+ double priority = 0.0;
+ try {
+ Enumeration urls = getResources(classLoader, fileName);
+
+ if (urls == null) {
+ return null;
+ }
+
+ while (urls.hasMoreElements()) {
+ URL url = (URL) urls.nextElement();
+
+ Properties newProps = getProperties(url);
+ if (newProps != null) {
+ if (props == null) {
+ props = newProps;
+ } else {
+ String newPriorityStr = newProps.getProperty(PRIORITY_KEY);
+ if (newPriorityStr != null) {
+ double newPriority = Double.valueOf(newPriorityStr).doubleValue();
+ if (newPriority > priority) {
+ props = newProps;
+ priority = newPriority;
+ }
+ }
+ }
+ }
+ }
+ } catch (SecurityException e) {
+ logDiagnostic("SecurityException thrown");
+ }
+ return props;
}
/**
---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org