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;
18  
19  import java.util.Hashtable;
20  
21  import org.apache.commons.logging.impl.SLF4JLogFactory;
22  
23  /**
24   * <p>
25   * Factory for creating {@link Log} instances, which always delegates to an
26   * instance of {@link SLF4JLogFactory}.
27   * 
28   * </p>
29   * 
30   * @author Craig R. McClanahan
31   * @author Costin Manolache
32   * @author Richard A. Sitze
33   * @author Ceki G&uuml;lc&uuml;
34   */
35  
36  public abstract class LogFactory {
37  
38    static String UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J = "http://www.slf4j.org/codes.html#unsupported_operation_in_jcl_over_slf4j";
39  
40    static LogFactory logFactory = new SLF4JLogFactory();
41  
42    /**
43     * The name (<code>priority</code>) of the key in the config file used to
44     * specify the priority of that particular config file. The associated value
45     * is a floating-point number; higher values take priority over lower values.
46     * 
47     * <p>
48     * This property is not used but preserved here for compatibility.
49     */
50    public static final String PRIORITY_KEY = "priority";
51  
52    /**
53     * The name (<code>use_tccl</code>) of the key in the config file used to
54     * specify whether logging classes should be loaded via the thread context
55     * class loader (TCCL), or not. By default, the TCCL is used.
56     * 
57     * <p>
58     * This property is not used but preserved here for compatibility.
59     */
60    public static final String TCCL_KEY = "use_tccl";
61  
62    /**
63     * The name of the property used to identify the LogFactory implementation
64     * class name.
65     * <p>
66     * This property is not used but preserved here for compatibility.
67     */
68    public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";
69  
70    /**
71     * The fully qualified class name of the fallback <code>LogFactory</code>
72     * implementation class to use, if no other can be found.
73     * 
74     * <p>
75     * This property is not used but preserved here for compatibility.
76     */
77    public static final String FACTORY_DEFAULT = "org.apache.commons.logging.impl.SLF4JLogFactory";
78  
79    /**
80     * The name of the properties file to search for.
81     * <p>
82     * This property is not used but preserved here for compatibility.
83     */
84    public static final String FACTORY_PROPERTIES = "commons-logging.properties";
85  
86    
87    /**
88     * JDK1.3+ <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider">
89     * 'Service Provider' specification</a>.
90     * <p>
91     * This property is not used but preserved here for compatibility.
92     */
93    protected static final String SERVICE_ID =
94        "META-INF/services/org.apache.commons.logging.LogFactory";
95    
96    /**
97     * The name (<code>org.apache.commons.logging.diagnostics.dest</code>) of
98     * the property used to enable internal commons-logging diagnostic output, in
99     * order to get information on what logging implementations are being
100    * discovered, what classloaders they are loaded through, etc.
101    * 
102    * <p>
103    * This property is not used but preserved here for compatibility.
104    */
105   public static final String DIAGNOSTICS_DEST_PROPERTY = "org.apache.commons.logging.diagnostics.dest";
106 
107   /**
108    * <p>
109    * Setting this system property value allows the <code>Hashtable</code> used
110    * to store classloaders to be substituted by an alternative implementation.
111    * <p>
112    * This property is not used but preserved here for compatibility.
113    */
114   public static final String HASHTABLE_IMPLEMENTATION_PROPERTY = "org.apache.commons.logging.LogFactory.HashtableImpl";
115   
116   /**
117    * The previously constructed <code>LogFactory</code> instances, keyed by
118    * the <code>ClassLoader</code> with which it was created.
119    * 
120    * <p>
121    * This property is not used but preserved here for compatibility.
122    */
123   protected static Hashtable factories = null;
124   
125   /**
126    * <p>
127    * This property is not used but preserved here for compatibility.
128    */
129   protected static LogFactory nullClassLoaderFactory = null;
130 
131   /**
132    * Protected constructor that is not available for public use.
133    */
134   protected LogFactory() {
135   }
136 
137   // --------------------------------------------------------- Public Methods
138 
139   /**
140    * Return the configuration attribute with the specified name (if any), or
141    * <code>null</code> if there is no such attribute.
142    * 
143    * @param name
144    *                Name of the attribute to return
145    */
146   public abstract Object getAttribute(String name);
147 
148   /**
149    * Return an array containing the names of all currently defined configuration
150    * attributes. If there are no such attributes, a zero length array is
151    * returned.
152    */
153   public abstract String[] getAttributeNames();
154 
155   /**
156    * Convenience method to derive a name from the specified class and call
157    * <code>getInstance(String)</code> with it.
158    * 
159    * @param clazz
160    *                Class for which a suitable Log name will be derived
161    * 
162    * @exception LogConfigurationException
163    *                    if a suitable <code>Log</code> instance cannot be
164    *                    returned
165    */
166   public abstract Log getInstance(Class clazz) throws LogConfigurationException;
167 
168   /**
169    * <p>
170    * Construct (if necessary) and return a <code>Log</code> instance, using
171    * the factory's current set of configuration attributes.
172    * </p>
173    * 
174    * <p>
175    * <strong>NOTE </strong>- Depending upon the implementation of the
176    * <code>LogFactory</code> you are using, the <code>Log</code> instance
177    * you are returned may or may not be local to the current application, and
178    * may or may not be returned again on a subsequent call with the same name
179    * argument.
180    * </p>
181    * 
182    * @param name
183    *                Logical name of the <code>Log</code> instance to be
184    *                returned (the meaning of this name is only known to the
185    *                underlying logging implementation that is being wrapped)
186    * 
187    * @exception LogConfigurationException
188    *                    if a suitable <code>Log</code> instance cannot be
189    *                    returned
190    */
191   public abstract Log getInstance(String name) throws LogConfigurationException;
192 
193   /**
194    * Release any internal references to previously created {@link Log}instances
195    * returned by this factory. This is useful in environments like servlet
196    * containers, which implement application reloading by throwing away a
197    * ClassLoader. Dangling references to objects in that class loader would
198    * prevent garbage collection.
199    */
200   public abstract void release();
201 
202   /**
203    * Remove any configuration attribute associated with the specified name. If
204    * there is no such attribute, no action is taken.
205    * 
206    * @param name
207    *                Name of the attribute to remove
208    */
209   public abstract void removeAttribute(String name);
210 
211   /**
212    * Set the configuration attribute with the specified name. Calling this with
213    * a <code>null</code> value is equivalent to calling
214    * <code>removeAttribute(name)</code>.
215    * 
216    * @param name
217    *                Name of the attribute to set
218    * @param value
219    *                Value of the attribute to set, or <code>null</code> to
220    *                remove any setting for this attribute
221    */
222   public abstract void setAttribute(String name, Object value);
223 
224   // --------------------------------------------------------- Static Methods
225 
226   /**
227    * <p>
228    * Construct (if necessary) and return a <code>LogFactory</code> instance,
229    * using the following ordered lookup procedure to determine the name of the
230    * implementation class to be loaded.
231    * </p>
232    * <ul>
233    * <li>The <code>org.apache.commons.logging.LogFactory</code> system
234    * property.</li>
235    * <li>The JDK 1.3 Service Discovery mechanism</li>
236    * <li>Use the properties file <code>commons-logging.properties</code>
237    * file, if found in the class path of this class. The configuration file is
238    * in standard <code>java.util.Properties</code> format and contains the
239    * fully qualified name of the implementation class with the key being the
240    * system property defined above.</li>
241    * <li>Fall back to a default implementation class (
242    * <code>org.apache.commons.logging.impl.SLF4FLogFactory</code>).</li>
243    * </ul>
244    * 
245    * <p>
246    * <em>NOTE</em>- If the properties file method of identifying the
247    * <code>LogFactory</code> implementation class is utilized, all of the
248    * properties defined in this file will be set as configuration attributes on
249    * the corresponding <code>LogFactory</code> instance.
250    * </p>
251    * 
252    * @exception LogConfigurationException
253    *                    if the implementation class is not available or cannot
254    *                    be instantiated.
255    */
256   public static LogFactory getFactory() throws LogConfigurationException {
257     return logFactory;
258   }
259 
260   /**
261    * Convenience method to return a named logger, without the application having
262    * to care about factories.
263    * 
264    * @param clazz
265    *                Class from which a log name will be derived
266    * 
267    * @exception LogConfigurationException
268    *                    if a suitable <code>Log</code> instance cannot be
269    *                    returned
270    */
271   public static Log getLog(Class clazz) throws LogConfigurationException {
272     return (getFactory().getInstance(clazz));
273   }
274 
275   /**
276    * Convenience method to return a named logger, without the application having
277    * to care about factories.
278    * 
279    * @param name
280    *                Logical name of the <code>Log</code> instance to be
281    *                returned (the meaning of this name is only known to the
282    *                underlying logging implementation that is being wrapped)
283    * 
284    * @exception LogConfigurationException
285    *                    if a suitable <code>Log</code> instance cannot be
286    *                    returned
287    */
288   public static Log getLog(String name) throws LogConfigurationException {
289     return (getFactory().getInstance(name));
290   }
291 
292   /**
293    * Release any internal references to previously created {@link LogFactory}
294    * instances that have been associated with the specified class loader (if
295    * any), after calling the instance method <code>release()</code> on each of
296    * them.
297    * 
298    * @param classLoader
299    *                ClassLoader for which to release the LogFactory
300    */
301   public static void release(ClassLoader classLoader) {
302     // since SLF4J based JCL does not make use of classloaders, there is nothing
303     // to do here
304   }
305 
306   /**
307    * Release any internal references to previously created {@link LogFactory}
308    * instances, after calling the instance method <code>release()</code> on
309    * each of them. This is useful in environments like servlet containers, which
310    * implement application reloading by throwing away a ClassLoader. Dangling
311    * references to objects in that class loader would prevent garbage
312    * collection.
313    */
314   public static void releaseAll() {
315     // since SLF4J based JCL does not make use of classloaders, there is nothing
316     // to do here
317   }
318 
319   /**
320    * Returns a string that uniquely identifies the specified object, including
321    * its class.
322    * <p>
323    * The returned string is of form "classname@hashcode", ie is the same as the
324    * return value of the Object.toString() method, but works even when the
325    * specified object's class has overidden the toString method.
326    * 
327    * @param o
328    *                may be null.
329    * @return a string of form classname@hashcode, or "null" if param o is null.
330    * @since 1.1
331    */
332   public static String objectId(Object o) {
333     if (o == null) {
334       return "null";
335     } else {
336       return o.getClass().getName() + "@" + System.identityHashCode(o);
337     }
338   }
339 
340   // protected methods which were added in JCL 1.1. These are not used
341   // by SLF4JLogFactory
342 
343   /**
344    * This method exists to ensure signature compatibility.
345    */
346   protected static Object createFactory(String factoryClass, ClassLoader classLoader) {
347     throw new UnsupportedOperationException(
348         "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(
357         "Operation [directGetContextClassLoader] is not supported in jcl-over-slf4j. See also "
358             + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
359   }
360 
361   /**
362    * This method exists to ensure signature compatibility.
363    */
364   protected static ClassLoader getContextClassLoader()
365       throws LogConfigurationException {
366     throw new UnsupportedOperationException(
367         "Operation [getContextClassLoader] is not supported in jcl-over-slf4j. See also "
368             + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
369   }
370   
371   /**
372    * This method exists to ensure signature compatibility.
373    */
374   protected static ClassLoader getClassLoader(Class clazz) {
375     throw new UnsupportedOperationException(
376         "Operation [getClassLoader] is not supported in jcl-over-slf4j. See also "
377             + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
378   }
379 
380   /**
381    * This method exists to ensure signature compatibility.
382    */
383   protected static boolean isDiagnosticsEnabled() {
384     throw new UnsupportedOperationException(
385         "Operation [isDiagnosticsEnabled] is not supported in jcl-over-slf4j. See also "
386             + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
387   }
388   
389   /**
390    * This method exists to ensure signature compatibility.
391    */
392   protected static void logRawDiagnostic(String msg) {
393     throw new UnsupportedOperationException(
394         "Operation [logRawDiagnostic] is not supported in jcl-over-slf4j. See also "
395             + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
396   }
397   
398   /**
399    * This method exists to ensure signature compatibility.
400    */
401   protected static LogFactory newFactory(final String factoryClass,
402       final ClassLoader classLoader, final ClassLoader contextClassLoader) {
403     throw new UnsupportedOperationException(
404         "Operation [logRawDiagnostic] is not supported in jcl-over-slf4j. See also "
405             + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
406   }
407  
408   /**
409    * This method exists to ensure signature compatibility.
410    */
411   protected static LogFactory newFactory(final String factoryClass,
412                                          final ClassLoader classLoader) {
413     throw new UnsupportedOperationException(
414         "Operation [newFactory] is not supported in jcl-over-slf4j. See also "
415             + UNSUPPORTED_OPERATION_IN_JCL_OVER_SLF4J);
416   }
417 
418 
419 }