X-Git-Url: http://source.jalview.org/gitweb/?a=blobdiff_plain;f=srcjar%2Forg%2Fapache%2Flog4j%2Fxml%2FDOMConfigurator.java;fp=srcjar%2Forg%2Fapache%2Flog4j%2Fxml%2FDOMConfigurator.java;h=d3b664468f05c2cef6f8f70c245d8b9b6d19b549;hb=2d6292c0377bc6b773c6844a45d3f2c5fac352c7;hp=0000000000000000000000000000000000000000;hpb=954af328a2a6a0055572cd1a09ee035301222574;p=jalview.git diff --git a/srcjar/org/apache/log4j/xml/DOMConfigurator.java b/srcjar/org/apache/log4j/xml/DOMConfigurator.java new file mode 100644 index 0000000..d3b6644 --- /dev/null +++ b/srcjar/org/apache/log4j/xml/DOMConfigurator.java @@ -0,0 +1,1129 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.log4j.xml; + +import org.apache.log4j.Appender; +import org.apache.log4j.Layout; +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.apache.log4j.config.PropertySetter; +import org.apache.log4j.helpers.FileWatchdog; +import org.apache.log4j.helpers.Loader; +import org.apache.log4j.helpers.LogLog; +import org.apache.log4j.helpers.OptionConverter; +import org.apache.log4j.or.RendererMap; +import org.apache.log4j.spi.AppenderAttachable; +import org.apache.log4j.spi.Configurator; +import org.apache.log4j.spi.ErrorHandler; +import org.apache.log4j.spi.Filter; +import org.apache.log4j.spi.LoggerFactory; +import org.apache.log4j.spi.LoggerRepository; +import org.apache.log4j.spi.RendererSupport; +import org.apache.log4j.spi.ThrowableRenderer; +import org.apache.log4j.spi.ThrowableRendererSupport; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.FactoryConfigurationError; +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.io.InterruptedIOException; +import java.io.Reader; +import java.lang.reflect.Method; +import java.lang.reflect.InvocationTargetException; +import java.net.URL; +import java.net.URLConnection; +import java.util.Hashtable; +import java.util.Properties; + +// Contributors: Mark Womack +// Arun Katkere + +/** + Use this class to initialize the log4j environment using a DOM tree. + +
The DTD is specified in log4j.dtd. + +
Sometimes it is useful to see how log4j is reading configuration
+ files. You can enable log4j internal logging by defining the
+ log4j.debug variable on the java command
+ line. Alternatively, set the debug
attribute in the
+ log4j:configuration
element. As in
+
+ <log4j:configuration debug="true" xmlns:log4j="http://jakarta.apache.org/log4j/"> + ... + </log4j:configuration> ++ +
There are sample XML files included in the package.
+
+ @author Christopher Taylor
+ @author Ceki Gülcü
+ @author Anders Kristensen
+
+ @since 0.8.3 */
+public class DOMConfigurator implements Configurator {
+
+ static final String CONFIGURATION_TAG = "log4j:configuration";
+ static final String OLD_CONFIGURATION_TAG = "configuration";
+ static final String RENDERER_TAG = "renderer";
+ private static final String THROWABLE_RENDERER_TAG = "throwableRenderer";
+ static final String APPENDER_TAG = "appender";
+ static final String APPENDER_REF_TAG = "appender-ref";
+ static final String PARAM_TAG = "param";
+ static final String LAYOUT_TAG = "layout";
+ static final String CATEGORY = "category";
+ static final String LOGGER = "logger";
+ static final String LOGGER_REF = "logger-ref";
+ static final String CATEGORY_FACTORY_TAG = "categoryFactory";
+ static final String LOGGER_FACTORY_TAG = "loggerFactory";
+ static final String NAME_ATTR = "name";
+ static final String CLASS_ATTR = "class";
+ static final String VALUE_ATTR = "value";
+ static final String ROOT_TAG = "root";
+ static final String ROOT_REF = "root-ref";
+ static final String LEVEL_TAG = "level";
+ static final String PRIORITY_TAG = "priority";
+ static final String FILTER_TAG = "filter";
+ static final String ERROR_HANDLER_TAG = "errorHandler";
+ static final String REF_ATTR = "ref";
+ static final String ADDITIVITY_ATTR = "additivity";
+ static final String THRESHOLD_ATTR = "threshold";
+ static final String CONFIG_DEBUG_ATTR = "configDebug";
+ static final String INTERNAL_DEBUG_ATTR = "debug";
+ private static final String RESET_ATTR = "reset";
+ static final String RENDERING_CLASS_ATTR = "renderingClass";
+ static final String RENDERED_CLASS_ATTR = "renderedClass";
+
+ static final String EMPTY_STR = "";
+ static final Class[] ONE_STRING_PARAM = new Class[] {String.class};
+
+ final static String dbfKey = "javax.xml.parsers.DocumentBuilderFactory";
+
+
+ // key: appenderName, value: appender
+ Hashtable appenderBag;
+
+ Properties props;
+ LoggerRepository repository;
+
+ protected LoggerFactory catFactory = null;
+
+ /**
+ No argument constructor.
+ */
+ public
+ DOMConfigurator () {
+ appenderBag = new Hashtable();
+ }
+
+ /**
+ Used internally to parse appenders by IDREF name.
+ */
+ protected
+ Appender findAppenderByName(Document doc, String appenderName) {
+ Appender appender = (Appender) appenderBag.get(appenderName);
+
+ if(appender != null) {
+ return appender;
+ } else {
+ // Doesn't work on DOM Level 1 :
+ // Element element = doc.getElementById(appenderName);
+
+ // Endre's hack:
+ Element element = null;
+ NodeList list = doc.getElementsByTagName("appender");
+ for (int t=0; t < list.getLength(); t++) {
+ Node node = list.item(t);
+ NamedNodeMap map= node.getAttributes();
+ Node attrNode = map.getNamedItem("name");
+ if (appenderName.equals(attrNode.getNodeValue())) {
+ element = (Element) node;
+ break;
+ }
+ }
+ // Hack finished.
+
+ if(element == null) {
+ LogLog.error("No appender named ["+appenderName+"] could be found.");
+ return null;
+ } else {
+ appender = parseAppender(element);
+ if (appender != null) {
+ appenderBag.put(appenderName, appender);
+ }
+ return appender;
+ }
+ }
+ }
+ /**
+ Used internally to parse appenders by IDREF element.
+ */
+ protected
+ Appender findAppenderByReference(Element appenderRef) {
+ String appenderName = subst(appenderRef.getAttribute(REF_ATTR));
+ Document doc = appenderRef.getOwnerDocument();
+ return findAppenderByName(doc, appenderName);
+ }
+
+ /**
+ * Delegates unrecognized content to created instance if
+ * it supports UnrecognizedElementParser.
+ * @since 1.2.15
+ * @param instance instance, may be null.
+ * @param element element, may not be null.
+ * @param props properties
+ * @throws IOException thrown if configuration of owner object
+ * should be abandoned.
+ */
+ private static void parseUnrecognizedElement(final Object instance,
+ final Element element,
+ final Properties props) throws Exception {
+ boolean recognized = false;
+ if (instance instanceof UnrecognizedElementHandler) {
+ recognized = ((UnrecognizedElementHandler) instance).parseUnrecognizedElement(
+ element, props);
+ }
+ if (!recognized) {
+ LogLog.warn("Unrecognized element " + element.getNodeName());
+ }
+ }
+
+ /**
+ * Delegates unrecognized content to created instance if
+ * it supports UnrecognizedElementParser and catches and
+ * logs any exception.
+ * @since 1.2.15
+ * @param instance instance, may be null.
+ * @param element element, may not be null.
+ * @param props properties
+ */
+ private static void quietParseUnrecognizedElement(final Object instance,
+ final Element element,
+ final Properties props) {
+ try {
+ parseUnrecognizedElement(instance, element, props);
+ } catch (Exception ex) {
+ if (ex instanceof InterruptedException || ex instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ LogLog.error("Error in extension content: ", ex);
+ }
+ }
+
+ /**
+ Used internally to parse an appender element.
+ */
+ protected
+ Appender parseAppender (Element appenderElement) {
+ String className = subst(appenderElement.getAttribute(CLASS_ATTR));
+ LogLog.debug("Class name: [" + className+']');
+ try {
+ Object instance = Loader.loadClass(className).newInstance();
+ Appender appender = (Appender)instance;
+ PropertySetter propSetter = new PropertySetter(appender);
+
+ appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
+
+ NodeList children = appenderElement.getChildNodes();
+ final int length = children.getLength();
+
+ for (int loop = 0; loop < length; loop++) {
+ Node currentNode = children.item(loop);
+
+ /* We're only interested in Elements */
+ if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element currentElement = (Element)currentNode;
+
+ // Parse appender parameters
+ if (currentElement.getTagName().equals(PARAM_TAG)) {
+ setParameter(currentElement, propSetter);
+ }
+ // Set appender layout
+ else if (currentElement.getTagName().equals(LAYOUT_TAG)) {
+ appender.setLayout(parseLayout(currentElement));
+ }
+ // Add filters
+ else if (currentElement.getTagName().equals(FILTER_TAG)) {
+ parseFilters(currentElement, appender);
+ }
+ else if (currentElement.getTagName().equals(ERROR_HANDLER_TAG)) {
+ parseErrorHandler(currentElement, appender);
+ }
+ else if (currentElement.getTagName().equals(APPENDER_REF_TAG)) {
+ String refName = subst(currentElement.getAttribute(REF_ATTR));
+ if(appender instanceof AppenderAttachable) {
+ AppenderAttachable aa = (AppenderAttachable) appender;
+ LogLog.debug("Attaching appender named ["+ refName+
+ "] to appender named ["+ appender.getName()+"].");
+ aa.addAppender(findAppenderByReference(currentElement));
+ } else {
+ LogLog.error("Requesting attachment of appender named ["+
+ refName+ "] to appender named ["+ appender.getName()+
+ "] which does not implement org.apache.log4j.spi.AppenderAttachable.");
+ }
+ } else {
+ parseUnrecognizedElement(instance, currentElement, props);
+ }
+ }
+ }
+ propSetter.activate();
+ return appender;
+ }
+ /* Yes, it's ugly. But all of these exceptions point to the same
+ problem: we can't create an Appender */
+ catch (Exception oops) {
+ if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ LogLog.error("Could not create an Appender. Reported error follows.",
+ oops);
+ return null;
+ }
+ }
+
+ /**
+ Used internally to parse an {@link ErrorHandler} element.
+ */
+ protected
+ void parseErrorHandler(Element element, Appender appender) {
+ ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByClassName(
+ subst(element.getAttribute(CLASS_ATTR)),
+ org.apache.log4j.spi.ErrorHandler.class,
+ null);
+
+ if(eh != null) {
+ eh.setAppender(appender);
+
+ PropertySetter propSetter = new PropertySetter(eh);
+ NodeList children = element.getChildNodes();
+ final int length = children.getLength();
+
+ for (int loop = 0; loop < length; loop++) {
+ Node currentNode = children.item(loop);
+ if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element currentElement = (Element) currentNode;
+ String tagName = currentElement.getTagName();
+ if(tagName.equals(PARAM_TAG)) {
+ setParameter(currentElement, propSetter);
+ } else if(tagName.equals(APPENDER_REF_TAG)) {
+ eh.setBackupAppender(findAppenderByReference(currentElement));
+ } else if(tagName.equals(LOGGER_REF)) {
+ String loggerName = currentElement.getAttribute(REF_ATTR);
+ Logger logger = (catFactory == null) ? repository.getLogger(loggerName)
+ : repository.getLogger(loggerName, catFactory);
+ eh.setLogger(logger);
+ } else if(tagName.equals(ROOT_REF)) {
+ Logger root = repository.getRootLogger();
+ eh.setLogger(root);
+ } else {
+ quietParseUnrecognizedElement(eh, currentElement, props);
+ }
+ }
+ }
+ propSetter.activate();
+ appender.setErrorHandler(eh);
+ }
+ }
+
+ /**
+ Used internally to parse a filter element.
+ */
+ protected
+ void parseFilters(Element element, Appender appender) {
+ String clazz = subst(element.getAttribute(CLASS_ATTR));
+ Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz,
+ Filter.class, null);
+
+ if(filter != null) {
+ PropertySetter propSetter = new PropertySetter(filter);
+ NodeList children = element.getChildNodes();
+ final int length = children.getLength();
+
+ for (int loop = 0; loop < length; loop++) {
+ Node currentNode = children.item(loop);
+ if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element currentElement = (Element) currentNode;
+ String tagName = currentElement.getTagName();
+ if(tagName.equals(PARAM_TAG)) {
+ setParameter(currentElement, propSetter);
+ } else {
+ quietParseUnrecognizedElement(filter, currentElement, props);
+ }
+ }
+ }
+ propSetter.activate();
+ LogLog.debug("Adding filter of type ["+filter.getClass()
+ +"] to appender named ["+appender.getName()+"].");
+ appender.addFilter(filter);
+ }
+ }
+
+ /**
+ Used internally to parse an category element.
+ */
+ protected
+ void parseCategory (Element loggerElement) {
+ // Create a new org.apache.log4j.Category object from the configuration
element as
+ defined in the log4j.dtd.
+
+ */
+ static
+ public
+ void configure (Element element) {
+ DOMConfigurator configurator = new DOMConfigurator();
+ configurator.doConfigure(element, LogManager.getLoggerRepository());
+ }
+
+ /**
+ Like {@link #configureAndWatch(String, long)} except that the
+ default delay as defined by {@link FileWatchdog#DEFAULT_DELAY} is
+ used.
+
+ @param configFilename A log4j configuration file in XML format.
+
+ */
+ static
+ public
+ void configureAndWatch(String configFilename) {
+ configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
+ }
+
+ /**
+ Read the configuration file configFilename
if it
+ exists. Moreover, a thread will be created that will periodically
+ check if configFilename
has been created or
+ modified. The period is determined by the delay
+ argument. If a change or file creation is detected, then
+ configFilename
is read to configure log4j.
+
+ @param configFilename A log4j configuration file in XML format.
+ @param delay The delay in milliseconds to wait between each check.
+ */
+ static
+ public
+ void configureAndWatch(String configFilename, long delay) {
+ XMLWatchdog xdog = new XMLWatchdog(configFilename);
+ xdog.setDelay(delay);
+ xdog.start();
+ }
+
+ private interface ParseAction {
+ Document parse(final DocumentBuilder parser) throws SAXException, IOException;
+ }
+
+
+ public
+ void doConfigure(final String filename, LoggerRepository repository) {
+ ParseAction action = new ParseAction() {
+ public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
+ return parser.parse(new File(filename));
+ }
+ public String toString() {
+ return "file [" + filename + "]";
+ }
+ };
+ doConfigure(action, repository);
+ }
+
+
+ public
+ void doConfigure(final URL url, LoggerRepository repository) {
+ ParseAction action = new ParseAction() {
+ public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
+ URLConnection uConn = url.openConnection();
+ uConn.setUseCaches(false);
+ InputStream stream = uConn.getInputStream();
+ try {
+ InputSource src = new InputSource(stream);
+ src.setSystemId(url.toString());
+ return parser.parse(src);
+ } finally {
+ stream.close();
+ }
+ }
+ public String toString() {
+ return "url [" + url.toString() + "]";
+ }
+ };
+ doConfigure(action, repository);
+ }
+
+ /**
+ Configure log4j by reading in a log4j.dtd compliant XML
+ configuration file.
+
+ */
+ public
+ void doConfigure(final InputStream inputStream, LoggerRepository repository)
+ throws FactoryConfigurationError {
+ ParseAction action = new ParseAction() {
+ public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
+ InputSource inputSource = new InputSource(inputStream);
+ inputSource.setSystemId("dummy://log4j.dtd");
+ return parser.parse(inputSource);
+ }
+ public String toString() {
+ return "input stream [" + inputStream.toString() + "]";
+ }
+ };
+ doConfigure(action, repository);
+ }
+
+ /**
+ Configure log4j by reading in a log4j.dtd compliant XML
+ configuration file.
+
+ */
+ public
+ void doConfigure(final Reader reader, LoggerRepository repository)
+ throws FactoryConfigurationError {
+ ParseAction action = new ParseAction() {
+ public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
+ InputSource inputSource = new InputSource(reader);
+ inputSource.setSystemId("dummy://log4j.dtd");
+ return parser.parse(inputSource);
+ }
+ public String toString() {
+ return "reader [" + reader.toString() + "]";
+ }
+ };
+ doConfigure(action, repository);
+ }
+
+ /**
+ Configure log4j by reading in a log4j.dtd compliant XML
+ configuration file.
+
+ */
+ protected
+ void doConfigure(final InputSource inputSource, LoggerRepository repository)
+ throws FactoryConfigurationError {
+ if (inputSource.getSystemId() == null) {
+ inputSource.setSystemId("dummy://log4j.dtd");
+ }
+ ParseAction action = new ParseAction() {
+ public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
+ return parser.parse(inputSource);
+ }
+ public String toString() {
+ return "input source [" + inputSource.toString() + "]";
+ }
+ };
+ doConfigure(action, repository);
+ }
+
+
+ private final void doConfigure(final ParseAction action, final LoggerRepository repository)
+ throws FactoryConfigurationError {
+ DocumentBuilderFactory dbf = null;
+ this.repository = repository;
+ try {
+ LogLog.debug("System property is :"+
+ OptionConverter.getSystemProperty(dbfKey,
+ null));
+ dbf = DocumentBuilderFactory.newInstance();
+ LogLog.debug("Standard DocumentBuilderFactory search succeded.");
+ LogLog.debug("DocumentBuilderFactory is: "+dbf.getClass().getName());
+ } catch(FactoryConfigurationError fce) {
+ Exception e = fce.getException();
+ LogLog.debug("Could not instantiate a DocumentBuilderFactory.", e);
+ throw fce;
+ }
+
+ try {
+ dbf.setValidating(true);
+
+ DocumentBuilder docBuilder = dbf.newDocumentBuilder();
+
+ docBuilder.setErrorHandler(new SAXErrorHandler());
+ docBuilder.setEntityResolver(new Log4jEntityResolver());
+
+ Document doc = action.parse(docBuilder);
+ parse(doc.getDocumentElement());
+ } catch (Exception e) {
+ if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
+ Thread.currentThread().interrupt();
+ }
+ // I know this is miserable...
+ LogLog.error("Could not parse "+ action.toString() + ".", e);
+ }
+ }
+
+ /**
+ Configure by taking in an DOM element.
+ */
+ public void doConfigure(Element element, LoggerRepository repository) {
+ this.repository = repository;
+ parse(element);
+ }
+
+
+ /**
+ A static version of {@link #doConfigure(String, LoggerRepository)}. */
+ static
+ public
+ void configure(String filename) throws FactoryConfigurationError {
+ new DOMConfigurator().doConfigure(filename,
+ LogManager.getLoggerRepository());
+ }
+
+ /**
+ A static version of {@link #doConfigure(URL, LoggerRepository)}.
+ */
+ static
+ public
+ void configure(URL url) throws FactoryConfigurationError {
+ new DOMConfigurator().doConfigure(url, LogManager.getLoggerRepository());
+ }
+
+ /**
+ Used internally to configure the log4j framework by parsing a DOM
+ tree of XML elements based on log4j.dtd.
+
+ */
+ protected
+ void parse(Element element) {
+
+ String rootElementName = element.getTagName();
+
+ if (!rootElementName.equals(CONFIGURATION_TAG)) {
+ if(rootElementName.equals(OLD_CONFIGURATION_TAG)) {
+ LogLog.warn("The <"+OLD_CONFIGURATION_TAG+
+ "> element has been deprecated.");
+ LogLog.warn("Use the <"+CONFIGURATION_TAG+"> element instead.");
+ } else {
+ LogLog.error("DOM element is - not a <"+CONFIGURATION_TAG+"> element.");
+ return;
+ }
+ }
+
+
+ String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR));
+
+ LogLog.debug("debug attribute= \"" + debugAttrib +"\".");
+ // if the log4j.dtd is not specified in the XML file, then the
+ // "debug" attribute is returned as the empty string.
+ if(!debugAttrib.equals("") && !debugAttrib.equals("null")) {
+ LogLog.setInternalDebugging(OptionConverter.toBoolean(debugAttrib, true));
+ } else {
+ LogLog.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
+ }
+
+ //
+ // reset repository before configuration if reset="true"
+ // on configuration element.
+ //
+ String resetAttrib = subst(element.getAttribute(RESET_ATTR));
+ LogLog.debug("reset attribute= \"" + resetAttrib +"\".");
+ if(!("".equals(resetAttrib))) {
+ if (OptionConverter.toBoolean(resetAttrib, false)) {
+ repository.resetConfiguration();
+ }
+ }
+
+
+
+ String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
+ if(!confDebug.equals("") && !confDebug.equals("null")) {
+ LogLog.warn("The \""+CONFIG_DEBUG_ATTR+"\" attribute is deprecated.");
+ LogLog.warn("Use the \""+INTERNAL_DEBUG_ATTR+"\" attribute instead.");
+ LogLog.setInternalDebugging(OptionConverter.toBoolean(confDebug, true));
+ }
+
+ String thresholdStr = subst(element.getAttribute(THRESHOLD_ATTR));
+ LogLog.debug("Threshold =\"" + thresholdStr +"\".");
+ if(!"".equals(thresholdStr) && !"null".equals(thresholdStr)) {
+ repository.setThreshold(thresholdStr);
+ }
+
+ //Hashtable appenderBag = new Hashtable(11);
+
+ /* Building Appender objects, placing them in a local namespace
+ for future reference */
+
+ // First configure each category factory under the root element.
+ // Category factories need to be configured before any of
+ // categories they support.
+ //
+ String tagName = null;
+ Element currentElement = null;
+ Node currentNode = null;
+ NodeList children = element.getChildNodes();
+ final int length = children.getLength();
+
+ for (int loop = 0; loop < length; loop++) {
+ currentNode = children.item(loop);
+ if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+ currentElement = (Element) currentNode;
+ tagName = currentElement.getTagName();
+
+ if (tagName.equals(CATEGORY_FACTORY_TAG) || tagName.equals(LOGGER_FACTORY_TAG)) {
+ parseCategoryFactory(currentElement);
+ }
+ }
+ }
+
+ for (int loop = 0; loop < length; loop++) {
+ currentNode = children.item(loop);
+ if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+ currentElement = (Element) currentNode;
+ tagName = currentElement.getTagName();
+
+ if (tagName.equals(CATEGORY) || tagName.equals(LOGGER)) {
+ parseCategory(currentElement);
+ } else if (tagName.equals(ROOT_TAG)) {
+ parseRoot(currentElement);
+ } else if(tagName.equals(RENDERER_TAG)) {
+ parseRenderer(currentElement);
+ } else if(tagName.equals(THROWABLE_RENDERER_TAG)) {
+ if (repository instanceof ThrowableRendererSupport) {
+ ThrowableRenderer tr = parseThrowableRenderer(currentElement);
+ if (tr != null) {
+ ((ThrowableRendererSupport) repository).setThrowableRenderer(tr);
+ }
+ }
+ } else if (!(tagName.equals(APPENDER_TAG)
+ || tagName.equals(CATEGORY_FACTORY_TAG)
+ || tagName.equals(LOGGER_FACTORY_TAG))) {
+ quietParseUnrecognizedElement(repository, currentElement, props);
+ }
+ }
+ }
+ }
+
+
+ protected
+ String subst(final String value) {
+ return subst(value, props);
+ }
+
+ /**
+ * Substitutes property value for any references in expression.
+ *
+ * @param value value from configuration file, may contain
+ * literal text, property references or both
+ * @param props properties.
+ * @return evaluated expression, may still contain expressions
+ * if unable to expand.
+ * @since 1.2.15
+ */
+ public static String subst(final String value, final Properties props) {
+ try {
+ return OptionConverter.substVars(value, props);
+ } catch (IllegalArgumentException e) {
+ LogLog.warn("Could not perform variable substitution.", e);
+ return value;
+ }
+ }
+
+
+ /**
+ * Sets a parameter based from configuration file content.
+ *
+ * @param elem param element, may not be null.
+ * @param propSetter property setter, may not be null.
+ * @param props properties
+ * @since 1.2.15
+ */
+ public static void setParameter(final Element elem,
+ final PropertySetter propSetter,
+ final Properties props) {
+ String name = subst(elem.getAttribute("name"), props);
+ String value = (elem.getAttribute("value"));
+ value = subst(OptionConverter.convertSpecialChars(value), props);
+ propSetter.setProperty(name, value);
+ }
+
+ /**
+ * Creates an object and processes any nested param elements
+ * but does not call activateOptions. If the class also supports
+ * UnrecognizedElementParser, the parseUnrecognizedElement method
+ * will be call for any child elements other than param.
+ *
+ * @param element element, may not be null.
+ * @param props properties
+ * @param expectedClass interface or class expected to be implemented
+ * by created class
+ * @return created class or null.
+ * @throws Exception thrown if the contain object should be abandoned.
+ * @since 1.2.15
+ */
+ public static Object parseElement(final Element element,
+ final Properties props,
+ final Class expectedClass) throws Exception {
+ String clazz = subst(element.getAttribute("class"), props);
+ Object instance = OptionConverter.instantiateByClassName(clazz,
+ expectedClass, null);
+
+ if (instance != null) {
+ PropertySetter propSetter = new PropertySetter(instance);
+ NodeList children = element.getChildNodes();
+ final int length = children.getLength();
+
+ for (int loop = 0; loop < length; loop++) {
+ Node currentNode = children.item(loop);
+ if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
+ Element currentElement = (Element) currentNode;
+ String tagName = currentElement.getTagName();
+ if (tagName.equals("param")) {
+ setParameter(currentElement, propSetter, props);
+ } else {
+ parseUnrecognizedElement(instance, currentElement, props);
+ }
+ }
+ }
+ return instance;
+ }
+ return null;
+ }
+
+}
+
+
+class XMLWatchdog extends FileWatchdog {
+
+ XMLWatchdog(String filename) {
+ super(filename);
+ }
+
+ /**
+ Call {@link DOMConfigurator#configure(String)} with the
+ filename
to reconfigure log4j. */
+ public
+ void doOnChange() {
+ new DOMConfigurator().doConfigure(filename,
+ LogManager.getLoggerRepository());
+ }
+}