protected static Object createFactory()

in src/main/java/org/apache/commons/logging/LogFactory.java [291:418]


    protected static Object createFactory(final String factoryClassName, final ClassLoader classLoader) {
        // This will be used to diagnose bad configurations
        // and allow a useful message to be sent to the user
        Class<?> logFactoryClass = null;
        try {
            if (classLoader != null) {
                try {
                    // First the given class loader param (thread class loader)

                    // Warning: must typecast here & allow exception
                    // to be generated/caught & recast properly.
                    logFactoryClass = classLoader.loadClass(factoryClassName);
                    if (LogFactory.class.isAssignableFrom(logFactoryClass)) {
                        if (isDiagnosticsEnabled()) {
                            logDiagnostic("Loaded class " + logFactoryClass.getName() + " from class loader " + objectId(classLoader));
                        }
                    } else //
                    // This indicates a problem with the ClassLoader tree.
                    // An incompatible ClassLoader was used to load the
                    // implementation.
                    // As the same classes
                    // must be available in multiple class loaders,
                    // it is very likely that multiple JCL jars are present.
                    // The most likely fix for this
                    // problem is to remove the extra JCL jars from the
                    // ClassLoader hierarchy.
                    //
                    if (isDiagnosticsEnabled()) {
                        logDiagnostic("Factory class " + logFactoryClass.getName() + " loaded from class loader " + objectId(logFactoryClass.getClassLoader())
                                + " does not extend '" + LogFactory.class.getName() + "' as loaded by this class loader.");
                        logHierarchy("[BAD CL TREE] ", classLoader);
                    }
                    // Force a ClassCastException
                    return LogFactory.class.cast(logFactoryClass.getConstructor().newInstance());

                } catch (final ClassNotFoundException ex) {
                    if (classLoader == thisClassLoaderRef.get()) {
                        // Nothing more to try, onwards.
                        if (isDiagnosticsEnabled()) {
                            logDiagnostic("Unable to locate any class called '" + factoryClassName + "' via class loader " + objectId(classLoader));
                        }
                        throw ex;
                    }
                    // ignore exception, continue
                } catch (final NoClassDefFoundError e) {
                    if (classLoader == thisClassLoaderRef.get()) {
                        // Nothing more to try, onwards.
                        if (isDiagnosticsEnabled()) {
                            logDiagnostic("Class '" + factoryClassName + "' cannot be loaded" + " via class loader " + objectId(classLoader)
                                    + " - it depends on some other class that cannot be found.");
                        }
                        throw e;
                    }
                    // ignore exception, continue
                } catch (final ClassCastException e) {
                    if (classLoader == thisClassLoaderRef.get()) {
                        // There's no point in falling through to the code below that
                        // tries again with thisClassLoaderRef, because we've just tried
                        // loading with that loader (not the TCCL). Just throw an
                        // appropriate exception here.
                        final boolean implementsLogFactory = implementsLogFactory(logFactoryClass);
                        //
                        // Construct a good message: users may not actual expect that a custom implementation
                        // has been specified. Several well known containers use this mechanism to adapt JCL
                        // to their native logging system.
                        //
                        final StringBuilder msg = new StringBuilder();
                        msg.append("The application has specified that a custom LogFactory implementation should be used but Class '");
                        msg.append(factoryClassName);
                        msg.append("' cannot be converted to '");
                        msg.append(LogFactory.class.getName());
                        msg.append("'. ");
                        if (implementsLogFactory) {
                            msg.append("The conflict is caused by the presence of multiple LogFactory classes in incompatible class loaders. Background can");
                            msg.append(" be found in https://commons.apache.org/logging/tech.html. If you have not explicitly specified a custom LogFactory");
                            msg.append(" then it is likely that the container has set one without your knowledge. In this case, consider using the ");
                            msg.append("commons-logging-adapters.jar file or specifying the standard LogFactory from the command line. ");
                        } else {
                            msg.append("Please check the custom implementation. ");
                        }
                        msg.append("Help can be found at https://commons.apache.org/logging/troubleshooting.html.");
                        logDiagnostic(msg.toString());
                        throw new ClassCastException(msg.toString());
                    }
                    // Ignore exception, continue. Presumably the class loader was the
                    // TCCL; the code below will try to load the class via thisClassLoaderRef.
                    // This will handle the case where the original calling class is in
                    // a shared classpath but the TCCL has a copy of LogFactory and the
                    // specified LogFactory implementation; we will fall back to using the
                    // LogFactory implementation from the same class loader as this class.
                    //
                    // Issue: this doesn't handle the reverse case, where this LogFactory
                    // is in the webapp, and the specified LogFactory implementation is
                    // in a shared classpath. In that case:
                    // (a) the class really does implement LogFactory (bad log msg above)
                    // (b) the fallback code will result in exactly the same problem.
                }
            }

            /*
             * At this point, either classLoader == null, OR classLoader was unable to load factoryClass.
             *
             * In either case, we call Class.forName, which is equivalent to LogFactory.class.getClassLoader().load(name), that is, we ignore the class loader
             * parameter the caller passed, and fall back to trying the class loader associated with this class. See the Javadoc for the newFactory method for
             * more info on the consequences of this.
             *
             * Notes: * LogFactory.class.getClassLoader() may return 'null' if LogFactory is loaded by the bootstrap class loader.
             */
            // Warning: must typecast here & allow exception
            // to be generated/caught & recast properly.
            if (isDiagnosticsEnabled()) {
                logDiagnostic(
                        "Unable to load factory class via class loader " + objectId(classLoader) + " - trying the class loader associated with this LogFactory.");
            }
            logFactoryClass = Class.forName(factoryClassName);
            // Force a ClassCastException
            return LogFactory.class.cast(logFactoryClass.getConstructor().newInstance());
        } catch (final Exception e) {
            // Check to see if we've got a bad configuration
            if (isDiagnosticsEnabled()) {
                logDiagnostic("Unable to create LogFactory instance.");
            }
            if (logFactoryClass != null && !LogFactory.class.isAssignableFrom(logFactoryClass)) {
                return new LogConfigurationException("The chosen LogFactory implementation does not extend LogFactory. Please check your configuration.", e);
            }
            return new LogConfigurationException(e);
        }
    }