alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

What this is

This file is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Other links

The source code

/*
 * 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.txt 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.*;
import org.apache.log4j.spi.*;
import org.apache.log4j.or.RendererMap;
import org.apache.log4j.helpers.*;
import org.apache.log4j.config.PropertySetter;

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
//                 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"; 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 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"; 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; /** 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); 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); } /** 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) { 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 = repository.getLogger(loggerName); eh.setLogger(logger); } else if(tagName.equals(ROOT_REF)) { Logger root = repository.getRootLogger(); eh.setLogger(root); } } } 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(); 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 element. String catName = subst(loggerElement.getAttribute(NAME_ATTR)); Logger cat; String className = subst(loggerElement.getAttribute(CLASS_ATTR)); if(EMPTY_STR.equals(className)) { LogLog.debug("Retreiving an instance of org.apache.log4j.Logger."); cat = repository.getLogger(catName); } else { LogLog.debug("Desired logger sub-class: ["+className+']'); try { Class clazz = Loader.loadClass(className); Method getInstanceMethod = clazz.getMethod("getLogger", ONE_STRING_PARAM); cat = (Logger) 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(loggerElement.getAttribute(ADDITIVITY_ATTR)), true); LogLog.debug("Setting ["+cat.getName()+"] additivity to ["+additivity+"]."); cat.setAdditivity(additivity); parseChildrenOfLoggerElement(loggerElement, cat, false); } } /** Used internally to parse the category factory element. */ protected void parseCategoryFactory(Element factoryElement) { 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, LoggerFactory.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) { Logger root = repository.getRootLogger(); // category configuration needs to be atomic synchronized(root) { parseChildrenOfLoggerElement(rootElement, root, true); } } /** Used internally to parse the children of a category element. */ protected void parseChildrenOfLoggerElement(Element catElement, Logger 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(PRIORITY_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) { String renderingClass = subst(element.getAttribute(RENDERING_CLASS_ATTR)); String renderedClass = subst(element.getAttribute(RENDERED_CLASS_ATTR)); if(repository instanceof RendererSupport) { RendererMap.addRenderer((RendererSupport) repository, renderedClass, renderingClass); } } /** Used internally to parse a level element. */ protected void parseLevel(Element element, Logger logger, boolean isRoot) { String catName = logger.getName(); if(isRoot) { catName = "root"; } String priStr = subst(element.getAttribute(VALUE_ATTR)); LogLog.debug("Level value for "+catName+" is ["+priStr+"]."); if(INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) { if(isRoot) { LogLog.error("Root level cannot be inherited. Ignoring directive."); } else { logger.setLevel(null); } } else { String className = subst(element.getAttribute(CLASS_ATTR)); if(EMPTY_STR.equals(className)) { logger.setLevel(OptionConverter.toLevel(priStr, Level.DEBUG)); } 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}); logger.setLevel(pri); } catch (Exception oops) { LogLog.error("Could not create level ["+priStr+ "]. Reported error follows.", oops); return; } } } LogLog.debug(catName + " level set to " + logger.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 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(); } public void doConfigure(String filename, LoggerRepository repository) { FileInputStream fis = null; try { fis = new FileInputStream(filename); doConfigure(fis, repository); } 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, LoggerRepository repository) { try { doConfigure(url.openStream(), repository); } 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, LoggerRepository repository) throws FactoryConfigurationError { doConfigure(new InputSource(inputStream), repository); } /** Configure log4j by reading in a log4j.dtd compliant XML configuration file. */ public void doConfigure(Reader reader, LoggerRepository repository) throws FactoryConfigurationError { doConfigure(new InputSource(reader), repository); } /** Configure log4j by reading in a log4j.dtd compliant XML configuration file. */ protected void doConfigure(InputSource inputSource, 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()); // we change the system ID to a valid URI so that Crimson won't // complain. Indeed, "log4j.dtd" alone is not a valid URI which // causes Crimson to barf. The Log4jEntityResolver only cares // about the "log4j.dtd" ending. inputSource.setSystemId("dummy://log4j.dtd"); Document doc = docBuilder.parse(inputSource); parse(doc.getDocumentElement()); } catch (Exception e) { // I know this is miserable... LogLog.error("Could not parse input source ["+inputSource+"].", 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."); } 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)) { 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); } } } } 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 filename to reconfigure log4j. */ public void doOnChange() { new DOMConfigurator().doConfigure(filename, LogManager.getLoggerRepository()); } }

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.