001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.commons.logging;
019
020import java.io.BufferedReader;
021import java.io.FileOutputStream;
022import java.io.IOException;
023import java.io.InputStream;
024import java.io.InputStreamReader;
025import java.io.PrintStream;
026import java.lang.reflect.InvocationTargetException;
027import java.lang.reflect.Method;
028import java.net.URL;
029import java.net.URLConnection;
030import java.security.AccessController;
031import java.security.PrivilegedAction;
032import java.util.Enumeration;
033import java.util.Hashtable;
034import java.util.Properties;
035
036/**
037 * Factory for creating {@link Log} instances, with discovery and
038 * configuration features similar to that employed by standard Java APIs
039 * such as JAXP.
040 * <p>
041 * <strong>IMPLEMENTATION NOTE</strong> - This implementation is heavily
042 * based on the SAXParserFactory and DocumentBuilderFactory implementations
043 * (corresponding to the JAXP pluggability APIs) found in Apache Xerces.
044 *
045 * @version $Id: LogFactory.html 855121 2013-03-19 21:14:39Z tn $
046 */
047public abstract class LogFactory {
048    // Implementation note re AccessController usage
049    //
050    // It is important to keep code invoked via an AccessController to small
051    // auditable blocks. Such code must carefully evaluate all user input
052    // (parameters, system properties, config file contents, etc). As an
053    // example, a Log implementation should not write to its logfile
054    // with an AccessController anywhere in the call stack, otherwise an
055    // insecure application could configure the log implementation to write
056    // to a protected file using the privileges granted to JCL rather than
057    // to the calling application.
058    //
059    // Under no circumstance should a non-private method return data that is
060    // retrieved via an AccessController. That would allow an insecure app
061    // to invoke that method and obtain data that it is not permitted to have.
062    //
063    // Invoking user-supplied code with an AccessController set is not a major
064    // issue (eg invoking the constructor of the class specified by
065    // HASHTABLE_IMPLEMENTATION_PROPERTY). That class will be in a different
066    // trust domain, and therefore must have permissions to do whatever it
067    // is trying to do regardless of the permissions granted to JCL. There is
068    // a slight issue in that untrusted code may point that environment var
069    // to another trusted library, in which case the code runs if both that
070    // lib and JCL have the necessary permissions even when the untrusted
071    // caller does not. That's a pretty hard route to exploit though.
072
073    // ----------------------------------------------------- Manifest Constants
074
075    /**
076     * The name (<code>priority</code>) of the key in the config file used to
077     * specify the priority of that particular config file. The associated value
078     * is a floating-point number; higher values take priority over lower values.
079     */
080    public static final String PRIORITY_KEY = "priority";
081
082    /**
083     * The name (<code>use_tccl</code>) of the key in the config file used
084     * to specify whether logging classes should be loaded via the thread
085     * context class loader (TCCL), or not. By default, the TCCL is used.
086     */
087    public static final String TCCL_KEY = "use_tccl";
088
089    /**
090     * The name (<code>org.apache.commons.logging.LogFactory</code>) of the property
091     * used to identify the LogFactory implementation
092     * class name. This can be used as a system property, or as an entry in a
093     * configuration properties file.
094     */
095    public static final String FACTORY_PROPERTY = "org.apache.commons.logging.LogFactory";
096
097    /**
098     * The fully qualified class name of the fallback <code>LogFactory</code>
099     * 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}