1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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.RendererSupport;
38 import org.apache.log4j.spi.ThrowableRenderer;
39 import org.apache.log4j.spi.ThrowableRendererSupport;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Element;
42 import org.w3c.dom.NamedNodeMap;
43 import org.w3c.dom.Node;
44 import org.w3c.dom.NodeList;
45 import org.xml.sax.InputSource;
46 import org.xml.sax.SAXException;
47
48 import javax.xml.parsers.DocumentBuilder;
49 import javax.xml.parsers.DocumentBuilderFactory;
50 import javax.xml.parsers.FactoryConfigurationError;
51 import java.io.File;
52 import java.io.IOException;
53 import java.io.InputStream;
54 import java.io.InterruptedIOException;
55 import java.io.Reader;
56 import java.lang.reflect.Method;
57 import java.lang.reflect.InvocationTargetException;
58 import java.net.URL;
59 import java.net.URLConnection;
60 import java.util.Hashtable;
61 import java.util.Properties;
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public class DOMConfigurator implements Configurator {
91
92 static final String CONFIGURATION_TAG = "log4j:configuration";
93 static final String OLD_CONFIGURATION_TAG = "configuration";
94 static final String RENDERER_TAG = "renderer";
95 private static final String THROWABLE_RENDERER_TAG = "throwableRenderer";
96 static final String APPENDER_TAG = "appender";
97 static final String APPENDER_REF_TAG = "appender-ref";
98 static final String PARAM_TAG = "param";
99 static final String LAYOUT_TAG = "layout";
100 static final String CATEGORY = "category";
101 static final String LOGGER = "logger";
102 static final String LOGGER_REF = "logger-ref";
103 static final String CATEGORY_FACTORY_TAG = "categoryFactory";
104 static final String LOGGER_FACTORY_TAG = "loggerFactory";
105 static final String NAME_ATTR = "name";
106 static final String CLASS_ATTR = "class";
107 static final String VALUE_ATTR = "value";
108 static final String ROOT_TAG = "root";
109 static final String ROOT_REF = "root-ref";
110 static final String LEVEL_TAG = "level";
111 static final String PRIORITY_TAG = "priority";
112 static final String FILTER_TAG = "filter";
113 static final String ERROR_HANDLER_TAG = "errorHandler";
114 static final String REF_ATTR = "ref";
115 static final String ADDITIVITY_ATTR = "additivity";
116 static final String THRESHOLD_ATTR = "threshold";
117 static final String CONFIG_DEBUG_ATTR = "configDebug";
118 static final String INTERNAL_DEBUG_ATTR = "debug";
119 private static final String RESET_ATTR = "reset";
120 static final String RENDERING_CLASS_ATTR = "renderingClass";
121 static final String RENDERED_CLASS_ATTR = "renderedClass";
122
123 static final String EMPTY_STR = "";
124 static final Class[] ONE_STRING_PARAM = new Class[] {String.class};
125
126 final static String dbfKey = "javax.xml.parsers.DocumentBuilderFactory";
127
128
129
130 Hashtable appenderBag;
131
132 Properties props;
133 LoggerRepository repository;
134
135 protected LoggerFactory catFactory = null;
136
137
138
139
140 public
141 DOMConfigurator () {
142 appenderBag = new Hashtable();
143 }
144
145
146
147
148 protected
149 Appender findAppenderByName(Document doc, String appenderName) {
150 Appender appender = (Appender) appenderBag.get(appenderName);
151
152 if(appender != null) {
153 return appender;
154 } else {
155
156
157
158
159 Element element = null;
160 NodeList list = doc.getElementsByTagName("appender");
161 for (int t=0; t < list.getLength(); t++) {
162 Node node = list.item(t);
163 NamedNodeMap map= node.getAttributes();
164 Node attrNode = map.getNamedItem("name");
165 if (appenderName.equals(attrNode.getNodeValue())) {
166 element = (Element) node;
167 break;
168 }
169 }
170
171
172 if(element == null) {
173 LogLog.error("No appender named ["+appenderName+"] could be found.");
174 return null;
175 } else {
176 appender = parseAppender(element);
177 if (appender != null) {
178 appenderBag.put(appenderName, appender);
179 }
180 return appender;
181 }
182 }
183 }
184
185
186
187 protected
188 Appender findAppenderByReference(Element appenderRef) {
189 String appenderName = subst(appenderRef.getAttribute(REF_ATTR));
190 Document doc = appenderRef.getOwnerDocument();
191 return findAppenderByName(doc, appenderName);
192 }
193
194
195
196
197
198
199
200
201
202
203
204 private static void parseUnrecognizedElement(final Object instance,
205 final Element element,
206 final Properties props) throws Exception {
207 boolean recognized = false;
208 if (instance instanceof UnrecognizedElementHandler) {
209 recognized = ((UnrecognizedElementHandler) instance).parseUnrecognizedElement(
210 element, props);
211 }
212 if (!recognized) {
213 LogLog.warn("Unrecognized element " + element.getNodeName());
214 }
215 }
216
217
218
219
220
221
222
223
224
225
226 private static void quietParseUnrecognizedElement(final Object instance,
227 final Element element,
228 final Properties props) {
229 try {
230 parseUnrecognizedElement(instance, element, props);
231 } catch (Exception ex) {
232 if (ex instanceof InterruptedException || ex instanceof InterruptedIOException) {
233 Thread.currentThread().interrupt();
234 }
235 LogLog.error("Error in extension content: ", ex);
236 }
237 }
238
239
240
241
242 protected
243 Appender parseAppender (Element appenderElement) {
244 String className = subst(appenderElement.getAttribute(CLASS_ATTR));
245 LogLog.debug("Class name: [" + className+']');
246 try {
247 Object instance = Loader.loadClass(className).newInstance();
248 Appender appender = (Appender)instance;
249 PropertySetter propSetter = new PropertySetter(appender);
250
251 appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
252
253 NodeList children = appenderElement.getChildNodes();
254 final int length = children.getLength();
255
256 for (int loop = 0; loop < length; loop++) {
257 Node currentNode = children.item(loop);
258
259
260 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
261 Element currentElement = (Element)currentNode;
262
263
264 if (currentElement.getTagName().equals(PARAM_TAG)) {
265 setParameter(currentElement, propSetter);
266 }
267
268 else if (currentElement.getTagName().equals(LAYOUT_TAG)) {
269 appender.setLayout(parseLayout(currentElement));
270 }
271
272 else if (currentElement.getTagName().equals(FILTER_TAG)) {
273 parseFilters(currentElement, appender);
274 }
275 else if (currentElement.getTagName().equals(ERROR_HANDLER_TAG)) {
276 parseErrorHandler(currentElement, appender);
277 }
278 else if (currentElement.getTagName().equals(APPENDER_REF_TAG)) {
279 String refName = subst(currentElement.getAttribute(REF_ATTR));
280 if(appender instanceof AppenderAttachable) {
281 AppenderAttachable aa = (AppenderAttachable) appender;
282 LogLog.debug("Attaching appender named ["+ refName+
283 "] to appender named ["+ appender.getName()+"].");
284 aa.addAppender(findAppenderByReference(currentElement));
285 } else {
286 LogLog.error("Requesting attachment of appender named ["+
287 refName+ "] to appender named ["+ appender.getName()+
288 "] which does not implement org.apache.log4j.spi.AppenderAttachable.");
289 }
290 } else {
291 parseUnrecognizedElement(instance, currentElement, props);
292 }
293 }
294 }
295 propSetter.activate();
296 return appender;
297 }
298
299
300 catch (Exception oops) {
301 if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
302 Thread.currentThread().interrupt();
303 }
304 LogLog.error("Could not create an Appender. Reported error follows.",
305 oops);
306 return null;
307 }
308 }
309
310
311
312
313 protected
314 void parseErrorHandler(Element element, Appender appender) {
315 ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByClassName(
316 subst(element.getAttribute(CLASS_ATTR)),
317 org.apache.log4j.spi.ErrorHandler.class,
318 null);
319
320 if(eh != null) {
321 eh.setAppender(appender);
322
323 PropertySetter propSetter = new PropertySetter(eh);
324 NodeList children = element.getChildNodes();
325 final int length = children.getLength();
326
327 for (int loop = 0; loop < length; loop++) {
328 Node currentNode = children.item(loop);
329 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
330 Element currentElement = (Element) currentNode;
331 String tagName = currentElement.getTagName();
332 if(tagName.equals(PARAM_TAG)) {
333 setParameter(currentElement, propSetter);
334 } else if(tagName.equals(APPENDER_REF_TAG)) {
335 eh.setBackupAppender(findAppenderByReference(currentElement));
336 } else if(tagName.equals(LOGGER_REF)) {
337 String loggerName = currentElement.getAttribute(REF_ATTR);
338 Logger logger = (catFactory == null) ? repository.getLogger(loggerName)
339 : repository.getLogger(loggerName, catFactory);
340 eh.setLogger(logger);
341 } else if(tagName.equals(ROOT_REF)) {
342 Logger root = repository.getRootLogger();
343 eh.setLogger(root);
344 } else {
345 quietParseUnrecognizedElement(eh, currentElement, props);
346 }
347 }
348 }
349 propSetter.activate();
350 appender.setErrorHandler(eh);
351 }
352 }
353
354
355
356
357 protected
358 void parseFilters(Element element, Appender appender) {
359 String clazz = subst(element.getAttribute(CLASS_ATTR));
360 Filter filter = (Filter) OptionConverter.instantiateByClassName(clazz,
361 Filter.class, null);
362
363 if(filter != null) {
364 PropertySetter propSetter = new PropertySetter(filter);
365 NodeList children = element.getChildNodes();
366 final int length = children.getLength();
367
368 for (int loop = 0; loop < length; loop++) {
369 Node currentNode = children.item(loop);
370 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
371 Element currentElement = (Element) currentNode;
372 String tagName = currentElement.getTagName();
373 if(tagName.equals(PARAM_TAG)) {
374 setParameter(currentElement, propSetter);
375 } else {
376 quietParseUnrecognizedElement(filter, currentElement, props);
377 }
378 }
379 }
380 propSetter.activate();
381 LogLog.debug("Adding filter of type ["+filter.getClass()
382 +"] to appender named ["+appender.getName()+"].");
383 appender.addFilter(filter);
384 }
385 }
386
387
388
389
390 protected
391 void parseCategory (Element loggerElement) {
392
393 String catName = subst(loggerElement.getAttribute(NAME_ATTR));
394
395 Logger cat;
396
397 String className = subst(loggerElement.getAttribute(CLASS_ATTR));
398
399
400 if(EMPTY_STR.equals(className)) {
401 LogLog.debug("Retreiving an instance of org.apache.log4j.Logger.");
402 cat = (catFactory == null) ? repository.getLogger(catName) : repository.getLogger(catName, catFactory);
403 }
404 else {
405 LogLog.debug("Desired logger sub-class: ["+className+']');
406 try {
407 Class clazz = Loader.loadClass(className);
408 Method getInstanceMethod = clazz.getMethod("getLogger",
409 ONE_STRING_PARAM);
410 cat = (Logger) getInstanceMethod.invoke(null, new Object[] {catName});
411 } catch (InvocationTargetException oops) {
412 if (oops.getTargetException() instanceof InterruptedException
413 || oops.getTargetException() instanceof InterruptedIOException) {
414 Thread.currentThread().interrupt();
415 }
416 LogLog.error("Could not retrieve category ["+catName+
417 "]. Reported error follows.", oops);
418 return;
419 } catch (Exception oops) {
420 LogLog.error("Could not retrieve category ["+catName+
421 "]. Reported error follows.", oops);
422 return;
423 }
424 }
425
426
427
428
429 synchronized(cat) {
430 boolean additivity = OptionConverter.toBoolean(
431 subst(loggerElement.getAttribute(ADDITIVITY_ATTR)),
432 true);
433
434 LogLog.debug("Setting ["+cat.getName()+"] additivity to ["+additivity+"].");
435 cat.setAdditivity(additivity);
436 parseChildrenOfLoggerElement(loggerElement, cat, false);
437 }
438 }
439
440
441
442
443
444 protected
445 void parseCategoryFactory(Element factoryElement) {
446 String className = subst(factoryElement.getAttribute(CLASS_ATTR));
447
448 if(EMPTY_STR.equals(className)) {
449 LogLog.error("Category Factory tag " + CLASS_ATTR + " attribute not found.");
450 LogLog.debug("No Category Factory configured.");
451 }
452 else {
453 LogLog.debug("Desired category factory: ["+className+']');
454 Object factory = OptionConverter.instantiateByClassName(className,
455 LoggerFactory.class,
456 null);
457 if (factory instanceof LoggerFactory) {
458 catFactory = (LoggerFactory) factory;
459 } else {
460 LogLog.error("Category Factory class " + className + " does not implement org.apache.log4j.LoggerFactory");
461 }
462 PropertySetter propSetter = new PropertySetter(factory);
463
464 Element currentElement = null;
465 Node currentNode = null;
466 NodeList children = factoryElement.getChildNodes();
467 final int length = children.getLength();
468
469 for (int loop=0; loop < length; loop++) {
470 currentNode = children.item(loop);
471 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
472 currentElement = (Element)currentNode;
473 if (currentElement.getTagName().equals(PARAM_TAG)) {
474 setParameter(currentElement, propSetter);
475 } else {
476 quietParseUnrecognizedElement(factory, currentElement, props);
477 }
478 }
479 }
480 }
481 }
482
483
484
485
486
487 protected
488 void parseRoot (Element rootElement) {
489 Logger root = repository.getRootLogger();
490
491 synchronized(root) {
492 parseChildrenOfLoggerElement(rootElement, root, true);
493 }
494 }
495
496
497
498
499
500 protected
501 void parseChildrenOfLoggerElement(Element catElement,
502 Logger cat, boolean isRoot) {
503
504 PropertySetter propSetter = new PropertySetter(cat);
505
506
507
508 cat.removeAllAppenders();
509
510
511 NodeList children = catElement.getChildNodes();
512 final int length = children.getLength();
513
514 for (int loop = 0; loop < length; loop++) {
515 Node currentNode = children.item(loop);
516
517 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
518 Element currentElement = (Element) currentNode;
519 String tagName = currentElement.getTagName();
520
521 if (tagName.equals(APPENDER_REF_TAG)) {
522 Element appenderRef = (Element) currentNode;
523 Appender appender = findAppenderByReference(appenderRef);
524 String refName = subst(appenderRef.getAttribute(REF_ATTR));
525 if(appender != null)
526 LogLog.debug("Adding appender named ["+ refName+
527 "] to category ["+cat.getName()+"].");
528 else
529 LogLog.debug("Appender named ["+ refName + "] not found.");
530
531 cat.addAppender(appender);
532
533 } else if(tagName.equals(LEVEL_TAG)) {
534 parseLevel(currentElement, cat, isRoot);
535 } else if(tagName.equals(PRIORITY_TAG)) {
536 parseLevel(currentElement, cat, isRoot);
537 } else if(tagName.equals(PARAM_TAG)) {
538 setParameter(currentElement, propSetter);
539 } else {
540 quietParseUnrecognizedElement(cat, currentElement, props);
541 }
542 }
543 }
544 propSetter.activate();
545 }
546
547
548
549
550 protected
551 Layout parseLayout (Element layout_element) {
552 String className = subst(layout_element.getAttribute(CLASS_ATTR));
553 LogLog.debug("Parsing layout of class: \""+className+"\"");
554 try {
555 Object instance = Loader.loadClass(className).newInstance();
556 Layout layout = (Layout)instance;
557 PropertySetter propSetter = new PropertySetter(layout);
558
559 NodeList params = layout_element.getChildNodes();
560 final int length = params.getLength();
561
562 for (int loop = 0; loop < length; loop++) {
563 Node currentNode = (Node)params.item(loop);
564 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
565 Element currentElement = (Element) currentNode;
566 String tagName = currentElement.getTagName();
567 if(tagName.equals(PARAM_TAG)) {
568 setParameter(currentElement, propSetter);
569 } else {
570 parseUnrecognizedElement(instance, currentElement, props);
571 }
572 }
573 }
574
575 propSetter.activate();
576 return layout;
577 }
578 catch (Exception oops) {
579 if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
580 Thread.currentThread().interrupt();
581 }
582 LogLog.error("Could not create the Layout. Reported error follows.",
583 oops);
584 return null;
585 }
586 }
587
588 protected
589 void parseRenderer(Element element) {
590 String renderingClass = subst(element.getAttribute(RENDERING_CLASS_ATTR));
591 String renderedClass = subst(element.getAttribute(RENDERED_CLASS_ATTR));
592 if(repository instanceof RendererSupport) {
593 RendererMap.addRenderer((RendererSupport) repository, renderedClass,
594 renderingClass);
595 }
596 }
597
598
599
600
601
602
603
604 protected ThrowableRenderer parseThrowableRenderer(final Element element) {
605 String className = subst(element.getAttribute(CLASS_ATTR));
606 LogLog.debug("Parsing throwableRenderer of class: \""+className+"\"");
607 try {
608 Object instance = Loader.loadClass(className).newInstance();
609 ThrowableRenderer tr = (ThrowableRenderer)instance;
610 PropertySetter propSetter = new PropertySetter(tr);
611
612 NodeList params = element.getChildNodes();
613 final int length = params.getLength();
614
615 for (int loop = 0; loop < length; loop++) {
616 Node currentNode = (Node)params.item(loop);
617 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
618 Element currentElement = (Element) currentNode;
619 String tagName = currentElement.getTagName();
620 if(tagName.equals(PARAM_TAG)) {
621 setParameter(currentElement, propSetter);
622 } else {
623 parseUnrecognizedElement(instance, currentElement, props);
624 }
625 }
626 }
627
628 propSetter.activate();
629 return tr;
630 }
631 catch (Exception oops) {
632 if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
633 Thread.currentThread().interrupt();
634 }
635 LogLog.error("Could not create the ThrowableRenderer. Reported error follows.",
636 oops);
637 return null;
638 }
639 }
640
641
642
643
644 protected
645 void parseLevel(Element element, Logger logger, boolean isRoot) {
646 String catName = logger.getName();
647 if(isRoot) {
648 catName = "root";
649 }
650
651 String priStr = subst(element.getAttribute(VALUE_ATTR));
652 LogLog.debug("Level value for "+catName+" is ["+priStr+"].");
653
654 if(INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) {
655 if(isRoot) {
656 LogLog.error("Root level cannot be inherited. Ignoring directive.");
657 } else {
658 logger.setLevel(null);
659 }
660 } else {
661 String className = subst(element.getAttribute(CLASS_ATTR));
662 if(EMPTY_STR.equals(className)) {
663 logger.setLevel(OptionConverter.toLevel(priStr, Level.DEBUG));
664 } else {
665 LogLog.debug("Desired Level sub-class: ["+className+']');
666 try {
667 Class clazz = Loader.loadClass(className);
668 Method toLevelMethod = clazz.getMethod("toLevel",
669 ONE_STRING_PARAM);
670 Level pri = (Level) toLevelMethod.invoke(null,
671 new Object[] {priStr});
672 logger.setLevel(pri);
673 } catch (Exception oops) {
674 if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
675 Thread.currentThread().interrupt();
676 }
677 LogLog.error("Could not create level ["+priStr+
678 "]. Reported error follows.", oops);
679 return;
680 }
681 }
682 }
683 LogLog.debug(catName + " level set to " + logger.getLevel());
684 }
685
686 protected
687 void setParameter(Element elem, PropertySetter propSetter) {
688 String name = subst(elem.getAttribute(NAME_ATTR));
689 String value = (elem.getAttribute(VALUE_ATTR));
690 value = subst(OptionConverter.convertSpecialChars(value));
691 propSetter.setProperty(name, value);
692 }
693
694
695
696
697
698
699
700 static
701 public
702 void configure (Element element) {
703 DOMConfigurator configurator = new DOMConfigurator();
704 configurator.doConfigure(element, LogManager.getLoggerRepository());
705 }
706
707
708
709
710
711
712
713
714
715 static
716 public
717 void configureAndWatch(String configFilename) {
718 configureAndWatch(configFilename, FileWatchdog.DEFAULT_DELAY);
719 }
720
721
722
723
724
725
726
727
728
729
730
731
732 static
733 public
734 void configureAndWatch(String configFilename, long delay) {
735 XMLWatchdog xdog = new XMLWatchdog(configFilename);
736 xdog.setDelay(delay);
737 xdog.start();
738 }
739
740 private interface ParseAction {
741 Document parse(final DocumentBuilder parser) throws SAXException, IOException;
742 }
743
744
745 public
746 void doConfigure(final String filename, LoggerRepository repository) {
747 ParseAction action = new ParseAction() {
748 public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
749 return parser.parse(new File(filename));
750 }
751 public String toString() {
752 return "file [" + filename + "]";
753 }
754 };
755 doConfigure(action, repository);
756 }
757
758
759 public
760 void doConfigure(final URL url, LoggerRepository repository) {
761 ParseAction action = new ParseAction() {
762 public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
763 URLConnection uConn = url.openConnection();
764 uConn.setUseCaches(false);
765 InputStream stream = uConn.getInputStream();
766 try {
767 InputSource src = new InputSource(stream);
768 src.setSystemId(url.toString());
769 return parser.parse(src);
770 } finally {
771 stream.close();
772 }
773 }
774 public String toString() {
775 return "url [" + url.toString() + "]";
776 }
777 };
778 doConfigure(action, repository);
779 }
780
781
782
783
784
785
786 public
787 void doConfigure(final InputStream inputStream, LoggerRepository repository)
788 throws FactoryConfigurationError {
789 ParseAction action = new ParseAction() {
790 public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
791 InputSource inputSource = new InputSource(inputStream);
792 inputSource.setSystemId("dummy://log4j.dtd");
793 return parser.parse(inputSource);
794 }
795 public String toString() {
796 return "input stream [" + inputStream.toString() + "]";
797 }
798 };
799 doConfigure(action, repository);
800 }
801
802
803
804
805
806
807 public
808 void doConfigure(final Reader reader, LoggerRepository repository)
809 throws FactoryConfigurationError {
810 ParseAction action = new ParseAction() {
811 public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
812 InputSource inputSource = new InputSource(reader);
813 inputSource.setSystemId("dummy://log4j.dtd");
814 return parser.parse(inputSource);
815 }
816 public String toString() {
817 return "reader [" + reader.toString() + "]";
818 }
819 };
820 doConfigure(action, repository);
821 }
822
823
824
825
826
827
828 protected
829 void doConfigure(final InputSource inputSource, LoggerRepository repository)
830 throws FactoryConfigurationError {
831 if (inputSource.getSystemId() == null) {
832 inputSource.setSystemId("dummy://log4j.dtd");
833 }
834 ParseAction action = new ParseAction() {
835 public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
836 return parser.parse(inputSource);
837 }
838 public String toString() {
839 return "input source [" + inputSource.toString() + "]";
840 }
841 };
842 doConfigure(action, repository);
843 }
844
845
846 private final void doConfigure(final ParseAction action, final LoggerRepository repository)
847 throws FactoryConfigurationError {
848 DocumentBuilderFactory dbf = null;
849 this.repository = repository;
850 try {
851 LogLog.debug("System property is :"+
852 OptionConverter.getSystemProperty(dbfKey,
853 null));
854 dbf = DocumentBuilderFactory.newInstance();
855 LogLog.debug("Standard DocumentBuilderFactory search succeded.");
856 LogLog.debug("DocumentBuilderFactory is: "+dbf.getClass().getName());
857 } catch(FactoryConfigurationError fce) {
858 Exception e = fce.getException();
859 LogLog.debug("Could not instantiate a DocumentBuilderFactory.", e);
860 throw fce;
861 }
862
863 try {
864 dbf.setValidating(true);
865
866 DocumentBuilder docBuilder = dbf.newDocumentBuilder();
867
868 docBuilder.setErrorHandler(new SAXErrorHandler());
869 docBuilder.setEntityResolver(new Log4jEntityResolver());
870
871 Document doc = action.parse(docBuilder);
872 parse(doc.getDocumentElement());
873 } catch (Exception e) {
874 if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
875 Thread.currentThread().interrupt();
876 }
877
878 LogLog.error("Could not parse "+ action.toString() + ".", e);
879 }
880 }
881
882
883
884
885 public void doConfigure(Element element, LoggerRepository repository) {
886 this.repository = repository;
887 parse(element);
888 }
889
890
891
892
893 static
894 public
895 void configure(String filename) throws FactoryConfigurationError {
896 new DOMConfigurator().doConfigure(filename,
897 LogManager.getLoggerRepository());
898 }
899
900
901
902
903 static
904 public
905 void configure(URL url) throws FactoryConfigurationError {
906 new DOMConfigurator().doConfigure(url, LogManager.getLoggerRepository());
907 }
908
909
910
911
912
913
914
915 protected
916 void parse(Element element) {
917
918 String rootElementName = element.getTagName();
919
920 if (!rootElementName.equals(CONFIGURATION_TAG)) {
921 if(rootElementName.equals(OLD_CONFIGURATION_TAG)) {
922 LogLog.warn("The <"+OLD_CONFIGURATION_TAG+
923 "> element has been deprecated.");
924 LogLog.warn("Use the <"+CONFIGURATION_TAG+"> element instead.");
925 } else {
926 LogLog.error("DOM element is - not a <"+CONFIGURATION_TAG+"> element.");
927 return;
928 }
929 }
930
931
932 String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR));
933
934 LogLog.debug("debug attribute= \"" + debugAttrib +"\".");
935
936
937 if(!debugAttrib.equals("") && !debugAttrib.equals("null")) {
938 LogLog.setInternalDebugging(OptionConverter.toBoolean(debugAttrib, true));
939 } else {
940 LogLog.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
941 }
942
943
944
945
946
947 String resetAttrib = subst(element.getAttribute(RESET_ATTR));
948 LogLog.debug("reset attribute= \"" + resetAttrib +"\".");
949 if(!("".equals(resetAttrib))) {
950 if (OptionConverter.toBoolean(resetAttrib, false)) {
951 repository.resetConfiguration();
952 }
953 }
954
955
956
957 String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
958 if(!confDebug.equals("") && !confDebug.equals("null")) {
959 LogLog.warn("The \""+CONFIG_DEBUG_ATTR+"\" attribute is deprecated.");
960 LogLog.warn("Use the \""+INTERNAL_DEBUG_ATTR+"\" attribute instead.");
961 LogLog.setInternalDebugging(OptionConverter.toBoolean(confDebug, true));
962 }
963
964 String thresholdStr = subst(element.getAttribute(THRESHOLD_ATTR));
965 LogLog.debug("Threshold =\"" + thresholdStr +"\".");
966 if(!"".equals(thresholdStr) && !"null".equals(thresholdStr)) {
967 repository.setThreshold(thresholdStr);
968 }
969
970
971
972
973
974
975
976
977
978
979 String tagName = null;
980 Element currentElement = null;
981 Node currentNode = null;
982 NodeList children = element.getChildNodes();
983 final int length = children.getLength();
984
985 for (int loop = 0; loop < length; loop++) {
986 currentNode = children.item(loop);
987 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
988 currentElement = (Element) currentNode;
989 tagName = currentElement.getTagName();
990
991 if (tagName.equals(CATEGORY_FACTORY_TAG) || tagName.equals(LOGGER_FACTORY_TAG)) {
992 parseCategoryFactory(currentElement);
993 }
994 }
995 }
996
997 for (int loop = 0; loop < length; loop++) {
998 currentNode = children.item(loop);
999 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
1000 currentElement = (Element) currentNode;
1001 tagName = currentElement.getTagName();
1002
1003 if (tagName.equals(CATEGORY) || tagName.equals(LOGGER)) {
1004 parseCategory(currentElement);
1005 } else if (tagName.equals(ROOT_TAG)) {
1006 parseRoot(currentElement);
1007 } else if(tagName.equals(RENDERER_TAG)) {
1008 parseRenderer(currentElement);
1009 } else if(tagName.equals(THROWABLE_RENDERER_TAG)) {
1010 if (repository instanceof ThrowableRendererSupport) {
1011 ThrowableRenderer tr = parseThrowableRenderer(currentElement);
1012 if (tr != null) {
1013 ((ThrowableRendererSupport) repository).setThrowableRenderer(tr);
1014 }
1015 }
1016 } else if (!(tagName.equals(APPENDER_TAG)
1017 || tagName.equals(CATEGORY_FACTORY_TAG)
1018 || tagName.equals(LOGGER_FACTORY_TAG))) {
1019 quietParseUnrecognizedElement(repository, currentElement, props);
1020 }
1021 }
1022 }
1023 }
1024
1025
1026 protected
1027 String subst(final String value) {
1028 return subst(value, props);
1029 }
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041 public static String subst(final String value, final Properties props) {
1042 try {
1043 return OptionConverter.substVars(value, props);
1044 } catch (IllegalArgumentException e) {
1045 LogLog.warn("Could not perform variable substitution.", e);
1046 return value;
1047 }
1048 }
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059 public static void setParameter(final Element elem,
1060 final PropertySetter propSetter,
1061 final Properties props) {
1062 String name = subst(elem.getAttribute("name"), props);
1063 String value = (elem.getAttribute("value"));
1064 value = subst(OptionConverter.convertSpecialChars(value), props);
1065 propSetter.setProperty(name, value);
1066 }
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082 public static Object parseElement(final Element element,
1083 final Properties props,
1084 final Class expectedClass) throws Exception {
1085 String clazz = subst(element.getAttribute("class"), props);
1086 Object instance = OptionConverter.instantiateByClassName(clazz,
1087 expectedClass, null);
1088
1089 if (instance != null) {
1090 PropertySetter propSetter = new PropertySetter(instance);
1091 NodeList children = element.getChildNodes();
1092 final int length = children.getLength();
1093
1094 for (int loop = 0; loop < length; loop++) {
1095 Node currentNode = children.item(loop);
1096 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
1097 Element currentElement = (Element) currentNode;
1098 String tagName = currentElement.getTagName();
1099 if (tagName.equals("param")) {
1100 setParameter(currentElement, propSetter, props);
1101 } else {
1102 parseUnrecognizedElement(instance, currentElement, props);
1103 }
1104 }
1105 }
1106 return instance;
1107 }
1108 return null;
1109 }
1110
1111 }
1112
1113
1114 class XMLWatchdog extends FileWatchdog {
1115
1116 XMLWatchdog(String filename) {
1117 super(filename);
1118 }
1119
1120
1121
1122
1123 public
1124 void doOnChange() {
1125 new DOMConfigurator().doConfigure(filename,
1126 LogManager.getLoggerRepository());
1127 }
1128 }