| /* |
| * Copyright (C) The Apache Software Foundation. All rights reserved. |
| * |
| * This software is published under the terms of the Apache Software |
| * License version 1.1, a copy of which has been included with this |
| * distribution in the LICENSE.APL file. */ |
| |
| package org.apache.log4j.xml; |
| |
| import java.util.*; |
| |
| import java.net.URL; |
| |
| import org.w3c.dom.*; |
| import java.lang.reflect.Method; |
| import org.apache.log4j.Category; |
| import org.apache.log4j.spi.OptionHandler; |
| import org.apache.log4j.spi.ErrorHandler; |
| import org.apache.log4j.spi.AppenderAttachable; |
| import org.apache.log4j.spi.Configurator; |
| import org.apache.log4j.spi.CategoryFactory; |
| import org.apache.log4j.Appender; |
| import org.apache.log4j.Layout; |
| import org.apache.log4j.Level; |
| import org.apache.log4j.Hierarchy; |
| import org.apache.log4j.BasicConfigurator; |
| import org.apache.log4j.spi.Filter; |
| import org.apache.log4j.helpers.LogLog; |
| import org.apache.log4j.config.PropertySetter; |
| import org.apache.log4j.helpers.OptionConverter; |
| import org.apache.log4j.helpers.FileWatchdog; |
| import org.apache.log4j.helpers.Loader; |
| import org.xml.sax.InputSource; |
| import java.io.FileInputStream; |
| import java.io.InputStream; |
| import java.io.Reader; |
| import java.io.IOException; |
| import java.net.URL; |
| import javax.xml.parsers.DocumentBuilderFactory; |
| import javax.xml.parsers.DocumentBuilder; |
| import javax.xml.parsers.FactoryConfigurationError; |
| |
| // Contributors: Mark Womack <mwomack@bevocal.com> |
| |
| |
| /** |
| Use this class to initialize the log4j environment using a DOM tree. |
| |
| <p>The DTD is specified in <a |
| href="doc-files/log4j.dtd"><b>log4j.dtd</b></a>. |
| |
| <p>Sometimes it is useful to see how log4j is reading configuration |
| files. You can enable log4j internal logging by defining the |
| <b>log4j.debug</b> variable on the java command |
| line. Alternatively, set the <code>debug</code> attribute in the |
| <code>log4j:configuration</code> element. As in |
| <pre> |
| <log4j:configuration debug=true" xmlns:log4j="http://jakarta.apache.org/log4j/"> |
| ... |
| </log4j:configuration> |
| </pre> |
| |
| <p>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 extends BasicConfigurator implements Configurator { |
| |
| static final String CONFIGURATION_TAG = "log4j:configuration"; |
| static final String OLD_CONFIGURATION_TAG = "configuration"; |
| static final String RENDERER_TAG = "renderer"; |
| 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 CATEGORY_FACTORY_TAG = "categoryFactory"; |
| 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 LEVEL_TAG = "level"; |
| 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 DISABLE_OVERRIDE_ATTR = "disableOverride"; |
| static final String DISABLE_ATTR = "disable"; |
| static final String CONFIG_DEBUG_ATTR = "configDebug"; |
| static final String INTERNAL_DEBUG_ATTR = "debug"; |
| 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; |
| |
| /** |
| No argument constructor. |
| */ |
| public |
| DOMConfigurator () { |
| appenderBag = new Hashtable(); |
| } |
| |
| /** |
| Used internally to parse appenders by IDREF. |
| */ |
| protected |
| Appender findAppenderByReference(Element appenderRef) { |
| String appenderName = subst(appenderRef.getAttribute(REF_ATTR)); |
| |
| Appender appender = (Appender) appenderBag.get(appenderName); |
| if(appender != null) { |
| return appender; |
| } else { |
| Document doc = appenderRef.getOwnerDocument(); |
| |
| // 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); |
| appenderBag.put(appenderName, appender); |
| return appender; |
| } |
| } |
| } |
| |
| /** |
| 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."); |
| } |
| } |
| } |
| } |
| 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) { |
| 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) { |
| 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); |
| } |
| } |
| } |
| 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); |
| } |
| } |
| } |
| propSetter.activate(); |
| appender.addFilter(filter); |
| } |
| } |
| |
| /** |
| Used internally to parse an category element. |
| */ |
| protected |
| void parseCategory (Element categoryElement, Hierarchy hierarchy) { |
| // Create a new org.apache.log4j.Category object from the <category> element. |
| String catName = subst(categoryElement.getAttribute(NAME_ATTR)); |
| |
| Category cat; |
| |
| String className = subst(categoryElement.getAttribute(CLASS_ATTR)); |
| |
| |
| if(EMPTY_STR.equals(className)) { |
| LogLog.debug("Retreiving an instance of org.apache.log4j.Category."); |
| cat = hierarchy.getInstance(catName); |
| } |
| else { |
| LogLog.debug("Desired category sub-class: ["+className+']'); |
| try { |
| Class clazz = Loader.loadClass(className); |
| Method getInstanceMethod = clazz.getMethod("getInstance", |
| ONE_STRING_PARAM); |
| cat = (Category) getInstanceMethod.invoke(null, new Object[] {catName}); |
| } catch (Exception oops) { |
| LogLog.error("Could not retrieve category ["+catName+ |
| "]. Reported error follows.", oops); |
| return; |
| } |
| } |
| |
| // Setting up a category needs to be an atomic operation, in order |
| // to protect potential log operations while category |
| // configuration is in progress. |
| synchronized(cat) { |
| boolean additivity = OptionConverter.toBoolean( |
| subst(categoryElement.getAttribute(ADDITIVITY_ATTR)), |
| true); |
| |
| LogLog.debug("Setting ["+cat.getName()+"] additivity to ["+additivity+"]."); |
| cat.setAdditivity(additivity); |
| parseChildrenOfCategoryElement(categoryElement, cat, false); |
| } |
| } |
| |
| |
| /** |
| Used internally to parse the category factory element. |
| */ |
| protected |
| void parseCategoryFactory(Element factoryElement, Hierarchy hierarchy) { |
| String className = subst(factoryElement.getAttribute(CLASS_ATTR)); |
| |
| if(EMPTY_STR.equals(className)) { |
| LogLog.error("Category Factory tag " + CLASS_ATTR + " attribute not found."); |
| LogLog.debug("No Category Factory configured."); |
| } |
| else { |
| LogLog.debug("Desired category factory: ["+className+']'); |
| Object catFactory = OptionConverter.instantiateByClassName(className, |
| CategoryFactory.class, |
| null); |
| PropertySetter propSetter = new PropertySetter(catFactory); |
| |
| Element currentElement = null; |
| Node currentNode = null; |
| NodeList children = factoryElement.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; |
| if (currentElement.getTagName().equals(PARAM_TAG)) { |
| setParameter(currentElement, propSetter); |
| } |
| } |
| } |
| } |
| } |
| |
| |
| /** |
| Used internally to parse the roor category element. |
| */ |
| protected |
| void parseRoot (Element rootElement, Hierarchy hierarchy) { |
| Category root = hierarchy.getRoot(); |
| // category configuration needs to be atomic |
| synchronized(root) { |
| parseChildrenOfCategoryElement(rootElement, root, true); |
| } |
| } |
| |
| |
| /** |
| Used internally to parse the children of a category element. |
| */ |
| protected |
| void parseChildrenOfCategoryElement(Element catElement, |
| Category cat, boolean isRoot) { |
| |
| PropertySetter propSetter = new PropertySetter(cat); |
| |
| // Remove all existing appenders from cat. They will be |
| // reconstructed if need be. |
| cat.removeAllAppenders(); |
| |
| |
| NodeList children = catElement.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(APPENDER_REF_TAG)) { |
| Element appenderRef = (Element) currentNode; |
| Appender appender = findAppenderByReference(appenderRef); |
| String refName = subst(appenderRef.getAttribute(REF_ATTR)); |
| if(appender != null) |
| LogLog.debug("Adding appender named ["+ refName+ |
| "] to category ["+cat.getName()+"]."); |
| else |
| LogLog.debug("Appender named ["+ refName + "] not found."); |
| |
| cat.addAppender(appender); |
| |
| } else if(tagName.equals(LEVEL_TAG)) { |
| parseLevel(currentElement, cat, isRoot); |
| } else if(tagName.equals(PARAM_TAG)) { |
| setParameter(currentElement, propSetter); |
| } |
| } |
| } |
| propSetter.activate(); |
| } |
| |
| /** |
| Used internally to parse a layout element. |
| */ |
| protected |
| Layout parseLayout (Element layout_element) { |
| String className = subst(layout_element.getAttribute(CLASS_ATTR)); |
| LogLog.debug("Parsing layout of class: \""+className+"\""); |
| try { |
| Object instance = Loader.loadClass(className).newInstance(); |
| Layout layout = (Layout)instance; |
| PropertySetter propSetter = new PropertySetter(layout); |
| |
| NodeList params = layout_element.getChildNodes(); |
| final int length = params.getLength(); |
| |
| for (int loop = 0; loop < length; loop++) { |
| Node currentNode = (Node)params.item(loop); |
| if (currentNode.getNodeType() == Node.ELEMENT_NODE) { |
| Element currentElement = (Element) currentNode; |
| String tagName = currentElement.getTagName(); |
| if(tagName.equals(PARAM_TAG)) { |
| setParameter(currentElement, propSetter); |
| } |
| } |
| } |
| |
| propSetter.activate(); |
| return layout; |
| } |
| catch (Exception oops) { |
| LogLog.error("Could not create the Layout. Reported error follows.", |
| oops); |
| return null; |
| } |
| } |
| |
| protected |
| void parseRenderer(Element element, Hierarchy hierarchy) { |
| String renderingClass = subst(element.getAttribute(RENDERING_CLASS_ATTR)); |
| String renderedClass = subst(element.getAttribute(RENDERED_CLASS_ATTR)); |
| addRenderer(hierarchy, renderedClass, renderingClass); |
| } |
| |
| /** |
| Used internally to parse a level element. |
| */ |
| protected |
| void parseLevel(Element element, Category cat, boolean isRoot) { |
| String catName = cat.getName(); |
| if(isRoot) { |
| catName = "root"; |
| } |
| |
| String priStr = subst(element.getAttribute(VALUE_ATTR)); |
| LogLog.debug("Level value for "+catName+" is ["+priStr+"]."); |
| |
| if(BasicConfigurator.INHERITED.equals(priStr)) { |
| if(isRoot) { |
| LogLog.error("Root level cannot be inherited. Ignoring directive."); |
| } else { |
| cat.setLevel(null); |
| } |
| } else { |
| String className = subst(element.getAttribute(CLASS_ATTR)); |
| if(EMPTY_STR.equals(className)) { |
| |
| cat.setLevel(Level.toLevel(priStr)); |
| } else { |
| LogLog.debug("Desired Level sub-class: ["+className+']'); |
| try { |
| Class clazz = Loader.loadClass(className); |
| Method toLevelMethod = clazz.getMethod("toLevel", |
| ONE_STRING_PARAM); |
| Level pri = (Level) toLevelMethod.invoke(null, |
| new Object[] {priStr}); |
| cat.setLevel(pri); |
| } catch (Exception oops) { |
| LogLog.error("Could not create level ["+priStr+ |
| "]. Reported error follows.", oops); |
| return; |
| } |
| } |
| } |
| LogLog.debug(catName + " level set to " + cat.getLevel()); |
| } |
| |
| protected |
| void setParameter(Element elem, PropertySetter propSetter) { |
| String name = subst(elem.getAttribute(NAME_ATTR)); |
| String value = (elem.getAttribute(VALUE_ATTR)); |
| value = subst(OptionConverter.convertSpecialChars(value)); |
| propSetter.setProperty(name, value); |
| } |
| |
| |
| /** |
| Configure log4j using a <code>configuration</code> element as |
| defined in the log4j.dtd. |
| |
| */ |
| static |
| public |
| void configure (Element element) { |
| DOMConfigurator configurator = new DOMConfigurator(); |
| configurator.parse(element, Category.getDefaultHierarchy()); |
| } |
| |
| /** |
| 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 <code>configFilename</code> if it |
| exists. Moreover, a thread will be created that will periodically |
| check if <code>configFilename</code> has been created or |
| modified. The period is determined by the <code>delay</code> |
| argument. If a change or file creation is detected, then |
| <code>configFilename</code> 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(); |
| } |
| |
| public |
| void doConfigure(String filename, Hierarchy hierarchy) { |
| FileInputStream fis = null; |
| try { |
| fis = new FileInputStream(filename); |
| doConfigure(fis, hierarchy); |
| } catch(IOException e) { |
| LogLog.error("Could not open ["+filename+"].", e); |
| } finally { |
| if (fis != null) { |
| try { |
| fis.close(); |
| } catch(java.io.IOException e) { |
| LogLog.error("Could not close ["+filename+"].", e); |
| } |
| } |
| } |
| } |
| |
| |
| public |
| void doConfigure(URL url, Hierarchy hierarchy) { |
| try { |
| doConfigure(url.openStream(), hierarchy); |
| } catch(IOException e) { |
| LogLog.error("Could not open ["+url+"].", e); |
| } |
| } |
| |
| /** |
| Configure log4j by reading in a log4j.dtd compliant XML |
| configuration file. |
| |
| */ |
| public |
| void doConfigure(InputStream inputStream, Hierarchy hierarchy) |
| throws FactoryConfigurationError { |
| doConfigure(new InputSource(inputStream), hierarchy); |
| } |
| |
| /** |
| Configure log4j by reading in a log4j.dtd compliant XML |
| configuration file. |
| |
| */ |
| public |
| void doConfigure(Reader reader, Hierarchy hierarchy) |
| throws FactoryConfigurationError { |
| doConfigure(new InputSource(reader), hierarchy); |
| } |
| |
| /** |
| Configure log4j by reading in a log4j.dtd compliant XML |
| configuration file. |
| |
| */ |
| protected |
| void doConfigure(InputSource inputSource, Hierarchy hierarchy) |
| throws FactoryConfigurationError { |
| DocumentBuilderFactory dbf = null; |
| 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 { |
| // This makes ID/IDREF attributes to have a meaning. Don't ask |
| // me why. |
| dbf.setValidating(true); |
| //dbf.setNamespaceAware(true); |
| |
| DocumentBuilder docBuilder = dbf.newDocumentBuilder(); |
| //docBuilder.setErrorHandler(new ReportParserError()); |
| |
| Class clazz = this.getClass(); |
| URL dtdURL = clazz.getResource("/org/apache/log4j/xml/log4j.dtd"); |
| if(dtdURL == null) { |
| LogLog.error("Could not find [log4j.dtd]. Used ["+clazz.getClassLoader()+ |
| "] class loader in the search."); |
| } |
| else { |
| LogLog.debug("URL to log4j.dtd is [" + dtdURL.toString()+"]."); |
| inputSource.setSystemId(dtdURL.toString()); |
| } |
| Document doc = docBuilder.parse(inputSource); |
| parse(doc.getDocumentElement(), hierarchy); |
| } catch (Exception e) { |
| // I know this is miserable... |
| LogLog.error("Could not parse input source ["+inputSource+"].", e); |
| } |
| } |
| |
| |
| /** |
| A static version of {@link #doConfigure(String, Hierarchy)}. */ |
| static |
| public |
| void configure(String filename) throws FactoryConfigurationError { |
| new DOMConfigurator().doConfigure(filename, Category.getDefaultHierarchy()); |
| } |
| |
| /** |
| A static version of {@link #doConfigure(URL, Hierarchy)}. |
| */ |
| static |
| public |
| void configure(URL url) throws FactoryConfigurationError { |
| new DOMConfigurator().doConfigure(url, Category.getDefaultHierarchy()); |
| } |
| |
| /** |
| Used internally to configure the log4j framework by parsing a DOM |
| tree of XML elements based on <a |
| href="doc-files/log4j.dtd">log4j.dtd</a>. |
| |
| */ |
| protected |
| void parse(Element element, Hierarchy hierarchy) { |
| |
| 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."); |
| |
| |
| 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 override = subst(element.getAttribute(DISABLE_OVERRIDE_ATTR)); |
| LogLog.debug("Disable override=\"" + override +"\"."); |
| // if the log4j.dtd is not specified in the XML file, then the |
| // DISABLE_OVERRIDE attribute is returned as the empty string when |
| // it is not specified in the XML file. |
| if(!override.equals("") && !override.equals("null")) { |
| hierarchy.overrideAsNeeded(override); |
| } |
| |
| String disableStr = subst(element.getAttribute(DISABLE_ATTR)); |
| LogLog.debug("Disable =\"" + disableStr +"\"."); |
| if(!"".equals(disableStr) && !"null".equals(disableStr)) { |
| hierarchy.disable(disableStr); |
| } |
| |
| |
| |
| |
| //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)) { |
| parseCategoryFactory(currentElement, hierarchy); |
| } |
| } |
| } |
| |
| 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)) { |
| parseCategory(currentElement, hierarchy); |
| } else if (tagName.equals(ROOT_TAG)) { |
| parseRoot(currentElement, hierarchy); |
| } else if(tagName.equals(RENDERER_TAG)) { |
| parseRenderer(currentElement, hierarchy); |
| } |
| } |
| } |
| } |
| |
| |
| protected |
| String subst(String value) { |
| try { |
| return OptionConverter.substVars(value, props); |
| } catch(IllegalArgumentException e) { |
| LogLog.warn("Could not perform variable substitution.", e); |
| return value; |
| } |
| } |
| } |
| |
| |
| class XMLWatchdog extends FileWatchdog { |
| |
| XMLWatchdog(String filename) { |
| super(filename); |
| } |
| |
| /** |
| Call {@link PropertyConfigurator#configure(String)} with the |
| <code>filename</code> to reconfigure log4j. */ |
| public |
| void doOnChange() { |
| new DOMConfigurator().doConfigure(filename, Category.getDefaultHierarchy()); |
| } |
| } |