craigmcc 02/02/13 16:19:03
Modified: logging/src/java/org/apache/commons/logging LogFactory.java
LogSource.java
logging/src/java/org/apache/commons/logging/impl
LogFactoryImpl.java
Log:
Improvements to the new LogFactory APIs, based on feedback from Costin and
Jon plus some additional thought about using it in a multi-class-loader
environment (like Tomcat):
* Changed newFactory() to getFactory(), and implemented a cache of
previously created factory instances (one per class loader). This
avoids potentially expensive and redundant discovery operations.
* Added convenient static getLog() method so a typical application
component can initialize it's Log instance like this:
Log log = LogFactory.getLog("com.mycompany.mypackage.MyClass");
* Added variants of getInstance() and getLog() that take a Class
parameter instead of a String. LogSource had this convenience
feature, and there's no reason not to keep it.
* Added release() and releaseAll() methods to instruct the factory
instances to release any cached references to other LogFactory
or Log instances. This is important, for example, if you put
commons-logging.jar in Tomcat's shared "lib" directory, and then
use the application reload facility. The references maintained
here would otherwise prevent garbage collection of the old
webapp class loader once a reload takes place.
* Added a note on getInstance() that you can make no assumptions
about whether or not the actual Log instance you get back is
shared or not. The actual sharability is a feature of the
LogFactory implementation you are using, and what kind of a
class loader environment you ae installing.
* Deprecated LogSource, but left it there to ease transition of
existing code using it.
Revision Changes Path
1.2 +141 -31
jakarta-commons/logging/src/java/org/apache/commons/logging/LogFactory.java
Index: LogFactory.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/LogFactory.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- LogFactory.java 13 Feb 2002 02:18:11 -0000 1.1
+++ LogFactory.java 14 Feb 2002 00:19:03 -0000 1.2
@@ -1,7 +1,7 @@
/*
- * $Header:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/LogFactory.java,v
1.1 2002/02/13 02:18:11 craigmcc Exp $
- * $Revision: 1.1 $
- * $Date: 2002/02/13 02:18:11 $
+ * $Header:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/LogFactory.java,v
1.2 2002/02/14 00:19:03 craigmcc Exp $
+ * $Revision: 1.2 $
+ * $Date: 2002/02/14 00:19:03 $
*
* ====================================================================
*
@@ -67,6 +67,7 @@
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Enumeration;
+import java.util.Hashtable;
import java.util.Properties;
@@ -81,7 +82,7 @@
*
* @author Craig R. McClanahan
* @author Costin Manolache
- * @version $Revision: 1.1 $ $Date: 2002/02/13 02:18:11 $
+ * @version $Revision: 1.2 $ $Date: 2002/02/14 00:19:03 $
*/
public abstract class LogFactory {
@@ -143,9 +144,28 @@
/**
+ * Convenience method to derive a name from the specified class and
+ * call <code>getInstance(String)</code> with it.
+ *
+ * @param clazz Class for which a suitable Log name will be derived
+ *
+ * @exception LogConfigurationException if a suitable <code>Log</code>
+ * instance cannot be returned
+ */
+ public abstract Log getInstance(Class clazz)
+ throws LogConfigurationException;
+
+
+ /**
* <p>Construct (if necessary) and return a <code>Log</code> instance,
* using the factory's current set of configuration attributes.</p>
*
+ * <p><strong>NOTE</strong> - Depending upon the implementation of
+ * the <code>LogFactory</code> you are using, the <code>Log</code>
+ * instance you are returned may or may not be local to the current
+ * application, and may or may not be returned again on a subsequent
+ * call with the same name argument.</p>
+ *
* @param name Logical name of the <code>Log</code> instance to be
* returned (the meaning of this name is only known to the underlying
* logging implementation that is being wrapped)
@@ -158,6 +178,16 @@
/**
+ * Release any internal references to previously created {@link Log}
+ * instances returned by this factory. This is useful environments
+ * like servlet containers, which implement application reloading by
+ * throwing away a ClassLoader. Dangling references to objects in that
+ * class loader would prevent garbage collection.
+ */
+ public abstract void release();
+
+
+ /**
* Remove any configuration attribute associated with the specified name.
* If there is no such attribute, no action is taken.
*
@@ -178,13 +208,23 @@
public abstract void setAttribute(String name, Object value);
+ // ------------------------------------------------------- Static Variables
+
+
+ /**
+ * The previously constructed <code>LogFactory</code> instances, keyed by
+ * the <code>ClassLoader</code> with which it was created.
+ */
+ protected static Hashtable factories = new Hashtable();
+
+
// --------------------------------------------------------- Static Methods
/**
- * <p>Construct and return a new <code>LogFactory</code> instance, using
- * the following ordered lookup procedure to determine the name of the
- * implementation class to be loaded:</p>
+ * <p>Construct (if necessary) and return a <code>LogFactory</code>
+ * instance, using the following ordered lookup procedure to determine
+ * the name of the implementation class to be loaded:</p>
* <ul>
* <li>The <code>org.apache.commons.logging.LogFactory</code> system
* property.</li>
@@ -205,48 +245,118 @@
* @exception LogConfigurationException if the implementation class is not
* available or cannot be instantiated.
*/
- public static LogFactory newFactory() throws LogConfigurationException {
+ public static LogFactory getFactory() throws LogConfigurationException {
// Identify the class loader we will be using
ClassLoader classLoader = findClassLoader();
+ // Return any previously registered factory for this class loader
+ LogFactory factory = (LogFactory) factories.get(classLoader);
+ if (factory != null) {
+ return (factory);
+ }
+
// First, try the system property
try {
String factoryClass = System.getProperty(FACTORY_PROPERTY);
if (factoryClass != null) {
- return (newInstance(factoryClass, classLoader));
+ factory = newFactory(factoryClass, classLoader);
}
} catch (SecurityException e) {
;
}
// Second, try a properties file
- try {
- InputStream stream =
- classLoader.getResourceAsStream(FACTORY_PROPERTIES);
- if (stream != null) {
- Properties props = new Properties();
- props.load(stream);
- stream.close();
- String factoryClass = props.getProperty(FACTORY_PROPERTY);
- if (factoryClass != null) {
- LogFactory instance =
- newInstance(factoryClass, classLoader);
- Enumeration names = props.propertyNames();
- while (names.hasMoreElements()) {
- String name = (String) names.nextElement();
- String value = props.getProperty(name);
- instance.setAttribute(name, value);
+ if (factory == null) {
+ try {
+ InputStream stream =
+ classLoader.getResourceAsStream(FACTORY_PROPERTIES);
+ if (stream != null) {
+ Properties props = new Properties();
+ props.load(stream);
+ stream.close();
+ String factoryClass = props.getProperty(FACTORY_PROPERTY);
+ if (factoryClass != null) {
+ factory = newFactory(factoryClass, classLoader);
+ Enumeration names = props.propertyNames();
+ while (names.hasMoreElements()) {
+ String name = (String) names.nextElement();
+ String value = props.getProperty(name);
+ factory.setAttribute(name, value);
+ }
}
- return (instance);
}
+ } catch (IOException e) {
+ } catch (SecurityException e) {
}
- } catch (IOException e) {
- } catch (SecurityException e) {
}
// Third, try the fallback implementation class
- return (newInstance(FACTORY_DEFAULT, classLoader));
+ if (factory == null) {
+ factory = newFactory(FACTORY_DEFAULT, classLoader);
+ }
+
+ // Cache and return the new factory instance
+ factories.put(classLoader, factory);
+ return (factory);
+
+ }
+
+
+ /**
+ * Convenience method to return a named logger, without the application
+ * having to care about factories.
+ *
+ * @param clazz Class for which a log name will be derived
+ *
+ * @exception LogConfigurationException if a suitable <code>Log</code>
+ * instance cannot be returned
+ */
+ public static Log getLog(Class clazz)
+ throws LogConfigurationException {
+
+ return (getFactory().getInstance(clazz));
+
+ }
+
+
+ /**
+ * Convenience method to return a named logger, without the application
+ * having to care about factories.
+ *
+ * @param name Logical name of the <code>Log</code> instance to be
+ * returned (the meaning of this name is only known to the underlying
+ * logging implementation that is being wrapped)
+ *
+ * @exception LogConfigurationException if a suitable <code>Log</code>
+ * instance cannot be returned
+ */
+ public static Log getLog(String name)
+ throws LogConfigurationException {
+
+ return (getFactory().getInstance(name));
+
+ }
+
+
+ /**
+ * Release any internal references to previously created {@link LogFactory}
+ * instances, after calling the instance method <code>release()</code> on
+ * each of them. This is useful environments like servlet containers,
+ * which implement application reloading by throwing away a ClassLoader.
+ * Dangling references to objects in that class loader would prevent
+ * garbage collection.
+ */
+ public static void releaseAll() {
+
+ synchronized (factories) {
+ Enumeration elements = factories.elements();
+ while (elements.hasMoreElements()) {
+ LogFactory element = (LogFactory) elements.nextElement();
+ element.release();
+ }
+ factories.clear();
+ }
}
@@ -308,8 +418,8 @@
* @exception LogConfigurationException if a suitable instance
* cannot be created
*/
- private static LogFactory newInstance(String factoryClass,
- ClassLoader classLoader)
+ protected static LogFactory newFactory(String factoryClass,
+ ClassLoader classLoader)
throws LogConfigurationException {
try {
1.13 +7 -4
jakarta-commons/logging/src/java/org/apache/commons/logging/LogSource.java
Index: LogSource.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/LogSource.java,v
retrieving revision 1.12
retrieving revision 1.13
diff -u -r1.12 -r1.13
--- LogSource.java 3 Feb 2002 01:31:54 -0000 1.12
+++ LogSource.java 14 Feb 2002 00:19:03 -0000 1.13
@@ -1,7 +1,7 @@
/*
- * $Header:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/LogSource.java,v
1.12 2002/02/03 01:31:54 sanders Exp $
- * $Revision: 1.12 $
- * $Date: 2002/02/03 01:31:54 $
+ * $Header:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/LogSource.java,v
1.13 2002/02/14 00:19:03 craigmcc Exp $
+ * $Revision: 1.13 $
+ * $Date: 2002/02/14 00:19:03 $
*
* ====================================================================
*
@@ -93,8 +93,11 @@
* <li>At runtime, call <code>LogSource.setLogImplementation()</code>.</li>
* </ul>
*
+ * @deprecated Use {@link LogFactory} instead - The default factory
+ * implementation performs exactly the same algorithm as this class did
+ *
* @author Rod Waldhoff
- * @version $Id: LogSource.java,v 1.12 2002/02/03 01:31:54 sanders Exp $
+ * @version $Id: LogSource.java,v 1.13 2002/02/14 00:19:03 craigmcc Exp $
*/
public class LogSource {
1.2 +41 -4
jakarta-commons/logging/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java
Index: LogFactoryImpl.java
===================================================================
RCS file:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- LogFactoryImpl.java 13 Feb 2002 02:18:11 -0000 1.1
+++ LogFactoryImpl.java 14 Feb 2002 00:19:03 -0000 1.2
@@ -1,7 +1,7 @@
/*
- * $Header:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java,v
1.1 2002/02/13 02:18:11 craigmcc Exp $
- * $Revision: 1.1 $
- * $Date: 2002/02/13 02:18:11 $
+ * $Header:
/home/cvs/jakarta-commons/logging/src/java/org/apache/commons/logging/impl/LogFactoryImpl.java,v
1.2 2002/02/14 00:19:03 craigmcc Exp $
+ * $Revision: 1.2 $
+ * $Date: 2002/02/14 00:19:03 $
*
* ====================================================================
*
@@ -101,7 +101,7 @@
*
* @author Rod Waldhoff
* @author Craig R. McClanahan
- * @version $Revision: 1.1 $ $Date: 2002/02/13 02:18:11 $
+ * @version $Revision: 1.2 $ $Date: 2002/02/14 00:19:03 $
*/
public class LogFactoryImpl extends LogFactory {
@@ -229,9 +229,32 @@
/**
+ * Convenience method to derive a name from the specified class and
+ * call <code>getInstance(String)</code> with it.
+ *
+ * @param clazz Class for which a suitable Log name will be derived
+ *
+ * @exception LogConfigurationException if a suitable <code>Log</code>
+ * instance cannot be returned
+ */
+ public Log getInstance(Class clazz)
+ throws LogConfigurationException {
+
+ return (getInstance(clazz.getName()));
+
+ }
+
+
+ /**
* <p>Construct (if necessary) and return a <code>Log</code> instance,
* using the factory's current set of configuration attributes.</p>
*
+ * <p><strong>NOTE</strong> - Depending upon the implementation of
+ * the <code>LogFactory</code> you are using, the <code>Log</code>
+ * instance you are returned may or may not be local to the current
+ * application, and may or may not be returned again on a subsequent
+ * call with the same name argument.</p>
+ *
* @param name Logical name of the <code>Log</code> instance to be
* returned (the meaning of this name is only known to the underlying
* logging implementation that is being wrapped)
@@ -248,6 +271,20 @@
instances.put(name, instance);
}
return (instance);
+
+ }
+
+
+ /**
+ * Release any internal references to previously created {@link Log}
+ * instances returned by this factory. This is useful environments
+ * like servlet containers, which implement application reloading by
+ * throwing away a ClassLoader. Dangling references to objects in that
+ * class loader would prevent garbage collection.
+ */
+ public void release() {
+
+ instances.clear();
}
--
To unsubscribe, e-mail: <mailto:[EMAIL PROTECTED]>
For additional commands, e-mail: <mailto:[EMAIL PROTECTED]>