View Javadoc

    1   /*
    2    * Copyright 2001-2004 The Apache Software Foundation.
    3    *
    4    * Licensed under the Apache License, Version 2.0 (the "License");
    5    * you may not use this file except in compliance with the License.
    6    * You may obtain a copy of the License at
    7    *
    8    *      http://www.apache.org/licenses/LICENSE-2.0
    9    *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16
    17  package org.apache.commons.logging.impl;
    18
    19  import org.apache.commons.logging.Log;
    20  import org.apache.commons.logging.LogConfigurationException;
    21  import org.apache.commons.logging.LogFactory;
    22  import org.slf4j.Logger;
    23  import org.slf4j.LoggerFactory;
    24  import org.slf4j.spi.LocationAwareLogger;
    25
    26  import java.util.ArrayList;
    27  import java.util.Enumeration;
    28  import java.util.Hashtable;
    29  import java.util.List;
    30  import java.util.concurrent.ConcurrentHashMap;
    31  import java.util.concurrent.ConcurrentMap;
    32
    33  /**
    34   * <p>
    35   * Concrete subclass of {@link LogFactory} which always delegates to the
    36   * {@link LoggerFactory org.slf4j.LoggerFactory} class.
    37   *
    38   * <p>
    39   * This factory generates instances of {@link SLF4JLog}. It will remember
    40   * previously created instances for the same name, and will return them on
    41   * repeated requests to the <code>getInstance()</code> method.
    42   *
    43   * <p>
    44   * This implementation ignores any configured attributes.
    45   * </p>
    46   *
    47   * @author Rod Waldhoff
    48   * @author Craig R. McClanahan
    49   * @author Richard A. Sitze
    50   * @author Ceki G&uuml;lc&uuml;
    51   */
    52  @SuppressWarnings("rawtypes")
    53  public class SLF4JLogFactory extends LogFactory {
    54
    55      // ----------------------------------------------------------- Constructors
    56
    57      /**
    58       * The {@link org.apache.commons.logging.Log}instances that have already been
    59       * created, keyed by logger name.
    60       */
    61      ConcurrentMap<String, Log> loggerMap;
    62
    63      /**
    64       * Public no-arguments constructor required by the lookup mechanism.
    65       */
    66      public SLF4JLogFactory() {
    67          loggerMap = new ConcurrentHashMap<String, Log>();
    68      }
    69
    70      // ----------------------------------------------------- Manifest Constants
    71
    72      /**
    73       * The name of the system property identifying our {@link Log}implementation
    74       * class.
    75       */
    76      public static final String LOG_PROPERTY = "org.apache.commons.logging.Log";
    77
    78      // ----------------------------------------------------- Instance Variables
    79
    80      /**
    81       * Configuration attributes.
    82       */
    83      protected Hashtable attributes = new Hashtable();
    84
    85      // --------------------------------------------------------- Public Methods
    86
    87      /**
    88       * Return the configuration attribute with the specified name (if any), or
    89       * <code>null</code> if there is no such attribute.
    90       *
    91       * @param name
    92       *          Name of the attribute to return
    93       */
    94      public Object getAttribute(String name) {
    95
    96          return (attributes.get(name));
    97
    98      }
    99
    100     /**
    101      * Return an array containing the names of all currently defined configuration
    102      * attributes. If there are no such attributes, a zero length array is
    103      * returned.
    104      */
    105     @SuppressWarnings("unchecked")
    106     public String[] getAttributeNames() {
    107
    108         List<String> names = new ArrayList<String>();
    109         Enumeration<String> keys = attributes.keys();
    110         while (keys.hasMoreElements()) {
    111             names.add((String) keys.nextElement());
    112         }
    113         String results[] = new String[names.size()];
    114         for (int i = 0; i < results.length; i++) {
    115             results[i] = (String) names.get(i);
    116         }
    117         return (results);
    118
    119     }
    120
    121     /**
    122      * Convenience method to derive a name from the specified class and call
    123      * <code>getInstance(String)</code> with it.
    124      *
    125      * @param clazz
    126      *          Class for which a suitable Log name will be derived
    127      *
    128      * @exception LogConfigurationException
    129      *              if a suitable <code>Log</code> instance cannot be returned
    130      */
    131     public Log getInstance(Class clazz) throws LogConfigurationException {
    132         return (getInstance(clazz.getName()));
    133     }
    134
    135     /**
    136      * <p>
    137      * Construct (if necessary) and return a <code>Log</code> instance, using
    138      * the factory's current set of configuration attributes.
    139      * </p>
    140      *
    141      * @param name
    142      *          Logical name of the <code>Log</code> instance to be returned
    143      *          (the meaning of this name is only known to the underlying logging
    144      *          implementation that is being wrapped)
    145      *
    146      * @exception LogConfigurationException
    147      *              if a suitable <code>Log</code> instance cannot be returned
    148      */
    149     public Log getInstance(String name) throws LogConfigurationException {
    150         Log instance = loggerMap.get(name);
    151         if (instance != null) {
    152             return instance;
    153         } else {
    154             Log newInstance;
    155             Logger slf4jLogger = LoggerFactory.getLogger(name);
    156             if (slf4jLogger instanceof LocationAwareLogger) {
    157                 newInstance = new SLF4JLocationAwareLog((LocationAwareLogger) slf4jLogger);
    158             } else {
    159                 newInstance = new SLF4JLog(slf4jLogger);
    160             }
    161             Log oldInstance = loggerMap.putIfAbsent(name, newInstance);
    162             return oldInstance == null ? newInstance : oldInstance;
    163         }
    164     }
    165
    166     /**
    167      * Release any internal references to previously created
    168      * {@link org.apache.commons.logging.Log}instances returned by this factory.
    169      * This is useful in environments like servlet containers, which implement
    170      * application reloading by throwing away a ClassLoader. Dangling references
    171      * to objects in that class loader would prevent garbage collection.
    172      */
    173     public void release() {
    174         // This method is never called by jcl-over-slf4j classes. However,
    175         // in certain deployment scenarios, in particular if jcl-over-slf4j.jar
    176         // is
    177         // in the the web-app class loader and the official commons-logging.jar is
    178         // deployed in some parent class loader (e.g. commons/lib), then it is
    179         // possible
    180         // for the parent class loader to mask the classes shipping in
    181         // jcl-over-slf4j.jar.
    182         System.out.println("WARN: The method " + SLF4JLogFactory.class + "#release() was invoked.");
    183         System.out.println("WARN: Please see http://www.slf4j.org/codes.html#release for an explanation.");
    184         System.out.flush();
    185     }
    186
    187     /**
    188      * Remove any configuration attribute associated with the specified name. If
    189      * there is no such attribute, no action is taken.
    190      *
    191      * @param name
    192      *          Name of the attribute to remove
    193      */
    194     public void removeAttribute(String name) {
    195         attributes.remove(name);
    196     }
    197
    198     /**
    199      * Set the configuration attribute with the specified name. Calling this with
    200      * a <code>null</code> value is equivalent to calling
    201      * <code>removeAttribute(name)</code>.
    202      *
    203      * @param name
    204      *          Name of the attribute to set
    205      * @param value
    206      *          Value of the attribute to set, or <code>null</code> to remove
    207      *          any setting for this attribute
    208      */
    209     @SuppressWarnings("unchecked")
    210     public void setAttribute(String name, Object value) {
    211
    212         if (value == null) {
    213             attributes.remove(name);
    214         } else {
    215             attributes.put(name, value);
    216         }
    217
    218     }
    219 }