public static LogFactory getFactory()

in src/main/java/org/apache/commons/logging/LogFactory.java [724:910]


    public static LogFactory getFactory() throws LogConfigurationException {
        // Identify the class loader we will be using
        final ClassLoader contextClassLoader = getContextClassLoaderInternal();

        // This is an odd enough situation to report about. This
        // output will be a nuisance on JDK1.1, as the system
        // class loader is null in that environment.
        if (contextClassLoader == null) {
            logDiagnostic("Context class loader is null.");
        }

        // Return any previously registered factory for this class loader
        LogFactory factory = getCachedFactory(contextClassLoader);
        if (factory != null) {
            return factory;
        }

        if (isDiagnosticsEnabled()) {
            logDiagnostic(
                    "[LOOKUP] LogFactory implementation requested for the first time for context class loader " +
                    objectId(contextClassLoader));
            logHierarchy("[LOOKUP] ", contextClassLoader);
        }

        // Load properties file.
        //
        // If the properties file exists, then its contents are used as
        // "attributes" on the LogFactory implementation class. One particular
        // property may also control which LogFactory concrete subclass is
        // used, but only if other discovery mechanisms fail.
        //
        // As the properties file (if it exists) will be used one way or
        // another in the end we may as well look for it first.

        final Properties props = getConfigurationFile(contextClassLoader, FACTORY_PROPERTIES);

        // Determine whether we will be using the thread context class loader to
        // load logging classes or not by checking the loaded properties file (if any).
        boolean useTccl = contextClassLoader != null;
        if (props != null) {
            final String useTCCLStr = props.getProperty(TCCL_KEY);
            useTccl &= useTCCLStr == null || Boolean.parseBoolean(useTCCLStr);
        }
        // If TCCL is still enabled at this point, we check if it resolves this class
        if (useTccl) {
            try {
                if (!LogFactory.class.equals(Class.forName(LogFactory.class.getName(), false, contextClassLoader))) {
                    logDiagnostic(() -> "The class " + LogFactory.class.getName() + " loaded by the context class loader " + objectId(contextClassLoader)
                            + " and this class differ. Disabling the usage of the context class loader."
                            + "Background can be found in https://commons.apache.org/logging/tech.html. ");
                    logHierarchy("[BAD CL TREE] ", contextClassLoader);
                    useTccl = false;
                }
            } catch (final ClassNotFoundException ignored) {
                logDiagnostic(() -> "The class " + LogFactory.class.getName() + " is not present in the the context class loader "
                        + objectId(contextClassLoader) + ". Disabling the usage of the context class loader."
                        + "Background can be found in https://commons.apache.org/logging/tech.html. ");
                logHierarchy("[BAD CL TREE] ", contextClassLoader);
                useTccl = false;
            }
        }
        final ClassLoader baseClassLoader = useTccl ? contextClassLoader : thisClassLoaderRef.get();

        // Determine which concrete LogFactory subclass to use.
        // First, try a global system property
        logDiagnostic(() -> "[LOOKUP] Looking for system property [" + FACTORY_PROPERTY +
                      "] to define the LogFactory subclass to use...");

        try {
            final String factoryClass = getSystemProperty(FACTORY_PROPERTY, null);
            if (factoryClass != null) {
                logDiagnostic(() -> "[LOOKUP] Creating an instance of LogFactory class '" + factoryClass +
                              "' as specified by system property " + FACTORY_PROPERTY);
                factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
            } else {
                logDiagnostic(() -> "[LOOKUP] No system property [" + FACTORY_PROPERTY + "] defined.");
            }
        } catch (final SecurityException e) {
            logDiagnostic(() -> "[LOOKUP] A security exception occurred while trying to create an instance of the custom factory class" + ": ["
                    + trim(e.getMessage()) + "]. Trying alternative implementations...");
            // ignore
        } catch (final RuntimeException e) {
            // This is not consistent with the behavior when a bad LogFactory class is
            // specified in a services file.
            //
            // One possible exception that can occur here is a ClassCastException when
            // the specified class wasn't castable to this LogFactory type.
            logDiagnostic(() -> "[LOOKUP] An exception occurred while trying to create an instance of the custom factory class: [" + trim(e.getMessage())
                    + "] as specified by a system property.");
            throw e;
        }
        //
        // Second, try to find a service by using the JDK 1.3 class
        // discovery mechanism, which involves putting a file with the name
        // of an interface class in the META-INF/services directory, where the
        // contents of the file is a single line specifying a concrete class
        // that implements the desired interface.
        if (factory == null) {
            logDiagnostic("[LOOKUP] Using ServiceLoader  to define the LogFactory subclass to use...");
            try {
                final ServiceLoader<LogFactory> serviceLoader = ServiceLoader.load(LogFactory.class, baseClassLoader);
                final Iterator<LogFactory> iterator = serviceLoader.iterator();

                int i = MAX_BROKEN_SERVICES;
                while (factory == null && i-- > 0) {
                    try {
                        if (iterator.hasNext()) {
                            factory = iterator.next();
                        }
                    } catch (final ServiceConfigurationError | LinkageError ex) {
                        logDiagnostic(() -> "[LOOKUP] An exception occurred while trying to find an instance of LogFactory: [" + trim(ex.getMessage())
                                + "]. Trying alternative implementations...");
                    }
                }
            } catch (final Exception ex) {
                // note: if the specified LogFactory class wasn't compatible with LogFactory
                // for some reason, a ClassCastException will be caught here, and attempts will
                // continue to find a compatible class.
                logDiagnostic(() -> "[LOOKUP] A security exception occurred while trying to create an instance of the custom factory class: ["
                        + trim(ex.getMessage()) + "]. Trying alternative implementations...");
                // ignore
            }
        }
        //
        // Third try looking into the properties file read earlier (if found)
        if (factory == null) {
            if (props != null) {
                logDiagnostic(() ->
                    "[LOOKUP] Looking in properties file for entry with key '" + FACTORY_PROPERTY +
                    "' to define the LogFactory subclass to use...");
                final String factoryClass = props.getProperty(FACTORY_PROPERTY);
                if (factoryClass != null) {
                    logDiagnostic(() ->
                        "[LOOKUP] Properties file specifies LogFactory subclass '" + factoryClass + "'");
                    factory = newFactory(factoryClass, baseClassLoader, contextClassLoader);
                    // TODO: think about whether we need to handle exceptions from newFactory
                } else {
                    logDiagnostic("[LOOKUP] Properties file has no entry specifying LogFactory subclass.");
                }
            } else {
                logDiagnostic("[LOOKUP] No properties file available to determine LogFactory subclass from..");
            }
        }
        //
        // Fourth, try one of the three provided factories first from the specified classloader
        // and then from the current one.
        if (factory == null) {
            factory = newStandardFactory(baseClassLoader);
        }
        if (factory == null && baseClassLoader != thisClassLoaderRef.get()) {
            factory = newStandardFactory(thisClassLoaderRef.get());
        }
        if (factory != null) {
            if (isDiagnosticsEnabled()) {
                logDiagnostic("Created object " + objectId(factory) + " to manage class loader " + objectId(contextClassLoader));
            }
        } else {
            logDiagnostic(() ->
                "[LOOKUP] Loading the default LogFactory implementation '" + FACTORY_DEFAULT +
                "' via the same class loader that loaded this LogFactory class (ie not looking in the context class loader).");
            // Note: unlike the above code which can try to load custom LogFactory
            // implementations via the TCCL, we don't try to load the default LogFactory
            // implementation via the context class loader because:
            // * that can cause problems (see comments in newFactory method)
            // * no-one should be customizing the code of the default class
            // Yes, we do give up the ability for the child to ship a newer
            // version of the LogFactoryImpl class and have it used dynamically
            // by an old LogFactory class in the parent, but that isn't
            // necessarily a good idea anyway.
            factory = newFactory(FACTORY_DEFAULT, thisClassLoaderRef.get(), contextClassLoader);
        }
        if (factory != null) {
            /**
             * Always cache using context class loader.
             */
            cacheFactory(contextClassLoader, factory);
            if (props != null) {
                final Enumeration<?> names = props.propertyNames();
                while (names.hasMoreElements()) {
                    final String name = Objects.toString(names.nextElement(), null);
                    final String value = props.getProperty(name);
                    factory.setAttribute(name, value);
                }
            }
        }
        return factory;
    }