001package ch.qos.logback.classic.util;
002
003import ch.qos.logback.classic.ClassicConstants;
004import ch.qos.logback.classic.LoggerContext;
005import ch.qos.logback.classic.spi.Configurator;
006import ch.qos.logback.core.LogbackException;
007import ch.qos.logback.core.spi.ContextAwareBase;
008import ch.qos.logback.core.status.InfoStatus;
009import ch.qos.logback.core.status.StatusManager;
010import ch.qos.logback.core.util.Loader;
011import ch.qos.logback.core.util.OptionHelper;
012import ch.qos.logback.classic.joran.JoranConfigurator;
013import ch.qos.logback.core.joran.spi.JoranException;
014
015import java.io.File;
016import java.io.IOException;
017import java.net.MalformedURLException;
018import java.net.URL;
019import java.util.Set;
020
021/**
022 * @since 1.3.0-beta1
023 */
024public class DefaultJoranConfigurator extends ContextAwareBase implements Configurator {
025
026    final public static String AUTOCONFIG_FILE = "logback.xml";
027    final public static String TEST_AUTOCONFIG_FILE = "logback-test.xml";
028
029    @Override
030    public ExecutionStatus configure(LoggerContext loggerContext) {
031        URL url = findURLOfDefaultConfigurationFile(true);
032        if (url != null) {
033            try {
034                configureByResource(url);
035            } catch (JoranException e) {
036                e.printStackTrace();
037            }
038            // we tried and that counts Mary.
039            return ExecutionStatus.DO_NOT_INVOKE_NEXT_IF_ANY;
040        } else {
041            return ExecutionStatus.INVOKE_NEXT_IF_ANY;
042        }
043    }
044
045    public void configureByResource(URL url) throws JoranException {
046        if (url == null) {
047            throw new IllegalArgumentException("URL argument cannot be null");
048        }
049        final String urlString = url.toString();
050        if (urlString.endsWith("xml")) {
051            JoranConfigurator configurator = new JoranConfigurator();
052            configurator.setContext(context);
053            configurator.doConfigure(url);
054        } else {
055            throw new LogbackException(
056                    "Unexpected filename extension of file [" + url.toString() + "]. Should be .xml");
057        }
058    }
059
060    public URL findURLOfDefaultConfigurationFile(boolean updateStatus) {
061        ClassLoader myClassLoader = Loader.getClassLoaderOfObject(this);
062        URL url = findConfigFileURLFromSystemProperties(myClassLoader, updateStatus);
063        if (url != null) {
064            return url;
065        }
066
067        url = getResource(TEST_AUTOCONFIG_FILE, myClassLoader, updateStatus);
068        if (url != null) {
069            return url;
070        }
071
072        return getResource(AUTOCONFIG_FILE, myClassLoader, updateStatus);
073    }
074
075    private URL findConfigFileURLFromSystemProperties(ClassLoader classLoader, boolean updateStatus) {
076        String logbackConfigFile = OptionHelper.getSystemProperty(ClassicConstants.CONFIG_FILE_PROPERTY);
077        if (logbackConfigFile != null) {
078            URL result = null;
079            try {
080                result = new URL(logbackConfigFile);
081                return result;
082            } catch (MalformedURLException e) {
083                // so, resource is not a URL:
084                // attempt to get the resource from the class path
085                result = Loader.getResource(logbackConfigFile, classLoader);
086                if (result != null) {
087                    return result;
088                }
089                File f = new File(logbackConfigFile);
090                if (f.exists() && f.isFile()) {
091                    try {
092                        result = f.toURI().toURL();
093                        return result;
094                    } catch (MalformedURLException e1) {
095                    }
096                }
097            } finally {
098                if (updateStatus) {
099                    statusOnResourceSearch(logbackConfigFile, classLoader, result);
100                }
101            }
102        }
103        return null;
104    }
105
106    private URL getResource(String filename, ClassLoader myClassLoader, boolean updateStatus) {
107        URL url = Loader.getResource(filename, myClassLoader);
108        if (updateStatus) {
109            statusOnResourceSearch(filename, myClassLoader, url);
110        }
111        return url;
112    }
113
114    private void statusOnResourceSearch(String resourceName, ClassLoader classLoader, URL url) {
115        StatusManager sm = context.getStatusManager();
116        if (url == null) {
117            sm.add(new InfoStatus("Could NOT find resource [" + resourceName + "]", context));
118        } else {
119            sm.add(new InfoStatus("Found resource [" + resourceName + "] at [" + url.toString() + "]", context));
120            multiplicityWarning(resourceName, classLoader);
121        }
122    }
123
124    private void multiplicityWarning(String resourceName, ClassLoader classLoader) {
125        Set<URL> urlSet = null;
126        try {
127            urlSet = Loader.getResources(resourceName, classLoader);
128        } catch (IOException e) {
129            addError("Failed to get url list for resource [" + resourceName + "]", e);
130        }
131        if (urlSet != null && urlSet.size() > 1) {
132            addWarn("Resource [" + resourceName + "] occurs multiple times on the classpath.");
133            for (URL url : urlSet) {
134                addWarn("Resource [" + resourceName + "] occurs at [" + url.toString() + "]");
135            }
136        }
137    }
138}