/** * Logback: the reliable, generic, fast and flexible logging framework. * Copyright (C) 1999-2013, QOS.ch. All rights reserved. * * This program and the accompanying materials are dual-licensed under * either the terms of the Eclipse Public License v1.0 as published by * the Eclipse Foundation * * or (per the licensee's choosing) * * under the terms of the GNU Lesser General Public License version 2.1 * as published by the Free Software Foundation. */ package ch.qos.logback.core.joran; import ch.qos.logback.core.Context; import ch.qos.logback.core.joran.event.SaxEvent; import ch.qos.logback.core.joran.event.SaxEventRecorder; import ch.qos.logback.core.joran.spi.*; import ch.qos.logback.core.joran.util.ConfigurationWatchListUtil; import ch.qos.logback.core.spi.ContextAwareBase; import ch.qos.logback.core.status.StatusUtil; import org.xml.sax.InputSource; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.List; import static ch.qos.logback.core.CoreConstants.SAFE_JORAN_CONFIGURATION; public abstract class GenericConfigurator extends ContextAwareBase { protected Interpreter interpreter; /** * Configures logback with the configuration XML read from a file, * located at the given URL * * @param url URL to the file, containing the configuration XML * @throws JoranException configuration error occurred */ public final void doConfigure(URL url) throws JoranException { InputStream in = null; try { informContextOfURLUsedForConfiguration(getContext(), url); URLConnection urlConnection = url.openConnection(); // per http://jira.qos.ch/browse/LBCORE-105 // per http://jira.qos.ch/browse/LBCORE-127 urlConnection.setUseCaches(false); // this closes the stream for us in = urlConnection.getInputStream(); doConfigure(in); } catch (IOException ioe) { String errMsg = "Could not open URL [" + url + "]."; addError(errMsg, ioe); throw new JoranException(errMsg, ioe); } } /** * Configures logback with the configuration XML read from a file, * located at the given path on the host filesystem * * @param filename path to the file, containing the configuration XML * @throws JoranException configuration error occurred */ public final void doConfigure(String filename) throws JoranException { doConfigure(new File(filename)); } /** * Configures logback with the configuration XML read from a given file * * @param file the file, containing the configuration XML * @throws JoranException configuration error occurred */ public final void doConfigure(File file) throws JoranException { FileInputStream fis = null; try { informContextOfURLUsedForConfiguration(getContext(), file.toURI().toURL()); fis = new FileInputStream(file); // this closes the stream for us doConfigure(fis); } catch (IOException ioe) { String errMsg = "Could not open [" + file.getPath() + "]."; addError(errMsg, ioe); throw new JoranException(errMsg, ioe); } } /** * Adds the URL of the used configuration file to the watch list, which is * periodically scanned for changes when the "scan" flag is set in logback.xml * ({@code <configuration scan="true" ...>}). * * @param context the logger context to modify * @param url the URL to add */ public static void informContextOfURLUsedForConfiguration(Context context, URL url) { ConfigurationWatchListUtil.setMainWatchURL(context, url); } /** * Configures logback with the configuraiton XML read from an input stream, * and then closes the stream * * @param inputStream stream to contents of configuration XML * @throws JoranException configuration error occurred */ public final void doConfigure(InputStream inputStream) throws JoranException { try { doConfigure(new InputSource(inputStream)); } finally { try { inputStream.close(); } catch (IOException ioe) { String errMsg = "Could not close the stream"; addError(errMsg, ioe); throw new JoranException(errMsg, ioe); } } } protected abstract void addInstanceRules(RuleStore rs); protected abstract void addImplicitRules(Interpreter interpreter); protected void addDefaultNestedComponentRegistryRules(DefaultNestedComponentRegistry registry) { } protected ElementPath initialElementPath() { return new ElementPath(); } /** * Builds a generic configuration-XML interpreter */ protected void buildInterpreter() { RuleStore rs = new SimpleRuleStore(context); addInstanceRules(rs); this.interpreter = new Interpreter(context, rs, initialElementPath()); InterpretationContext interpretationContext = interpreter.getInterpretationContext(); interpretationContext.setContext(context); addImplicitRules(interpreter); addDefaultNestedComponentRegistryRules(interpretationContext.getDefaultNestedComponentRegistry()); } /** * Configures logback with the configuration XML read from an input source. * * @param inputSource the input source, containing the configuration XML * @throws JoranException */ private final void doConfigure(final InputSource inputSource) throws JoranException { long threshold = System.currentTimeMillis(); if (!ConfigurationWatchListUtil.wasConfigurationWatchListReset(context)) { informContextOfURLUsedForConfiguration(getContext(), null); } SaxEventRecorder recorder = new SaxEventRecorder(context); recorder.recordEvents(inputSource); doConfigure(recorder.getSaxEventList()); // no exceptions a this level StatusUtil statusUtil = new StatusUtil(context); if (statusUtil.noXMLParsingErrorsOccurred(threshold)) { addInfo("Registering current configuration as safe fallback point"); registerSafeConfiguration(); } } /** * Configures logback with SAX events of configuration XML * * @param eventList list of SAX events * @throws JoranException configuration error occurred */ public void doConfigure(final List<SaxEvent> eventList) throws JoranException { buildInterpreter(); // disallow simultaneous configurations of the same context synchronized (context.getConfigurationLock()) { interpreter.getEventPlayer().play(eventList); } } /** * Register the current event list in the interpreter as a safe * configuration point. * * @since 0.9.30 */ public void registerSafeConfiguration() { context.putObject(SAFE_JORAN_CONFIGURATION, interpreter.getEventPlayer().getCopyOfPlayerEventList()); } /** * Recall the event list previously registered as a safe point. * @return the SAX event list */ public List<SaxEvent> recallSafeConfiguration() { return (List<SaxEvent>) context.getObject(SAFE_JORAN_CONFIGURATION); } }