    001/*
    002 * Copyright 2001-2004 The Apache Software Foundation.
    003 *
    004 * Licensed under the Apache License, Version 2.0 (the "License");
    005 * you may not use this file except in compliance with the License.
    006 * You may obtain a copy of the License at
    007 *
    008 *      http://www.apache.org/licenses/LICENSE-2.0
    009 *
    010 * Unless required by applicable law or agreed to in writing, software
    011 * distributed under the License is distributed on an "AS IS" BASIS,
    012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    013 * See the License for the specific language governing permissions and
    014 * limitations under the License.
    015 */
    016
    017package org.apache.commons.logging;
    018
    019import java.util.Hashtable;
    020
    021import org.apache.commons.logging.impl.SLF4JLogFactory;
    022
    023/**
    024 * <p>
    025 * Factory for creating {@link Log} instances, which always delegates to an
    026 * instance of {@link SLF4JLogFactory}.
    027 *
    028 * </p>
    029 *
    030 * @author Craig R. McClanahan
    031 * @author Costin Manolache
    032 * @author Richard A. Sitze
    033 * @author Ceki G&uuml;lc&uuml;
    034 */
    035
    036@SuppressWarnings("rawtypes")
    037public abstract class LogFactory {
    038
    039    static String UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J = "http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j";
    040
    041    static LogFactory logFactory = new SLF4JLogFactory();
    042
    043    /**
    044     * The name (<code>priority</code>) of the key in the config file used to
    045     * specify the priority of that particular config file. The associated value
    046     * is a floating-point number; higher values take priority over lower values.
    047     *
    048     * <p>
    049     * This property is not used but preserved here for compatibility.
    050     */
    051    public static final String PRIORITY_KEY = "priority";
    052
    053    /**
    054     * The name (<code>use_tccl</code>) of the key in the config file used to
    055     * specify whether logging classes should be loaded via the thread context
    056     * class loader (TCCL), or not. By default, the TCCL is used.
    057     *
    058     * <p>
    059     * This property is not used but preserved here for compatibility.
    060     */
    061    public static final String TCCL_KEY = "use_tccl";
    062
    063    /**
    064     * The name of the property used to identify the LogFactory implementation
    065     * class name.
    066     * <p>
    067     * This property is not used but preserved here for compatibility.
    068     */
    069    public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";
    070
    071    /**
    072     * The fully qualified class name of the fallback <code>LogFactory</code>
    073     * implementation class to use, if no other can be found.
    074     *
    075     * <p>
    076     * This property is not used but preserved here for compatibility.
    077     */
    078    public static final String FACTORY_DEFAULT = "org.apache.commons.logging.impl.SLF4JLogFactory";
    079
    080    /**
    081     * The name of the properties file to search for.
    082     * <p>
    083     * This property is not used but preserved here for compatibility.
    084     */
    085    public static final String FACTORY_PROPERTIES = "commons-logging.properties";
    086
    087    /**
    088     * JDK1.3+ <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider">
    089     * 'Service Provider' specification</a>.
    090     * <p>
    091     * This property is not used but preserved here for compatibility.
    092     */
    093    protected static final String SERVICE_ID = "META-INF/services/org.apache.commons.logging.LogFactory";
    094
    095    /**
    096     * The name (<code>org.apache.commons.logging.diagnostics.dest</code>) of
    097     * the property used to enable internal commons-logging diagnostic output, in
    098     * order to get information on what logging implementations are being
    099     * discovered, what classloaders they are loaded through, etc.
    100     *
    101     * <p>
    102     * This property is not used but preserved here for compatibility.
    103     */
    104    public static final String DIAGNOSTICS_DEST_PROPERTY = "org.apache.commons.logging.diagnostics.dest";
    105
    106    /**
    107     * <p>
    108     * Setting this system property value allows the <code>Hashtable</code> used
    109     * to store classloaders to be substituted by an alternative implementation.
    110     * <p>
    111     * This property is not used but preserved here for compatibility.
    112     */
    113    public static final String HASHTABLE_IMPLEMENTATION_PROPERTY = "org.apache.commons.logging.LogFactory.HashtableImpl";
    114
    115    /**
    116     * The previously constructed <code>LogFactory</code> instances, keyed by
    117     * the <code>ClassLoader</code> with which it was created.
    118     *
    119     * <p>
    120     * This property is not used but preserved here for compatibility.
    121     */
    122    protected static Hashtable factories = null;
    123
    124    /**
    125     * <p>
    126     * This property is not used but preserved here for compatibility.
    127     */
    128    protected static LogFactory nullClassLoaderFactory = null;
    129
    130    /**
    131     * Protected constructor that is not available for public use.
    132     */
    133    protected LogFactory() {
    134    }
    135
    136    // --------------------------------------------------------- Public Methods
    137
    138    /**
    139     * Return the configuration attribute with the specified name (if any), or
    140     * <code>null</code> if there is no such attribute.
    141     *
    142     * @param name Name of the attribute to return
    143     * @return configuration attribute
    144     */
    145    public abstract Object getAttribute(String name);
    146
    147    /**
    148     * Return an array containing the names of all currently defined configuration
    149     * attributes. If there are no such attributes, a zero length array is
    150     * returned.
    151     *
    152     * @return names of all currently defined configuration attributes
    153     */
    154    public abstract String[] getAttributeNames();
    155
    156    /**
    157     * Convenience method to derive a name from the specified class and call
    158     * <code>getInstance(String)</code> with it.
    159     *
    160     * @param clazz
    161     *                Class for which a suitable Log name will be derived
    162     *
    163     * @exception LogConfigurationException
    164     *                    if a suitable <code>Log</code> instance cannot be
    165     *                    returned
    166     */
    167    public abstract Log getInstance(Class clazz) throws LogConfigurationException;
    168
    169    /**
    170     * <p>
    171     * Construct (if necessary) and return a <code>Log</code> instance, using
    172     * the factory's current set of configuration attributes.
    173     * </p>
    174     *
    175     * <p>
    176     * <strong>NOTE </strong>- Depending upon the implementation of the
    177     * <code>LogFactory</code> you are using, the <code>Log</code> instance
    178     * you are returned may or may not be local to the current application, and
    179     * may or may not be returned again on a subsequent call with the same name
    180     * argument.
    181     * </p>
    182     *
    183     * @param name
    184     *                Logical name of the <code>Log</code> instance to be
    185     *                returned (the meaning of this name is only known to the
    186     *                underlying logging implementation that is being wrapped)
    187     *
    188     * @exception LogConfigurationException
    189     *                    if a suitable <code>Log</code> instance cannot be
    190     *                    returned
    191     */
    192    public abstract Log getInstance(String name) throws LogConfigurationException;
    193
    194    /**
    195     * Release any internal references to previously created {@link Log}instances
    196     * returned by this factory. This is useful in environments like servlet
    197     * containers, which implement application reloading by throwing away a
    198     * ClassLoader. Dangling references to objects in that class loader would
    199     * prevent garbage collection.
    200     */
    201    public abstract void release();
    202
    203    /**
    204     * Remove any configuration attribute associated with the specified name. If
    205     * there is no such attribute, no action is taken.
    206     *
    207     * @param name
    208     *                Name of the attribute to remove
    209     */
    210    public abstract void removeAttribute(String name);
    211
    212    /**
    213     * Set the configuration attribute with the specified name. Calling this with
    214     * a <code>null</code> value is equivalent to calling
    215     * <code>removeAttribute(name)</code>.
    216     *
    217     * @param name
    218     *                Name of the attribute to set
    219     * @param value
    220     *                Value of the attribute to set, or <code>null</code> to
    221     *                remove any setting for this attribute
    222     */
    223    public abstract void setAttribute(String name, Object value);
    224
    225    // --------------------------------------------------------- Static Methods
    226
    227    /**
    228     * <p>
    229     * Construct (if necessary) and return a <code>LogFactory</code> instance,
    230     * using the following ordered lookup procedure to determine the name of the
    231     * implementation class to be loaded.
    232     * </p>
    233     * <ul>
    234     * <li>The <code>org.apache.commons.logging.LogFactory</code> system
    235     * property.</li>
    236     * <li>The JDK 1.3 Service Discovery mechanism</li>
    237     * <li>Use the properties file <code>commons-logging.properties</code>
    238     * file, if found in the class path of this class. The configuration file is
    239     * in standard <code>java.util.Properties</code> format and contains the
    240     * fully qualified name of the implementation class with the key being the
    241     * system property defined above.</li>
    242     * <li>Fall back to a default implementation class (
    243     * <code>org.apache.commons.logging.impl.SLF4FLogFactory</code>).</li>
    244     * </ul>
    245     *
    246     * <p>
    247     * <em>NOTE</em>- If the properties file method of identifying the
    248     * <code>LogFactory</code> implementation class is utilized, all of the
    249     * properties defined in this file will be set as configuration attributes on
    250     * the corresponding <code>LogFactory</code> instance.
    251     * </p>
    252     *
    253     * @exception LogConfigurationException
    254     *                    if the implementation class is not available or cannot
    255     *                    be instantiated.
    256     */
    257    public static LogFactory getFactory() throws LogConfigurationException {
    258        return logFactory;
    259    }
    260
    261    /**
    262     * Convenience method to return a named logger, without the application having
    263     * to care about factories.
    264     *
    265     * @param clazz
    266     *                Class from which a log name will be derived
    267     *
    268     * @exception LogConfigurationException
    269     *                    if a suitable <code>Log</code> instance cannot be
    270     *                    returned
    271     */
    272    public static Log getLog(Class clazz) throws LogConfigurationException {
    273        return (getFactory().getInstance(clazz));
    274    }
    275
    276    /**
    277     * Convenience method to return a named logger, without the application having
    278     * to care about factories.
    279     *
    280     * @param name
    281     *                Logical name of the <code>Log</code> instance to be
    282     *                returned (the meaning of this name is only known to the
    283     *                underlying logging implementation that is being wrapped)
    284     *
    285     * @exception LogConfigurationException
    286     *                    if a suitable <code>Log</code> instance cannot be
    287     *                    returned
    288     */
    289    public static Log getLog(String name) throws LogConfigurationException {
    290        return (getFactory().getInstance(name));
    291    }
    292
    293    /**
    294     * Release any internal references to previously created {@link LogFactory}
    295     * instances that have been associated with the specified class loader (if
    296     * any), after calling the instance method <code>release()</code> on each of
    297     * them.
    298     *
    299     * @param classLoader
    300     *                ClassLoader for which to release the LogFactory
    301     */
    302    public static void release(ClassLoader classLoader) {
    303        // since SLF4J based JCL does not make use of classloaders, there is nothing
    304        // to do here
    305    }
    306
    307    /**
    308     * Release any internal references to previously created {@link LogFactory}
    309     * instances, after calling the instance method <code>release()</code> on
    310     * each of them. This is useful in environments like servlet containers, which
    311     * implement application reloading by throwing away a ClassLoader. Dangling
    312     * references to objects in that class loader would prevent garbage
    313     * collection.
    314     */
    315    public static void releaseAll() {
    316        // since SLF4J based JCL does not make use of classloaders, there is nothing
    317        // to do here
    318    }
    319
    320    /**
    321     * Returns a string that uniquely identifies the specified object, including
    322     * its class.
    323     * <p>
    324     * The returned string is of form "classname@hashcode", i.e. is the same as the
    325     * return value of the Object.toString() method, but works even when the
    326     * specified object's class has overridden the toString method.
    327     *
    328     * @param o
    329     *                may be null.
    330     * @return a string of form classname@hashcode, or "null" if param o is null.
    331     * @since 1.1
    332     */
    333    public static String objectId(Object o) {
    334        if (o == null) {
    335            return "null";
    336        } else {
    337            return o.getClass().getName() + "@" + System.identityHashCode(o);
    338        }
    339    }
    340
    341    // protected methods which were added in JCL 1.1. These are not used
    342    // by SLF4JLogFactory
    343
    344    /**
    345     * This method exists to ensure signature compatibility.
    346     */
    347    protected static Object createFactory(String factoryClass, ClassLoader classLoader) {
    348        throw new UnsupportedOperationException("Operation [factoryClass] is not supported in jcl-over-slf4j. See also "
    349                        + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
    350    }
    351
    352    /**
    353     * This method exists to ensure signature compatibility.
    354     */
    355    protected static ClassLoader directGetContextClassLoader() {
    356        throw new UnsupportedOperationException("Operation [directGetContextClassLoader] is not supported in jcl-over-slf4j. See also "
    357                        + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
    358    }
    359
    360    /**
    361     * This method exists to ensure signature compatibility.
    362     */
    363    protected static ClassLoader getContextClassLoader() throws LogConfigurationException {
    364        throw new UnsupportedOperationException("Operation [getContextClassLoader] is not supported in jcl-over-slf4j. See also "
    365                        + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
    366    }
    367
    368    /**
    369     * This method exists to ensure signature compatibility.
    370     */
    371    protected static ClassLoader getClassLoader(Class clazz) {
    372        throw new UnsupportedOperationException("Operation [getClassLoader] is not supported in jcl-over-slf4j. See also "
    373                        + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
    374    }
    375
    376    /**
    377     * This method exists to ensure signature compatibility.
    378     */
    379    protected static boolean isDiagnosticsEnabled() {
    380        throw new UnsupportedOperationException("Operation [isDiagnosticsEnabled] is not supported in jcl-over-slf4j. See also "
    381                        + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
    382    }
    383
    384    /**
    385     * This method exists to ensure signature compatibility.
    386     */
    387    protected static void logRawDiagnostic(String msg) {
    388        throw new UnsupportedOperationException("Operation [logRawDiagnostic] is not supported in jcl-over-slf4j. See also "
    389                        + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
    390    }
    391
    392    /**
    393     * This method exists to ensure signature compatibility.
    394     */
    395    protected static LogFactory newFactory(final String factoryClass, final ClassLoader classLoader, final ClassLoader contextClassLoader) {
    396        throw new UnsupportedOperationException("Operation [logRawDiagnostic] is not supported in jcl-over-slf4j. See also "
    397                        + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
    398    }
    399
    400    /**
    401     * This method exists to ensure signature compatibility.
    402     */
    403    protected static LogFactory newFactory(final String factoryClass, final ClassLoader classLoader) {
    404        throw new UnsupportedOperationException("Operation [newFactory] is not supported in jcl-over-slf4j. See also "
    405                        + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
    406    }
    407
    408}