1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.core.config;
18
19 import java.io.Serializable;
20 import java.lang.annotation.Annotation;
21 import java.lang.reflect.Array;
22 import java.lang.reflect.Method;
23 import java.lang.reflect.Modifier;
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.HashSet;
27 import java.util.List;
28 import java.util.Map;
29 import java.util.Set;
30 import java.util.concurrent.ConcurrentHashMap;
31 import java.util.concurrent.ConcurrentMap;
32 import java.util.concurrent.CopyOnWriteArrayList;
33
34 import org.apache.logging.log4j.Level;
35 import org.apache.logging.log4j.LogManager;
36 import org.apache.logging.log4j.Logger;
37 import org.apache.logging.log4j.core.Appender;
38 import org.apache.logging.log4j.core.Filter;
39 import org.apache.logging.log4j.core.Layout;
40 import org.apache.logging.log4j.core.LogEvent;
41 import org.apache.logging.log4j.core.appender.AsyncAppender;
42 import org.apache.logging.log4j.core.appender.ConsoleAppender;
43 import org.apache.logging.log4j.core.async.AsyncLoggerConfig;
44 import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
45 import org.apache.logging.log4j.core.config.plugins.PluginAliases;
46 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
47 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
48 import org.apache.logging.log4j.core.config.plugins.PluginElement;
49 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
50 import org.apache.logging.log4j.core.config.plugins.PluginManager;
51 import org.apache.logging.log4j.core.config.plugins.PluginNode;
52 import org.apache.logging.log4j.core.config.plugins.PluginType;
53 import org.apache.logging.log4j.core.config.plugins.PluginValue;
54 import org.apache.logging.log4j.core.filter.AbstractFilterable;
55 import org.apache.logging.log4j.core.helpers.Constants;
56 import org.apache.logging.log4j.core.helpers.NameUtil;
57 import org.apache.logging.log4j.core.impl.Log4jContextFactory;
58 import org.apache.logging.log4j.core.layout.PatternLayout;
59 import org.apache.logging.log4j.core.lookup.Interpolator;
60 import org.apache.logging.log4j.core.lookup.MapLookup;
61 import org.apache.logging.log4j.core.lookup.StrLookup;
62 import org.apache.logging.log4j.core.lookup.StrSubstitutor;
63 import org.apache.logging.log4j.core.net.Advertiser;
64 import org.apache.logging.log4j.core.selector.ContextSelector;
65 import org.apache.logging.log4j.spi.LoggerContextFactory;
66 import org.apache.logging.log4j.status.StatusLogger;
67 import org.apache.logging.log4j.util.PropertiesUtil;
68
69
70
71
72 public class BaseConfiguration extends AbstractFilterable implements Configuration {
73
74
75
76 protected static final Logger LOGGER = StatusLogger.getLogger();
77
78
79
80
81 protected Node rootNode;
82
83
84
85
86 protected final List<ConfigurationListener> listeners =
87 new CopyOnWriteArrayList<ConfigurationListener>();
88
89
90
91
92 protected ConfigurationMonitor monitor = new DefaultConfigurationMonitor();
93
94
95
96
97 private Advertiser advertiser = new DefaultAdvertiser();
98
99 protected Map<String, String> advertisedConfiguration;
100
101 private Node advertiserNode = null;
102
103 private Object advertisement;
104
105
106
107
108 protected boolean isShutdownHookEnabled = true;
109
110 private String name;
111
112 private ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<String, Appender>();
113
114 private ConcurrentMap<String, LoggerConfig> loggers = new ConcurrentHashMap<String, LoggerConfig>();
115
116 private ConcurrentMap<String, String> properties = new ConcurrentHashMap<String, String>();
117
118 private final StrLookup tempLookup = new Interpolator(properties);
119
120 private final StrSubstitutor subst = new StrSubstitutor(tempLookup);
121
122 private LoggerConfig root = new LoggerConfig();
123
124 private final boolean started = false;
125
126 private final ConcurrentMap<String, Object> componentMap = new ConcurrentHashMap<String, Object>();
127
128 protected PluginManager pluginManager;
129
130
131
132
133 protected BaseConfiguration() {
134 componentMap.put(Configuration.CONTEXT_PROPERTIES, properties);
135 pluginManager = new PluginManager("Core");
136 rootNode = new Node();
137 }
138
139 @Override
140 @SuppressWarnings("unchecked")
141 public Map<String, String> getProperties() {
142 return properties;
143 }
144
145
146
147
148 @Override
149 public void start() {
150 pluginManager.collectPlugins();
151 PluginManager levelPlugins = new PluginManager("Level");
152 levelPlugins.collectPlugins();
153 Map<String, PluginType<?>> plugins = levelPlugins.getPlugins();
154 if (plugins != null) {
155 for (PluginType<?> type : plugins.values()) {
156 try {
157
158 Class.forName(type.getPluginClass().getName(), true, type.getPluginClass().getClassLoader());
159 } catch (Exception ex) {
160 LOGGER.error("Unable to initialize " + type.getPluginClass().getName() + " due to " + ex.getClass().getSimpleName() + ":" + ex.getMessage());
161 }
162 }
163 }
164 setup();
165 setupAdvertisement();
166 doConfigure();
167 for (final LoggerConfig logger : loggers.values()) {
168 logger.startFilter();
169 }
170 for (final Appender appender : appenders.values()) {
171 appender.start();
172 }
173 root.startFilter();
174 startFilter();
175 }
176
177
178
179
180 @Override
181 public void stop() {
182
183
184 final LoggerContextFactory factory = LogManager.getFactory();
185 if (factory instanceof Log4jContextFactory) {
186 ContextSelector selector = ((Log4jContextFactory) factory).getSelector();
187 if (selector instanceof AsyncLoggerContextSelector) {
188
189
190
191
192
193
194 }
195 }
196
197 Set<LoggerConfig> alreadyStopped = new HashSet<LoggerConfig>();
198 for (final LoggerConfig logger : loggers.values()) {
199 if (logger instanceof AsyncLoggerConfig) {
200 logger.clearAppenders();
201 logger.stopFilter();
202 alreadyStopped.add(logger);
203 }
204 }
205 if (root instanceof AsyncLoggerConfig) {
206 root.stopFilter();
207 alreadyStopped.add(root);
208 }
209
210
211 final Appender[] array = appenders.values().toArray(new Appender[appenders.size()]);
212
213
214 for (int i = array.length - 1; i >= 0; --i) {
215 if (array[i] instanceof AsyncAppender) {
216 array[i].stop();
217 }
218 }
219 for (int i = array.length - 1; i >= 0; --i) {
220 if (array[i].isStarted()) {
221 array[i].stop();
222 }
223 }
224 for (final LoggerConfig logger : loggers.values()) {
225 if (alreadyStopped.contains(logger)) {
226 continue;
227 }
228 logger.clearAppenders();
229 logger.stopFilter();
230 }
231 if (!alreadyStopped.contains(root)) {
232 root.stopFilter();
233 }
234 stopFilter();
235 if (advertiser != null && advertisement != null) {
236 advertiser.unadvertise(advertisement);
237 }
238 }
239
240 @Override
241 public boolean isShutdownHookEnabled() {
242 return isShutdownHookEnabled;
243 }
244
245 protected void setup() {
246 }
247
248 protected Level getDefaultStatus() {
249 final String statusLevel = PropertiesUtil.getProperties().getStringProperty(Constants.LOG4J_DEFAULT_STATUS_LEVEL,
250 Level.ERROR.name());
251 try {
252 return Level.toLevel(statusLevel);
253 } catch (final Exception ex) {
254 return Level.ERROR;
255 }
256 }
257
258 protected void createAdvertiser(String advertiserString, ConfigurationFactory.ConfigurationSource configSource,
259 byte[] buffer, String contentType) {
260 if (advertiserString != null) {
261 Node node = new Node(null, advertiserString, null);
262 Map<String, String> attributes = node.getAttributes();
263 attributes.put("content", new String(buffer));
264 attributes.put("contentType", contentType);
265 attributes.put("name", "configuration");
266 if (configSource.getLocation() != null) {
267 attributes.put("location", configSource.getLocation());
268 }
269 advertiserNode = node;
270 }
271 }
272
273 private void setupAdvertisement() {
274 if (advertiserNode != null)
275 {
276 String name = advertiserNode.getName();
277 @SuppressWarnings("unchecked")
278 final PluginType<Advertiser> type = (PluginType<Advertiser>) pluginManager.getPluginType(name);
279 if (type != null)
280 {
281 final Class<Advertiser> clazz = type.getPluginClass();
282 try {
283 advertiser = clazz.newInstance();
284 advertisement = advertiser.advertise(advertiserNode.getAttributes());
285 } catch (final InstantiationException e) {
286 System.err.println("InstantiationException attempting to instantiate advertiser: " + name);
287 } catch (final IllegalAccessException e) {
288 System.err.println("IllegalAccessException attempting to instantiate advertiser: " + name);
289 }
290 }
291 }
292 }
293
294 @SuppressWarnings("unchecked")
295 @Override
296 public <T> T getComponent(final String name) {
297 return (T) componentMap.get(name);
298 }
299
300 @Override
301 public void addComponent(final String name, final Object obj) {
302 componentMap.putIfAbsent(name, obj);
303 }
304
305 @SuppressWarnings("unchecked")
306 protected void doConfigure() {
307 boolean setRoot = false;
308 boolean setLoggers = false;
309 if (rootNode.hasChildren() && rootNode.getChildren().get(0).getName().equalsIgnoreCase("Properties")) {
310 Node first = rootNode.getChildren().get(0);
311 createConfiguration(first, null);
312 if (first.getObject() != null) {
313 subst.setVariableResolver((StrLookup) first.getObject());
314 }
315 } else {
316 final Map<String, String> map = (Map<String, String>) componentMap.get(CONTEXT_PROPERTIES);
317 final StrLookup lookup = map == null ? null : new MapLookup(map);
318 subst.setVariableResolver(new Interpolator(lookup));
319 }
320
321 for (final Node child : rootNode.getChildren()) {
322 if (child.getName().equalsIgnoreCase("Properties")) {
323 if (tempLookup == subst.getVariableResolver()) {
324 LOGGER.error("Properties declaration must be the first element in the configuration");
325 }
326 continue;
327 }
328 createConfiguration(child, null);
329 if (child.getObject() == null) {
330 continue;
331 }
332 if (child.getName().equalsIgnoreCase("Appenders")) {
333 appenders = (ConcurrentMap<String, Appender>) child.getObject();
334 } else if (child.getObject() instanceof Filter) {
335 addFilter((Filter) child.getObject());
336 } else if (child.getName().equalsIgnoreCase("Loggers")) {
337 final Loggers l = (Loggers) child.getObject();
338 loggers = l.getMap();
339 setLoggers = true;
340 if (l.getRoot() != null) {
341 root = l.getRoot();
342 setRoot = true;
343 }
344 } else {
345 LOGGER.error("Unknown object \"" + child.getName() + "\" of type " +
346 child.getObject().getClass().getName() + " is ignored");
347 }
348 }
349
350 if (!setLoggers) {
351 LOGGER.warn("No Loggers were configured, using default. Is the Loggers element missing?");
352 setToDefault();
353 return;
354 } else if (!setRoot) {
355 LOGGER.warn("No Root logger was configured, creating default ERROR-level Root logger with Console appender");
356 setToDefault();
357
358 }
359
360 for (final Map.Entry<String, LoggerConfig> entry : loggers.entrySet()) {
361 final LoggerConfig l = entry.getValue();
362 for (final AppenderRef ref : l.getAppenderRefs()) {
363 final Appender app = appenders.get(ref.getRef());
364 if (app != null) {
365 l.addAppender(app, ref.getLevel(), ref.getFilter());
366 } else {
367 LOGGER.error("Unable to locate appender " + ref.getRef() + " for logger " + l.getName());
368 }
369 }
370
371 }
372
373 setParents();
374 }
375
376 private void setToDefault() {
377 setName(DefaultConfiguration.DEFAULT_NAME);
378 final Layout<? extends Serializable> layout =
379 PatternLayout.createLayout("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n",
380 null, null, null, null, null);
381 final Appender appender = ConsoleAppender.createAppender(layout, null, "SYSTEM_OUT", "Console", "false",
382 "true");
383 appender.start();
384 addAppender(appender);
385 final LoggerConfig root = getRootLogger();
386 root.addAppender(appender, null, null);
387
388 final String levelName = PropertiesUtil.getProperties().getStringProperty(DefaultConfiguration.DEFAULT_LEVEL);
389 final Level level = levelName != null && Level.getLevel(levelName) != null ?
390 Level.getLevel(levelName) : Level.ERROR;
391 root.setLevel(level);
392 }
393
394
395
396
397
398 public void setName(final String name) {
399 this.name = name;
400 }
401
402
403
404
405
406 @Override
407 public String getName() {
408 return name;
409 }
410
411
412
413
414
415 @Override
416 public void addListener(final ConfigurationListener listener) {
417 listeners.add(listener);
418 }
419
420
421
422
423
424 @Override
425 public void removeListener(final ConfigurationListener listener) {
426 listeners.remove(listener);
427 }
428
429
430
431
432
433
434 public Appender getAppender(final String name) {
435 return appenders.get(name);
436 }
437
438
439
440
441
442 @Override
443 public Map<String, Appender> getAppenders() {
444 return appenders;
445 }
446
447
448
449
450
451 public void addAppender(final Appender appender) {
452 appenders.put(appender.getName(), appender);
453 }
454
455 @Override
456 public StrSubstitutor getStrSubstitutor() {
457 return subst;
458 }
459
460 @Override
461 public void setConfigurationMonitor(final ConfigurationMonitor monitor) {
462 this.monitor = monitor;
463 }
464
465 @Override
466 public ConfigurationMonitor getConfigurationMonitor() {
467 return monitor;
468 }
469
470 @Override
471 public void setAdvertiser(final Advertiser advertiser) {
472 this.advertiser = advertiser;
473 }
474
475 @Override
476 public Advertiser getAdvertiser() {
477 return advertiser;
478 }
479
480
481
482
483
484
485
486
487
488
489 @Override
490 public synchronized void addLoggerAppender(final org.apache.logging.log4j.core.Logger logger,
491 final Appender appender) {
492 final String name = logger.getName();
493 appenders.putIfAbsent(appender.getName(), appender);
494 final LoggerConfig lc = getLoggerConfig(name);
495 if (lc.getName().equals(name)) {
496 lc.addAppender(appender, null, null);
497 } else {
498 final LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), lc.isAdditive());
499 nlc.addAppender(appender, null, null);
500 nlc.setParent(lc);
501 loggers.putIfAbsent(name, nlc);
502 setParents();
503 logger.getContext().updateLoggers();
504 }
505 }
506
507
508
509
510
511
512
513
514
515 @Override
516 public synchronized void addLoggerFilter(final org.apache.logging.log4j.core.Logger logger, final Filter filter) {
517 final String name = logger.getName();
518 final LoggerConfig lc = getLoggerConfig(name);
519 if (lc.getName().equals(name)) {
520
521 lc.addFilter(filter);
522 } else {
523 final LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), lc.isAdditive());
524 nlc.addFilter(filter);
525 nlc.setParent(lc);
526 loggers.putIfAbsent(name, nlc);
527 setParents();
528 logger.getContext().updateLoggers();
529 }
530 }
531
532
533
534
535
536
537
538
539
540 @Override
541 public synchronized void setLoggerAdditive(final org.apache.logging.log4j.core.Logger logger,
542 final boolean additive) {
543 final String name = logger.getName();
544 final LoggerConfig lc = getLoggerConfig(name);
545 if (lc.getName().equals(name)) {
546 lc.setAdditive(additive);
547 } else {
548 final LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), additive);
549 nlc.setParent(lc);
550 loggers.putIfAbsent(name, nlc);
551 setParents();
552 logger.getContext().updateLoggers();
553 }
554 }
555
556
557
558
559
560
561
562 public synchronized void removeAppender(final String name) {
563 for (final LoggerConfig logger : loggers.values()) {
564 logger.removeAppender(name);
565 }
566 final Appender app = appenders.remove(name);
567
568 if (app != null) {
569 app.stop();
570 }
571 }
572
573
574
575
576
577
578
579 @Override
580 public LoggerConfig getLoggerConfig(final String name) {
581 if (loggers.containsKey(name)) {
582 return loggers.get(name);
583 }
584 String substr = name;
585 while ((substr = NameUtil.getSubName(substr)) != null) {
586 if (loggers.containsKey(substr)) {
587 return loggers.get(substr);
588 }
589 }
590 return root;
591 }
592
593
594
595
596
597 public LoggerConfig getRootLogger() {
598 return root;
599 }
600
601
602
603
604
605 @Override
606 public Map<String, LoggerConfig> getLoggers() {
607 return Collections.unmodifiableMap(loggers);
608 }
609
610
611
612
613
614
615 public LoggerConfig getLogger(final String name) {
616 return loggers.get(name);
617 }
618
619
620
621
622
623
624
625
626 public void addLogger(final String name, final LoggerConfig loggerConfig) {
627 if (started) {
628 final String msg = "Cannot add logger " + name + " to an active configuration";
629 LOGGER.warn(msg);
630 throw new IllegalStateException(msg);
631 }
632 loggers.put(name, loggerConfig);
633 setParents();
634 }
635
636
637
638
639
640
641
642 public void removeLogger(final String name) {
643 if (started) {
644 final String msg = "Cannot remove logger " + name + " in an active configuration";
645 LOGGER.warn(msg);
646 throw new IllegalStateException(msg);
647 }
648 loggers.remove(name);
649 setParents();
650 }
651
652 @Override
653 public void createConfiguration(final Node node, final LogEvent event) {
654 final PluginType<?> type = node.getType();
655 if (type != null && type.isDeferChildren()) {
656 node.setObject(createPluginObject(type, node, event));
657 } else {
658 for (final Node child : node.getChildren()) {
659 createConfiguration(child, event);
660 }
661
662 if (type == null) {
663 if (node.getParent() != null) {
664 LOGGER.error("Unable to locate plugin for " + node.getName());
665 }
666 } else {
667 node.setObject(createPluginObject(type, node, event));
668 }
669 }
670 }
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687 private <T> Object createPluginObject(final PluginType<T> type, final Node node, final LogEvent event)
688 {
689 final Class<T> clazz = type.getPluginClass();
690
691 if (Map.class.isAssignableFrom(clazz)) {
692 try {
693 @SuppressWarnings("unchecked")
694 final Map<String, Object> map = (Map<String, Object>) clazz.newInstance();
695 for (final Node child : node.getChildren()) {
696 map.put(child.getName(), child.getObject());
697 }
698 return map;
699 } catch (final Exception ex) {
700 LOGGER.warn("Unable to create Map for " + type.getElementName() + " of class " +
701 clazz);
702 }
703 }
704
705 if (List.class.isAssignableFrom(clazz)) {
706 try {
707 @SuppressWarnings("unchecked")
708 final List<Object> list = (List<Object>) clazz.newInstance();
709 for (final Node child : node.getChildren()) {
710 list.add(child.getObject());
711 }
712 return list;
713 } catch (final Exception ex) {
714 LOGGER.warn("Unable to create List for " + type.getElementName() + " of class " +
715 clazz);
716 }
717 }
718
719 Method factoryMethod = null;
720
721 for (final Method method : clazz.getMethods()) {
722 if (method.isAnnotationPresent(PluginFactory.class)) {
723 factoryMethod = method;
724 break;
725 }
726 }
727 if (factoryMethod == null) {
728 return null;
729 }
730
731 final Annotation[][] parmArray = factoryMethod.getParameterAnnotations();
732 final Class<?>[] parmClasses = factoryMethod.getParameterTypes();
733 if (parmArray.length != parmClasses.length) {
734 LOGGER.error("Number of parameter annotations does not equal the number of paramters");
735 }
736 final Object[] parms = new Object[parmClasses.length];
737
738 int index = 0;
739 final Map<String, String> attrs = node.getAttributes();
740 final List<Node> children = node.getChildren();
741 final StringBuilder sb = new StringBuilder();
742 final List<Node> used = new ArrayList<Node>();
743
744
745
746
747
748
749
750
751
752
753
754 for (final Annotation[] parmTypes : parmArray) {
755 String[] aliases = null;
756 for (final Annotation a: parmTypes) {
757 if (a instanceof PluginAliases) {
758 aliases = ((PluginAliases) a).value();
759 }
760 }
761 for (final Annotation a : parmTypes) {
762 if (a instanceof PluginAliases) {
763 continue;
764 }
765 if (sb.length() == 0) {
766 sb.append(" with params(");
767 } else {
768 sb.append(", ");
769 }
770 if (a instanceof PluginNode) {
771 parms[index] = node;
772 sb.append("Node=").append(node.getName());
773 } else if (a instanceof PluginConfiguration) {
774 parms[index] = this;
775 if (this.name != null) {
776 sb.append("Configuration(").append(name).append(")");
777 } else {
778 sb.append("Configuration");
779 }
780 } else if (a instanceof PluginValue) {
781 final String name = ((PluginValue) a).value();
782 String v = node.getValue();
783 if (v == null) {
784 v = getAttrValue("value", null, attrs);
785 }
786 final String value = subst.replace(event, v);
787 sb.append(name).append("=\"").append(value).append("\"");
788 parms[index] = value;
789 } else if (a instanceof PluginAttribute) {
790 PluginAttribute attr = (PluginAttribute) a;
791 final String name = attr.value();
792 final String value = subst.replace(event, getAttrValue(name, aliases, attrs));
793 sb.append(name).append("=\"").append(value).append("\"");
794 parms[index] = value;
795 } else if (a instanceof PluginElement) {
796 final PluginElement elem = (PluginElement) a;
797 final String name = elem.value();
798 if (parmClasses[index].isArray()) {
799 final Class<?> parmClass = parmClasses[index].getComponentType();
800 final List<Object> list = new ArrayList<Object>();
801 sb.append(name).append("={");
802 boolean first = true;
803 for (final Node child : children) {
804 final PluginType<?> childType = child.getType();
805 if (elem.value().equalsIgnoreCase(childType.getElementName()) ||
806 parmClass.isAssignableFrom(childType.getPluginClass())) {
807 used.add(child);
808 if (!first) {
809 sb.append(", ");
810 }
811 first = false;
812 final Object obj = child.getObject();
813 if (obj == null) {
814 LOGGER.error("Null object returned for " + child.getName() + " in " +
815 node.getName());
816 continue;
817 }
818 if (obj.getClass().isArray()) {
819 printArray(sb, (Object[]) obj);
820 parms[index] = obj;
821 break;
822 }
823 sb.append(child.toString());
824 list.add(obj);
825 }
826 }
827 sb.append("}");
828 if (parms[index] != null) {
829 break;
830 }
831 if (list.size() > 0 && !parmClass.isAssignableFrom(list.get(0).getClass())) {
832 LOGGER.error("Attempted to assign List containing class " +
833 list.get(0).getClass().getName() + " to array of type " + parmClass +
834 " for attribute " + name);
835 break;
836 }
837 final Object[] array = (Object[]) Array.newInstance(parmClass, list.size());
838 int i = 0;
839 for (final Object obj : list) {
840 array[i] = obj;
841 ++i;
842 }
843 parms[index] = array;
844 } else {
845 final Class<?> parmClass = parmClasses[index];
846 boolean present = false;
847 for (final Node child : children) {
848 final PluginType<?> childType = child.getType();
849 if (elem.value().equals(childType.getElementName()) ||
850 parmClass.isAssignableFrom(childType.getPluginClass())) {
851 sb.append(child.getName()).append("(").append(child.toString()).append(")");
852 present = true;
853 used.add(child);
854 parms[index] = child.getObject();
855 break;
856 }
857 }
858 if (!present) {
859 sb.append("null");
860 }
861 }
862 }
863 }
864 ++index;
865 }
866 if (sb.length() > 0) {
867 sb.append(")");
868 }
869
870 if (attrs.size() > 0) {
871 final StringBuilder eb = new StringBuilder();
872 for (final String key : attrs.keySet()) {
873 if (eb.length() == 0) {
874 eb.append(node.getName());
875 eb.append(" contains ");
876 if (attrs.size() == 1) {
877 eb.append("an invalid element or attribute ");
878 } else {
879 eb.append("invalid attributes ");
880 }
881 } else {
882 eb.append(", ");
883 }
884 eb.append("\"");
885 eb.append(key);
886 eb.append("\"");
887
888 }
889 LOGGER.error(eb.toString());
890 }
891
892 if (!type.isDeferChildren() && used.size() != children.size()) {
893 for (final Node child : children) {
894 if (used.contains(child)) {
895 continue;
896 }
897 final String nodeType = node.getType().getElementName();
898 final String start = nodeType.equals(node.getName()) ? node.getName() : nodeType + " " + node.getName();
899 LOGGER.error(start + " has no parameter that matches element " + child.getName());
900 }
901 }
902
903 try {
904 final int mod = factoryMethod.getModifiers();
905 if (!Modifier.isStatic(mod)) {
906 LOGGER.error(factoryMethod.getName() + " method is not static on class " +
907 clazz.getName() + " for element " + node.getName());
908 return null;
909 }
910 LOGGER.debug("Calling {} on class {} for element {}{}", factoryMethod.getName(), clazz.getName(),
911 node.getName(), sb.toString());
912
913 return factoryMethod.invoke(null, parms);
914
915
916 } catch (final Exception e) {
917 LOGGER.error("Unable to invoke method " + factoryMethod.getName() + " in class " +
918 clazz.getName() + " for element " + node.getName(), e);
919 }
920 return null;
921 }
922
923 private void printArray(final StringBuilder sb, final Object... array) {
924 boolean first = true;
925 for (final Object obj : array) {
926 if (!first) {
927 sb.append(", ");
928 }
929 sb.append(obj.toString());
930 first = false;
931 }
932 }
933
934 private String getAttrValue(final String name, final String[] aliases, final Map<String, String> attrs) {
935 for (final String key : attrs.keySet()) {
936 if (key.equalsIgnoreCase(name)) {
937 final String attr = attrs.get(key);
938 attrs.remove(key);
939 return attr;
940 }
941 if (aliases != null) {
942 for (String alias : aliases) {
943 if (key.equalsIgnoreCase(alias)) {
944 final String attr = attrs.get(key);
945 attrs.remove(key);
946 return attr;
947 }
948 }
949 }
950 }
951 return null;
952 }
953
954 private void setParents() {
955 for (final Map.Entry<String, LoggerConfig> entry : loggers.entrySet()) {
956 final LoggerConfig logger = entry.getValue();
957 String name = entry.getKey();
958 if (!name.equals("")) {
959 final int i = name.lastIndexOf('.');
960 if (i > 0) {
961 name = name.substring(0, i);
962 LoggerConfig parent = getLoggerConfig(name);
963 if (parent == null) {
964 parent = root;
965 }
966 logger.setParent(parent);
967 } else {
968 logger.setParent(root);
969 }
970 }
971 }
972 }
973 }