17ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu/**
27ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu * Copyright (c) 2004-2011 QOS.ch
388c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * All rights reserved.
47ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu *
588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * Permission is hereby granted, free  of charge, to any person obtaining
688c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * a  copy  of this  software  and  associated  documentation files  (the
788c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * "Software"), to  deal in  the Software without  restriction, including
888c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * without limitation  the rights to  use, copy, modify,  merge, publish,
988c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * distribute,  sublicense, and/or sell  copies of  the Software,  and to
1088c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * permit persons to whom the Software  is furnished to do so, subject to
1188c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * the following conditions:
127ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu *
1388c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * The  above  copyright  notice  and  this permission  notice  shall  be
1488c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * included in all copies or substantial portions of the Software.
157ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu *
1688c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
1788c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
1888c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
1988c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
2088c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
2188c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
2288c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
237ba0605dc97fb81bde8311510d27b3ccba170008Ceki Gulcu *
2488c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu */
2588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcupackage org.slf4j;
2688c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
2788c4c456766193e012eb890e2208473d99b91f83Ceki Gulcuimport java.io.IOException;
2888c4c456766193e012eb890e2208473d99b91f83Ceki Gulcuimport java.net.URL;
292f82a78ab216cfacbc465cc48da0038a20d45d18Hendy Irawanimport java.util.Arrays;
302f82a78ab216cfacbc465cc48da0038a20d45d18Hendy Irawanimport java.util.Enumeration;
312f82a78ab216cfacbc465cc48da0038a20d45d18Hendy Irawanimport java.util.Iterator;
322f82a78ab216cfacbc465cc48da0038a20d45d18Hendy Irawanimport java.util.LinkedHashSet;
332f82a78ab216cfacbc465cc48da0038a20d45d18Hendy Irawanimport java.util.List;
342f82a78ab216cfacbc465cc48da0038a20d45d18Hendy Irawanimport java.util.Set;
352f82a78ab216cfacbc465cc48da0038a20d45d18Hendy Irawan
36d1d27b8d8748190f397b0be72c8d85722f8c5b00Ceki Gulcuimport org.slf4j.helpers.NOPLoggerFactory;
378f28a83eb4f6b81dd46e53052e17df3aaf602347Ceki Gulcuimport org.slf4j.helpers.SubstituteLogger;
3888c4c456766193e012eb890e2208473d99b91f83Ceki Gulcuimport org.slf4j.helpers.SubstituteLoggerFactory;
3988c4c456766193e012eb890e2208473d99b91f83Ceki Gulcuimport org.slf4j.helpers.Util;
4088c4c456766193e012eb890e2208473d99b91f83Ceki Gulcuimport org.slf4j.impl.StaticLoggerBinder;
4188c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
4288c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu/**
4388c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * The <code>LoggerFactory</code> is a utility class producing Loggers for
449f10490a05f7344f4b3ef657e8991f5d51934e2fCeki Gulcu * various logging APIs, most notably for log4j, logback and JDK 1.4 logging.
4588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * Other implementations such as {@link org.slf4j.impl.NOPLogger NOPLogger} and
4688c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * {@link org.slf4j.impl.SimpleLogger SimpleLogger} are also supported.
47e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu * <p/>
48e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu * <p/>
4988c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * <code>LoggerFactory</code> is essentially a wrapper around an
5088c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * {@link ILoggerFactory} instance bound with <code>LoggerFactory</code> at
5188c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * compile time.
52e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu * <p/>
53e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu * <p/>
5488c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * Please note that all methods in <code>LoggerFactory</code> are static.
55e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu *
5626b01116722ebdd3b2471a6579f9d5a6feda83e7Ceki Gulcu *
577552796aa666c11442713cba37e7fbc339bfa020Alexander Dorokhine * @author Alexander Dorokhine
5888c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu * @author Robert Elliot
5926b01116722ebdd3b2471a6579f9d5a6feda83e7Ceki Gulcu * @author Ceki G&uuml;lc&uuml;
6026b01116722ebdd3b2471a6579f9d5a6feda83e7Ceki Gulcu *
6188c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu */
6288c4c456766193e012eb890e2208473d99b91f83Ceki Gulcupublic final class LoggerFactory {
6388c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
6431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String CODES_PREFIX = "http://www.slf4j.org/codes.html";
6588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
6631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String NO_STATICLOGGERBINDER_URL = CODES_PREFIX + "#StaticLoggerBinder";
6731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String MULTIPLE_BINDINGS_URL = CODES_PREFIX + "#multiple_bindings";
6831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String NULL_LF_URL = CODES_PREFIX + "#null_LF";
6931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String VERSION_MISMATCH = CODES_PREFIX + "#version_mismatch";
7031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String SUBSTITUTE_LOGGER_URL = CODES_PREFIX + "#substituteLogger";
7131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String LOGGER_NAME_MISMATCH_URL = CODES_PREFIX + "#loggerNameMismatch";
72e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu
7331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String UNSUCCESSFUL_INIT_URL = CODES_PREFIX + "#unsuccessfulInit";
7431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String UNSUCCESSFUL_INIT_MSG = "org.slf4j.LoggerFactory could not be successfully initialized. See also " + UNSUCCESSFUL_INIT_URL;
7588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
7631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final int UNINITIALIZED = 0;
7731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final int ONGOING_INITIALIZATION = 1;
7831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final int FAILED_INITIALIZATION = 2;
7931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final int SUCCESSFUL_INITIALIZATION = 3;
8031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final int NOP_FALLBACK_INITIALIZATION = 4;
8188c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
8231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static int INITIALIZATION_STATE = UNINITIALIZED;
8331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static SubstituteLoggerFactory TEMP_FACTORY = new SubstituteLoggerFactory();
8431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static NOPLoggerFactory NOP_FALLBACK_FACTORY = new NOPLoggerFactory();
8588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
8631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    // Support for detecting mismatched logger names.
8731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static final String DETECT_LOGGER_NAME_MISMATCH_PROPERTY = "slf4j.detectLoggerNameMismatch";
8831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static boolean DETECT_LOGGER_NAME_MISMATCH = Boolean.getBoolean(DETECT_LOGGER_NAME_MISMATCH_PROPERTY);
8997f96c5ad52259c2e620370309cf129b7ba30f54Alexander Dorokhine
9031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
9131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * It is LoggerFactory's responsibility to track version changes and manage
9231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * the compatibility list.
9331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p/>
9431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p/>
9531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * It is assumed that all versions in the 1.6 are mutually compatible.
9631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
9731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static private final String[] API_COMPATIBILITY_LIST = new String[] { "1.6", "1.7" };
9888c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
9931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    // private constructor prevents instantiation
10031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private LoggerFactory() {
10131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
10288c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
10331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
10431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * Force LoggerFactory to consider itself uninitialized.
10531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p/>
10631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p/>
10731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * This method is intended to be called by classes (in the same package) for
10831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * testing purposes. This method is internal. It can be modified, renamed or
10931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * removed at any time without notice.
11031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p/>
11131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p/>
11231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * You are strongly discouraged from calling this method in production code.
11331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
11431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static void reset() {
11531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        INITIALIZATION_STATE = UNINITIALIZED;
11631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        TEMP_FACTORY = new SubstituteLoggerFactory();
11731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
11888c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
11931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private final static void performInitialization() {
12031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        bind();
12131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (INITIALIZATION_STATE == SUCCESSFUL_INITIALIZATION) {
12231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            versionSanityCheck();
12331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
124d1d27b8d8748190f397b0be72c8d85722f8c5b00Ceki Gulcu    }
12588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
12631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static boolean messageContainsOrgSlf4jImplStaticLoggerBinder(String msg) {
12731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (msg == null)
12831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            return false;
12931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (msg.indexOf("org/slf4j/impl/StaticLoggerBinder") != -1)
13031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            return true;
13131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (msg.indexOf("org.slf4j.impl.StaticLoggerBinder") != -1)
13231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            return true;
13331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        return false;
13431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
13567f86a636d4f8b01d7ab324b8206602c47907473Ceki Gulcu
13631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private final static void bind() {
13731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        try {
13831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Set<URL> staticLoggerBinderPathSet = findPossibleStaticLoggerBinderPathSet();
13931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            reportMultipleBindingAmbiguity(staticLoggerBinderPathSet);
14031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            // the next line does the binding
14131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            StaticLoggerBinder.getSingleton();
14231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            INITIALIZATION_STATE = SUCCESSFUL_INITIALIZATION;
14331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            reportActualBinding(staticLoggerBinderPathSet);
14431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            fixSubstitutedLoggers();
14531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        } catch (NoClassDefFoundError ncde) {
14631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            String msg = ncde.getMessage();
14731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (messageContainsOrgSlf4jImplStaticLoggerBinder(msg)) {
14831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                INITIALIZATION_STATE = NOP_FALLBACK_INITIALIZATION;
14931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("Failed to load class \"org.slf4j.impl.StaticLoggerBinder\".");
15031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("Defaulting to no-operation (NOP) logger implementation");
15131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("See " + NO_STATICLOGGERBINDER_URL + " for further details.");
15231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            } else {
15331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                failedBinding(ncde);
15431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                throw ncde;
15531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
15631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        } catch (java.lang.NoSuchMethodError nsme) {
15731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            String msg = nsme.getMessage();
15831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (msg != null && msg.indexOf("org.slf4j.impl.StaticLoggerBinder.getSingleton()") != -1) {
15931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                INITIALIZATION_STATE = FAILED_INITIALIZATION;
16031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("slf4j-api 1.6.x (or later) is incompatible with this binding.");
16131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("Your binding is version 1.5.5 or earlier.");
16231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("Upgrade your binding to version 1.6.x.");
16331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
16431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            throw nsme;
16531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        } catch (Exception e) {
16631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            failedBinding(e);
16731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            throw new IllegalStateException("Unexpected initialization failure", e);
16831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
16931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
17031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
17131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    static void failedBinding(Throwable t) {
172e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu        INITIALIZATION_STATE = FAILED_INITIALIZATION;
17331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Util.report("Failed to instantiate SLF4J LoggerFactory", t);
17488c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu    }
17588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
17631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private final static void fixSubstitutedLoggers() {
17731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        List<SubstituteLogger> loggers = TEMP_FACTORY.getLoggers();
178d1d27b8d8748190f397b0be72c8d85722f8c5b00Ceki Gulcu
17931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (loggers.isEmpty()) {
18031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            return;
18131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
1824f1bf59089529a4ab386ab9270bdd58374ac36dcChetan Mehrotra
18331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Util.report("The following set of substitute loggers may have been accessed");
18431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Util.report("during the initialization phase. Logging calls during this");
18531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Util.report("phase were not honored. However, subsequent logging calls to these");
18631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Util.report("loggers will work as normally expected.");
18731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Util.report("See also " + SUBSTITUTE_LOGGER_URL);
18831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        for (SubstituteLogger subLogger : loggers) {
18931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            subLogger.setDelegate(getLogger(subLogger.getName()));
19031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Util.report(subLogger.getName());
19131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
1924f1bf59089529a4ab386ab9270bdd58374ac36dcChetan Mehrotra
19331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        TEMP_FACTORY.clear();
19488c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu    }
1954f1bf59089529a4ab386ab9270bdd58374ac36dcChetan Mehrotra
19631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private final static void versionSanityCheck() {
19731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        try {
19831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            String requested = StaticLoggerBinder.REQUESTED_API_VERSION;
19988c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
20031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            boolean match = false;
20131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            for (int i = 0; i < API_COMPATIBILITY_LIST.length; i++) {
20231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                if (requested.startsWith(API_COMPATIBILITY_LIST[i])) {
20331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                    match = true;
20431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                }
20531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
20631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (!match) {
20731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("The requested version " + requested + " by your slf4j binding is not compatible with "
20831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                                + Arrays.asList(API_COMPATIBILITY_LIST).toString());
20931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("See " + VERSION_MISMATCH + " for further details.");
21031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
21131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        } catch (java.lang.NoSuchFieldError nsfe) {
21231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            // given our large user base and SLF4J's commitment to backward
21331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            // compatibility, we cannot cry here. Only for implementations
21431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            // which willingly declare a REQUESTED_API_VERSION field do we
21531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            // emit compatibility warnings.
21631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        } catch (Throwable e) {
21731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            // we should never reach here
21831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Util.report("Unexpected problem occured during version sanity check", e);
21988c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu        }
22088c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu    }
22188c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
22231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    // We need to use the name of the StaticLoggerBinder class, but we can't reference
22331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    // the class itself.
22431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static String STATIC_LOGGER_BINDER_PATH = "org/slf4j/impl/StaticLoggerBinder.class";
22588c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
22631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static Set<URL> findPossibleStaticLoggerBinderPathSet() {
22731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        // use Set instead of list in order to deal with bug #138
22831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        // LinkedHashSet appropriate here because it preserves insertion order during iteration
22931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Set<URL> staticLoggerBinderPathSet = new LinkedHashSet<URL>();
23031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        try {
23131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            ClassLoader loggerFactoryClassLoader = LoggerFactory.class.getClassLoader();
23231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Enumeration<URL> paths;
23331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (loggerFactoryClassLoader == null) {
23431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                paths = ClassLoader.getSystemResources(STATIC_LOGGER_BINDER_PATH);
23531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            } else {
23631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                paths = loggerFactoryClassLoader.getResources(STATIC_LOGGER_BINDER_PATH);
23731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
23831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            while (paths.hasMoreElements()) {
23931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                URL path = (URL) paths.nextElement();
24031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                staticLoggerBinderPathSet.add(path);
24131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
24231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        } catch (IOException ioe) {
24331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Util.report("Error getting resources from path", ioe);
24431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
24531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        return staticLoggerBinderPathSet;
24688c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu    }
247e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu
24831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static boolean isAmbiguousStaticLoggerBinderPathSet(Set<URL> staticLoggerBinderPathSet) {
24931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        return staticLoggerBinderPathSet.size() > 1;
250e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu    }
25188c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
25231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
25331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * Prints a warning message on the console if multiple bindings were found on the class path.
25431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * No reporting is done otherwise.
25531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
25631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
25731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static void reportMultipleBindingAmbiguity(Set<URL> staticLoggerBinderPathSet) {
25831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) {
25931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Util.report("Class path contains multiple SLF4J bindings.");
26031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Iterator<URL> iterator = staticLoggerBinderPathSet.iterator();
26131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            while (iterator.hasNext()) {
26231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                URL path = (URL) iterator.next();
26331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("Found binding in [" + path + "]");
26431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
26531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Util.report("See " + MULTIPLE_BINDINGS_URL + " for an explanation.");
26631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
267e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu    }
268e5eb0b068d3e99fb5a39c82ce6f72e484f33e9d1Ceki Gulcu
26931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static void reportActualBinding(Set<URL> staticLoggerBinderPathSet) {
27031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (isAmbiguousStaticLoggerBinderPathSet(staticLoggerBinderPathSet)) {
27131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Util.report("Actual binding is of type [" + StaticLoggerBinder.getSingleton().getLoggerFactoryClassStr() + "]");
27231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
27331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
27488c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
27531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
27631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * Return a logger named according to the name parameter using the statically
27731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * bound {@link ILoggerFactory} instance.
27831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
27931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @param name The name of the logger.
28031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @return logger
28131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
28231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    public static Logger getLogger(String name) {
28331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        ILoggerFactory iLoggerFactory = getILoggerFactory();
28431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        return iLoggerFactory.getLogger(name);
28597f96c5ad52259c2e620370309cf129b7ba30f54Alexander Dorokhine    }
28688c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu
28731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
28831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * Return a logger named corresponding to the class passed as parameter, using
28931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * the statically bound {@link ILoggerFactory} instance.
29031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
29131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p>In case the the <code>clazz</code> parameter differs from the name of
29231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * the caller as computed internally by SLF4J, a logger name mismatch warning will be
29331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * printed but only if the <code>slf4j.detectLoggerNameMismatch</code> system property is
29431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * set to true. By default, this property is not set and no warnings will be printed
29531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * even in case of a logger name mismatch.
29631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
29731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @param clazz the returned logger will be named after clazz
29831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @return logger
29931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
30031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
30131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @see <a href="http://www.slf4j.org/codes.html#loggerNameMismatch">Detected logger name mismatch</a>
30231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
30331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    public static Logger getLogger(Class<?> clazz) {
30431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        Logger logger = getLogger(clazz.getName());
30531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (DETECT_LOGGER_NAME_MISMATCH) {
30631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            Class<?> autoComputedCallingClass = Util.getCallingClass();
30731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            if (nonMatchingClasses(clazz, autoComputedCallingClass)) {
30831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report(String.format("Detected logger name mismatch. Given name: \"%s\"; computed name: \"%s\".", logger.getName(),
30931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                                autoComputedCallingClass.getName()));
31031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu                Util.report("See " + LOGGER_NAME_MISMATCH_URL + " for an explanation");
31131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            }
31231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
31331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        return logger;
31431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    }
315c0f5835dcd6fdf7f9e2224211ccf8fe6b98cd7c7Ceki Gulcu
31631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    private static boolean nonMatchingClasses(Class<?> clazz, Class<?> autoComputedCallingClass) {
31731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        return !autoComputedCallingClass.isAssignableFrom(clazz);
31888c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu    }
31931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu
32031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    /**
32131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * Return the {@link ILoggerFactory} instance in use.
32231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p/>
32331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * <p/>
32431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * ILoggerFactory instance is bound with this class at compile time.
32531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     *
32631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     * @return the ILoggerFactory instance in use
32731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu     */
32831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu    public static ILoggerFactory getILoggerFactory() {
32931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        if (INITIALIZATION_STATE == UNINITIALIZED) {
33031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            INITIALIZATION_STATE = ONGOING_INITIALIZATION;
33131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            performInitialization();
33231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
33331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        switch (INITIALIZATION_STATE) {
33431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        case SUCCESSFUL_INITIALIZATION:
33531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            return StaticLoggerBinder.getSingleton().getLoggerFactory();
33631212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        case NOP_FALLBACK_INITIALIZATION:
33731212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            return NOP_FALLBACK_FACTORY;
33831212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        case FAILED_INITIALIZATION:
33931212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            throw new IllegalStateException(UNSUCCESSFUL_INIT_MSG);
34031212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        case ONGOING_INITIALIZATION:
34131212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            // support re-entrant behavior.
34231212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            // See also http://bugzilla.slf4j.org/show_bug.cgi?id=106
34331212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu            return TEMP_FACTORY;
34431212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        }
34531212435723e2dfd5d6716d1f6a7b0e66a1e6b38Ceki Gulcu        throw new IllegalStateException("Unreachable code");
34688c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu    }
34788c4c456766193e012eb890e2208473d99b91f83Ceki Gulcu}
348