View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.commons.logging;
19  
20  import java.io.BufferedReader;
21  import java.io.FileOutputStream;
22  import java.io.IOException;
23  import java.io.InputStream;
24  import java.io.InputStreamReader;
25  import java.io.PrintStream;
26  import java.lang.reflect.InvocationTargetException;
27  import java.lang.reflect.Method;
28  import java.net.URL;
29  import java.net.URLConnection;
30  import java.security.AccessController;
31  import java.security.PrivilegedAction;
32  import java.util.Enumeration;
33  import java.util.Hashtable;
34  import java.util.Properties;
35  
36  /**
37   * Factory for creating {@link Log} instances, with discovery and
38   * configuration features similar to that employed by standard Java APIs
39   * such as JAXP.
40   * <p>
41   * <strong>IMPLEMENTATION NOTE</strong> - This implementation is heavily
42   * based on the SAXParserFactory and DocumentBuilderFactory implementations
43   * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
44   *
45   * @version $Id: LogFactory.java 1449064 2013-02-22 14:49:22Z tn $
46   */
47  public abstract class LogFactory {
48      // Implementation note re AccessController usage
49      //
50      // It is important to keep code invoked via an AccessController to small
51      // auditable blocks. Such code must carefully evaluate all user input
52      // (parameters, system properties, config file contents, etc). As an
53      // example, a Log implementation should not write to its logfile
54      // with an AccessController anywhere in the call stack, otherwise an
55      // insecure application could configure the log implementation to write
56      // to a protected file using the privileges granted to JCL rather than
57      // to the calling application.
58      //
59      // Under no circumstance should a non-private method return data that is
60      // retrieved via an AccessController. That would allow an insecure app
61      // to invoke that method and obtain data that it is not permitted to have.
62      //
63      // Invoking user-supplied code with an AccessController set is not a major
64      // issue (eg invoking the constructor of the class specified by
65      // HASHTABLE_IMPLEMENTATION_PROPERTY). That class will be in a different
66      // trust domain, and therefore must have permissions to do whatever it
67      // is trying to do regardless of the permissions granted to JCL. There is
68      // a slight issue in that untrusted code may point that environment var
69      // to another trusted library, in which case the code runs if both that
70      // lib and JCL have the necessary permissions even when the untrusted
71      // caller does not. That's a pretty hard route to exploit though.
72  
73      // ----------------------------------------------------- Manifest Constants
74  
75      /**
76       * The name (<code>priority</code>) of the key in the config file used to
77       * specify the priority of that particular config file. The associated value
78       * is a floating-point number; higher values take priority over lower values.
79       */
80      public static final String PRIORITY_KEY = "priority";
81  
82      /**
83       * The name (<code>use_tccl</code>) of the key in the config file used
84       * to specify whether logging classes should be loaded via the thread
85       * context class loader (TCCL), or not. By default, the TCCL is used.
86       */
87      public static final String TCCL_KEY = "use_tccl";
88  
89      /**
90       * The name (<code>org.apache.commons.logging.LogFactory</code>) of the property
91       * used to identify the LogFactory implementation
92       * class name. This can be used as a system property, or as an entry in a
93       * configuration properties file.
94       */
95      public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";
96  
97      /**
98       * The fully qualified class name of the fallback <code>LogFactory</code>
99       * implementation class to use, if no other can be found.
100      */
101     public static final String FACTORY_DEFAULT = "org.apache.commons.logging.impl.LogFactoryImpl";
102 
103     /**
104      * The name (<code>commons-logging.properties</code>) of the properties file to search for.
105      */
106     public static final String FACTORY_PROPERTIES = "commons-logging.properties";
107 
108     /**
109      * JDK1.3+ <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Service%20Provider">
110      * 'Service Provider' specification</a>.
111      */
112     protected static final String SERVICE_ID =
113         "META-INF/services/org.apache.commons.logging.LogFactory";
114 
115     /**
116      * The name (<code>org.apache.commons.logging.diagnostics.dest</code>)
117      * of the property used to enable internal commons-logging
118      * diagnostic output, in order to get information on what logging
119      * implementations are being discovered, what classloaders they
120      * are loaded through, etc.
121      * <p>
122      * If a system property of this name is set then the value is
123      * assumed to be the name of a file. The special strings
124      * STDOUT or STDERR (case-sensitive) indicate output to
125      * System.out and System.err respectively.
126      * <p>
127      * Diagnostic logging should be used only to debug problematic
128      * configurations and should not be set in normal production use.
129      */
130     public static final String DIAGNOSTICS_DEST_PROPERTY =
131         "org.apache.commons.logging.diagnostics.dest";
132 
133     /**
134      * When null (the usual case), no diagnostic output will be
135      * generated by LogFactory or LogFactoryImpl. When non-null,
136      * interesting events will be written to the specified object.
137      */
138     private static PrintStream diagnosticsStream = null;
139 
140     /**
141      * A string that gets prefixed to every message output by the
142      * logDiagnostic method, so that users can clearly see which
143      * LogFactory class is generating the output.
144      */
145     private static final String diagnosticPrefix;
146 
147     /**
148      * Setting this system property
149      * (<code>org.apache.commons.logging.LogFactory.HashtableImpl</code>)
150      * value allows the <code>Hashtable</code> used to store
151      * classloaders to be substituted by an alternative implementation.
152      * <p>
153      * <strong>Note:</strong> <code>LogFactory</code> will print:
154      * <code><pre>
155      * [ERROR] LogFactory: Load of custom hashtable failed</em>
156      * </pre></code>
157      * to system error and then continue using a standard Hashtable.
158      * <p>
159      * <strong>Usage:</strong> Set this property when Java is invoked
160      * and <code>LogFactory</code> will attempt to load a new instance
161      * of the given implementation class.
162      * For example, running the following ant scriplet:
163      * <code><pre>
164      *  &lt;java classname="${test.runner}" fork="yes" failonerror="${test.failonerror}"&gt;
165      *     ...
166      *     &lt;sysproperty
167      *        key="org.apache.commons.logging.LogFactory.HashtableImpl"
168      *        value="org.apache.commons.logging.AltHashtable"/&gt;
169      *  &lt;/java&gt;
170      * </pre></code>
171      * will mean that <code>LogFactory</code> will load an instance of
172      * <code>org.apache.commons.logging.AltHashtable</code>.
173      * <p>
174      * A typical use case is to allow a custom
175      * Hashtable implementation using weak references to be substituted.
176      * This will allow classloaders to be garbage collected without
177      * the need to release them (on 1.3+ JVMs only, of course ;).
178      */
179     public static final String HASHTABLE_IMPLEMENTATION_PROPERTY =
180         "org.apache.commons.logging.LogFactory.HashtableImpl";
181 
182     /** Name used to load the weak hashtable implementation by names. */
183     private static final String WEAK_HASHTABLE_CLASSNAME =
184         "org.apache.commons.logging.impl.WeakHashtable";
185 
186     /**
187      * A reference to the classloader that loaded this class. This is the
188      * same as LogFactory.class.getClassLoader(). However computing this
189      * value isn't quite as simple as that, as we potentially need to use
190      * AccessControllers etc. It's more efficient to compute it once and
191      * cache it here.
192      */
193     private static final ClassLoader thisClassLoader;
194 
195     // ----------------------------------------------------------- Constructors
196 
197     /**
198      * Protected constructor that is not available for public use.
199      */
200     protected LogFactory() {
201     }
202 
203     // --------------------------------------------------------- Public Methods
204 
205     /**
206      * Return the configuration attribute with the specified name (if any),
207      * or <code>null</code> if there is no such attribute.
208      *
209      * @param name Name of the attribute to return
210      */
211     public abstract Object getAttribute(String name);
212 
213     /**
214      * Return an array containing the names of all currently defined
215      * configuration attributes.  If there are no such attributes, a zero
216      * length array is returned.
217      */
218     public abstract String[] getAttributeNames();
219 
220     /**
221      * Convenience method to derive a name from the specified class and
222      * call <code>getInstance(String)</code> with it.
223      *
224      * @param clazz Class for which a suitable Log name will be derived
225      * @throws LogConfigurationException if a suitable <code>Log</code>
226      *  instance cannot be returned
227      */
228     public abstract Log getInstance(Class clazz)
229         throws LogConfigurationException;
230 
231     /**
232      * Construct (if necessary) and return a <code>Log</code> instance,
233      * using the factory's current set of configuration attributes.
234      * <p>
235      * <strong>NOTE</strong> - Depending upon the implementation of
236      * the <code>LogFactory</code> you are using, the <code>Log</code>
237      * instance you are returned may or may not be local to the current
238      * application, and may or may not be returned again on a subsequent
239      * call with the same name argument.
240      *
241      * @param name Logical name of the <code>Log</code> instance to be
242      *  returned (the meaning of this name is only known to the underlying
243      *  logging implementation that is being wrapped)
244      * @throws LogConfigurationException if a suitable <code>Log</code>
245      *  instance cannot be returned
246      */
247     public abstract Log getInstance(String name)
248         throws LogConfigurationException;
249 
250     /**
251      * Release any internal references to previously created {@link Log}
252      * instances returned by this factory.  This is useful in environments
253      * like servlet containers, which implement application reloading by
254      * throwing away a ClassLoader.  Dangling references to objects in that
255      * class loader would prevent garbage collection.
256      */
257     public abstract void release();
258 
259     /**
260      * Remove any configuration attribute associated with the specified name.
261      * If there is no such attribute, no action is taken.
262      *
263      * @param name Name of the attribute to remove
264      */
265     public abstract void removeAttribute(String name);
266 
267     /**
268      * Set the configuration attribute with the specified name.  Calling
269      * this with a <code>null</code> value is equivalent to calling
270      * <code>removeAttribute(name)</code>.
271      *
272      * @param name Name of the attribute to set
273      * @param value Value of the attribute to set, or <code>null</code>
274      *  to remove any setting for this attribute
275      */
276     public abstract void setAttribute(String name, Object value);
277 
278     // ------------------------------------------------------- Static Variables
279 
280     /**
281      * The previously constructed <code>LogFactory</code> instances, keyed by
282      * the <code>ClassLoader</code> with which it was created.
283      */
284     protected static Hashtable factories = null;
285 
286     /**
287      * Previously constructed <code>LogFactory</code> instance as in the
288      * <code>factories</code> map, but for the case where
289      * <code>getClassLoader</code> returns <code>null</code>.
290      * This can happen when:
291      * <ul>
292      * <li>using JDK1.1 and the calling code is loaded via the system
293      *  classloader (very common)</li>
294      * <li>using JDK1.2+ and the calling code is loaded via the boot
295      *  classloader (only likely for embedded systems work).</li>
296      * </ul>
297      * Note that <code>factories</code> is a <i>Hashtable</i> (not a HashMap),
298      * and hashtables don't allow null as a key.
299      * @deprecated since 1.1.2
300      */
301     protected static volatile LogFactory nullClassLoaderFactory = null;
302 
303     /**
304      * Create the hashtable which will be used to store a map of
305      * (context-classloader -> logfactory-object). Version 1.2+ of Java
306      * supports "weak references", allowing a custom Hashtable class
307      * to be used which uses only weak references to its keys. Using weak
308      * references can fix memory leaks on webapp unload in some cases (though
309      * not all). Version 1.1 of Java does not support weak references, so we
310      * must dynamically determine which we are using. And just for fun, this
311      * code also supports the ability for a system property to specify an
312      * arbitrary Hashtable implementation name.
313      * <p>
314      * Note that the correct way to ensure no memory leaks occur is to ensure
315      * that LogFactory.release(contextClassLoader) is called whenever a
316      * webapp is undeployed.
317      */
318     private static final Hashtable createFactoryStore() {
319         Hashtable result = null;
320         String storeImplementationClass;
321         try {
322             storeImplementationClass = getSystemProperty(HASHTABLE_IMPLEMENTATION_PROPERTY, null);
323         } catch (SecurityException ex) {
324             // Permissions don't allow this to be accessed. Default to the "modern"
325             // weak hashtable implementation if it is available.
326             storeImplementationClass = null;
327         }
328 
329         if (storeImplementationClass == null) {
330             storeImplementationClass = WEAK_HASHTABLE_CLASSNAME;
331         }
332         try {
333             Class implementationClass = Class.forName(storeImplementationClass);
334             result = (Hashtable) implementationClass.newInstance();
335         } catch (Throwable t) {
336             handleThrowable(t); // may re-throw t
337 
338             // ignore
339             if (!WEAK_HASHTABLE_CLASSNAME.equals(storeImplementationClass)) {
340                 // if the user's trying to set up a custom implementation, give a clue
341                 if (isDiagnosticsEnabled()) {
342                     // use internal logging to issue the warning
343                     logDiagnostic("[ERROR] LogFactory: Load of custom hashtable failed");
344                 } else {
345                     // we *really* want this output, even if diagnostics weren't
346                     // explicitly enabled by the user.
347                     System.err.println("[ERROR] LogFactory: Load of custom hashtable failed");
348                 }
349             }
350         }
351         if (result == null) {
352             result = new Hashtable();
353         }
354         return result;
355     }
356 
357     // --------------------------------------------------------- Static Methods
358 
359     /** Utility method to safely trim a string. */
360     private static String trim(String src) {
361         if (src == null) {
362             return null;
363         }
364         return src.trim();
365     }
366 
367     /**
368      * Checks whether the supplied Throwable is one that needs to be
369      * re-thrown and ignores all others.
370      *
371      * The following errors are re-thrown:
372      * <ul>
373      *   <li>ThreadDeath</li>
374      *   <li>VirtualMachineError</li>
375      * </ul>
376      *
377      * @param t the Throwable to check
378      */
379     protected static void handleThrowable(Throwable t) {
380         if (t instanceof ThreadDeath) {
381             throw (ThreadDeath) t;
382         }
383         if (t instanceof VirtualMachineError) {
384             throw (VirtualMachineError) t;
385         }
386         // All other instances of Throwable will be silently ignored
387     }
388 
389     /**
390      * Construct (if necessary) and return a <code>LogFactory</code>
391      * instance, using the following ordered lookup procedure to determine
392      * the name of the implementation class to be loaded.
393      * <p>
394      * <ul>
395      * <li>The <code>org.apache.commons.logging.LogFactory</code> system
396      *     property.</li>
397      * <li>The JDK 1.3 Service Discovery mechanism</li>
398      * <li>Use the properties file <code>commons-logging.properties</code>
399      *     file, if found in the class path of this class.  The configuration
400      *     file is in standard <code>java.util.Properties</code> format and
401      *     contains the fully qualified name of the implementation class
402      *     with the key being the system property defined above.</li>
403      * <li>Fall back to a default implementation class
404      *     (<code>org.apache.commons.logging.impl.LogFactoryImpl</code>).</li>
405      * </ul>
406      * <p>
407      * <em>NOTE</em> - If the properties file method of identifying the
408      * <code>LogFactory</code> implementation class is utilized, all of the
409      * properties defined in this file will be set as configuration attributes
410      * on the corresponding <code>LogFactory</code> instance.
411      * <p>
412      * <em>NOTE</em> - In a multi-threaded environment it is possible
413      * that two different instances will be returned for the same
414      * classloader environment.
415      *
416      * @throws LogConfigurationException if the implementation class is not
417      *  available or cannot be instantiated.
418      */
419     public static LogFactory getFactory() throws LogConfigurationException {
420         // Identify the class loader we will be using
421         ClassLoader contextClassLoader = getContextClassLoaderInternal();
422 
423         if (contextClassLoader == null) {
424             // This is an odd enough situation to report about. This
425             // output will be a nuisance on JDK1.1, as the system
426             // classloader is null in that environment.
427             if (isDiagnosticsEnabled()) {
428                 logDiagnostic("Context classloader is null.");
429             }
430         }
431 
432         // Return any previously registered factory for this class loader
433         LogFactory factory = getCachedFactory(contextClassLoader);
434         if (factory != null) {
435             return factory;
436         }
437 
438         if (isDiagnosticsEnabled()) {
439             logDiagnostic(
440                     "[LOOKUP] LogFactory implementation requested for the first time for context classloader " +
441                     objectId(contextClassLoader));
442             logHierarchy("[LOOKUP] ", contextClassLoader);
443         }
444 
445         // Load properties file.
446         //
447         // If the properties file exists, then its contents are used as
448         // "attributes" on the LogFactory implementation class. One particular
449         // property may also control which LogFactory concrete subclass is
450         // used, but only if other discovery mechanisms fail..
451         //
452         // As the properties file (if it exists) will be used one way or
453         // another in the end we may as well look for it first.
454 
455         Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES);
456 
457         // Determine whether we will be using the thread context class loader to
458         // load logging classes or not by checking the loaded properties file (if any).
459         ClassLoader baseClassLoader = contextClassLoader;
460         if (props != null) {
461             String useTCCLStr = props.getProperty(TCCL_KEY);
462             if (useTCCLStr != null) {
463                 // The Boolean.valueOf(useTCCLStr).booleanValue() formulation
464                 // is required for Java 1.2 compatibility.
465                 if (Boolean.valueOf(useTCCLStr).booleanValue() == false) {
466                     // Don't use current context classloader when locating any
467                     // LogFactory or Log classes, just use the class that loaded
468                     // this abstract class. When this class is deployed in a shared
469                     // classpath of a container, it means webapps cannot deploy their
470                     // own logging implementations. It also means that it is up to the
471                     // implementation whether to load library-specific config files
472                     // from the TCCL or not.
473                     baseClassLoader = thisClassLoader;
474                 }
475             }
476         }
477 
478         // Determine which concrete LogFactory subclass to use.
479         // First, try a global system property
480         if (isDiagnosticsEnabled()) {
481             logDiagnostic("[LOOKUP] Looking for system property [" + FACTORY_PROPERTY +
482                           "] to define the LogFactory subclass to use...");
483         }
484 
485         try {
486             String factoryClass = getSystemProperty(FACTORY_PROPERTY, null);
487             if (factoryClass != null) {
488                 if (isDiagnosticsEnabled()) {
489                     logDiagnostic("[LOOKUP] Creating an instance of LogFactory class '" + factoryClass +
490                                   "' as specified by system property " + FACTORY_PROPERTY);
491                 }
492                 factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
493             } else {
494                 if (isDiagnosticsEnabled()) {
495                     logDiagnostic("[LOOKUP] No system property [" + FACTORY_PROPERTY + "] defined.");
496                 }
497             }
498         } catch (SecurityException e) {
499             if (isDiagnosticsEnabled()) {
500                 logDiagnostic("[LOOKUP] A security exception occurred while trying to create an" +
501                               " instance of the custom factory class" + ": [" + trim(e.getMessage()) +
502                               "]. Trying alternative implementations...");
503             }
504             // ignore
505         } catch (RuntimeException e) {
506             // This is not consistent with the behaviour when a bad LogFactory class is
507             // specified in a services file.
508             //
509             // One possible exception that can occur here is a ClassCastException when
510             // the specified class wasn't castable to this LogFactory type.
511             if (isDiagnosticsEnabled()) {
512                 logDiagnostic("[LOOKUP] An exception occurred while trying to create an" +
513                               " instance of the custom factory class" + ": [" +
514                               trim(e.getMessage()) +
515                               "] as specified by a system property.");
516             }
517             throw e;
518         }
519 
520         // Second, try to find a service by using the JDK1.3 class
521         // discovery mechanism, which involves putting a file with the name
522         // of an interface class in the META-INF/services directory, where the
523         // contents of the file is a single line specifying a concrete class
524         // that implements the desired interface.
525 
526         if (factory == null) {
527             if (isDiagnosticsEnabled()) {
528                 logDiagnostic("[LOOKUP] Looking for a resource file of name [" + SERVICE_ID +
529                               "] to define the LogFactory subclass to use...");
530             }
531             try {
532                 final InputStream is = getResourceAsStream(contextClassLoader, SERVICE_ID);
533 
534                 if( is != null ) {
535                     // This code is needed by EBCDIC and other strange systems.
536                     // It's a fix for bugs reported in xerces
537                     BufferedReader rd;
538                     try {
539                         rd = new BufferedReader(new InputStreamReader(is, "UTF-8"));
540                     } catch (java.io.UnsupportedEncodingException e) {
541                         rd = new BufferedReader(new InputStreamReader(is));
542                     }
543 
544                     String factoryClassName = rd.readLine();
545                     rd.close();
546 
547                     if (factoryClassName != null && ! "".equals(factoryClassName)) {
548                         if (isDiagnosticsEnabled()) {
549                             logDiagnostic("[LOOKUP]  Creating an instance of LogFactory class " +
550                                           factoryClassName +
551                                           " as specified by file '" + SERVICE_ID +
552                                           "' which was present in the path of the context classloader.");
553                         }
554                         factory = newFactory(factoryClassName, baseClassLoader, contextClassLoader );
555                     }
556                 } else {
557                     // is == null
558                     if (isDiagnosticsEnabled()) {
559                         logDiagnostic("[LOOKUP] No resource file with name '" + SERVICE_ID + "' found.");
560                     }
561                 }
562             } catch (Exception ex) {
563                 // note: if the specified LogFactory class wasn't compatible with LogFactory
564                 // for some reason, a ClassCastException will be caught here, and attempts will
565                 // continue to find a compatible class.
566                 if (isDiagnosticsEnabled()) {
567                     logDiagnostic(
568                         "[LOOKUP] A security exception occurred while trying to create an" +
569                         " instance of the custom factory class" +
570                         ": [" + trim(ex.getMessage()) +
571                         "]. Trying alternative implementations...");
572                 }
573                 // ignore
574             }
575         }
576 
577         // Third try looking into the properties file read earlier (if found)
578 
579         if (factory == null) {
580             if (props != null) {
581                 if (isDiagnosticsEnabled()) {
582                     logDiagnostic(
583                         "[LOOKUP] Looking in properties file for entry with key '" + FACTORY_PROPERTY +
584                         "' to define the LogFactory subclass to use...");
585                 }
586                 String factoryClass = props.getProperty(FACTORY_PROPERTY);
587                 if (factoryClass != null) {
588                     if (isDiagnosticsEnabled()) {
589                         logDiagnostic(
590                             "[LOOKUP] Properties file specifies LogFactory subclass '" + factoryClass + "'");
591                     }
592                     factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
593 
594                     // TODO: think about whether we need to handle exceptions from newFactory
595                 } else {
596                     if (isDiagnosticsEnabled()) {
597                         logDiagnostic("[LOOKUP] Properties file has no entry specifying LogFactory subclass.");
598                     }
599                 }
600             } else {
601                 if (isDiagnosticsEnabled()) {
602                     logDiagnostic("[LOOKUP] No properties file available to determine" + " LogFactory subclass from..");
603                 }
604             }
605         }
606 
607         // Fourth, try the fallback implementation class
608 
609         if (factory == null) {
610             if (isDiagnosticsEnabled()) {
611                 logDiagnostic(
612                     "[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT +
613                     "' via the same classloader that loaded this LogFactory" +
614                     " class (ie not looking in the context classloader).");
615             }
616 
617             // Note: unlike the above code which can try to load custom LogFactory
618             // implementations via the TCCL, we don't try to load the default LogFactory
619             // implementation via the context classloader because:
620             // * that can cause problems (see comments in newFactory method)
621             // * no-one should be customising the code of the default class
622             // Yes, we do give up the ability for the child to ship a newer
623             // version of the LogFactoryImpl class and have it used dynamically
624             // by an old LogFactory class in the parent, but that isn't
625             // necessarily a good idea anyway.
626             factory = newFactory(FACTORY_DEFAULT, thisClassLoader, contextClassLoader);
627         }
628 
629         if (factory != null) {
630             /**
631              * Always cache using context class loader.
632              */
633             cacheFactory(contextClassLoader, factory);
634 
635             if (props != null) {
636                 Enumeration names = props.propertyNames();
637                 while (names.hasMoreElements()) {
638                     String name = (String) names.nextElement();
639                     String value = props.getProperty(name);
640                     factory.setAttribute(name, value);
641                 }
642             }
643         }
644 
645         return factory;
646     }
647 
648     /**
649      * Convenience method to return a named logger, without the application
650      * having to care about factories.
651      *
652      * @param clazz Class from which a log name will be derived
653      * @throws LogConfigurationException if a suitable <code>Log</code>
654      *  instance cannot be returned
655      */
656     public static Log getLog(Class clazz) throws LogConfigurationException {
657         return getFactory().getInstance(clazz);
658     }
659 
660     /**
661      * Convenience method to return a named logger, without the application
662      * having to care about factories.
663      *
664      * @param name Logical name of the <code>Log</code> instance to be
665      *  returned (the meaning of this name is only known to the underlying
666      *  logging implementation that is being wrapped)
667      * @throws LogConfigurationException if a suitable <code>Log</code>
668      *  instance cannot be returned
669      */
670     public static Log getLog(String name) throws LogConfigurationException {
671         return getFactory().getInstance(name);
672     }
673 
674     /**
675      * Release any internal references to previously created {@link LogFactory}
676      * instances that have been associated with the specified class loader
677      * (if any), after calling the instance method <code>release()</code> on
678      * each of them.
679      *
680      * @param classLoader ClassLoader for which to release the LogFactory
681      */
682     public static void release(ClassLoader classLoader) {
683         if (isDiagnosticsEnabled()) {
684             logDiagnostic("Releasing factory for classloader " + objectId(classLoader));
685         }
686         // factories is not final and could be replaced in this block.
687         final Hashtable factories = LogFactory.factories;
688         synchronized (factories) {
689             if (classLoader == null) {
690                 if (nullClassLoaderFactory != null) {
691                     nullClassLoaderFactory.release();
692                     nullClassLoaderFactory = null;
693                 }
694             } else {
695                 final LogFactory factory = (LogFactory) factories.get(classLoader);
696                 if (factory != null) {
697                     factory.release();
698                     factories.remove(classLoader);
699                 }
700             }
701         }
702     }
703 
704     /**
705      * Release any internal references to previously created {@link LogFactory}
706      * instances, after calling the instance method <code>release()</code> on
707      * each of them.  This is useful in environments like servlet containers,
708      * which implement application reloading by throwing away a ClassLoader.
709      * Dangling references to objects in that class loader would prevent
710      * garbage collection.
711      */
712     public static void releaseAll() {
713         if (isDiagnosticsEnabled()) {
714             logDiagnostic("Releasing factory for all classloaders.");
715         }
716         // factories is not final and could be replaced in this block.
717         final Hashtable factories = LogFactory.factories;
718         synchronized (factories) {
719             final Enumeration elements = factories.elements();
720             while (elements.hasMoreElements()) {
721                 LogFactory element = (LogFactory) elements.nextElement();
722                 element.release();
723             }
724             factories.clear();
725 
726             if (nullClassLoaderFactory != null) {
727                 nullClassLoaderFactory.release();
728                 nullClassLoaderFactory = null;
729             }
730         }
731     }
732 
733     // ------------------------------------------------------ Protected Methods
734 
735     /**
736      * Safely get access to the classloader for the specified class.
737      * <p>
738      * Theoretically, calling getClassLoader can throw a security exception,
739      * and so should be done under an AccessController in order to provide
740      * maximum flexibility. However in practice people don't appear to use
741      * security policies that forbid getClassLoader calls. So for the moment
742      * all code is written to call this method rather than Class.getClassLoader,
743      * so that we could put AccessController stuff in this method without any
744      * disruption later if we need to.
745      * <p>
746      * Even when using an AccessController, however, this method can still
747      * throw SecurityException. Commons-logging basically relies on the
748      * ability to access classloaders, ie a policy that forbids all
749      * classloader access will also prevent commons-logging from working:
750      * currently this method will throw an exception preventing the entire app
751      * from starting up. Maybe it would be good to detect this situation and
752      * just disable all commons-logging? Not high priority though - as stated
753      * above, security policies that prevent classloader access aren't common.
754      * <p>
755      * Note that returning an object fetched via an AccessController would
756      * technically be a security flaw anyway; untrusted code that has access
757      * to a trusted JCL library could use it to fetch the classloader for
758      * a class even when forbidden to do so directly.
759      *
760      * @since 1.1
761      */
762     protected static ClassLoader getClassLoader(Class clazz) {
763         try {
764             return clazz.getClassLoader();
765         } catch (SecurityException ex) {
766             if (isDiagnosticsEnabled()) {
767                 logDiagnostic("Unable to get classloader for class '" + clazz +
768                               "' due to security restrictions - " + ex.getMessage());
769             }
770             throw ex;
771         }
772     }
773 
774     /**
775      * Returns the current context classloader.
776      * <p>
777      * In versions prior to 1.1, this method did not use an AccessController.
778      * In version 1.1, an AccessController wrapper was incorrectly added to
779      * this method, causing a minor security flaw.
780      * <p>
781      * In version 1.1.1 this change was reverted; this method no longer uses
782      * an AccessController. User code wishing to obtain the context classloader
783      * must invoke this method via AccessController.doPrivileged if it needs
784      * support for that.
785      *
786      * @return the context classloader associated with the current thread,
787      *  or null if security doesn't allow it.
788      * @throws LogConfigurationException if there was some weird error while
789      *  attempting to get the context classloader.
790      * @throws SecurityException if the current java security policy doesn't
791      *  allow this class to access the context classloader.
792      */
793     protected static ClassLoader getContextClassLoader() throws LogConfigurationException {
794         return directGetContextClassLoader();
795     }
796 
797     /**
798      * Calls LogFactory.directGetContextClassLoader under the control of an
799      * AccessController class. This means that java code running under a
800      * security manager that forbids access to ClassLoaders will still work
801      * if this class is given appropriate privileges, even when the caller
802      * doesn't have such privileges. Without using an AccessController, the
803      * the entire call stack must have the privilege before the call is
804      * allowed.
805      *
806      * @return the context classloader associated with the current thread,
807      *  or null if security doesn't allow it.
808      * @throws LogConfigurationException if there was some weird error while
809      *  attempting to get the context classloader.
810      * @throws SecurityException if the current java security policy doesn't
811      *  allow this class to access the context classloader.
812      */
813     private static ClassLoader getContextClassLoaderInternal() throws LogConfigurationException {
814         return (ClassLoader)AccessController.doPrivileged(
815             new PrivilegedAction() {
816                 public Object run() {
817                     return directGetContextClassLoader();
818                 }
819             });
820     }
821 
822     /**
823      * Return the thread context class loader if available; otherwise return null.
824      * <p>
825      * Most/all code should call getContextClassLoaderInternal rather than
826      * calling this method directly.
827      * <p>
828      * The thread context class loader is available for JDK 1.2
829      * or later, if certain security conditions are met.
830      * <p>
831      * Note that no internal logging is done within this method because
832      * this method is called every time LogFactory.getLogger() is called,
833      * and we don't want too much output generated here.
834      *
835      * @throws LogConfigurationException if a suitable class loader
836      *  cannot be identified.
837      * @throws SecurityException if the java security policy forbids
838      *  access to the context classloader from one of the classes in the
839      *  current call stack.
840      * @since 1.1
841      */
842     protected static ClassLoader directGetContextClassLoader() throws LogConfigurationException {
843         ClassLoader classLoader = null;
844 
845         try {
846             // Are we running on a JDK 1.2 or later system?
847             final Method method = Thread.class.getMethod("getContextClassLoader", (Class[]) null);
848 
849             // Get the thread context class loader (if there is one)
850             try {
851                 classLoader = (ClassLoader)method.invoke(Thread.currentThread(), (Object[]) null);
852             } catch (IllegalAccessException e) {
853                 throw new LogConfigurationException
854                     ("Unexpected IllegalAccessException", e);
855             } catch (InvocationTargetException e) {
856                 /**
857                  * InvocationTargetException is thrown by 'invoke' when
858                  * the method being invoked (getContextClassLoader) throws
859                  * an exception.
860                  *
861                  * getContextClassLoader() throws SecurityException when
862                  * the context class loader isn't an ancestor of the
863                  * calling class's class loader, or if security
864                  * permissions are restricted.
865                  *
866                  * In the first case (not related), we want to ignore and
867                  * keep going.  We cannot help but also ignore the second
868                  * with the logic below, but other calls elsewhere (to
869                  * obtain a class loader) will trigger this exception where
870                  * we can make a distinction.
871                  */
872                 if (e.getTargetException() instanceof SecurityException) {
873                     // ignore
874                 } else {
875                     // Capture 'e.getTargetException()' exception for details
876                     // alternate: log 'e.getTargetException()', and pass back 'e'.
877                     throw new LogConfigurationException("Unexpected InvocationTargetException", e.getTargetException());
878                 }
879             }
880         } catch (NoSuchMethodException e) {
881             // Assume we are running on JDK 1.1
882             classLoader = getClassLoader(LogFactory.class);
883 
884             // We deliberately don't log a message here to outputStream;
885             // this message would be output for every call to LogFactory.getLog()
886             // when running on JDK1.1
887             //
888             // if (outputStream != null) {
889             //    outputStream.println(
890             //        "Method Thread.getContextClassLoader does not exist;"
891             //         + " assuming this is JDK 1.1, and that the context"
892             //         + " classloader is the same as the class that loaded"
893             //         + " the concrete LogFactory class.");
894             // }
895         }
896 
897         // Return the selected class loader
898         return classLoader;
899     }
900 
901     /**
902      * Check cached factories (keyed by contextClassLoader)
903      *
904      * @param contextClassLoader is the context classloader associated
905      * with the current thread. This allows separate LogFactory objects
906      * per component within a container, provided each component has
907      * a distinct context classloader set. This parameter may be null
908      * in JDK1.1, and in embedded systems where jcl-using code is
909      * placed in the bootclasspath.
910      *
911      * @return the factory associated with the specified classloader if
912      *  one has previously been created, or null if this is the first time
913      *  we have seen this particular classloader.
914      */
915     private static LogFactory getCachedFactory(ClassLoader contextClassLoader) {
916         if (contextClassLoader == null) {
917             // We have to handle this specially, as factories is a Hashtable
918             // and those don't accept null as a key value.
919             //
920             // nb: nullClassLoaderFactory might be null. That's ok.
921             return nullClassLoaderFactory;
922         } else {
923             return (LogFactory) factories.get(contextClassLoader);
924         }
925     }
926 
927     /**
928      * Remember this factory, so later calls to LogFactory.getCachedFactory
929      * can return the previously created object (together with all its
930      * cached Log objects).
931      *
932      * @param classLoader should be the current context classloader. Note that
933      *  this can be null under some circumstances; this is ok.
934      * @param factory should be the factory to cache. This should never be null.
935      */
936     private static void cacheFactory(ClassLoader classLoader, LogFactory factory) {
937         // Ideally we would assert(factory != null) here. However reporting
938         // errors from within a logging implementation is a little tricky!
939 
940         if (factory != null) {
941             if (classLoader == null) {
942                 nullClassLoaderFactory = factory;
943             } else {
944                 factories.put(classLoader, factory);
945             }
946         }
947     }
948 
949     /**
950      * Return a new instance of the specified <code>LogFactory</code>
951      * implementation class, loaded by the specified class loader.
952      * If that fails, try the class loader used to load this
953      * (abstract) LogFactory.
954      * <p>
955      * <h2>ClassLoader conflicts</h2>
956      * Note that there can be problems if the specified ClassLoader is not the
957      * same as the classloader that loaded this class, ie when loading a
958      * concrete LogFactory subclass via a context classloader.
959      * <p>
960      * The problem is the same one that can occur when loading a concrete Log
961      * subclass via a context classloader.
962      * <p>
963      * The problem occurs when code running in the context classloader calls
964      * class X which was loaded via a parent classloader, and class X then calls
965      * LogFactory.getFactory (either directly or via LogFactory.getLog). Because
966      * class X was loaded via the parent, it binds to LogFactory loaded via
967      * the parent. When the code in this method finds some LogFactoryYYYY
968      * class in the child (context) classloader, and there also happens to be a
969      * LogFactory class defined in the child classloader, then LogFactoryYYYY
970      * will be bound to LogFactory@childloader. It cannot be cast to
971      * LogFactory@parentloader, ie this method cannot return the object as
972      * the desired type. Note that it doesn't matter if the LogFactory class
973      * in the child classloader is identical to the LogFactory class in the
974      * parent classloader, they are not compatible.
975      * <p>
976      * The solution taken here is to simply print out an error message when
977      * this occurs then throw an exception. The deployer of the application
978      * must ensure they remove all occurrences of the LogFactory class from
979      * the child classloader in order to resolve the issue. Note that they
980      * do not have to move the custom LogFactory subclass; that is ok as
981      * long as the only LogFactory class it can find to bind to is in the
982      * parent classloader.
983      *
984      * @param factoryClass Fully qualified name of the <code>LogFactory</code>
985      *  implementation class
986      * @param classLoader ClassLoader from which to load this class
987      * @param contextClassLoader is the context that this new factory will
988      *  manage logging for.
989      * @throws LogConfigurationException if a suitable instance
990      *  cannot be created
991      * @since 1.1
992      */
993     protected static LogFactory newFactory(final String factoryClass,
994                                            final ClassLoader classLoader,
995                                            final ClassLoader contextClassLoader)
996         throws LogConfigurationException {
997         // Note that any unchecked exceptions thrown by the createFactory
998         // method will propagate out of this method; in particular a
999         // ClassCastException can be thrown.
1000         Object result = AccessController.doPrivileged(
1001             new PrivilegedAction() {
1002                 public Object run() {
1003                     return createFactory(factoryClass, classLoader);
1004                 }
1005             });
1006 
1007         if (result instanceof LogConfigurationException) {
1008             LogConfigurationException ex = (LogConfigurationException) result;
1009             if (isDiagnosticsEnabled()) {
1010                 logDiagnostic("An error occurred while loading the factory class:" + ex.getMessage());
1011             }
1012             throw ex;
1013         }
1014         if (isDiagnosticsEnabled()) {
1015             logDiagnostic("Created object " + objectId(result) + " to manage classloader " +
1016                           objectId(contextClassLoader));
1017         }
1018         return (LogFactory)result;
1019     }
1020 
1021     /**
1022      * Method provided for backwards compatibility; see newFactory version that
1023      * takes 3 parameters.
1024      * <p>
1025      * This method would only ever be called in some rather odd situation.
1026      * Note that this method is static, so overriding in a subclass doesn't
1027      * have any effect unless this method is called from a method in that
1028      * subclass. However this method only makes sense to use from the
1029      * getFactory method, and as that is almost always invoked via
1030      * LogFactory.getFactory, any custom definition in a subclass would be
1031      * pointless. Only a class with a custom getFactory method, then invoked
1032      * directly via CustomFactoryImpl.getFactory or similar would ever call
1033      * this. Anyway, it's here just in case, though the "managed class loader"
1034      * value output to the diagnostics will not report the correct value.
1035      */
1036     protected static LogFactory newFactory(final String factoryClass,
1037                                            final ClassLoader classLoader) {
1038         return newFactory(factoryClass, classLoader, null);
1039     }
1040 
1041     /**
1042      * Implements the operations described in the javadoc for newFactory.
1043      *
1044      * @param factoryClass
1045      * @param classLoader used to load the specified factory class. This is
1046      *  expected to be either the TCCL or the classloader which loaded this
1047      *  class. Note that the classloader which loaded this class might be
1048      *  "null" (ie the bootloader) for embedded systems.
1049      * @return either a LogFactory object or a LogConfigurationException object.
1050      * @since 1.1
1051      */
1052     protected static Object createFactory(String factoryClass, ClassLoader classLoader) {
1053         // This will be used to diagnose bad configurations
1054         // and allow a useful message to be sent to the user
1055         Class logFactoryClass = null;
1056         try {
1057             if (classLoader != null) {
1058                 try {
1059                     // First the given class loader param (thread class loader)
1060 
1061                     // Warning: must typecast here & allow exception
1062                     // to be generated/caught & recast properly.
1063                     logFactoryClass = classLoader.loadClass(factoryClass);
1064                     if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
1065                         if (isDiagnosticsEnabled()) {
1066                             logDiagnostic("Loaded class " + logFactoryClass.getName() +
1067                                           " from classloader " + objectId(classLoader));
1068                         }
1069                     } else {
1070                         //
1071                         // This indicates a problem with the ClassLoader tree.
1072                         // An incompatible ClassLoader was used to load the
1073                         // implementation.
1074                         // As the same classes
1075                         // must be available in multiple class loaders,
1076                         // it is very likely that multiple JCL jars are present.
1077                         // The most likely fix for this
1078                         // problem is to remove the extra JCL jars from the
1079                         // ClassLoader hierarchy.
1080                         //
1081                         if (isDiagnosticsEnabled()) {
1082                             logDiagnostic("Factory class " + logFactoryClass.getName() +
1083                                           " loaded from classloader " + objectId(logFactoryClass.getClassLoader()) +
1084                                           " does not extend '" + LogFactory.class.getName() +
1085                                           "' as loaded by this classloader.");
1086                             logHierarchy("[BAD CL TREE] ", classLoader);
1087                         }
1088                     }
1089 
1090                     return (LogFactory) logFactoryClass.newInstance();
1091 
1092                 } catch (ClassNotFoundException ex) {
1093                     if (classLoader == thisClassLoader) {
1094                         // Nothing more to try, onwards.
1095                         if (isDiagnosticsEnabled()) {
1096                             logDiagnostic("Unable to locate any class called '" + factoryClass +
1097                                           "' via classloader " + objectId(classLoader));
1098                         }
1099                         throw ex;
1100                     }
1101                     // ignore exception, continue
1102                 } catch (NoClassDefFoundError e) {
1103                     if (classLoader == thisClassLoader) {
1104                         // Nothing more to try, onwards.
1105                         if (isDiagnosticsEnabled()) {
1106                             logDiagnostic("Class '" + factoryClass + "' cannot be loaded" +
1107                                           " via classloader " + objectId(classLoader) +
1108                                           " - it depends on some other class that cannot be found.");
1109                         }
1110                         throw e;
1111                     }
1112                     // ignore exception, continue
1113                 } catch (ClassCastException e) {
1114                     if (classLoader == thisClassLoader) {
1115                         // There's no point in falling through to the code below that
1116                         // tries again with thisClassLoader, because we've just tried
1117                         // loading with that loader (not the TCCL). Just throw an
1118                         // appropriate exception here.
1119 
1120                         final boolean implementsLogFactory = implementsLogFactory(logFactoryClass);
1121 
1122                         //
1123                         // Construct a good message: users may not actual expect that a custom implementation
1124                         // has been specified. Several well known containers use this mechanism to adapt JCL
1125                         // to their native logging system.
1126                         //
1127                         final StringBuffer msg = new StringBuffer();
1128                         msg.append("The application has specified that a custom LogFactory implementation ");
1129                         msg.append("should be used but Class '");
1130                         msg.append(factoryClass);
1131                         msg.append("' cannot be converted to '");
1132                         msg.append(LogFactory.class.getName());
1133                         msg.append("'. ");
1134                         if (implementsLogFactory) {
1135                             msg.append("The conflict is caused by the presence of multiple LogFactory classes ");
1136                             msg.append("in incompatible classloaders. ");
1137                             msg.append("Background can be found in http://commons.apache.org/logging/tech.html. ");
1138                             msg.append("If you have not explicitly specified a custom LogFactory then it is likely ");
1139                             msg.append("that the container has set one without your knowledge. ");
1140                             msg.append("In this case, consider using the commons-logging-adapters.jar file or ");
1141                             msg.append("specifying the standard LogFactory from the command line. ");
1142                         } else {
1143                             msg.append("Please check the custom implementation. ");
1144                         }
1145                         msg.append("Help can be found @http://commons.apache.org/logging/troubleshooting.html.");
1146 
1147                         if (isDiagnosticsEnabled()) {
1148                             logDiagnostic(msg.toString());
1149                         }
1150 
1151                         throw new ClassCastException(msg.toString());
1152                     }
1153 
1154                     // Ignore exception, continue. Presumably the classloader was the
1155                     // TCCL; the code below will try to load the class via thisClassLoader.
1156                     // This will handle the case where the original calling class is in
1157                     // a shared classpath but the TCCL has a copy of LogFactory and the
1158                     // specified LogFactory implementation; we will fall back to using the
1159                     // LogFactory implementation from the same classloader as this class.
1160                     //
1161                     // Issue: this doesn't handle the reverse case, where this LogFactory
1162                     // is in the webapp, and the specified LogFactory implementation is
1163                     // in a shared classpath. In that case:
1164                     // (a) the class really does implement LogFactory (bad log msg above)
1165                     // (b) the fallback code will result in exactly the same problem.
1166                 }
1167             }
1168 
1169             /* At this point, either classLoader == null, OR
1170              * classLoader was unable to load factoryClass.
1171              *
1172              * In either case, we call Class.forName, which is equivalent
1173              * to LogFactory.class.getClassLoader().load(name), ie we ignore
1174              * the classloader parameter the caller passed, and fall back
1175              * to trying the classloader associated with this class. See the
1176              * javadoc for the newFactory method for more info on the
1177              * consequences of this.
1178              *
1179              * Notes:
1180              * * LogFactory.class.getClassLoader() may return 'null'
1181              *   if LogFactory is loaded by the bootstrap classloader.
1182              */
1183             // Warning: must typecast here & allow exception
1184             // to be generated/caught & recast properly.
1185             if (isDiagnosticsEnabled()) {
1186                 logDiagnostic("Unable to load factory class via classloader " + objectId(classLoader) +
1187                               " - trying the classloader associated with this LogFactory.");
1188             }
1189             logFactoryClass = Class.forName(factoryClass);
1190             return (LogFactory) logFactoryClass.newInstance();
1191         } catch (Exception e) {
1192             // Check to see if we've got a bad configuration
1193             if (isDiagnosticsEnabled()) {
1194                 logDiagnostic("Unable to create LogFactory instance.");
1195             }
1196             if (logFactoryClass != null && !LogFactory.class.isAssignableFrom(logFactoryClass)) {
1197                 return new LogConfigurationException(
1198                     "The chosen LogFactory implementation does not extend LogFactory." +
1199                     " Please check your configuration.", e);
1200             }
1201             return new LogConfigurationException(e);
1202         }
1203     }
1204 
1205     /**
1206      * Determines whether the given class actually implements <code>LogFactory</code>.
1207      * Diagnostic information is also logged.
1208      * <p>
1209      * <strong>Usage:</strong> to diagnose whether a classloader conflict is the cause
1210      * of incompatibility. The test used is whether the class is assignable from
1211      * the <code>LogFactory</code> class loaded by the class's classloader.
1212      * @param logFactoryClass <code>Class</code> which may implement <code>LogFactory</code>
1213      * @return true if the <code>logFactoryClass</code> does extend
1214      * <code>LogFactory</code> when that class is loaded via the same
1215      * classloader that loaded the <code>logFactoryClass</code>.
1216      */
1217     private static boolean implementsLogFactory(Class logFactoryClass) {
1218         boolean implementsLogFactory = false;
1219         if (logFactoryClass != null) {
1220             try {
1221                 ClassLoader logFactoryClassLoader = logFactoryClass.getClassLoader();
1222                 if (logFactoryClassLoader == null) {
1223                     logDiagnostic("[CUSTOM LOG FACTORY] was loaded by the boot classloader");
1224                 } else {
1225                     logHierarchy("[CUSTOM LOG FACTORY] ", logFactoryClassLoader);
1226                     Class factoryFromCustomLoader
1227                         = Class.forName("org.apache.commons.logging.LogFactory", false, logFactoryClassLoader);
1228                     implementsLogFactory = factoryFromCustomLoader.isAssignableFrom(logFactoryClass);
1229                     if (implementsLogFactory) {
1230                         logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName() +
1231                                       " implements LogFactory but was loaded by an incompatible classloader.");
1232                     } else {
1233                         logDiagnostic("[CUSTOM LOG FACTORY] " + logFactoryClass.getName() +
1234                                       " does not implement LogFactory.");
1235                     }
1236                 }
1237             } catch (SecurityException e) {
1238                 //
1239                 // The application is running within a hostile security environment.
1240                 // This will make it very hard to diagnose issues with JCL.
1241                 // Consider running less securely whilst debugging this issue.
1242                 //
1243                 logDiagnostic("[CUSTOM LOG FACTORY] SecurityException thrown whilst trying to determine whether " +
1244                               "the compatibility was caused by a classloader conflict: " + e.getMessage());
1245             } catch (LinkageError e) {
1246                 //
1247                 // This should be an unusual circumstance.
1248                 // LinkageError's usually indicate that a dependent class has incompatibly changed.
1249                 // Another possibility may be an exception thrown by an initializer.
1250                 // Time for a clean rebuild?
1251                 //
1252                 logDiagnostic("[CUSTOM LOG FACTORY] LinkageError thrown whilst trying to determine whether " +
1253                               "the compatibility was caused by a classloader conflict: " + e.getMessage());
1254             } catch (ClassNotFoundException e) {
1255                 //
1256                 // LogFactory cannot be loaded by the classloader which loaded the custom factory implementation.
1257                 // The custom implementation is not viable until this is corrected.
1258                 // Ensure that the JCL jar and the custom class are available from the same classloader.
1259                 // Running with diagnostics on should give information about the classloaders used
1260                 // to load the custom factory.
1261                 //
1262                 logDiagnostic("[CUSTOM LOG FACTORY] LogFactory class cannot be loaded by classloader which loaded " +
1263                               "the custom LogFactory implementation. Is the custom factory in the right classloader?");
1264             }
1265         }
1266         return implementsLogFactory;
1267     }
1268 
1269     /**
1270      * Applets may run in an environment where accessing resources of a loader is
1271      * a secure operation, but where the commons-logging library has explicitly
1272      * been granted permission for that operation. In this case, we need to
1273      * run the operation using an AccessController.
1274      */
1275     private static InputStream getResourceAsStream(final ClassLoader loader, final String name) {
1276         return (InputStream)AccessController.doPrivileged(
1277             new PrivilegedAction() {
1278                 public Object run() {
1279                     if (loader != null) {
1280                         return loader.getResourceAsStream(name);
1281                     } else {
1282                         return ClassLoader.getSystemResourceAsStream(name);
1283                     }
1284                 }
1285             });
1286     }
1287 
1288     /**
1289      * Given a filename, return an enumeration of URLs pointing to
1290      * all the occurrences of that filename in the classpath.
1291      * <p>
1292      * This is just like ClassLoader.getResources except that the
1293      * operation is done under an AccessController so that this method will
1294      * succeed when this jarfile is privileged but the caller is not.
1295      * This method must therefore remain private to avoid security issues.
1296      * <p>
1297      * If no instances are found, an Enumeration is returned whose
1298      * hasMoreElements method returns false (ie an "empty" enumeration).
1299      * If resources could not be listed for some reason, null is returned.
1300      */
1301     private static Enumeration getResources(final ClassLoader loader, final String name) {
1302         PrivilegedAction action =
1303             new PrivilegedAction() {
1304                 public Object run() {
1305                     try {
1306                         if (loader != null) {
1307                             return loader.getResources(name);
1308                         } else {
1309                             return ClassLoader.getSystemResources(name);
1310                         }
1311                     } catch (IOException e) {
1312                         if (isDiagnosticsEnabled()) {
1313                             logDiagnostic("Exception while trying to find configuration file " +
1314                                           name + ":" + e.getMessage());
1315                         }
1316                         return null;
1317                     } catch (NoSuchMethodError e) {
1318                         // we must be running on a 1.1 JVM which doesn't support
1319                         // ClassLoader.getSystemResources; just return null in
1320                         // this case.
1321                         return null;
1322                     }
1323                 }
1324             };
1325         Object result = AccessController.doPrivileged(action);
1326         return (Enumeration) result;
1327     }
1328 
1329     /**
1330      * Given a URL that refers to a .properties file, load that file.
1331      * This is done under an AccessController so that this method will
1332      * succeed when this jarfile is privileged but the caller is not.
1333      * This method must therefore remain private to avoid security issues.
1334      * <p>
1335      * {@code Null} is returned if the URL cannot be opened.
1336      */
1337     private static Properties getProperties(final URL url) {
1338         PrivilegedAction action =
1339             new PrivilegedAction() {
1340                 public Object run() {
1341                     InputStream stream = null;
1342                     try {
1343                         // We must ensure that useCaches is set to false, as the
1344                         // default behaviour of java is to cache file handles, and
1345                         // this "locks" files, preventing hot-redeploy on windows.
1346                         URLConnection connection = url.openConnection();
1347                         connection.setUseCaches(false);
1348                         stream = connection.getInputStream();
1349                         if (stream != null) {
1350                             Properties props = new Properties();
1351                             props.load(stream);
1352                             stream.close();
1353                             stream = null;
1354                             return props;
1355                         }
1356                     } catch (IOException e) {
1357                         if (isDiagnosticsEnabled()) {
1358                             logDiagnostic("Unable to read URL " + url);
1359                         }
1360                     } finally {
1361                         if (stream != null) {
1362                             try {
1363                                 stream.close();
1364                             } catch (IOException e) {
1365                                 // ignore exception; this should not happen
1366                                 if (isDiagnosticsEnabled()) {
1367                                     logDiagnostic("Unable to close stream for URL " + url);
1368                                 }
1369                             }
1370                         }
1371                     }
1372 
1373                     return null;
1374                 }
1375             };
1376         return (Properties) AccessController.doPrivileged(action);
1377     }
1378 
1379     /**
1380      * Locate a user-provided configuration file.
1381      * <p>
1382      * The classpath of the specified classLoader (usually the context classloader)
1383      * is searched for properties files of the specified name. If none is found,
1384      * null is returned. If more than one is found, then the file with the greatest
1385      * value for its PRIORITY property is returned. If multiple files have the
1386      * same PRIORITY value then the first in the classpath is returned.
1387      * <p>
1388      * This differs from the 1.0.x releases; those always use the first one found.
1389      * However as the priority is a new field, this change is backwards compatible.
1390      * <p>
1391      * The purpose of the priority field is to allow a webserver administrator to
1392      * override logging settings in all webapps by placing a commons-logging.properties
1393      * file in a shared classpath location with a priority > 0; this overrides any
1394      * commons-logging.properties files without priorities which are in the
1395      * webapps. Webapps can also use explicit priorities to override a configuration
1396      * file in the shared classpath if needed.
1397      */
1398     private static final Properties getConfigurationFile(ClassLoader classLoader, String fileName) {
1399         Properties props = null;
1400         double priority = 0.0;
1401         URL propsUrl = null;
1402         try {
1403             Enumeration urls = getResources(classLoader, fileName);
1404 
1405             if (urls == null) {
1406                 return null;
1407             }
1408 
1409             while (urls.hasMoreElements()) {
1410                 URL url = (URL) urls.nextElement();
1411 
1412                 Properties newProps = getProperties(url);
1413                 if (newProps != null) {
1414                     if (props == null) {
1415                         propsUrl = url;
1416                         props = newProps;
1417                         String priorityStr = props.getProperty(PRIORITY_KEY);
1418                         priority = 0.0;
1419                         if (priorityStr != null) {
1420                             priority = Double.parseDouble(priorityStr);
1421                         }
1422 
1423                         if (isDiagnosticsEnabled()) {
1424                             logDiagnostic("[LOOKUP] Properties file found at '" + url + "'" +
1425                                           " with priority " + priority);
1426                         }
1427                     } else {
1428                         String newPriorityStr = newProps.getProperty(PRIORITY_KEY);
1429                         double newPriority = 0.0;
1430                         if (newPriorityStr != null) {
1431                             newPriority = Double.parseDouble(newPriorityStr);
1432                         }
1433 
1434                         if (newPriority > priority) {
1435                             if (isDiagnosticsEnabled()) {
1436                                 logDiagnostic("[LOOKUP] Properties file at '" + url + "'" +
1437                                               " with priority " + newPriority +
1438                                               " overrides file at '" + propsUrl + "'" +
1439                                               " with priority " + priority);
1440                             }
1441 
1442                             propsUrl = url;
1443                             props = newProps;
1444                             priority = newPriority;
1445                         } else {
1446                             if (isDiagnosticsEnabled()) {
1447                                 logDiagnostic("[LOOKUP] Properties file at '" + url + "'" +
1448                                               " with priority " + newPriority +
1449                                               " does not override file at '" + propsUrl + "'" +
1450                                               " with priority " + priority);
1451                             }
1452                         }
1453                     }
1454 
1455                 }
1456             }
1457         } catch (SecurityException e) {
1458             if (isDiagnosticsEnabled()) {
1459                 logDiagnostic("SecurityException thrown while trying to find/read config files.");
1460             }
1461         }
1462 
1463         if (isDiagnosticsEnabled()) {
1464             if (props == null) {
1465                 logDiagnostic("[LOOKUP] No properties file of name '" + fileName + "' found.");
1466             } else {
1467                 logDiagnostic("[LOOKUP] Properties file of name '" + fileName + "' found at '" + propsUrl + '"');
1468             }
1469         }
1470 
1471         return props;
1472     }
1473 
1474     /**
1475      * Read the specified system property, using an AccessController so that
1476      * the property can be read if JCL has been granted the appropriate
1477      * security rights even if the calling code has not.
1478      * <p>
1479      * Take care not to expose the value returned by this method to the
1480      * calling application in any way; otherwise the calling app can use that
1481      * info to access data that should not be available to it.
1482      */
1483     private static String getSystemProperty(final String key, final String def)
1484         throws SecurityException {
1485         return (String) AccessController.doPrivileged(
1486                 new PrivilegedAction() {
1487                     public Object run() {
1488                         return System.getProperty(key, def);
1489                     }
1490                 });
1491     }
1492 
1493     /**
1494      * Determines whether the user wants internal diagnostic output. If so,
1495      * returns an appropriate writer object. Users can enable diagnostic
1496      * output by setting the system property named {@link #DIAGNOSTICS_DEST_PROPERTY} to
1497      * a filename, or the special values STDOUT or STDERR.
1498      */
1499     private static PrintStream initDiagnostics() {
1500         String dest;
1501         try {
1502             dest = getSystemProperty(DIAGNOSTICS_DEST_PROPERTY, null);
1503             if (dest == null) {
1504                 return null;
1505             }
1506         } catch (SecurityException ex) {
1507             // We must be running in some very secure environment.
1508             // We just have to assume output is not wanted..
1509             return null;
1510         }
1511 
1512         if (dest.equals("STDOUT")) {
1513             return System.out;
1514         } else if (dest.equals("STDERR")) {
1515             return System.err;
1516         } else {
1517             try {
1518                 // open the file in append mode
1519                 FileOutputStream fos = new FileOutputStream(dest, true);
1520                 return new PrintStream(fos);
1521             } catch (IOException ex) {
1522                 // We should report this to the user - but how?
1523                 return null;
1524             }
1525         }
1526     }
1527 
1528     /**
1529      * Indicates true if the user has enabled internal logging.
1530      * <p>
1531      * By the way, sorry for the incorrect grammar, but calling this method
1532      * areDiagnosticsEnabled just isn't java beans style.
1533      *
1534      * @return true if calls to logDiagnostic will have any effect.
1535      * @since 1.1
1536      */
1537     protected static boolean isDiagnosticsEnabled() {
1538         return diagnosticsStream != null;
1539     }
1540 
1541     /**
1542      * Write the specified message to the internal logging destination.
1543      * <p>
1544      * Note that this method is private; concrete subclasses of this class
1545      * should not call it because the diagnosticPrefix string this
1546      * method puts in front of all its messages is LogFactory@....,
1547      * while subclasses should put SomeSubClass@...
1548      * <p>
1549      * Subclasses should instead compute their own prefix, then call
1550      * logRawDiagnostic. Note that calling isDiagnosticsEnabled is
1551      * fine for subclasses.
1552      * <p>
1553      * Note that it is safe to call this method before initDiagnostics
1554      * is called; any output will just be ignored (as isDiagnosticsEnabled
1555      * will return false).
1556      *
1557      * @param msg is the diagnostic message to be output.
1558      */
1559     private static final void logDiagnostic(String msg) {
1560         if (diagnosticsStream != null) {
1561             diagnosticsStream.print(diagnosticPrefix);
1562             diagnosticsStream.println(msg);
1563             diagnosticsStream.flush();
1564         }
1565     }
1566 
1567     /**
1568      * Write the specified message to the internal logging destination.
1569      *
1570      * @param msg is the diagnostic message to be output.
1571      * @since 1.1
1572      */
1573     protected static final void logRawDiagnostic(String msg) {
1574         if (diagnosticsStream != null) {
1575             diagnosticsStream.println(msg);
1576             diagnosticsStream.flush();
1577         }
1578     }
1579 
1580     /**
1581      * Generate useful diagnostics regarding the classloader tree for
1582      * the specified class.
1583      * <p>
1584      * As an example, if the specified class was loaded via a webapp's
1585      * classloader, then you may get the following output:
1586      * <pre>
1587      * Class com.acme.Foo was loaded via classloader 11111
1588      * ClassLoader tree: 11111 -> 22222 (SYSTEM) -> 33333 -> BOOT
1589      * </pre>
1590      * <p>
1591      * This method returns immediately if isDiagnosticsEnabled()
1592      * returns false.
1593      *
1594      * @param clazz is the class whose classloader + tree are to be
1595      * output.
1596      */
1597     private static void logClassLoaderEnvironment(Class clazz) {
1598         if (!isDiagnosticsEnabled()) {
1599             return;
1600         }
1601 
1602         try {
1603             // Deliberately use System.getProperty here instead of getSystemProperty; if
1604             // the overall security policy for the calling application forbids access to
1605             // these variables then we do not want to output them to the diagnostic stream.
1606             logDiagnostic("[ENV] Extension directories (java.ext.dir): " + System.getProperty("java.ext.dir"));
1607             logDiagnostic("[ENV] Application classpath (java.class.path): " + System.getProperty("java.class.path"));
1608         } catch (SecurityException ex) {
1609             logDiagnostic("[ENV] Security setting prevent interrogation of system classpaths.");
1610         }
1611 
1612         String className = clazz.getName();
1613         ClassLoader classLoader;
1614 
1615         try {
1616             classLoader = getClassLoader(clazz);
1617         } catch (SecurityException ex) {
1618             // not much useful diagnostics we can print here!
1619             logDiagnostic("[ENV] Security forbids determining the classloader for " + className);
1620             return;
1621         }
1622 
1623         logDiagnostic("[ENV] Class " + className + " was loaded via classloader " + objectId(classLoader));
1624         logHierarchy("[ENV] Ancestry of classloader which loaded " + className + " is ", classLoader);
1625     }
1626 
1627     /**
1628      * Logs diagnostic messages about the given classloader
1629      * and it's hierarchy. The prefix is prepended to the message
1630      * and is intended to make it easier to understand the logs.
1631      * @param prefix
1632      * @param classLoader
1633      */
1634     private static void logHierarchy(String prefix, ClassLoader classLoader) {
1635         if (!isDiagnosticsEnabled()) {
1636             return;
1637         }
1638         ClassLoader systemClassLoader;
1639         if (classLoader != null) {
1640             final String classLoaderString = classLoader.toString();
1641             logDiagnostic(prefix + objectId(classLoader) + " == '" + classLoaderString + "'");
1642         }
1643 
1644         try {
1645             systemClassLoader = ClassLoader.getSystemClassLoader();
1646         } catch (SecurityException ex) {
1647             logDiagnostic(prefix + "Security forbids determining the system classloader.");
1648             return;
1649         }
1650         if (classLoader != null) {
1651             final StringBuffer buf = new StringBuffer(prefix + "ClassLoader tree:");
1652             for(;;) {
1653                 buf.append(objectId(classLoader));
1654                 if (classLoader == systemClassLoader) {
1655                     buf.append(" (SYSTEM) ");
1656                 }
1657 
1658                 try {
1659                     classLoader = classLoader.getParent();
1660                 } catch (SecurityException ex) {
1661                     buf.append(" --> SECRET");
1662                     break;
1663                 }
1664 
1665                 buf.append(" --> ");
1666                 if (classLoader == null) {
1667                     buf.append("BOOT");
1668                     break;
1669                 }
1670             }
1671             logDiagnostic(buf.toString());
1672         }
1673     }
1674 
1675     /**
1676      * Returns a string that uniquely identifies the specified object, including
1677      * its class.
1678      * <p>
1679      * The returned string is of form "classname@hashcode", ie is the same as
1680      * the return value of the Object.toString() method, but works even when
1681      * the specified object's class has overidden the toString method.
1682      *
1683      * @param o may be null.
1684      * @return a string of form classname@hashcode, or "null" if param o is null.
1685      * @since 1.1
1686      */
1687     public static String objectId(Object o) {
1688         if (o == null) {
1689             return "null";
1690         } else {
1691             return o.getClass().getName() + "@" + System.identityHashCode(o);
1692         }
1693     }
1694 
1695     // ----------------------------------------------------------------------
1696     // Static initialiser block to perform initialisation at class load time.
1697     //
1698     // We can't do this in the class constructor, as there are many
1699     // static methods on this class that can be called before any
1700     // LogFactory instances are created, and they depend upon this
1701     // stuff having been set up.
1702     //
1703     // Note that this block must come after any variable declarations used
1704     // by any methods called from this block, as we want any static initialiser
1705     // associated with the variable to run first. If static initialisers for
1706     // variables run after this code, then (a) their value might be needed
1707     // by methods called from here, and (b) they might *override* any value
1708     // computed here!
1709     //
1710     // So the wisest thing to do is just to place this code at the very end
1711     // of the class file.
1712     // ----------------------------------------------------------------------
1713 
1714     static {
1715         // note: it's safe to call methods before initDiagnostics (though
1716         // diagnostic output gets discarded).
1717         thisClassLoader = getClassLoader(LogFactory.class);
1718         // In order to avoid confusion where multiple instances of JCL are
1719         // being used via different classloaders within the same app, we
1720         // ensure each logged message has a prefix of form
1721         // [LogFactory from classloader OID]
1722         //
1723         // Note that this prefix should be kept consistent with that
1724         // in LogFactoryImpl. However here we don't need to output info
1725         // about the actual *instance* of LogFactory, as all methods that
1726         // output diagnostics from this class are static.
1727         String classLoaderName;
1728         try {
1729             ClassLoader classLoader = thisClassLoader;
1730             if (thisClassLoader == null) {
1731                 classLoaderName = "BOOTLOADER";
1732             } else {
1733                 classLoaderName = objectId(classLoader);
1734             }
1735         } catch (SecurityException e) {
1736             classLoaderName = "UNKNOWN";
1737         }
1738         diagnosticPrefix = "[LogFactory from " + classLoaderName + "] ";
1739         diagnosticsStream = initDiagnostics();
1740         logClassLoaderEnvironment(LogFactory.class);
1741         factories = createFactoryStore();
1742         if (isDiagnosticsEnabled()) {
1743             logDiagnostic("BOOTSTRAP COMPLETED");
1744         }
1745     }
1746 }