Save This Page
Home » slf4j-1.5.5 » org.apache » log4j » xml » [javadoc | source]
    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    * 
    9    *      http://www.apache.org/licenses/LICENSE-2.0
   10    * 
   11    * Unless required by applicable law or agreed to in writing, software
   12    * distributed under the License is distributed on an "AS IS" BASIS,
   13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    * See the License for the specific language governing permissions and
   15    * limitations under the License.
   16    */
   17   
   18   package org.apache.log4j.xml;
   19   
   20   import org.apache.log4j.Appender;
   21   import org.apache.log4j.Layout;
   22   import org.apache.log4j.Level;
   23   import org.apache.log4j.LogManager;
   24   import org.apache.log4j.Logger;
   25   import org.apache.log4j.config.PropertySetter;
   26   import org.apache.log4j.helpers.FileWatchdog;
   27   import org.apache.log4j.helpers.Loader;
   28   import org.apache.log4j.helpers.LogLog;
   29   import org.apache.log4j.helpers.OptionConverter;
   30   import org.apache.log4j.or.RendererMap;
   31   import org.apache.log4j.spi.AppenderAttachable;
   32   import org.apache.log4j.spi.Configurator;
   33   import org.apache.log4j.spi.ErrorHandler;
   34   import org.apache.log4j.spi.Filter;
   35   import org.apache.log4j.spi.LoggerFactory;
   36   import org.apache.log4j.spi.LoggerRepository;
   37   import org.apache.log4j.spi.OptionHandler;
   38   import org.apache.log4j.spi.RendererSupport;
   39   import org.w3c.dom.Document;
   40   import org.w3c.dom.Element;
   41   import org.w3c.dom.NamedNodeMap;
   42   import org.w3c.dom.Node;
   43   import org.w3c.dom.NodeList;
   44   import org.xml.sax.InputSource;
   45   import org.xml.sax.SAXException;
   46   
   47   import javax.xml.parsers.DocumentBuilder;
   48   import javax.xml.parsers.DocumentBuilderFactory;
   49   import javax.xml.parsers.FactoryConfigurationError;
   50   import java.io.File;
   51   import java.io.IOException;
   52   import java.io.InputStream;
   53   import java.io.Reader;
   54   import java.lang.reflect.Method;
   55   import java.net.URL;
   56   import java.util.Hashtable;
   57   import java.util.Properties;
   58   
   59   // Contributors:   Mark Womack
   60   //                 Arun Katkere 
   61   
   62   /**
   63      Use this class to initialize the log4j environment using a DOM tree.
   64   
   65      <p>The DTD is specified in <a
   66      href="log4j.dtd"><b>log4j.dtd</b></a>.
   67   
   68      <p>Sometimes it is useful to see how log4j is reading configuration
   69      files. You can enable log4j internal logging by defining the
   70      <b>log4j.debug</b> variable on the java command
   71      line. Alternatively, set the <code>debug</code> attribute in the
   72      <code>log4j:configuration</code> element. As in
   73   <pre>
   74      &lt;log4j:configuration <b>debug="true"</b> xmlns:log4j="http://jakarta.apache.org/log4j/">
   75      ...
   76      &lt;/log4j:configuration>
   77   </pre>
   78   
   79      <p>There are sample XML files included in the package.
   80      
   81      @author Christopher Taylor
   82      @author Ceki G&uuml;lc&uuml;
   83      @author Anders Kristensen
   84   
   85      @since 0.8.3 */
   86   public class DOMConfigurator implements Configurator {
   87   
   88     static final String CONFIGURATION_TAG = "log4j:configuration";
   89     static final String OLD_CONFIGURATION_TAG = "configuration";
   90     static final String RENDERER_TAG      = "renderer";
   91     static final String APPENDER_TAG 	= "appender";
   92     static final String APPENDER_REF_TAG 	= "appender-ref";  
   93     static final String PARAM_TAG    	= "param";
   94     static final String LAYOUT_TAG	= "layout";
   95     static final String CATEGORY		= "category";
   96     static final String LOGGER		= "logger";
   97     static final String LOGGER_REF	= "logger-ref";
   98     static final String CATEGORY_FACTORY_TAG  = "categoryFactory";
   99     static final String LOGGER_FACTORY_TAG  = "loggerFactory";
  100     static final String NAME_ATTR		= "name";
  101     static final String CLASS_ATTR        = "class";
  102     static final String VALUE_ATTR	= "value";
  103     static final String ROOT_TAG		= "root";
  104     static final String ROOT_REF		= "root-ref";
  105     static final String LEVEL_TAG	        = "level";
  106     static final String PRIORITY_TAG      = "priority";
  107     static final String FILTER_TAG	= "filter";
  108     static final String ERROR_HANDLER_TAG	= "errorHandler";
  109     static final String REF_ATTR		= "ref";
  110     static final String ADDITIVITY_ATTR    = "additivity";  
  111     static final String THRESHOLD_ATTR       = "threshold";
  112     static final String CONFIG_DEBUG_ATTR  = "configDebug";
  113     static final String INTERNAL_DEBUG_ATTR  = "debug";
  114     private static final String RESET_ATTR  = "reset";
  115     static final String RENDERING_CLASS_ATTR = "renderingClass";
  116     static final String RENDERED_CLASS_ATTR = "renderedClass";
  117   
  118     static final String EMPTY_STR = "";
  119     static final Class[] ONE_STRING_PARAM = new Class[] {String.class};
  120   
  121     final static String dbfKey = "javax.xml.parsers.DocumentBuilderFactory";
  122   
  123     
  124     // key: appenderName, value: appender
  125     Hashtable appenderBag;
  126   
  127     Properties props;
  128     LoggerRepository repository;
  129   
  130     protected LoggerFactory catFactory = null;
  131   
  132     /**
  133        No argument constructor.
  134     */
  135     public
  136     DOMConfigurator () { 
  137       appenderBag = new Hashtable();
  138     }
  139   
  140     /**
  141        Used internally to parse appenders by IDREF name.
  142     */
  143     protected
  144     Appender findAppenderByName(Document doc, String appenderName)  {      
  145       Appender appender = (Appender) appenderBag.get(appenderName);
  146   
  147       if(appender != null) {
  148         return appender;
  149       } else {
  150         // Doesn't work on DOM Level 1 :
  151         // Element element = doc.getElementById(appenderName);
  152                           
  153         // Endre's hack:
  154         Element element = null;
  155         NodeList list = doc.getElementsByTagName("appender");
  156         for (int t=0; t < list.getLength(); t++) {
  157   	Node node = list.item(t);
  158   	NamedNodeMap map= node.getAttributes();
  159   	Node attrNode = map.getNamedItem("name");
  160   	if (appenderName.equals(attrNode.getNodeValue())) {
  161   	  element = (Element) node;
  162   	  break;
  163   	}
  164         }
  165         // Hack finished.
  166   
  167         if(element == null) {
  168   	LogLog.error("No appender named ["+appenderName+"] could be found."); 
  169   	return null;
  170         } else {
  171   	appender = parseAppender(element);
  172   	appenderBag.put(appenderName, appender);
  173   	return appender;
  174         }
  175       } 
  176     }
  177     /**
  178        Used internally to parse appenders by IDREF element.
  179      */
  180     protected
  181     Appender findAppenderByReference(Element appenderRef) {    
  182       String appenderName = subst(appenderRef.getAttribute(REF_ATTR));    
  183       Document doc = appenderRef.getOwnerDocument();
  184       return findAppenderByName(doc, appenderName);
  185     }
  186   
  187       /**
  188        * Delegates unrecognized content to created instance if
  189        * it supports UnrecognizedElementParser.
  190        * @since 1.2.15
  191        * @param instance instance, may be null.
  192        * @param element element, may not be null.
  193        * @param props properties
  194        * @throws IOException thrown if configuration of owner object
  195        * should be abandoned.
  196        */
  197     private static void parseUnrecognizedElement(final Object instance,
  198                                           final Element element,
  199                                           final Properties props) throws Exception {
  200         boolean recognized = false;
  201         if (instance instanceof UnrecognizedElementHandler) {
  202             recognized = ((UnrecognizedElementHandler) instance).parseUnrecognizedElement(
  203                     element, props);
  204         }
  205         if (!recognized) {
  206             LogLog.warn("Unrecognized element " + element.getNodeName());
  207         }
  208     }
  209   
  210       /**
  211         * Delegates unrecognized content to created instance if
  212         * it supports UnrecognizedElementParser and catches and
  213        *  logs any exception.
  214         * @since 1.2.15
  215         * @param instance instance, may be null.
  216         * @param element element, may not be null.
  217         * @param props properties
  218         */
  219      private static void quietParseUnrecognizedElement(final Object instance,
  220                                             final Element element,
  221                                             final Properties props) {
  222         try {
  223             parseUnrecognizedElement(instance, element, props);
  224         } catch (Exception ex) {
  225             LogLog.error("Error in extension content: ", ex);
  226         }
  227     }
  228   
  229     /**
  230        Used internally to parse an appender element.
  231      */
  232     protected
  233     Appender parseAppender (Element appenderElement) {
  234       String className = subst(appenderElement.getAttribute(CLASS_ATTR));
  235       LogLog.debug("Class name: [" + className+']');    
  236       try {
  237         Object instance 	= Loader.loadClass(className).newInstance();
  238         Appender appender	= (Appender)instance;
  239         PropertySetter propSetter = new PropertySetter(appender);
  240   
  241         appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
  242         
  243         NodeList children	= appenderElement.getChildNodes();
  244         final int length 	= children.getLength();
  245   
  246         for (int loop = 0; loop < length; loop++) {
  247   	Node currentNode = children.item(loop);
  248   
  249   	/* We're only interested in Elements */
  250   	if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
  251   	  Element currentElement = (Element)currentNode;
  252   
  253   	  // Parse appender parameters 
  254   	  if (currentElement.getTagName().equals(PARAM_TAG)) {
  255               setParameter(currentElement, propSetter);
  256   	  }
  257   	  // Set appender layout
  258   	  else if (currentElement.getTagName().equals(LAYOUT_TAG)) {
  259   	    appender.setLayout(parseLayout(currentElement));
  260   	  }
  261   	  // Add filters
  262   	  else if (currentElement.getTagName().equals(FILTER_TAG)) {
  263   	    parseFilters(currentElement, appender);
  264   	  }
  265   	  else if (currentElement.getTagName().equals(ERROR_HANDLER_TAG)) {
  266   	    parseErrorHandler(currentElement, appender);
  267   	  }
  268   	  else if (currentElement.getTagName().equals(APPENDER_REF_TAG)) {
  269   	    String refName = subst(currentElement.getAttribute(REF_ATTR));
  270   	    if(appender instanceof AppenderAttachable) {
  271   	      AppenderAttachable aa = (AppenderAttachable) appender;
  272   	      LogLog.debug("Attaching appender named ["+ refName+
  273   			   "] to appender named ["+ appender.getName()+"].");
  274   	      aa.addAppender(findAppenderByReference(currentElement));
  275   	    } else {
  276   	      LogLog.error("Requesting attachment of appender named ["+
  277   			   refName+ "] to appender named ["+ appender.getName()+
  278                   "] which does not implement org.apache.log4j.spi.AppenderAttachable.");
  279   	    }
  280   	  } else {
  281             parseUnrecognizedElement(instance, currentElement, props);
  282         }
  283   	}
  284         }
  285         propSetter.activate();
  286         return appender;
  287       }
  288       /* Yes, it's ugly.  But all of these exceptions point to the same
  289          problem: we can't create an Appender */
  290       catch (Exception oops) {
  291         LogLog.error("Could not create an Appender. Reported error follows.",
  292   		   oops);
  293         return null;
  294       }
  295     }
  296   
  297     /**
  298        Used internally to parse an {@link ErrorHandler} element.
  299      */
  300     protected
  301     void parseErrorHandler(Element element, Appender appender) {
  302       ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByClassName(
  303                                          subst(element.getAttribute(CLASS_ATTR)),
  304                                          org.apache.log4j.spi.ErrorHandler.class, 
  305    				       null);
  306       
  307       if(eh != null) {
  308         eh.setAppender(appender);
  309   
  310         PropertySetter propSetter = new PropertySetter(eh);
  311         NodeList children = element.getChildNodes();
  312         final int length 	= children.getLength();
  313   
  314         for (int loop = 0; loop < length; loop++) {
  315   	Node currentNode = children.item(loop);
  316   	if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
  317   	  Element currentElement = (Element) currentNode;
  318   	  String tagName = currentElement.getTagName();
  319   	  if(tagName.equals(PARAM_TAG)) {
  320               setParameter(currentElement, propSetter);
  321   	  } else if(tagName.equals(APPENDER_REF_TAG)) {
  322   	    eh.setBackupAppender(findAppenderByReference(currentElement));
  323   	  } else if(tagName.equals(LOGGER_REF)) {
  324   	    String loggerName = currentElement.getAttribute(REF_ATTR);	    
  325   	    Logger logger = (catFactory == null) ? repository.getLogger(loggerName)
  326                   : repository.getLogger(loggerName, catFactory);
  327   	    eh.setLogger(logger);
  328   	  } else if(tagName.equals(ROOT_REF)) {
  329   	    Logger root = repository.getRootLogger();
  330   	    eh.setLogger(root);
  331   	  } else {
  332             quietParseUnrecognizedElement(eh, currentElement, props);
  333         }
  334   	}
  335         }
  336         propSetter.activate();
  337         appender.setErrorHandler(eh);
  338       }
  339     }
  340     
  341     /**
  342        Used internally to parse a filter element.
  343      */
  344     protected
  345     void parseFilters(Element element, Appender appender) {
  346       String clazz = subst(element.getAttribute(CLASS_ATTR));
  347       Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz,
  348                                                   Filter.class, null);
  349       
  350       if(filter != null) {
  351         PropertySetter propSetter = new PropertySetter(filter);
  352         NodeList children = element.getChildNodes();
  353         final int length 	= children.getLength();
  354   
  355         for (int loop = 0; loop < length; loop++) {
  356   	Node currentNode = children.item(loop);
  357   	if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
  358   	  Element currentElement = (Element) currentNode;
  359   	  String tagName = currentElement.getTagName();
  360   	  if(tagName.equals(PARAM_TAG)) {
  361               setParameter(currentElement, propSetter);
  362   	  } else {
  363               quietParseUnrecognizedElement(filter, currentElement, props);
  364         }
  365   	}
  366         }
  367         propSetter.activate();
  368         LogLog.debug("Adding filter of type ["+filter.getClass()
  369   		   +"] to appender named ["+appender.getName()+"].");
  370         appender.addFilter(filter);
  371       }    
  372     }
  373     
  374     /**
  375        Used internally to parse an category element.
  376     */
  377     protected
  378     void parseCategory (Element loggerElement) {
  379       // Create a new org.apache.log4j.Category object from the <category> element.
  380       String catName = subst(loggerElement.getAttribute(NAME_ATTR));
  381   
  382       Logger cat;    
  383   
  384       String className = subst(loggerElement.getAttribute(CLASS_ATTR));
  385   
  386   
  387       if(EMPTY_STR.equals(className)) {
  388         LogLog.debug("Retreiving an instance of org.apache.log4j.Logger.");
  389         cat = (catFactory == null) ? repository.getLogger(catName) : repository.getLogger(catName, catFactory);
  390       }
  391       else {
  392         LogLog.debug("Desired logger sub-class: ["+className+']');
  393          try {	 
  394   	 Class clazz = Loader.loadClass(className);
  395   	 Method getInstanceMethod = clazz.getMethod("getLogger", 
  396   						    ONE_STRING_PARAM);
  397   	 cat = (Logger) getInstanceMethod.invoke(null, new Object[] {catName});
  398          } catch (Exception oops) {
  399   	 LogLog.error("Could not retrieve category ["+catName+
  400   		      "]. Reported error follows.", oops);
  401   	 return;
  402          }
  403       }
  404   
  405       // Setting up a category needs to be an atomic operation, in order
  406       // to protect potential log operations while category
  407       // configuration is in progress.
  408       synchronized(cat) {
  409         boolean additivity = OptionConverter.toBoolean(
  410                              subst(loggerElement.getAttribute(ADDITIVITY_ATTR)),
  411   			   true);
  412       
  413         LogLog.debug("Setting ["+cat.getName()+"] additivity to ["+additivity+"].");
  414         cat.setAdditivity(additivity);
  415         parseChildrenOfLoggerElement(loggerElement, cat, false);
  416       }
  417     }
  418   
  419   
  420     /**
  421        Used internally to parse the category factory element.
  422     */
  423     protected
  424     void parseCategoryFactory(Element factoryElement) {
  425       String className = subst(factoryElement.getAttribute(CLASS_ATTR));
  426   
  427       if(EMPTY_STR.equals(className)) {
  428         LogLog.error("Category Factory tag " + CLASS_ATTR + " attribute not found.");
  429         LogLog.debug("No Category Factory configured.");
  430       }
  431       else {
  432         LogLog.debug("Desired category factory: ["+className+']');
  433         Object factory = OptionConverter.instantiateByClassName(className,
  434                                                                    LoggerFactory.class, 
  435                                                                    null);
  436         if (factory instanceof LoggerFactory) {
  437             catFactory = (LoggerFactory) factory;
  438         } else {
  439             LogLog.error("Category Factory class " + className + " does not implement org.apache.log4j.LoggerFactory");
  440         }
  441         PropertySetter propSetter = new PropertySetter(factory);
  442   
  443         Element  currentElement = null;
  444         Node     currentNode    = null;
  445         NodeList children       = factoryElement.getChildNodes();
  446         final int length        = children.getLength();
  447   
  448         for (int loop=0; loop < length; loop++) {
  449           currentNode = children.item(loop);
  450   	if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
  451   	  currentElement = (Element)currentNode;
  452   	  if (currentElement.getTagName().equals(PARAM_TAG)) {
  453   	    setParameter(currentElement, propSetter);
  454   	  } else {
  455              quietParseUnrecognizedElement(factory, currentElement, props);
  456         }
  457   	}
  458         }
  459       }
  460     }
  461   
  462   
  463     /**
  464        Used internally to parse the roor category element.
  465     */
  466     protected
  467     void parseRoot (Element rootElement) {
  468       Logger root = repository.getRootLogger();
  469       // category configuration needs to be atomic
  470       synchronized(root) {    
  471         parseChildrenOfLoggerElement(rootElement, root, true);
  472       }
  473     }
  474   
  475   
  476     /**
  477        Used internally to parse the children of a category element.
  478     */
  479     protected
  480     void parseChildrenOfLoggerElement(Element catElement,
  481   				      Logger cat, boolean isRoot) {
  482       
  483       PropertySetter propSetter = new PropertySetter(cat);
  484       
  485       // Remove all existing appenders from cat. They will be
  486       // reconstructed if need be.
  487       cat.removeAllAppenders();
  488   
  489   
  490       NodeList children 	= catElement.getChildNodes();
  491       final int length 	= children.getLength();
  492       
  493       for (int loop = 0; loop < length; loop++) {
  494         Node currentNode = children.item(loop);
  495   
  496         if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
  497   	Element currentElement = (Element) currentNode;
  498   	String tagName = currentElement.getTagName();
  499   	
  500   	if (tagName.equals(APPENDER_REF_TAG)) {
  501   	  Element appenderRef = (Element) currentNode;
  502   	  Appender appender = findAppenderByReference(appenderRef);
  503   	  String refName =  subst(appenderRef.getAttribute(REF_ATTR));
  504   	  if(appender != null)
  505   	    LogLog.debug("Adding appender named ["+ refName+ 
  506   			 "] to category ["+cat.getName()+"].");
  507   	  else 
  508   	    LogLog.debug("Appender named ["+ refName + "] not found.");
  509   	    
  510   	  cat.addAppender(appender);
  511   	  
  512   	} else if(tagName.equals(LEVEL_TAG)) {
  513   	  parseLevel(currentElement, cat, isRoot);	
  514   	} else if(tagName.equals(PRIORITY_TAG)) {
  515   	  parseLevel(currentElement, cat, isRoot);
  516   	} else if(tagName.equals(PARAM_TAG)) {
  517             setParameter(currentElement, propSetter);
  518   	} else {
  519           quietParseUnrecognizedElement(cat, currentElement, props);
  520       }
  521         }
  522       }
  523       propSetter.activate();
  524     }
  525   
  526     /**
  527        Used internally to parse a layout element.
  528     */  
  529     protected
  530     Layout parseLayout (Element layout_element) {
  531       String className = subst(layout_element.getAttribute(CLASS_ATTR));
  532       LogLog.debug("Parsing layout of class: \""+className+"\"");		 
  533       try {
  534         Object instance 	= Loader.loadClass(className).newInstance();
  535         Layout layout   	= (Layout)instance;
  536         PropertySetter propSetter = new PropertySetter(layout);
  537         
  538         NodeList params 	= layout_element.getChildNodes();
  539         final int length 	= params.getLength();
  540   
  541         for (int loop = 0; loop < length; loop++) {
  542   	Node currentNode = (Node)params.item(loop);
  543   	if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
  544   	  Element currentElement = (Element) currentNode;
  545   	  String tagName = currentElement.getTagName();
  546   	  if(tagName.equals(PARAM_TAG)) {
  547               setParameter(currentElement, propSetter);
  548   	  } else {
  549             parseUnrecognizedElement(instance, currentElement, props);
  550         }
  551   	}
  552         }
  553         
  554         propSetter.activate();
  555         return layout;
  556       }
  557       catch (Exception oops) {
  558         LogLog.error("Could not create the Layout. Reported error follows.",
  559   		   oops);
  560         return null;
  561       }
  562     }
  563   
  564     protected 
  565     void parseRenderer(Element element) {
  566       String renderingClass = subst(element.getAttribute(RENDERING_CLASS_ATTR));
  567       String renderedClass = subst(element.getAttribute(RENDERED_CLASS_ATTR));
  568       if(repository instanceof RendererSupport) {
  569         RendererMap.addRenderer((RendererSupport) repository, renderedClass, 
  570   			      renderingClass);
  571       }
  572     }
  573   
  574     /**
  575        Used internally to parse a level  element.
  576     */
  577     protected
  578     void parseLevel(Element element, Logger logger, boolean isRoot) {
  579       String catName = logger.getName();
  580       if(isRoot) {
  581         catName = "root";
  582       }
  583   
  584       String priStr = subst(element.getAttribute(VALUE_ATTR));
  585       LogLog.debug("Level value for "+catName+" is  ["+priStr+"].");
  586       
  587       if(INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) {
  588         if(isRoot) {
  589   	LogLog.error("Root level cannot be inherited. Ignoring directive.");
  590         } else {
  591   	logger.setLevel(null);
  592         }
  593       } else {
  594         String className = subst(element.getAttribute(CLASS_ATTR));      
  595         if(EMPTY_STR.equals(className)) {	
  596   	logger.setLevel(OptionConverter.toLevel(priStr, Level.DEBUG));
  597         } else {
  598   	LogLog.debug("Desired Level sub-class: ["+className+']');
  599   	try {	 
  600   	  Class clazz = Loader.loadClass(className);
  601   	  Method toLevelMethod = clazz.getMethod("toLevel", 
  602   						    ONE_STRING_PARAM);
  603   	  Level pri = (Level) toLevelMethod.invoke(null, 
  604   						    new Object[] {priStr});
  605   	  logger.setLevel(pri);
  606   	} catch (Exception oops) {
  607   	  LogLog.error("Could not create level ["+priStr+
  608   		       "]. Reported error follows.", oops);
  609   	  return;
  610   	}
  611         }
  612       }
  613       LogLog.debug(catName + " level set to " + logger.getLevel());    
  614     }
  615   
  616     protected
  617     void setParameter(Element elem, PropertySetter propSetter) {
  618         setParameter(elem, propSetter, props);
  619     }
  620   
  621   
  622     /**
  623        Configure log4j using a <code>configuration</code> element as
  624        defined in the log4j.dtd. 
  625   
  626     */
  627     static
  628     public
  629     void configure (Element element) {
  630       DOMConfigurator configurator = new DOMConfigurator();
  631       configurator.doConfigure(element,  LogManager.getLoggerRepository());
  632     }
  633   
  634    /**
  635        Like {@link #configureAndWatch(String, long)} except that the
  636        default delay as defined by {@link FileWatchdog#DEFAULT_DELAY} is
  637        used. 
  638   
  639        @param configFilename A log4j configuration file in XML format.
  640   
  641     */
  642     static
  643     public
  644     void configureAndWatch(String configFilename) {
  645       configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
  646     }
  647   
  648     /**
  649        Read the configuration file <code>configFilename</code> if it
  650        exists. Moreover, a thread will be created that will periodically
  651        check if <code>configFilename</code> has been created or
  652        modified. The period is determined by the <code>delay</code>
  653        argument. If a change or file creation is detected, then
  654        <code>configFilename</code> is read to configure log4j.  
  655   
  656         @param configFilename A log4j configuration file in XML format.
  657         @param delay The delay in milliseconds to wait between each check.
  658     */
  659     static
  660     public
  661     void configureAndWatch(String configFilename, long delay) {
  662       XMLWatchdog xdog = new XMLWatchdog(configFilename);
  663       xdog.setDelay(delay);
  664       xdog.start();
  665     }
  666     
  667     private interface ParseAction {
  668         Document parse(final DocumentBuilder parser) throws SAXException, IOException;
  669     }
  670   
  671   
  672     public
  673     void doConfigure(final String filename, LoggerRepository repository) {
  674       ParseAction action = new ParseAction() {
  675             public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
  676                 return parser.parse(new File(filename));
  677             }
  678             public String toString() { 
  679                 return "file [" + filename + "]"; 
  680             }
  681       };
  682       doConfigure(action, repository);
  683     }
  684     
  685   
  686     public
  687     void doConfigure(final URL url, LoggerRepository repository) {
  688         ParseAction action = new ParseAction() {
  689             public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
  690                 return parser.parse(url.toString());
  691             }
  692             public String toString() { 
  693                 return "url [" + url.toString() + "]"; 
  694             }
  695         };
  696         doConfigure(action, repository);
  697     }
  698   
  699     /**
  700        Configure log4j by reading in a log4j.dtd compliant XML
  701        configuration file.
  702   
  703     */
  704     public
  705     void doConfigure(final InputStream inputStream, LoggerRepository repository) 
  706                                             throws FactoryConfigurationError {
  707         ParseAction action = new ParseAction() {
  708             public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
  709                 InputSource inputSource = new InputSource(inputStream);
  710                 inputSource.setSystemId("dummy://log4j.dtd");
  711                 return parser.parse(inputSource);
  712             }
  713             public String toString() { 
  714                 return "input stream [" + inputStream.toString() + "]"; 
  715             }
  716         };
  717         doConfigure(action, repository);
  718     }
  719   
  720     /**
  721        Configure log4j by reading in a log4j.dtd compliant XML
  722        configuration file.
  723   
  724     */
  725     public
  726     void doConfigure(final Reader reader, LoggerRepository repository) 
  727                                             throws FactoryConfigurationError {
  728         ParseAction action = new ParseAction() {
  729             public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
  730                 InputSource inputSource = new InputSource(reader);
  731                 inputSource.setSystemId("dummy://log4j.dtd");
  732                 return parser.parse(inputSource);
  733             }
  734             public String toString() { 
  735                 return "reader [" + reader.toString() + "]"; 
  736             }
  737         };
  738       doConfigure(action, repository);
  739     }
  740   
  741     /**
  742        Configure log4j by reading in a log4j.dtd compliant XML
  743        configuration file.
  744   
  745     */
  746     protected
  747     void doConfigure(final InputSource inputSource, LoggerRepository repository) 
  748                                             throws FactoryConfigurationError {
  749         if (inputSource.getSystemId() == null) {
  750             inputSource.setSystemId("dummy://log4j.dtd");
  751         }
  752         ParseAction action = new ParseAction() {
  753             public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
  754                 return parser.parse(inputSource);
  755             }
  756             public String toString() { 
  757                 return "input source [" + inputSource.toString() + "]"; 
  758             }
  759         };
  760         doConfigure(action, repository);
  761       }
  762       
  763       
  764     private final void doConfigure(final ParseAction action, final LoggerRepository repository)
  765            throws FactoryConfigurationError {
  766       DocumentBuilderFactory dbf = null;
  767       this.repository = repository;
  768       try { 
  769         LogLog.debug("System property is :"+
  770     	                        OptionConverter.getSystemProperty(dbfKey, 
  771   								  null)); 
  772         dbf = DocumentBuilderFactory.newInstance();
  773         LogLog.debug("Standard DocumentBuilderFactory search succeded.");
  774         LogLog.debug("DocumentBuilderFactory is: "+dbf.getClass().getName());
  775       } catch(FactoryConfigurationError fce) {
  776         Exception e = fce.getException();
  777         LogLog.debug("Could not instantiate a DocumentBuilderFactory.", e);
  778         throw fce;
  779       }
  780         
  781       try {
  782         dbf.setValidating(true);
  783   
  784         DocumentBuilder docBuilder = dbf.newDocumentBuilder();
  785   
  786         docBuilder.setErrorHandler(new SAXErrorHandler());      
  787         docBuilder.setEntityResolver(new Log4jEntityResolver());
  788            
  789         Document doc = action.parse(docBuilder);     
  790         parse(doc.getDocumentElement());
  791       } catch (Exception e) {
  792         // I know this is miserable...
  793         LogLog.error("Could not parse "+ action.toString() + ".", e);
  794       }
  795     }
  796   
  797     /**
  798        Configure by taking in an DOM element. 
  799     */
  800     public void doConfigure(Element element, LoggerRepository repository) {
  801       this.repository = repository;
  802       parse(element);
  803     }
  804   
  805     
  806     /**
  807        A static version of {@link #doConfigure(String, LoggerRepository)}.  */
  808     static
  809     public
  810     void configure(String filename) throws FactoryConfigurationError {
  811       new DOMConfigurator().doConfigure(filename, 
  812   				      LogManager.getLoggerRepository());
  813     }
  814   
  815     /**
  816        A static version of {@link #doConfigure(URL, LoggerRepository)}.
  817      */
  818     static
  819     public
  820     void configure(URL url) throws FactoryConfigurationError {
  821       new DOMConfigurator().doConfigure(url, LogManager.getLoggerRepository());
  822     }
  823   
  824     /**
  825        Used internally to configure the log4j framework by parsing a DOM
  826        tree of XML elements based on <a
  827        href="doc-files/log4j.dtd">log4j.dtd</a>.
  828        
  829     */
  830     protected
  831     void parse(Element element) {
  832   
  833       String rootElementName = element.getTagName();
  834   
  835       if (!rootElementName.equals(CONFIGURATION_TAG)) {
  836         if(rootElementName.equals(OLD_CONFIGURATION_TAG)) {
  837   	LogLog.warn("The <"+OLD_CONFIGURATION_TAG+
  838   		     "> element has been deprecated.");
  839   	LogLog.warn("Use the <"+CONFIGURATION_TAG+"> element instead.");
  840         } else {
  841   	LogLog.error("DOM element is - not a <"+CONFIGURATION_TAG+"> element.");
  842   	return;
  843         }
  844       }
  845   
  846   
  847       String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR));
  848         
  849       LogLog.debug("debug attribute= \"" + debugAttrib +"\".");
  850       // if the log4j.dtd is not specified in the XML file, then the
  851       // "debug" attribute is returned as the empty string.
  852       if(!debugAttrib.equals("") && !debugAttrib.equals("null")) {      
  853         LogLog.setInternalDebugging(OptionConverter.toBoolean(debugAttrib, true));
  854       } else {
  855         LogLog.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
  856       }
  857   
  858         //
  859         //   reset repository before configuration if reset="true"
  860         //       on configuration element.
  861         //
  862       String resetAttrib = subst(element.getAttribute(RESET_ATTR));
  863       LogLog.debug("reset attribute= \"" + resetAttrib +"\".");
  864       if(!("".equals(resetAttrib))) {
  865            if (OptionConverter.toBoolean(resetAttrib, false)) {
  866                repository.resetConfiguration();
  867            }
  868       }
  869   
  870   
  871   
  872       String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
  873       if(!confDebug.equals("") && !confDebug.equals("null")) {      
  874         LogLog.warn("The \""+CONFIG_DEBUG_ATTR+"\" attribute is deprecated.");
  875         LogLog.warn("Use the \""+INTERNAL_DEBUG_ATTR+"\" attribute instead.");
  876         LogLog.setInternalDebugging(OptionConverter.toBoolean(confDebug, true));
  877       }
  878   
  879       String thresholdStr = subst(element.getAttribute(THRESHOLD_ATTR));
  880       LogLog.debug("Threshold =\"" + thresholdStr +"\".");
  881       if(!"".equals(thresholdStr) && !"null".equals(thresholdStr)) {
  882         repository.setThreshold(thresholdStr);
  883       }
  884   
  885       //Hashtable appenderBag = new Hashtable(11);
  886   
  887       /* Building Appender objects, placing them in a local namespace
  888          for future reference */
  889   
  890       // First configure each category factory under the root element.
  891       // Category factories need to be configured before any of
  892       // categories they support.
  893       //
  894       String   tagName = null;
  895       Element  currentElement = null;
  896       Node     currentNode = null;
  897       NodeList children = element.getChildNodes();
  898       final int length = children.getLength();
  899   
  900       for (int loop = 0; loop < length; loop++) {
  901         currentNode = children.item(loop);
  902         if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
  903   	currentElement = (Element) currentNode;
  904   	tagName = currentElement.getTagName();
  905   
  906   	if (tagName.equals(CATEGORY_FACTORY_TAG) || tagName.equals(LOGGER_FACTORY_TAG)) {
  907   	  parseCategoryFactory(currentElement);
  908   	}
  909         }
  910       }
  911       
  912       for (int loop = 0; loop < length; loop++) {
  913         currentNode = children.item(loop);
  914         if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
  915   	currentElement = (Element) currentNode;
  916   	tagName = currentElement.getTagName();
  917   
  918   	if (tagName.equals(CATEGORY) || tagName.equals(LOGGER)) {
  919   	  parseCategory(currentElement);
  920   	} else if (tagName.equals(ROOT_TAG)) {
  921   	  parseRoot(currentElement);
  922   	} else if(tagName.equals(RENDERER_TAG)) {
  923   	  parseRenderer(currentElement);
  924   	} else if (!(tagName.equals(APPENDER_TAG)
  925               || tagName.equals(CATEGORY_FACTORY_TAG)
  926               || tagName.equals(LOGGER_FACTORY_TAG))) {
  927           quietParseUnrecognizedElement(repository, currentElement, props);
  928       }
  929         }
  930       }
  931     }
  932   
  933     
  934     protected
  935     String subst(final String value) {
  936         return subst(value, props);
  937     }
  938   
  939       /**
  940        * Substitutes property value for any references in expression.
  941        *
  942        * @param value value from configuration file, may contain
  943        *              literal text, property references or both
  944        * @param props properties.
  945        * @return evaluated expression, may still contain expressions
  946        *         if unable to expand.
  947        * @since 1.2.15
  948        */
  949       public static String subst(final String value, final Properties props) {
  950           try {
  951               return OptionConverter.substVars(value, props);
  952           } catch (IllegalArgumentException e) {
  953               LogLog.warn("Could not perform variable substitution.", e);
  954               return value;
  955           }
  956       }
  957   
  958   
  959       /**
  960        * Sets a parameter based from configuration file content.
  961        *
  962        * @param elem       param element, may not be null.
  963        * @param propSetter property setter, may not be null.
  964        * @param props      properties
  965        * @since 1.2.15
  966        */
  967       public static void setParameter(final Element elem,
  968                                       final PropertySetter propSetter,
  969                                       final Properties props) {
  970           String name = subst(elem.getAttribute("name"), props);
  971           String value = (elem.getAttribute("value"));
  972           value = subst(OptionConverter.convertSpecialChars(value), props);
  973           propSetter.setProperty(name, value);
  974       }
  975   
  976       /**
  977        * Creates an object and processes any nested param elements
  978        * but does not call activateOptions.  If the class also supports
  979        * UnrecognizedElementParser, the parseUnrecognizedElement method
  980        * will be call for any child elements other than param.
  981        *
  982        * @param element       element, may not be null.
  983        * @param props         properties
  984        * @param expectedClass interface or class expected to be implemented
  985        *                      by created class
  986        * @return created class or null.
  987        * @throws Exception thrown if the contain object should be abandoned.
  988        * @since 1.2.15
  989        */
  990       public static Object parseElement(final Element element,
  991                                                final Properties props,
  992                                                final Class expectedClass) throws Exception {
  993           String clazz = subst(element.getAttribute("class"), props);
  994           Object instance = OptionConverter.instantiateByClassName(clazz,
  995                   expectedClass, null);
  996   
  997           if (instance != null) {
  998               PropertySetter propSetter = new PropertySetter(instance);
  999               NodeList children = element.getChildNodes();
 1000               final int length = children.getLength();
 1001   
 1002               for (int loop = 0; loop < length; loop++) {
 1003                   Node currentNode = children.item(loop);
 1004                   if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
 1005                       Element currentElement = (Element) currentNode;
 1006                       String tagName = currentElement.getTagName();
 1007                       if (tagName.equals("param")) {
 1008                           setParameter(currentElement, propSetter, props);
 1009                       } else {
 1010                            parseUnrecognizedElement(instance, currentElement, props);
 1011                       }
 1012                   }
 1013               }
 1014               return instance;
 1015           }
 1016           return null;
 1017       }
 1018   
 1019   }
 1020   
 1021   
 1022   class XMLWatchdog extends FileWatchdog {
 1023   
 1024       XMLWatchdog(String filename) {
 1025       super(filename);
 1026     }
 1027   
 1028     /**
 1029        Call {@link DOMConfigurator#configure(String)} with the
 1030        <code>filename</code> to reconfigure log4j. */
 1031     public
 1032     void doOnChange() {
 1033       new DOMConfigurator().doConfigure(filename, 
 1034   				      LogManager.getLoggerRepository());
 1035     }
 1036   }

Save This Page
Home » slf4j-1.5.5 » org.apache » log4j » xml » [javadoc | source]