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