Author: mattsicker
Date: Thu Apr 10 20:06:14 2014
New Revision: 1586456
URL: http://svn.apache.org/r1586456
Log:
Create PluginBuilder for Configuration objects.
Added:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilder.java
(with props)
Modified:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
Modified:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java?rev=1586456&r1=1586455&r2=1586456&view=diff
==============================================================================
---
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
(original)
+++
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
Thu Apr 10 20:06:14 2014
@@ -20,11 +20,6 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.Serializable;
-import java.lang.annotation.Annotation;
-import java.lang.reflect.Array;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
@@ -34,7 +29,6 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.CopyOnWriteArrayList;
-
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
@@ -46,15 +40,10 @@ import org.apache.logging.log4j.core.app
import org.apache.logging.log4j.core.appender.ConsoleAppender;
import org.apache.logging.log4j.core.async.AsyncLoggerConfig;
import org.apache.logging.log4j.core.async.AsyncLoggerContextSelector;
-import org.apache.logging.log4j.core.config.plugins.PluginAliases;
-import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
-import org.apache.logging.log4j.core.config.plugins.PluginConfiguration;
-import org.apache.logging.log4j.core.config.plugins.PluginElement;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilder;
import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.config.plugins.PluginManager;
-import org.apache.logging.log4j.core.config.plugins.PluginNode;
import org.apache.logging.log4j.core.config.plugins.PluginType;
-import org.apache.logging.log4j.core.config.plugins.PluginValue;
import org.apache.logging.log4j.core.filter.AbstractFilterable;
import org.apache.logging.log4j.core.helpers.Constants;
import org.apache.logging.log4j.core.helpers.NameUtil;
@@ -666,10 +655,11 @@ public abstract class AbstractConfigurat
}
}
- /*
- * Retrieve a static public 'method to create the desired object. Every
parameter
- * will be annotated to identify the appropriate attribute or element to
use to
+ /**
+ * Invokes a static factory method to create the desired object. Every
parameter
+ * must be annotated to identify the appropriate attribute or element to
use to
* set the value of the parameter.
+ *
* Parameters annotated with PluginAttribute will always be set as Strings.
* Parameters annotated with PluginElement may be Objects or arrays.
Collections
* and Maps are currently not supported, although the factory method that
is called
@@ -677,9 +667,11 @@ public abstract class AbstractConfigurat
*
* Although the happy path works, more work still needs to be done to log
incorrect
* parameters. These will generally result in unhelpful
InvocationTargetExceptions.
- * @param classClass the class.
- * @return the instantiate method or null if there is none by that
- * description.
+ *
+ * @param type the type of plugin to create.
+ * @param node the corresponding configuration node for this plugin to
create.
+ * @param event the LogEvent that spurred the creation of this plugin
+ * @return the created plugin object or {@code null} if there was an error
setting it up.
*/
private <T> Object createPluginObject(final PluginType<T> type, final Node
node, final LogEvent event)
{
@@ -702,216 +694,17 @@ public abstract class AbstractConfigurat
}
}
- Method factoryMethod = findFactoryMethod(clazz);
- if (factoryMethod == null) return null;
-
- final Annotation[][] parmArray =
factoryMethod.getParameterAnnotations();
- final Class<?>[] parmClasses = factoryMethod.getParameterTypes();
- if (parmArray.length != parmClasses.length) {
- LOGGER.error("Number of parameter annotations ({}) does not equal
the number of parameters ({})",
- parmArray.length, parmClasses.length
- );
- }
- final Object[] parms = new Object[parmClasses.length];
-
- int index = 0;
- final Map<String, String> attrs = node.getAttributes();
- final List<Node> children = node.getChildren();
- final StringBuilder sb = new StringBuilder();
- final List<Node> used = new ArrayList<Node>();
-
- /*
- * For each parameter:
- * If the parameter is an attribute store the value of the attribute
in the parameter array.
- * If the parameter is an element:
- * Determine if the required parameter is an array.
- * If so, if a child contains the array, use it,
- * otherwise create the array from all child nodes of the correct
type.
- * Store the array into the parameter array.
- * If not an array, store the object in the child node into the
parameter array.
- */
- for (final Annotation[] parmTypes : parmArray) {
- String[] aliases = extractPluginAliases(parmTypes);
- for (final Annotation a : parmTypes) {
- if (a instanceof PluginAliases) {
- continue;
- }
- if (sb.length() == 0) {
- sb.append(" with params(");
- } else {
- sb.append(", ");
- }
- if (a instanceof PluginNode) {
- parms[index] = node;
- sb.append("Node=").append(node.getName());
- } else if (a instanceof PluginConfiguration) {
- parms[index] = this;
- if (this.name != null) {
- sb.append("Configuration(").append(name).append(')');
- } else {
- sb.append("Configuration");
- }
- } else if (a instanceof PluginValue) {
- final String name = ((PluginValue) a).value();
- String v = node.getValue();
- if (v == null) {
- v = getAttrValue("value", null, attrs);
- }
- final String value = subst.replace(event, v);
- sb.append(name).append("=\"").append(value).append('"');
- parms[index] = value;
- } else if (a instanceof PluginAttribute) {
- PluginAttribute attr = (PluginAttribute) a;
- final String name = attr.value();
- final String value = subst.replace(event,
getAttrValue(name, aliases, attrs));
- sb.append(name).append("=\"").append(value).append('"');
- parms[index] = value;
- } else if (a instanceof PluginElement) {
- final PluginElement elem = (PluginElement) a;
- final String name = elem.value();
- if (parmClasses[index].isArray()) {
- final Class<?> parmClass =
parmClasses[index].getComponentType();
- final List<Object> list = new ArrayList<Object>();
- sb.append(name).append("={");
- boolean first = true;
- for (final Node child : children) {
- final PluginType<?> childType = child.getType();
- if
(name.equalsIgnoreCase(childType.getElementName()) ||
-
parmClass.isAssignableFrom(childType.getPluginClass())) {
- used.add(child);
- if (!first) {
- sb.append(", ");
- }
- first = false;
- final Object obj = child.getObject();
- if (obj == null) {
- LOGGER.error("Null object returned for {}
in {}", child.getName(), node.getName());
- continue;
- }
- if (obj.getClass().isArray()) {
- printArray(sb, (Object[]) obj);
- parms[index] = obj;
- break;
- }
- sb.append(child.toString());
- list.add(obj);
- }
- }
- sb.append('}');
- if (parms[index] != null) {
- break;
- }
- if (!(list.isEmpty() ||
parmClass.isAssignableFrom(list.get(0).getClass()))) {
- LOGGER.error(
- "Attempted to assign List containing class
{} to array of type {} for attribute {}",
- list.get(0).getClass().getName(),
parmClass, name
- );
- break;
- }
- parms[index] = collectionToArray(list, parmClass);
- } else {
- final Node child = findNamedNode(name,
parmClasses[index], children);
- if (child == null) {
- sb.append("null");
- } else {
-
sb.append(child.getName()).append('(').append(child.toString()).append(')');
- used.add(child);
- parms[index] = child.getObject();
- }
- }
- }
- }
- ++index;
- }
- if (sb.length() > 0) {
- sb.append(')');
- }
-
- checkForRemainingAttributes(node);
-
- if (!type.isDeferChildren() && used.size() != children.size()) {
- children.removeAll(used);
- for (final Node child : children) {
- final String nodeType = node.getType().getElementName();
- final String start = nodeType.equals(node.getName()) ?
node.getName() : nodeType + ' ' + node.getName();
- LOGGER.error("{} has no parameter that matches element {}",
start, child.getName());
- }
- }
-
try {
- final int mod = factoryMethod.getModifiers();
- if (!Modifier.isStatic(mod)) {
- LOGGER.error("{} method is not static on class {} for element
{}",
- factoryMethod.getName(), clazz.getName(),
node.getName());
- return null;
- }
- LOGGER.debug("Calling {} on class {} for element {}{}",
factoryMethod.getName(), clazz.getName(),
- node.getName(), sb.toString());
- //if (parms.length > 0) {
- return factoryMethod.invoke(null, parms);
- //}
- //return factoryMethod.invoke(null, node);
- } catch (final Exception e) {
- LOGGER.error("Unable to invoke method {} in class {} for element
{}",
- factoryMethod.getName(), clazz.getName(), node.getName(),
e);
- }
- return null;
- }
-
- private static Object[] collectionToArray(final Collection<?> collection,
final Class<?> type) {
- final Object[] array = (Object[]) Array.newInstance(type,
collection.size());
- int i = 0;
- for (final Object obj : collection) {
- array[i] = obj;
- ++i;
- }
- return array;
- }
-
- private static Node findNamedNode(final String name, final Class<?> type,
final Iterable<Node> nodes) {
- for (final Node child : nodes) {
- final PluginType<?> childType = child.getType();
- if (name.equalsIgnoreCase(childType.getElementName()) ||
- type.isAssignableFrom(childType.getPluginClass())) {
- return child;
- }
- }
- return null;
- }
-
- private static void checkForRemainingAttributes(final Node node) {
- final Map<String, String> attrs = node.getAttributes();
- if (!attrs.isEmpty()) {
- final StringBuilder eb = new StringBuilder();
- for (final String key : attrs.keySet()) {
- if (eb.length() == 0) {
- eb.append(node.getName());
- eb.append(" contains ");
- if (attrs.size() == 1) {
- eb.append("an invalid element or attribute ");
- } else {
- eb.append("invalid attributes ");
- }
- } else {
- eb.append(", ");
- }
- eb.append('"');
- eb.append(key);
- eb.append('"');
-
- }
- LOGGER.error(eb.toString());
- }
- }
-
- private static String[] extractPluginAliases(final Annotation...
parmTypes) {
- String[] aliases = null;
- for (final Annotation a : parmTypes) {
- if (a instanceof PluginAliases) {
- aliases = ((PluginAliases) a).value();
- }
+ return new PluginBuilder<T>(type)
+ .withFactoryMethodAnnotatedBy(PluginFactory.class)
+ .withConfiguration(this)
+ .withConfigurationNode(node)
+ .forLogEvent(event)
+ .build();
+ } catch (NoSuchMethodException e) {
+ LOGGER.error("No suitable factory method could be found on class
{}", clazz, e);
+ return null;
}
- return aliases;
}
private static <T> Object createPluginMap(final Node node, final Class<T>
clazz) throws InstantiationException, IllegalAccessException {
@@ -932,48 +725,6 @@ public abstract class AbstractConfigurat
return list;
}
- private static <T> Method findFactoryMethod(final Class<T> clazz) {
- for (final Method method : clazz.getMethods()) {
- if (method.isAnnotationPresent(PluginFactory.class)) {
- return method;
- }
- }
- // TODO: this should probably throw an exception instead of returning
null
- return null;
- }
-
- private void printArray(final StringBuilder sb, final Object... array) {
- boolean first = true;
- for (final Object obj : array) {
- if (!first) {
- sb.append(", ");
- }
- sb.append(obj.toString());
- first = false;
- }
- }
-
- private String getAttrValue(final String name, final String[] aliases,
final Map<String, String> attrs) {
- for (final Map.Entry<String, String> entry : attrs.entrySet()) {
- final String key = entry.getKey();
- if (key.equalsIgnoreCase(name)) {
- final String attr = entry.getValue();
- attrs.remove(key);
- return attr;
- }
- if (aliases != null) {
- for (String alias : aliases) {
- if (key.equalsIgnoreCase(alias)) {
- final String attr = entry.getValue();
- attrs.remove(key);
- return attr;
- }
- }
- }
- }
- return null;
- }
-
private void setParents() {
for (final Map.Entry<String, LoggerConfig> entry :
loggers.entrySet()) {
final LoggerConfig logger = entry.getValue();
Added:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilder.java
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilder.java?rev=1586456&view=auto
==============================================================================
---
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilder.java
(added)
+++
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilder.java
Thu Apr 10 20:06:14 2014
@@ -0,0 +1,337 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.logging.log4j.core.config.plugins;
+
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Array;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.Node;
+import org.apache.logging.log4j.status.StatusLogger;
+
+/**
+ * Builder class to instantiate and configure a Plugin object using a
PluginFactory method.
+ *
+ * @param <T> type of Plugin class.
+ */
+public class PluginBuilder<T> {
+
+ private static final Logger LOGGER = StatusLogger.getLogger();
+
+ private final PluginType<T> pluginType;
+ private final Class<T> clazz;
+
+ private Configuration configuration;
+ private Node node;
+ private LogEvent event;
+
+ private Method factory;
+ private Annotation[][] annotations;
+ private Class<?>[] types;
+ private List<Node> children;
+ private Collection<Node> used;
+
+ /**
+ * Constructs a PluginBuilder for a given PluginType.
+ *
+ * @param pluginType type of plugin to configure
+ */
+ public PluginBuilder(final PluginType<T> pluginType) {
+ this.pluginType = pluginType;
+ this.clazz = pluginType.getPluginClass();
+ }
+
+ /**
+ * Specifies which annotation denotes a plugin factory method. The method
must be static.
+ *
+ * @param annotationType class of annotation marking the plugin factory.
+ * @param <A> type of annotation.
+ * @return {@code this}
+ * @throws NoSuchMethodException
+ */
+ public <A extends Annotation> PluginBuilder<T>
withFactoryMethodAnnotatedBy(final Class<A> annotationType)
+ throws NoSuchMethodException {
+ for (final Method method : clazz.getMethods()) {
+ if (method.isAnnotationPresent(annotationType) &&
Modifier.isStatic(method.getModifiers())) {
+ factory = method;
+ LOGGER.trace("Using factory method {} on class {}",
method.getName(), clazz.getName());
+ return this;
+ }
+ }
+ throw new NoSuchMethodException("No method annotated with " +
annotationType.getName() + "was found in " + clazz.getName());
+ }
+
+ /**
+ * Specifies the Configuration to use for constructing the plugin instance.
+ *
+ * @param configuration the configuration to use.
+ * @return {@code this}
+ */
+ public PluginBuilder<T> withConfiguration(final Configuration
configuration) {
+ this.configuration = configuration;
+ return this;
+ }
+
+ /**
+ * Specifies the Node corresponding to the plugin object that will be
created.
+ *
+ * @param node the plugin configuration node to use.
+ * @return {@code this}
+ */
+ public PluginBuilder<T> withConfigurationNode(final Node node) {
+ this.node = node;
+ this.children = this.node.getChildren();
+ this.used = new HashSet<Node>(this.children.size());
+ return this;
+ }
+
+ /**
+ * Specifies the LogEvent that may be used to provide extra context for
string substitutions.
+ *
+ * @param event the event to use for extra information.
+ * @return {@code this}
+ */
+ public PluginBuilder<T> forLogEvent(final LogEvent event) {
+ this.event = event;
+ return this;
+ }
+
+ /**
+ * Builds the plugin object.
+ *
+ * @return the plugin object or {@code null} if there was a problem
creating it.
+ */
+ public Object build() {
+ init();
+ try {
+ return factory.invoke(null, generateParameters());
+ } catch (final Exception e) {
+ LOGGER.error("Unable to invoke method {} in class {} for element
{}",
+ factory.getName(), clazz.getName(), node.getName(), e);
+ return null;
+ }
+ }
+
+ private void init() {
+ if (factory == null) {
+ throw new IllegalStateException("No factory method was found.");
+ }
+ if (configuration == null) {
+ throw new IllegalStateException("No Configuration object was
set.");
+ }
+ if (node == null) {
+ throw new IllegalStateException("No Node object was set.");
+ }
+ annotations = factory.getParameterAnnotations();
+ types = factory.getParameterTypes();
+ }
+
+ private Object[] generateParameters() {
+ final StringBuilder sb = new StringBuilder();
+ final Object[] args = new Object[annotations.length];
+ for (int i = 0; i < annotations.length; i++) {
+ final String[] aliases = extractPluginAliases(annotations[i]);
+ for (Annotation a : annotations[i]) {
+ if (a instanceof PluginAliases) {
+ continue; // already processed
+ }
+ sb.append(sb.length() == 0 ? "with params(" : ", ");
+ if (a instanceof PluginNode) {
+ args[i] = node;
+ sb.append("Node=").append(node.getName());
+ } else if (a instanceof PluginConfiguration) {
+ args[i] = configuration;
+ sb.append("Configuration");
+ if (configuration.getName() != null) {
+
sb.append('(').append(configuration.getName()).append(')');
+ }
+ } else if (a instanceof PluginValue) {
+ final String name = ((PluginValue) a).value();
+ final String v = node.getValue() != null ? node.getValue()
: getAttrValue("value");
+ final String value =
configuration.getStrSubstitutor().replace(event, v);
+ args[i] = value;
+ sb.append(name).append("=\"").append(value).append('"');
+ } else if (a instanceof PluginAttribute) {
+ final PluginAttribute attribute = (PluginAttribute) a;
+ final String name = attribute.value();
+ final String value =
configuration.getStrSubstitutor().replace(event, getAttrValue(name, aliases));
+ args[i] = value;
+ sb.append(name).append("=\"").append(value).append('"');
+ } else if (a instanceof PluginElement) {
+ final PluginElement element = (PluginElement) a;
+ final String name = element.value();
+ if (types[i].isArray()) {
+ final Class<?> type = types[i].getComponentType();
+ sb.append(name).append("={");
+ final List<Object> values = new ArrayList<Object>();
+ boolean first = true;
+ for (final Node child : children) {
+ final PluginType<?> childType = child.getType();
+ if
(name.equalsIgnoreCase(childType.getElementName()) ||
+
type.isAssignableFrom(childType.getPluginClass())) {
+ if (!first) {
+ sb.append(", ");
+ }
+ first = false;
+ used.add(child);
+ final Object o = child.getObject();
+ if (o == null) {
+ LOGGER.error("Null object returned for {}
in {}", child.getName(), node.getName());
+ continue;
+ }
+ if (o.getClass().isArray()) {
+ sb.append(Arrays.toString((Object[]) o));
+ args[i] = o;
+ break;
+ }
+ sb.append(child.toString());
+ values.add(o);
+ }
+ }
+ sb.append('}');
+ if (args[i] != null) {
+ break;
+ }
+ if (!(values.isEmpty() ||
type.isAssignableFrom(values.get(0).getClass()))) {
+ LOGGER.error(
+ "Attempted to assign List containing class
{} to array of type {} for attribute {}",
+ values.get(0).getClass().getName(), type,
name
+ );
+ break;
+ }
+ args[i] = collectionToArray(values, type);
+ } else {
+ final Node namedNode = findNamedNode(name, types[i],
children);
+ if (namedNode == null) {
+ sb.append("null");
+ } else {
+
sb.append(namedNode.getName()).append('(').append(namedNode.toString()).append(')');
+ used.add(namedNode);
+ args[i] = namedNode.getObject();
+ }
+ }
+ }
+ }
+ }
+ if (sb.length() > 0) {
+ sb.append(')');
+ }
+ checkForRemainingAttributes();
+ verifyNodeChildrenUsed();
+ LOGGER.debug("Calling {} on class {} for element {} {}",
factory.getName(), clazz.getName(), node.getName(), sb.toString());
+ return args;
+ }
+
+ private static String[] extractPluginAliases(final Annotation...
parmTypes) {
+ String[] aliases = null;
+ for (final Annotation a : parmTypes) {
+ if (a instanceof PluginAliases) {
+ aliases = ((PluginAliases) a).value();
+ }
+ }
+ return aliases;
+ }
+
+ private String getAttrValue(final String name, final String... aliases) {
+ final Map<String, String> attrs = node.getAttributes();
+ for (final Map.Entry<String, String> entry : attrs.entrySet()) {
+ final String key = entry.getKey();
+ if (key.equalsIgnoreCase(name)) {
+ final String attr = entry.getValue();
+ attrs.remove(key);
+ return attr;
+ }
+ if (aliases != null) {
+ for (String alias : aliases) {
+ if (key.equalsIgnoreCase(alias)) {
+ final String attr = entry.getValue();
+ attrs.remove(key);
+ return attr;
+ }
+ }
+ }
+ }
+ return null;
+ }
+
+ private static Object[] collectionToArray(final Collection<?> collection,
final Class<?> type) {
+ final Object[] array = (Object[]) Array.newInstance(type,
collection.size());
+ int i = 0;
+ for (final Object obj : collection) {
+ array[i] = obj;
+ ++i;
+ }
+ return array;
+ }
+
+ private static Node findNamedNode(final String name, final Class<?> type,
final Iterable<Node> nodes) {
+ for (final Node child : nodes) {
+ final PluginType<?> childType = child.getType();
+ if (name.equalsIgnoreCase(childType.getElementName()) ||
+ type.isAssignableFrom(childType.getPluginClass())) {
+ return child;
+ }
+ }
+ return null;
+ }
+
+ private void checkForRemainingAttributes() {
+ final Map<String, String> attrs = node.getAttributes();
+ if (!attrs.isEmpty()) {
+ final StringBuilder eb = new StringBuilder();
+ for (final String key : attrs.keySet()) {
+ if (eb.length() == 0) {
+ eb.append(node.getName());
+ eb.append(" contains ");
+ if (attrs.size() == 1) {
+ eb.append("an invalid element or attribute ");
+ } else {
+ eb.append("invalid attributes ");
+ }
+ } else {
+ eb.append(", ");
+ }
+ eb.append('"');
+ eb.append(key);
+ eb.append('"');
+
+ }
+ LOGGER.error(eb.toString());
+ }
+ }
+
+ private void verifyNodeChildrenUsed() {
+ if (!(pluginType.isDeferChildren() || used.size() == children.size()))
{
+ children.removeAll(used);
+ for (final Node child : children) {
+ final String nodeType = node.getType().getElementName();
+ final String start = nodeType.equals(node.getName()) ?
node.getName() : nodeType + ' ' + node.getName();
+ LOGGER.error("{} has no parameter that matches element {}",
start, child.getName());
+ }
+ }
+ }
+}
Propchange:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilder.java
------------------------------------------------------------------------------
svn:eol-style = native