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