001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache license, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the license for the specific language governing permissions and 015 * limitations under the license. 016 */ 017 package org.apache.logging.log4j.core.config; 018 019 import org.apache.logging.log4j.Level; 020 import org.apache.logging.log4j.Logger; 021 import org.apache.logging.log4j.core.Appender; 022 import org.apache.logging.log4j.core.Filter; 023 import org.apache.logging.log4j.core.Layout; 024 import org.apache.logging.log4j.core.LogEvent; 025 import org.apache.logging.log4j.core.appender.ConsoleAppender; 026 import org.apache.logging.log4j.core.config.plugins.PluginAttr; 027 import org.apache.logging.log4j.core.config.plugins.PluginConfiguration; 028 import org.apache.logging.log4j.core.config.plugins.PluginFactory; 029 import org.apache.logging.log4j.core.config.plugins.PluginManager; 030 import org.apache.logging.log4j.core.config.plugins.PluginElement; 031 import org.apache.logging.log4j.core.config.plugins.PluginNode; 032 import org.apache.logging.log4j.core.config.plugins.PluginType; 033 import org.apache.logging.log4j.core.config.plugins.PluginValue; 034 import org.apache.logging.log4j.core.filter.AbstractFilterable; 035 import org.apache.logging.log4j.core.helpers.NameUtil; 036 import org.apache.logging.log4j.core.layout.PatternLayout; 037 import org.apache.logging.log4j.core.lookup.Interpolator; 038 import org.apache.logging.log4j.core.lookup.MapLookup; 039 import org.apache.logging.log4j.core.lookup.StrLookup; 040 import org.apache.logging.log4j.core.lookup.StrSubstitutor; 041 import org.apache.logging.log4j.core.net.Advertiser; 042 import org.apache.logging.log4j.status.StatusLogger; 043 import org.apache.logging.log4j.util.PropertiesUtil; 044 045 import java.lang.annotation.Annotation; 046 import java.lang.reflect.Array; 047 import java.lang.reflect.Method; 048 import java.lang.reflect.Modifier; 049 import java.util.ArrayList; 050 import java.util.Collections; 051 import java.util.List; 052 import java.util.Map; 053 import java.util.concurrent.ConcurrentHashMap; 054 import java.util.concurrent.ConcurrentMap; 055 import java.util.concurrent.CopyOnWriteArrayList; 056 057 /** 058 * The Base Configuration. Many configuration implementations will extend this class. 059 */ 060 public class BaseConfiguration extends AbstractFilterable implements Configuration { 061 /** 062 * Allow subclasses access to the status logger without creating another instance. 063 */ 064 protected static final Logger LOGGER = StatusLogger.getLogger(); 065 066 /** 067 * The root node of the configuration. 068 */ 069 protected Node rootNode; 070 071 /** 072 * Listeners for configuration changes. 073 */ 074 protected final List<ConfigurationListener> listeners = 075 new CopyOnWriteArrayList<ConfigurationListener>(); 076 077 /** 078 * The ConfigurationMonitor that checks for configuration changes. 079 */ 080 protected ConfigurationMonitor monitor = new DefaultConfigurationMonitor(); 081 082 /** 083 * The Advertiser which exposes appender configurations to external systems. 084 */ 085 protected Advertiser advertiser = new DefaultAdvertiser(); 086 087 private String name; 088 089 private ConcurrentMap<String, Appender<?>> appenders = new ConcurrentHashMap<String, Appender<?>>(); 090 091 private ConcurrentMap<String, LoggerConfig> loggers = new ConcurrentHashMap<String, LoggerConfig>(); 092 093 private final StrLookup tempLookup = new Interpolator(); 094 095 private final StrSubstitutor subst = new StrSubstitutor(tempLookup); 096 097 private LoggerConfig root = new LoggerConfig(); 098 099 private final boolean started = false; 100 101 private final ConcurrentMap<String, Object> componentMap = new ConcurrentHashMap<String, Object>(); 102 103 /** 104 * Constructor. 105 */ 106 protected BaseConfiguration() { 107 rootNode = new Node(); 108 } 109 110 public Map<String, String> getProperties() { 111 return (Map<String, String>) componentMap.get(CONTEXT_PROPERTIES); 112 } 113 114 /** 115 * Initialize the configuration. 116 */ 117 public void start() { 118 setup(); 119 doConfigure(); 120 for (final LoggerConfig logger : loggers.values()) { 121 logger.startFilter(); 122 } 123 for (final Appender appender : appenders.values()) { 124 appender.start(); 125 } 126 127 startFilter(); 128 } 129 130 /** 131 * Tear down the configuration. 132 */ 133 public void stop() { 134 for (final LoggerConfig logger : loggers.values()) { 135 logger.clearAppenders(); 136 logger.stopFilter(); 137 } 138 // Stop the appenders in reverse order in case they still have activity. 139 final Appender[] array = appenders.values().toArray(new Appender[appenders.size()]); 140 for (int i = array.length - 1; i >= 0; --i) { 141 array[i].stop(); 142 } 143 stopFilter(); 144 } 145 146 protected void setup() { 147 } 148 149 public Object getComponent(final String name) { 150 return componentMap.get(name); 151 } 152 153 public void addComponent(final String name, final Object obj) { 154 componentMap.putIfAbsent(name, obj); 155 } 156 157 protected void doConfigure() { 158 boolean setRoot = false; 159 boolean setLoggers = false; 160 for (final Node child : rootNode.getChildren()) { 161 createConfiguration(child, null); 162 if (child.getObject() == null) { 163 continue; 164 } 165 if (child.getName().equalsIgnoreCase("properties")) { 166 if (tempLookup == subst.getVariableResolver()) { 167 subst.setVariableResolver((StrLookup) child.getObject()); 168 } else { 169 LOGGER.error("Properties declaration must be the first element in the configuration"); 170 } 171 continue; 172 } else if (tempLookup == subst.getVariableResolver()) { 173 final Map<String, String> map = (Map<String, String>) componentMap.get(CONTEXT_PROPERTIES); 174 final StrLookup lookup = map == null ? null : new MapLookup(map); 175 subst.setVariableResolver(new Interpolator(lookup)); 176 } 177 if (child.getName().equalsIgnoreCase("appenders")) { 178 appenders = (ConcurrentMap<String, Appender<?>>) child.getObject(); 179 } else if (child.getObject() instanceof Filter) { 180 addFilter((Filter) child.getObject()); 181 } else if (child.getName().equalsIgnoreCase("loggers")) { 182 final Loggers l = (Loggers) child.getObject(); 183 loggers = l.getMap(); 184 setLoggers = true; 185 if (l.getRoot() != null) { 186 root = l.getRoot(); 187 setRoot = true; 188 } 189 } else { 190 LOGGER.error("Unknown object \"" + child.getName() + "\" of type " + 191 child.getObject().getClass().getName() + " is ignored"); 192 } 193 } 194 195 if (!setLoggers) { 196 LOGGER.warn("No Loggers were configured, using default. Is the Loggers element missing?"); 197 setToDefault(); 198 return; 199 } else if (!setRoot) { 200 LOGGER.warn("No Root logger was configured, using default"); 201 setToDefault(); 202 return; 203 } 204 205 for (final Map.Entry<String, LoggerConfig> entry : loggers.entrySet()) { 206 final LoggerConfig l = entry.getValue(); 207 for (final AppenderRef ref : l.getAppenderRefs()) { 208 final Appender app = appenders.get(ref.getRef()); 209 if (app != null) { 210 l.addAppender(app, ref.getLevel(), ref.getFilter()); 211 } else { 212 LOGGER.error("Unable to locate appender " + ref.getRef() + " for logger " + l.getName()); 213 } 214 } 215 216 } 217 218 setParents(); 219 } 220 221 private void setToDefault() { 222 setName(DefaultConfiguration.DEFAULT_NAME); 223 final Layout layout = PatternLayout.createLayout("%d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n", 224 null, null, null); 225 final Appender appender = ConsoleAppender.createAppender(layout, null, "SYSTEM_OUT", "Console", "false", 226 "true"); 227 appender.start(); 228 addAppender(appender); 229 final LoggerConfig root = getRootLogger(); 230 root.addAppender(appender, null, null); 231 232 final String levelName = PropertiesUtil.getProperties().getStringProperty(DefaultConfiguration.DEFAULT_LEVEL); 233 final Level level = levelName != null && Level.valueOf(levelName) != null ? 234 Level.valueOf(levelName) : Level.ERROR; 235 root.setLevel(level); 236 } 237 238 protected PluginManager getPluginManager() { 239 //don't cache a pluginmanager instance - packages may be updated, requiring 240 // re-discovery of plugins 241 PluginManager mgr = new PluginManager("Core"); 242 mgr.collectPlugins(); 243 return mgr; 244 } 245 246 /** 247 * Set the name of the configuration. 248 * @param name The name. 249 */ 250 public void setName(final String name) { 251 this.name = name; 252 } 253 254 /** 255 * Returns the name of the configuration. 256 * @return the name of the configuration. 257 */ 258 public String getName() { 259 return name; 260 } 261 262 /** 263 * Add a listener for changes on the configuration. 264 * @param listener The ConfigurationListener to add. 265 */ 266 public void addListener(final ConfigurationListener listener) { 267 listeners.add(listener); 268 } 269 270 /** 271 * Remove a ConfigurationListener. 272 * @param listener The ConfigurationListener to remove. 273 */ 274 public void removeListener(final ConfigurationListener listener) { 275 listeners.remove(listener); 276 } 277 278 /** 279 * Returns the Appender with the specified name. 280 * @param name The name of the Appender. 281 * @return the Appender with the specified name or null if the Appender cannot be located. 282 */ 283 public Appender getAppender(final String name) { 284 return appenders.get(name); 285 } 286 287 /** 288 * Returns a Map containing all the Appenders and their name. 289 * @return A Map containing each Appender's name and the Appender object. 290 */ 291 public Map<String, Appender<?>> getAppenders() { 292 return appenders; 293 } 294 295 /** 296 * Adds an Appender to the configuration. 297 * @param appender The Appender to add. 298 */ 299 public void addAppender(final Appender appender) { 300 appenders.put(appender.getName(), appender); 301 } 302 303 public StrSubstitutor getSubst() { 304 return subst; 305 } 306 307 public void setConfigurationMonitor(ConfigurationMonitor monitor) { 308 this.monitor = monitor; 309 } 310 311 public ConfigurationMonitor getConfigurationMonitor() { 312 return monitor; 313 } 314 315 public void setAdvertiser(Advertiser advertiser) { 316 this.advertiser = advertiser; 317 } 318 319 public Advertiser getAdvertiser() { 320 return advertiser; 321 } 322 323 /** 324 * Associates an Appender with a LoggerConfig. This method is synchronized in case a Logger with the 325 * same name is being updated at the same time. 326 * 327 * Note: This method is not used when configuring via configuration. It is primarily used by 328 * unit tests. 329 * @param logger The Logger the Appender will be associated with. 330 * @param appender The Appender. 331 */ 332 public synchronized void addLoggerAppender(final org.apache.logging.log4j.core.Logger logger, 333 final Appender appender) { 334 final String name = logger.getName(); 335 appenders.putIfAbsent(appender.getName(), appender); 336 final LoggerConfig lc = getLoggerConfig(name); 337 if (lc.getName().equals(name)) { 338 lc.addAppender(appender, null, null); 339 } else { 340 final LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), lc.isAdditive()); 341 nlc.addAppender(appender, null, null); 342 nlc.setParent(lc); 343 loggers.putIfAbsent(name, nlc); 344 setParents(); 345 logger.getContext().updateLoggers(); 346 } 347 } 348 /** 349 * Associates a Filter with a LoggerConfig. This method is synchronized in case a Logger with the 350 * same name is being updated at the same time. 351 * 352 * Note: This method is not used when configuring via configuration. It is primarily used by 353 * unit tests. 354 * @param logger The Logger the Fo;ter will be associated with. 355 * @param filter The Filter. 356 */ 357 public synchronized void addLoggerFilter(final org.apache.logging.log4j.core.Logger logger, final Filter filter) { 358 final String name = logger.getName(); 359 final LoggerConfig lc = getLoggerConfig(name); 360 if (lc.getName().equals(name)) { 361 362 lc.addFilter(filter); 363 } else { 364 final LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), lc.isAdditive()); 365 nlc.addFilter(filter); 366 nlc.setParent(lc); 367 loggers.putIfAbsent(name, nlc); 368 setParents(); 369 logger.getContext().updateLoggers(); 370 } 371 } 372 /** 373 * Marks a LoggerConfig as additive. This method is synchronized in case a Logger with the 374 * same name is being updated at the same time. 375 * 376 * Note: This method is not used when configuring via configuration. It is primarily used by 377 * unit tests. 378 * @param logger The Logger the Appender will be associated with. 379 * @param additive True if the LoggerConfig should be additive, false otherwise. 380 */ 381 public synchronized void setLoggerAdditive(final org.apache.logging.log4j.core.Logger logger, 382 final boolean additive) { 383 final String name = logger.getName(); 384 final LoggerConfig lc = getLoggerConfig(name); 385 if (lc.getName().equals(name)) { 386 lc.setAdditive(additive); 387 } else { 388 final LoggerConfig nlc = new LoggerConfig(name, lc.getLevel(), additive); 389 nlc.setParent(lc); 390 loggers.putIfAbsent(name, nlc); 391 setParents(); 392 logger.getContext().updateLoggers(); 393 } 394 } 395 396 /** 397 * Remove an Appender. First removes any associations between LoggerConfigs and the Appender, removes 398 * the Appender from this appender list and then stops the appender. This method is synchronized in 399 * case an Appender with the same name is being added during the removal. 400 * @param name the name of the appender to remove. 401 */ 402 public synchronized void removeAppender(final String name) { 403 for (final LoggerConfig logger : loggers.values()) { 404 logger.removeAppender(name); 405 } 406 final Appender app = appenders.remove(name); 407 408 if (app != null) { 409 app.stop(); 410 } 411 } 412 413 /** 414 * Locates the appropriate LoggerConfig for a Logger name. This will remove tokens from the 415 * package name as necessary or return the root LoggerConfig if no other matches were found. 416 * @param name The Logger name. 417 * @return The located LoggerConfig. 418 */ 419 public LoggerConfig getLoggerConfig(final String name) { 420 if (loggers.containsKey(name)) { 421 return loggers.get(name); 422 } 423 String substr = name; 424 while ((substr = NameUtil.getSubName(substr)) != null) { 425 if (loggers.containsKey(substr)) { 426 return loggers.get(substr); 427 } 428 } 429 return root; 430 } 431 432 /** 433 * Returns the root Logger. 434 * @return the root Logger. 435 */ 436 public LoggerConfig getRootLogger() { 437 return root; 438 } 439 440 /** 441 * Returns a Map of all the LoggerConfigs. 442 * @return a Map with each entry containing the name of the Logger and the LoggerConfig. 443 */ 444 public Map<String, LoggerConfig> getLoggers() { 445 return Collections.unmodifiableMap(loggers); 446 } 447 448 /** 449 * Returns the LoggerConfig with the specified name. 450 * @param name The Logger name. 451 * @return The LoggerConfig or null if no match was found. 452 */ 453 public LoggerConfig getLogger(final String name) { 454 return loggers.get(name); 455 } 456 457 /** 458 * Adding a logger cannot be done atomically so is not allowed in an active configuration. Adding 459 * or removing a Logger requires creating a new configuration and then switching. 460 * 461 * @param name The name of the Logger. 462 * @param loggerConfig The LoggerConfig. 463 */ 464 public void addLogger(final String name, final LoggerConfig loggerConfig) { 465 if (started) { 466 final String msg = "Cannot add logger " + name + " to an active configuration"; 467 LOGGER.warn(msg); 468 throw new IllegalStateException(msg); 469 } 470 loggers.put(name, loggerConfig); 471 setParents(); 472 } 473 474 /** 475 * Removing a logger cannot be done atomically so is not allowed in an active configuration. Adding 476 * or removing a Logger requires creating a new configuration and then switching. 477 * 478 * @param name The name of the Logger. 479 */ 480 public void removeLogger(final String name) { 481 if (started) { 482 final String msg = "Cannot remove logger " + name + " in an active configuration"; 483 LOGGER.warn(msg); 484 throw new IllegalStateException(msg); 485 } 486 loggers.remove(name); 487 setParents(); 488 } 489 490 public void createConfiguration(final Node node, final LogEvent event) { 491 final PluginType type = node.getType(); 492 if (type != null && type.isDeferChildren()) { 493 node.setObject(createPluginObject(type, node, event)); 494 } else { 495 for (final Node child : node.getChildren()) { 496 createConfiguration(child, event); 497 } 498 499 if (type == null) { 500 if (node.getParent() != null) { 501 LOGGER.error("Unable to locate plugin for " + node.getName()); 502 } 503 } else { 504 node.setObject(createPluginObject(type, node, event)); 505 } 506 } 507 } 508 509 /* 510 * Retrieve a static public 'method to create the desired object. Every parameter 511 * will be annotated to identify the appropriate attribute or element to use to 512 * set the value of the parameter. 513 * Parameters annotated with PluginAttr will always be set as Strings. 514 * Parameters annotated with PluginElement may be Objects or arrays. Collections 515 * and Maps are currently not supported, although the factory method that is called 516 * can create these from an array. 517 * 518 * Although the happy path works, more work still needs to be done to log incorrect 519 * parameters. These will generally result in unhelpful InvocationTargetExceptions. 520 * @param classClass the class. 521 * @return the instantiate method or null if there is none by that 522 * description. 523 */ 524 private Object createPluginObject(final PluginType type, final Node node, final LogEvent event) 525 { 526 final Class clazz = type.getPluginClass(); 527 528 if (Map.class.isAssignableFrom(clazz)) { 529 try { 530 final Map<String, Object> map = (Map<String, Object>) clazz.newInstance(); 531 for (final Node child : node.getChildren()) { 532 map.put(child.getName(), child.getObject()); 533 } 534 return map; 535 } catch (final Exception ex) { 536 LOGGER.warn("Unable to create Map for " + type.getElementName() + " of class " + 537 clazz); 538 } 539 } 540 541 if (List.class.isAssignableFrom(clazz)) { 542 try { 543 final List<Object> list = (List<Object>) clazz.newInstance(); 544 for (final Node child : node.getChildren()) { 545 list.add(child.getObject()); 546 } 547 return list; 548 } catch (final Exception ex) { 549 LOGGER.warn("Unable to create List for " + type.getElementName() + " of class " + 550 clazz); 551 } 552 } 553 554 Method factoryMethod = null; 555 556 for (final Method method : clazz.getMethods()) { 557 if (method.isAnnotationPresent(PluginFactory.class)) { 558 factoryMethod = method; 559 break; 560 } 561 } 562 if (factoryMethod == null) { 563 return null; 564 } 565 566 final Annotation[][] parmArray = factoryMethod.getParameterAnnotations(); 567 final Class[] parmClasses = factoryMethod.getParameterTypes(); 568 if (parmArray.length != parmClasses.length) { 569 LOGGER.error("Number of parameter annotations does not equal the number of paramters"); 570 } 571 final Object[] parms = new Object[parmClasses.length]; 572 573 int index = 0; 574 final Map<String, String> attrs = node.getAttributes(); 575 final List<Node> children = node.getChildren(); 576 final StringBuilder sb = new StringBuilder(); 577 final List<Node> used = new ArrayList<Node>(); 578 579 /* 580 * For each parameter: 581 * If the parameter is an attribute store the value of the attribute in the parameter array. 582 * If the parameter is an element: 583 * Determine if the required parameter is an array. 584 * If so, if a child contains the array, use it, 585 * otherwise create the array from all child nodes of the correct type. 586 * Store the array into the parameter array. 587 * If not an array, store the object in the child node into the parameter array. 588 */ 589 for (final Annotation[] parmTypes : parmArray) { 590 for (final Annotation a : parmTypes) { 591 if (sb.length() == 0) { 592 sb.append(" with params("); 593 } else { 594 sb.append(", "); 595 } 596 if (a instanceof PluginNode) { 597 parms[index] = node; 598 sb.append("Node=").append(node.getName()); 599 } else if (a instanceof PluginConfiguration) { 600 parms[index] = this; 601 if (this.name != null) { 602 sb.append("Configuration(").append(name).append(")"); 603 } else { 604 sb.append("Configuration"); 605 } 606 } else if (a instanceof PluginValue) { 607 final String name = ((PluginValue) a).value(); 608 String v = node.getValue(); 609 if (v == null) { 610 v = getAttrValue("value", attrs); 611 } 612 final String value = subst.replace(event, v); 613 sb.append(name).append("=\"").append(value).append("\""); 614 parms[index] = value; 615 } else if (a instanceof PluginAttr) { 616 final String name = ((PluginAttr) a).value(); 617 final String value = subst.replace(event, getAttrValue(name, attrs)); 618 sb.append(name).append("=\"").append(value).append("\""); 619 parms[index] = value; 620 } else if (a instanceof PluginElement) { 621 final PluginElement elem = (PluginElement) a; 622 final String name = elem.value(); 623 if (parmClasses[index].isArray()) { 624 final Class parmClass = parmClasses[index].getComponentType(); 625 final List<Object> list = new ArrayList<Object>(); 626 sb.append(name).append("={"); 627 boolean first = true; 628 for (final Node child : children) { 629 final PluginType childType = child.getType(); 630 if (elem.value().equalsIgnoreCase(childType.getElementName()) || 631 parmClass.isAssignableFrom(childType.getPluginClass())) { 632 used.add(child); 633 if (!first) { 634 sb.append(", "); 635 } 636 first = false; 637 final Object obj = child.getObject(); 638 if (obj == null) { 639 LOGGER.error("Null object returned for " + child.getName() + " in " + 640 node.getName()); 641 continue; 642 } 643 if (obj.getClass().isArray()) { 644 printArray(sb, (Object[]) obj); 645 parms[index] = obj; 646 break; 647 } 648 sb.append(child.toString()); 649 list.add(obj); 650 } 651 } 652 sb.append("}"); 653 if (parms[index] != null) { 654 break; 655 } 656 if (list.size() > 0 && !parmClass.isAssignableFrom(list.get(0).getClass())) { 657 LOGGER.error("Attempted to assign List containing class " + 658 list.get(0).getClass().getName() + " to array of type " + parmClass + 659 " for attribute " + name); 660 break; 661 } 662 final Object[] array = (Object[]) Array.newInstance(parmClass, list.size()); 663 int i = 0; 664 for (final Object obj : list) { 665 array[i] = obj; 666 ++i; 667 } 668 parms[index] = array; 669 } else { 670 final Class parmClass = parmClasses[index]; 671 boolean present = false; 672 for (final Node child : children) { 673 final PluginType childType = child.getType(); 674 if (elem.value().equals(childType.getElementName()) || 675 parmClass.isAssignableFrom(childType.getPluginClass())) { 676 sb.append(child.getName()).append("(").append(child.toString()).append(")"); 677 present = true; 678 used.add(child); 679 parms[index] = child.getObject(); 680 break; 681 } 682 } 683 if (!present) { 684 sb.append("null"); 685 } 686 } 687 } 688 } 689 ++index; 690 } 691 if (sb.length() > 0) { 692 sb.append(")"); 693 } 694 695 if (attrs.size() > 0) { 696 final StringBuilder eb = new StringBuilder(); 697 for (final String key : attrs.keySet()) { 698 if (eb.length() == 0) { 699 eb.append(node.getName()); 700 eb.append(" contains "); 701 if (attrs.size() == 1) { 702 eb.append("an invalid element or attribute "); 703 } else { 704 eb.append("invalid attributes "); 705 } 706 } else { 707 eb.append(", "); 708 } 709 eb.append("\""); 710 eb.append(key); 711 eb.append("\""); 712 713 } 714 LOGGER.error(eb.toString()); 715 } 716 717 if (!type.isDeferChildren() && used.size() != children.size()) { 718 for (final Node child : children) { 719 if (used.contains(child)) { 720 continue; 721 } 722 final String nodeType = node.getType().getElementName(); 723 final String start = nodeType.equals(node.getName()) ? node.getName() : nodeType + " " + node.getName(); 724 LOGGER.error(start + " has no parameter that matches element " + child.getName()); 725 } 726 } 727 728 try { 729 final int mod = factoryMethod.getModifiers(); 730 if (!Modifier.isStatic(mod)) { 731 LOGGER.error(factoryMethod.getName() + " method is not static on class " + 732 clazz.getName() + " for element " + node.getName()); 733 return null; 734 } 735 LOGGER.debug("Calling {} on class {} for element {}{}", factoryMethod.getName(), clazz.getName(), 736 node.getName(), sb.toString()); 737 //if (parms.length > 0) { 738 return factoryMethod.invoke(null, parms); 739 //} 740 //return factoryMethod.invoke(null, node); 741 } catch (final Exception e) { 742 LOGGER.error("Unable to invoke method " + factoryMethod.getName() + " in class " + 743 clazz.getName() + " for element " + node.getName(), e); 744 } 745 return null; 746 } 747 748 private void printArray(final StringBuilder sb, final Object... array) { 749 boolean first = true; 750 for (final Object obj : array) { 751 if (!first) { 752 sb.append(", "); 753 } 754 sb.append(obj.toString()); 755 first = false; 756 } 757 } 758 759 private String getAttrValue(final String name, final Map<String, String> attrs) { 760 for (final String key : attrs.keySet()) { 761 if (key.equalsIgnoreCase(name)) { 762 final String attr = attrs.get(key); 763 attrs.remove(key); 764 return attr; 765 } 766 } 767 return null; 768 } 769 770 private void setParents() { 771 for (final Map.Entry<String, LoggerConfig> entry : loggers.entrySet()) { 772 final LoggerConfig logger = entry.getValue(); 773 String name = entry.getKey(); 774 if (!name.equals("")) { 775 final int i = name.lastIndexOf('.'); 776 if (i > 0) { 777 name = name.substring(0, i); 778 LoggerConfig parent = getLoggerConfig(name); 779 if (parent == null) { 780 parent = root; 781 } 782 logger.setParent(parent); 783 } else { 784 logger.setParent(root); 785 } 786 } 787 } 788 } 789 }