1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.log4j.xml;
18
19 import org.apache.log4j.Appender;
20 import org.apache.log4j.Layout;
21 import org.apache.log4j.Level;
22 import org.apache.log4j.bridge.AppenderAdapter;
23 import org.apache.log4j.bridge.AppenderWrapper;
24 import org.apache.log4j.config.Log4j1Configuration;
25 import org.apache.log4j.config.PropertySetter;
26 import org.apache.log4j.helpers.OptionConverter;
27 import org.apache.log4j.rewrite.RewritePolicy;
28 import org.apache.log4j.spi.AppenderAttachable;
29 import org.apache.log4j.spi.ErrorHandler;
30 import org.apache.log4j.spi.Filter;
31 import org.apache.logging.log4j.core.LoggerContext;
32 import org.apache.logging.log4j.core.config.ConfigurationSource;
33 import org.apache.logging.log4j.core.config.LoggerConfig;
34 import org.apache.logging.log4j.core.config.status.StatusConfiguration;
35 import org.apache.logging.log4j.status.StatusLogger;
36 import org.apache.logging.log4j.util.LoaderUtil;
37 import org.w3c.dom.Document;
38 import org.w3c.dom.Element;
39 import org.w3c.dom.NamedNodeMap;
40 import org.w3c.dom.Node;
41 import org.w3c.dom.NodeList;
42 import org.xml.sax.InputSource;
43 import org.xml.sax.SAXException;
44 import org.xml.sax.SAXParseException;
45
46 import javax.xml.parsers.DocumentBuilder;
47 import javax.xml.parsers.DocumentBuilderFactory;
48 import javax.xml.parsers.FactoryConfigurationError;
49 import java.io.IOException;
50 import java.io.InterruptedIOException;
51 import java.lang.reflect.Method;
52 import java.util.HashMap;
53 import java.util.Map;
54 import java.util.Properties;
55 import java.util.function.Consumer;
56
57
58
59
60 public class XmlConfiguration extends Log4j1Configuration {
61
62 private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
63
64 private static final String CONFIGURATION_TAG = "log4j:configuration";
65 private static final String OLD_CONFIGURATION_TAG = "configuration";
66 private static final String RENDERER_TAG = "renderer";
67 private static final String APPENDER_TAG = "appender";
68 public static final String PARAM_TAG = "param";
69 public static final String LAYOUT_TAG = "layout";
70 private static final String CATEGORY = "category";
71 private static final String LOGGER_ELEMENT = "logger";
72 private static final String CATEGORY_FACTORY_TAG = "categoryFactory";
73 private static final String LOGGER_FACTORY_TAG = "loggerFactory";
74 public static final String NAME_ATTR = "name";
75 private static final String CLASS_ATTR = "class";
76 public static final String VALUE_ATTR = "value";
77 private static final String ROOT_TAG = "root";
78 private static final String LEVEL_TAG = "level";
79 private static final String PRIORITY_TAG = "priority";
80 public static final String FILTER_TAG = "filter";
81 private static final String ERROR_HANDLER_TAG = "errorHandler";
82 public static final String REF_ATTR = "ref";
83 private static final String ADDITIVITY_ATTR = "additivity";
84 private static final String CONFIG_DEBUG_ATTR = "configDebug";
85 private static final String INTERNAL_DEBUG_ATTR = "debug";
86 private static final String EMPTY_STR = "";
87 private static final Class[] ONE_STRING_PARAM = new Class[]{String.class};
88 private static final String dbfKey = "javax.xml.parsers.DocumentBuilderFactory";
89 private static final String THROWABLE_RENDERER_TAG = "throwableRenderer";
90
91 public static final long DEFAULT_DELAY = 60000;
92
93
94
95 protected static final String TEST_PREFIX = "log4j-test";
96
97
98
99
100 protected static final String DEFAULT_PREFIX = "log4j";
101
102
103 private Map<String, Appender> appenderMap;
104
105 private Properties props = null;
106
107 public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSource source,
108 int monitorIntervalSeconds) {
109 super(loggerContext, source, monitorIntervalSeconds);
110 appenderMap = new HashMap<>();
111 }
112
113 public void addAppenderIfAbsent(Appender appender) {
114 appenderMap.putIfAbsent(appender.getName(), appender);
115 }
116
117
118
119
120
121 @Override
122 public void doConfigure() throws FactoryConfigurationError {
123 ConfigurationSource source = getConfigurationSource();
124 ParseAction action = new ParseAction() {
125 public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
126 InputSource inputSource = new InputSource(source.getInputStream());
127 inputSource.setSystemId("dummy://log4j.dtd");
128 return parser.parse(inputSource);
129 }
130
131 public String toString() {
132 return getConfigurationSource().getLocation();
133 }
134 };
135 doConfigure(action);
136 }
137
138 private void doConfigure(final ParseAction action) throws FactoryConfigurationError {
139 DocumentBuilderFactory dbf;
140 try {
141 LOGGER.debug("System property is : {}", OptionConverter.getSystemProperty(dbfKey, null));
142 dbf = DocumentBuilderFactory.newInstance();
143 LOGGER.debug("Standard DocumentBuilderFactory search succeded.");
144 LOGGER.debug("DocumentBuilderFactory is: " + dbf.getClass().getName());
145 } catch (FactoryConfigurationError fce) {
146 Exception e = fce.getException();
147 LOGGER.debug("Could not instantiate a DocumentBuilderFactory.", e);
148 throw fce;
149 }
150
151 try {
152 dbf.setValidating(true);
153
154 DocumentBuilder docBuilder = dbf.newDocumentBuilder();
155
156 docBuilder.setErrorHandler(new SAXErrorHandler());
157 docBuilder.setEntityResolver(new Log4jEntityResolver());
158
159 Document doc = action.parse(docBuilder);
160 parse(doc.getDocumentElement());
161 } catch (Exception e) {
162 if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
163 Thread.currentThread().interrupt();
164 }
165
166 LOGGER.error("Could not parse " + action.toString() + ".", e);
167 }
168 }
169
170
171
172
173
174
175
176
177
178 private void parseUnrecognizedElement(final Object instance, final Element element,
179 final Properties props) throws Exception {
180 boolean recognized = false;
181 if (instance instanceof UnrecognizedElementHandler) {
182 recognized = ((UnrecognizedElementHandler) instance).parseUnrecognizedElement(
183 element, props);
184 }
185 if (!recognized) {
186 LOGGER.warn("Unrecognized element {}", element.getNodeName());
187 }
188 }
189
190
191
192
193
194
195
196
197
198
199
200 private void quietParseUnrecognizedElement(final Object instance,
201 final Element element,
202 final Properties props) {
203 try {
204 parseUnrecognizedElement(instance, element, props);
205 } catch (Exception ex) {
206 if (ex instanceof InterruptedException || ex instanceof InterruptedIOException) {
207 Thread.currentThread().interrupt();
208 }
209 LOGGER.error("Error in extension content: ", ex);
210 }
211 }
212
213
214
215
216
217
218
219
220
221
222 public String subst(final String value, final Properties props) {
223 try {
224 return OptionConverter.substVars(value, props);
225 } catch (IllegalArgumentException e) {
226 LOGGER.warn("Could not perform variable substitution.", e);
227 return value;
228 }
229 }
230
231
232
233
234
235
236
237
238
239 public void setParameter(final Element elem, final PropertySetter propSetter, final Properties props) {
240 String name = subst(elem.getAttribute("name"), props);
241 String value = (elem.getAttribute("value"));
242 value = subst(OptionConverter.convertSpecialChars(value), props);
243 propSetter.setProperty(name, value);
244 }
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260 public Object parseElement(final Element element, final Properties props,
261 @SuppressWarnings("rawtypes") final Class expectedClass) throws Exception {
262 String clazz = subst(element.getAttribute("class"), props);
263 Object instance = OptionConverter.instantiateByClassName(clazz,
264 expectedClass, null);
265
266 if (instance != null) {
267 PropertySetter propSetter = new PropertySetter(instance);
268 NodeList children = element.getChildNodes();
269 final int length = children.getLength();
270
271 for (int loop = 0; loop < length; loop++) {
272 Node currentNode = children.item(loop);
273 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
274 Element currentElement = (Element) currentNode;
275 String tagName = currentElement.getTagName();
276 if (tagName.equals("param")) {
277 setParameter(currentElement, propSetter, props);
278 } else {
279 parseUnrecognizedElement(instance, currentElement, props);
280 }
281 }
282 }
283 return instance;
284 }
285 return null;
286 }
287
288
289
290
291 private Appender findAppenderByName(Document doc, String appenderName) {
292 Appender appender = appenderMap.get(appenderName);
293
294 if (appender != null) {
295 return appender;
296 } else {
297
298
299
300
301 Element element = null;
302 NodeList list = doc.getElementsByTagName("appender");
303 for (int t = 0; t < list.getLength(); t++) {
304 Node node = list.item(t);
305 NamedNodeMap map = node.getAttributes();
306 Node attrNode = map.getNamedItem("name");
307 if (appenderName.equals(attrNode.getNodeValue())) {
308 element = (Element) node;
309 break;
310 }
311 }
312
313
314 if (element == null) {
315
316 LOGGER.error("No appender named [{}] could be found.", appenderName);
317 return null;
318 } else {
319 appender = parseAppender(element);
320 if (appender != null) {
321 appenderMap.put(appenderName, appender);
322 }
323 return appender;
324 }
325 }
326 }
327
328
329
330
331 public Appender findAppenderByReference(Element appenderRef) {
332 String appenderName = subst(appenderRef.getAttribute(REF_ATTR));
333 Document doc = appenderRef.getOwnerDocument();
334 return findAppenderByName(doc, appenderName);
335 }
336
337
338
339
340 public Appender parseAppender(Element appenderElement) {
341 String className = subst(appenderElement.getAttribute(CLASS_ATTR));
342 LOGGER.debug("Class name: [" + className + ']');
343 Appender appender = manager.parseAppender(className, appenderElement, this);
344 if (appender == null) {
345 appender = buildAppender(className, appenderElement);
346 }
347 return appender;
348 }
349
350 private Appender buildAppender(String className, Element appenderElement) {
351 try {
352 Appender appender = LoaderUtil.newInstanceOf(className);
353 PropertySetter propSetter = new PropertySetter(appender);
354
355 appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
356 forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
357
358 switch (currentElement.getTagName()) {
359 case PARAM_TAG:
360 setParameter(currentElement, propSetter);
361 break;
362 case LAYOUT_TAG:
363 appender.setLayout(parseLayout(currentElement));
364 break;
365 case FILTER_TAG:
366 Filter filter = parseFilters(currentElement);
367 if (filter != null) {
368 LOGGER.debug("Adding filter of type [{}] to appender named [{}]",
369 filter.getClass(), appender.getName());
370 appender.addFilter(filter);
371 }
372 break;
373 case ERROR_HANDLER_TAG:
374 parseErrorHandler(currentElement, appender);
375 break;
376 case APPENDER_REF_TAG:
377 String refName = subst(currentElement.getAttribute(REF_ATTR));
378 if (appender instanceof AppenderAttachable) {
379 AppenderAttachable aa = (AppenderAttachable) appender;
380 Appender child = findAppenderByReference(currentElement);
381 LOGGER.debug("Attaching appender named [{}] to appender named [{}].", refName,
382 appender.getName());
383 aa.addAppender(child);
384 } else {
385 LOGGER.error("Requesting attachment of appender named [{}] to appender named [{}}]"
386 + "which does not implement org.apache.log4j.spi.AppenderAttachable.",
387 refName, appender.getName());
388 }
389 break;
390 default:
391 try {
392 parseUnrecognizedElement(appender, currentElement, props);
393 } catch (Exception ex) {
394 throw new ConsumerException(ex);
395 }
396 }
397 });
398 propSetter.activate();
399 return appender;
400 } catch (ConsumerException ex) {
401 Throwable t = ex.getCause();
402 if (t instanceof InterruptedException || t instanceof InterruptedIOException) {
403 Thread.currentThread().interrupt();
404 }
405 LOGGER.error("Could not create an Appender. Reported error follows.", t);
406 } catch (Exception oops) {
407 if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
408 Thread.currentThread().interrupt();
409 }
410 LOGGER.error("Could not create an Appender. Reported error follows.", oops);
411 }
412 return null;
413 }
414
415 public RewritePolicy parseRewritePolicy(Element rewritePolicyElement) {
416 String className = subst(rewritePolicyElement.getAttribute(CLASS_ATTR));
417 LOGGER.debug("Class name: [" + className + ']');
418 RewritePolicy policy = manager.parseRewritePolicy(className, rewritePolicyElement, this);
419 if (policy == null) {
420 policy = buildRewritePolicy(className, rewritePolicyElement);
421 }
422 return policy;
423 }
424
425 private RewritePolicy buildRewritePolicy(String className, Element element) {
426 try {
427 RewritePolicy policy = LoaderUtil.newInstanceOf(className);
428 PropertySetter propSetter = new PropertySetter(policy);
429
430 forEachElement(element.getChildNodes(), (currentElement) -> {
431 if (currentElement.getTagName().equalsIgnoreCase(PARAM_TAG)) {
432 setParameter(currentElement, propSetter);
433 }
434 });
435 propSetter.activate();
436 return policy;
437 } catch (ConsumerException ex) {
438 Throwable t = ex.getCause();
439 if (t instanceof InterruptedException || t instanceof InterruptedIOException) {
440 Thread.currentThread().interrupt();
441 }
442 LOGGER.error("Could not create an RewritePolicy. Reported error follows.", t);
443 } catch (Exception oops) {
444 if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
445 Thread.currentThread().interrupt();
446 }
447 LOGGER.error("Could not create an RewritePolicy. Reported error follows.", oops);
448 }
449 return null;
450 }
451
452
453
454
455 private void parseErrorHandler(Element element, Appender appender) {
456 ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByClassName(
457 subst(element.getAttribute(CLASS_ATTR)),
458 ErrorHandler.class,
459 null);
460
461 if (eh != null) {
462 eh.setAppender(appender);
463
464 PropertySetter propSetter = new PropertySetter(eh);
465 forEachElement(element.getChildNodes(), (currentElement) -> {
466 String tagName = currentElement.getTagName();
467 if (tagName.equals(PARAM_TAG)) {
468 setParameter(currentElement, propSetter);
469 }
470 });
471 propSetter.activate();
472 appender.setErrorHandler(eh);
473 }
474 }
475
476
477
478
479 public Filter parseFilters(Element filterElement) {
480 String className = subst(filterElement.getAttribute(CLASS_ATTR));
481 LOGGER.debug("Class name: [" + className + ']');
482 Filter filter = manager.parseFilter(className, filterElement, this);
483 if (filter == null) {
484 PropertySetter propSetter = new PropertySetter(filter);
485 forEachElement(filterElement.getChildNodes(), (currentElement) -> {
486 String tagName = currentElement.getTagName();
487 if (tagName.equals(PARAM_TAG)) {
488 setParameter(currentElement, propSetter);
489 } else {
490 quietParseUnrecognizedElement(filter, currentElement, props);
491 }
492 });
493 propSetter.activate();
494 }
495 return filter;
496 }
497
498
499
500
501 private void parseCategory(Element loggerElement) {
502
503 String catName = subst(loggerElement.getAttribute(NAME_ATTR));
504 boolean additivity = OptionConverter.toBoolean(subst(loggerElement.getAttribute(ADDITIVITY_ATTR)), true);
505 LoggerConfig loggerConfig = getLogger(catName);
506 if (loggerConfig == null) {
507 loggerConfig = new LoggerConfig(catName, org.apache.logging.log4j.Level.ERROR, additivity);
508 addLogger(catName, loggerConfig);
509 } else {
510 loggerConfig.setAdditive(additivity);
511 }
512 parseChildrenOfLoggerElement(loggerElement, loggerConfig, false);
513 }
514
515
516
517
518 private void parseRoot(Element rootElement) {
519 LoggerConfig root = getRootLogger();
520 parseChildrenOfLoggerElement(rootElement, root, true);
521 }
522
523
524
525
526 private void parseChildrenOfLoggerElement(Element catElement, LoggerConfig loggerConfig, boolean isRoot) {
527
528 final PropertySetter propSetter = new PropertySetter(loggerConfig);
529 loggerConfig.getAppenderRefs().clear();
530 forEachElement(catElement.getChildNodes(), (currentElement) -> {
531 switch (currentElement.getTagName()) {
532 case APPENDER_REF_TAG: {
533 Appender appender = findAppenderByReference(currentElement);
534 String refName = subst(currentElement.getAttribute(REF_ATTR));
535 if (appender != null) {
536 LOGGER.debug("Adding appender named [{}] to loggerConfig [{}].", refName,
537 loggerConfig.getName());
538 loggerConfig.addAppender(getAppender(refName), null, null);
539 } else {
540 LOGGER.debug("Appender named [{}}] not found.", refName);
541 }
542 break;
543 }
544 case LEVEL_TAG: case PRIORITY_TAG: {
545 parseLevel(currentElement, loggerConfig, isRoot);
546 break;
547 }
548 case PARAM_TAG: {
549 setParameter(currentElement, propSetter);
550 break;
551 }
552 default: {
553 quietParseUnrecognizedElement(loggerConfig, currentElement, props);
554 }
555 }
556 });
557 propSetter.activate();
558 }
559
560
561
562
563 public Layout parseLayout(Element layoutElement) {
564 String className = subst(layoutElement.getAttribute(CLASS_ATTR));
565 LOGGER.debug("Parsing layout of class: \"{}\"", className);
566 Layout layout = manager.parseLayout(className, layoutElement, this);
567 if (layout == null) {
568 layout = buildLayout(className, layoutElement);
569 }
570 return layout;
571 }
572
573 private Layout buildLayout(String className, Element layout_element) {
574 try {
575 Layout layout = LoaderUtil.newInstanceOf(className);
576 PropertySetter propSetter = new PropertySetter(layout);
577 forEachElement(layout_element.getChildNodes(), (currentElement) -> {
578 String tagName = currentElement.getTagName();
579 if (tagName.equals(PARAM_TAG)) {
580 setParameter(currentElement, propSetter);
581 } else {
582 try {
583 parseUnrecognizedElement(layout, currentElement, props);
584 } catch (Exception ex) {
585 throw new ConsumerException(ex);
586 }
587 }
588 });
589
590 propSetter.activate();
591 return layout;
592 } catch (ConsumerException ce) {
593 Throwable cause = ce.getCause();
594 if (cause instanceof InterruptedException || cause instanceof InterruptedIOException) {
595 Thread.currentThread().interrupt();
596 }
597 LOGGER.error("Could not create the Layout. Reported error follows.", cause);
598 } catch (Exception oops) {
599 if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
600 Thread.currentThread().interrupt();
601 }
602 LOGGER.error("Could not create the Layout. Reported error follows.", oops);
603 }
604 return null;
605 }
606
607
608
609
610 private void parseLevel(Element element, LoggerConfig logger, boolean isRoot) {
611 String catName = logger.getName();
612 if (isRoot) {
613 catName = "root";
614 }
615
616 String priStr = subst(element.getAttribute(VALUE_ATTR));
617 LOGGER.debug("Level value for {} is [{}}].", catName, priStr);
618
619 if (INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) {
620 if (isRoot) {
621 LOGGER.error("Root level cannot be inherited. Ignoring directive.");
622 } else {
623 logger.setLevel(null);
624 }
625 } else {
626 String className = subst(element.getAttribute(CLASS_ATTR));
627 if (EMPTY_STR.equals(className)) {
628 logger.setLevel(OptionConverter.convertLevel(priStr, org.apache.logging.log4j.Level.DEBUG));
629 } else {
630 LOGGER.debug("Desired Level sub-class: [{}]", className);
631 try {
632 Class<?> clazz = LoaderUtil.loadClass(className);
633 Method toLevelMethod = clazz.getMethod("toLevel", ONE_STRING_PARAM);
634 Level pri = (Level) toLevelMethod.invoke(null, new Object[]{priStr});
635 logger.setLevel(OptionConverter.convertLevel(pri));
636 } catch (Exception oops) {
637 if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
638 Thread.currentThread().interrupt();
639 }
640 LOGGER.error("Could not create level [" + priStr +
641 "]. Reported error follows.", oops);
642 return;
643 }
644 }
645 }
646 LOGGER.debug("{} level set to {}", catName, logger.getLevel());
647 }
648
649 private void setParameter(Element elem, PropertySetter propSetter) {
650 String name = subst(elem.getAttribute(NAME_ATTR));
651 String value = (elem.getAttribute(VALUE_ATTR));
652 value = subst(OptionConverter.convertSpecialChars(value));
653 propSetter.setProperty(name, value);
654 }
655
656
657
658
659
660
661 private void parse(Element element) {
662 String rootElementName = element.getTagName();
663
664 if (!rootElementName.equals(CONFIGURATION_TAG)) {
665 if (rootElementName.equals(OLD_CONFIGURATION_TAG)) {
666 LOGGER.warn("The <" + OLD_CONFIGURATION_TAG +
667 "> element has been deprecated.");
668 LOGGER.warn("Use the <" + CONFIGURATION_TAG + "> element instead.");
669 } else {
670 LOGGER.error("DOM element is - not a <" + CONFIGURATION_TAG + "> element.");
671 return;
672 }
673 }
674
675
676 String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR));
677
678 LOGGER.debug("debug attribute= \"" + debugAttrib + "\".");
679
680
681 String status = "error";
682 if (!debugAttrib.equals("") && !debugAttrib.equals("null")) {
683 status = OptionConverter.toBoolean(debugAttrib, true) ? "debug" : "error";
684
685 } else {
686 LOGGER.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
687 }
688
689 String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
690 if (!confDebug.equals("") && !confDebug.equals("null")) {
691 LOGGER.warn("The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated.");
692 LOGGER.warn("Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead.");
693 status = OptionConverter.toBoolean(confDebug, true) ? "debug" : "error";
694 }
695
696 final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(status);
697 statusConfig.initialize();
698
699 forEachElement(element.getChildNodes(), (currentElement) -> {
700 switch (currentElement.getTagName()) {
701 case CATEGORY: case LOGGER_ELEMENT:
702 parseCategory(currentElement);
703 break;
704 case ROOT_TAG:
705 parseRoot(currentElement);
706 break;
707 case RENDERER_TAG:
708 LOGGER.warn("Renderers are not supported by Log4j 2 and will be ignored.");
709 break;
710 case THROWABLE_RENDERER_TAG:
711 LOGGER.warn("Throwable Renderers are not supported by Log4j 2 and will be ignored.");
712 break;
713 case CATEGORY_FACTORY_TAG: case LOGGER_FACTORY_TAG:
714 LOGGER.warn("Log4j 1 Logger factories are not supported by Log4j 2 and will be ignored.");
715 break;
716 case APPENDER_TAG:
717 Appender appender = parseAppender(currentElement);
718 appenderMap.put(appender.getName(), appender);
719 if (appender instanceof AppenderWrapper) {
720 addAppender(((AppenderWrapper) appender).getAppender());
721 } else {
722 addAppender(new AppenderAdapter(appender).getAdapter());
723 }
724 break;
725 default:
726 quietParseUnrecognizedElement(null, currentElement, props);
727 }
728 });
729 }
730
731 private String subst(final String value) {
732 return getStrSubstitutor().replace(value);
733 }
734
735 public static void forEachElement(NodeList list, Consumer<Element> consumer) {
736 final int length = list.getLength();
737 for (int loop = 0; loop < length; loop++) {
738 Node currentNode = list.item(loop);
739
740 if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
741 Element currentElement = (Element) currentNode;
742 consumer.accept(currentElement);
743 }
744 }
745 }
746
747 private interface ParseAction {
748 Document parse(final DocumentBuilder parser) throws SAXException, IOException;
749 }
750
751 private static class SAXErrorHandler implements org.xml.sax.ErrorHandler {
752 private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
753
754 public void error(final SAXParseException ex) {
755 emitMessage("Continuable parsing error ", ex);
756 }
757
758 public void fatalError(final SAXParseException ex) {
759 emitMessage("Fatal parsing error ", ex);
760 }
761
762 public void warning(final SAXParseException ex) {
763 emitMessage("Parsing warning ", ex);
764 }
765
766 private static void emitMessage(final String msg, final SAXParseException ex) {
767 LOGGER.warn("{} {} and column {}", msg, ex.getLineNumber(), ex.getColumnNumber());
768 LOGGER.warn(ex.getMessage(), ex.getException());
769 }
770 }
771
772 private static class ConsumerException extends RuntimeException {
773
774 ConsumerException(Exception ex) {
775 super(ex);
776 }
777 }
778 }