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