Author: mattsicker
Date: Mon May 26 22:07:46 2014
New Revision: 1597653
URL: http://svn.apache.org/r1597653
Log:
Update PluginBuilder to work with builder classes as well as factory
methods.
- Removed some unnecessary class fields and prefer passing through
method parameters.
- Removed the strange withFactoryMethodAnnotatedBy method.
- Renamed init() to verify() to better reflect updated usage.
- Try to use builder first if one can be found. Fall back to
factory method otherwise (as usual).
- Migrated logic from withFactoryMethodAnnotatedBy to
findFactoryMethod with hard-coded reference to PluginFactory.
- Added createBuilder and injectFields methods for builder-style
plugin creation. (The Builder<T> interface turned out to be handy
here).
- Renamed helper local variable to visitor (refactoring didn't
catch that when I renamed PluginHelper to PluginVisitor before
committing).
Modified:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfiguration.java
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.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=1597653&r1=1597652&r2=1597653&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
Mon May 26 22:07:46 2014
@@ -38,7 +38,6 @@ 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.PluginFactory;
import org.apache.logging.log4j.core.config.plugins.util.PluginBuilder;
import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
import org.apache.logging.log4j.core.config.plugins.util.PluginType;
@@ -685,7 +684,6 @@ public abstract class AbstractConfigurat
*/
private <T> Object createPluginObject(final PluginType<T> type, final Node
node, final LogEvent event)
{
- // TODO: add support for type conversion
final Class<T> clazz = type.getPluginClass();
if (Map.class.isAssignableFrom(clazz)) {
@@ -704,17 +702,11 @@ public abstract class AbstractConfigurat
}
}
- try {
- 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 new PluginBuilder<T>(type)
+ .withConfiguration(this)
+ .withConfigurationNode(node)
+ .forLogEvent(event)
+ .build();
}
private static <T> Object createPluginMap(final Node node, final Class<T>
clazz) throws InstantiationException, IllegalAccessException {
Modified:
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
URL:
http://svn.apache.org/viewvc/logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java?rev=1597653&r1=1597652&r2=1597653&view=diff
==============================================================================
---
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
(original)
+++
logging/log4j/log4j2/trunk/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginBuilder.java
Mon May 26 22:07:46 2014
@@ -18,16 +18,21 @@
package org.apache.logging.log4j.core.config.plugins.util;
import java.lang.annotation.Annotation;
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.Map;
+import org.apache.logging.log4j.Level;
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.core.config.plugins.PluginAliases;
+import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
+import org.apache.logging.log4j.core.config.plugins.PluginFactory;
import org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor;
import org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitors;
import org.apache.logging.log4j.core.util.Assert;
@@ -35,14 +40,13 @@ import org.apache.logging.log4j.core.uti
import org.apache.logging.log4j.status.StatusLogger;
/**
- * Builder class to instantiate and configure a Plugin object using a
PluginFactory method.
+ * Builder class to instantiate and configure a Plugin object using a
PluginFactory method or PluginBuilderFactory
+ * builder class.
*
* @param <T> type of Plugin class.
*/
public class PluginBuilder<T> implements Builder<T> {
- // TODO: field injection for builder factories annotated with
@PluginBuilderFactory
-
private static final Logger LOGGER = StatusLogger.getLogger();
private final PluginType<T> pluginType;
@@ -52,10 +56,6 @@ public class PluginBuilder<T> implements
private Node node;
private LogEvent event;
- private Method factory;
- private Annotation[][] annotations;
- private Class<?>[] types;
-
/**
* Constructs a PluginBuilder for a given PluginType.
*
@@ -67,26 +67,6 @@ public class PluginBuilder<T> implements
}
/**
- * 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.
@@ -126,27 +106,91 @@ public class PluginBuilder<T> implements
*/
@Override
public T build() {
- init();
+ verify();
+ // first try to use a builder class if one is available
+ try {
+ final Builder<T> builder = createBuilder(this.clazz);
+ if (builder != null) {
+ injectFields(builder);
+ return builder.build();
+ }
+ } catch (final Exception e) {
+ LOGGER.catching(Level.DEBUG, e);
+ LOGGER.error("Unable to inject fields into builder class for
plugin type {}, element {}.", this.clazz,
+ node.getName());
+ }
+ // or fall back to factory method if no builder class is available
try {
+ final Method factory = findFactoryMethod(this.clazz);
+ final Object[] params =
generateParameters(factory.getParameterTypes(),
factory.getParameterAnnotations());
@SuppressWarnings("unchecked")
- final T plugin = (T) factory.invoke(null, generateParameters());
+ final T plugin = (T) factory.invoke(null, params);
return plugin;
} catch (final Exception e) {
- LOGGER.error("Unable to invoke method {} in class {} for element
{}",
- factory.getName(), clazz.getName(), node.getName(), e);
+ LOGGER.catching(Level.DEBUG, e);
+ LOGGER.error("Unable to invoke factory method in class {} for
element {}.", this.clazz, this.node.getName());
return null;
}
}
- private void init() {
- Assert.requireNonNull(factory, "No factory method was found.");
- Assert.requireNonNull(configuration, "No Configuration object was
set.");
- Assert.requireNonNull(node, "No Node object was set.");
- annotations = factory.getParameterAnnotations();
- types = factory.getParameterTypes();
+ private void verify() {
+ Assert.requireNonNull(this.configuration, "No Configuration object was
set.");
+ Assert.requireNonNull(this.node, "No Node object was set.");
+ }
+
+ private static <T> Builder<T> createBuilder(final Class<T> clazz)
+ throws InvocationTargetException, IllegalAccessException {
+ for (final Method method : clazz.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(PluginBuilderFactory.class) &&
+ Modifier.isStatic(method.getModifiers())) {
+ @SuppressWarnings("unchecked")
+ final Builder<T> builder = (Builder<T>) method.invoke(null);
+ LOGGER.debug("Found builder factory method {}.{}.", clazz,
method);
+ return builder;
+ }
+ }
+ LOGGER.debug("No compatible method annotated with {} found in class
{}.", PluginBuilderFactory.class, clazz);
+ return null;
+ }
+
+ private void injectFields(final Builder<T> builder) throws
IllegalAccessException {
+ final Field[] fields = builder.getClass().getDeclaredFields();
+ for (final Field field : fields) {
+ field.setAccessible(true);
+ final Annotation[] annotations = field.getDeclaredAnnotations();
+ final String[] aliases = extractPluginAliases(annotations);
+ for (final Annotation a : annotations) {
+ if (a instanceof PluginAliases) {
+ continue; // already processed
+ }
+ final PluginVisitor<? extends Annotation> visitor =
PluginVisitors.findVisitor(a.annotationType());
+ if (visitor != null) {
+ final Object value = visitor.setAliases(aliases)
+ .setAnnotation(a)
+ .setConversionType(field.getType())
+ .setStrSubstitutor(configuration.getStrSubstitutor())
+ .visit(configuration, node, event);
+ field.set(builder, value);
+ }
+ }
+ }
+ checkForRemainingAttributes();
+ verifyNodeChildrenUsed();
+ }
+
+ private static <T> Method findFactoryMethod(final Class<T> clazz) {
+ for (final Method method : clazz.getDeclaredMethods()) {
+ if (method.isAnnotationPresent(PluginFactory.class) &&
+ Modifier.isStatic(method.getModifiers())) {
+ LOGGER.debug("Found factory method {}.{}.", clazz, method);
+ return method;
+ }
+ }
+ LOGGER.debug("No compatible method annotated with {} found in class
{}.", PluginFactory.class, clazz);
+ return null;
}
- private Object[] generateParameters() {
+ private Object[] generateParameters(final Class<?>[] types, final
Annotation[][] annotations) {
final Object[] args = new Object[annotations.length];
for (int i = 0; i < annotations.length; i++) {
final String[] aliases = extractPluginAliases(annotations[i]);
@@ -155,9 +199,9 @@ public class PluginBuilder<T> implements
if (a instanceof PluginAliases) {
continue; // already processed
}
- final PluginVisitor<? extends Annotation> helper =
PluginVisitors.findVisitor(a.annotationType());
- if (helper != null) {
- args[i] = helper.setAliases(aliases)
+ final PluginVisitor<? extends Annotation> visitor =
PluginVisitors.findVisitor(a.annotationType());
+ if (visitor != null) {
+ args[i] = visitor.setAliases(aliases)
.setAnnotation(a)
.setConversionType(types[i])
.setStrSubstitutor(configuration.getStrSubstitutor())