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]>

Reply via email to