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    
018    package org.apache.commons.logging;
019    
020    import java.io.BufferedReader;
021    import java.io.FileOutputStream;
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.io.InputStreamReader;
025    import java.io.PrintStream;
026    import java.lang.reflect.InvocationTargetException;
027    import java.lang.reflect.Method;
028    import java.net.URL;
029    import java.net.URLConnection;
030    import java.security.AccessController;
031    import java.security.PrivilegedAction;
032    import java.util.Enumeration;
033    import java.util.Hashtable;
034    import 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 862526 2013-05-20 17:07:42Z tn $
046     */
047    public 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    }