1 16 17 package org.apache.log4j.xml; 18 19 import java.util.*; 20 21 import java.net.URL ; 22 23 import org.w3c.dom.*; 24 import java.lang.reflect.Method ; 25 import org.apache.log4j.*; 26 import org.apache.log4j.spi.*; 27 import org.apache.log4j.or.RendererMap; 28 import org.apache.log4j.helpers.*; 29 import org.apache.log4j.config.PropertySetter; 30 31 import org.xml.sax.InputSource ; 32 import java.io.FileInputStream ; 33 import java.io.InputStream ; 34 import java.io.Reader ; 35 import java.io.IOException ; 36 import java.net.URL ; 37 import javax.xml.parsers.DocumentBuilderFactory ; 38 import javax.xml.parsers.DocumentBuilder ; 39 import javax.xml.parsers.FactoryConfigurationError ; 40 41 44 68 public class DOMConfigurator implements Configurator { 69 70 static final String CONFIGURATION_TAG = "log4j:configuration"; 71 static final String OLD_CONFIGURATION_TAG = "configuration"; 72 static final String RENDERER_TAG = "renderer"; 73 static final String APPENDER_TAG = "appender"; 74 static final String APPENDER_REF_TAG = "appender-ref"; 75 static final String PARAM_TAG = "param"; 76 static final String LAYOUT_TAG = "layout"; 77 static final String CATEGORY = "category"; 78 static final String LOGGER = "logger"; 79 static final String LOGGER_REF = "logger-ref"; 80 static final String CATEGORY_FACTORY_TAG = "categoryFactory"; 81 static final String NAME_ATTR = "name"; 82 static final String CLASS_ATTR = "class"; 83 static final String VALUE_ATTR = "value"; 84 static final String ROOT_TAG = "root"; 85 static final String ROOT_REF = "root-ref"; 86 static final String LEVEL_TAG = "level"; 87 static final String PRIORITY_TAG = "priority"; 88 static final String FILTER_TAG = "filter"; 89 static final String ERROR_HANDLER_TAG = "errorHandler"; 90 static final String REF_ATTR = "ref"; 91 static final String ADDITIVITY_ATTR = "additivity"; 92 static final String THRESHOLD_ATTR = "threshold"; 93 static final String CONFIG_DEBUG_ATTR = "configDebug"; 94 static final String INTERNAL_DEBUG_ATTR = "debug"; 95 static final String RENDERING_CLASS_ATTR = "renderingClass"; 96 static final String RENDERED_CLASS_ATTR = "renderedClass"; 97 98 static final String EMPTY_STR = ""; 99 static final Class [] ONE_STRING_PARAM = new Class [] {String .class}; 100 101 final static String dbfKey = "javax.xml.parsers.DocumentBuilderFactory"; 102 103 104 Hashtable appenderBag; 106 107 Properties props; 108 LoggerRepository repository; 109 110 113 public 114 DOMConfigurator () { 115 appenderBag = new Hashtable(); 116 } 117 118 121 protected 122 Appender findAppenderByName(Document doc, String appenderName) { 123 Appender appender = (Appender) appenderBag.get(appenderName); 124 125 if(appender != null) { 126 return appender; 127 } else { 128 131 Element element = null; 133 NodeList list = doc.getElementsByTagName("appender"); 134 for (int t=0; t < list.getLength(); t++) { 135 Node node = list.item(t); 136 NamedNodeMap map= node.getAttributes(); 137 Node attrNode = map.getNamedItem("name"); 138 if (appenderName.equals(attrNode.getNodeValue())) { 139 element = (Element) node; 140 break; 141 } 142 } 143 145 if(element == null) { 146 LogLog.error("No appender named ["+appenderName+"] could be found."); 147 return null; 148 } else { 149 appender = parseAppender(element); 150 appenderBag.put(appenderName, appender); 151 return appender; 152 } 153 } 154 } 155 158 protected 159 Appender findAppenderByReference(Element appenderRef) { 160 String appenderName = subst(appenderRef.getAttribute(REF_ATTR)); 161 Document doc = appenderRef.getOwnerDocument(); 162 return findAppenderByName(doc, appenderName); 163 } 164 165 168 protected 169 Appender parseAppender (Element appenderElement) { 170 String className = subst(appenderElement.getAttribute(CLASS_ATTR)); 171 LogLog.debug("Class name: [" + className+']'); 172 try { 173 Object instance = Loader.loadClass(className).newInstance(); 174 Appender appender = (Appender)instance; 175 PropertySetter propSetter = new PropertySetter(appender); 176 177 appender.setName(subst(appenderElement.getAttribute(NAME_ATTR))); 178 179 NodeList children = appenderElement.getChildNodes(); 180 final int length = children.getLength(); 181 182 for (int loop = 0; loop < length; loop++) { 183 Node currentNode = children.item(loop); 184 185 186 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 187 Element currentElement = (Element)currentNode; 188 189 if (currentElement.getTagName().equals(PARAM_TAG)) { 191 setParameter(currentElement, propSetter); 192 } 193 else if (currentElement.getTagName().equals(LAYOUT_TAG)) { 195 appender.setLayout(parseLayout(currentElement)); 196 } 197 else if (currentElement.getTagName().equals(FILTER_TAG)) { 199 parseFilters(currentElement, appender); 200 } 201 else if (currentElement.getTagName().equals(ERROR_HANDLER_TAG)) { 202 parseErrorHandler(currentElement, appender); 203 } 204 else if (currentElement.getTagName().equals(APPENDER_REF_TAG)) { 205 String refName = subst(currentElement.getAttribute(REF_ATTR)); 206 if(appender instanceof AppenderAttachable) { 207 AppenderAttachable aa = (AppenderAttachable) appender; 208 LogLog.debug("Attaching appender named ["+ refName+ 209 "] to appender named ["+ appender.getName()+"]."); 210 aa.addAppender(findAppenderByReference(currentElement)); 211 } else { 212 LogLog.error("Requesting attachment of appender named ["+ 213 refName+ "] to appender named ["+ appender.getName()+ 214 "] which does not implement org.apache.log4j.spi.AppenderAttachable."); 215 } 216 } 217 } 218 } 219 propSetter.activate(); 220 return appender; 221 } 222 224 catch (Exception oops) { 225 LogLog.error("Could not create an Appender. Reported error follows.", 226 oops); 227 return null; 228 } 229 } 230 231 234 protected 235 void parseErrorHandler(Element element, Appender appender) { 236 ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByClassName( 237 subst(element.getAttribute(CLASS_ATTR)), 238 org.apache.log4j.spi.ErrorHandler.class, 239 null); 240 241 if(eh != null) { 242 eh.setAppender(appender); 243 244 PropertySetter propSetter = new PropertySetter(eh); 245 NodeList children = element.getChildNodes(); 246 final int length = children.getLength(); 247 248 for (int loop = 0; loop < length; loop++) { 249 Node currentNode = children.item(loop); 250 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 251 Element currentElement = (Element) currentNode; 252 String tagName = currentElement.getTagName(); 253 if(tagName.equals(PARAM_TAG)) { 254 setParameter(currentElement, propSetter); 255 } else if(tagName.equals(APPENDER_REF_TAG)) { 256 eh.setBackupAppender(findAppenderByReference(currentElement)); 257 } else if(tagName.equals(LOGGER_REF)) { 258 String loggerName = currentElement.getAttribute(REF_ATTR); 259 Logger logger = repository.getLogger(loggerName); 260 eh.setLogger(logger); 261 } else if(tagName.equals(ROOT_REF)) { 262 Logger root = repository.getRootLogger(); 263 eh.setLogger(root); 264 } 265 } 266 } 267 propSetter.activate(); 268 appender.setErrorHandler(eh); 269 } 270 } 271 272 275 protected 276 void parseFilters(Element element, Appender appender) { 277 String clazz = subst(element.getAttribute(CLASS_ATTR)); 278 Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz, 279 Filter.class, null); 280 281 if(filter != null) { 282 PropertySetter propSetter = new PropertySetter(filter); 283 NodeList children = element.getChildNodes(); 284 final int length = children.getLength(); 285 286 for (int loop = 0; loop < length; loop++) { 287 Node currentNode = children.item(loop); 288 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 289 Element currentElement = (Element) currentNode; 290 String tagName = currentElement.getTagName(); 291 if(tagName.equals(PARAM_TAG)) { 292 setParameter(currentElement, propSetter); 293 } 294 } 295 } 296 propSetter.activate(); 297 LogLog.debug("Adding filter of type ["+filter.getClass() 298 +"] to appender named ["+appender.getName()+"]."); 299 appender.addFilter(filter); 300 } 301 } 302 303 306 protected 307 void parseCategory (Element loggerElement) { 308 String catName = subst(loggerElement.getAttribute(NAME_ATTR)); 310 311 Logger cat; 312 313 String className = subst(loggerElement.getAttribute(CLASS_ATTR)); 314 315 316 if(EMPTY_STR.equals(className)) { 317 LogLog.debug("Retreiving an instance of org.apache.log4j.Logger."); 318 cat = repository.getLogger(catName); 319 } 320 else { 321 LogLog.debug("Desired logger sub-class: ["+className+']'); 322 try { 323 Class clazz = Loader.loadClass(className); 324 Method getInstanceMethod = clazz.getMethod("getLogger", 325 ONE_STRING_PARAM); 326 cat = (Logger) getInstanceMethod.invoke(null, new Object [] {catName}); 327 } catch (Exception oops) { 328 LogLog.error("Could not retrieve category ["+catName+ 329 "]. Reported error follows.", oops); 330 return; 331 } 332 } 333 334 synchronized(cat) { 338 boolean additivity = OptionConverter.toBoolean( 339 subst(loggerElement.getAttribute(ADDITIVITY_ATTR)), 340 true); 341 342 LogLog.debug("Setting ["+cat.getName()+"] additivity to ["+additivity+"]."); 343 cat.setAdditivity(additivity); 344 parseChildrenOfLoggerElement(loggerElement, cat, false); 345 } 346 } 347 348 349 352 protected 353 void parseCategoryFactory(Element factoryElement) { 354 String className = subst(factoryElement.getAttribute(CLASS_ATTR)); 355 356 if(EMPTY_STR.equals(className)) { 357 LogLog.error("Category Factory tag " + CLASS_ATTR + " attribute not found."); 358 LogLog.debug("No Category Factory configured."); 359 } 360 else { 361 LogLog.debug("Desired category factory: ["+className+']'); 362 Object catFactory = OptionConverter.instantiateByClassName(className, 363 LoggerFactory.class, 364 null); 365 PropertySetter propSetter = new PropertySetter(catFactory); 366 367 Element currentElement = null; 368 Node currentNode = null; 369 NodeList children = factoryElement.getChildNodes(); 370 final int length = children.getLength(); 371 372 for (int loop=0; loop < length; loop++) { 373 currentNode = children.item(loop); 374 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 375 currentElement = (Element)currentNode; 376 if (currentElement.getTagName().equals(PARAM_TAG)) { 377 setParameter(currentElement, propSetter); 378 } 379 } 380 } 381 } 382 } 383 384 385 388 protected 389 void parseRoot (Element rootElement) { 390 Logger root = repository.getRootLogger(); 391 synchronized(root) { 393 parseChildrenOfLoggerElement(rootElement, root, true); 394 } 395 } 396 397 398 401 protected 402 void parseChildrenOfLoggerElement(Element catElement, 403 Logger cat, boolean isRoot) { 404 405 PropertySetter propSetter = new PropertySetter(cat); 406 407 cat.removeAllAppenders(); 410 411 412 NodeList children = catElement.getChildNodes(); 413 final int length = children.getLength(); 414 415 for (int loop = 0; loop < length; loop++) { 416 Node currentNode = children.item(loop); 417 418 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 419 Element currentElement = (Element) currentNode; 420 String tagName = currentElement.getTagName(); 421 422 if (tagName.equals(APPENDER_REF_TAG)) { 423 Element appenderRef = (Element) currentNode; 424 Appender appender = findAppenderByReference(appenderRef); 425 String refName = subst(appenderRef.getAttribute(REF_ATTR)); 426 if(appender != null) 427 LogLog.debug("Adding appender named ["+ refName+ 428 "] to category ["+cat.getName()+"]."); 429 else 430 LogLog.debug("Appender named ["+ refName + "] not found."); 431 432 cat.addAppender(appender); 433 434 } else if(tagName.equals(LEVEL_TAG)) { 435 parseLevel(currentElement, cat, isRoot); 436 } else if(tagName.equals(PRIORITY_TAG)) { 437 parseLevel(currentElement, cat, isRoot); 438 } else if(tagName.equals(PARAM_TAG)) { 439 setParameter(currentElement, propSetter); 440 } 441 } 442 } 443 propSetter.activate(); 444 } 445 446 449 protected 450 Layout parseLayout (Element layout_element) { 451 String className = subst(layout_element.getAttribute(CLASS_ATTR)); 452 LogLog.debug("Parsing layout of class: \""+className+"\""); 453 try { 454 Object instance = Loader.loadClass(className).newInstance(); 455 Layout layout = (Layout)instance; 456 PropertySetter propSetter = new PropertySetter(layout); 457 458 NodeList params = layout_element.getChildNodes(); 459 final int length = params.getLength(); 460 461 for (int loop = 0; loop < length; loop++) { 462 Node currentNode = (Node)params.item(loop); 463 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 464 Element currentElement = (Element) currentNode; 465 String tagName = currentElement.getTagName(); 466 if(tagName.equals(PARAM_TAG)) { 467 setParameter(currentElement, propSetter); 468 } 469 } 470 } 471 472 propSetter.activate(); 473 return layout; 474 } 475 catch (Exception oops) { 476 LogLog.error("Could not create the Layout. Reported error follows.", 477 oops); 478 return null; 479 } 480 } 481 482 protected 483 void parseRenderer(Element element) { 484 String renderingClass = subst(element.getAttribute(RENDERING_CLASS_ATTR)); 485 String renderedClass = subst(element.getAttribute(RENDERED_CLASS_ATTR)); 486 if(repository instanceof RendererSupport) { 487 RendererMap.addRenderer((RendererSupport) repository, renderedClass, 488 renderingClass); 489 } 490 } 491 492 495 protected 496 void parseLevel(Element element, Logger logger, boolean isRoot) { 497 String catName = logger.getName(); 498 if(isRoot) { 499 catName = "root"; 500 } 501 502 String priStr = subst(element.getAttribute(VALUE_ATTR)); 503 LogLog.debug("Level value for "+catName+" is ["+priStr+"]."); 504 505 if(INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) { 506 if(isRoot) { 507 LogLog.error("Root level cannot be inherited. Ignoring directive."); 508 } else { 509 logger.setLevel(null); 510 } 511 } else { 512 String className = subst(element.getAttribute(CLASS_ATTR)); 513 if(EMPTY_STR.equals(className)) { 514 logger.setLevel(OptionConverter.toLevel(priStr, Level.DEBUG)); 515 } else { 516 LogLog.debug("Desired Level sub-class: ["+className+']'); 517 try { 518 Class clazz = Loader.loadClass(className); 519 Method toLevelMethod = clazz.getMethod("toLevel", 520 ONE_STRING_PARAM); 521 Level pri = (Level) toLevelMethod.invoke(null, 522 new Object [] {priStr}); 523 logger.setLevel(pri); 524 } catch (Exception oops) { 525 LogLog.error("Could not create level ["+priStr+ 526 "]. Reported error follows.", oops); 527 return; 528 } 529 } 530 } 531 LogLog.debug(catName + " level set to " + logger.getLevel()); 532 } 533 534 protected 535 void setParameter(Element elem, PropertySetter propSetter) { 536 String name = subst(elem.getAttribute(NAME_ATTR)); 537 String value = (elem.getAttribute(VALUE_ATTR)); 538 value = subst(OptionConverter.convertSpecialChars(value)); 539 propSetter.setProperty(name, value); 540 } 541 542 543 548 static 549 public 550 void configure (Element element) { 551 DOMConfigurator configurator = new DOMConfigurator(); 552 configurator.doConfigure(element, LogManager.getLoggerRepository()); 553 } 554 555 563 static 564 public 565 void configureAndWatch(String configFilename) { 566 configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY); 567 } 568 569 580 static 581 public 582 void configureAndWatch(String configFilename, long delay) { 583 XMLWatchdog xdog = new XMLWatchdog(configFilename); 584 xdog.setDelay(delay); 585 xdog.start(); 586 } 587 588 public 589 void doConfigure(String filename, LoggerRepository repository) { 590 FileInputStream fis = null; 591 try { 592 fis = new FileInputStream (filename); 593 doConfigure(fis, repository); 594 } catch(IOException e) { 595 LogLog.error("Could not open ["+filename+"].", e); 596 } finally { 597 if (fis != null) { 598 try { 599 fis.close(); 600 } catch(java.io.IOException e) { 601 LogLog.error("Could not close ["+filename+"].", e); 602 } 603 } 604 } 605 } 606 607 608 public 609 void doConfigure(URL url, LoggerRepository repository) { 610 try { 611 doConfigure(url.openStream(), repository); 612 } catch(IOException e) { 613 LogLog.error("Could not open ["+url+"].", e); 614 } 615 } 616 617 622 public 623 void doConfigure(InputStream inputStream, LoggerRepository repository) 624 throws FactoryConfigurationError { 625 doConfigure(new InputSource (inputStream), repository); 626 } 627 628 633 public 634 void doConfigure(Reader reader, LoggerRepository repository) 635 throws FactoryConfigurationError { 636 doConfigure(new InputSource (reader), repository); 637 } 638 639 644 protected 645 void doConfigure(InputSource inputSource, LoggerRepository repository) 646 throws FactoryConfigurationError { 647 DocumentBuilderFactory dbf = null; 648 this.repository = repository; 649 try { 650 LogLog.debug("System property is :"+ 651 OptionConverter.getSystemProperty(dbfKey, 652 null)); 653 dbf = DocumentBuilderFactory.newInstance(); 654 LogLog.debug("Standard DocumentBuilderFactory search succeded."); 655 LogLog.debug("DocumentBuilderFactory is: "+dbf.getClass().getName()); 656 } catch(FactoryConfigurationError fce) { 657 Exception e = fce.getException(); 658 LogLog.debug("Could not instantiate a DocumentBuilderFactory.", e); 659 throw fce; 660 } 661 662 try { 663 dbf.setValidating(true); 664 665 DocumentBuilder docBuilder = dbf.newDocumentBuilder(); 666 667 docBuilder.setErrorHandler(new SAXErrorHandler()); 668 docBuilder.setEntityResolver(new Log4jEntityResolver()); 669 inputSource.setSystemId("dummy://log4j.dtd"); 674 Document doc = docBuilder.parse(inputSource); 675 parse(doc.getDocumentElement()); 676 } catch (Exception e) { 677 LogLog.error("Could not parse input source ["+inputSource+"].", e); 679 } 680 } 681 682 685 public void doConfigure(Element element, LoggerRepository repository) { 686 this.repository = repository; 687 parse(element); 688 } 689 690 691 693 static 694 public 695 void configure(String filename) throws FactoryConfigurationError { 696 new DOMConfigurator().doConfigure(filename, 697 LogManager.getLoggerRepository()); 698 } 699 700 703 static 704 public 705 void configure(URL url) throws FactoryConfigurationError { 706 new DOMConfigurator().doConfigure(url, LogManager.getLoggerRepository()); 707 } 708 709 715 protected 716 void parse(Element element) { 717 718 String rootElementName = element.getTagName(); 719 720 if (!rootElementName.equals(CONFIGURATION_TAG)) { 721 if(rootElementName.equals(OLD_CONFIGURATION_TAG)) { 722 LogLog.warn("The <"+OLD_CONFIGURATION_TAG+ 723 "> element has been deprecated."); 724 LogLog.warn("Use the <"+CONFIGURATION_TAG+"> element instead."); 725 } else { 726 LogLog.error("DOM element is - not a <"+CONFIGURATION_TAG+"> element."); 727 return; 728 } 729 } 730 731 String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR)); 732 733 LogLog.debug("debug attribute= \"" + debugAttrib +"\"."); 734 if(!debugAttrib.equals("") && !debugAttrib.equals("null")) { 737 LogLog.setInternalDebugging(OptionConverter.toBoolean(debugAttrib, true)); 738 } else { 739 LogLog.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute."); 740 } 741 742 743 String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR)); 744 if(!confDebug.equals("") && !confDebug.equals("null")) { 745 LogLog.warn("The \""+CONFIG_DEBUG_ATTR+"\" attribute is deprecated."); 746 LogLog.warn("Use the \""+INTERNAL_DEBUG_ATTR+"\" attribute instead."); 747 LogLog.setInternalDebugging(OptionConverter.toBoolean(confDebug, true)); 748 } 749 750 String thresholdStr = subst(element.getAttribute(THRESHOLD_ATTR)); 751 LogLog.debug("Threshold =\"" + thresholdStr +"\"."); 752 if(!"".equals(thresholdStr) && !"null".equals(thresholdStr)) { 753 repository.setThreshold(thresholdStr); 754 } 755 756 758 760 761 String tagName = null; 766 Element currentElement = null; 767 Node currentNode = null; 768 NodeList children = element.getChildNodes(); 769 final int length = children.getLength(); 770 771 for (int loop = 0; loop < length; loop++) { 772 currentNode = children.item(loop); 773 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 774 currentElement = (Element) currentNode; 775 tagName = currentElement.getTagName(); 776 777 if (tagName.equals(CATEGORY_FACTORY_TAG)) { 778 parseCategoryFactory(currentElement); 779 } 780 } 781 } 782 783 for (int loop = 0; loop < length; loop++) { 784 currentNode = children.item(loop); 785 if (currentNode.getNodeType() == Node.ELEMENT_NODE) { 786 currentElement = (Element) currentNode; 787 tagName = currentElement.getTagName(); 788 789 if (tagName.equals(CATEGORY) || tagName.equals(LOGGER)) { 790 parseCategory(currentElement); 791 } else if (tagName.equals(ROOT_TAG)) { 792 parseRoot(currentElement); 793 } else if(tagName.equals(RENDERER_TAG)) { 794 parseRenderer(currentElement); 795 } 796 } 797 } 798 } 799 800 801 protected 802 String subst(String value) { 803 try { 804 return OptionConverter.substVars(value, props); 805 } catch(IllegalArgumentException e) { 806 LogLog.warn("Could not perform variable substitution.", e); 807 return value; 808 } 809 } 810 } 811 812 813 class XMLWatchdog extends FileWatchdog { 814 815 XMLWatchdog(String filename) { 816 super(filename); 817 } 818 819 822 public 823 void doOnChange() { 824 new DOMConfigurator().doConfigure(filename, 825 LogManager.getLoggerRepository()); 826 } 827 } 828 | Popular Tags |