You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@logging.apache.org by Gary Gregory <ga...@gmail.com> on 2019/06/03 10:56:21 UTC

Re: [logging-log4j2] 01/02: LOG4J2-2621 - Initial commit

This is weird, note the "}":

.../org/apache/logging/log4j}/util/Assert.java     |   0

Gary

On Sun, Jun 2, 2019 at 6:38 PM <rg...@apache.org> wrote:

> This is an automated email from the ASF dual-hosted git repository.
>
> rgoers pushed a commit to branch LOG4J2-2621
> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>
> commit b69c2d9e4b79ee7830a69463c6f89de1c50fe84d
> Author: Ralph Goers <rg...@apache.org>
> AuthorDate: Sun Jun 2 13:18:36 2019 -0700
>
>     LOG4J2-2621 - Initial commit
> ---
>  .../org/apache/logging/log4j}/util/Assert.java     |   0
>  .../logging/log4j/util/InternalException.java      |  56 ++++
>  .../org/apache/logging/log4j}/util/NameUtil.java   |   0
>  .../apache/logging/log4j}/util/ReflectionUtil.java |   6 +-
>  .../log4j/junit/AbstractExternalFileCleaner.java   |   0
>  .../org/apache/logging/log4j/junit/CleanFiles.java |   0
>  .../apache/logging/log4j/junit/CleanFolders.java   |   0
>  .../log4j/junit/URLStreamHandlerFactoryRule.java   |   0
>  .../org/apache/logging/log4j}/util/AssertTest.java |   2 +-
>  .../config/plugins/convert/Base64Converter.java    |  79 -----
>  ...TypeConverters.java => CoreTypeConverters.java} |   7 +-
>  .../ValidatingPluginWithGenericBuilderTest.java    |  10 +-
>  log4j-plugins-java9/pom.xml                        | 157 +++++++++
>  log4j-plugins-java9/src/assembly/java9.xml         |  40 +++
>  .../src/main/java/module-info.java                 |  15 +-
>  .../org/apache/logging/log4j/plugins/Dummy.java    |   9 +-
>  .../logging/log4j/plugins/convert/Dummy.java       |   9 +-
>  .../log4j/plugins/processor/PluginService.java     |   9 +-
>  .../apache/logging/log4j/plugins/util/Dummy.java   |   9 +-
>  .../logging/log4j/plugins/validation/Dummy.java    |   9 +-
>  .../logging/log4j/plugins/visitors/Dummy.java      |   9 +-
>  log4j-plugins/pom.xml                              | 360
> +++++++++++++++++++++
>  .../org/apache/logging/log4j/plugins}/Node.java    |   6 +-
>  .../org/apache/logging/log4j}/plugins/Plugin.java  |   6 +-
>  .../logging/log4j}/plugins/PluginAliases.java      |   4 +-
>  .../logging/log4j}/plugins/PluginAttribute.java    |   8 +-
>  .../log4j}/plugins/PluginBuilderAttribute.java     |   8 +-
>  .../log4j}/plugins/PluginBuilderFactory.java       |   2 +-
>  .../logging/log4j}/plugins/PluginElement.java      |   6 +-
>  .../logging/log4j}/plugins/PluginFactory.java      |   2 +-
>  .../apache/logging/log4j}/plugins/PluginNode.java  |   6 +-
>  .../apache/logging/log4j}/plugins/PluginValue.java |   6 +-
>  .../log4j}/plugins/PluginVisitorStrategy.java      |   8 +-
>  .../log4j}/plugins/convert/EnumConverter.java      |   2 +-
>  .../log4j}/plugins/convert/HexConverter.java       |   2 +-
>  .../log4j}/plugins/convert/TypeConverter.java      |   2 +-
>  .../plugins/convert/TypeConverterRegistry.java     |  23 +-
>  .../log4j}/plugins/convert/TypeConverters.java     |  47 +--
>  .../log4j/plugins/convert}/package-info.java       |   7 +-
>  .../logging/log4j/plugins/osgi/Activator.java      | 103 ++++++
>  .../logging/log4j/plugins/osgi}/package-info.java  |   6 +-
>  .../logging/log4j/plugins}/package-info.java       |   6 +-
>  .../log4j}/plugins/processor/PluginCache.java      |  30 +-
>  .../log4j}/plugins/processor/PluginEntry.java      |  14 +-
>  .../log4j}/plugins/processor/PluginProcessor.java  | 157 +++++++--
>  .../log4j/plugins/processor/PluginService.java     |  56 ++++
>  .../log4j}/plugins/processor/package-info.java     |   2 +-
>  .../logging/log4j/plugins}/util/Builder.java       |   4 +-
>  .../logging/log4j}/plugins/util/PluginManager.java |   8 +-
>  .../log4j}/plugins/util/PluginRegistry.java        |  81 +++--
>  .../logging/log4j}/plugins/util/PluginType.java    |   6 +-
>  .../logging/log4j}/plugins/util/ResolverUtil.java  |  29 +-
>  .../logging/log4j/plugins/util/TypeUtil.java       | 217 +++++++++++++
>  .../logging/log4j/plugins/util}/package-info.java  |   2 +-
>  .../log4j}/plugins/validation/Constraint.java      |   9 +-
>  .../plugins/validation/ConstraintValidator.java    |   2 +-
>  .../plugins/validation/ConstraintValidators.java   |   8 +-
>  .../plugins/validation/constraints/Required.java   |  12 +-
>  .../plugins/validation/constraints/ValidHost.java  |   6 +-
>  .../plugins/validation/constraints/ValidPort.java  |  12 +-
>  .../validation/constraints/package-info.java       |   2 +-
>  .../log4j}/plugins/validation/package-info.java    |   2 +-
>  .../validation/validators/RequiredValidator.java   |  14 +-
>  .../validation/validators/ValidHostValidator.java  |   6 +-
>  .../validation/validators/ValidPortValidator.java  |   8 +-
>  .../validation/validators/package-info.java        |   2 +-
>  .../plugins/visitors/AbstractPluginVisitor.java    |  34 +-
>  .../plugins/visitors/PluginAttributeVisitor.java   |  27 +-
>  .../visitors/PluginBuilderAttributeVisitor.java    |  23 +-
>  .../plugins/visitors/PluginElementVisitor.java     |  17 +-
>  .../log4j}/plugins/visitors/PluginNodeVisitor.java |  14 +-
>  .../plugins/visitors/PluginValueVisitor.java       |  18 +-
>  .../log4j}/plugins/visitors/PluginVisitor.java     |  36 +--
>  .../log4j}/plugins/visitors/PluginVisitors.java    |  12 +-
>  .../log4j/plugins/visitors}/package-info.java      |   9 +-
>  .../services/javax.annotation.processing.Processor |   2 +-
>  .../plugins/convert/TypeConverterRegistryTest.java |   4 +-
>  .../log4j}/plugins/processor/FakePlugin.java       |   6 +-
>  .../plugins/processor/PluginProcessorTest.java     |  26 +-
>  .../util/ResolverUtilCustomProtocolTest.java       |  30 +-
>  .../log4j}/plugins/util/ResolverUtilTest.java      |  76 +++--
>  .../AbstractPluginWithGenericBuilder.java          |   6 +-
>  .../log4j}/plugins/validation/HostAndPort.java     |  14 +-
>  .../PluginWithGenericSubclassFoo1Builder.java      |  12 +-
>  .../plugins/validation/ValidatingPlugin.java       |  16 +-
>  .../ValidatingPluginWithGenericBuilder.java        |  17 +-
>  .../ValidatingPluginWithTypedBuilder.java          |  16 +-
>  .../resources/customplugin/FixedString.java.source |  37 ++-
>  .../log4j+config+with+plus+characters.xml          |  31 ++
>  .../log4j+config+with+plus+characters.xml          |  31 ++
>  90 files changed, 1655 insertions(+), 594 deletions(-)
>
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Assert.java
> b/log4j-api/src/main/java/org/apache/logging/log4j/util/Assert.java
> similarity index 100%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/util/Assert.java
> rename to log4j-api/src/main/java/org/apache/logging/log4j/util/Assert.java
> diff --git
> a/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
> b/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
> new file mode 100644
> index 0000000..8c433db
> --- /dev/null
> +++
> b/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
> @@ -0,0 +1,56 @@
> +/*
> + * 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;
> +
> +/**
> + * Exception thrown when an error occurs while logging.  In most cases
> exceptions will be handled
> + * within Log4j but certain Appenders may be configured to allow
> exceptions to propagate to the
> + * application. This is a RuntimeException so that the exception may be
> thrown in those cases without
> + * requiring all Logger methods be contained with try/catch blocks.
> + */
> +public class LoggingException extends RuntimeException {
> +
> +    private static final long serialVersionUID = 6366395965071580537L;
> +
> +    /**
> +     * Construct an exception with a message.
> +     *
> +     * @param message The reason for the exception
> +     */
> +    public LoggingException(final String message) {
> +        super(message);
> +    }
> +
> +    /**
> +     * Construct an exception with a message and underlying cause.
> +     *
> +     * @param message The reason for the exception
> +     * @param cause The underlying cause of the exception
> +     */
> +    public LoggingException(final String message, final Throwable cause) {
> +        super(message, cause);
> +    }
> +
> +    /**
> +     * Construct an exception with an underlying cause.
> +     *
> +     * @param cause The underlying cause of the exception
> +     */
> +    public LoggingException(final Throwable cause) {
> +        super(cause);
> +    }
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NameUtil.java
> b/log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
> similarity index 100%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/util/NameUtil.java
> rename to
> log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
> b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
> similarity index 98%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
> rename to
> log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
> index ffee439..f00e64a 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
> +++
> b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
> @@ -193,8 +193,10 @@ public final class ReflectionUtil {
>          } catch (final IllegalAccessException e) {
>              throw new IllegalStateException(e);
>          } catch (final InvocationTargetException e) {
> -            Throwables.rethrow(e.getCause());
> -            throw new InternalError("Unreachable");
> +            if (e.getCause() instanceof RuntimeException) {
> +                throw (RuntimeException) e.getCause();
> +            }
> +            throw new
>          }
>      }
>  }
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
> similarity index 100%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
> rename to
> log4j-api/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
> similarity index 100%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
> rename to
> log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
> similarity index 100%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
> rename to
> log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
> similarity index 100%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
> rename to
> log4j-api/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
> b/log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
> similarity index 99%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
> rename to
> log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
> index 242c41e..7e46036 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
> +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
> @@ -65,4 +65,4 @@ public class AssertTest {
>          assertEquals(isEmpty, Assert.isEmpty(value));
>      }
>
> -}
> \ No newline at end of file
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
> deleted file mode 100644
> index f4e421f..0000000
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
> +++ /dev/null
> @@ -1,79 +0,0 @@
> -/*
> - * 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.convert;
> -
> -import java.lang.reflect.InvocationTargetException;
> -import java.lang.reflect.Method;
> -
> -import org.apache.logging.log4j.Logger;
> -import org.apache.logging.log4j.status.StatusLogger;
> -import org.apache.logging.log4j.util.LoaderUtil;
> -
> -/**
> - * @Since 2.9
> - */
> -public class Base64Converter {
> -
> -    private static final Logger LOGGER = StatusLogger.getLogger();
> -    private static Method method = null;
> -    private static Object decoder = null;
> -
> -    static {
> -        try {
> -            // Base64 is available in Java 8 and up.
> -            Class<?> clazz = LoaderUtil.loadClass("java.util.Base64");
> -            final Method getDecoder = clazz.getMethod("getDecoder",
> (Class[]) null);
> -            decoder = getDecoder.invoke(null, (Object[]) null);
> -            clazz = decoder.getClass();
> -            method = clazz.getMethod("decode", String.class);
> -        } catch (final ClassNotFoundException ex) {
> -
> -        } catch (final NoSuchMethodException ex) {
> -
> -        } catch (final IllegalAccessException ex) {
> -
> -        } catch (final InvocationTargetException ex) {
> -
> -        }
> -        if (method == null) {
> -            try {
> -                // DatatypeConverter is not in the default module in Java
> 9.
> -                final Class<?> clazz =
> LoaderUtil.loadClass("javax.xml.bind.DatatypeConverter");
> -                method = clazz.getMethod("parseBase64Binary",
> String.class);
> -            } catch (final ClassNotFoundException ex) {
> -                LOGGER.error("No Base64 Converter is available");
> -            } catch (final NoSuchMethodException ex) {
> -
> -            }
> -        }
> -    }
> -
> -    public static byte[] parseBase64Binary(final String encoded) {
> -        if (method == null) {
> -            LOGGER.error("No base64 converter");
> -        } else {
> -            try {
> -                return (byte[]) method.invoke(decoder, encoded);
> -            } catch (final IllegalAccessException ex) {
> -                LOGGER.error("Error decoding string - " +
> ex.getMessage());
> -            } catch (final InvocationTargetException ex) {
> -                LOGGER.error("Error decoding string - " +
> ex.getMessage());
> -            }
> -        }
> -        return new byte[0];
> -    }
> -}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
> similarity index 98%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
> copy to
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
> index dc833f0..00e6da7 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
> +++
> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
> @@ -30,13 +30,14 @@ import java.nio.file.Path;
>  import java.nio.file.Paths;
>  import java.security.Provider;
>  import java.security.Security;
> +import java.util.Base64;
>  import java.util.UUID;
>  import java.util.regex.Pattern;
>
>  import org.apache.logging.log4j.Level;
>  import org.apache.logging.log4j.Logger;
>  import org.apache.logging.log4j.core.appender.rolling.action.Duration;
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> +import org.apache.logging.log4j.plugins.Plugin;
>  import org.apache.logging.log4j.core.util.CronExpression;
>  import org.apache.logging.log4j.status.StatusLogger;
>  import org.apache.logging.log4j.util.LoaderUtil;
> @@ -56,6 +57,8 @@ public final class TypeConverters {
>       */
>      public static final String CATEGORY = "TypeConverter";
>
> +    private static final Base64.Decoder decoder = Base64.getDecoder();
> +
>      /**
>       * Parses a {@link String} into a {@link BigDecimal}.
>       */
> @@ -112,7 +115,7 @@ public final class TypeConverters {
>                  bytes = new byte[0];
>              } else if (value.startsWith(PREFIX_BASE64)) {
>                  final String lexicalXSDBase64Binary =
> value.substring(PREFIX_BASE64.length());
> -                bytes =
> Base64Converter.parseBase64Binary(lexicalXSDBase64Binary);
> +                bytes = decoder.decode(lexicalXSDBase64Binary);
>              } else if (value.startsWith(PREFIX_0x)) {
>                  final String lexicalXSDHexBinary =
> value.substring(PREFIX_0x.length());
>                  bytes = HexConverter.parseHexBinary(lexicalXSDHexBinary);
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
> index 8ee5abb..27ac5fe 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
> +++
> b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
> @@ -20,12 +20,12 @@ import static org.junit.Assert.assertEquals;
>  import static org.junit.Assert.assertNotNull;
>  import static org.junit.Assert.assertNull;
>
> -import org.apache.logging.log4j.core.config.Node;
> +import org.apache.logging.log4j.plugins.Node;
>  import org.apache.logging.log4j.core.config.NullConfiguration;
> -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;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.ValidatingPluginWithGenericBuilder;
> +import org.apache.logging.log4j.plugins.util.PluginBuilder;
> +import org.apache.logging.log4j.plugins.util.PluginManager;
> +import org.apache.logging.log4j.plugins.util.PluginType;
> +import
> org.apache.logging.log4j.plugins.validation.ValidatingPluginWithGenericBuilder;
>  import org.junit.Before;
>  import org.junit.Test;
>
> diff --git a/log4j-plugins-java9/pom.xml b/log4j-plugins-java9/pom.xml
> new file mode 100644
> index 0000000..49f81c6
> --- /dev/null
> +++ b/log4j-plugins-java9/pom.xml
> @@ -0,0 +1,157 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!--
> +  ~ 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.
> +  -->
> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
> http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
> http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
> ">
> +  <modelVersion>4.0.0</modelVersion>
> +  <parent>
> +    <groupId>org.apache.logging.log4j</groupId>
> +    <artifactId>log4j</artifactId>
> +    <version>3.0.0-SNAPSHOT</version>
> +    <relativePath>../</relativePath>
> +  </parent>
> +  <artifactId>log4j-plugins-java9</artifactId>
> +  <packaging>pom</packaging>
> +  <name>Apache Log4j Plugins Module support</name>
> +  <description>Apache Log4j Plugin Moduels Support</description>
> +  <properties>
> +    <log4jParentDir>${basedir}/..</log4jParentDir>
> +    <docLabel>Log4j Plugins Documentation</docLabel>
> +    <projectDir>/plugins</projectDir>
> +  </properties>
> +  <dependencies>
> +    <dependency>
> +      <groupId>org.apache.logging.log4j</groupId>
> +      <artifactId>log4j-api</artifactId>
> +    </dependency>
> +    <dependency>
> +      <groupId>junit</groupId>
> +      <artifactId>junit</artifactId>
> +      <scope>test</scope>
> +    </dependency>
> +    <dependency>
> +      <groupId>org.apache.maven</groupId>
> +      <artifactId>maven-core</artifactId>
> +      <scope>test</scope>
> +    </dependency>
> +  </dependencies>
> +  <build>
> +    <plugins>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-toolchains-plugin</artifactId>
> +        <version>1.1</version>
> +        <executions>
> +          <execution>
> +            <goals>
> +              <goal>toolchain</goal>
> +            </goals>
> +          </execution>
> +        </executions>
> +        <configuration>
> +          <toolchains>
> +            <jdk>
> +              <version>[9, )</version>
> +            </jdk>
> +          </toolchains>
> +        </configuration>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-compiler-plugin</artifactId>
> +        <executions>
> +          <execution>
> +            <id>default-compile</id>
> +            <phase>compile</phase>
> +            <goals>
> +              <goal>compile</goal>
> +            </goals>
> +          </execution>
> +          <execution>
> +            <id>default-test-compile</id>
> +            <phase>test-compile</phase>
> +            <goals>
> +              <goal>testCompile</goal>
> +            </goals>
> +          </execution>
> +        </executions>
> +        <configuration>
> +          <source>9</source>
> +          <target>9</target>
> +          <release>9</release>
> +          <proc>none</proc>
> +          <!-- disable errorprone -->
> +          <compilerId>javac</compilerId>
> +        </configuration>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-surefire-plugin</artifactId>
> +        <!-- Do not upgrade until
> https://issues.apache.org/jira/browse/SUREFIRE-720 is fixed -->
> +        <version>2.13</version>
> +        <executions>
> +          <execution>
> +            <id>test</id>
> +            <phase>test</phase>
> +            <goals>
> +              <goal>test</goal>
> +            </goals>
> +          </execution>
> +        </executions>
> +        <configuration>
> +          <systemPropertyVariables>
> +            <java.awt.headless>true</java.awt.headless>
> +          </systemPropertyVariables>
> +          <includes>
> +            <include>**/Test*.java</include>
> +            <include>**/*Test.java</include>
> +          </includes>
> +          <excludes>
> +            <exclude>**/*FuncTest.java</exclude>
> +          </excludes>
> +        </configuration>
> +      </plugin>
> +      <plugin>
> +        <artifactId>maven-assembly-plugin</artifactId>
> +        <executions>
> +          <execution>
> +            <id>zip</id>
> +            <phase>package</phase>
> +            <goals>
> +              <goal>single</goal>
> +            </goals>
> +            <configuration>
> +
> <finalName>log4j-plugins-java9-${project.version}</finalName>
> +              <appendAssemblyId>false</appendAssemblyId>
> +              <descriptors>
> +                <descriptor>src/assembly/java9.xml</descriptor>
> +              </descriptors>
> +            </configuration>
> +          </execution>
> +        </executions>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-deploy-plugin</artifactId>
> +        <version>${deploy.plugin.version}</version>
> +        <configuration>
> +          <skip>true</skip>
> +        </configuration>
> +      </plugin>
> +    </plugins>
> +  </build>
> +</project>
> +
> diff --git a/log4j-plugins-java9/src/assembly/java9.xml
> b/log4j-plugins-java9/src/assembly/java9.xml
> new file mode 100644
> index 0000000..34649d4
> --- /dev/null
> +++ b/log4j-plugins-java9/src/assembly/java9.xml
> @@ -0,0 +1,40 @@
> +<?xml version='1.0' encoding='UTF-8'?>
> +<!--
> +  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.
> +-->
> +
> +<assembly>
> +  <id>src</id>
> +  <formats>
> +    <format>zip</format>
> +  </formats>
> +  <baseDirectory>/</baseDirectory>
> +  <fileSets>
> +    <fileSet>
> +      <directory>${project.build.outputDirectory}</directory>
> +      <outputDirectory>/classes/META-INF/versions/9</outputDirectory>
> +      <includes>
> +        <include>module-info.class</include>
> +      </includes>
> +      <excludes>
> +        <exclude>**/Dummy.class</exclude>
> +        <exclude>**/PluginService.class</exclude>
> +      </excludes>
> +    </fileSet>
> +  </fileSets>
> +</assembly>
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins-java9/src/main/java/module-info.java
> similarity index 65%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to log4j-plugins-java9/src/main/java/module-info.java
> index f22ba49..9802622 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++ b/log4j-plugins-java9/src/main/java/module-info.java
> @@ -14,10 +14,13 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> +module org.apache.logging.log4j.plugins {
> +    exports org.apache.logging.log4j.plugins;
> +    exports org.apache.logging.log4j.plugins.convert;
> +    exports org.apache.logging.log4j.plugins.processor;
> +    exports org.apache.logging.log4j.plugins.util;
> +    exports org.apache.logging.log4j.plugins.validation;
> +    exports org.apache.logging.log4j.plugins.visitors;
>
> -/**
> - * Validation annotations.
> - *
> - * @since 2.1
> - */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +    uses org.apache.logging.log4j.plugins.processor.PluginService;
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
> similarity index 80%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
> index f22ba49..14a90ed 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
> @@ -14,10 +14,11 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> +package org.apache.logging.log4j.plugins;
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * This is a dummy class and is only here to allow module-info.java to
> compile. It will not
> + * be copied into the log4j-api module.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +public class Dummy {
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
> similarity index 79%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
> index f22ba49..10923e8 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
> @@ -14,10 +14,11 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> +package org.apache.logging.log4j.plugins.convert;
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * This is a dummy class and is only here to allow module-info.java to
> compile. It will not
> + * be copied into the log4j-api module.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +public class Dummy {
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
> similarity index 79%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
> index f22ba49..b93ef59 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
> @@ -14,10 +14,11 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> +package org.apache.logging.log4j.plugins.processor;
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * This is a dummy class and is only here to allow module-info.java to
> compile. It will not
> + * be copied into the log4j-api module.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +public class PluginService {
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
> similarity index 80%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
> index f22ba49..5940b03 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
> @@ -14,10 +14,11 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> +package org.apache.logging.log4j.plugins.util;
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * This is a dummy class and is only here to allow module-info.java to
> compile. It will not
> + * be copied into the log4j-api module.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +public class Dummy {
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
> similarity index 79%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
> index f22ba49..14882b5 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
> @@ -14,10 +14,11 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> +package org.apache.logging.log4j.plugins.validation;
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * This is a dummy class and is only here to allow module-info.java to
> compile. It will not
> + * be copied into the log4j-api module.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +public class Dummy {
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
> similarity index 79%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
> index f22ba49..5596338 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
> @@ -14,10 +14,11 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> +package org.apache.logging.log4j.plugins.visitors;
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * This is a dummy class and is only here to allow module-info.java to
> compile. It will not
> + * be copied into the log4j-api module.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +public class Dummy {
> +}
> diff --git a/log4j-plugins/pom.xml b/log4j-plugins/pom.xml
> new file mode 100644
> index 0000000..3551d51
> --- /dev/null
> +++ b/log4j-plugins/pom.xml
> @@ -0,0 +1,360 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!--
> +  ~ 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.
> +  -->
> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
> http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
> http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
> ">
> +  <modelVersion>4.0.0</modelVersion>
> +  <parent>
> +    <groupId>org.apache.logging.log4j</groupId>
> +    <artifactId>log4j</artifactId>
> +    <version>3.0.0-SNAPSHOT</version>
> +    <relativePath>../</relativePath>
> +  </parent>
> +  <artifactId>log4j-plugins</artifactId>
> +  <packaging>jar</packaging>
> +  <name>Apache Log4j Plugins</name>
> +  <description>Log4j Plugin Support</description>
> +  <properties>
> +    <log4jParentDir>${basedir}/..</log4jParentDir>
> +    <docLabel>Plugin Documentation</docLabel>
> +    <projectDir>/plugins</projectDir>
> +  </properties>
> +  <dependencies>
> +    <dependency>
> +      <groupId>org.apache.logging.log4j</groupId>
> +      <artifactId>log4j-api</artifactId>
> +    </dependency>
> +    <!-- Classes and resources to be shaded into the core jar -->
> +    <dependency>
> +      <groupId>org.apache.logging.log4j</groupId>
> +      <artifactId>log4j-plugins-java9</artifactId>
> +      <scope>provided</scope>
> +      <type>zip</type>
> +    </dependency>
> +    <!-- Used for OSGi bundle support -->
> +    <dependency>
> +      <groupId>org.osgi</groupId>
> +      <artifactId>org.osgi.core</artifactId>
> +      <scope>provided</scope>
> +    </dependency>
> +
> +    <!-- TEST DEPENDENCIES -->
> +
> +    <!-- Pull in useful test classes from API -->
> +    <dependency>
> +      <groupId>org.apache.logging.log4j</groupId>
> +      <artifactId>log4j-api</artifactId>
> +      <type>test-jar</type>
> +      <scope>test</scope>
> +    </dependency>
> +    <dependency>
> +      <groupId>junit</groupId>
> +      <artifactId>junit</artifactId>
> +      <scope>test</scope>
> +    </dependency>
> +    <dependency>
> +      <groupId>org.hamcrest</groupId>
> +      <artifactId>hamcrest-all</artifactId>
> +      <scope>test</scope>
> +    </dependency>
> +  </dependencies>
> +  <build>
> +    <plugins>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-dependency-plugin</artifactId>
> +        <version>3.0.2</version>
> +        <executions>
> +          <execution>
> +            <id>unpack-classes</id>
> +            <phase>prepare-package</phase>
> +            <goals>
> +              <goal>unpack</goal>
> +            </goals>
> +            <configuration>
> +              <artifactItems>
> +                <artifactItem>
> +                  <groupId>org.apache.logging.log4j</groupId>
> +                  <artifactId>log4j-plugins-java9</artifactId>
> +                  <version>${project.version}</version>
> +                  <type>zip</type>
> +                  <overWrite>false</overWrite>
> +                </artifactItem>
> +              </artifactItems>
> +              <includes>**/*.class</includes>
> +              <excludes>**/*.java</excludes>
> +
> <outputDirectory>${project.build.directory}</outputDirectory>
> +              <overWriteReleases>false</overWriteReleases>
> +              <overWriteSnapshots>true</overWriteSnapshots>
> +            </configuration>
> +          </execution>
> +        </executions>
> +      </plugin>
> +      <plugin>
> +        <artifactId>maven-compiler-plugin</artifactId>
> +        <executions>
> +          <execution>
> +            <!-- disable annotation processing for first pass -->
> +            <id>generate-plugins</id>
> +            <phase>process-classes</phase>
> +            <goals>
> +              <goal>compile</goal>
> +            </goals>
> +            <configuration>
> +              <excludes>
> +                <exclude>module-info.java</exclude>
> +              </excludes>
> +            </configuration>
> +          </execution>
> +          <execution>
> +            <!-- disable annotation processing for first pass -->
> +            <id>generate-test-plugins</id>
> +            <phase>generate-test-sources</phase>
> +            <goals>
> +              <goal>compile</goal>
> +            </goals>
> +            <configuration>
> +              <excludes>
> +                <exclude>module-info.java</exclude>
> +              </excludes>
> +              <proc>only</proc>
> +            </configuration>
> +          </execution>
> +          <execution>
> +            <!-- disable annotation processing for first pass -->
> +            <id>default-compile</id>
> +            <configuration>
> +              <excludes>
> +                <exclude>module-info.java</exclude>
> +              </excludes>
> +              <proc>none</proc>
> +            </configuration>
> +          </execution>
> +        </executions>
> +      </plugin>
> +      <plugin>
> +        <artifactId>maven-surefire-plugin</artifactId>
> +        <configuration>
> +          <excludedGroups>
> +            org.apache.logging.log4j.categories.PerformanceTests
> +          </excludedGroups>
> +          <systemPropertyVariables>
> +
> <org.apache.activemq.SERIALIZABLE_PACKAGES>*</org.apache.activemq.SERIALIZABLE_PACKAGES>
> +          </systemPropertyVariables>
> +        </configuration>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-failsafe-plugin</artifactId>
> +        <configuration>
> +          <skipTests>true</skipTests>
> +        </configuration>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-jar-plugin</artifactId>
> +        <executions>
> +          <execution>
> +            <id>default-jar</id>
> +            <goals>
> +              <goal>jar</goal>
> +            </goals>
> +            <configuration combine.self="override">
> +              <archive>
> +                <manifestFile>${manifestfile}</manifestFile>
> +                <manifestEntries>
> +                  <Specification-Title>${project.name
> }</Specification-Title>
> +
> <Specification-Version>${project.version}</Specification-Version>
> +                  <Specification-Vendor>${project.organization.name
> }</Specification-Vendor>
> +                  <Implementation-Title>${project.name
> }</Implementation-Title>
> +
> <Implementation-Version>${project.version}</Implementation-Version>
> +                  <Implementation-Vendor>${project.organization.name
> }</Implementation-Vendor>
> +
> <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
> +
> <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
> +
> <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
> +
> <Automatic-Module-Name>org.apache.logging.log4j.plugins</Automatic-Module-Name>
> +                  <Multi-Release>true</Multi-Release>
> +                </manifestEntries>
> +              </archive>
> +            </configuration>
> +          </execution>
> +          <execution>
> +            <id>default</id>
> +            <goals>
> +              <goal>test-jar</goal>
> +            </goals>
> +            <configuration>
> +              <archive>
> +                <manifestFile>${manifestfile}</manifestFile>
> +                <manifestEntries>
> +                  <Specification-Title>${project.name
> }</Specification-Title>
> +
> <Specification-Version>${project.version}</Specification-Version>
> +                  <Specification-Vendor>${project.organization.name
> }</Specification-Vendor>
> +                  <Implementation-Title>${project.name
> }</Implementation-Title>
> +
> <Implementation-Version>${project.version}</Implementation-Version>
> +                  <Implementation-Vendor>${project.organization.name
> }</Implementation-Vendor>
> +
> <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
> +
> <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
> +
> <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
> +                </manifestEntries>
> +              </archive>
> +            </configuration>
> +          </execution>
> +        </executions>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.felix</groupId>
> +        <artifactId>maven-bundle-plugin</artifactId>
> +        <configuration>
> +          <instructions>
> +
> <Bundle-SymbolicName>org.apache.logging.log4j.plugins</Bundle-SymbolicName>
> +            <!-- TODO: exclude internal classes from export -->
> +
> <Export-Package>org.apache.logging.log4j.plugins.*</Export-Package>
> +            <Import-Package>
> +              sun.reflect;resolution:=optional,
> +              org.apache.logging.log4j.util,
> +              *
> +            </Import-Package>
> +
> <Bundle-Activator>org.apache.logging.log4j.plugins.osgi.Activator</Bundle-Activator>
> +          </instructions>
> +        </configuration>
> +      </plugin>
> +    </plugins>
> +  </build>
> +  <reporting>
> +    <plugins>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-changes-plugin</artifactId>
> +        <version>${changes.plugin.version}</version>
> +        <reportSets>
> +          <reportSet>
> +            <reports>
> +              <report>changes-report</report>
> +            </reports>
> +          </reportSet>
> +        </reportSets>
> +        <configuration>
> +
> <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
> +          <useJql>true</useJql>
> +        </configuration>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-checkstyle-plugin</artifactId>
> +        <version>${checkstyle.plugin.version}</version>
> +        <configuration>
> +
> <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation>
> -->
> +
> <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
> +
> <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
> +          <enableRulesSummary>false</enableRulesSummary>
> +          <propertyExpansion>basedir=${basedir}</propertyExpansion>
> +
> <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
> +        </configuration>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-javadoc-plugin</artifactId>
> +        <version>${javadoc.plugin.version}</version>
> +        <configuration>
> +          <failOnError>false</failOnError>
> +          <bottom><![CDATA[<p align="center">Copyright &#169;
> {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
> +            Apache Logging, Apache Log4j, Log4j, Apache, the Apache
> feather logo, the Apache Logging project logo,
> +            and the Apache Log4j logo are trademarks of The Apache
> Software Foundation.</p>]]></bottom>
> +          <!-- module link generation is completely broken in the javadoc
> plugin for a multi-module non-aggregating
> +               project -->
> +          <additionalparam>${javadoc.opts}</additionalparam>
> +          <detectOfflineLinks>false</detectOfflineLinks>
> +          <linksource>true</linksource>
> +          <links>
> +            <link>http://docs.oracle.com/javaee/6/api/</link>
> +            <link>http://www.osgi.org/javadoc/r4v43/core/</link>
> +            <link>
> https://commons.apache.org/proper/commons-lang/javadocs/api-release/
> </link>
> +          </links>
> +          <groups>
> +            <group>
> +              <title>Core API</title>
> +              <packages>org.apache.logging.log4j.core</packages>
> +            </group>
> +            <group>
> +              <title>Configuration</title>
> +
> <packages>org.apache.logging.log4j.core.config*:org.apache.logging.log4j.core.selector</packages>
> +            </group>
> +            <group>
> +              <title>Core Plugins</title>
> +
> <packages>org.apache.logging.log4j.core.appender*:org.apache.logging.log4j.core.filter:org.apache.logging.log4j.core.layout:org.apache.logging.log4j.core.lookup:org.apache.logging.log4j.core.pattern:org.apache.logging.log4j.core.script</packages>
> +            </group>
> +            <group>
> +              <title>Tools</title>
> +              <packages>org.apache.logging.log4j.core.net
> *:org.apache.logging.log4j.core.tools</packages>
> +            </group>
> +            <group>
> +              <title>Internals</title>
> +
> <packages>org.apache.logging.log4j.core.async:org.apache.logging.log4j.core.impl:org.apache.logging.log4j.core.util*:org.apache.logging.log4j.core.osgi:org.apache.logging.log4j.core.jackson:org.apache.logging.log4j.core.jmx</packages>
> +            </group>
> +          </groups>
> +        </configuration>
> +        <reportSets>
> +          <reportSet>
> +            <id>non-aggregate</id>
> +            <reports>
> +              <report>javadoc</report>
> +            </reports>
> +          </reportSet>
> +        </reportSets>
> +      </plugin>
> +      <plugin>
> +        <groupId>com.github.spotbugs</groupId>
> +        <artifactId>spotbugs-maven-plugin</artifactId>
> +        <configuration>
> +          <fork>true</fork>
> +          <jvmArgs>-Duser.language=en</jvmArgs>
> +          <threshold>Normal</threshold>
> +          <effort>Default</effort>
> +
> <excludeFilterFile>${log4jParentDir}/spotbugs-exclude-filter.xml</excludeFilterFile>
> +        </configuration>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-jxr-plugin</artifactId>
> +        <version>${jxr.plugin.version}</version>
> +        <reportSets>
> +          <reportSet>
> +            <id>non-aggregate</id>
> +            <reports>
> +              <report>jxr</report>
> +            </reports>
> +          </reportSet>
> +          <reportSet>
> +            <id>aggregate</id>
> +            <reports>
> +              <report>aggregate</report>
> +            </reports>
> +          </reportSet>
> +        </reportSets>
> +      </plugin>
> +      <plugin>
> +        <groupId>org.apache.maven.plugins</groupId>
> +        <artifactId>maven-pmd-plugin</artifactId>
> +        <version>${pmd.plugin.version}</version>
> +        <configuration>
> +          <targetJdk>${maven.compiler.target}</targetJdk>
> +        </configuration>
> +      </plugin>
> +    </plugins>
> +  </reporting>
> +</project>
> +
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
> similarity index 97%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
> index c92c904..22fd9bf 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
> @@ -14,15 +14,15 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config;
> +package org.apache.logging.log4j.plugins;
> +
> +import org.apache.logging.log4j.plugins.util.PluginType;
>
>  import java.util.ArrayList;
>  import java.util.HashMap;
>  import java.util.List;
>  import java.util.Map;
>
> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
> -
>  /**
>   * A Configuration node.
>   */
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
> similarity index 97%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
> index 8aaf117..348754f 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
> @@ -14,7 +14,9 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
> +
> +import org.apache.logging.log4j.util.Strings;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>  import java.lang.annotation.RetentionPolicy;
>  import java.lang.annotation.Target;
>
> -import org.apache.logging.log4j.util.Strings;
> -
>  /**
>   * Annotation that identifies a Class as a Plugin.
>   */
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
> similarity index 87%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
> index 7be3dea..4dce103 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
> @@ -14,7 +14,7 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> @@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy;
>  import java.lang.annotation.Target;
>
>  /**
> - * Identifies a list of aliases for a {@link Plugin}, {@link
> PluginAttribute}, or {@link PluginBuilderAttribute}.
> + * Identifies a list of aliases for a Plugin, PluginAttribute, or
> PluginBuilderAttribute.
>   */
>  @Documented
>  @Retention(RetentionPolicy.RUNTIME)
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
> similarity index 96%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
> index bd88220..b9d4684 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
> @@ -14,7 +14,10 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
> +
> +import org.apache.logging.log4j.plugins.visitors.PluginAttributeVisitor;
> +import org.apache.logging.log4j.util.Strings;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> @@ -22,9 +25,6 @@ import java.lang.annotation.Retention;
>  import java.lang.annotation.RetentionPolicy;
>  import java.lang.annotation.Target;
>
> -import
> org.apache.logging.log4j.core.config.plugins.visitors.PluginAttributeVisitor;
> -import org.apache.logging.log4j.util.Strings;
> -
>  /**
>   * Identifies a Plugin Attribute and its default value. Note that only
> one of the defaultFoo attributes will be
>   * used based on the type this annotation is attached to. Thus, for
> primitive types, the default<i>Type</i>
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
> similarity index 92%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
> index 675d78f..c7fce2f 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
> @@ -15,7 +15,10 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
> +
> +import
> org.apache.logging.log4j.plugins.visitors.PluginBuilderAttributeVisitor;
> +import org.apache.logging.log4j.util.Strings;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> @@ -23,9 +26,6 @@ import java.lang.annotation.Retention;
>  import java.lang.annotation.RetentionPolicy;
>  import java.lang.annotation.Target;
>
> -import
> org.apache.logging.log4j.core.config.plugins.visitors.PluginBuilderAttributeVisitor;
> -import org.apache.logging.log4j.util.Strings;
> -
>  /**
>   * Marks a field as a Plugin Attribute.
>   */
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
> similarity index 95%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
> index 4e69262..035b025 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
> @@ -15,7 +15,7 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
> similarity index 91%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
> index 7ea358b..6cfb6fa 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
> @@ -14,7 +14,9 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
> +
> +import org.apache.logging.log4j.plugins.visitors.PluginElementVisitor;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>  import java.lang.annotation.RetentionPolicy;
>  import java.lang.annotation.Target;
>
> -import
> org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor;
> -
>  /**
>   * Identifies a parameter as a Plugin and corresponds with an XML element
> (or equivalent) in configuration files.
>   */
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
> similarity index 96%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
> index 1c04106..b071510 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
> @@ -14,7 +14,7 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
> similarity index 90%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
> index d60f1b5..b172268 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
> @@ -14,7 +14,9 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
> +
> +import org.apache.logging.log4j.plugins.visitors.PluginNodeVisitor;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>  import java.lang.annotation.RetentionPolicy;
>  import java.lang.annotation.Target;
>
> -import
> org.apache.logging.log4j.core.config.plugins.visitors.PluginNodeVisitor;
> -
>  /**
>   * Identifies a Plugin configuration Node.
>   */
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
> similarity index 91%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
> index 9c20cc2..31e5a23 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
> @@ -14,7 +14,9 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
> +
> +import org.apache.logging.log4j.plugins.visitors.PluginValueVisitor;
>
>  import java.lang.annotation.Documented;
>  import java.lang.annotation.ElementType;
> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>  import java.lang.annotation.RetentionPolicy;
>  import java.lang.annotation.Target;
>
> -import
> org.apache.logging.log4j.core.config.plugins.visitors.PluginValueVisitor;
> -
>  /**
>   * Identifies a parameter as a value. These correspond with property
> values generally, but are meant as values to be
>   * used as a placeholder value somewhere.
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
> similarity index 89%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
> index 65fcb76..093cc50 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
> @@ -15,7 +15,9 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins;
> +package org.apache.logging.log4j.plugins;
> +
> +import org.apache.logging.log4j.plugins.visitors.PluginVisitor;
>
>  import java.lang.annotation.Annotation;
>  import java.lang.annotation.Documented;
> @@ -24,8 +26,6 @@ import java.lang.annotation.Retention;
>  import java.lang.annotation.RetentionPolicy;
>  import java.lang.annotation.Target;
>
> -import
> org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor;
> -
>  /**
>   * Meta-annotation to denote the class name to use that implements
>   * {@link
> org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor} for
> the annotated annotation.
> @@ -40,5 +40,5 @@ public @interface PluginVisitorStrategy {
>       * for the given annotation. The generic type in {@code
> PluginVisitor} should match the annotation this annotation
>       * is applied to.
>       */
> -    Class<? extends PluginVisitor<? extends Annotation>> value();
> +    Class<? extends PluginVisitor<? extends Annotation, ?>> value();
>  }
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
> similarity index 95%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
> copy to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
> index 15a162c..fd8012a 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
> @@ -14,7 +14,7 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.convert;
> +package org.apache.logging.log4j.plugins.convert;
>
>  import org.apache.logging.log4j.util.EnglishEnums;
>
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
> similarity index 95%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
> index e629657..f9037b3 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
> @@ -14,7 +14,7 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.convert;
> +package org.apache.logging.log4j.plugins.convert;
>
>  /**
>   * Converts Strings to hex. This is used in place of
> java.xml.bind.DataTypeConverter which is not available by
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
> similarity index 95%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
> index e67e213..aaa5b4d 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
> @@ -15,7 +15,7 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.convert;
> +package org.apache.logging.log4j.plugins.convert;
>
>  /**
>   * Interface for doing automatic String conversion to a specific type.
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
> similarity index 92%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
> index 5088f15..fb5b27e 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
> @@ -14,7 +14,14 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.convert;
> +package org.apache.logging.log4j.plugins.convert;
> +
> +import org.apache.logging.log4j.Logger;
> +import org.apache.logging.log4j.plugins.util.PluginManager;
> +import org.apache.logging.log4j.plugins.util.PluginType;
> +import org.apache.logging.log4j.plugins.util.TypeUtil;
> +import org.apache.logging.log4j.util.ReflectionUtil;
> +import org.apache.logging.log4j.status.StatusLogger;
>
>  import java.lang.reflect.ParameterizedType;
>  import java.lang.reflect.Type;
> @@ -25,13 +32,6 @@ import java.util.UnknownFormatConversionException;
>  import java.util.concurrent.ConcurrentHashMap;
>  import java.util.concurrent.ConcurrentMap;
>
> -import org.apache.logging.log4j.Logger;
> -import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
> -import org.apache.logging.log4j.core.util.ReflectionUtil;
> -import org.apache.logging.log4j.core.util.TypeUtil;
> -import org.apache.logging.log4j.status.StatusLogger;
> -
>  /**
>   * Registry for {@link TypeConverter} plugins.
>   *
> @@ -152,7 +152,12 @@ public class TypeConverterRegistry {
>      }
>
>      private void registerTypeAlias(final Type knownType, final Type
> aliasType) {
> -        registry.putIfAbsent(aliasType, registry.get(knownType));
> +        TypeConverter<?> converter = registry.get(knownType);
> +        if (converter != null) {
> +            registry.putIfAbsent(aliasType, converter);
> +        } else {
> +            LOGGER.error("Cannot locate converter for {}", knownType);
> +        }
>      }
>
>  }
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
> similarity index 92%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
> index dc833f0..7a71b4a 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
> @@ -15,32 +15,27 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.convert;
> +package org.apache.logging.log4j.plugins.convert;
> +
> +import org.apache.logging.log4j.Level;
> +import org.apache.logging.log4j.Logger;
> +import org.apache.logging.log4j.plugins.Plugin;
> +import org.apache.logging.log4j.status.StatusLogger;
> +import org.apache.logging.log4j.util.LoaderUtil;
>
>  import java.io.File;
>  import java.math.BigDecimal;
>  import java.math.BigInteger;
> -import java.net.InetAddress;
> -import java.net.MalformedURLException;
> -import java.net.URI;
> -import java.net.URISyntaxException;
> -import java.net.URL;
> +import java.net.*;
>  import java.nio.charset.Charset;
>  import java.nio.file.Path;
>  import java.nio.file.Paths;
>  import java.security.Provider;
>  import java.security.Security;
> +import java.util.Base64;
>  import java.util.UUID;
>  import java.util.regex.Pattern;
>
> -import org.apache.logging.log4j.Level;
> -import org.apache.logging.log4j.Logger;
> -import org.apache.logging.log4j.core.appender.rolling.action.Duration;
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import org.apache.logging.log4j.core.util.CronExpression;
> -import org.apache.logging.log4j.status.StatusLogger;
> -import org.apache.logging.log4j.util.LoaderUtil;
> -
>  /**
>   * Collection of basic TypeConverter implementations. May be used to
> register additional TypeConverters or find
>   * registered TypeConverters.
> @@ -56,6 +51,8 @@ public final class TypeConverters {
>       */
>      public static final String CATEGORY = "TypeConverter";
>
> +    private static final Base64.Decoder decoder = Base64.getDecoder();
> +
>      /**
>       * Parses a {@link String} into a {@link BigDecimal}.
>       */
> @@ -112,7 +109,7 @@ public final class TypeConverters {
>                  bytes = new byte[0];
>              } else if (value.startsWith(PREFIX_BASE64)) {
>                  final String lexicalXSDBase64Binary =
> value.substring(PREFIX_BASE64.length());
> -                bytes =
> Base64Converter.parseBase64Binary(lexicalXSDBase64Binary);
> +                bytes = decoder.decode(lexicalXSDBase64Binary);
>              } else if (value.startsWith(PREFIX_0x)) {
>                  final String lexicalXSDHexBinary =
> value.substring(PREFIX_0x.length());
>                  bytes = HexConverter.parseHexBinary(lexicalXSDHexBinary);
> @@ -203,14 +200,6 @@ public final class TypeConverters {
>          }
>      }
>
> -    @Plugin(name = "CronExpression", category = CATEGORY)
> -    public static class CronExpressionConverter implements
> TypeConverter<CronExpression> {
> -        @Override
> -        public CronExpression convert(final String s) throws Exception {
> -            return new CronExpression(s);
> -        }
> -    }
> -
>      /**
>       * Converts a {@link String} into a {@link Double}.
>       */
> @@ -223,18 +212,6 @@ public final class TypeConverters {
>      }
>
>      /**
> -     * Converts a {@link String} into a {@link Duration}.
> -     * @since 2.5
> -     */
> -    @Plugin(name = "Duration", category = CATEGORY)
> -    public static class DurationConverter implements
> TypeConverter<Duration> {
> -        @Override
> -        public Duration convert(final String s) {
> -            return Duration.parse(s);
> -        }
> -    }
> -
> -    /**
>       * Converts a {@link String} into a {@link File}.
>       */
>      @Plugin(name = "File", category = CATEGORY)
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
> similarity index 80%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
> index f22ba49..958beb4 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
> @@ -16,8 +16,7 @@
>   */
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * TypeConverter plugins for converter strings into various types. These
> plugins are used for parsing plugin
> + * attributes in plugin factory methods.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +package org.apache.logging.log4j.plugins.convert;
> diff --git
> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
> new file mode 100644
> index 0000000..518bee7
> --- /dev/null
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
> @@ -0,0 +1,103 @@
> +/*
> + * 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.plugins.osgi;
> +
> +import org.apache.logging.log4j.LogManager;
> +import org.apache.logging.log4j.Logger;
> +import org.apache.logging.log4j.plugins.processor.PluginService;
> +import org.apache.logging.log4j.plugins.util.PluginRegistry;
> +import org.apache.logging.log4j.spi.Provider;
> +import org.apache.logging.log4j.status.StatusLogger;
> +import org.apache.logging.log4j.util.PropertiesUtil;
> +import org.osgi.framework.*;
> +import org.osgi.framework.wiring.BundleWiring;
> +
> +import java.util.Hashtable;
> +import java.util.concurrent.atomic.AtomicReference;
> +
> +/**
> + * OSGi BundleActivator.
> + */
> +public final class Activator implements BundleActivator,
> SynchronousBundleListener {
> +
> +    private static final Logger LOGGER = StatusLogger.getLogger();
> +
> +    private final AtomicReference<BundleContext> contextRef = new
> AtomicReference<>();
> +
> +    ServiceRegistration provideRegistration = null;
> +
> +    @Override
> +    public void start(final BundleContext context) throws Exception {
> +        final PluginService pluginService = new Log4jProvider();
> +        final Hashtable<String, String> props = new Hashtable<>();
> +        props.put("APIVersion", "3.0");
> +        provideRegistration =
> context.registerService(pluginService.class.getName(), provider, props);
> +        if (this.contextRef.compareAndSet(null, context)) {
> +            context.addBundleListener(this);
> +            // done after the BundleListener as to not miss any new
> bundle installs in the interim
> +            scanInstalledBundlesForPlugins(context);
> +        }
> +    }
> +
> +    private static void scanInstalledBundlesForPlugins(final
> BundleContext context) {
> +        final Bundle[] bundles = context.getBundles();
> +        for (final Bundle bundle : bundles) {
> +            // TODO: bundle state can change during this
> +            scanBundleForPlugins(bundle);
> +        }
> +    }
> +
> +    private static void scanBundleForPlugins(final Bundle bundle) {
> +        final long bundleId = bundle.getBundleId();
> +        // LOG4J2-920: don't scan system bundle for plugins
> +        if (bundle.getState() == Bundle.ACTIVE && bundleId != 0) {
> +            LOGGER.trace("Scanning bundle [{}, id=%d] for plugins.",
> bundle.getSymbolicName(), bundleId);
> +            PluginRegistry.getInstance().loadFromBundle(bundleId,
> +                    bundle.adapt(BundleWiring.class).getClassLoader());
> +        }
> +    }
> +
> +    private static void stopBundlePlugins(final Bundle bundle) {
> +        LOGGER.trace("Stopping bundle [{}] plugins.",
> bundle.getSymbolicName());
> +        // TODO: plugin lifecycle code
> +
> PluginRegistry.getInstance().clearBundlePlugins(bundle.getBundleId());
> +    }
> +
> +    @Override
> +    public void stop(final BundleContext context) throws Exception {
> +        provideRegistration.unregister();
> +        this.contextRef.compareAndSet(context, null);
> +    }
> +
> +    @Override
> +    public void bundleChanged(final BundleEvent event) {
> +        switch (event.getType()) {
> +            // FIXME: STARTING instead of STARTED?
> +            case BundleEvent.STARTED:
> +                scanBundleForPlugins(event.getBundle());
> +                break;
> +
> +            case BundleEvent.STOPPING:
> +                stopBundlePlugins(event.getBundle());
> +                break;
> +
> +            default:
> +                break;
> +        }
> +    }
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
> similarity index 87%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
> index f22ba49..37dadd4 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
> @@ -16,8 +16,6 @@
>   */
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * Collection of OSGi-specific classes for bundles.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +package org.apache.logging.log4j.plugins.osgi;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
> similarity index 87%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
> index f22ba49..b161185 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
> @@ -16,8 +16,6 @@
>   */
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * Annotations for Log4j 2 plugins.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +package org.apache.logging.log4j.plugins;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
> similarity index 71%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
> index 2fd4160..784dece 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
> @@ -15,7 +15,7 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.processor;
> +package org.apache.logging.log4j.plugins.processor;
>
>  import java.io.BufferedInputStream;
>  import java.io.BufferedOutputStream;
> @@ -60,34 +60,6 @@ public class PluginCache {
>      }
>
>      /**
> -     * Stores the plugin cache to a given OutputStream.
> -     *
> -     * @param os destination to save cache to.
> -     * @throws IOException if an I/O exception occurs.
> -     */
> -    // NOTE: if this file format is to be changed, the filename should
> change and this format should still be readable
> -    public void writeCache(final OutputStream os) throws IOException {
> -        try (final DataOutputStream out = new DataOutputStream(new
> BufferedOutputStream(os))) {
> -            // See PluginManager.readFromCacheFiles for the corresponding
> decoder. Format may not be changed
> -            // without breaking existing Log4j2Plugins.dat files.
> -            out.writeInt(categories.size());
> -            for (final Map.Entry<String, Map<String, PluginEntry>>
> category : categories.entrySet()) {
> -                out.writeUTF(category.getKey());
> -                final Map<String, PluginEntry> m = category.getValue();
> -                out.writeInt(m.size());
> -                for (final Map.Entry<String, PluginEntry> entry :
> m.entrySet()) {
> -                    final PluginEntry plugin = entry.getValue();
> -                    out.writeUTF(plugin.getKey());
> -                    out.writeUTF(plugin.getClassName());
> -                    out.writeUTF(plugin.getName());
> -                    out.writeBoolean(plugin.isPrintable());
> -                    out.writeBoolean(plugin.isDefer());
> -                }
> -            }
> -        }
> -    }
> -
> -    /**
>       * Loads and merges all the Log4j plugin cache files specified.
> Usually, this is obtained via a ClassLoader.
>       *
>       * @param resources URLs to all the desired plugin cache files to
> load.
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
> similarity index 85%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
> index dd43601..bd452d3 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
> @@ -15,7 +15,7 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.processor;
> +package org.apache.logging.log4j.plugins.processor;
>
>  import java.io.Serializable;
>
> @@ -32,6 +32,18 @@ public class PluginEntry implements Serializable {
>      private boolean defer;
>      private transient String category;
>
> +    public PluginEntry() {
> +    }
> +
> +    public PluginEntry(String key, String className, String name, boolean
> printable, boolean defer, String category) {
> +        this.key = key;
> +        this.className = className;
> +        this.name = name;
> +        this.printable = printable;
> +        this.defer = defer;
> +        this.category = category;
> +    }
> +
>      public String getKey() {
>          return key;
>      }
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
> similarity index 54%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
> index 2f3b53f..975d2ab 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
> @@ -15,38 +15,47 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.processor;
> +package org.apache.logging.log4j.plugins.processor;
> +
> +import org.apache.logging.log4j.LoggingException;
> +import org.apache.logging.log4j.plugins.Plugin;
> +import org.apache.logging.log4j.plugins.PluginAliases;
> +import org.apache.logging.log4j.util.Strings;
>
> -import java.io.IOException;
> -import java.io.OutputStream;
> -import java.util.ArrayList;
> -import java.util.Collection;
> -import java.util.Collections;
> -import java.util.Locale;
> -import java.util.Map;
> -import java.util.Objects;
> -import java.util.Set;
>  import javax.annotation.processing.AbstractProcessor;
> +import javax.annotation.processing.Messager;
>  import javax.annotation.processing.RoundEnvironment;
>  import javax.annotation.processing.SupportedAnnotationTypes;
>  import javax.lang.model.SourceVersion;
>  import javax.lang.model.element.Element;
>  import javax.lang.model.element.ElementVisitor;
> +import javax.lang.model.element.Name;
>  import javax.lang.model.element.TypeElement;
>  import javax.lang.model.util.Elements;
>  import javax.lang.model.util.SimpleElementVisitor7;
>  import javax.tools.Diagnostic.Kind;
>  import javax.tools.FileObject;
> +import javax.tools.JavaFileObject;
>  import javax.tools.StandardLocation;
> +import java.io.BufferedWriter;
> +import java.io.IOException;
> +import java.io.OutputStreamWriter;
> +import java.io.PrintWriter;
> +import java.util.ArrayList;
> +import java.util.Collection;
> +import java.util.Collections;
> +import java.util.List;
> +import java.util.Locale;
> +import java.util.Map;
> +import java.util.Objects;
> +import java.util.Set;
>
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
> -import org.apache.logging.log4j.util.Strings;
> +import static java.nio.charset.StandardCharsets.UTF_8;
>
>  /**
>   * Annotation processor for pre-scanning Log4j 2 plugins.
>   */
>
> -@SupportedAnnotationTypes("org.apache.logging.log4j.core.config.plugins.*")
> +@SupportedAnnotationTypes({"org.apache.logging.log4j.plugins.*",
> "org.apache.logging.log4j.core.config.plugins.*"})
>  public class PluginProcessor extends AbstractProcessor {
>
>      // TODO: this could be made more abstract to allow for compile-time
> and run-time plugin processing
> @@ -57,8 +66,8 @@ public class PluginProcessor extends AbstractProcessor {
>       */
>      public static final String PLUGIN_CACHE_FILE =
>
>  "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat";
> -
> -    private final PluginCache pluginCache = new PluginCache();
> +    private static final String SERVICE_FILE_NAME =
> +
> "META-INF/services/org.apache.logging.log4j.plugins.processor.PluginService";
>
>      @Override
>      public SourceVersion getSupportedSourceVersion() {
> @@ -67,16 +76,21 @@ public class PluginProcessor extends AbstractProcessor
> {
>
>      @Override
>      public boolean process(final Set<? extends TypeElement> annotations,
> final RoundEnvironment roundEnv) {
> -        System.out.println("Processing annotations");
> +        Map<String, String> options = processingEnv.getOptions();
> +        String packageName = options.get("pluginPackage");
> +        Messager messager = processingEnv.getMessager();
> +        messager.printMessage(Kind.NOTE, "Processing Log4j annotations");
>          try {
>              final Set<? extends Element> elements =
> roundEnv.getElementsAnnotatedWith(Plugin.class);
>              if (elements.isEmpty()) {
> -                System.out.println("No elements to process");
> +                messager.printMessage(Kind.NOTE, "No elements to
> process");
>                  return false;
>              }
> -            collectPlugins(elements);
> -            writeCacheFile(elements.toArray(new
> Element[elements.size()]));
> -            System.out.println("Annotations processed");
> +            List<PluginEntry> list = new ArrayList<>();
> +            packageName = collectPlugins(packageName, elements, list);
> +            writeClassFile(packageName, list);
> +            writeServiceFile(packageName);
> +            messager.printMessage(Kind.NOTE, "Annotations processed");
>              return true;
>          } catch (final IOException e) {
>              e.printStackTrace();
> @@ -93,7 +107,8 @@ public class PluginProcessor extends AbstractProcessor {
>          processingEnv.getMessager().printMessage(Kind.ERROR, message);
>      }
>
> -    private void collectPlugins(final Iterable<? extends Element>
> elements) {
> +    private String collectPlugins(String packageName, final Iterable<?
> extends Element> elements, List<PluginEntry> list) {
> +        boolean calculatePackage = packageName == null;
>          final Elements elementUtils = processingEnv.getElementUtils();
>          final ElementVisitor<PluginEntry, Plugin> pluginVisitor = new
> PluginElementVisitor(elementUtils);
>          final ElementVisitor<Collection<PluginEntry>, Plugin>
> pluginAliasesVisitor = new PluginAliasesElementVisitor(
> @@ -104,23 +119,93 @@ public class PluginProcessor extends
> AbstractProcessor {
>                  continue;
>              }
>              final PluginEntry entry = element.accept(pluginVisitor,
> plugin);
> -            final Map<String, PluginEntry> category =
> pluginCache.getCategory(entry.getCategory());
> -            category.put(entry.getKey(), entry);
> +            list.add(entry);
> +            if (calculatePackage) {
> +                packageName = calculatePackage(elementUtils, element,
> packageName);
> +            }
>              final Collection<PluginEntry> entries =
> element.accept(pluginAliasesVisitor, plugin);
>              for (final PluginEntry pluginEntry : entries) {
> -                category.put(pluginEntry.getKey(), pluginEntry);
> +                list.add(pluginEntry);
>              }
>          }
> +        return packageName;
>      }
>
> -    private void writeCacheFile(final Element... elements) throws
> IOException {
> +    private String calculatePackage(Elements elements, Element element,
> String packageName) {
> +        Name name = elements.getPackageOf(element).getQualifiedName();
> +        if (name == null) {
> +            return null;
> +        }
> +        String pkgName = name.toString();
> +        if (packageName == null) {
> +            return pkgName;
> +        }
> +        if (pkgName.length() == packageName.length()) {
> +            return packageName;
> +        }
> +        if (pkgName.length() < packageName.length() &&
> packageName.startsWith(pkgName)) {
> +            return pkgName;
> +        }
> +
> +        return commonPrefix(pkgName, packageName);
> +    }
> +
> +    private void writeServiceFile(String pkgName) throws IOException {
>          final FileObject fileObject =
> processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
> Strings.EMPTY,
> -                PLUGIN_CACHE_FILE, elements);
> -        try (final OutputStream out = fileObject.openOutputStream()) {
> -            pluginCache.writeCache(out);
> +                SERVICE_FILE_NAME);
> +        try (final PrintWriter writer = new PrintWriter(new
> BufferedWriter(new OutputStreamWriter(fileObject.openOutputStream(),
> UTF_8)))) {
> +            writer.println(createFqcn(pkgName));
> +        }
> +    }
> +
> +    private void writeClassFile(String pkg, List<PluginEntry> list) {
> +        String fqcn = createFqcn(pkg);
> +        try (final PrintWriter writer = createSourceFile(fqcn)) {
> +            writer.println("package " + pkg + ".plugins;");
> +            writer.println("");
> +            writer.println("import
> org.apache.logging.log4j.plugins.processor.PluginEntry;");
> +            writer.println("import
> org.apache.logging.log4j.plugins.processor.PluginService;");
> +            writer.println("");
> +            writer.println("public class Log4jPlugins extends
> PluginService {");
> +            writer.println("");
> +            writer.println("    private static PluginEntry[] entries =
> new PluginEntry[] {");
> +            StringBuilder sb = new StringBuilder();
> +            int max = list.size() - 1;
> +            for (int i = 0; i < list.size(); ++i) {
> +                PluginEntry entry = list.get(i);
> +                sb.append("        ").append("new PluginEntry(\"");
> +                sb.append(entry.getKey()).append("\", \"");
> +                sb.append(entry.getClassName()).append("\", \"");
> +                sb.append(entry.getName()).append("\", ");
> +                sb.append(entry.isPrintable()).append(", ");
> +                sb.append(entry.isDefer()).append(", \"");
> +                sb.append(entry.getCategory()).append("\")");
> +                if (i < max) {
> +                    sb.append(",");
> +                }
> +                writer.println(sb.toString());
> +                sb.setLength(0);
> +            }
> +            writer.println("    };");
> +            writer.println("    @Override");
> +            writer.println("    public PluginEntry[] getEntries() {
> return entries;}");
> +            writer.println("}");
>          }
>      }
>
> +    private PrintWriter createSourceFile(String fqcn) {
> +        try {
> +            JavaFileObject sourceFile =
> processingEnv.getFiler().createSourceFile(fqcn);
> +            return new PrintWriter(sourceFile.openWriter());
> +        } catch (IOException e) {
> +            throw new LoggingException("Unable to create Plugin Service
> Class " + fqcn, e);
> +        }
> +    }
> +
> +    private String createFqcn(String packageName) {
> +        return packageName + ".plugins.Log4jPlugins";
> +    }
> +
>      /**
>       * ElementVisitor to scan the Plugin annotation.
>       */
> @@ -146,6 +231,20 @@ public class PluginProcessor extends
> AbstractProcessor {
>          }
>      }
>
> +    private String commonPrefix(String str1, String str2) {
> +        int minLength = str1.length() < str2.length() ? str1.length() :
> str2.length();
> +        for (int i = 0; i < minLength; i++) {
> +            if (str1.charAt(i) != str2.charAt(i)) {
> +                if (i > 1 && str1.charAt(i-1) == '.') {
> +                    return str1.substring(0, i-1);
> +                } else {
> +                    return str1.substring(0, i);
> +                }
> +            }
> +        }
> +        return str1.substring(0, minLength);
> +    }
> +
>      /**
>       * ElementVisitor to scan the PluginAliases annotation.
>       */
> diff --git
> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
> new file mode 100644
> index 0000000..5042456
> --- /dev/null
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
> @@ -0,0 +1,56 @@
> +/*
> + * 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.plugins.processor;
> +
> +import java.util.Collections;
> +import java.util.LinkedHashMap;
> +import java.util.Map;
> +
> +/**
> + * Class Description goes here.
> + */
> +public abstract class PluginService {
> +
> +    private final Map<String, Map<String, PluginEntry>> categories = new
> LinkedHashMap<>();
> +
> +    public PluginService() {
> +        PluginEntry[] entries = getEntries();
> +        for (PluginEntry entry : entries) {
> +            String category = entry.getCategory().toLowerCase();
> +            if (!categories.containsKey(category)) {
> +                categories.put(category, new LinkedHashMap<>());
> +            }
> +            Map<String, PluginEntry> map = categories.get(category);
> +            map.put(entry.getKey(), entry);
> +        }
> +    }
> +
> +    public abstract PluginEntry[] getEntries();
> +
> +    public Map<String, Map<String, PluginEntry>> getCategories() {
> +        return Collections.unmodifiableMap(categories);
> +    }
> +
> +    public Map<String, PluginEntry> getCategory(String category) {
> +        return
> Collections.unmodifiableMap(categories.get(category.toLowerCase()));
> +    }
> +
> +    public long size() {
> +        return categories.size();
> +    }
> +
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
> similarity index 94%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
> copy to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
> index 4f6ddda..2c296f9 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
> @@ -19,4 +19,4 @@
>   * Java annotation processor for pre-scanning Log4j 2 plugins. This is
> provided as an alternative to using the
>   * executable {@link
> org.apache.logging.log4j.core.config.plugins.util.PluginManager} class in
> your build process.
>   */
> -package org.apache.logging.log4j.core.config.plugins.processor;
> +package org.apache.logging.log4j.plugins.processor;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
> similarity index 93%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
> index 0935ce8..ec8a07f 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
> @@ -15,7 +15,7 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.util;
> +package org.apache.logging.log4j.plugins.util;
>
>  /**
>   * A type of builder that can be used to configure and create a instances
> using a Java DSL instead of
> @@ -25,7 +25,7 @@ package org.apache.logging.log4j.core.util;
>   * <p>
>   *     When creating <em>plugin</em> builders, it is customary to create
> the builder class as a public static inner class
>   *     called {@code Builder}. For instance, the builder class for
> - *     {@link org.apache.logging.log4j.core.layout.PatternLayout
> PatternLayout} would be
> + *     org.apache.logging.log4j.core.layout.PatternLayout PatternLayout
> would be
>   *     {@code PatternLayout.Builder}.
>   * </p>
>   *
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
> similarity index 96%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
> index 6f38d0e..b6f02f5 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
> @@ -15,17 +15,13 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.util;
> +package org.apache.logging.log4j.plugins.util;
>
>  import org.apache.logging.log4j.Logger;
>  import org.apache.logging.log4j.status.StatusLogger;
>  import org.apache.logging.log4j.util.Strings;
>
> -import java.util.Collection;
> -import java.util.HashMap;
> -import java.util.LinkedHashMap;
> -import java.util.List;
> -import java.util.Map;
> +import java.util.*;
>  import java.util.concurrent.CopyOnWriteArrayList;
>
>  /**
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
> similarity index 81%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
> index 99fa610..9e8c6e2 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
> @@ -15,32 +15,28 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.util;
> +package org.apache.logging.log4j.plugins.util;
> +
> +import org.apache.logging.log4j.Logger;
> +import org.apache.logging.log4j.plugins.Plugin;
> +import org.apache.logging.log4j.plugins.PluginAliases;
> +import org.apache.logging.log4j.plugins.processor.PluginCache;
> +import org.apache.logging.log4j.plugins.processor.PluginEntry;
> +import org.apache.logging.log4j.plugins.processor.PluginProcessor;
> +import org.apache.logging.log4j.plugins.processor.PluginService;
> +import org.apache.logging.log4j.status.StatusLogger;
> +import org.apache.logging.log4j.util.LoaderUtil;
> +import org.apache.logging.log4j.util.Strings;
>
>  import java.io.IOException;
>  import java.net.URI;
>  import java.net.URL;
>  import java.text.DecimalFormat;
> -import java.util.ArrayList;
> -import java.util.Collections;
> -import java.util.Enumeration;
> -import java.util.HashMap;
> -import java.util.List;
> -import java.util.Map;
> +import java.util.*;
>  import java.util.concurrent.ConcurrentHashMap;
>  import java.util.concurrent.ConcurrentMap;
>  import java.util.concurrent.atomic.AtomicReference;
>
> -import org.apache.logging.log4j.Logger;
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
> -import org.apache.logging.log4j.core.config.plugins.processor.PluginCache;
> -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry;
> -import
> org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor;
> -import org.apache.logging.log4j.core.util.Loader;
> -import org.apache.logging.log4j.status.StatusLogger;
> -import org.apache.logging.log4j.util.Strings;
> -
>  /**
>   * Registry singleton for PluginType maps partitioned by source type and
> then by category names.
>   */
> @@ -116,7 +112,8 @@ public class PluginRegistry {
>              // already loaded
>              return existing;
>          }
> -        final Map<String, List<PluginType<?>>> newPluginsByCategory =
> decodeCacheFiles(Loader.getClassLoader());
> +        final Map<String, List<PluginType<?>>> newPluginsByCategory =
> decodeCacheFiles(LoaderUtil.getClassLoader());
> +        loadPlugins(newPluginsByCategory);
>
>          // Note multiple threads could be calling this method
> concurrently. Both will do the work,
>          // but only one will be allowed to store the result in the
> AtomicReference.
> @@ -144,6 +141,7 @@ public class PluginRegistry {
>              return existing;
>          }
>          final Map<String, List<PluginType<?>>> newPluginsByCategory =
> decodeCacheFiles(loader);
> +        loadPlugins(loader, newPluginsByCategory);
>
>          // Note multiple threads could be calling this method
> concurrently. Both will do the work,
>          // but only one will be allowed to store the result in the outer
> map.
> @@ -155,6 +153,51 @@ public class PluginRegistry {
>          return newPluginsByCategory;
>      }
>
> +    /**
> +     * @since 3.0
> +     */
> +    public void loadPlugins(Map<String, List<PluginType<?>>> map) {
> +        for (ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
> +            try {
> +                loadPlugins(classLoader, map);
> +            } catch (Throwable ex) {
> +                LOGGER.debug("Unable to retrieve provider from
> ClassLoader {}", classLoader, ex);
> +            }
> +        }
> +    }
> +
> +    /**
> +     * @since 3.0
> +     */
> +    public void loadPlugins(ClassLoader classLoader, Map<String,
> List<PluginType<?>>> map) {
> +        final long startTime = System.nanoTime();
> +        final ServiceLoader<PluginService> serviceLoader =
> ServiceLoader.load(PluginService.class, classLoader);
> +        int pluginCount = 0;
> +        for (final PluginService pluginService : serviceLoader) {
> +            PluginEntry[] entries = pluginService.getEntries();
> +            for (PluginEntry entry : entries) {
> +                try {
> +                    final Class<?> clazz =
> classLoader.loadClass(entry.getClassName());
> +                    final PluginType<?> type = new PluginType(entry,
> clazz, entry.getName());
> +                    String category = entry.getCategory().toLowerCase();
> +                    if (!map.containsKey(category)) {
> +                        map.put(category, new ArrayList<>());
> +                    }
> +                    List<PluginType<?>> list = map.get(category);
> +                    list.add(type);
> +                    ++pluginCount;
> +                } catch (final ClassNotFoundException e) {
> +                    LOGGER.info("Plugin [{}] could not be loaded due to
> missing classes.", entry.getClassName(), e);
> +                }
> +            }
> +        }
> +        final long endTime = System.nanoTime();
> +        final DecimalFormat numFormat = new DecimalFormat("#0.000000");
> +        final double seconds = (endTime - startTime) * 1e-9;
> +        LOGGER.debug("Took {} seconds to load {} plugins from {}",
> +                numFormat.format(seconds), pluginCount, classLoader);
> +    }
> +
>      private Map<String, List<PluginType<?>>> decodeCacheFiles(final
> ClassLoader loader) {
>          final long startTime = System.nanoTime();
>          final PluginCache cache = new PluginCache();
> @@ -214,7 +257,7 @@ public class PluginRegistry {
>
>          final long startTime = System.nanoTime();
>          final ResolverUtil resolver = new ResolverUtil();
> -        final ClassLoader classLoader = Loader.getClassLoader();
> +        final ClassLoader classLoader = LoaderUtil.getClassLoader();
>          if (classLoader != null) {
>              resolver.setClassLoader(classLoader);
>          }
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
> similarity index 92%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
> index cc6bc66..c213f64 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
> @@ -14,16 +14,16 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.util;
> +package org.apache.logging.log4j.plugins.util;
>
>
> -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry;
> +import org.apache.logging.log4j.plugins.processor.PluginEntry;
>
>  /**
>   * Plugin Descriptor. This is a memento object for Plugin annotations
> paired to their annotated classes.
>   *
>   * @param <T> The plug-in class, which can be any kind of class.
> - * @see org.apache.logging.log4j.core.config.plugins.Plugin
> + * @see org.apache.logging.log4j.plugins.Plugin
>   */
>  public class PluginType<T> {
>
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
> similarity index 97%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
> index 73b5fc0..a57356c 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
> @@ -14,33 +14,24 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.util;
> +package org.apache.logging.log4j.plugins.util;
>
> -import java.io.File;
> -import java.io.FileInputStream;
> -import java.io.IOException;
> -import java.io.InputStream;
> -import java.io.UnsupportedEncodingException;
> +import org.apache.logging.log4j.Logger;
> +import org.apache.logging.log4j.util.LoaderUtil;
> +import org.apache.logging.log4j.status.StatusLogger;
> +import org.osgi.framework.FrameworkUtil;
> +import org.osgi.framework.wiring.BundleWiring;
> +
> +import java.io.*;
>  import java.net.URI;
>  import java.net.URISyntaxException;
>  import java.net.URL;
>  import java.net.URLDecoder;
>  import java.nio.charset.StandardCharsets;
> -import java.util.Arrays;
> -import java.util.Collection;
> -import java.util.Enumeration;
> -import java.util.HashSet;
> -import java.util.List;
> -import java.util.Set;
> +import java.util.*;
>  import java.util.jar.JarEntry;
>  import java.util.jar.JarInputStream;
>
> -import org.apache.logging.log4j.Logger;
> -import org.apache.logging.log4j.core.util.Loader;
> -import org.apache.logging.log4j.status.StatusLogger;
> -import org.osgi.framework.FrameworkUtil;
> -import org.osgi.framework.wiring.BundleWiring;
> -
>  /**
>   * <p>
>   * ResolverUtil is used to locate classes that are available in the/a
> class path and meet arbitrary conditions. The two
> @@ -126,7 +117,7 @@ public class ResolverUtil {
>       * @return the ClassLoader that will be used to scan for classes
>       */
>      public ClassLoader getClassLoader() {
> -        return classloader != null ? classloader : (classloader =
> Loader.getClassLoader(ResolverUtil.class, null));
> +        return classloader != null ? classloader : (classloader =
> LoaderUtil.getClassLoader(ResolverUtil.class, null));
>      }
>
>      /**
> diff --git
> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
> new file mode 100644
> index 0000000..e2bb462
> --- /dev/null
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
> @@ -0,0 +1,217 @@
> +/*
> + * 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.plugins.util;
> +
> +import java.lang.reflect.*;
> +import java.util.ArrayList;
> +import java.util.List;
> +import java.util.Objects;
> +
> +/**
> + * Utility class for working with Java {@link Type}s and derivatives.
> This class is adapted heavily from the
> + * <a href="http://projects.spring.io/spring-framework/">Spring
> Framework</a>, specifically the
> + * <a href="
> http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/TypeUtils.html
> ">TypeUtils</a>
> + * class.
> + *
> + * @see Type
> + * @see GenericArrayType
> + * @see ParameterizedType
> + * @see WildcardType
> + * @see Class
> + * @since 2.1
> + */
> +public final class TypeUtil {
> +
> +    private TypeUtil() {
> +    }
> +
> +    /**
> +     * Gets all declared fields for the given class (including
> superclasses).
> +     *
> +     * @param cls the class to examine
> +     * @return all declared fields for the given class (including
> superclasses).
> +     * @see Class#getDeclaredFields()
> +     */
> +    public static List<Field> getAllDeclaredFields(Class<?> cls) {
> +        final List<Field> fields = new ArrayList<>();
> +        while (cls != null) {
> +            for (final Field field : cls.getDeclaredFields()) {
> +                fields.add(field);
> +            }
> +            cls = cls.getSuperclass();
> +        }
> +        return fields;
> +    }
> +    /**
> +     * Indicates if two {@link Type}s are assignment compatible.
> +     *
> +     * @param lhs the left hand side to check assignability to
> +     * @param rhs the right hand side to check assignability from
> +     * @return {@code true} if it is legal to assign a variable of type
> {@code rhs} to a variable of type {@code lhs}
> +     * @see Class#isAssignableFrom(Class)
> +     */
> +    public static boolean isAssignable(final Type lhs, final Type rhs) {
> +        Objects.requireNonNull(lhs, "No left hand side type provided");
> +        Objects.requireNonNull(rhs, "No right hand side type provided");
> +        if (lhs.equals(rhs)) {
> +            return true;
> +        }
> +        if (Object.class.equals(lhs)) {
> +            // everything is assignable to Object
> +            return true;
> +        }
> +        // raw type on left
> +        if (lhs instanceof Class<?>) {
> +            final Class<?> lhsClass = (Class<?>) lhs;
> +            if (rhs instanceof Class<?>) {
> +                // no generics involved
> +                final Class<?> rhsClass = (Class<?>) rhs;
> +                return lhsClass.isAssignableFrom(rhsClass);
> +            }
> +            if (rhs instanceof ParameterizedType) {
> +                // check to see if the parameterized type has the same
> raw type as the lhs; this is legal
> +                final Type rhsRawType = ((ParameterizedType)
> rhs).getRawType();
> +                if (rhsRawType instanceof Class<?>) {
> +                    return lhsClass.isAssignableFrom((Class<?>)
> rhsRawType);
> +                }
> +            }
> +            if (lhsClass.isArray() && rhs instanceof GenericArrayType) {
> +                // check for compatible array component types
> +                return isAssignable(lhsClass.getComponentType(),
> ((GenericArrayType) rhs).getGenericComponentType());
> +            }
> +        }
> +        // parameterized type on left
> +        if (lhs instanceof ParameterizedType) {
> +            final ParameterizedType lhsType = (ParameterizedType) lhs;
> +            if (rhs instanceof Class<?>) {
> +                final Type lhsRawType = lhsType.getRawType();
> +                if (lhsRawType instanceof Class<?>) {
> +                    return ((Class<?>)
> lhsRawType).isAssignableFrom((Class<?>) rhs);
> +                }
> +            } else if (rhs instanceof ParameterizedType) {
> +                final ParameterizedType rhsType = (ParameterizedType) rhs;
> +                return isParameterizedAssignable(lhsType, rhsType);
> +            }
> +        }
> +        // generic array type on left
> +        if (lhs instanceof GenericArrayType) {
> +            final Type lhsComponentType = ((GenericArrayType)
> lhs).getGenericComponentType();
> +            if (rhs instanceof Class<?>) {
> +                // raw type on right
> +                final Class<?> rhsClass = (Class<?>) rhs;
> +                if (rhsClass.isArray()) {
> +                    return isAssignable(lhsComponentType,
> rhsClass.getComponentType());
> +                }
> +            } else if (rhs instanceof GenericArrayType) {
> +                return isAssignable(lhsComponentType, ((GenericArrayType)
> rhs).getGenericComponentType());
> +            }
> +        }
> +        // wildcard type on left
> +        if (lhs instanceof WildcardType) {
> +            return isWildcardAssignable((WildcardType) lhs, rhs);
> +        }
> +        // strange...
> +        return false;
> +    }
> +
> +    private static boolean isParameterizedAssignable(final
> ParameterizedType lhs, final ParameterizedType rhs) {
> +        if (lhs.equals(rhs)) {
> +            // that was easy
> +            return true;
> +        }
> +        final Type[] lhsTypeArguments = lhs.getActualTypeArguments();
> +        final Type[] rhsTypeArguments = rhs.getActualTypeArguments();
> +        final int size = lhsTypeArguments.length;
> +        if (rhsTypeArguments.length != size) {
> +            // clearly incompatible types
> +            return false;
> +        }
> +        for (int i = 0; i < size; i++) {
> +            // verify all type arguments are assignable
> +            final Type lhsArgument = lhsTypeArguments[i];
> +            final Type rhsArgument = rhsTypeArguments[i];
> +            if (!lhsArgument.equals(rhsArgument) &&
> +                !(lhsArgument instanceof WildcardType &&
> +                    isWildcardAssignable((WildcardType) lhsArgument,
> rhsArgument))) {
> +                return false;
> +            }
> +        }
> +        return true;
> +    }
> +
> +    private static boolean isWildcardAssignable(final WildcardType lhs,
> final Type rhs) {
> +        final Type[] lhsUpperBounds = getEffectiveUpperBounds(lhs);
> +        final Type[] lhsLowerBounds = getEffectiveLowerBounds(lhs);
> +        if (rhs instanceof WildcardType) {
> +            // oh boy, this scenario requires checking a lot of
> assignability!
> +            final WildcardType rhsType = (WildcardType) rhs;
> +            final Type[] rhsUpperBounds =
> getEffectiveUpperBounds(rhsType);
> +            final Type[] rhsLowerBounds =
> getEffectiveLowerBounds(rhsType);
> +            for (final Type lhsUpperBound : lhsUpperBounds) {
> +                for (final Type rhsUpperBound : rhsUpperBounds) {
> +                    if (!isBoundAssignable(lhsUpperBound, rhsUpperBound))
> {
> +                        return false;
> +                    }
> +                }
> +                for (final Type rhsLowerBound : rhsLowerBounds) {
> +                    if (!isBoundAssignable(lhsUpperBound, rhsLowerBound))
> {
> +                        return false;
> +                    }
> +                }
> +            }
> +            for (final Type lhsLowerBound : lhsLowerBounds) {
> +                for (final Type rhsUpperBound : rhsUpperBounds) {
> +                    if (!isBoundAssignable(rhsUpperBound, lhsLowerBound))
> {
> +                        return false;
> +                    }
> +                }
> +                for (final Type rhsLowerBound : rhsLowerBounds) {
> +                    if (!isBoundAssignable(rhsLowerBound, lhsLowerBound))
> {
> +                        return false;
> +                    }
> +                }
> +            }
> +        } else {
> +            // phew, far less bounds to check
> +            for (final Type lhsUpperBound : lhsUpperBounds) {
> +                if (!isBoundAssignable(lhsUpperBound, rhs)) {
> +                    return false;
> +                }
> +            }
> +            for (final Type lhsLowerBound : lhsLowerBounds) {
> +                if (!isBoundAssignable(lhsLowerBound, rhs)) {
> +                    return false;
> +                }
> +            }
> +        }
> +        return true;
> +    }
> +
> +    private static Type[] getEffectiveUpperBounds(final WildcardType
> type) {
> +        final Type[] upperBounds = type.getUpperBounds();
> +        return upperBounds.length == 0 ? new Type[]{Object.class} :
> upperBounds;
> +    }
> +
> +    private static Type[] getEffectiveLowerBounds(final WildcardType
> type) {
> +        final Type[] lowerBounds = type.getLowerBounds();
> +        return lowerBounds.length == 0 ? new Type[]{null} : lowerBounds;
> +    }
> +
> +    private static boolean isBoundAssignable(final Type lhs, final Type
> rhs) {
> +        return (rhs == null) || ((lhs != null) && isAssignable(lhs, rhs));
> +    }
> +}
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
> similarity index 94%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
> index 4f6ddda..fae7580 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
> @@ -19,4 +19,4 @@
>   * Java annotation processor for pre-scanning Log4j 2 plugins. This is
> provided as an alternative to using the
>   * executable {@link
> org.apache.logging.log4j.core.config.plugins.util.PluginManager} class in
> your build process.
>   */
> -package org.apache.logging.log4j.core.config.plugins.processor;
> +package org.apache.logging.log4j.plugins.util;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
> similarity index 81%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
> index 0ac2223..4586315 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
> @@ -14,14 +14,9 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
>
> -import java.lang.annotation.Annotation;
> -import java.lang.annotation.Documented;
> -import java.lang.annotation.ElementType;
> -import java.lang.annotation.Retention;
> -import java.lang.annotation.RetentionPolicy;
> -import java.lang.annotation.Target;
> +import java.lang.annotation.*;
>
>  /**
>   * Meta annotation to mark an annotation as a validation constraint. This
> annotation must specify a
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
> similarity index 96%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
> index 1d8c0c5..2f638a7 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
> @@ -14,7 +14,7 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
>
>  import java.lang.annotation.Annotation;
>
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
> similarity index 93%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
> index 374c8ec..6236bb6 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
> @@ -14,7 +14,9 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
> +
> +import org.apache.logging.log4j.util.ReflectionUtil;
>
>  import java.lang.annotation.Annotation;
>  import java.lang.reflect.ParameterizedType;
> @@ -22,8 +24,6 @@ import java.lang.reflect.Type;
>  import java.util.ArrayList;
>  import java.util.Collection;
>
> -import org.apache.logging.log4j.core.util.ReflectionUtil;
> -
>  /**
>   * Utility class to locate an appropriate {@link ConstraintValidator}
> implementation for an annotation.
>   *
> @@ -36,7 +36,7 @@ public final class ConstraintValidators {
>
>      /**
>       * Finds all relevant {@link ConstraintValidator} objects from an
> array of annotations. All validators will be
> -     * {@link
> ConstraintValidator#initialize(java.lang.annotation.Annotation)
> initialized} before being returned.
> +     * {@link ConstraintValidator#initialize(Annotation) initialized}
> before being returned.
>       *
>       * @param annotations the annotations to find constraint validators
> for
>       * @return a collection of ConstraintValidators for the given
> annotations
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
> similarity index 73%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
> index e6f3c56..9b8a75d 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
> @@ -15,16 +15,12 @@
>   * limitations under the license.
>   */
>
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +package org.apache.logging.log4j.plugins.validation.constraints;
>
> -import java.lang.annotation.Documented;
> -import java.lang.annotation.ElementType;
> -import java.lang.annotation.Retention;
> -import java.lang.annotation.RetentionPolicy;
> -import java.lang.annotation.Target;
> +import org.apache.logging.log4j.plugins.validation.Constraint;
> +import
> org.apache.logging.log4j.plugins.validation.validators.RequiredValidator;
>
> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.validators.RequiredValidator;
> +import java.lang.annotation.*;
>
>  /**
>   * Marks a plugin builder field or plugin factory parameter as required.
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
> similarity index 84%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
> index c652d40..14dd9a8 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
> @@ -14,10 +14,10 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +package org.apache.logging.log4j.plugins.validation.constraints;
>
> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.validators.ValidHostValidator;
> +import org.apache.logging.log4j.plugins.validation.Constraint;
> +import
> org.apache.logging.log4j.plugins.validation.validators.ValidHostValidator;
>
>  import java.lang.annotation.*;
>  import java.net.InetAddress;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
> similarity index 74%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
> index a7c68b1..c4aba16 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
> @@ -14,16 +14,12 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +package org.apache.logging.log4j.plugins.validation.constraints;
>
> -import java.lang.annotation.Documented;
> -import java.lang.annotation.ElementType;
> -import java.lang.annotation.Retention;
> -import java.lang.annotation.RetentionPolicy;
> -import java.lang.annotation.Target;
> +import org.apache.logging.log4j.plugins.validation.Constraint;
> +import
> org.apache.logging.log4j.plugins.validation.validators.ValidPortValidator;
>
> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.validators.ValidPortValidator;
> +import java.lang.annotation.*;
>
>  /**
>   * Indicates that a plugin attribute must be a valid port number. A valid
> port number is an integer between 0 and
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
> similarity index 91%
> copy from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> copy to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
> index f22ba49..298cd5a 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
> @@ -20,4 +20,4 @@
>   *
>   * @since 2.1
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +package org.apache.logging.log4j.plugins.validation.constraints;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
> similarity index 93%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
> index 171b25a..15955cb 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
> @@ -20,4 +20,4 @@
>   *
>   * @since 2.1
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
> similarity index 86%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
> index 98c0a71..9df6d3b 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
> @@ -14,17 +14,17 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.validators;
> -
> -import java.util.Collection;
> -import java.util.Map;
> +package org.apache.logging.log4j.plugins.validation.validators;
>
>  import org.apache.logging.log4j.Logger;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
> -import org.apache.logging.log4j.core.util.Assert;
> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
> +import org.apache.logging.log4j.util.Assert;
>  import org.apache.logging.log4j.status.StatusLogger;
>
> +import java.util.Collection;
> +import java.util.Map;
> +
>  /**
>   * Validator that checks an object for emptiness. Emptiness is defined
> here as:
>   * <ul>
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
> similarity index 89%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
> index 6c01753..41abbfd 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
> @@ -14,11 +14,11 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.validators;
> +package org.apache.logging.log4j.plugins.validation.validators;
>
>  import org.apache.logging.log4j.Logger;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
> +import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
>  import org.apache.logging.log4j.status.StatusLogger;
>
>  import java.net.InetAddress;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
> similarity index 85%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
> index a59742c..27e97f0 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
> @@ -14,12 +14,12 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.validators;
> +package org.apache.logging.log4j.plugins.validation.validators;
>
>  import org.apache.logging.log4j.Logger;
> -import
> org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
> +import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
> +import org.apache.logging.log4j.plugins.convert.TypeConverters;
>  import org.apache.logging.log4j.status.StatusLogger;
>
>  /**
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
> similarity index 92%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
> index a8ac560..cfe2041 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
> @@ -20,4 +20,4 @@
>   *
>   * @since 2.1
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.validators;
> +package org.apache.logging.log4j.plugins.validation.validators;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
> similarity index 84%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
> index 560cbe3..b98dc09 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
> @@ -15,18 +15,18 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.visitors;
> +package org.apache.logging.log4j.plugins.visitors;
> +
> +import org.apache.logging.log4j.Logger;
> +import org.apache.logging.log4j.plugins.convert.TypeConverters;
> +import org.apache.logging.log4j.status.StatusLogger;
> +import org.apache.logging.log4j.util.Strings;
>
>  import java.lang.annotation.Annotation;
>  import java.lang.reflect.Member;
>  import java.util.Map;
>  import java.util.Objects;
> -
> -import org.apache.logging.log4j.Logger;
> -import
> org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
> -import org.apache.logging.log4j.core.lookup.StrSubstitutor;
> -import org.apache.logging.log4j.status.StatusLogger;
> -import org.apache.logging.log4j.util.Strings;
> +import java.util.function.Function;
>
>  /**
>   * Base class for PluginVisitor implementations. Provides convenience
> methods as well as all method implementations
> @@ -34,7 +34,7 @@ import org.apache.logging.log4j.util.Strings;
>   *
>   * @param <A> the Plugin annotation type.
>   */
> -public abstract class AbstractPluginVisitor<A extends Annotation>
> implements PluginVisitor<A> {
> +public abstract class AbstractPluginVisitor<A extends Annotation, T>
> implements PluginVisitor<A, T> {
>
>      /** Status logger. */
>      protected static final Logger LOGGER = StatusLogger.getLogger();
> @@ -58,10 +58,6 @@ public abstract class AbstractPluginVisitor<A extends
> Annotation> implements Plu
>      /**
>       *
>       */
> -    protected StrSubstitutor substitutor;
> -    /**
> -     *
> -     */
>      protected Member member;
>
>      /**
> @@ -75,7 +71,7 @@ public abstract class AbstractPluginVisitor<A extends
> Annotation> implements Plu
>
>      @SuppressWarnings("unchecked")
>      @Override
> -    public PluginVisitor<A> setAnnotation(final Annotation anAnnotation) {
> +    public PluginVisitor<A, T> setAnnotation(final Annotation
> anAnnotation) {
>          final Annotation a = Objects.requireNonNull(anAnnotation, "No
> annotation was provided");
>          if (this.clazz.isInstance(a)) {
>              this.annotation = (A) a;
> @@ -84,25 +80,19 @@ public abstract class AbstractPluginVisitor<A extends
> Annotation> implements Plu
>      }
>
>      @Override
> -    public PluginVisitor<A> setAliases(final String... someAliases) {
> +    public PluginVisitor<A, T> setAliases(final String... someAliases) {
>          this.aliases = someAliases;
>          return this;
>      }
>
>      @Override
> -    public PluginVisitor<A> setConversionType(final Class<?>
> aConversionType) {
> +    public PluginVisitor<A, T> setConversionType(final Class<?>
> aConversionType) {
>          this.conversionType = Objects.requireNonNull(aConversionType, "No
> conversion type class was provided");
>          return this;
>      }
>
>      @Override
> -    public PluginVisitor<A> setStrSubstitutor(final StrSubstitutor
> aSubstitutor) {
> -        this.substitutor = Objects.requireNonNull(aSubstitutor, "No
> StrSubstitutor was provided");
> -        return this;
> -    }
> -
> -    @Override
> -    public PluginVisitor<A> setMember(final Member aMember) {
> +    public PluginVisitor<A, T> setMember(final Member aMember) {
>          this.member = aMember;
>          return this;
>      }
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
> similarity index 80%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
> index f4da42b..fbd28b9 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
> @@ -15,40 +15,39 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.visitors;
> +package org.apache.logging.log4j.plugins.visitors;
>
> -import java.util.Map;
> -
> -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.PluginAttribute;
> -import org.apache.logging.log4j.core.util.NameUtil;
> +import org.apache.logging.log4j.plugins.Node;
> +import org.apache.logging.log4j.plugins.PluginAttribute;
> +import org.apache.logging.log4j.util.NameUtil;
>  import org.apache.logging.log4j.util.StringBuilders;
>
> +import java.util.Map;
> +import java.util.function.Function;
> +
>  /**
>   * PluginVisitor implementation for {@link PluginAttribute}.
>   */
> -public class PluginAttributeVisitor extends
> AbstractPluginVisitor<PluginAttribute> {
> +public class PluginAttributeVisitor extends
> AbstractPluginVisitor<PluginAttribute, Object> {
>      public PluginAttributeVisitor() {
>          super(PluginAttribute.class);
>      }
>
>      @Override
> -    public Object visit(final Configuration configuration, final Node
> node, final LogEvent event,
> +    public Object visit(final Object unused, final Node node, final
> Function<String, String> substitutor,
>                          final StringBuilder log) {
>          final String name = this.annotation.value();
>          final Map<String, String> attributes = node.getAttributes();
>          final String rawValue = removeAttributeValue(attributes, name,
> this.aliases);
> -        final String replacedValue = this.substitutor.replace(event,
> rawValue);
> -        final Object defaultValue = findDefaultValue(event);
> +        final String replacedValue = substitutor.apply(rawValue);
> +        final Object defaultValue = findDefaultValue(substitutor);
>          final Object value = convert(replacedValue, defaultValue);
>          final Object debugValue = this.annotation.sensitive() ?
> NameUtil.md5(value + this.getClass().getName()) : value;
>          StringBuilders.appendKeyDqValue(log, name, debugValue);
>          return value;
>      }
>
> -    private Object findDefaultValue(final LogEvent event) {
> +    private Object findDefaultValue(Function<String, String> substitutor)
> {
>          if (this.conversionType == int.class || this.conversionType ==
> Integer.class) {
>              return this.annotation.defaultInt();
>          }
> @@ -76,6 +75,6 @@ public class PluginAttributeVisitor extends
> AbstractPluginVisitor<PluginAttribut
>          if (this.conversionType == Class.class) {
>              return this.annotation.defaultClass();
>          }
> -        return this.substitutor.replace(event,
> this.annotation.defaultString());
> +        return substitutor.apply(this.annotation.defaultString());
>      }
>  }
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
> similarity index 74%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
> index e951456..398ff1c 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
> @@ -15,38 +15,37 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.visitors;
> +package org.apache.logging.log4j.plugins.visitors;
>
> -import java.util.Map;
> -
> -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.PluginBuilderAttribute;
> -import org.apache.logging.log4j.core.util.NameUtil;
> +import org.apache.logging.log4j.plugins.Node;
> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
> +import org.apache.logging.log4j.util.NameUtil;
>  import org.apache.logging.log4j.util.StringBuilders;
>
> +import java.util.Map;
> +import java.util.function.Function;
> +
>  /**
>   * PluginVisitor for PluginBuilderAttribute. If {@code null} is returned
> for the
> - * {@link #visit(org.apache.logging.log4j.core.config.Configuration,
> org.apache.logging.log4j.core.config.Node,
> org.apache.logging.log4j.core.LogEvent, StringBuilder)}
> + * {@link #visit(org.apache.logging.log4j.core.config.Configuration,
> org.apache.logging.log4j.plugins.Node,
> org.apache.logging.log4j.core.LogEvent, StringBuilder)}
>   * method, then the default value of the field should remain untouched.
>   *
>   * @see org.apache.logging.log4j.core.config.plugins.util.PluginBuilder
>   */
> -public class PluginBuilderAttributeVisitor extends
> AbstractPluginVisitor<PluginBuilderAttribute> {
> +public class PluginBuilderAttributeVisitor extends
> AbstractPluginVisitor<PluginBuilderAttribute, Object> {
>
>      public PluginBuilderAttributeVisitor() {
>          super(PluginBuilderAttribute.class);
>      }
>
>      @Override
> -    public Object visit(final Configuration configuration, final Node
> node, final LogEvent event,
> +    public Object visit(final Object unused, final Node node, final
> Function<String, String> substitutor,
>                          final StringBuilder log) {
>          final String overridden = this.annotation.value();
>          final String name = overridden.isEmpty() ? this.member.getName()
> : overridden;
>          final Map<String, String> attributes = node.getAttributes();
>          final String rawValue = removeAttributeValue(attributes, name,
> this.aliases);
> -        final String replacedValue = this.substitutor.replace(event,
> rawValue);
> +        final String replacedValue = substitutor.apply(rawValue);
>          final Object value = convert(replacedValue, null);
>          final Object debugValue = this.annotation.sensitive() ?
> NameUtil.md5(value + this.getClass().getName()) : value;
>          StringBuilders.appendKeyDqValue(log, name, debugValue);
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
> similarity index 90%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
> index 2e6e6ef..f8197f1 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
> @@ -15,30 +15,29 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.visitors;
> +package org.apache.logging.log4j.plugins.visitors;
> +
> +import org.apache.logging.log4j.plugins.Node;
> +import org.apache.logging.log4j.plugins.PluginElement;
> +import org.apache.logging.log4j.plugins.util.PluginType;
>
>  import java.lang.reflect.Array;
>  import java.util.ArrayList;
>  import java.util.Arrays;
>  import java.util.Collection;
>  import java.util.List;
> -
> -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.PluginElement;
> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
> +import java.util.function.Function;
>
>  /**
>   * PluginVisitor implementation for {@link PluginElement}. Supports
> arrays as well as singular values.
>   */
> -public class PluginElementVisitor extends
> AbstractPluginVisitor<PluginElement> {
> +public class PluginElementVisitor extends
> AbstractPluginVisitor<PluginElement, Object> {
>      public PluginElementVisitor() {
>          super(PluginElement.class);
>      }
>
>      @Override
> -    public Object visit(final Configuration configuration, final Node
> node, final LogEvent event,
> +    public Object visit(final Object unused, final Node node, final
> Function<String, String> substitutor,
>                          final StringBuilder log) {
>          final String name = this.annotation.value();
>          if (this.conversionType.isArray()) {
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
> similarity index 77%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
> index 7f15392..9438b39 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
> @@ -15,23 +15,23 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.visitors;
> +package org.apache.logging.log4j.plugins.visitors;
>
> -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.PluginNode;
> +import org.apache.logging.log4j.plugins.Node;
> +import org.apache.logging.log4j.plugins.PluginNode;
> +
> +import java.util.function.Function;
>
>  /**
>   * PluginVisitor implementation for {@link PluginNode}.
>   */
> -public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode> {
> +public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode,
> Object> {
>      public PluginNodeVisitor() {
>          super(PluginNode.class);
>      }
>
>      @Override
> -    public Object visit(final Configuration configuration, final Node
> node, final LogEvent event,
> +    public Object visit(final Object unused, final Node node, final
> Function<String, String> substitutor,
>                          final StringBuilder log) {
>          if (this.conversionType.isInstance(node)) {
>              log.append("Node=").append(node.getName());
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
> similarity index 79%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
> index 8544570..2f68f04 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
> @@ -15,26 +15,26 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.visitors;
> +package org.apache.logging.log4j.plugins.visitors;
>
> -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.PluginValue;
> +import org.apache.logging.log4j.plugins.Node;
> +import org.apache.logging.log4j.plugins.PluginValue;
>  import org.apache.logging.log4j.util.StringBuilders;
>  import org.apache.logging.log4j.util.Strings;
>
> +import java.util.function.Function;
> +
>  /**
>   * PluginVisitor implementation for {@link PluginValue}.
>   */
> -public class PluginValueVisitor extends
> AbstractPluginVisitor<PluginValue> {
> +public class PluginValueVisitor extends
> AbstractPluginVisitor<PluginValue, Object> {
>      public PluginValueVisitor() {
>          super(PluginValue.class);
>      }
>
>      @Override
> -    public Object visit(final Configuration configuration, final Node
> node, final LogEvent event,
> -            final StringBuilder log) {
> +    public Object visit(final Object unused, final Node node, final
> Function<String, String> substitutor,
> +                        final StringBuilder log) {
>          final String name = this.annotation.value();
>          final String elementValue = node.getValue();
>          final String attributeValue = node.getAttributes().get("value");
> @@ -49,7 +49,7 @@ public class PluginValueVisitor extends
> AbstractPluginVisitor<PluginValue> {
>          } else {
>              rawValue = removeAttributeValue(node.getAttributes(),
> "value");
>          }
> -        final String value = this.substitutor.replace(event, rawValue);
> +        final String value = substitutor.apply(rawValue);
>          StringBuilders.appendKeyDqValue(log, name, value);
>          return value;
>      }
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
> similarity index 68%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
> index 34e2b78..fb7aca4 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
> @@ -15,15 +15,13 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.visitors;
> +package org.apache.logging.log4j.plugins.visitors;
> +
> +import org.apache.logging.log4j.plugins.Node;
>
>  import java.lang.annotation.Annotation;
>  import java.lang.reflect.Member;
> -
> -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.lookup.StrSubstitutor;
> +import java.util.function.Function;
>
>  /**
>   * Visitor strategy for parsing data from a {@link Node}, doing any
> relevant type conversion, and returning a
> @@ -31,7 +29,7 @@ import
> org.apache.logging.log4j.core.lookup.StrSubstitutor;
>   *
>   * @param <A> the Annotation type.
>   */
> -public interface PluginVisitor<A extends Annotation> {
> +public interface PluginVisitor<A extends Annotation, T> {
>
>      /**
>       * Sets the Annotation to be used for this. If the given Annotation
> is not compatible with this class's type, then
> @@ -41,7 +39,7 @@ public interface PluginVisitor<A extends Annotation> {
>       * @return {@code this}.
>       * @throws NullPointerException if the argument is {@code null}.
>       */
> -    PluginVisitor<A> setAnnotation(Annotation annotation);
> +    PluginVisitor<A, T> setAnnotation(Annotation annotation);
>
>      /**
>       * Sets the list of aliases to use for this visit. No aliases are
> required, however.
> @@ -49,7 +47,7 @@ public interface PluginVisitor<A extends Annotation> {
>       * @param aliases the list of aliases to use.
>       * @return {@code this}.
>       */
> -    PluginVisitor<A> setAliases(String... aliases);
> +    PluginVisitor<A, T> setAliases(String... aliases);
>
>      /**
>       * Sets the class to convert the plugin value to on this visit. This
> should correspond with a class obtained from
> @@ -59,17 +57,7 @@ public interface PluginVisitor<A extends Annotation> {
>       * @return {@code this}.
>       * @throws NullPointerException if the argument is {@code null}.
>       */
> -    PluginVisitor<A> setConversionType(Class<?> conversionType);
> -
> -    /**
> -     * Sets the StrSubstitutor to use for converting raw strings before
> type conversion. Generally obtained from a
> -     * {@link org.apache.logging.log4j.core.config.Configuration}.
> -     *
> -     * @param substitutor the StrSubstitutor to use on plugin values.
> -     * @return {@code this}.
> -     * @throws NullPointerException if the argument is {@code null}.
> -     */
> -    PluginVisitor<A> setStrSubstitutor(StrSubstitutor substitutor);
> +    PluginVisitor<A, T> setConversionType(Class<?> conversionType);
>
>      /**
>       * Sets the Member that this visitor is being used for injection
> upon. For instance, this could be the Field
> @@ -79,16 +67,16 @@ public interface PluginVisitor<A extends Annotation> {
>       * @param member the member this visitor is parsing a value for.
>       * @return {@code this}.
>       */
> -    PluginVisitor<A> setMember(Member member);
> +    PluginVisitor<A, T> setMember(Member member);
>
>      /**
>       * Visits a Node to obtain a value for constructing a Plugin object.
>       *
>       * @param configuration the current Configuration.
>       * @param node          the current Node corresponding to the Plugin
> object being created.
> -     * @param event         the current LogEvent that caused this Plugin
> object to be made (optional).
> -     * @param log           the StringBuilder being used to build a debug
> message.
> +     * @param substitutor   the function to perform String substitutions.
> +     * @param log           th e StringBuilder being used to build a
> debug message.
>       * @return the converted value to be used for Plugin creation.
>       */
> -    Object visit(Configuration configuration, Node node, LogEvent event,
> StringBuilder log);
> +    Object visit(T configuration, Node node, Function<String, String>
> substitutor, StringBuilder log);
>  }
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
> similarity index 86%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
> index 10ee0df..695d387 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
> @@ -15,14 +15,14 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.visitors;
> -
> -import java.lang.annotation.Annotation;
> +package org.apache.logging.log4j.plugins.visitors;
>
>  import org.apache.logging.log4j.Logger;
> -import org.apache.logging.log4j.core.config.plugins.PluginVisitorStrategy;
> +import org.apache.logging.log4j.plugins.PluginVisitorStrategy;
>  import org.apache.logging.log4j.status.StatusLogger;
>
> +import java.lang.annotation.Annotation;
> +
>  /**
>   * Utility class to locate an appropriate {@link PluginVisitor}
> implementation for an annotation.
>   */
> @@ -41,13 +41,13 @@ public final class PluginVisitors {
>       * @param annotation the Plugin annotation class to find a
> PluginVisitor for.
>       * @return a PluginVisitor instance if one could be created, or
> {@code null} otherwise.
>       */
> -    public static PluginVisitor<? extends Annotation> findVisitor(final
> Class<? extends Annotation> annotation) {
> +    public static <T> PluginVisitor<? extends Annotation, T>
> findVisitor(final Class<? extends Annotation> annotation) {
>          final PluginVisitorStrategy strategy =
> annotation.getAnnotation(PluginVisitorStrategy.class);
>          if (strategy == null) {
>              return null;
>          }
>          try {
> -            return strategy.value().newInstance();
> +            return (PluginVisitor<? extends Annotation, T>)
> strategy.value().newInstance();
>          } catch (final Exception e) {
>              LOGGER.error("Error loading PluginVisitor [{}] for annotation
> [{}].", strategy.value(), annotation, e);
>              return null;
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
> similarity index 67%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> rename to
> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
> index f22ba49..0855b16 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
> +++
> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
> @@ -16,8 +16,9 @@
>   */
>
>  /**
> - * Validation annotations.
> - *
> - * @since 2.1
> + * Visitor classes for extracting values from a Configuration or Node
> corresponding to a plugin annotation.
> + * Visitor implementations must implement {@link
> org.apache.logging.log4j.plugins.visitors.PluginVisitor},
> + * and the corresponding annotation must be annotated with
> + * {@link org.apache.logging.log4j.plugins.PluginVisitorStrategy}.
>   */
> -package
> org.apache.logging.log4j.core.config.plugins.validation.constraints;
> +package org.apache.logging.log4j.plugins.visitors;
> diff --git
> a/log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
> b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
> similarity index 91%
> rename from
> log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
> rename to
> log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
> index bb9dcb9..5d6951a 100644
> ---
> a/log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
> +++
> b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
> @@ -14,4 +14,4 @@
>  # See the license for the specific language governing permissions and
>  # limitations under the license.
>  #
> -org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor
> +org.apache.logging.log4j.plugins.processor.PluginProcessor
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
> similarity index 97%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
> index f9e757d..6e4b059 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
> @@ -14,7 +14,7 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.convert;
> +package org.apache.logging.log4j.plugins.convert;
>
>  import org.junit.Test;
>
> @@ -63,7 +63,7 @@ public class TypeConverterRegistryTest {
>          // TODO: is there a specific converter this should return?
>      }
>
> -    public static enum Foo {
> +    public enum Foo {
>          I, PITY, THE
>      }
>
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
> similarity index 84%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
> index f4ceb41..48ea7dc 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
> @@ -15,10 +15,10 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.processor;
> +package org.apache.logging.log4j.plugins.processor;
>
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
> +import org.apache.logging.log4j.plugins.Plugin;
> +import org.apache.logging.log4j.plugins.PluginAliases;
>
>  /**
>   * Test plugin class for unit tests.
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
> similarity index 75%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
> index 9c37af4..034705c 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
> @@ -15,17 +15,19 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.processor;
> +package org.apache.logging.log4j.plugins.processor;
>
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
> +import org.apache.logging.log4j.plugins.Plugin;
> +import org.apache.logging.log4j.plugins.PluginAliases;
>  import org.junit.BeforeClass;
>  import org.junit.Test;
>  import org.junit.runner.RunWith;
>  import org.junit.runners.JUnit4;
>
>  import java.net.URL;
> +import java.util.ArrayList;
>  import java.util.Enumeration;
> +import java.util.List;
>  import java.util.Map;
>
>  import static org.junit.Assert.*;
> @@ -33,29 +35,29 @@ import static org.junit.Assert.*;
>  @RunWith(JUnit4.class)
>  public class PluginProcessorTest {
>
> -    private static final PluginCache pluginCache = new PluginCache();
> +    private static PluginService pluginService;
>
>      private final Plugin p = FakePlugin.class.getAnnotation(Plugin.class);
>
>      @BeforeClass
>      public static void setUpClass() throws Exception {
> -        final Enumeration<URL> resources =
> -
> PluginProcessor.class.getClassLoader().getResources(PluginProcessor.PLUGIN_CACHE_FILE);
> -        pluginCache.loadCacheFiles(resources);
> +        Class<?> clazz =
> PluginProcessor.class.getClassLoader().loadClass("org.apache.logging.log4j.plugins.plugins.Log4jPlugins");
> +        assertNotNull("Could not locate plugins class", clazz);
> +        pluginService = (PluginService)
> clazz.getDeclaredConstructor().newInstance();;
>      }
>
>      @Test
>      public void testTestCategoryFound() throws Exception {
>          assertNotNull("No plugin annotation on FakePlugin.", p);
> -        final Map<String, PluginEntry> testCategory =
> pluginCache.getCategory(p.category());
> -        assertNotEquals("No plugins were found.", 0, pluginCache.size());
> +        final Map<String, PluginEntry> testCategory =
> pluginService.getCategory(p.category());
> +        assertNotEquals("No plugins were found.", 0,
> pluginService.size());
>          assertNotNull("The category '" + p.category() + "' was not
> found.", testCategory);
>          assertFalse(testCategory.isEmpty());
>      }
>
>      @Test
>      public void testFakePluginFoundWithCorrectInformation() throws
> Exception {
> -        final PluginEntry fake =
> pluginCache.getCategory(p.category()).get(p.name().toLowerCase());
> +        final PluginEntry fake =
> pluginService.getCategory(p.category()).get(p.name().toLowerCase());
>          verifyFakePluginEntry(p.name(), fake);
>      }
>
> @@ -63,7 +65,7 @@ public class PluginProcessorTest {
>      public void testFakePluginAliasesContainSameInformation() throws
> Exception {
>          final PluginAliases aliases =
> FakePlugin.class.getAnnotation(PluginAliases.class);
>          for (final String alias : aliases.value()) {
> -            final PluginEntry fake =
> pluginCache.getCategory(p.category()).get(alias.toLowerCase());
> +            final PluginEntry fake =
> pluginService.getCategory(p.category()).get(alias.toLowerCase());
>              verifyFakePluginEntry(alias, fake);
>          }
>      }
> @@ -81,7 +83,7 @@ public class PluginProcessorTest {
>      @Test
>      public void testNestedPlugin() throws Exception {
>          final Plugin p =
> FakePlugin.Nested.class.getAnnotation(Plugin.class);
> -        final PluginEntry nested =
> pluginCache.getCategory(p.category()).get(p.name().toLowerCase());
> +        final PluginEntry nested =
> pluginService.getCategory(p.category()).get(p.name().toLowerCase());
>          assertNotNull(nested);
>          assertEquals(p.name().toLowerCase(), nested.getKey());
>          assertEquals(FakePlugin.Nested.class.getName(),
> nested.getClassName());
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
> similarity index 93%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
> index 33e0ee1..d0b35d1 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
> @@ -15,27 +15,21 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.util;
> +package org.apache.logging.log4j.plugins.util;
>
> -import static org.junit.Assert.assertEquals;
> +import org.apache.logging.log4j.junit.CleanFolders;
> +import org.apache.logging.log4j.junit.URLStreamHandlerFactoryRule;
> +import org.junit.Rule;
> +import org.junit.Test;
> +import org.junit.rules.RuleChain;
>
>  import java.io.IOException;
> -import java.net.Proxy;
> -import java.net.URL;
> -import java.net.URLClassLoader;
> -import java.net.URLConnection;
> -import java.net.URLStreamHandler;
> -import java.net.URLStreamHandlerFactory;
> +import java.net.*;
>  import java.util.Arrays;
>  import java.util.Collections;
>  import java.util.Enumeration;
>
> -import
> org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest;
> -import org.apache.logging.log4j.junit.CleanFolders;
> -import org.apache.logging.log4j.junit.URLStreamHandlerFactoryRule;
> -import org.junit.Rule;
> -import org.junit.Test;
> -import org.junit.rules.RuleChain;
> +import static org.junit.Assert.assertEquals;
>
>  /**
>   * Tests the ResolverUtil class for custom protocol like bundleresource,
> vfs, vfszip.
> @@ -187,9 +181,9 @@ public class ResolverUtilCustomProtocolTest {
>              final ResolverUtil resolverUtil = new ResolverUtil();
>              resolverUtil
>                      .setClassLoader(new SingleURLClassLoader(new
> URL("vfs:/" + ResolverUtilTest.WORK_DIR + "/resolverutil3/customplugin3/"),
> cl));
> -            resolverUtil.findInPackage(new PluginTest(), "customplugin3");
> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
> "customplugin3");
>              assertEquals("Class not found in packages", 1,
> resolverUtil.getClasses().size());
> -            assertEquals("Unexpected class resolved",
> cl.loadClass("customplugin3.FixedString3Layout"),
> +            assertEquals("Unexpected class resolved",
> cl.loadClass("customplugin3.FixedString3"),
>                      resolverUtil.getClasses().iterator().next());
>          }
>      }
> @@ -200,9 +194,9 @@ public class ResolverUtilCustomProtocolTest {
>              final ResolverUtil resolverUtil = new ResolverUtil();
>              resolverUtil.setClassLoader(new SingleURLClassLoader(
>                      new URL("vfs:/" + ResolverUtilTest.WORK_DIR +
> "/resolverutil4/customplugin4.jar/customplugin4/"), cl));
> -            resolverUtil.findInPackage(new PluginTest(), "customplugin4");
> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
> "customplugin4");
>              assertEquals("Class not found in packages", 1,
> resolverUtil.getClasses().size());
> -            assertEquals("Unexpected class resolved",
> cl.loadClass("customplugin4.FixedString4Layout"),
> +            assertEquals("Unexpected class resolved",
> cl.loadClass("customplugin4.FixedString4"),
>                      resolverUtil.getClasses().iterator().next());
>          }
>      }
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
> similarity index 82%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
> index 1c6371b..361fe7b 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
> @@ -15,33 +15,25 @@
>   * limitations under the license.
>   */
>
> -package org.apache.logging.log4j.core.config.plugins.util;
> +package org.apache.logging.log4j.plugins.util;
>
> -import static org.junit.Assert.assertEquals;
> -import static org.junit.Assert.assertTrue;
> -
> -import java.io.File;
> -import java.io.IOException;
> -import java.io.UnsupportedEncodingException;
> -import java.net.MalformedURLException;
> -import java.net.URI;
> -import java.net.URISyntaxException;
> -import java.net.URL;
> -import java.net.URLClassLoader;
> -import java.nio.file.FileSystem;
> -import java.nio.file.FileSystems;
> -import java.nio.file.Files;
> -import java.nio.file.Path;
> -import java.nio.file.StandardCopyOption;
> -import java.util.HashMap;
> -import java.util.Map;
> -
> -import
> org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest;
>  import org.apache.logging.log4j.junit.CleanFolders;
>  import org.junit.Rule;
>  import org.junit.Test;
>  import org.junit.rules.RuleChain;
>
> +import javax.tools.*;
> +import java.io.File;
> +import java.io.IOException;
> +import java.io.UnsupportedEncodingException;
> +import java.net.*;
> +import java.nio.file.*;
> +import java.util.*;
> +
> +import static org.junit.Assert.assertEquals;
> +import static org.junit.Assert.assertTrue;
> +import static org.junit.Assert.assertNotNull;
> +
>  /**
>   * Tests the ResolverUtil class.
>   */
> @@ -67,6 +59,7 @@ public class ResolverUtilTest {
>      private void testExtractPathFromJarUrlNotDecodedIfFileExists(final
> String existingFile)
>              throws MalformedURLException, UnsupportedEncodingException,
> URISyntaxException {
>          URL url = ResolverUtilTest.class.getResource(existingFile);
> +        assertNotNull("No url returned for " + existingFile, url);
>          if (!url.getProtocol().equals("jar")) {
>              // create fake jar: URL that resolves to existing file
>              url = new URL("jar:" + url.toExternalForm() + "!/some/entry");
> @@ -152,9 +145,9 @@ public class ResolverUtilTest {
>          try (final URLClassLoader cl = compileAndCreateClassLoader("1")) {
>              final ResolverUtil resolverUtil = new ResolverUtil();
>              resolverUtil.setClassLoader(cl);
> -            resolverUtil.findInPackage(new PluginTest(), "customplugin1");
> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
> "customplugin1");
>              assertEquals("Class not found in packages", 1,
> resolverUtil.getClasses().size());
> -            assertEquals("Unexpected class resolved",
> cl.loadClass("customplugin1.FixedString1Layout"),
> +            assertEquals("Unexpected class resolved",
> cl.loadClass("customplugin1.FixedString1"),
>                      resolverUtil.getClasses().iterator().next());
>          }
>      }
> @@ -164,9 +157,9 @@ public class ResolverUtilTest {
>          try (final URLClassLoader cl =
> compileJarAndCreateClassLoader("2")) {
>              final ResolverUtil resolverUtil = new ResolverUtil();
>              resolverUtil.setClassLoader(cl);
> -            resolverUtil.findInPackage(new PluginTest(), "customplugin2");
> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
> "customplugin2");
>              assertEquals("Class not found in packages", 1,
> resolverUtil.getClasses().size());
> -            assertEquals("Unexpected class resolved",
> cl.loadClass("customplugin2.FixedString2Layout"),
> +            assertEquals("Unexpected class resolved",
> cl.loadClass("customplugin2.FixedString2"),
>                      resolverUtil.getClasses().iterator().next());
>          }
>      }
> @@ -176,7 +169,7 @@ public class ResolverUtilTest {
>          final File jarFile = new File(workDir, "customplugin" + suffix +
> ".jar");
>          final URI jarURI = jarFile.toURI();
>          createJar(jarURI, workDir, new File(workDir,
> -              "customplugin" + suffix + "/FixedString" + suffix +
> "Layout.class"));
> +              "customplugin" + suffix + "/FixedString" + suffix +
> ".class"));
>          return URLClassLoader.newInstance(new URL[] {jarURI.toURL()});
>      }
>
> @@ -186,9 +179,9 @@ public class ResolverUtilTest {
>      }
>
>      static File compile(final String suffix) throws IOException {
> -        final File orig = new
> File("target/test-classes/customplugin/FixedStringLayout.java.source");
> +        final File orig = new
> File("target/test-classes/customplugin/FixedString.java.source");
>          final File workDir = new File(WORK_DIR, "resolverutil" + suffix);
> -        final File f = new File(workDir, "customplugin" + suffix +
> "/FixedString" + suffix + "Layout.java");
> +        final File f = new File(workDir, "customplugin" + suffix +
> "/FixedString" + suffix + ".java");
>          final File parent = f.getParentFile();
>          if (!parent.exists()) {
>            assertTrue("Create customplugin" + suffix + " folder KO",
> f.getParentFile().mkdirs());
> @@ -199,7 +192,7 @@ public class ResolverUtilTest {
>            .replaceAll("customplugin", "customplugin" + suffix);
>          Files.write(f.toPath(), content.getBytes());
>
> -        PluginManagerPackagesTest.compile(f);
> +        compile(f);
>          return workDir;
>      }
>
> @@ -218,4 +211,29 @@ public class ResolverUtilTest {
>          }
>      }
>
> +    static void compile(final File f) throws IOException {
> +        // set up compiler
> +        final JavaCompiler compiler =
> ToolProvider.getSystemJavaCompiler();
> +        final DiagnosticCollector<JavaFileObject> diagnostics = new
> DiagnosticCollector<>();
> +        final List<String> errors = new ArrayList<>();
> +        try (final StandardJavaFileManager fileManager =
> compiler.getStandardFileManager(diagnostics, null, null)) {
> +            final Iterable<? extends JavaFileObject> compilationUnits =
> fileManager.getJavaFileObjectsFromFiles(Arrays
> +                .asList(f));
> +
> +            // compile generated source
> +            // (switch off annotation processing: no need to create
> Log4j2Plugins.dat)
> +            final List<String> options = Arrays.asList("-proc:none");
> +            compiler.getTask(null, fileManager, diagnostics, options,
> null, compilationUnits).call();
> +
> +            // check we don't have any compilation errors
> +            for (final Diagnostic<? extends JavaFileObject> diagnostic :
> diagnostics.getDiagnostics()) {
> +                if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
> +                    errors.add(String.format("Compile error at line %d,
> column %d: %s%n", diagnostic.getLineNumber(),
> +                        diagnostic.getColumnNumber(),
> diagnostic.getMessage(Locale.getDefault())));
> +                }
> +            }
> +        }
> +        assertTrue(errors.toString(), errors.isEmpty());
> +    }
> +
>  }
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
> similarity index 87%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
> index 5689e29..0e243f2 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
> @@ -14,10 +14,10 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
>
> -import
> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>
>  /**
>   *
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
> similarity index 78%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
> index 34123c0..626798e 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
> @@ -14,15 +14,15 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
>
> -import java.net.InetSocketAddress;
> +import org.apache.logging.log4j.plugins.PluginAttribute;
> +import org.apache.logging.log4j.plugins.PluginFactory;
> +import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
> +import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
> +import org.apache.logging.log4j.plugins.Plugin;
>
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
> +import java.net.InetSocketAddress;
>
>  @Plugin(name = "HostAndPort", category = "Test")
>  public class HostAndPort {
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
> similarity index 81%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
> index 3f2b15a..c3fe6c5 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
> @@ -14,18 +14,18 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
>
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import
> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
> -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
> -import
> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
> +import org.apache.logging.log4j.plugins.Plugin;
>
>  @Plugin(name = "PluginWithGenericSubclassFoo1Builder", category = "Test")
>  public class PluginWithGenericSubclassFoo1Builder extends
> AbstractPluginWithGenericBuilder {
>
>      public static class Builder<B extends Builder<B>> extends
> AbstractPluginWithGenericBuilder.Builder<B>
> -            implements
> org.apache.logging.log4j.core.util.Builder<PluginWithGenericSubclassFoo1Builder>
> {
> +            implements
> org.apache.logging.log4j.plugins.util.Builder<PluginWithGenericSubclassFoo1Builder>
> {
>
>          @PluginBuilderFactory
>          public static <B extends Builder<B>> B newBuilder() {
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
> similarity index 80%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
> index 95a4209..9caf453 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
> @@ -14,15 +14,15 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
>
> -import java.util.Objects;
> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
> +import org.apache.logging.log4j.plugins.PluginFactory;
> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
> +import org.apache.logging.log4j.plugins.Plugin;
>
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import
> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
> -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.validation.constraints.Required;
> +import java.util.Objects;
>
>  /**
>   *
> @@ -51,7 +51,7 @@ public class ValidatingPlugin {
>          return new Builder();
>      }
>
> -    public static class Builder implements
> org.apache.logging.log4j.core.util.Builder<ValidatingPlugin> {
> +    public static class Builder implements
> org.apache.logging.log4j.plugins.util.Builder<ValidatingPlugin> {
>
>          @PluginBuilderAttribute
>          @Required(message = "The name given by the builder is null")
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
> similarity index 80%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
> index 81b9d6f..b0bec53 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
> @@ -14,15 +14,16 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
>
> -import java.util.Objects;
> +import org.apache.logging.log4j.plugins.Plugin;
> +
> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
> +import org.apache.logging.log4j.plugins.PluginFactory;
> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import
> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
> -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.validation.constraints.Required;
> +import java.util.Objects;
>
>  /**
>   *
> @@ -51,7 +52,7 @@ public class ValidatingPluginWithGenericBuilder {
>          return new Builder<B>().asBuilder();
>      }
>
> -    public static class Builder<B extends Builder<B>> implements
> org.apache.logging.log4j.core.util.Builder<ValidatingPluginWithGenericBuilder>
> {
> +    public static class Builder<B extends Builder<B>> implements
> org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithGenericBuilder>
> {
>
>          @PluginBuilderAttribute
>          @Required(message = "The name given by the builder is null")
> diff --git
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
> similarity index 80%
> rename from
> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
> rename to
> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
> index 74a6477..256181c 100644
> ---
> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
> +++
> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
> @@ -14,15 +14,15 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.validation;
> +package org.apache.logging.log4j.plugins.validation;
>
> -import java.util.Objects;
> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
> +import org.apache.logging.log4j.plugins.PluginFactory;
> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
> +import org.apache.logging.log4j.plugins.Plugin;
>
> -import org.apache.logging.log4j.core.config.plugins.Plugin;
> -import
> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
> -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.validation.constraints.Required;
> +import java.util.Objects;
>
>  /**
>   *
> @@ -51,7 +51,7 @@ public class ValidatingPluginWithTypedBuilder {
>          return new Builder<>();
>      }
>
> -    public static class Builder<T> implements
> org.apache.logging.log4j.core.util.Builder<ValidatingPluginWithTypedBuilder>
> {
> +    public static class Builder<T> implements
> org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithTypedBuilder>
> {
>
>          @PluginBuilderAttribute
>          @Required(message = "The name given by the builder is null")
> diff --git
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
> b/log4j-plugins/src/test/resources/customplugin/FixedString.java.source
> similarity index 52%
> rename from
> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
> rename to
> log4j-plugins/src/test/resources/customplugin/FixedString.java.source
> index 15a162c..85a62ec 100644
> ---
> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
> +++ b/log4j-plugins/src/test/resources/customplugin/FixedString.java.source
> @@ -14,25 +14,32 @@
>   * See the license for the specific language governing permissions and
>   * limitations under the license.
>   */
> -package org.apache.logging.log4j.core.config.plugins.convert;
>
> -import org.apache.logging.log4j.util.EnglishEnums;
> +package customplugin;
>
> -/**
> - * Converts a {@link String} into a {@link Enum}. Returns {@code null}
> for invalid enum names.
> - *
> - * @param <E> the enum class to parse.
> - * @since 2.1 moved from TypeConverters
> - */
> -public class EnumConverter<E extends Enum<E>> implements TypeConverter<E>
> {
> -    private final Class<E> clazz;
> +import java.util.Collections;
> +import java.util.Map;
> +
> +import org.apache.logging.log4j.plugins.Plugin;
> +import org.apache.logging.log4j.plugins.PluginAttribute;
> +import org.apache.logging.log4j.plugins.PluginFactory;
> +
> +@Plugin(name = "FixedString", category = "Core", elementType = "plugin",
> printObject = true)
> +public class FixedString  {
> +
> +    private String fixedString;
> +
> +    @PluginFactory
> +    public static FixedString create(
> +            @PluginAttribute("fixedString") final String fixedString) {
> +        return new FixedString(fixedString);
> +    }
>
> -    public EnumConverter(final Class<E> clazz) {
> -        this.clazz = clazz;
> +    public FixedString(String fixedString) {
> +        this.fixedString = fixedString;
>      }
>
> -    @Override
> -    public E convert(final String s) {
> -        return EnglishEnums.valueOf(clazz, s);
> +    public Map<String, String> getContentFormat() {
> +        return Collections.emptyMap();
>      }
>  }
> diff --git
> a/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
> b/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
> new file mode 100644
> index 0000000..b85475a
> --- /dev/null
> +++
> b/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
> @@ -0,0 +1,31 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!--
> + 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.
> +
> +-->
> +<Configuration status="OFF" name="XMLConfigTest">
> +
> +  <Appenders>
> +    <List name="List">
> +    </List>
> +  </Appenders>
> +  <Loggers>
> +    <Root level="trace">
> +      <AppenderRef ref="List"/>
> +    </Root>
> +  </Loggers>
> +
> +</Configuration>
> \ No newline at end of file
> diff --git a/log4j-plugins/src/test/resources/s p a c e
> s/log4j+config+with+plus+characters.xml
> b/log4j-plugins/src/test/resources/s p a c e
> s/log4j+config+with+plus+characters.xml
> new file mode 100644
> index 0000000..b85475a
> --- /dev/null
> +++ b/log4j-plugins/src/test/resources/s p a c e
> s/log4j+config+with+plus+characters.xml
> @@ -0,0 +1,31 @@
> +<?xml version="1.0" encoding="UTF-8"?>
> +<!--
> + 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.
> +
> +-->
> +<Configuration status="OFF" name="XMLConfigTest">
> +
> +  <Appenders>
> +    <List name="List">
> +    </List>
> +  </Appenders>
> +  <Loggers>
> +    <Root level="trace">
> +      <AppenderRef ref="List"/>
> +    </Root>
> +  </Loggers>
> +
> +</Configuration>
> \ No newline at end of file
>
>

Re: [logging-log4j2] 01/02: LOG4J2-2621 - Initial commit

Posted by Ralph Goers <ra...@dslextreme.com>.
I have implemented compatibility with Log4j 2 2.x plugins. I’ve created a PR for easier review as this is a very large commit. If there are no comments I plan to commit this later in the week.

Ralph

> On Jun 9, 2019, at 11:39 AM, Ralph Goers <ra...@dslextreme.com> wrote:
> 
> I have updated the branch so that the build now succeeds and the OSGi tests pass. One quirk I noticed with OSGi is that in one of the tests the configuration is loaded from a sample bundle so that is where the LoggerContext ends up. When shutting down the LoggerContext is searched for on the log4j core bundle and isn’t found so then it creates a new LoggerContext during shutdown. This clearly isn’t right so I added an option to have LogManager.shutdown() try to shutdown LoggerContexts on all bundles and not create a new LoggerContext.
> 
> The only thing left is to add back support for existing plugins. Unfortunately, that is probably going to require adding deprecated classes back to core so that existing Plugins don’t get ClassNotFoundExceptions.
> 
> Ralph
> 
>> On Jun 3, 2019, at 7:58 AM, Ralph Goers <ra...@dslextreme.com> wrote:
>> 
>> Yes, but it shows up in the correct place in the git repo and the diff in the email shows the correct directory.
>> 
>> Ralph
>> 
>>> On Jun 3, 2019, at 3:56 AM, Gary Gregory <ga...@gmail.com> wrote:
>>> 
>>> This is weird, note the "}":
>>> 
>>> .../org/apache/logging/log4j}/util/Assert.java     |   0
>>> 
>>> Gary
>>> 
>>> On Sun, Jun 2, 2019 at 6:38 PM <rg...@apache.org> wrote:
>>> 
>>>> This is an automated email from the ASF dual-hosted git repository.
>>>> 
>>>> rgoers pushed a commit to branch LOG4J2-2621
>>>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>>>> 
>>>> commit b69c2d9e4b79ee7830a69463c6f89de1c50fe84d
>>>> Author: Ralph Goers <rg...@apache.org>
>>>> AuthorDate: Sun Jun 2 13:18:36 2019 -0700
>>>> 
>>>>  LOG4J2-2621 - Initial commit
>>>> ---
>>>> .../org/apache/logging/log4j}/util/Assert.java     |   0
>>>> .../logging/log4j/util/InternalException.java      |  56 ++++
>>>> .../org/apache/logging/log4j}/util/NameUtil.java   |   0
>>>> .../apache/logging/log4j}/util/ReflectionUtil.java |   6 +-
>>>> .../log4j/junit/AbstractExternalFileCleaner.java   |   0
>>>> .../org/apache/logging/log4j/junit/CleanFiles.java |   0
>>>> .../apache/logging/log4j/junit/CleanFolders.java   |   0
>>>> .../log4j/junit/URLStreamHandlerFactoryRule.java   |   0
>>>> .../org/apache/logging/log4j}/util/AssertTest.java |   2 +-
>>>> .../config/plugins/convert/Base64Converter.java    |  79 -----
>>>> ...TypeConverters.java => CoreTypeConverters.java} |   7 +-
>>>> .../ValidatingPluginWithGenericBuilderTest.java    |  10 +-
>>>> log4j-plugins-java9/pom.xml                        | 157 +++++++++
>>>> log4j-plugins-java9/src/assembly/java9.xml         |  40 +++
>>>> .../src/main/java/module-info.java                 |  15 +-
>>>> .../org/apache/logging/log4j/plugins/Dummy.java    |   9 +-
>>>> .../logging/log4j/plugins/convert/Dummy.java       |   9 +-
>>>> .../log4j/plugins/processor/PluginService.java     |   9 +-
>>>> .../apache/logging/log4j/plugins/util/Dummy.java   |   9 +-
>>>> .../logging/log4j/plugins/validation/Dummy.java    |   9 +-
>>>> .../logging/log4j/plugins/visitors/Dummy.java      |   9 +-
>>>> log4j-plugins/pom.xml                              | 360
>>>> +++++++++++++++++++++
>>>> .../org/apache/logging/log4j/plugins}/Node.java    |   6 +-
>>>> .../org/apache/logging/log4j}/plugins/Plugin.java  |   6 +-
>>>> .../logging/log4j}/plugins/PluginAliases.java      |   4 +-
>>>> .../logging/log4j}/plugins/PluginAttribute.java    |   8 +-
>>>> .../log4j}/plugins/PluginBuilderAttribute.java     |   8 +-
>>>> .../log4j}/plugins/PluginBuilderFactory.java       |   2 +-
>>>> .../logging/log4j}/plugins/PluginElement.java      |   6 +-
>>>> .../logging/log4j}/plugins/PluginFactory.java      |   2 +-
>>>> .../apache/logging/log4j}/plugins/PluginNode.java  |   6 +-
>>>> .../apache/logging/log4j}/plugins/PluginValue.java |   6 +-
>>>> .../log4j}/plugins/PluginVisitorStrategy.java      |   8 +-
>>>> .../log4j}/plugins/convert/EnumConverter.java      |   2 +-
>>>> .../log4j}/plugins/convert/HexConverter.java       |   2 +-
>>>> .../log4j}/plugins/convert/TypeConverter.java      |   2 +-
>>>> .../plugins/convert/TypeConverterRegistry.java     |  23 +-
>>>> .../log4j}/plugins/convert/TypeConverters.java     |  47 +--
>>>> .../log4j/plugins/convert}/package-info.java       |   7 +-
>>>> .../logging/log4j/plugins/osgi/Activator.java      | 103 ++++++
>>>> .../logging/log4j/plugins/osgi}/package-info.java  |   6 +-
>>>> .../logging/log4j/plugins}/package-info.java       |   6 +-
>>>> .../log4j}/plugins/processor/PluginCache.java      |  30 +-
>>>> .../log4j}/plugins/processor/PluginEntry.java      |  14 +-
>>>> .../log4j}/plugins/processor/PluginProcessor.java  | 157 +++++++--
>>>> .../log4j/plugins/processor/PluginService.java     |  56 ++++
>>>> .../log4j}/plugins/processor/package-info.java     |   2 +-
>>>> .../logging/log4j/plugins}/util/Builder.java       |   4 +-
>>>> .../logging/log4j}/plugins/util/PluginManager.java |   8 +-
>>>> .../log4j}/plugins/util/PluginRegistry.java        |  81 +++--
>>>> .../logging/log4j}/plugins/util/PluginType.java    |   6 +-
>>>> .../logging/log4j}/plugins/util/ResolverUtil.java  |  29 +-
>>>> .../logging/log4j/plugins/util/TypeUtil.java       | 217 +++++++++++++
>>>> .../logging/log4j/plugins/util}/package-info.java  |   2 +-
>>>> .../log4j}/plugins/validation/Constraint.java      |   9 +-
>>>> .../plugins/validation/ConstraintValidator.java    |   2 +-
>>>> .../plugins/validation/ConstraintValidators.java   |   8 +-
>>>> .../plugins/validation/constraints/Required.java   |  12 +-
>>>> .../plugins/validation/constraints/ValidHost.java  |   6 +-
>>>> .../plugins/validation/constraints/ValidPort.java  |  12 +-
>>>> .../validation/constraints/package-info.java       |   2 +-
>>>> .../log4j}/plugins/validation/package-info.java    |   2 +-
>>>> .../validation/validators/RequiredValidator.java   |  14 +-
>>>> .../validation/validators/ValidHostValidator.java  |   6 +-
>>>> .../validation/validators/ValidPortValidator.java  |   8 +-
>>>> .../validation/validators/package-info.java        |   2 +-
>>>> .../plugins/visitors/AbstractPluginVisitor.java    |  34 +-
>>>> .../plugins/visitors/PluginAttributeVisitor.java   |  27 +-
>>>> .../visitors/PluginBuilderAttributeVisitor.java    |  23 +-
>>>> .../plugins/visitors/PluginElementVisitor.java     |  17 +-
>>>> .../log4j}/plugins/visitors/PluginNodeVisitor.java |  14 +-
>>>> .../plugins/visitors/PluginValueVisitor.java       |  18 +-
>>>> .../log4j}/plugins/visitors/PluginVisitor.java     |  36 +--
>>>> .../log4j}/plugins/visitors/PluginVisitors.java    |  12 +-
>>>> .../log4j/plugins/visitors}/package-info.java      |   9 +-
>>>> .../services/javax.annotation.processing.Processor |   2 +-
>>>> .../plugins/convert/TypeConverterRegistryTest.java |   4 +-
>>>> .../log4j}/plugins/processor/FakePlugin.java       |   6 +-
>>>> .../plugins/processor/PluginProcessorTest.java     |  26 +-
>>>> .../util/ResolverUtilCustomProtocolTest.java       |  30 +-
>>>> .../log4j}/plugins/util/ResolverUtilTest.java      |  76 +++--
>>>> .../AbstractPluginWithGenericBuilder.java          |   6 +-
>>>> .../log4j}/plugins/validation/HostAndPort.java     |  14 +-
>>>> .../PluginWithGenericSubclassFoo1Builder.java      |  12 +-
>>>> .../plugins/validation/ValidatingPlugin.java       |  16 +-
>>>> .../ValidatingPluginWithGenericBuilder.java        |  17 +-
>>>> .../ValidatingPluginWithTypedBuilder.java          |  16 +-
>>>> .../resources/customplugin/FixedString.java.source |  37 ++-
>>>> .../log4j+config+with+plus+characters.xml          |  31 ++
>>>> .../log4j+config+with+plus+characters.xml          |  31 ++
>>>> 90 files changed, 1655 insertions(+), 594 deletions(-)
>>>> 
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Assert.java
>>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/Assert.java
>>>> similarity index 100%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/Assert.java
>>>> rename to log4j-api/src/main/java/org/apache/logging/log4j/util/Assert.java
>>>> diff --git
>>>> a/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>>>> new file mode 100644
>>>> index 0000000..8c433db
>>>> --- /dev/null
>>>> +++
>>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>>>> @@ -0,0 +1,56 @@
>>>> +/*
>>>> + * 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;
>>>> +
>>>> +/**
>>>> + * Exception thrown when an error occurs while logging.  In most cases
>>>> exceptions will be handled
>>>> + * within Log4j but certain Appenders may be configured to allow
>>>> exceptions to propagate to the
>>>> + * application. This is a RuntimeException so that the exception may be
>>>> thrown in those cases without
>>>> + * requiring all Logger methods be contained with try/catch blocks.
>>>> + */
>>>> +public class LoggingException extends RuntimeException {
>>>> +
>>>> +    private static final long serialVersionUID = 6366395965071580537L;
>>>> +
>>>> +    /**
>>>> +     * Construct an exception with a message.
>>>> +     *
>>>> +     * @param message The reason for the exception
>>>> +     */
>>>> +    public LoggingException(final String message) {
>>>> +        super(message);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Construct an exception with a message and underlying cause.
>>>> +     *
>>>> +     * @param message The reason for the exception
>>>> +     * @param cause The underlying cause of the exception
>>>> +     */
>>>> +    public LoggingException(final String message, final Throwable cause) {
>>>> +        super(message, cause);
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Construct an exception with an underlying cause.
>>>> +     *
>>>> +     * @param cause The underlying cause of the exception
>>>> +     */
>>>> +    public LoggingException(final Throwable cause) {
>>>> +        super(cause);
>>>> +    }
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NameUtil.java
>>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
>>>> similarity index 100%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/NameUtil.java
>>>> rename to
>>>> log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>>>> similarity index 98%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>>>> rename to
>>>> log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>>>> index ffee439..f00e64a 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>>>> +++
>>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>>>> @@ -193,8 +193,10 @@ public final class ReflectionUtil {
>>>>       } catch (final IllegalAccessException e) {
>>>>           throw new IllegalStateException(e);
>>>>       } catch (final InvocationTargetException e) {
>>>> -            Throwables.rethrow(e.getCause());
>>>> -            throw new InternalError("Unreachable");
>>>> +            if (e.getCause() instanceof RuntimeException) {
>>>> +                throw (RuntimeException) e.getCause();
>>>> +            }
>>>> +            throw new
>>>>       }
>>>>   }
>>>> }
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>>>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>>>> similarity index 100%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>>>> rename to
>>>> log4j-api/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>>>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>>>> similarity index 100%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>>>> rename to
>>>> log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>>>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>>>> similarity index 100%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>>>> rename to
>>>> log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>>>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>>>> similarity index 100%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>>>> rename to
>>>> log4j-api/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>>>> b/log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>>>> similarity index 99%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>>>> rename to
>>>> log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>>>> index 242c41e..7e46036 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>>>> +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>>>> @@ -65,4 +65,4 @@ public class AssertTest {
>>>>       assertEquals(isEmpty, Assert.isEmpty(value));
>>>>   }
>>>> 
>>>> -}
>>>> \ No newline at end of file
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>>>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>>>> deleted file mode 100644
>>>> index f4e421f..0000000
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>>>> +++ /dev/null
>>>> @@ -1,79 +0,0 @@
>>>> -/*
>>>> - * 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.convert;
>>>> -
>>>> -import java.lang.reflect.InvocationTargetException;
>>>> -import java.lang.reflect.Method;
>>>> -
>>>> -import org.apache.logging.log4j.Logger;
>>>> -import org.apache.logging.log4j.status.StatusLogger;
>>>> -import org.apache.logging.log4j.util.LoaderUtil;
>>>> -
>>>> -/**
>>>> - * @Since 2.9
>>>> - */
>>>> -public class Base64Converter {
>>>> -
>>>> -    private static final Logger LOGGER = StatusLogger.getLogger();
>>>> -    private static Method method = null;
>>>> -    private static Object decoder = null;
>>>> -
>>>> -    static {
>>>> -        try {
>>>> -            // Base64 is available in Java 8 and up.
>>>> -            Class<?> clazz = LoaderUtil.loadClass("java.util.Base64");
>>>> -            final Method getDecoder = clazz.getMethod("getDecoder",
>>>> (Class[]) null);
>>>> -            decoder = getDecoder.invoke(null, (Object[]) null);
>>>> -            clazz = decoder.getClass();
>>>> -            method = clazz.getMethod("decode", String.class);
>>>> -        } catch (final ClassNotFoundException ex) {
>>>> -
>>>> -        } catch (final NoSuchMethodException ex) {
>>>> -
>>>> -        } catch (final IllegalAccessException ex) {
>>>> -
>>>> -        } catch (final InvocationTargetException ex) {
>>>> -
>>>> -        }
>>>> -        if (method == null) {
>>>> -            try {
>>>> -                // DatatypeConverter is not in the default module in Java
>>>> 9.
>>>> -                final Class<?> clazz =
>>>> LoaderUtil.loadClass("javax.xml.bind.DatatypeConverter");
>>>> -                method = clazz.getMethod("parseBase64Binary",
>>>> String.class);
>>>> -            } catch (final ClassNotFoundException ex) {
>>>> -                LOGGER.error("No Base64 Converter is available");
>>>> -            } catch (final NoSuchMethodException ex) {
>>>> -
>>>> -            }
>>>> -        }
>>>> -    }
>>>> -
>>>> -    public static byte[] parseBase64Binary(final String encoded) {
>>>> -        if (method == null) {
>>>> -            LOGGER.error("No base64 converter");
>>>> -        } else {
>>>> -            try {
>>>> -                return (byte[]) method.invoke(decoder, encoded);
>>>> -            } catch (final IllegalAccessException ex) {
>>>> -                LOGGER.error("Error decoding string - " +
>>>> ex.getMessage());
>>>> -            } catch (final InvocationTargetException ex) {
>>>> -                LOGGER.error("Error decoding string - " +
>>>> ex.getMessage());
>>>> -            }
>>>> -        }
>>>> -        return new byte[0];
>>>> -    }
>>>> -}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>>>> similarity index 98%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>>> copy to
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>>>> index dc833f0..00e6da7 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>>> +++
>>>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>>>> @@ -30,13 +30,14 @@ import java.nio.file.Path;
>>>> import java.nio.file.Paths;
>>>> import java.security.Provider;
>>>> import java.security.Security;
>>>> +import java.util.Base64;
>>>> import java.util.UUID;
>>>> import java.util.regex.Pattern;
>>>> 
>>>> import org.apache.logging.log4j.Level;
>>>> import org.apache.logging.log4j.Logger;
>>>> import org.apache.logging.log4j.core.appender.rolling.action.Duration;
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> import org.apache.logging.log4j.core.util.CronExpression;
>>>> import org.apache.logging.log4j.status.StatusLogger;
>>>> import org.apache.logging.log4j.util.LoaderUtil;
>>>> @@ -56,6 +57,8 @@ public final class TypeConverters {
>>>>    */
>>>>   public static final String CATEGORY = "TypeConverter";
>>>> 
>>>> +    private static final Base64.Decoder decoder = Base64.getDecoder();
>>>> +
>>>>   /**
>>>>    * Parses a {@link String} into a {@link BigDecimal}.
>>>>    */
>>>> @@ -112,7 +115,7 @@ public final class TypeConverters {
>>>>               bytes = new byte[0];
>>>>           } else if (value.startsWith(PREFIX_BASE64)) {
>>>>               final String lexicalXSDBase64Binary =
>>>> value.substring(PREFIX_BASE64.length());
>>>> -                bytes =
>>>> Base64Converter.parseBase64Binary(lexicalXSDBase64Binary);
>>>> +                bytes = decoder.decode(lexicalXSDBase64Binary);
>>>>           } else if (value.startsWith(PREFIX_0x)) {
>>>>               final String lexicalXSDHexBinary =
>>>> value.substring(PREFIX_0x.length());
>>>>               bytes = HexConverter.parseHexBinary(lexicalXSDHexBinary);
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>>>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>>>> index 8ee5abb..27ac5fe 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>>>> +++
>>>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>>>> @@ -20,12 +20,12 @@ import static org.junit.Assert.assertEquals;
>>>> import static org.junit.Assert.assertNotNull;
>>>> import static org.junit.Assert.assertNull;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.Node;
>>>> +import org.apache.logging.log4j.plugins.Node;
>>>> import org.apache.logging.log4j.core.config.NullConfiguration;
>>>> -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;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.ValidatingPluginWithGenericBuilder;
>>>> +import org.apache.logging.log4j.plugins.util.PluginBuilder;
>>>> +import org.apache.logging.log4j.plugins.util.PluginManager;
>>>> +import org.apache.logging.log4j.plugins.util.PluginType;
>>>> +import
>>>> org.apache.logging.log4j.plugins.validation.ValidatingPluginWithGenericBuilder;
>>>> import org.junit.Before;
>>>> import org.junit.Test;
>>>> 
>>>> diff --git a/log4j-plugins-java9/pom.xml b/log4j-plugins-java9/pom.xml
>>>> new file mode 100644
>>>> index 0000000..49f81c6
>>>> --- /dev/null
>>>> +++ b/log4j-plugins-java9/pom.xml
>>>> @@ -0,0 +1,157 @@
>>>> +<?xml version="1.0" encoding="UTF-8"?>
>>>> +<!--
>>>> +  ~ 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.
>>>> +  -->
>>>> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
>>>> http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
>>>> http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
>>>> ">
>>>> +  <modelVersion>4.0.0</modelVersion>
>>>> +  <parent>
>>>> +    <groupId>org.apache.logging.log4j</groupId>
>>>> +    <artifactId>log4j</artifactId>
>>>> +    <version>3.0.0-SNAPSHOT</version>
>>>> +    <relativePath>../</relativePath>
>>>> +  </parent>
>>>> +  <artifactId>log4j-plugins-java9</artifactId>
>>>> +  <packaging>pom</packaging>
>>>> +  <name>Apache Log4j Plugins Module support</name>
>>>> +  <description>Apache Log4j Plugin Moduels Support</description>
>>>> +  <properties>
>>>> +    <log4jParentDir>${basedir}/..</log4jParentDir>
>>>> +    <docLabel>Log4j Plugins Documentation</docLabel>
>>>> +    <projectDir>/plugins</projectDir>
>>>> +  </properties>
>>>> +  <dependencies>
>>>> +    <dependency>
>>>> +      <groupId>org.apache.logging.log4j</groupId>
>>>> +      <artifactId>log4j-api</artifactId>
>>>> +    </dependency>
>>>> +    <dependency>
>>>> +      <groupId>junit</groupId>
>>>> +      <artifactId>junit</artifactId>
>>>> +      <scope>test</scope>
>>>> +    </dependency>
>>>> +    <dependency>
>>>> +      <groupId>org.apache.maven</groupId>
>>>> +      <artifactId>maven-core</artifactId>
>>>> +      <scope>test</scope>
>>>> +    </dependency>
>>>> +  </dependencies>
>>>> +  <build>
>>>> +    <plugins>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-toolchains-plugin</artifactId>
>>>> +        <version>1.1</version>
>>>> +        <executions>
>>>> +          <execution>
>>>> +            <goals>
>>>> +              <goal>toolchain</goal>
>>>> +            </goals>
>>>> +          </execution>
>>>> +        </executions>
>>>> +        <configuration>
>>>> +          <toolchains>
>>>> +            <jdk>
>>>> +              <version>[9, )</version>
>>>> +            </jdk>
>>>> +          </toolchains>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-compiler-plugin</artifactId>
>>>> +        <executions>
>>>> +          <execution>
>>>> +            <id>default-compile</id>
>>>> +            <phase>compile</phase>
>>>> +            <goals>
>>>> +              <goal>compile</goal>
>>>> +            </goals>
>>>> +          </execution>
>>>> +          <execution>
>>>> +            <id>default-test-compile</id>
>>>> +            <phase>test-compile</phase>
>>>> +            <goals>
>>>> +              <goal>testCompile</goal>
>>>> +            </goals>
>>>> +          </execution>
>>>> +        </executions>
>>>> +        <configuration>
>>>> +          <source>9</source>
>>>> +          <target>9</target>
>>>> +          <release>9</release>
>>>> +          <proc>none</proc>
>>>> +          <!-- disable errorprone -->
>>>> +          <compilerId>javac</compilerId>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-surefire-plugin</artifactId>
>>>> +        <!-- Do not upgrade until
>>>> https://issues.apache.org/jira/browse/SUREFIRE-720 is fixed -->
>>>> +        <version>2.13</version>
>>>> +        <executions>
>>>> +          <execution>
>>>> +            <id>test</id>
>>>> +            <phase>test</phase>
>>>> +            <goals>
>>>> +              <goal>test</goal>
>>>> +            </goals>
>>>> +          </execution>
>>>> +        </executions>
>>>> +        <configuration>
>>>> +          <systemPropertyVariables>
>>>> +            <java.awt.headless>true</java.awt.headless>
>>>> +          </systemPropertyVariables>
>>>> +          <includes>
>>>> +            <include>**/Test*.java</include>
>>>> +            <include>**/*Test.java</include>
>>>> +          </includes>
>>>> +          <excludes>
>>>> +            <exclude>**/*FuncTest.java</exclude>
>>>> +          </excludes>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <artifactId>maven-assembly-plugin</artifactId>
>>>> +        <executions>
>>>> +          <execution>
>>>> +            <id>zip</id>
>>>> +            <phase>package</phase>
>>>> +            <goals>
>>>> +              <goal>single</goal>
>>>> +            </goals>
>>>> +            <configuration>
>>>> +
>>>> <finalName>log4j-plugins-java9-${project.version}</finalName>
>>>> +              <appendAssemblyId>false</appendAssemblyId>
>>>> +              <descriptors>
>>>> +                <descriptor>src/assembly/java9.xml</descriptor>
>>>> +              </descriptors>
>>>> +            </configuration>
>>>> +          </execution>
>>>> +        </executions>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-deploy-plugin</artifactId>
>>>> +        <version>${deploy.plugin.version}</version>
>>>> +        <configuration>
>>>> +          <skip>true</skip>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +    </plugins>
>>>> +  </build>
>>>> +</project>
>>>> +
>>>> diff --git a/log4j-plugins-java9/src/assembly/java9.xml
>>>> b/log4j-plugins-java9/src/assembly/java9.xml
>>>> new file mode 100644
>>>> index 0000000..34649d4
>>>> --- /dev/null
>>>> +++ b/log4j-plugins-java9/src/assembly/java9.xml
>>>> @@ -0,0 +1,40 @@
>>>> +<?xml version='1.0' encoding='UTF-8'?>
>>>> +<!--
>>>> +  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.
>>>> +-->
>>>> +
>>>> +<assembly>
>>>> +  <id>src</id>
>>>> +  <formats>
>>>> +    <format>zip</format>
>>>> +  </formats>
>>>> +  <baseDirectory>/</baseDirectory>
>>>> +  <fileSets>
>>>> +    <fileSet>
>>>> +      <directory>${project.build.outputDirectory}</directory>
>>>> +      <outputDirectory>/classes/META-INF/versions/9</outputDirectory>
>>>> +      <includes>
>>>> +        <include>module-info.class</include>
>>>> +      </includes>
>>>> +      <excludes>
>>>> +        <exclude>**/Dummy.class</exclude>
>>>> +        <exclude>**/PluginService.class</exclude>
>>>> +      </excludes>
>>>> +    </fileSet>
>>>> +  </fileSets>
>>>> +</assembly>
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins-java9/src/main/java/module-info.java
>>>> similarity index 65%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to log4j-plugins-java9/src/main/java/module-info.java
>>>> index f22ba49..9802622 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++ b/log4j-plugins-java9/src/main/java/module-info.java
>>>> @@ -14,10 +14,13 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> +module org.apache.logging.log4j.plugins {
>>>> +    exports org.apache.logging.log4j.plugins;
>>>> +    exports org.apache.logging.log4j.plugins.convert;
>>>> +    exports org.apache.logging.log4j.plugins.processor;
>>>> +    exports org.apache.logging.log4j.plugins.util;
>>>> +    exports org.apache.logging.log4j.plugins.validation;
>>>> +    exports org.apache.logging.log4j.plugins.visitors;
>>>> 
>>>> -/**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> - */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +    uses org.apache.logging.log4j.plugins.processor.PluginService;
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>>>> similarity index 80%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>>>> index f22ba49..14a90ed 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>>>> @@ -14,10 +14,11 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> +package org.apache.logging.log4j.plugins;
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * This is a dummy class and is only here to allow module-info.java to
>>>> compile. It will not
>>>> + * be copied into the log4j-api module.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +public class Dummy {
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>>>> similarity index 79%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>>>> index f22ba49..10923e8 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>>>> @@ -14,10 +14,11 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> +package org.apache.logging.log4j.plugins.convert;
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * This is a dummy class and is only here to allow module-info.java to
>>>> compile. It will not
>>>> + * be copied into the log4j-api module.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +public class Dummy {
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>>> similarity index 79%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>>> index f22ba49..b93ef59 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>>> @@ -14,10 +14,11 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> +package org.apache.logging.log4j.plugins.processor;
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * This is a dummy class and is only here to allow module-info.java to
>>>> compile. It will not
>>>> + * be copied into the log4j-api module.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +public class PluginService {
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>>>> similarity index 80%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>>>> index f22ba49..5940b03 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>>>> @@ -14,10 +14,11 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * This is a dummy class and is only here to allow module-info.java to
>>>> compile. It will not
>>>> + * be copied into the log4j-api module.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +public class Dummy {
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>>>> similarity index 79%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>>>> index f22ba49..14882b5 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>>>> @@ -14,10 +14,11 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * This is a dummy class and is only here to allow module-info.java to
>>>> compile. It will not
>>>> + * be copied into the log4j-api module.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +public class Dummy {
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>>>> similarity index 79%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>>>> index f22ba49..5596338 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>>>> @@ -14,10 +14,11 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * This is a dummy class and is only here to allow module-info.java to
>>>> compile. It will not
>>>> + * be copied into the log4j-api module.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +public class Dummy {
>>>> +}
>>>> diff --git a/log4j-plugins/pom.xml b/log4j-plugins/pom.xml
>>>> new file mode 100644
>>>> index 0000000..3551d51
>>>> --- /dev/null
>>>> +++ b/log4j-plugins/pom.xml
>>>> @@ -0,0 +1,360 @@
>>>> +<?xml version="1.0" encoding="UTF-8"?>
>>>> +<!--
>>>> +  ~ 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.
>>>> +  -->
>>>> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
>>>> http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
>>>> http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
>>>> ">
>>>> +  <modelVersion>4.0.0</modelVersion>
>>>> +  <parent>
>>>> +    <groupId>org.apache.logging.log4j</groupId>
>>>> +    <artifactId>log4j</artifactId>
>>>> +    <version>3.0.0-SNAPSHOT</version>
>>>> +    <relativePath>../</relativePath>
>>>> +  </parent>
>>>> +  <artifactId>log4j-plugins</artifactId>
>>>> +  <packaging>jar</packaging>
>>>> +  <name>Apache Log4j Plugins</name>
>>>> +  <description>Log4j Plugin Support</description>
>>>> +  <properties>
>>>> +    <log4jParentDir>${basedir}/..</log4jParentDir>
>>>> +    <docLabel>Plugin Documentation</docLabel>
>>>> +    <projectDir>/plugins</projectDir>
>>>> +  </properties>
>>>> +  <dependencies>
>>>> +    <dependency>
>>>> +      <groupId>org.apache.logging.log4j</groupId>
>>>> +      <artifactId>log4j-api</artifactId>
>>>> +    </dependency>
>>>> +    <!-- Classes and resources to be shaded into the core jar -->
>>>> +    <dependency>
>>>> +      <groupId>org.apache.logging.log4j</groupId>
>>>> +      <artifactId>log4j-plugins-java9</artifactId>
>>>> +      <scope>provided</scope>
>>>> +      <type>zip</type>
>>>> +    </dependency>
>>>> +    <!-- Used for OSGi bundle support -->
>>>> +    <dependency>
>>>> +      <groupId>org.osgi</groupId>
>>>> +      <artifactId>org.osgi.core</artifactId>
>>>> +      <scope>provided</scope>
>>>> +    </dependency>
>>>> +
>>>> +    <!-- TEST DEPENDENCIES -->
>>>> +
>>>> +    <!-- Pull in useful test classes from API -->
>>>> +    <dependency>
>>>> +      <groupId>org.apache.logging.log4j</groupId>
>>>> +      <artifactId>log4j-api</artifactId>
>>>> +      <type>test-jar</type>
>>>> +      <scope>test</scope>
>>>> +    </dependency>
>>>> +    <dependency>
>>>> +      <groupId>junit</groupId>
>>>> +      <artifactId>junit</artifactId>
>>>> +      <scope>test</scope>
>>>> +    </dependency>
>>>> +    <dependency>
>>>> +      <groupId>org.hamcrest</groupId>
>>>> +      <artifactId>hamcrest-all</artifactId>
>>>> +      <scope>test</scope>
>>>> +    </dependency>
>>>> +  </dependencies>
>>>> +  <build>
>>>> +    <plugins>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-dependency-plugin</artifactId>
>>>> +        <version>3.0.2</version>
>>>> +        <executions>
>>>> +          <execution>
>>>> +            <id>unpack-classes</id>
>>>> +            <phase>prepare-package</phase>
>>>> +            <goals>
>>>> +              <goal>unpack</goal>
>>>> +            </goals>
>>>> +            <configuration>
>>>> +              <artifactItems>
>>>> +                <artifactItem>
>>>> +                  <groupId>org.apache.logging.log4j</groupId>
>>>> +                  <artifactId>log4j-plugins-java9</artifactId>
>>>> +                  <version>${project.version}</version>
>>>> +                  <type>zip</type>
>>>> +                  <overWrite>false</overWrite>
>>>> +                </artifactItem>
>>>> +              </artifactItems>
>>>> +              <includes>**/*.class</includes>
>>>> +              <excludes>**/*.java</excludes>
>>>> +
>>>> <outputDirectory>${project.build.directory}</outputDirectory>
>>>> +              <overWriteReleases>false</overWriteReleases>
>>>> +              <overWriteSnapshots>true</overWriteSnapshots>
>>>> +            </configuration>
>>>> +          </execution>
>>>> +        </executions>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <artifactId>maven-compiler-plugin</artifactId>
>>>> +        <executions>
>>>> +          <execution>
>>>> +            <!-- disable annotation processing for first pass -->
>>>> +            <id>generate-plugins</id>
>>>> +            <phase>process-classes</phase>
>>>> +            <goals>
>>>> +              <goal>compile</goal>
>>>> +            </goals>
>>>> +            <configuration>
>>>> +              <excludes>
>>>> +                <exclude>module-info.java</exclude>
>>>> +              </excludes>
>>>> +            </configuration>
>>>> +          </execution>
>>>> +          <execution>
>>>> +            <!-- disable annotation processing for first pass -->
>>>> +            <id>generate-test-plugins</id>
>>>> +            <phase>generate-test-sources</phase>
>>>> +            <goals>
>>>> +              <goal>compile</goal>
>>>> +            </goals>
>>>> +            <configuration>
>>>> +              <excludes>
>>>> +                <exclude>module-info.java</exclude>
>>>> +              </excludes>
>>>> +              <proc>only</proc>
>>>> +            </configuration>
>>>> +          </execution>
>>>> +          <execution>
>>>> +            <!-- disable annotation processing for first pass -->
>>>> +            <id>default-compile</id>
>>>> +            <configuration>
>>>> +              <excludes>
>>>> +                <exclude>module-info.java</exclude>
>>>> +              </excludes>
>>>> +              <proc>none</proc>
>>>> +            </configuration>
>>>> +          </execution>
>>>> +        </executions>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <artifactId>maven-surefire-plugin</artifactId>
>>>> +        <configuration>
>>>> +          <excludedGroups>
>>>> +            org.apache.logging.log4j.categories.PerformanceTests
>>>> +          </excludedGroups>
>>>> +          <systemPropertyVariables>
>>>> +
>>>> <org.apache.activemq.SERIALIZABLE_PACKAGES>*</org.apache.activemq.SERIALIZABLE_PACKAGES>
>>>> +          </systemPropertyVariables>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-failsafe-plugin</artifactId>
>>>> +        <configuration>
>>>> +          <skipTests>true</skipTests>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-jar-plugin</artifactId>
>>>> +        <executions>
>>>> +          <execution>
>>>> +            <id>default-jar</id>
>>>> +            <goals>
>>>> +              <goal>jar</goal>
>>>> +            </goals>
>>>> +            <configuration combine.self="override">
>>>> +              <archive>
>>>> +                <manifestFile>${manifestfile}</manifestFile>
>>>> +                <manifestEntries>
>>>> +                  <Specification-Title>${project.name
>>>> }</Specification-Title>
>>>> +
>>>> <Specification-Version>${project.version}</Specification-Version>
>>>> +                  <Specification-Vendor>${project.organization.name
>>>> }</Specification-Vendor>
>>>> +                  <Implementation-Title>${project.name
>>>> }</Implementation-Title>
>>>> +
>>>> <Implementation-Version>${project.version}</Implementation-Version>
>>>> +                  <Implementation-Vendor>${project.organization.name
>>>> }</Implementation-Vendor>
>>>> +
>>>> <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
>>>> +
>>>> <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
>>>> +
>>>> <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
>>>> +
>>>> <Automatic-Module-Name>org.apache.logging.log4j.plugins</Automatic-Module-Name>
>>>> +                  <Multi-Release>true</Multi-Release>
>>>> +                </manifestEntries>
>>>> +              </archive>
>>>> +            </configuration>
>>>> +          </execution>
>>>> +          <execution>
>>>> +            <id>default</id>
>>>> +            <goals>
>>>> +              <goal>test-jar</goal>
>>>> +            </goals>
>>>> +            <configuration>
>>>> +              <archive>
>>>> +                <manifestFile>${manifestfile}</manifestFile>
>>>> +                <manifestEntries>
>>>> +                  <Specification-Title>${project.name
>>>> }</Specification-Title>
>>>> +
>>>> <Specification-Version>${project.version}</Specification-Version>
>>>> +                  <Specification-Vendor>${project.organization.name
>>>> }</Specification-Vendor>
>>>> +                  <Implementation-Title>${project.name
>>>> }</Implementation-Title>
>>>> +
>>>> <Implementation-Version>${project.version}</Implementation-Version>
>>>> +                  <Implementation-Vendor>${project.organization.name
>>>> }</Implementation-Vendor>
>>>> +
>>>> <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
>>>> +
>>>> <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
>>>> +
>>>> <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
>>>> +                </manifestEntries>
>>>> +              </archive>
>>>> +            </configuration>
>>>> +          </execution>
>>>> +        </executions>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.felix</groupId>
>>>> +        <artifactId>maven-bundle-plugin</artifactId>
>>>> +        <configuration>
>>>> +          <instructions>
>>>> +
>>>> <Bundle-SymbolicName>org.apache.logging.log4j.plugins</Bundle-SymbolicName>
>>>> +            <!-- TODO: exclude internal classes from export -->
>>>> +
>>>> <Export-Package>org.apache.logging.log4j.plugins.*</Export-Package>
>>>> +            <Import-Package>
>>>> +              sun.reflect;resolution:=optional,
>>>> +              org.apache.logging.log4j.util,
>>>> +              *
>>>> +            </Import-Package>
>>>> +
>>>> <Bundle-Activator>org.apache.logging.log4j.plugins.osgi.Activator</Bundle-Activator>
>>>> +          </instructions>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +    </plugins>
>>>> +  </build>
>>>> +  <reporting>
>>>> +    <plugins>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-changes-plugin</artifactId>
>>>> +        <version>${changes.plugin.version}</version>
>>>> +        <reportSets>
>>>> +          <reportSet>
>>>> +            <reports>
>>>> +              <report>changes-report</report>
>>>> +            </reports>
>>>> +          </reportSet>
>>>> +        </reportSets>
>>>> +        <configuration>
>>>> +
>>>> <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
>>>> +          <useJql>true</useJql>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-checkstyle-plugin</artifactId>
>>>> +        <version>${checkstyle.plugin.version}</version>
>>>> +        <configuration>
>>>> +
>>>> <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation>
>>>> -->
>>>> +
>>>> <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
>>>> +
>>>> <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
>>>> +          <enableRulesSummary>false</enableRulesSummary>
>>>> +          <propertyExpansion>basedir=${basedir}</propertyExpansion>
>>>> +
>>>> <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-javadoc-plugin</artifactId>
>>>> +        <version>${javadoc.plugin.version}</version>
>>>> +        <configuration>
>>>> +          <failOnError>false</failOnError>
>>>> +          <bottom><![CDATA[<p align="center">Copyright &#169;
>>>> {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
>>>> +            Apache Logging, Apache Log4j, Log4j, Apache, the Apache
>>>> feather logo, the Apache Logging project logo,
>>>> +            and the Apache Log4j logo are trademarks of The Apache
>>>> Software Foundation.</p>]]></bottom>
>>>> +          <!-- module link generation is completely broken in the javadoc
>>>> plugin for a multi-module non-aggregating
>>>> +               project -->
>>>> +          <additionalparam>${javadoc.opts}</additionalparam>
>>>> +          <detectOfflineLinks>false</detectOfflineLinks>
>>>> +          <linksource>true</linksource>
>>>> +          <links>
>>>> +            <link>http://docs.oracle.com/javaee/6/api/</link>
>>>> +            <link>http://www.osgi.org/javadoc/r4v43/core/</link>
>>>> +            <link>
>>>> https://commons.apache.org/proper/commons-lang/javadocs/api-release/
>>>> </link>
>>>> +          </links>
>>>> +          <groups>
>>>> +            <group>
>>>> +              <title>Core API</title>
>>>> +              <packages>org.apache.logging.log4j.core</packages>
>>>> +            </group>
>>>> +            <group>
>>>> +              <title>Configuration</title>
>>>> +
>>>> <packages>org.apache.logging.log4j.core.config*:org.apache.logging.log4j.core.selector</packages>
>>>> +            </group>
>>>> +            <group>
>>>> +              <title>Core Plugins</title>
>>>> +
>>>> <packages>org.apache.logging.log4j.core.appender*:org.apache.logging.log4j.core.filter:org.apache.logging.log4j.core.layout:org.apache.logging.log4j.core.lookup:org.apache.logging.log4j.core.pattern:org.apache.logging.log4j.core.script</packages>
>>>> +            </group>
>>>> +            <group>
>>>> +              <title>Tools</title>
>>>> +              <packages>org.apache.logging.log4j.core.net
>>>> *:org.apache.logging.log4j.core.tools</packages>
>>>> +            </group>
>>>> +            <group>
>>>> +              <title>Internals</title>
>>>> +
>>>> <packages>org.apache.logging.log4j.core.async:org.apache.logging.log4j.core.impl:org.apache.logging.log4j.core.util*:org.apache.logging.log4j.core.osgi:org.apache.logging.log4j.core.jackson:org.apache.logging.log4j.core.jmx</packages>
>>>> +            </group>
>>>> +          </groups>
>>>> +        </configuration>
>>>> +        <reportSets>
>>>> +          <reportSet>
>>>> +            <id>non-aggregate</id>
>>>> +            <reports>
>>>> +              <report>javadoc</report>
>>>> +            </reports>
>>>> +          </reportSet>
>>>> +        </reportSets>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>com.github.spotbugs</groupId>
>>>> +        <artifactId>spotbugs-maven-plugin</artifactId>
>>>> +        <configuration>
>>>> +          <fork>true</fork>
>>>> +          <jvmArgs>-Duser.language=en</jvmArgs>
>>>> +          <threshold>Normal</threshold>
>>>> +          <effort>Default</effort>
>>>> +
>>>> <excludeFilterFile>${log4jParentDir}/spotbugs-exclude-filter.xml</excludeFilterFile>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-jxr-plugin</artifactId>
>>>> +        <version>${jxr.plugin.version}</version>
>>>> +        <reportSets>
>>>> +          <reportSet>
>>>> +            <id>non-aggregate</id>
>>>> +            <reports>
>>>> +              <report>jxr</report>
>>>> +            </reports>
>>>> +          </reportSet>
>>>> +          <reportSet>
>>>> +            <id>aggregate</id>
>>>> +            <reports>
>>>> +              <report>aggregate</report>
>>>> +            </reports>
>>>> +          </reportSet>
>>>> +        </reportSets>
>>>> +      </plugin>
>>>> +      <plugin>
>>>> +        <groupId>org.apache.maven.plugins</groupId>
>>>> +        <artifactId>maven-pmd-plugin</artifactId>
>>>> +        <version>${pmd.plugin.version}</version>
>>>> +        <configuration>
>>>> +          <targetJdk>${maven.compiler.target}</targetJdk>
>>>> +        </configuration>
>>>> +      </plugin>
>>>> +    </plugins>
>>>> +  </reporting>
>>>> +</project>
>>>> +
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>>>> similarity index 97%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>>>> index c92c904..22fd9bf 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>>>> @@ -14,15 +14,15 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config;
>>>> +package org.apache.logging.log4j.plugins;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.util.PluginType;
>>>> 
>>>> import java.util.ArrayList;
>>>> import java.util.HashMap;
>>>> import java.util.List;
>>>> import java.util.Map;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>>>> -
>>>> /**
>>>> * A Configuration node.
>>>> */
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>>>> similarity index 97%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>>>> index 8aaf117..348754f 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>>>> @@ -14,7 +14,9 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> +
>>>> +import org.apache.logging.log4j.util.Strings;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>>>> import java.lang.annotation.RetentionPolicy;
>>>> import java.lang.annotation.Target;
>>>> 
>>>> -import org.apache.logging.log4j.util.Strings;
>>>> -
>>>> /**
>>>> * Annotation that identifies a Class as a Plugin.
>>>> */
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>>>> similarity index 87%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>>>> index 7be3dea..4dce103 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>>>> @@ -14,7 +14,7 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> @@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy;
>>>> import java.lang.annotation.Target;
>>>> 
>>>> /**
>>>> - * Identifies a list of aliases for a {@link Plugin}, {@link
>>>> PluginAttribute}, or {@link PluginBuilderAttribute}.
>>>> + * Identifies a list of aliases for a Plugin, PluginAttribute, or
>>>> PluginBuilderAttribute.
>>>> */
>>>> @Documented
>>>> @Retention(RetentionPolicy.RUNTIME)
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>>>> similarity index 96%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>>>> index bd88220..b9d4684 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>>>> @@ -14,7 +14,10 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.visitors.PluginAttributeVisitor;
>>>> +import org.apache.logging.log4j.util.Strings;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> @@ -22,9 +25,6 @@ import java.lang.annotation.Retention;
>>>> import java.lang.annotation.RetentionPolicy;
>>>> import java.lang.annotation.Target;
>>>> 
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginAttributeVisitor;
>>>> -import org.apache.logging.log4j.util.Strings;
>>>> -
>>>> /**
>>>> * Identifies a Plugin Attribute and its default value. Note that only
>>>> one of the defaultFoo attributes will be
>>>> * used based on the type this annotation is attached to. Thus, for
>>>> primitive types, the default<i>Type</i>
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>>>> similarity index 92%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>>>> index 675d78f..c7fce2f 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>>>> @@ -15,7 +15,10 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> +
>>>> +import
>>>> org.apache.logging.log4j.plugins.visitors.PluginBuilderAttributeVisitor;
>>>> +import org.apache.logging.log4j.util.Strings;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> @@ -23,9 +26,6 @@ import java.lang.annotation.Retention;
>>>> import java.lang.annotation.RetentionPolicy;
>>>> import java.lang.annotation.Target;
>>>> 
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginBuilderAttributeVisitor;
>>>> -import org.apache.logging.log4j.util.Strings;
>>>> -
>>>> /**
>>>> * Marks a field as a Plugin Attribute.
>>>> */
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>>>> similarity index 95%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>>>> index 4e69262..035b025 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>>>> @@ -15,7 +15,7 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>>>> similarity index 91%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>>>> index 7ea358b..6cfb6fa 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>>>> @@ -14,7 +14,9 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.visitors.PluginElementVisitor;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>>>> import java.lang.annotation.RetentionPolicy;
>>>> import java.lang.annotation.Target;
>>>> 
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor;
>>>> -
>>>> /**
>>>> * Identifies a parameter as a Plugin and corresponds with an XML element
>>>> (or equivalent) in configuration files.
>>>> */
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>>>> similarity index 96%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>>>> index 1c04106..b071510 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>>>> @@ -14,7 +14,7 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>>>> similarity index 90%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>>>> index d60f1b5..b172268 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>>>> @@ -14,7 +14,9 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.visitors.PluginNodeVisitor;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>>>> import java.lang.annotation.RetentionPolicy;
>>>> import java.lang.annotation.Target;
>>>> 
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginNodeVisitor;
>>>> -
>>>> /**
>>>> * Identifies a Plugin configuration Node.
>>>> */
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>>>> similarity index 91%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>>>> index 9c20cc2..31e5a23 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>>>> @@ -14,7 +14,9 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.visitors.PluginValueVisitor;
>>>> 
>>>> import java.lang.annotation.Documented;
>>>> import java.lang.annotation.ElementType;
>>>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>>>> import java.lang.annotation.RetentionPolicy;
>>>> import java.lang.annotation.Target;
>>>> 
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginValueVisitor;
>>>> -
>>>> /**
>>>> * Identifies a parameter as a value. These correspond with property
>>>> values generally, but are meant as values to be
>>>> * used as a placeholder value somewhere.
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>>>> similarity index 89%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>>>> index 65fcb76..093cc50 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>>>> @@ -15,7 +15,9 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins;
>>>> +package org.apache.logging.log4j.plugins;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.visitors.PluginVisitor;
>>>> 
>>>> import java.lang.annotation.Annotation;
>>>> import java.lang.annotation.Documented;
>>>> @@ -24,8 +26,6 @@ import java.lang.annotation.Retention;
>>>> import java.lang.annotation.RetentionPolicy;
>>>> import java.lang.annotation.Target;
>>>> 
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor;
>>>> -
>>>> /**
>>>> * Meta-annotation to denote the class name to use that implements
>>>> * {@link
>>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor} for
>>>> the annotated annotation.
>>>> @@ -40,5 +40,5 @@ public @interface PluginVisitorStrategy {
>>>>    * for the given annotation. The generic type in {@code
>>>> PluginVisitor} should match the annotation this annotation
>>>>    * is applied to.
>>>>    */
>>>> -    Class<? extends PluginVisitor<? extends Annotation>> value();
>>>> +    Class<? extends PluginVisitor<? extends Annotation, ?>> value();
>>>> }
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>>>> similarity index 95%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>>> copy to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>>>> index 15a162c..fd8012a 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>>>> @@ -14,7 +14,7 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>>> +package org.apache.logging.log4j.plugins.convert;
>>>> 
>>>> import org.apache.logging.log4j.util.EnglishEnums;
>>>> 
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>>>> similarity index 95%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>>>> index e629657..f9037b3 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>>>> @@ -14,7 +14,7 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>>> +package org.apache.logging.log4j.plugins.convert;
>>>> 
>>>> /**
>>>> * Converts Strings to hex. This is used in place of
>>>> java.xml.bind.DataTypeConverter which is not available by
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>>>> similarity index 95%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>>>> index e67e213..aaa5b4d 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>>>> @@ -15,7 +15,7 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>>> +package org.apache.logging.log4j.plugins.convert;
>>>> 
>>>> /**
>>>> * Interface for doing automatic String conversion to a specific type.
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>>>> similarity index 92%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>>>> index 5088f15..fb5b27e 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>>>> @@ -14,7 +14,14 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>>> +package org.apache.logging.log4j.plugins.convert;
>>>> +
>>>> +import org.apache.logging.log4j.Logger;
>>>> +import org.apache.logging.log4j.plugins.util.PluginManager;
>>>> +import org.apache.logging.log4j.plugins.util.PluginType;
>>>> +import org.apache.logging.log4j.plugins.util.TypeUtil;
>>>> +import org.apache.logging.log4j.util.ReflectionUtil;
>>>> +import org.apache.logging.log4j.status.StatusLogger;
>>>> 
>>>> import java.lang.reflect.ParameterizedType;
>>>> import java.lang.reflect.Type;
>>>> @@ -25,13 +32,6 @@ import java.util.UnknownFormatConversionException;
>>>> import java.util.concurrent.ConcurrentHashMap;
>>>> import java.util.concurrent.ConcurrentMap;
>>>> 
>>>> -import org.apache.logging.log4j.Logger;
>>>> -import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
>>>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>>>> -import org.apache.logging.log4j.core.util.ReflectionUtil;
>>>> -import org.apache.logging.log4j.core.util.TypeUtil;
>>>> -import org.apache.logging.log4j.status.StatusLogger;
>>>> -
>>>> /**
>>>> * Registry for {@link TypeConverter} plugins.
>>>> *
>>>> @@ -152,7 +152,12 @@ public class TypeConverterRegistry {
>>>>   }
>>>> 
>>>>   private void registerTypeAlias(final Type knownType, final Type
>>>> aliasType) {
>>>> -        registry.putIfAbsent(aliasType, registry.get(knownType));
>>>> +        TypeConverter<?> converter = registry.get(knownType);
>>>> +        if (converter != null) {
>>>> +            registry.putIfAbsent(aliasType, converter);
>>>> +        } else {
>>>> +            LOGGER.error("Cannot locate converter for {}", knownType);
>>>> +        }
>>>>   }
>>>> 
>>>> }
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>>>> similarity index 92%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>>>> index dc833f0..7a71b4a 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>>>> @@ -15,32 +15,27 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>>> +package org.apache.logging.log4j.plugins.convert;
>>>> +
>>>> +import org.apache.logging.log4j.Level;
>>>> +import org.apache.logging.log4j.Logger;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> +import org.apache.logging.log4j.status.StatusLogger;
>>>> +import org.apache.logging.log4j.util.LoaderUtil;
>>>> 
>>>> import java.io.File;
>>>> import java.math.BigDecimal;
>>>> import java.math.BigInteger;
>>>> -import java.net.InetAddress;
>>>> -import java.net.MalformedURLException;
>>>> -import java.net.URI;
>>>> -import java.net.URISyntaxException;
>>>> -import java.net.URL;
>>>> +import java.net.*;
>>>> import java.nio.charset.Charset;
>>>> import java.nio.file.Path;
>>>> import java.nio.file.Paths;
>>>> import java.security.Provider;
>>>> import java.security.Security;
>>>> +import java.util.Base64;
>>>> import java.util.UUID;
>>>> import java.util.regex.Pattern;
>>>> 
>>>> -import org.apache.logging.log4j.Level;
>>>> -import org.apache.logging.log4j.Logger;
>>>> -import org.apache.logging.log4j.core.appender.rolling.action.Duration;
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import org.apache.logging.log4j.core.util.CronExpression;
>>>> -import org.apache.logging.log4j.status.StatusLogger;
>>>> -import org.apache.logging.log4j.util.LoaderUtil;
>>>> -
>>>> /**
>>>> * Collection of basic TypeConverter implementations. May be used to
>>>> register additional TypeConverters or find
>>>> * registered TypeConverters.
>>>> @@ -56,6 +51,8 @@ public final class TypeConverters {
>>>>    */
>>>>   public static final String CATEGORY = "TypeConverter";
>>>> 
>>>> +    private static final Base64.Decoder decoder = Base64.getDecoder();
>>>> +
>>>>   /**
>>>>    * Parses a {@link String} into a {@link BigDecimal}.
>>>>    */
>>>> @@ -112,7 +109,7 @@ public final class TypeConverters {
>>>>               bytes = new byte[0];
>>>>           } else if (value.startsWith(PREFIX_BASE64)) {
>>>>               final String lexicalXSDBase64Binary =
>>>> value.substring(PREFIX_BASE64.length());
>>>> -                bytes =
>>>> Base64Converter.parseBase64Binary(lexicalXSDBase64Binary);
>>>> +                bytes = decoder.decode(lexicalXSDBase64Binary);
>>>>           } else if (value.startsWith(PREFIX_0x)) {
>>>>               final String lexicalXSDHexBinary =
>>>> value.substring(PREFIX_0x.length());
>>>>               bytes = HexConverter.parseHexBinary(lexicalXSDHexBinary);
>>>> @@ -203,14 +200,6 @@ public final class TypeConverters {
>>>>       }
>>>>   }
>>>> 
>>>> -    @Plugin(name = "CronExpression", category = CATEGORY)
>>>> -    public static class CronExpressionConverter implements
>>>> TypeConverter<CronExpression> {
>>>> -        @Override
>>>> -        public CronExpression convert(final String s) throws Exception {
>>>> -            return new CronExpression(s);
>>>> -        }
>>>> -    }
>>>> -
>>>>   /**
>>>>    * Converts a {@link String} into a {@link Double}.
>>>>    */
>>>> @@ -223,18 +212,6 @@ public final class TypeConverters {
>>>>   }
>>>> 
>>>>   /**
>>>> -     * Converts a {@link String} into a {@link Duration}.
>>>> -     * @since 2.5
>>>> -     */
>>>> -    @Plugin(name = "Duration", category = CATEGORY)
>>>> -    public static class DurationConverter implements
>>>> TypeConverter<Duration> {
>>>> -        @Override
>>>> -        public Duration convert(final String s) {
>>>> -            return Duration.parse(s);
>>>> -        }
>>>> -    }
>>>> -
>>>> -    /**
>>>>    * Converts a {@link String} into a {@link File}.
>>>>    */
>>>>   @Plugin(name = "File", category = CATEGORY)
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>>>> similarity index 80%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>>>> index f22ba49..958beb4 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>>>> @@ -16,8 +16,7 @@
>>>> */
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * TypeConverter plugins for converter strings into various types. These
>>>> plugins are used for parsing plugin
>>>> + * attributes in plugin factory methods.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +package org.apache.logging.log4j.plugins.convert;
>>>> diff --git
>>>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>>>> new file mode 100644
>>>> index 0000000..518bee7
>>>> --- /dev/null
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>>>> @@ -0,0 +1,103 @@
>>>> +/*
>>>> + * 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.plugins.osgi;
>>>> +
>>>> +import org.apache.logging.log4j.LogManager;
>>>> +import org.apache.logging.log4j.Logger;
>>>> +import org.apache.logging.log4j.plugins.processor.PluginService;
>>>> +import org.apache.logging.log4j.plugins.util.PluginRegistry;
>>>> +import org.apache.logging.log4j.spi.Provider;
>>>> +import org.apache.logging.log4j.status.StatusLogger;
>>>> +import org.apache.logging.log4j.util.PropertiesUtil;
>>>> +import org.osgi.framework.*;
>>>> +import org.osgi.framework.wiring.BundleWiring;
>>>> +
>>>> +import java.util.Hashtable;
>>>> +import java.util.concurrent.atomic.AtomicReference;
>>>> +
>>>> +/**
>>>> + * OSGi BundleActivator.
>>>> + */
>>>> +public final class Activator implements BundleActivator,
>>>> SynchronousBundleListener {
>>>> +
>>>> +    private static final Logger LOGGER = StatusLogger.getLogger();
>>>> +
>>>> +    private final AtomicReference<BundleContext> contextRef = new
>>>> AtomicReference<>();
>>>> +
>>>> +    ServiceRegistration provideRegistration = null;
>>>> +
>>>> +    @Override
>>>> +    public void start(final BundleContext context) throws Exception {
>>>> +        final PluginService pluginService = new Log4jProvider();
>>>> +        final Hashtable<String, String> props = new Hashtable<>();
>>>> +        props.put("APIVersion", "3.0");
>>>> +        provideRegistration =
>>>> context.registerService(pluginService.class.getName(), provider, props);
>>>> +        if (this.contextRef.compareAndSet(null, context)) {
>>>> +            context.addBundleListener(this);
>>>> +            // done after the BundleListener as to not miss any new
>>>> bundle installs in the interim
>>>> +            scanInstalledBundlesForPlugins(context);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    private static void scanInstalledBundlesForPlugins(final
>>>> BundleContext context) {
>>>> +        final Bundle[] bundles = context.getBundles();
>>>> +        for (final Bundle bundle : bundles) {
>>>> +            // TODO: bundle state can change during this
>>>> +            scanBundleForPlugins(bundle);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    private static void scanBundleForPlugins(final Bundle bundle) {
>>>> +        final long bundleId = bundle.getBundleId();
>>>> +        // LOG4J2-920: don't scan system bundle for plugins
>>>> +        if (bundle.getState() == Bundle.ACTIVE && bundleId != 0) {
>>>> +            LOGGER.trace("Scanning bundle [{}, id=%d] for plugins.",
>>>> bundle.getSymbolicName(), bundleId);
>>>> +            PluginRegistry.getInstance().loadFromBundle(bundleId,
>>>> +                    bundle.adapt(BundleWiring.class).getClassLoader());
>>>> +        }
>>>> +    }
>>>> +
>>>> +    private static void stopBundlePlugins(final Bundle bundle) {
>>>> +        LOGGER.trace("Stopping bundle [{}] plugins.",
>>>> bundle.getSymbolicName());
>>>> +        // TODO: plugin lifecycle code
>>>> +
>>>> PluginRegistry.getInstance().clearBundlePlugins(bundle.getBundleId());
>>>> +    }
>>>> +
>>>> +    @Override
>>>> +    public void stop(final BundleContext context) throws Exception {
>>>> +        provideRegistration.unregister();
>>>> +        this.contextRef.compareAndSet(context, null);
>>>> +    }
>>>> +
>>>> +    @Override
>>>> +    public void bundleChanged(final BundleEvent event) {
>>>> +        switch (event.getType()) {
>>>> +            // FIXME: STARTING instead of STARTED?
>>>> +            case BundleEvent.STARTED:
>>>> +                scanBundleForPlugins(event.getBundle());
>>>> +                break;
>>>> +
>>>> +            case BundleEvent.STOPPING:
>>>> +                stopBundlePlugins(event.getBundle());
>>>> +                break;
>>>> +
>>>> +            default:
>>>> +                break;
>>>> +        }
>>>> +    }
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>>>> similarity index 87%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>>>> index f22ba49..37dadd4 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>>>> @@ -16,8 +16,6 @@
>>>> */
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * Collection of OSGi-specific classes for bundles.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +package org.apache.logging.log4j.plugins.osgi;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>>>> similarity index 87%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>>>> index f22ba49..b161185 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>>>> @@ -16,8 +16,6 @@
>>>> */
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * Annotations for Log4j 2 plugins.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +package org.apache.logging.log4j.plugins;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>>>> similarity index 71%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>>>> index 2fd4160..784dece 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>>>> @@ -15,7 +15,7 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>>> +package org.apache.logging.log4j.plugins.processor;
>>>> 
>>>> import java.io.BufferedInputStream;
>>>> import java.io.BufferedOutputStream;
>>>> @@ -60,34 +60,6 @@ public class PluginCache {
>>>>   }
>>>> 
>>>>   /**
>>>> -     * Stores the plugin cache to a given OutputStream.
>>>> -     *
>>>> -     * @param os destination to save cache to.
>>>> -     * @throws IOException if an I/O exception occurs.
>>>> -     */
>>>> -    // NOTE: if this file format is to be changed, the filename should
>>>> change and this format should still be readable
>>>> -    public void writeCache(final OutputStream os) throws IOException {
>>>> -        try (final DataOutputStream out = new DataOutputStream(new
>>>> BufferedOutputStream(os))) {
>>>> -            // See PluginManager.readFromCacheFiles for the corresponding
>>>> decoder. Format may not be changed
>>>> -            // without breaking existing Log4j2Plugins.dat files.
>>>> -            out.writeInt(categories.size());
>>>> -            for (final Map.Entry<String, Map<String, PluginEntry>>
>>>> category : categories.entrySet()) {
>>>> -                out.writeUTF(category.getKey());
>>>> -                final Map<String, PluginEntry> m = category.getValue();
>>>> -                out.writeInt(m.size());
>>>> -                for (final Map.Entry<String, PluginEntry> entry :
>>>> m.entrySet()) {
>>>> -                    final PluginEntry plugin = entry.getValue();
>>>> -                    out.writeUTF(plugin.getKey());
>>>> -                    out.writeUTF(plugin.getClassName());
>>>> -                    out.writeUTF(plugin.getName());
>>>> -                    out.writeBoolean(plugin.isPrintable());
>>>> -                    out.writeBoolean(plugin.isDefer());
>>>> -                }
>>>> -            }
>>>> -        }
>>>> -    }
>>>> -
>>>> -    /**
>>>>    * Loads and merges all the Log4j plugin cache files specified.
>>>> Usually, this is obtained via a ClassLoader.
>>>>    *
>>>>    * @param resources URLs to all the desired plugin cache files to
>>>> load.
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>>>> similarity index 85%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>>>> index dd43601..bd452d3 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>>>> @@ -15,7 +15,7 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>>> +package org.apache.logging.log4j.plugins.processor;
>>>> 
>>>> import java.io.Serializable;
>>>> 
>>>> @@ -32,6 +32,18 @@ public class PluginEntry implements Serializable {
>>>>   private boolean defer;
>>>>   private transient String category;
>>>> 
>>>> +    public PluginEntry() {
>>>> +    }
>>>> +
>>>> +    public PluginEntry(String key, String className, String name, boolean
>>>> printable, boolean defer, String category) {
>>>> +        this.key = key;
>>>> +        this.className = className;
>>>> +        this.name = name;
>>>> +        this.printable = printable;
>>>> +        this.defer = defer;
>>>> +        this.category = category;
>>>> +    }
>>>> +
>>>>   public String getKey() {
>>>>       return key;
>>>>   }
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>>>> similarity index 54%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>>>> index 2f3b53f..975d2ab 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>>>> @@ -15,38 +15,47 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>>> +package org.apache.logging.log4j.plugins.processor;
>>>> +
>>>> +import org.apache.logging.log4j.LoggingException;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> +import org.apache.logging.log4j.plugins.PluginAliases;
>>>> +import org.apache.logging.log4j.util.Strings;
>>>> 
>>>> -import java.io.IOException;
>>>> -import java.io.OutputStream;
>>>> -import java.util.ArrayList;
>>>> -import java.util.Collection;
>>>> -import java.util.Collections;
>>>> -import java.util.Locale;
>>>> -import java.util.Map;
>>>> -import java.util.Objects;
>>>> -import java.util.Set;
>>>> import javax.annotation.processing.AbstractProcessor;
>>>> +import javax.annotation.processing.Messager;
>>>> import javax.annotation.processing.RoundEnvironment;
>>>> import javax.annotation.processing.SupportedAnnotationTypes;
>>>> import javax.lang.model.SourceVersion;
>>>> import javax.lang.model.element.Element;
>>>> import javax.lang.model.element.ElementVisitor;
>>>> +import javax.lang.model.element.Name;
>>>> import javax.lang.model.element.TypeElement;
>>>> import javax.lang.model.util.Elements;
>>>> import javax.lang.model.util.SimpleElementVisitor7;
>>>> import javax.tools.Diagnostic.Kind;
>>>> import javax.tools.FileObject;
>>>> +import javax.tools.JavaFileObject;
>>>> import javax.tools.StandardLocation;
>>>> +import java.io.BufferedWriter;
>>>> +import java.io.IOException;
>>>> +import java.io.OutputStreamWriter;
>>>> +import java.io.PrintWriter;
>>>> +import java.util.ArrayList;
>>>> +import java.util.Collection;
>>>> +import java.util.Collections;
>>>> +import java.util.List;
>>>> +import java.util.Locale;
>>>> +import java.util.Map;
>>>> +import java.util.Objects;
>>>> +import java.util.Set;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>>>> -import org.apache.logging.log4j.util.Strings;
>>>> +import static java.nio.charset.StandardCharsets.UTF_8;
>>>> 
>>>> /**
>>>> * Annotation processor for pre-scanning Log4j 2 plugins.
>>>> */
>>>> 
>>>> -@SupportedAnnotationTypes("org.apache.logging.log4j.core.config.plugins.*")
>>>> +@SupportedAnnotationTypes({"org.apache.logging.log4j.plugins.*",
>>>> "org.apache.logging.log4j.core.config.plugins.*"})
>>>> public class PluginProcessor extends AbstractProcessor {
>>>> 
>>>>   // TODO: this could be made more abstract to allow for compile-time
>>>> and run-time plugin processing
>>>> @@ -57,8 +66,8 @@ public class PluginProcessor extends AbstractProcessor {
>>>>    */
>>>>   public static final String PLUGIN_CACHE_FILE =
>>>> 
>>>> "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat";
>>>> -
>>>> -    private final PluginCache pluginCache = new PluginCache();
>>>> +    private static final String SERVICE_FILE_NAME =
>>>> +
>>>> "META-INF/services/org.apache.logging.log4j.plugins.processor.PluginService";
>>>> 
>>>>   @Override
>>>>   public SourceVersion getSupportedSourceVersion() {
>>>> @@ -67,16 +76,21 @@ public class PluginProcessor extends AbstractProcessor
>>>> {
>>>> 
>>>>   @Override
>>>>   public boolean process(final Set<? extends TypeElement> annotations,
>>>> final RoundEnvironment roundEnv) {
>>>> -        System.out.println("Processing annotations");
>>>> +        Map<String, String> options = processingEnv.getOptions();
>>>> +        String packageName = options.get("pluginPackage");
>>>> +        Messager messager = processingEnv.getMessager();
>>>> +        messager.printMessage(Kind.NOTE, "Processing Log4j annotations");
>>>>       try {
>>>>           final Set<? extends Element> elements =
>>>> roundEnv.getElementsAnnotatedWith(Plugin.class);
>>>>           if (elements.isEmpty()) {
>>>> -                System.out.println("No elements to process");
>>>> +                messager.printMessage(Kind.NOTE, "No elements to
>>>> process");
>>>>               return false;
>>>>           }
>>>> -            collectPlugins(elements);
>>>> -            writeCacheFile(elements.toArray(new
>>>> Element[elements.size()]));
>>>> -            System.out.println("Annotations processed");
>>>> +            List<PluginEntry> list = new ArrayList<>();
>>>> +            packageName = collectPlugins(packageName, elements, list);
>>>> +            writeClassFile(packageName, list);
>>>> +            writeServiceFile(packageName);
>>>> +            messager.printMessage(Kind.NOTE, "Annotations processed");
>>>>           return true;
>>>>       } catch (final IOException e) {
>>>>           e.printStackTrace();
>>>> @@ -93,7 +107,8 @@ public class PluginProcessor extends AbstractProcessor {
>>>>       processingEnv.getMessager().printMessage(Kind.ERROR, message);
>>>>   }
>>>> 
>>>> -    private void collectPlugins(final Iterable<? extends Element>
>>>> elements) {
>>>> +    private String collectPlugins(String packageName, final Iterable<?
>>>> extends Element> elements, List<PluginEntry> list) {
>>>> +        boolean calculatePackage = packageName == null;
>>>>       final Elements elementUtils = processingEnv.getElementUtils();
>>>>       final ElementVisitor<PluginEntry, Plugin> pluginVisitor = new
>>>> PluginElementVisitor(elementUtils);
>>>>       final ElementVisitor<Collection<PluginEntry>, Plugin>
>>>> pluginAliasesVisitor = new PluginAliasesElementVisitor(
>>>> @@ -104,23 +119,93 @@ public class PluginProcessor extends
>>>> AbstractProcessor {
>>>>               continue;
>>>>           }
>>>>           final PluginEntry entry = element.accept(pluginVisitor,
>>>> plugin);
>>>> -            final Map<String, PluginEntry> category =
>>>> pluginCache.getCategory(entry.getCategory());
>>>> -            category.put(entry.getKey(), entry);
>>>> +            list.add(entry);
>>>> +            if (calculatePackage) {
>>>> +                packageName = calculatePackage(elementUtils, element,
>>>> packageName);
>>>> +            }
>>>>           final Collection<PluginEntry> entries =
>>>> element.accept(pluginAliasesVisitor, plugin);
>>>>           for (final PluginEntry pluginEntry : entries) {
>>>> -                category.put(pluginEntry.getKey(), pluginEntry);
>>>> +                list.add(pluginEntry);
>>>>           }
>>>>       }
>>>> +        return packageName;
>>>>   }
>>>> 
>>>> -    private void writeCacheFile(final Element... elements) throws
>>>> IOException {
>>>> +    private String calculatePackage(Elements elements, Element element,
>>>> String packageName) {
>>>> +        Name name = elements.getPackageOf(element).getQualifiedName();
>>>> +        if (name == null) {
>>>> +            return null;
>>>> +        }
>>>> +        String pkgName = name.toString();
>>>> +        if (packageName == null) {
>>>> +            return pkgName;
>>>> +        }
>>>> +        if (pkgName.length() == packageName.length()) {
>>>> +            return packageName;
>>>> +        }
>>>> +        if (pkgName.length() < packageName.length() &&
>>>> packageName.startsWith(pkgName)) {
>>>> +            return pkgName;
>>>> +        }
>>>> +
>>>> +        return commonPrefix(pkgName, packageName);
>>>> +    }
>>>> +
>>>> +    private void writeServiceFile(String pkgName) throws IOException {
>>>>       final FileObject fileObject =
>>>> processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
>>>> Strings.EMPTY,
>>>> -                PLUGIN_CACHE_FILE, elements);
>>>> -        try (final OutputStream out = fileObject.openOutputStream()) {
>>>> -            pluginCache.writeCache(out);
>>>> +                SERVICE_FILE_NAME);
>>>> +        try (final PrintWriter writer = new PrintWriter(new
>>>> BufferedWriter(new OutputStreamWriter(fileObject.openOutputStream(),
>>>> UTF_8)))) {
>>>> +            writer.println(createFqcn(pkgName));
>>>> +        }
>>>> +    }
>>>> +
>>>> +    private void writeClassFile(String pkg, List<PluginEntry> list) {
>>>> +        String fqcn = createFqcn(pkg);
>>>> +        try (final PrintWriter writer = createSourceFile(fqcn)) {
>>>> +            writer.println("package " + pkg + ".plugins;");
>>>> +            writer.println("");
>>>> +            writer.println("import
>>>> org.apache.logging.log4j.plugins.processor.PluginEntry;");
>>>> +            writer.println("import
>>>> org.apache.logging.log4j.plugins.processor.PluginService;");
>>>> +            writer.println("");
>>>> +            writer.println("public class Log4jPlugins extends
>>>> PluginService {");
>>>> +            writer.println("");
>>>> +            writer.println("    private static PluginEntry[] entries =
>>>> new PluginEntry[] {");
>>>> +            StringBuilder sb = new StringBuilder();
>>>> +            int max = list.size() - 1;
>>>> +            for (int i = 0; i < list.size(); ++i) {
>>>> +                PluginEntry entry = list.get(i);
>>>> +                sb.append("        ").append("new PluginEntry(\"");
>>>> +                sb.append(entry.getKey()).append("\", \"");
>>>> +                sb.append(entry.getClassName()).append("\", \"");
>>>> +                sb.append(entry.getName()).append("\", ");
>>>> +                sb.append(entry.isPrintable()).append(", ");
>>>> +                sb.append(entry.isDefer()).append(", \"");
>>>> +                sb.append(entry.getCategory()).append("\")");
>>>> +                if (i < max) {
>>>> +                    sb.append(",");
>>>> +                }
>>>> +                writer.println(sb.toString());
>>>> +                sb.setLength(0);
>>>> +            }
>>>> +            writer.println("    };");
>>>> +            writer.println("    @Override");
>>>> +            writer.println("    public PluginEntry[] getEntries() {
>>>> return entries;}");
>>>> +            writer.println("}");
>>>>       }
>>>>   }
>>>> 
>>>> +    private PrintWriter createSourceFile(String fqcn) {
>>>> +        try {
>>>> +            JavaFileObject sourceFile =
>>>> processingEnv.getFiler().createSourceFile(fqcn);
>>>> +            return new PrintWriter(sourceFile.openWriter());
>>>> +        } catch (IOException e) {
>>>> +            throw new LoggingException("Unable to create Plugin Service
>>>> Class " + fqcn, e);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    private String createFqcn(String packageName) {
>>>> +        return packageName + ".plugins.Log4jPlugins";
>>>> +    }
>>>> +
>>>>   /**
>>>>    * ElementVisitor to scan the Plugin annotation.
>>>>    */
>>>> @@ -146,6 +231,20 @@ public class PluginProcessor extends
>>>> AbstractProcessor {
>>>>       }
>>>>   }
>>>> 
>>>> +    private String commonPrefix(String str1, String str2) {
>>>> +        int minLength = str1.length() < str2.length() ? str1.length() :
>>>> str2.length();
>>>> +        for (int i = 0; i < minLength; i++) {
>>>> +            if (str1.charAt(i) != str2.charAt(i)) {
>>>> +                if (i > 1 && str1.charAt(i-1) == '.') {
>>>> +                    return str1.substring(0, i-1);
>>>> +                } else {
>>>> +                    return str1.substring(0, i);
>>>> +                }
>>>> +            }
>>>> +        }
>>>> +        return str1.substring(0, minLength);
>>>> +    }
>>>> +
>>>>   /**
>>>>    * ElementVisitor to scan the PluginAliases annotation.
>>>>    */
>>>> diff --git
>>>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>>> new file mode 100644
>>>> index 0000000..5042456
>>>> --- /dev/null
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>>> @@ -0,0 +1,56 @@
>>>> +/*
>>>> + * 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.plugins.processor;
>>>> +
>>>> +import java.util.Collections;
>>>> +import java.util.LinkedHashMap;
>>>> +import java.util.Map;
>>>> +
>>>> +/**
>>>> + * Class Description goes here.
>>>> + */
>>>> +public abstract class PluginService {
>>>> +
>>>> +    private final Map<String, Map<String, PluginEntry>> categories = new
>>>> LinkedHashMap<>();
>>>> +
>>>> +    public PluginService() {
>>>> +        PluginEntry[] entries = getEntries();
>>>> +        for (PluginEntry entry : entries) {
>>>> +            String category = entry.getCategory().toLowerCase();
>>>> +            if (!categories.containsKey(category)) {
>>>> +                categories.put(category, new LinkedHashMap<>());
>>>> +            }
>>>> +            Map<String, PluginEntry> map = categories.get(category);
>>>> +            map.put(entry.getKey(), entry);
>>>> +        }
>>>> +    }
>>>> +
>>>> +    public abstract PluginEntry[] getEntries();
>>>> +
>>>> +    public Map<String, Map<String, PluginEntry>> getCategories() {
>>>> +        return Collections.unmodifiableMap(categories);
>>>> +    }
>>>> +
>>>> +    public Map<String, PluginEntry> getCategory(String category) {
>>>> +        return
>>>> Collections.unmodifiableMap(categories.get(category.toLowerCase()));
>>>> +    }
>>>> +
>>>> +    public long size() {
>>>> +        return categories.size();
>>>> +    }
>>>> +
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>>>> similarity index 94%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>>> copy to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>>>> index 4f6ddda..2c296f9 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>>>> @@ -19,4 +19,4 @@
>>>> * Java annotation processor for pre-scanning Log4j 2 plugins. This is
>>>> provided as an alternative to using the
>>>> * executable {@link
>>>> org.apache.logging.log4j.core.config.plugins.util.PluginManager} class in
>>>> your build process.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>>> +package org.apache.logging.log4j.plugins.processor;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>>>> similarity index 93%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>>>> index 0935ce8..ec8a07f 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>>>> @@ -15,7 +15,7 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.util;
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> 
>>>> /**
>>>> * A type of builder that can be used to configure and create a instances
>>>> using a Java DSL instead of
>>>> @@ -25,7 +25,7 @@ package org.apache.logging.log4j.core.util;
>>>> * <p>
>>>> *     When creating <em>plugin</em> builders, it is customary to create
>>>> the builder class as a public static inner class
>>>> *     called {@code Builder}. For instance, the builder class for
>>>> - *     {@link org.apache.logging.log4j.core.layout.PatternLayout
>>>> PatternLayout} would be
>>>> + *     org.apache.logging.log4j.core.layout.PatternLayout PatternLayout
>>>> would be
>>>> *     {@code PatternLayout.Builder}.
>>>> * </p>
>>>> *
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>>>> similarity index 96%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>>>> index 6f38d0e..b6f02f5 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>>>> @@ -15,17 +15,13 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> 
>>>> import org.apache.logging.log4j.Logger;
>>>> import org.apache.logging.log4j.status.StatusLogger;
>>>> import org.apache.logging.log4j.util.Strings;
>>>> 
>>>> -import java.util.Collection;
>>>> -import java.util.HashMap;
>>>> -import java.util.LinkedHashMap;
>>>> -import java.util.List;
>>>> -import java.util.Map;
>>>> +import java.util.*;
>>>> import java.util.concurrent.CopyOnWriteArrayList;
>>>> 
>>>> /**
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>>>> similarity index 81%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>>>> index 99fa610..9e8c6e2 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>>>> @@ -15,32 +15,28 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> +
>>>> +import org.apache.logging.log4j.Logger;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> +import org.apache.logging.log4j.plugins.PluginAliases;
>>>> +import org.apache.logging.log4j.plugins.processor.PluginCache;
>>>> +import org.apache.logging.log4j.plugins.processor.PluginEntry;
>>>> +import org.apache.logging.log4j.plugins.processor.PluginProcessor;
>>>> +import org.apache.logging.log4j.plugins.processor.PluginService;
>>>> +import org.apache.logging.log4j.status.StatusLogger;
>>>> +import org.apache.logging.log4j.util.LoaderUtil;
>>>> +import org.apache.logging.log4j.util.Strings;
>>>> 
>>>> import java.io.IOException;
>>>> import java.net.URI;
>>>> import java.net.URL;
>>>> import java.text.DecimalFormat;
>>>> -import java.util.ArrayList;
>>>> -import java.util.Collections;
>>>> -import java.util.Enumeration;
>>>> -import java.util.HashMap;
>>>> -import java.util.List;
>>>> -import java.util.Map;
>>>> +import java.util.*;
>>>> import java.util.concurrent.ConcurrentHashMap;
>>>> import java.util.concurrent.ConcurrentMap;
>>>> import java.util.concurrent.atomic.AtomicReference;
>>>> 
>>>> -import org.apache.logging.log4j.Logger;
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>>>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginCache;
>>>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor;
>>>> -import org.apache.logging.log4j.core.util.Loader;
>>>> -import org.apache.logging.log4j.status.StatusLogger;
>>>> -import org.apache.logging.log4j.util.Strings;
>>>> -
>>>> /**
>>>> * Registry singleton for PluginType maps partitioned by source type and
>>>> then by category names.
>>>> */
>>>> @@ -116,7 +112,8 @@ public class PluginRegistry {
>>>>           // already loaded
>>>>           return existing;
>>>>       }
>>>> -        final Map<String, List<PluginType<?>>> newPluginsByCategory =
>>>> decodeCacheFiles(Loader.getClassLoader());
>>>> +        final Map<String, List<PluginType<?>>> newPluginsByCategory =
>>>> decodeCacheFiles(LoaderUtil.getClassLoader());
>>>> +        loadPlugins(newPluginsByCategory);
>>>> 
>>>>       // Note multiple threads could be calling this method
>>>> concurrently. Both will do the work,
>>>>       // but only one will be allowed to store the result in the
>>>> AtomicReference.
>>>> @@ -144,6 +141,7 @@ public class PluginRegistry {
>>>>           return existing;
>>>>       }
>>>>       final Map<String, List<PluginType<?>>> newPluginsByCategory =
>>>> decodeCacheFiles(loader);
>>>> +        loadPlugins(loader, newPluginsByCategory);
>>>> 
>>>>       // Note multiple threads could be calling this method
>>>> concurrently. Both will do the work,
>>>>       // but only one will be allowed to store the result in the outer
>>>> map.
>>>> @@ -155,6 +153,51 @@ public class PluginRegistry {
>>>>       return newPluginsByCategory;
>>>>   }
>>>> 
>>>> +    /**
>>>> +     * @since 3.0
>>>> +     */
>>>> +    public void loadPlugins(Map<String, List<PluginType<?>>> map) {
>>>> +        for (ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
>>>> +            try {
>>>> +                loadPlugins(classLoader, map);
>>>> +            } catch (Throwable ex) {
>>>> +                LOGGER.debug("Unable to retrieve provider from
>>>> ClassLoader {}", classLoader, ex);
>>>> +            }
>>>> +        }
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * @since 3.0
>>>> +     */
>>>> +    public void loadPlugins(ClassLoader classLoader, Map<String,
>>>> List<PluginType<?>>> map) {
>>>> +        final long startTime = System.nanoTime();
>>>> +        final ServiceLoader<PluginService> serviceLoader =
>>>> ServiceLoader.load(PluginService.class, classLoader);
>>>> +        int pluginCount = 0;
>>>> +        for (final PluginService pluginService : serviceLoader) {
>>>> +            PluginEntry[] entries = pluginService.getEntries();
>>>> +            for (PluginEntry entry : entries) {
>>>> +                try {
>>>> +                    final Class<?> clazz =
>>>> classLoader.loadClass(entry.getClassName());
>>>> +                    final PluginType<?> type = new PluginType(entry,
>>>> clazz, entry.getName());
>>>> +                    String category = entry.getCategory().toLowerCase();
>>>> +                    if (!map.containsKey(category)) {
>>>> +                        map.put(category, new ArrayList<>());
>>>> +                    }
>>>> +                    List<PluginType<?>> list = map.get(category);
>>>> +                    list.add(type);
>>>> +                    ++pluginCount;
>>>> +                } catch (final ClassNotFoundException e) {
>>>> +                    LOGGER.info("Plugin [{}] could not be loaded due to
>>>> missing classes.", entry.getClassName(), e);
>>>> +                }
>>>> +            }
>>>> +        }
>>>> +        final long endTime = System.nanoTime();
>>>> +        final DecimalFormat numFormat = new DecimalFormat("#0.000000");
>>>> +        final double seconds = (endTime - startTime) * 1e-9;
>>>> +        LOGGER.debug("Took {} seconds to load {} plugins from {}",
>>>> +                numFormat.format(seconds), pluginCount, classLoader);
>>>> +    }
>>>> +
>>>>   private Map<String, List<PluginType<?>>> decodeCacheFiles(final
>>>> ClassLoader loader) {
>>>>       final long startTime = System.nanoTime();
>>>>       final PluginCache cache = new PluginCache();
>>>> @@ -214,7 +257,7 @@ public class PluginRegistry {
>>>> 
>>>>       final long startTime = System.nanoTime();
>>>>       final ResolverUtil resolver = new ResolverUtil();
>>>> -        final ClassLoader classLoader = Loader.getClassLoader();
>>>> +        final ClassLoader classLoader = LoaderUtil.getClassLoader();
>>>>       if (classLoader != null) {
>>>>           resolver.setClassLoader(classLoader);
>>>>       }
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>>>> similarity index 92%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>>>> index cc6bc66..c213f64 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>>>> @@ -14,16 +14,16 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> 
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry;
>>>> +import org.apache.logging.log4j.plugins.processor.PluginEntry;
>>>> 
>>>> /**
>>>> * Plugin Descriptor. This is a memento object for Plugin annotations
>>>> paired to their annotated classes.
>>>> *
>>>> * @param <T> The plug-in class, which can be any kind of class.
>>>> - * @see org.apache.logging.log4j.core.config.plugins.Plugin
>>>> + * @see org.apache.logging.log4j.plugins.Plugin
>>>> */
>>>> public class PluginType<T> {
>>>> 
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>>>> similarity index 97%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>>>> index 73b5fc0..a57356c 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>>>> @@ -14,33 +14,24 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> 
>>>> -import java.io.File;
>>>> -import java.io.FileInputStream;
>>>> -import java.io.IOException;
>>>> -import java.io.InputStream;
>>>> -import java.io.UnsupportedEncodingException;
>>>> +import org.apache.logging.log4j.Logger;
>>>> +import org.apache.logging.log4j.util.LoaderUtil;
>>>> +import org.apache.logging.log4j.status.StatusLogger;
>>>> +import org.osgi.framework.FrameworkUtil;
>>>> +import org.osgi.framework.wiring.BundleWiring;
>>>> +
>>>> +import java.io.*;
>>>> import java.net.URI;
>>>> import java.net.URISyntaxException;
>>>> import java.net.URL;
>>>> import java.net.URLDecoder;
>>>> import java.nio.charset.StandardCharsets;
>>>> -import java.util.Arrays;
>>>> -import java.util.Collection;
>>>> -import java.util.Enumeration;
>>>> -import java.util.HashSet;
>>>> -import java.util.List;
>>>> -import java.util.Set;
>>>> +import java.util.*;
>>>> import java.util.jar.JarEntry;
>>>> import java.util.jar.JarInputStream;
>>>> 
>>>> -import org.apache.logging.log4j.Logger;
>>>> -import org.apache.logging.log4j.core.util.Loader;
>>>> -import org.apache.logging.log4j.status.StatusLogger;
>>>> -import org.osgi.framework.FrameworkUtil;
>>>> -import org.osgi.framework.wiring.BundleWiring;
>>>> -
>>>> /**
>>>> * <p>
>>>> * ResolverUtil is used to locate classes that are available in the/a
>>>> class path and meet arbitrary conditions. The two
>>>> @@ -126,7 +117,7 @@ public class ResolverUtil {
>>>>    * @return the ClassLoader that will be used to scan for classes
>>>>    */
>>>>   public ClassLoader getClassLoader() {
>>>> -        return classloader != null ? classloader : (classloader =
>>>> Loader.getClassLoader(ResolverUtil.class, null));
>>>> +        return classloader != null ? classloader : (classloader =
>>>> LoaderUtil.getClassLoader(ResolverUtil.class, null));
>>>>   }
>>>> 
>>>>   /**
>>>> diff --git
>>>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>>>> new file mode 100644
>>>> index 0000000..e2bb462
>>>> --- /dev/null
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>>>> @@ -0,0 +1,217 @@
>>>> +/*
>>>> + * 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.plugins.util;
>>>> +
>>>> +import java.lang.reflect.*;
>>>> +import java.util.ArrayList;
>>>> +import java.util.List;
>>>> +import java.util.Objects;
>>>> +
>>>> +/**
>>>> + * Utility class for working with Java {@link Type}s and derivatives.
>>>> This class is adapted heavily from the
>>>> + * <a href="http://projects.spring.io/spring-framework/">Spring
>>>> Framework</a>, specifically the
>>>> + * <a href="
>>>> http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/TypeUtils.html
>>>> ">TypeUtils</a>
>>>> + * class.
>>>> + *
>>>> + * @see Type
>>>> + * @see GenericArrayType
>>>> + * @see ParameterizedType
>>>> + * @see WildcardType
>>>> + * @see Class
>>>> + * @since 2.1
>>>> + */
>>>> +public final class TypeUtil {
>>>> +
>>>> +    private TypeUtil() {
>>>> +    }
>>>> +
>>>> +    /**
>>>> +     * Gets all declared fields for the given class (including
>>>> superclasses).
>>>> +     *
>>>> +     * @param cls the class to examine
>>>> +     * @return all declared fields for the given class (including
>>>> superclasses).
>>>> +     * @see Class#getDeclaredFields()
>>>> +     */
>>>> +    public static List<Field> getAllDeclaredFields(Class<?> cls) {
>>>> +        final List<Field> fields = new ArrayList<>();
>>>> +        while (cls != null) {
>>>> +            for (final Field field : cls.getDeclaredFields()) {
>>>> +                fields.add(field);
>>>> +            }
>>>> +            cls = cls.getSuperclass();
>>>> +        }
>>>> +        return fields;
>>>> +    }
>>>> +    /**
>>>> +     * Indicates if two {@link Type}s are assignment compatible.
>>>> +     *
>>>> +     * @param lhs the left hand side to check assignability to
>>>> +     * @param rhs the right hand side to check assignability from
>>>> +     * @return {@code true} if it is legal to assign a variable of type
>>>> {@code rhs} to a variable of type {@code lhs}
>>>> +     * @see Class#isAssignableFrom(Class)
>>>> +     */
>>>> +    public static boolean isAssignable(final Type lhs, final Type rhs) {
>>>> +        Objects.requireNonNull(lhs, "No left hand side type provided");
>>>> +        Objects.requireNonNull(rhs, "No right hand side type provided");
>>>> +        if (lhs.equals(rhs)) {
>>>> +            return true;
>>>> +        }
>>>> +        if (Object.class.equals(lhs)) {
>>>> +            // everything is assignable to Object
>>>> +            return true;
>>>> +        }
>>>> +        // raw type on left
>>>> +        if (lhs instanceof Class<?>) {
>>>> +            final Class<?> lhsClass = (Class<?>) lhs;
>>>> +            if (rhs instanceof Class<?>) {
>>>> +                // no generics involved
>>>> +                final Class<?> rhsClass = (Class<?>) rhs;
>>>> +                return lhsClass.isAssignableFrom(rhsClass);
>>>> +            }
>>>> +            if (rhs instanceof ParameterizedType) {
>>>> +                // check to see if the parameterized type has the same
>>>> raw type as the lhs; this is legal
>>>> +                final Type rhsRawType = ((ParameterizedType)
>>>> rhs).getRawType();
>>>> +                if (rhsRawType instanceof Class<?>) {
>>>> +                    return lhsClass.isAssignableFrom((Class<?>)
>>>> rhsRawType);
>>>> +                }
>>>> +            }
>>>> +            if (lhsClass.isArray() && rhs instanceof GenericArrayType) {
>>>> +                // check for compatible array component types
>>>> +                return isAssignable(lhsClass.getComponentType(),
>>>> ((GenericArrayType) rhs).getGenericComponentType());
>>>> +            }
>>>> +        }
>>>> +        // parameterized type on left
>>>> +        if (lhs instanceof ParameterizedType) {
>>>> +            final ParameterizedType lhsType = (ParameterizedType) lhs;
>>>> +            if (rhs instanceof Class<?>) {
>>>> +                final Type lhsRawType = lhsType.getRawType();
>>>> +                if (lhsRawType instanceof Class<?>) {
>>>> +                    return ((Class<?>)
>>>> lhsRawType).isAssignableFrom((Class<?>) rhs);
>>>> +                }
>>>> +            } else if (rhs instanceof ParameterizedType) {
>>>> +                final ParameterizedType rhsType = (ParameterizedType) rhs;
>>>> +                return isParameterizedAssignable(lhsType, rhsType);
>>>> +            }
>>>> +        }
>>>> +        // generic array type on left
>>>> +        if (lhs instanceof GenericArrayType) {
>>>> +            final Type lhsComponentType = ((GenericArrayType)
>>>> lhs).getGenericComponentType();
>>>> +            if (rhs instanceof Class<?>) {
>>>> +                // raw type on right
>>>> +                final Class<?> rhsClass = (Class<?>) rhs;
>>>> +                if (rhsClass.isArray()) {
>>>> +                    return isAssignable(lhsComponentType,
>>>> rhsClass.getComponentType());
>>>> +                }
>>>> +            } else if (rhs instanceof GenericArrayType) {
>>>> +                return isAssignable(lhsComponentType, ((GenericArrayType)
>>>> rhs).getGenericComponentType());
>>>> +            }
>>>> +        }
>>>> +        // wildcard type on left
>>>> +        if (lhs instanceof WildcardType) {
>>>> +            return isWildcardAssignable((WildcardType) lhs, rhs);
>>>> +        }
>>>> +        // strange...
>>>> +        return false;
>>>> +    }
>>>> +
>>>> +    private static boolean isParameterizedAssignable(final
>>>> ParameterizedType lhs, final ParameterizedType rhs) {
>>>> +        if (lhs.equals(rhs)) {
>>>> +            // that was easy
>>>> +            return true;
>>>> +        }
>>>> +        final Type[] lhsTypeArguments = lhs.getActualTypeArguments();
>>>> +        final Type[] rhsTypeArguments = rhs.getActualTypeArguments();
>>>> +        final int size = lhsTypeArguments.length;
>>>> +        if (rhsTypeArguments.length != size) {
>>>> +            // clearly incompatible types
>>>> +            return false;
>>>> +        }
>>>> +        for (int i = 0; i < size; i++) {
>>>> +            // verify all type arguments are assignable
>>>> +            final Type lhsArgument = lhsTypeArguments[i];
>>>> +            final Type rhsArgument = rhsTypeArguments[i];
>>>> +            if (!lhsArgument.equals(rhsArgument) &&
>>>> +                !(lhsArgument instanceof WildcardType &&
>>>> +                    isWildcardAssignable((WildcardType) lhsArgument,
>>>> rhsArgument))) {
>>>> +                return false;
>>>> +            }
>>>> +        }
>>>> +        return true;
>>>> +    }
>>>> +
>>>> +    private static boolean isWildcardAssignable(final WildcardType lhs,
>>>> final Type rhs) {
>>>> +        final Type[] lhsUpperBounds = getEffectiveUpperBounds(lhs);
>>>> +        final Type[] lhsLowerBounds = getEffectiveLowerBounds(lhs);
>>>> +        if (rhs instanceof WildcardType) {
>>>> +            // oh boy, this scenario requires checking a lot of
>>>> assignability!
>>>> +            final WildcardType rhsType = (WildcardType) rhs;
>>>> +            final Type[] rhsUpperBounds =
>>>> getEffectiveUpperBounds(rhsType);
>>>> +            final Type[] rhsLowerBounds =
>>>> getEffectiveLowerBounds(rhsType);
>>>> +            for (final Type lhsUpperBound : lhsUpperBounds) {
>>>> +                for (final Type rhsUpperBound : rhsUpperBounds) {
>>>> +                    if (!isBoundAssignable(lhsUpperBound, rhsUpperBound))
>>>> {
>>>> +                        return false;
>>>> +                    }
>>>> +                }
>>>> +                for (final Type rhsLowerBound : rhsLowerBounds) {
>>>> +                    if (!isBoundAssignable(lhsUpperBound, rhsLowerBound))
>>>> {
>>>> +                        return false;
>>>> +                    }
>>>> +                }
>>>> +            }
>>>> +            for (final Type lhsLowerBound : lhsLowerBounds) {
>>>> +                for (final Type rhsUpperBound : rhsUpperBounds) {
>>>> +                    if (!isBoundAssignable(rhsUpperBound, lhsLowerBound))
>>>> {
>>>> +                        return false;
>>>> +                    }
>>>> +                }
>>>> +                for (final Type rhsLowerBound : rhsLowerBounds) {
>>>> +                    if (!isBoundAssignable(rhsLowerBound, lhsLowerBound))
>>>> {
>>>> +                        return false;
>>>> +                    }
>>>> +                }
>>>> +            }
>>>> +        } else {
>>>> +            // phew, far less bounds to check
>>>> +            for (final Type lhsUpperBound : lhsUpperBounds) {
>>>> +                if (!isBoundAssignable(lhsUpperBound, rhs)) {
>>>> +                    return false;
>>>> +                }
>>>> +            }
>>>> +            for (final Type lhsLowerBound : lhsLowerBounds) {
>>>> +                if (!isBoundAssignable(lhsLowerBound, rhs)) {
>>>> +                    return false;
>>>> +                }
>>>> +            }
>>>> +        }
>>>> +        return true;
>>>> +    }
>>>> +
>>>> +    private static Type[] getEffectiveUpperBounds(final WildcardType
>>>> type) {
>>>> +        final Type[] upperBounds = type.getUpperBounds();
>>>> +        return upperBounds.length == 0 ? new Type[]{Object.class} :
>>>> upperBounds;
>>>> +    }
>>>> +
>>>> +    private static Type[] getEffectiveLowerBounds(final WildcardType
>>>> type) {
>>>> +        final Type[] lowerBounds = type.getLowerBounds();
>>>> +        return lowerBounds.length == 0 ? new Type[]{null} : lowerBounds;
>>>> +    }
>>>> +
>>>> +    private static boolean isBoundAssignable(final Type lhs, final Type
>>>> rhs) {
>>>> +        return (rhs == null) || ((lhs != null) && isAssignable(lhs, rhs));
>>>> +    }
>>>> +}
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>>>> similarity index 94%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>>>> index 4f6ddda..fae7580 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>>>> @@ -19,4 +19,4 @@
>>>> * Java annotation processor for pre-scanning Log4j 2 plugins. This is
>>>> provided as an alternative to using the
>>>> * executable {@link
>>>> org.apache.logging.log4j.core.config.plugins.util.PluginManager} class in
>>>> your build process.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>>>> similarity index 81%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>>>> index 0ac2223..4586315 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>>>> @@ -14,14 +14,9 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> -import java.lang.annotation.Annotation;
>>>> -import java.lang.annotation.Documented;
>>>> -import java.lang.annotation.ElementType;
>>>> -import java.lang.annotation.Retention;
>>>> -import java.lang.annotation.RetentionPolicy;
>>>> -import java.lang.annotation.Target;
>>>> +import java.lang.annotation.*;
>>>> 
>>>> /**
>>>> * Meta annotation to mark an annotation as a validation constraint. This
>>>> annotation must specify a
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>>>> similarity index 96%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>>>> index 1d8c0c5..2f638a7 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>>>> @@ -14,7 +14,7 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> import java.lang.annotation.Annotation;
>>>> 
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>>>> similarity index 93%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>>>> index 374c8ec..6236bb6 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>>>> @@ -14,7 +14,9 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> +
>>>> +import org.apache.logging.log4j.util.ReflectionUtil;
>>>> 
>>>> import java.lang.annotation.Annotation;
>>>> import java.lang.reflect.ParameterizedType;
>>>> @@ -22,8 +24,6 @@ import java.lang.reflect.Type;
>>>> import java.util.ArrayList;
>>>> import java.util.Collection;
>>>> 
>>>> -import org.apache.logging.log4j.core.util.ReflectionUtil;
>>>> -
>>>> /**
>>>> * Utility class to locate an appropriate {@link ConstraintValidator}
>>>> implementation for an annotation.
>>>> *
>>>> @@ -36,7 +36,7 @@ public final class ConstraintValidators {
>>>> 
>>>>   /**
>>>>    * Finds all relevant {@link ConstraintValidator} objects from an
>>>> array of annotations. All validators will be
>>>> -     * {@link
>>>> ConstraintValidator#initialize(java.lang.annotation.Annotation)
>>>> initialized} before being returned.
>>>> +     * {@link ConstraintValidator#initialize(Annotation) initialized}
>>>> before being returned.
>>>>    *
>>>>    * @param annotations the annotations to find constraint validators
>>>> for
>>>>    * @return a collection of ConstraintValidators for the given
>>>> annotations
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>>>> similarity index 73%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>>>> index e6f3c56..9b8a75d 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>>>> @@ -15,16 +15,12 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +package org.apache.logging.log4j.plugins.validation.constraints;
>>>> 
>>>> -import java.lang.annotation.Documented;
>>>> -import java.lang.annotation.ElementType;
>>>> -import java.lang.annotation.Retention;
>>>> -import java.lang.annotation.RetentionPolicy;
>>>> -import java.lang.annotation.Target;
>>>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>>>> +import
>>>> org.apache.logging.log4j.plugins.validation.validators.RequiredValidator;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.validators.RequiredValidator;
>>>> +import java.lang.annotation.*;
>>>> 
>>>> /**
>>>> * Marks a plugin builder field or plugin factory parameter as required.
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>>>> similarity index 84%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>>>> index c652d40..14dd9a8 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>>>> @@ -14,10 +14,10 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +package org.apache.logging.log4j.plugins.validation.constraints;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.validators.ValidHostValidator;
>>>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>>>> +import
>>>> org.apache.logging.log4j.plugins.validation.validators.ValidHostValidator;
>>>> 
>>>> import java.lang.annotation.*;
>>>> import java.net.InetAddress;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>>>> similarity index 74%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>>>> index a7c68b1..c4aba16 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>>>> @@ -14,16 +14,12 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +package org.apache.logging.log4j.plugins.validation.constraints;
>>>> 
>>>> -import java.lang.annotation.Documented;
>>>> -import java.lang.annotation.ElementType;
>>>> -import java.lang.annotation.Retention;
>>>> -import java.lang.annotation.RetentionPolicy;
>>>> -import java.lang.annotation.Target;
>>>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>>>> +import
>>>> org.apache.logging.log4j.plugins.validation.validators.ValidPortValidator;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.validators.ValidPortValidator;
>>>> +import java.lang.annotation.*;
>>>> 
>>>> /**
>>>> * Indicates that a plugin attribute must be a valid port number. A valid
>>>> port number is an integer between 0 and
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>>>> similarity index 91%
>>>> copy from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> copy to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>>>> index f22ba49..298cd5a 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>>>> @@ -20,4 +20,4 @@
>>>> *
>>>> * @since 2.1
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +package org.apache.logging.log4j.plugins.validation.constraints;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>>>> similarity index 93%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>>>> index 171b25a..15955cb 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>>>> @@ -20,4 +20,4 @@
>>>> *
>>>> * @since 2.1
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>>>> similarity index 86%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>>>> index 98c0a71..9df6d3b 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>>>> @@ -14,17 +14,17 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>>>> -
>>>> -import java.util.Collection;
>>>> -import java.util.Map;
>>>> +package org.apache.logging.log4j.plugins.validation.validators;
>>>> 
>>>> import org.apache.logging.log4j.Logger;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>>>> -import org.apache.logging.log4j.core.util.Assert;
>>>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>>> +import org.apache.logging.log4j.util.Assert;
>>>> import org.apache.logging.log4j.status.StatusLogger;
>>>> 
>>>> +import java.util.Collection;
>>>> +import java.util.Map;
>>>> +
>>>> /**
>>>> * Validator that checks an object for emptiness. Emptiness is defined
>>>> here as:
>>>> * <ul>
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>>>> similarity index 89%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>>>> index 6c01753..41abbfd 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>>>> @@ -14,11 +14,11 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>>>> +package org.apache.logging.log4j.plugins.validation.validators;
>>>> 
>>>> import org.apache.logging.log4j.Logger;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
>>>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
>>>> import org.apache.logging.log4j.status.StatusLogger;
>>>> 
>>>> import java.net.InetAddress;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>>>> similarity index 85%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>>>> index a59742c..27e97f0 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>>>> @@ -14,12 +14,12 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>>>> +package org.apache.logging.log4j.plugins.validation.validators;
>>>> 
>>>> import org.apache.logging.log4j.Logger;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
>>>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
>>>> +import org.apache.logging.log4j.plugins.convert.TypeConverters;
>>>> import org.apache.logging.log4j.status.StatusLogger;
>>>> 
>>>> /**
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>>>> similarity index 92%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>>>> index a8ac560..cfe2041 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>>>> @@ -20,4 +20,4 @@
>>>> *
>>>> * @since 2.1
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>>>> +package org.apache.logging.log4j.plugins.validation.validators;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>>>> similarity index 84%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>>>> index 560cbe3..b98dc09 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>>>> @@ -15,18 +15,18 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> +
>>>> +import org.apache.logging.log4j.Logger;
>>>> +import org.apache.logging.log4j.plugins.convert.TypeConverters;
>>>> +import org.apache.logging.log4j.status.StatusLogger;
>>>> +import org.apache.logging.log4j.util.Strings;
>>>> 
>>>> import java.lang.annotation.Annotation;
>>>> import java.lang.reflect.Member;
>>>> import java.util.Map;
>>>> import java.util.Objects;
>>>> -
>>>> -import org.apache.logging.log4j.Logger;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
>>>> -import org.apache.logging.log4j.core.lookup.StrSubstitutor;
>>>> -import org.apache.logging.log4j.status.StatusLogger;
>>>> -import org.apache.logging.log4j.util.Strings;
>>>> +import java.util.function.Function;
>>>> 
>>>> /**
>>>> * Base class for PluginVisitor implementations. Provides convenience
>>>> methods as well as all method implementations
>>>> @@ -34,7 +34,7 @@ import org.apache.logging.log4j.util.Strings;
>>>> *
>>>> * @param <A> the Plugin annotation type.
>>>> */
>>>> -public abstract class AbstractPluginVisitor<A extends Annotation>
>>>> implements PluginVisitor<A> {
>>>> +public abstract class AbstractPluginVisitor<A extends Annotation, T>
>>>> implements PluginVisitor<A, T> {
>>>> 
>>>>   /** Status logger. */
>>>>   protected static final Logger LOGGER = StatusLogger.getLogger();
>>>> @@ -58,10 +58,6 @@ public abstract class AbstractPluginVisitor<A extends
>>>> Annotation> implements Plu
>>>>   /**
>>>>    *
>>>>    */
>>>> -    protected StrSubstitutor substitutor;
>>>> -    /**
>>>> -     *
>>>> -     */
>>>>   protected Member member;
>>>> 
>>>>   /**
>>>> @@ -75,7 +71,7 @@ public abstract class AbstractPluginVisitor<A extends
>>>> Annotation> implements Plu
>>>> 
>>>>   @SuppressWarnings("unchecked")
>>>>   @Override
>>>> -    public PluginVisitor<A> setAnnotation(final Annotation anAnnotation) {
>>>> +    public PluginVisitor<A, T> setAnnotation(final Annotation
>>>> anAnnotation) {
>>>>       final Annotation a = Objects.requireNonNull(anAnnotation, "No
>>>> annotation was provided");
>>>>       if (this.clazz.isInstance(a)) {
>>>>           this.annotation = (A) a;
>>>> @@ -84,25 +80,19 @@ public abstract class AbstractPluginVisitor<A extends
>>>> Annotation> implements Plu
>>>>   }
>>>> 
>>>>   @Override
>>>> -    public PluginVisitor<A> setAliases(final String... someAliases) {
>>>> +    public PluginVisitor<A, T> setAliases(final String... someAliases) {
>>>>       this.aliases = someAliases;
>>>>       return this;
>>>>   }
>>>> 
>>>>   @Override
>>>> -    public PluginVisitor<A> setConversionType(final Class<?>
>>>> aConversionType) {
>>>> +    public PluginVisitor<A, T> setConversionType(final Class<?>
>>>> aConversionType) {
>>>>       this.conversionType = Objects.requireNonNull(aConversionType, "No
>>>> conversion type class was provided");
>>>>       return this;
>>>>   }
>>>> 
>>>>   @Override
>>>> -    public PluginVisitor<A> setStrSubstitutor(final StrSubstitutor
>>>> aSubstitutor) {
>>>> -        this.substitutor = Objects.requireNonNull(aSubstitutor, "No
>>>> StrSubstitutor was provided");
>>>> -        return this;
>>>> -    }
>>>> -
>>>> -    @Override
>>>> -    public PluginVisitor<A> setMember(final Member aMember) {
>>>> +    public PluginVisitor<A, T> setMember(final Member aMember) {
>>>>       this.member = aMember;
>>>>       return this;
>>>>   }
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>>>> similarity index 80%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>>>> index f4da42b..fbd28b9 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>>>> @@ -15,40 +15,39 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> 
>>>> -import java.util.Map;
>>>> -
>>>> -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.PluginAttribute;
>>>> -import org.apache.logging.log4j.core.util.NameUtil;
>>>> +import org.apache.logging.log4j.plugins.Node;
>>>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>>>> +import org.apache.logging.log4j.util.NameUtil;
>>>> import org.apache.logging.log4j.util.StringBuilders;
>>>> 
>>>> +import java.util.Map;
>>>> +import java.util.function.Function;
>>>> +
>>>> /**
>>>> * PluginVisitor implementation for {@link PluginAttribute}.
>>>> */
>>>> -public class PluginAttributeVisitor extends
>>>> AbstractPluginVisitor<PluginAttribute> {
>>>> +public class PluginAttributeVisitor extends
>>>> AbstractPluginVisitor<PluginAttribute, Object> {
>>>>   public PluginAttributeVisitor() {
>>>>       super(PluginAttribute.class);
>>>>   }
>>>> 
>>>>   @Override
>>>> -    public Object visit(final Configuration configuration, final Node
>>>> node, final LogEvent event,
>>>> +    public Object visit(final Object unused, final Node node, final
>>>> Function<String, String> substitutor,
>>>>                       final StringBuilder log) {
>>>>       final String name = this.annotation.value();
>>>>       final Map<String, String> attributes = node.getAttributes();
>>>>       final String rawValue = removeAttributeValue(attributes, name,
>>>> this.aliases);
>>>> -        final String replacedValue = this.substitutor.replace(event,
>>>> rawValue);
>>>> -        final Object defaultValue = findDefaultValue(event);
>>>> +        final String replacedValue = substitutor.apply(rawValue);
>>>> +        final Object defaultValue = findDefaultValue(substitutor);
>>>>       final Object value = convert(replacedValue, defaultValue);
>>>>       final Object debugValue = this.annotation.sensitive() ?
>>>> NameUtil.md5(value + this.getClass().getName()) : value;
>>>>       StringBuilders.appendKeyDqValue(log, name, debugValue);
>>>>       return value;
>>>>   }
>>>> 
>>>> -    private Object findDefaultValue(final LogEvent event) {
>>>> +    private Object findDefaultValue(Function<String, String> substitutor)
>>>> {
>>>>       if (this.conversionType == int.class || this.conversionType ==
>>>> Integer.class) {
>>>>           return this.annotation.defaultInt();
>>>>       }
>>>> @@ -76,6 +75,6 @@ public class PluginAttributeVisitor extends
>>>> AbstractPluginVisitor<PluginAttribut
>>>>       if (this.conversionType == Class.class) {
>>>>           return this.annotation.defaultClass();
>>>>       }
>>>> -        return this.substitutor.replace(event,
>>>> this.annotation.defaultString());
>>>> +        return substitutor.apply(this.annotation.defaultString());
>>>>   }
>>>> }
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>>>> similarity index 74%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>>>> index e951456..398ff1c 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>>>> @@ -15,38 +15,37 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> 
>>>> -import java.util.Map;
>>>> -
>>>> -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.PluginBuilderAttribute;
>>>> -import org.apache.logging.log4j.core.util.NameUtil;
>>>> +import org.apache.logging.log4j.plugins.Node;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>>> +import org.apache.logging.log4j.util.NameUtil;
>>>> import org.apache.logging.log4j.util.StringBuilders;
>>>> 
>>>> +import java.util.Map;
>>>> +import java.util.function.Function;
>>>> +
>>>> /**
>>>> * PluginVisitor for PluginBuilderAttribute. If {@code null} is returned
>>>> for the
>>>> - * {@link #visit(org.apache.logging.log4j.core.config.Configuration,
>>>> org.apache.logging.log4j.core.config.Node,
>>>> org.apache.logging.log4j.core.LogEvent, StringBuilder)}
>>>> + * {@link #visit(org.apache.logging.log4j.core.config.Configuration,
>>>> org.apache.logging.log4j.plugins.Node,
>>>> org.apache.logging.log4j.core.LogEvent, StringBuilder)}
>>>> * method, then the default value of the field should remain untouched.
>>>> *
>>>> * @see org.apache.logging.log4j.core.config.plugins.util.PluginBuilder
>>>> */
>>>> -public class PluginBuilderAttributeVisitor extends
>>>> AbstractPluginVisitor<PluginBuilderAttribute> {
>>>> +public class PluginBuilderAttributeVisitor extends
>>>> AbstractPluginVisitor<PluginBuilderAttribute, Object> {
>>>> 
>>>>   public PluginBuilderAttributeVisitor() {
>>>>       super(PluginBuilderAttribute.class);
>>>>   }
>>>> 
>>>>   @Override
>>>> -    public Object visit(final Configuration configuration, final Node
>>>> node, final LogEvent event,
>>>> +    public Object visit(final Object unused, final Node node, final
>>>> Function<String, String> substitutor,
>>>>                       final StringBuilder log) {
>>>>       final String overridden = this.annotation.value();
>>>>       final String name = overridden.isEmpty() ? this.member.getName()
>>>> : overridden;
>>>>       final Map<String, String> attributes = node.getAttributes();
>>>>       final String rawValue = removeAttributeValue(attributes, name,
>>>> this.aliases);
>>>> -        final String replacedValue = this.substitutor.replace(event,
>>>> rawValue);
>>>> +        final String replacedValue = substitutor.apply(rawValue);
>>>>       final Object value = convert(replacedValue, null);
>>>>       final Object debugValue = this.annotation.sensitive() ?
>>>> NameUtil.md5(value + this.getClass().getName()) : value;
>>>>       StringBuilders.appendKeyDqValue(log, name, debugValue);
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>>>> similarity index 90%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>>>> index 2e6e6ef..f8197f1 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>>>> @@ -15,30 +15,29 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.Node;
>>>> +import org.apache.logging.log4j.plugins.PluginElement;
>>>> +import org.apache.logging.log4j.plugins.util.PluginType;
>>>> 
>>>> import java.lang.reflect.Array;
>>>> import java.util.ArrayList;
>>>> import java.util.Arrays;
>>>> import java.util.Collection;
>>>> import java.util.List;
>>>> -
>>>> -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.PluginElement;
>>>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>>>> +import java.util.function.Function;
>>>> 
>>>> /**
>>>> * PluginVisitor implementation for {@link PluginElement}. Supports
>>>> arrays as well as singular values.
>>>> */
>>>> -public class PluginElementVisitor extends
>>>> AbstractPluginVisitor<PluginElement> {
>>>> +public class PluginElementVisitor extends
>>>> AbstractPluginVisitor<PluginElement, Object> {
>>>>   public PluginElementVisitor() {
>>>>       super(PluginElement.class);
>>>>   }
>>>> 
>>>>   @Override
>>>> -    public Object visit(final Configuration configuration, final Node
>>>> node, final LogEvent event,
>>>> +    public Object visit(final Object unused, final Node node, final
>>>> Function<String, String> substitutor,
>>>>                       final StringBuilder log) {
>>>>       final String name = this.annotation.value();
>>>>       if (this.conversionType.isArray()) {
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>>>> similarity index 77%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>>>> index 7f15392..9438b39 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>>>> @@ -15,23 +15,23 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> 
>>>> -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.PluginNode;
>>>> +import org.apache.logging.log4j.plugins.Node;
>>>> +import org.apache.logging.log4j.plugins.PluginNode;
>>>> +
>>>> +import java.util.function.Function;
>>>> 
>>>> /**
>>>> * PluginVisitor implementation for {@link PluginNode}.
>>>> */
>>>> -public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode> {
>>>> +public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode,
>>>> Object> {
>>>>   public PluginNodeVisitor() {
>>>>       super(PluginNode.class);
>>>>   }
>>>> 
>>>>   @Override
>>>> -    public Object visit(final Configuration configuration, final Node
>>>> node, final LogEvent event,
>>>> +    public Object visit(final Object unused, final Node node, final
>>>> Function<String, String> substitutor,
>>>>                       final StringBuilder log) {
>>>>       if (this.conversionType.isInstance(node)) {
>>>>           log.append("Node=").append(node.getName());
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>>>> similarity index 79%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>>>> index 8544570..2f68f04 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>>>> @@ -15,26 +15,26 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> 
>>>> -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.PluginValue;
>>>> +import org.apache.logging.log4j.plugins.Node;
>>>> +import org.apache.logging.log4j.plugins.PluginValue;
>>>> import org.apache.logging.log4j.util.StringBuilders;
>>>> import org.apache.logging.log4j.util.Strings;
>>>> 
>>>> +import java.util.function.Function;
>>>> +
>>>> /**
>>>> * PluginVisitor implementation for {@link PluginValue}.
>>>> */
>>>> -public class PluginValueVisitor extends
>>>> AbstractPluginVisitor<PluginValue> {
>>>> +public class PluginValueVisitor extends
>>>> AbstractPluginVisitor<PluginValue, Object> {
>>>>   public PluginValueVisitor() {
>>>>       super(PluginValue.class);
>>>>   }
>>>> 
>>>>   @Override
>>>> -    public Object visit(final Configuration configuration, final Node
>>>> node, final LogEvent event,
>>>> -            final StringBuilder log) {
>>>> +    public Object visit(final Object unused, final Node node, final
>>>> Function<String, String> substitutor,
>>>> +                        final StringBuilder log) {
>>>>       final String name = this.annotation.value();
>>>>       final String elementValue = node.getValue();
>>>>       final String attributeValue = node.getAttributes().get("value");
>>>> @@ -49,7 +49,7 @@ public class PluginValueVisitor extends
>>>> AbstractPluginVisitor<PluginValue> {
>>>>       } else {
>>>>           rawValue = removeAttributeValue(node.getAttributes(),
>>>> "value");
>>>>       }
>>>> -        final String value = this.substitutor.replace(event, rawValue);
>>>> +        final String value = substitutor.apply(rawValue);
>>>>       StringBuilders.appendKeyDqValue(log, name, value);
>>>>       return value;
>>>>   }
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>>>> similarity index 68%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>>>> index 34e2b78..fb7aca4 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>>>> @@ -15,15 +15,13 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.Node;
>>>> 
>>>> import java.lang.annotation.Annotation;
>>>> import java.lang.reflect.Member;
>>>> -
>>>> -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.lookup.StrSubstitutor;
>>>> +import java.util.function.Function;
>>>> 
>>>> /**
>>>> * Visitor strategy for parsing data from a {@link Node}, doing any
>>>> relevant type conversion, and returning a
>>>> @@ -31,7 +29,7 @@ import
>>>> org.apache.logging.log4j.core.lookup.StrSubstitutor;
>>>> *
>>>> * @param <A> the Annotation type.
>>>> */
>>>> -public interface PluginVisitor<A extends Annotation> {
>>>> +public interface PluginVisitor<A extends Annotation, T> {
>>>> 
>>>>   /**
>>>>    * Sets the Annotation to be used for this. If the given Annotation
>>>> is not compatible with this class's type, then
>>>> @@ -41,7 +39,7 @@ public interface PluginVisitor<A extends Annotation> {
>>>>    * @return {@code this}.
>>>>    * @throws NullPointerException if the argument is {@code null}.
>>>>    */
>>>> -    PluginVisitor<A> setAnnotation(Annotation annotation);
>>>> +    PluginVisitor<A, T> setAnnotation(Annotation annotation);
>>>> 
>>>>   /**
>>>>    * Sets the list of aliases to use for this visit. No aliases are
>>>> required, however.
>>>> @@ -49,7 +47,7 @@ public interface PluginVisitor<A extends Annotation> {
>>>>    * @param aliases the list of aliases to use.
>>>>    * @return {@code this}.
>>>>    */
>>>> -    PluginVisitor<A> setAliases(String... aliases);
>>>> +    PluginVisitor<A, T> setAliases(String... aliases);
>>>> 
>>>>   /**
>>>>    * Sets the class to convert the plugin value to on this visit. This
>>>> should correspond with a class obtained from
>>>> @@ -59,17 +57,7 @@ public interface PluginVisitor<A extends Annotation> {
>>>>    * @return {@code this}.
>>>>    * @throws NullPointerException if the argument is {@code null}.
>>>>    */
>>>> -    PluginVisitor<A> setConversionType(Class<?> conversionType);
>>>> -
>>>> -    /**
>>>> -     * Sets the StrSubstitutor to use for converting raw strings before
>>>> type conversion. Generally obtained from a
>>>> -     * {@link org.apache.logging.log4j.core.config.Configuration}.
>>>> -     *
>>>> -     * @param substitutor the StrSubstitutor to use on plugin values.
>>>> -     * @return {@code this}.
>>>> -     * @throws NullPointerException if the argument is {@code null}.
>>>> -     */
>>>> -    PluginVisitor<A> setStrSubstitutor(StrSubstitutor substitutor);
>>>> +    PluginVisitor<A, T> setConversionType(Class<?> conversionType);
>>>> 
>>>>   /**
>>>>    * Sets the Member that this visitor is being used for injection
>>>> upon. For instance, this could be the Field
>>>> @@ -79,16 +67,16 @@ public interface PluginVisitor<A extends Annotation> {
>>>>    * @param member the member this visitor is parsing a value for.
>>>>    * @return {@code this}.
>>>>    */
>>>> -    PluginVisitor<A> setMember(Member member);
>>>> +    PluginVisitor<A, T> setMember(Member member);
>>>> 
>>>>   /**
>>>>    * Visits a Node to obtain a value for constructing a Plugin object.
>>>>    *
>>>>    * @param configuration the current Configuration.
>>>>    * @param node          the current Node corresponding to the Plugin
>>>> object being created.
>>>> -     * @param event         the current LogEvent that caused this Plugin
>>>> object to be made (optional).
>>>> -     * @param log           the StringBuilder being used to build a debug
>>>> message.
>>>> +     * @param substitutor   the function to perform String substitutions.
>>>> +     * @param log           th e StringBuilder being used to build a
>>>> debug message.
>>>>    * @return the converted value to be used for Plugin creation.
>>>>    */
>>>> -    Object visit(Configuration configuration, Node node, LogEvent event,
>>>> StringBuilder log);
>>>> +    Object visit(T configuration, Node node, Function<String, String>
>>>> substitutor, StringBuilder log);
>>>> }
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>>>> similarity index 86%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>>>> index 10ee0df..695d387 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>>>> @@ -15,14 +15,14 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>>> -
>>>> -import java.lang.annotation.Annotation;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> 
>>>> import org.apache.logging.log4j.Logger;
>>>> -import org.apache.logging.log4j.core.config.plugins.PluginVisitorStrategy;
>>>> +import org.apache.logging.log4j.plugins.PluginVisitorStrategy;
>>>> import org.apache.logging.log4j.status.StatusLogger;
>>>> 
>>>> +import java.lang.annotation.Annotation;
>>>> +
>>>> /**
>>>> * Utility class to locate an appropriate {@link PluginVisitor}
>>>> implementation for an annotation.
>>>> */
>>>> @@ -41,13 +41,13 @@ public final class PluginVisitors {
>>>>    * @param annotation the Plugin annotation class to find a
>>>> PluginVisitor for.
>>>>    * @return a PluginVisitor instance if one could be created, or
>>>> {@code null} otherwise.
>>>>    */
>>>> -    public static PluginVisitor<? extends Annotation> findVisitor(final
>>>> Class<? extends Annotation> annotation) {
>>>> +    public static <T> PluginVisitor<? extends Annotation, T>
>>>> findVisitor(final Class<? extends Annotation> annotation) {
>>>>       final PluginVisitorStrategy strategy =
>>>> annotation.getAnnotation(PluginVisitorStrategy.class);
>>>>       if (strategy == null) {
>>>>           return null;
>>>>       }
>>>>       try {
>>>> -            return strategy.value().newInstance();
>>>> +            return (PluginVisitor<? extends Annotation, T>)
>>>> strategy.value().newInstance();
>>>>       } catch (final Exception e) {
>>>>           LOGGER.error("Error loading PluginVisitor [{}] for annotation
>>>> [{}].", strategy.value(), annotation, e);
>>>>           return null;
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>>>> similarity index 67%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> rename to
>>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>>>> index f22ba49..0855b16 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>>> +++
>>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>>>> @@ -16,8 +16,9 @@
>>>> */
>>>> 
>>>> /**
>>>> - * Validation annotations.
>>>> - *
>>>> - * @since 2.1
>>>> + * Visitor classes for extracting values from a Configuration or Node
>>>> corresponding to a plugin annotation.
>>>> + * Visitor implementations must implement {@link
>>>> org.apache.logging.log4j.plugins.visitors.PluginVisitor},
>>>> + * and the corresponding annotation must be annotated with
>>>> + * {@link org.apache.logging.log4j.plugins.PluginVisitorStrategy}.
>>>> */
>>>> -package
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>>> +package org.apache.logging.log4j.plugins.visitors;
>>>> diff --git
>>>> a/log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>>> b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>>> similarity index 91%
>>>> rename from
>>>> log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>>> rename to
>>>> log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>>> index bb9dcb9..5d6951a 100644
>>>> ---
>>>> a/log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>>> +++
>>>> b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>>> @@ -14,4 +14,4 @@
>>>> # See the license for the specific language governing permissions and
>>>> # limitations under the license.
>>>> #
>>>> -org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor
>>>> +org.apache.logging.log4j.plugins.processor.PluginProcessor
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>>>> similarity index 97%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>>>> index f9e757d..6e4b059 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>>>> @@ -14,7 +14,7 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>>> +package org.apache.logging.log4j.plugins.convert;
>>>> 
>>>> import org.junit.Test;
>>>> 
>>>> @@ -63,7 +63,7 @@ public class TypeConverterRegistryTest {
>>>>       // TODO: is there a specific converter this should return?
>>>>   }
>>>> 
>>>> -    public static enum Foo {
>>>> +    public enum Foo {
>>>>       I, PITY, THE
>>>>   }
>>>> 
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>>>> similarity index 84%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>>>> index f4ceb41..48ea7dc 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>>>> @@ -15,10 +15,10 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>>> +package org.apache.logging.log4j.plugins.processor;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> +import org.apache.logging.log4j.plugins.PluginAliases;
>>>> 
>>>> /**
>>>> * Test plugin class for unit tests.
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>>>> similarity index 75%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>>>> index 9c37af4..034705c 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>>>> @@ -15,17 +15,19 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>>> +package org.apache.logging.log4j.plugins.processor;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> +import org.apache.logging.log4j.plugins.PluginAliases;
>>>> import org.junit.BeforeClass;
>>>> import org.junit.Test;
>>>> import org.junit.runner.RunWith;
>>>> import org.junit.runners.JUnit4;
>>>> 
>>>> import java.net.URL;
>>>> +import java.util.ArrayList;
>>>> import java.util.Enumeration;
>>>> +import java.util.List;
>>>> import java.util.Map;
>>>> 
>>>> import static org.junit.Assert.*;
>>>> @@ -33,29 +35,29 @@ import static org.junit.Assert.*;
>>>> @RunWith(JUnit4.class)
>>>> public class PluginProcessorTest {
>>>> 
>>>> -    private static final PluginCache pluginCache = new PluginCache();
>>>> +    private static PluginService pluginService;
>>>> 
>>>>   private final Plugin p = FakePlugin.class.getAnnotation(Plugin.class);
>>>> 
>>>>   @BeforeClass
>>>>   public static void setUpClass() throws Exception {
>>>> -        final Enumeration<URL> resources =
>>>> -
>>>> PluginProcessor.class.getClassLoader().getResources(PluginProcessor.PLUGIN_CACHE_FILE);
>>>> -        pluginCache.loadCacheFiles(resources);
>>>> +        Class<?> clazz =
>>>> PluginProcessor.class.getClassLoader().loadClass("org.apache.logging.log4j.plugins.plugins.Log4jPlugins");
>>>> +        assertNotNull("Could not locate plugins class", clazz);
>>>> +        pluginService = (PluginService)
>>>> clazz.getDeclaredConstructor().newInstance();;
>>>>   }
>>>> 
>>>>   @Test
>>>>   public void testTestCategoryFound() throws Exception {
>>>>       assertNotNull("No plugin annotation on FakePlugin.", p);
>>>> -        final Map<String, PluginEntry> testCategory =
>>>> pluginCache.getCategory(p.category());
>>>> -        assertNotEquals("No plugins were found.", 0, pluginCache.size());
>>>> +        final Map<String, PluginEntry> testCategory =
>>>> pluginService.getCategory(p.category());
>>>> +        assertNotEquals("No plugins were found.", 0,
>>>> pluginService.size());
>>>>       assertNotNull("The category '" + p.category() + "' was not
>>>> found.", testCategory);
>>>>       assertFalse(testCategory.isEmpty());
>>>>   }
>>>> 
>>>>   @Test
>>>>   public void testFakePluginFoundWithCorrectInformation() throws
>>>> Exception {
>>>> -        final PluginEntry fake =
>>>> pluginCache.getCategory(p.category()).get(p.name().toLowerCase());
>>>> +        final PluginEntry fake =
>>>> pluginService.getCategory(p.category()).get(p.name().toLowerCase());
>>>>       verifyFakePluginEntry(p.name(), fake);
>>>>   }
>>>> 
>>>> @@ -63,7 +65,7 @@ public class PluginProcessorTest {
>>>>   public void testFakePluginAliasesContainSameInformation() throws
>>>> Exception {
>>>>       final PluginAliases aliases =
>>>> FakePlugin.class.getAnnotation(PluginAliases.class);
>>>>       for (final String alias : aliases.value()) {
>>>> -            final PluginEntry fake =
>>>> pluginCache.getCategory(p.category()).get(alias.toLowerCase());
>>>> +            final PluginEntry fake =
>>>> pluginService.getCategory(p.category()).get(alias.toLowerCase());
>>>>           verifyFakePluginEntry(alias, fake);
>>>>       }
>>>>   }
>>>> @@ -81,7 +83,7 @@ public class PluginProcessorTest {
>>>>   @Test
>>>>   public void testNestedPlugin() throws Exception {
>>>>       final Plugin p =
>>>> FakePlugin.Nested.class.getAnnotation(Plugin.class);
>>>> -        final PluginEntry nested =
>>>> pluginCache.getCategory(p.category()).get(p.name().toLowerCase());
>>>> +        final PluginEntry nested =
>>>> pluginService.getCategory(p.category()).get(p.name().toLowerCase());
>>>>       assertNotNull(nested);
>>>>       assertEquals(p.name().toLowerCase(), nested.getKey());
>>>>       assertEquals(FakePlugin.Nested.class.getName(),
>>>> nested.getClassName());
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>>>> similarity index 93%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>>>> index 33e0ee1..d0b35d1 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>>>> @@ -15,27 +15,21 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> 
>>>> -import static org.junit.Assert.assertEquals;
>>>> +import org.apache.logging.log4j.junit.CleanFolders;
>>>> +import org.apache.logging.log4j.junit.URLStreamHandlerFactoryRule;
>>>> +import org.junit.Rule;
>>>> +import org.junit.Test;
>>>> +import org.junit.rules.RuleChain;
>>>> 
>>>> import java.io.IOException;
>>>> -import java.net.Proxy;
>>>> -import java.net.URL;
>>>> -import java.net.URLClassLoader;
>>>> -import java.net.URLConnection;
>>>> -import java.net.URLStreamHandler;
>>>> -import java.net.URLStreamHandlerFactory;
>>>> +import java.net.*;
>>>> import java.util.Arrays;
>>>> import java.util.Collections;
>>>> import java.util.Enumeration;
>>>> 
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest;
>>>> -import org.apache.logging.log4j.junit.CleanFolders;
>>>> -import org.apache.logging.log4j.junit.URLStreamHandlerFactoryRule;
>>>> -import org.junit.Rule;
>>>> -import org.junit.Test;
>>>> -import org.junit.rules.RuleChain;
>>>> +import static org.junit.Assert.assertEquals;
>>>> 
>>>> /**
>>>> * Tests the ResolverUtil class for custom protocol like bundleresource,
>>>> vfs, vfszip.
>>>> @@ -187,9 +181,9 @@ public class ResolverUtilCustomProtocolTest {
>>>>           final ResolverUtil resolverUtil = new ResolverUtil();
>>>>           resolverUtil
>>>>                   .setClassLoader(new SingleURLClassLoader(new
>>>> URL("vfs:/" + ResolverUtilTest.WORK_DIR + "/resolverutil3/customplugin3/"),
>>>> cl));
>>>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin3");
>>>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>>>> "customplugin3");
>>>>           assertEquals("Class not found in packages", 1,
>>>> resolverUtil.getClasses().size());
>>>> -            assertEquals("Unexpected class resolved",
>>>> cl.loadClass("customplugin3.FixedString3Layout"),
>>>> +            assertEquals("Unexpected class resolved",
>>>> cl.loadClass("customplugin3.FixedString3"),
>>>>                   resolverUtil.getClasses().iterator().next());
>>>>       }
>>>>   }
>>>> @@ -200,9 +194,9 @@ public class ResolverUtilCustomProtocolTest {
>>>>           final ResolverUtil resolverUtil = new ResolverUtil();
>>>>           resolverUtil.setClassLoader(new SingleURLClassLoader(
>>>>                   new URL("vfs:/" + ResolverUtilTest.WORK_DIR +
>>>> "/resolverutil4/customplugin4.jar/customplugin4/"), cl));
>>>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin4");
>>>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>>>> "customplugin4");
>>>>           assertEquals("Class not found in packages", 1,
>>>> resolverUtil.getClasses().size());
>>>> -            assertEquals("Unexpected class resolved",
>>>> cl.loadClass("customplugin4.FixedString4Layout"),
>>>> +            assertEquals("Unexpected class resolved",
>>>> cl.loadClass("customplugin4.FixedString4"),
>>>>                   resolverUtil.getClasses().iterator().next());
>>>>       }
>>>>   }
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>>>> similarity index 82%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>>>> index 1c6371b..361fe7b 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>>>> @@ -15,33 +15,25 @@
>>>> * limitations under the license.
>>>> */
>>>> 
>>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>>> +package org.apache.logging.log4j.plugins.util;
>>>> 
>>>> -import static org.junit.Assert.assertEquals;
>>>> -import static org.junit.Assert.assertTrue;
>>>> -
>>>> -import java.io.File;
>>>> -import java.io.IOException;
>>>> -import java.io.UnsupportedEncodingException;
>>>> -import java.net.MalformedURLException;
>>>> -import java.net.URI;
>>>> -import java.net.URISyntaxException;
>>>> -import java.net.URL;
>>>> -import java.net.URLClassLoader;
>>>> -import java.nio.file.FileSystem;
>>>> -import java.nio.file.FileSystems;
>>>> -import java.nio.file.Files;
>>>> -import java.nio.file.Path;
>>>> -import java.nio.file.StandardCopyOption;
>>>> -import java.util.HashMap;
>>>> -import java.util.Map;
>>>> -
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest;
>>>> import org.apache.logging.log4j.junit.CleanFolders;
>>>> import org.junit.Rule;
>>>> import org.junit.Test;
>>>> import org.junit.rules.RuleChain;
>>>> 
>>>> +import javax.tools.*;
>>>> +import java.io.File;
>>>> +import java.io.IOException;
>>>> +import java.io.UnsupportedEncodingException;
>>>> +import java.net.*;
>>>> +import java.nio.file.*;
>>>> +import java.util.*;
>>>> +
>>>> +import static org.junit.Assert.assertEquals;
>>>> +import static org.junit.Assert.assertTrue;
>>>> +import static org.junit.Assert.assertNotNull;
>>>> +
>>>> /**
>>>> * Tests the ResolverUtil class.
>>>> */
>>>> @@ -67,6 +59,7 @@ public class ResolverUtilTest {
>>>>   private void testExtractPathFromJarUrlNotDecodedIfFileExists(final
>>>> String existingFile)
>>>>           throws MalformedURLException, UnsupportedEncodingException,
>>>> URISyntaxException {
>>>>       URL url = ResolverUtilTest.class.getResource(existingFile);
>>>> +        assertNotNull("No url returned for " + existingFile, url);
>>>>       if (!url.getProtocol().equals("jar")) {
>>>>           // create fake jar: URL that resolves to existing file
>>>>           url = new URL("jar:" + url.toExternalForm() + "!/some/entry");
>>>> @@ -152,9 +145,9 @@ public class ResolverUtilTest {
>>>>       try (final URLClassLoader cl = compileAndCreateClassLoader("1")) {
>>>>           final ResolverUtil resolverUtil = new ResolverUtil();
>>>>           resolverUtil.setClassLoader(cl);
>>>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin1");
>>>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>>>> "customplugin1");
>>>>           assertEquals("Class not found in packages", 1,
>>>> resolverUtil.getClasses().size());
>>>> -            assertEquals("Unexpected class resolved",
>>>> cl.loadClass("customplugin1.FixedString1Layout"),
>>>> +            assertEquals("Unexpected class resolved",
>>>> cl.loadClass("customplugin1.FixedString1"),
>>>>                   resolverUtil.getClasses().iterator().next());
>>>>       }
>>>>   }
>>>> @@ -164,9 +157,9 @@ public class ResolverUtilTest {
>>>>       try (final URLClassLoader cl =
>>>> compileJarAndCreateClassLoader("2")) {
>>>>           final ResolverUtil resolverUtil = new ResolverUtil();
>>>>           resolverUtil.setClassLoader(cl);
>>>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin2");
>>>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>>>> "customplugin2");
>>>>           assertEquals("Class not found in packages", 1,
>>>> resolverUtil.getClasses().size());
>>>> -            assertEquals("Unexpected class resolved",
>>>> cl.loadClass("customplugin2.FixedString2Layout"),
>>>> +            assertEquals("Unexpected class resolved",
>>>> cl.loadClass("customplugin2.FixedString2"),
>>>>                   resolverUtil.getClasses().iterator().next());
>>>>       }
>>>>   }
>>>> @@ -176,7 +169,7 @@ public class ResolverUtilTest {
>>>>       final File jarFile = new File(workDir, "customplugin" + suffix +
>>>> ".jar");
>>>>       final URI jarURI = jarFile.toURI();
>>>>       createJar(jarURI, workDir, new File(workDir,
>>>> -              "customplugin" + suffix + "/FixedString" + suffix +
>>>> "Layout.class"));
>>>> +              "customplugin" + suffix + "/FixedString" + suffix +
>>>> ".class"));
>>>>       return URLClassLoader.newInstance(new URL[] {jarURI.toURL()});
>>>>   }
>>>> 
>>>> @@ -186,9 +179,9 @@ public class ResolverUtilTest {
>>>>   }
>>>> 
>>>>   static File compile(final String suffix) throws IOException {
>>>> -        final File orig = new
>>>> File("target/test-classes/customplugin/FixedStringLayout.java.source");
>>>> +        final File orig = new
>>>> File("target/test-classes/customplugin/FixedString.java.source");
>>>>       final File workDir = new File(WORK_DIR, "resolverutil" + suffix);
>>>> -        final File f = new File(workDir, "customplugin" + suffix +
>>>> "/FixedString" + suffix + "Layout.java");
>>>> +        final File f = new File(workDir, "customplugin" + suffix +
>>>> "/FixedString" + suffix + ".java");
>>>>       final File parent = f.getParentFile();
>>>>       if (!parent.exists()) {
>>>>         assertTrue("Create customplugin" + suffix + " folder KO",
>>>> f.getParentFile().mkdirs());
>>>> @@ -199,7 +192,7 @@ public class ResolverUtilTest {
>>>>         .replaceAll("customplugin", "customplugin" + suffix);
>>>>       Files.write(f.toPath(), content.getBytes());
>>>> 
>>>> -        PluginManagerPackagesTest.compile(f);
>>>> +        compile(f);
>>>>       return workDir;
>>>>   }
>>>> 
>>>> @@ -218,4 +211,29 @@ public class ResolverUtilTest {
>>>>       }
>>>>   }
>>>> 
>>>> +    static void compile(final File f) throws IOException {
>>>> +        // set up compiler
>>>> +        final JavaCompiler compiler =
>>>> ToolProvider.getSystemJavaCompiler();
>>>> +        final DiagnosticCollector<JavaFileObject> diagnostics = new
>>>> DiagnosticCollector<>();
>>>> +        final List<String> errors = new ArrayList<>();
>>>> +        try (final StandardJavaFileManager fileManager =
>>>> compiler.getStandardFileManager(diagnostics, null, null)) {
>>>> +            final Iterable<? extends JavaFileObject> compilationUnits =
>>>> fileManager.getJavaFileObjectsFromFiles(Arrays
>>>> +                .asList(f));
>>>> +
>>>> +            // compile generated source
>>>> +            // (switch off annotation processing: no need to create
>>>> Log4j2Plugins.dat)
>>>> +            final List<String> options = Arrays.asList("-proc:none");
>>>> +            compiler.getTask(null, fileManager, diagnostics, options,
>>>> null, compilationUnits).call();
>>>> +
>>>> +            // check we don't have any compilation errors
>>>> +            for (final Diagnostic<? extends JavaFileObject> diagnostic :
>>>> diagnostics.getDiagnostics()) {
>>>> +                if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
>>>> +                    errors.add(String.format("Compile error at line %d,
>>>> column %d: %s%n", diagnostic.getLineNumber(),
>>>> +                        diagnostic.getColumnNumber(),
>>>> diagnostic.getMessage(Locale.getDefault())));
>>>> +                }
>>>> +            }
>>>> +        }
>>>> +        assertTrue(errors.toString(), errors.isEmpty());
>>>> +    }
>>>> +
>>>> }
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>>>> similarity index 87%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>>>> index 5689e29..0e243f2 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>>>> @@ -14,10 +14,10 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>>> 
>>>> /**
>>>> *
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>>>> similarity index 78%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>>>> index 34123c0..626798e 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>>>> @@ -14,15 +14,15 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> -import java.net.InetSocketAddress;
>>>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
>>>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
>>>> +import java.net.InetSocketAddress;
>>>> 
>>>> @Plugin(name = "HostAndPort", category = "Test")
>>>> public class HostAndPort {
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>>> similarity index 81%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>>> index 3f2b15a..c3fe6c5 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>>> @@ -14,18 +14,18 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>>> -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> 
>>>> @Plugin(name = "PluginWithGenericSubclassFoo1Builder", category = "Test")
>>>> public class PluginWithGenericSubclassFoo1Builder extends
>>>> AbstractPluginWithGenericBuilder {
>>>> 
>>>>   public static class Builder<B extends Builder<B>> extends
>>>> AbstractPluginWithGenericBuilder.Builder<B>
>>>> -            implements
>>>> org.apache.logging.log4j.core.util.Builder<PluginWithGenericSubclassFoo1Builder>
>>>> {
>>>> +            implements
>>>> org.apache.logging.log4j.plugins.util.Builder<PluginWithGenericSubclassFoo1Builder>
>>>> {
>>>> 
>>>>       @PluginBuilderFactory
>>>>       public static <B extends Builder<B>> B newBuilder() {
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>>>> similarity index 80%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>>>> index 95a4209..9caf453 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>>>> @@ -14,15 +14,15 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> -import java.util.Objects;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>>> -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.validation.constraints.Required;
>>>> +import java.util.Objects;
>>>> 
>>>> /**
>>>> *
>>>> @@ -51,7 +51,7 @@ public class ValidatingPlugin {
>>>>       return new Builder();
>>>>   }
>>>> 
>>>> -    public static class Builder implements
>>>> org.apache.logging.log4j.core.util.Builder<ValidatingPlugin> {
>>>> +    public static class Builder implements
>>>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPlugin> {
>>>> 
>>>>       @PluginBuilderAttribute
>>>>       @Required(message = "The name given by the builder is null")
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>>> similarity index 80%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>>> index 81b9d6f..b0bec53 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>>> @@ -14,15 +14,16 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> -import java.util.Objects;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>>> -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.validation.constraints.Required;
>>>> +import java.util.Objects;
>>>> 
>>>> /**
>>>> *
>>>> @@ -51,7 +52,7 @@ public class ValidatingPluginWithGenericBuilder {
>>>>       return new Builder<B>().asBuilder();
>>>>   }
>>>> 
>>>> -    public static class Builder<B extends Builder<B>> implements
>>>> org.apache.logging.log4j.core.util.Builder<ValidatingPluginWithGenericBuilder>
>>>> {
>>>> +    public static class Builder<B extends Builder<B>> implements
>>>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithGenericBuilder>
>>>> {
>>>> 
>>>>       @PluginBuilderAttribute
>>>>       @Required(message = "The name given by the builder is null")
>>>> diff --git
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>>> similarity index 80%
>>>> rename from
>>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>>> rename to
>>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>>> index 74a6477..256181c 100644
>>>> ---
>>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>>> +++
>>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>>> @@ -14,15 +14,15 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>>> +package org.apache.logging.log4j.plugins.validation;
>>>> 
>>>> -import java.util.Objects;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> 
>>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>>> -import
>>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>>> -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.validation.constraints.Required;
>>>> +import java.util.Objects;
>>>> 
>>>> /**
>>>> *
>>>> @@ -51,7 +51,7 @@ public class ValidatingPluginWithTypedBuilder {
>>>>       return new Builder<>();
>>>>   }
>>>> 
>>>> -    public static class Builder<T> implements
>>>> org.apache.logging.log4j.core.util.Builder<ValidatingPluginWithTypedBuilder>
>>>> {
>>>> +    public static class Builder<T> implements
>>>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithTypedBuilder>
>>>> {
>>>> 
>>>>       @PluginBuilderAttribute
>>>>       @Required(message = "The name given by the builder is null")
>>>> diff --git
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>>> b/log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>>>> similarity index 52%
>>>> rename from
>>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>>> rename to
>>>> log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>>>> index 15a162c..85a62ec 100644
>>>> ---
>>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>>> +++ b/log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>>>> @@ -14,25 +14,32 @@
>>>> * See the license for the specific language governing permissions and
>>>> * limitations under the license.
>>>> */
>>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>>> 
>>>> -import org.apache.logging.log4j.util.EnglishEnums;
>>>> +package customplugin;
>>>> 
>>>> -/**
>>>> - * Converts a {@link String} into a {@link Enum}. Returns {@code null}
>>>> for invalid enum names.
>>>> - *
>>>> - * @param <E> the enum class to parse.
>>>> - * @since 2.1 moved from TypeConverters
>>>> - */
>>>> -public class EnumConverter<E extends Enum<E>> implements TypeConverter<E>
>>>> {
>>>> -    private final Class<E> clazz;
>>>> +import java.util.Collections;
>>>> +import java.util.Map;
>>>> +
>>>> +import org.apache.logging.log4j.plugins.Plugin;
>>>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>>> +
>>>> +@Plugin(name = "FixedString", category = "Core", elementType = "plugin",
>>>> printObject = true)
>>>> +public class FixedString  {
>>>> +
>>>> +    private String fixedString;
>>>> +
>>>> +    @PluginFactory
>>>> +    public static FixedString create(
>>>> +            @PluginAttribute("fixedString") final String fixedString) {
>>>> +        return new FixedString(fixedString);
>>>> +    }
>>>> 
>>>> -    public EnumConverter(final Class<E> clazz) {
>>>> -        this.clazz = clazz;
>>>> +    public FixedString(String fixedString) {
>>>> +        this.fixedString = fixedString;
>>>>   }
>>>> 
>>>> -    @Override
>>>> -    public E convert(final String s) {
>>>> -        return EnglishEnums.valueOf(clazz, s);
>>>> +    public Map<String, String> getContentFormat() {
>>>> +        return Collections.emptyMap();
>>>>   }
>>>> }
>>>> diff --git
>>>> a/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>>>> b/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>>>> new file mode 100644
>>>> index 0000000..b85475a
>>>> --- /dev/null
>>>> +++
>>>> b/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>>>> @@ -0,0 +1,31 @@
>>>> +<?xml version="1.0" encoding="UTF-8"?>
>>>> +<!--
>>>> + 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.
>>>> +
>>>> +-->
>>>> +<Configuration status="OFF" name="XMLConfigTest">
>>>> +
>>>> +  <Appenders>
>>>> +    <List name="List">
>>>> +    </List>
>>>> +  </Appenders>
>>>> +  <Loggers>
>>>> +    <Root level="trace">
>>>> +      <AppenderRef ref="List"/>
>>>> +    </Root>
>>>> +  </Loggers>
>>>> +
>>>> +</Configuration>
>>>> \ No newline at end of file
>>>> diff --git a/log4j-plugins/src/test/resources/s p a c e
>>>> s/log4j+config+with+plus+characters.xml
>>>> b/log4j-plugins/src/test/resources/s p a c e
>>>> s/log4j+config+with+plus+characters.xml
>>>> new file mode 100644
>>>> index 0000000..b85475a
>>>> --- /dev/null
>>>> +++ b/log4j-plugins/src/test/resources/s p a c e
>>>> s/log4j+config+with+plus+characters.xml
>>>> @@ -0,0 +1,31 @@
>>>> +<?xml version="1.0" encoding="UTF-8"?>
>>>> +<!--
>>>> + 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.
>>>> +
>>>> +-->
>>>> +<Configuration status="OFF" name="XMLConfigTest">
>>>> +
>>>> +  <Appenders>
>>>> +    <List name="List">
>>>> +    </List>
>>>> +  </Appenders>
>>>> +  <Loggers>
>>>> +    <Root level="trace">
>>>> +      <AppenderRef ref="List"/>
>>>> +    </Root>
>>>> +  </Loggers>
>>>> +
>>>> +</Configuration>
>>>> \ No newline at end of file
>>>> 
>>>> 
>> 
>> 
>> 
> 
> 
> 



Re: [logging-log4j2] 01/02: LOG4J2-2621 - Initial commit

Posted by Ralph Goers <ra...@dslextreme.com>.
I have updated the branch so that the build now succeeds and the OSGi tests pass. One quirk I noticed with OSGi is that in one of the tests the configuration is loaded from a sample bundle so that is where the LoggerContext ends up. When shutting down the LoggerContext is searched for on the log4j core bundle and isn’t found so then it creates a new LoggerContext during shutdown. This clearly isn’t right so I added an option to have LogManager.shutdown() try to shutdown LoggerContexts on all bundles and not create a new LoggerContext.

The only thing left is to add back support for existing plugins. Unfortunately, that is probably going to require adding deprecated classes back to core so that existing Plugins don’t get ClassNotFoundExceptions.

Ralph

> On Jun 3, 2019, at 7:58 AM, Ralph Goers <ra...@dslextreme.com> wrote:
> 
> Yes, but it shows up in the correct place in the git repo and the diff in the email shows the correct directory.
> 
> Ralph
> 
>> On Jun 3, 2019, at 3:56 AM, Gary Gregory <ga...@gmail.com> wrote:
>> 
>> This is weird, note the "}":
>> 
>> .../org/apache/logging/log4j}/util/Assert.java     |   0
>> 
>> Gary
>> 
>> On Sun, Jun 2, 2019 at 6:38 PM <rg...@apache.org> wrote:
>> 
>>> This is an automated email from the ASF dual-hosted git repository.
>>> 
>>> rgoers pushed a commit to branch LOG4J2-2621
>>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>>> 
>>> commit b69c2d9e4b79ee7830a69463c6f89de1c50fe84d
>>> Author: Ralph Goers <rg...@apache.org>
>>> AuthorDate: Sun Jun 2 13:18:36 2019 -0700
>>> 
>>>   LOG4J2-2621 - Initial commit
>>> ---
>>> .../org/apache/logging/log4j}/util/Assert.java     |   0
>>> .../logging/log4j/util/InternalException.java      |  56 ++++
>>> .../org/apache/logging/log4j}/util/NameUtil.java   |   0
>>> .../apache/logging/log4j}/util/ReflectionUtil.java |   6 +-
>>> .../log4j/junit/AbstractExternalFileCleaner.java   |   0
>>> .../org/apache/logging/log4j/junit/CleanFiles.java |   0
>>> .../apache/logging/log4j/junit/CleanFolders.java   |   0
>>> .../log4j/junit/URLStreamHandlerFactoryRule.java   |   0
>>> .../org/apache/logging/log4j}/util/AssertTest.java |   2 +-
>>> .../config/plugins/convert/Base64Converter.java    |  79 -----
>>> ...TypeConverters.java => CoreTypeConverters.java} |   7 +-
>>> .../ValidatingPluginWithGenericBuilderTest.java    |  10 +-
>>> log4j-plugins-java9/pom.xml                        | 157 +++++++++
>>> log4j-plugins-java9/src/assembly/java9.xml         |  40 +++
>>> .../src/main/java/module-info.java                 |  15 +-
>>> .../org/apache/logging/log4j/plugins/Dummy.java    |   9 +-
>>> .../logging/log4j/plugins/convert/Dummy.java       |   9 +-
>>> .../log4j/plugins/processor/PluginService.java     |   9 +-
>>> .../apache/logging/log4j/plugins/util/Dummy.java   |   9 +-
>>> .../logging/log4j/plugins/validation/Dummy.java    |   9 +-
>>> .../logging/log4j/plugins/visitors/Dummy.java      |   9 +-
>>> log4j-plugins/pom.xml                              | 360
>>> +++++++++++++++++++++
>>> .../org/apache/logging/log4j/plugins}/Node.java    |   6 +-
>>> .../org/apache/logging/log4j}/plugins/Plugin.java  |   6 +-
>>> .../logging/log4j}/plugins/PluginAliases.java      |   4 +-
>>> .../logging/log4j}/plugins/PluginAttribute.java    |   8 +-
>>> .../log4j}/plugins/PluginBuilderAttribute.java     |   8 +-
>>> .../log4j}/plugins/PluginBuilderFactory.java       |   2 +-
>>> .../logging/log4j}/plugins/PluginElement.java      |   6 +-
>>> .../logging/log4j}/plugins/PluginFactory.java      |   2 +-
>>> .../apache/logging/log4j}/plugins/PluginNode.java  |   6 +-
>>> .../apache/logging/log4j}/plugins/PluginValue.java |   6 +-
>>> .../log4j}/plugins/PluginVisitorStrategy.java      |   8 +-
>>> .../log4j}/plugins/convert/EnumConverter.java      |   2 +-
>>> .../log4j}/plugins/convert/HexConverter.java       |   2 +-
>>> .../log4j}/plugins/convert/TypeConverter.java      |   2 +-
>>> .../plugins/convert/TypeConverterRegistry.java     |  23 +-
>>> .../log4j}/plugins/convert/TypeConverters.java     |  47 +--
>>> .../log4j/plugins/convert}/package-info.java       |   7 +-
>>> .../logging/log4j/plugins/osgi/Activator.java      | 103 ++++++
>>> .../logging/log4j/plugins/osgi}/package-info.java  |   6 +-
>>> .../logging/log4j/plugins}/package-info.java       |   6 +-
>>> .../log4j}/plugins/processor/PluginCache.java      |  30 +-
>>> .../log4j}/plugins/processor/PluginEntry.java      |  14 +-
>>> .../log4j}/plugins/processor/PluginProcessor.java  | 157 +++++++--
>>> .../log4j/plugins/processor/PluginService.java     |  56 ++++
>>> .../log4j}/plugins/processor/package-info.java     |   2 +-
>>> .../logging/log4j/plugins}/util/Builder.java       |   4 +-
>>> .../logging/log4j}/plugins/util/PluginManager.java |   8 +-
>>> .../log4j}/plugins/util/PluginRegistry.java        |  81 +++--
>>> .../logging/log4j}/plugins/util/PluginType.java    |   6 +-
>>> .../logging/log4j}/plugins/util/ResolverUtil.java  |  29 +-
>>> .../logging/log4j/plugins/util/TypeUtil.java       | 217 +++++++++++++
>>> .../logging/log4j/plugins/util}/package-info.java  |   2 +-
>>> .../log4j}/plugins/validation/Constraint.java      |   9 +-
>>> .../plugins/validation/ConstraintValidator.java    |   2 +-
>>> .../plugins/validation/ConstraintValidators.java   |   8 +-
>>> .../plugins/validation/constraints/Required.java   |  12 +-
>>> .../plugins/validation/constraints/ValidHost.java  |   6 +-
>>> .../plugins/validation/constraints/ValidPort.java  |  12 +-
>>> .../validation/constraints/package-info.java       |   2 +-
>>> .../log4j}/plugins/validation/package-info.java    |   2 +-
>>> .../validation/validators/RequiredValidator.java   |  14 +-
>>> .../validation/validators/ValidHostValidator.java  |   6 +-
>>> .../validation/validators/ValidPortValidator.java  |   8 +-
>>> .../validation/validators/package-info.java        |   2 +-
>>> .../plugins/visitors/AbstractPluginVisitor.java    |  34 +-
>>> .../plugins/visitors/PluginAttributeVisitor.java   |  27 +-
>>> .../visitors/PluginBuilderAttributeVisitor.java    |  23 +-
>>> .../plugins/visitors/PluginElementVisitor.java     |  17 +-
>>> .../log4j}/plugins/visitors/PluginNodeVisitor.java |  14 +-
>>> .../plugins/visitors/PluginValueVisitor.java       |  18 +-
>>> .../log4j}/plugins/visitors/PluginVisitor.java     |  36 +--
>>> .../log4j}/plugins/visitors/PluginVisitors.java    |  12 +-
>>> .../log4j/plugins/visitors}/package-info.java      |   9 +-
>>> .../services/javax.annotation.processing.Processor |   2 +-
>>> .../plugins/convert/TypeConverterRegistryTest.java |   4 +-
>>> .../log4j}/plugins/processor/FakePlugin.java       |   6 +-
>>> .../plugins/processor/PluginProcessorTest.java     |  26 +-
>>> .../util/ResolverUtilCustomProtocolTest.java       |  30 +-
>>> .../log4j}/plugins/util/ResolverUtilTest.java      |  76 +++--
>>> .../AbstractPluginWithGenericBuilder.java          |   6 +-
>>> .../log4j}/plugins/validation/HostAndPort.java     |  14 +-
>>> .../PluginWithGenericSubclassFoo1Builder.java      |  12 +-
>>> .../plugins/validation/ValidatingPlugin.java       |  16 +-
>>> .../ValidatingPluginWithGenericBuilder.java        |  17 +-
>>> .../ValidatingPluginWithTypedBuilder.java          |  16 +-
>>> .../resources/customplugin/FixedString.java.source |  37 ++-
>>> .../log4j+config+with+plus+characters.xml          |  31 ++
>>> .../log4j+config+with+plus+characters.xml          |  31 ++
>>> 90 files changed, 1655 insertions(+), 594 deletions(-)
>>> 
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Assert.java
>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/Assert.java
>>> similarity index 100%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/Assert.java
>>> rename to log4j-api/src/main/java/org/apache/logging/log4j/util/Assert.java
>>> diff --git
>>> a/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>>> new file mode 100644
>>> index 0000000..8c433db
>>> --- /dev/null
>>> +++
>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>>> @@ -0,0 +1,56 @@
>>> +/*
>>> + * 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;
>>> +
>>> +/**
>>> + * Exception thrown when an error occurs while logging.  In most cases
>>> exceptions will be handled
>>> + * within Log4j but certain Appenders may be configured to allow
>>> exceptions to propagate to the
>>> + * application. This is a RuntimeException so that the exception may be
>>> thrown in those cases without
>>> + * requiring all Logger methods be contained with try/catch blocks.
>>> + */
>>> +public class LoggingException extends RuntimeException {
>>> +
>>> +    private static final long serialVersionUID = 6366395965071580537L;
>>> +
>>> +    /**
>>> +     * Construct an exception with a message.
>>> +     *
>>> +     * @param message The reason for the exception
>>> +     */
>>> +    public LoggingException(final String message) {
>>> +        super(message);
>>> +    }
>>> +
>>> +    /**
>>> +     * Construct an exception with a message and underlying cause.
>>> +     *
>>> +     * @param message The reason for the exception
>>> +     * @param cause The underlying cause of the exception
>>> +     */
>>> +    public LoggingException(final String message, final Throwable cause) {
>>> +        super(message, cause);
>>> +    }
>>> +
>>> +    /**
>>> +     * Construct an exception with an underlying cause.
>>> +     *
>>> +     * @param cause The underlying cause of the exception
>>> +     */
>>> +    public LoggingException(final Throwable cause) {
>>> +        super(cause);
>>> +    }
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NameUtil.java
>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
>>> similarity index 100%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/NameUtil.java
>>> rename to
>>> log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>>> similarity index 98%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>>> rename to
>>> log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>>> index ffee439..f00e64a 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>>> +++
>>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>>> @@ -193,8 +193,10 @@ public final class ReflectionUtil {
>>>        } catch (final IllegalAccessException e) {
>>>            throw new IllegalStateException(e);
>>>        } catch (final InvocationTargetException e) {
>>> -            Throwables.rethrow(e.getCause());
>>> -            throw new InternalError("Unreachable");
>>> +            if (e.getCause() instanceof RuntimeException) {
>>> +                throw (RuntimeException) e.getCause();
>>> +            }
>>> +            throw new
>>>        }
>>>    }
>>> }
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>>> similarity index 100%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>>> rename to
>>> log4j-api/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>>> similarity index 100%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>>> rename to
>>> log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>>> similarity index 100%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>>> rename to
>>> log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>>> similarity index 100%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>>> rename to
>>> log4j-api/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>>> b/log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>>> similarity index 99%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>>> rename to
>>> log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>>> index 242c41e..7e46036 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>>> +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>>> @@ -65,4 +65,4 @@ public class AssertTest {
>>>        assertEquals(isEmpty, Assert.isEmpty(value));
>>>    }
>>> 
>>> -}
>>> \ No newline at end of file
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>>> deleted file mode 100644
>>> index f4e421f..0000000
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>>> +++ /dev/null
>>> @@ -1,79 +0,0 @@
>>> -/*
>>> - * 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.convert;
>>> -
>>> -import java.lang.reflect.InvocationTargetException;
>>> -import java.lang.reflect.Method;
>>> -
>>> -import org.apache.logging.log4j.Logger;
>>> -import org.apache.logging.log4j.status.StatusLogger;
>>> -import org.apache.logging.log4j.util.LoaderUtil;
>>> -
>>> -/**
>>> - * @Since 2.9
>>> - */
>>> -public class Base64Converter {
>>> -
>>> -    private static final Logger LOGGER = StatusLogger.getLogger();
>>> -    private static Method method = null;
>>> -    private static Object decoder = null;
>>> -
>>> -    static {
>>> -        try {
>>> -            // Base64 is available in Java 8 and up.
>>> -            Class<?> clazz = LoaderUtil.loadClass("java.util.Base64");
>>> -            final Method getDecoder = clazz.getMethod("getDecoder",
>>> (Class[]) null);
>>> -            decoder = getDecoder.invoke(null, (Object[]) null);
>>> -            clazz = decoder.getClass();
>>> -            method = clazz.getMethod("decode", String.class);
>>> -        } catch (final ClassNotFoundException ex) {
>>> -
>>> -        } catch (final NoSuchMethodException ex) {
>>> -
>>> -        } catch (final IllegalAccessException ex) {
>>> -
>>> -        } catch (final InvocationTargetException ex) {
>>> -
>>> -        }
>>> -        if (method == null) {
>>> -            try {
>>> -                // DatatypeConverter is not in the default module in Java
>>> 9.
>>> -                final Class<?> clazz =
>>> LoaderUtil.loadClass("javax.xml.bind.DatatypeConverter");
>>> -                method = clazz.getMethod("parseBase64Binary",
>>> String.class);
>>> -            } catch (final ClassNotFoundException ex) {
>>> -                LOGGER.error("No Base64 Converter is available");
>>> -            } catch (final NoSuchMethodException ex) {
>>> -
>>> -            }
>>> -        }
>>> -    }
>>> -
>>> -    public static byte[] parseBase64Binary(final String encoded) {
>>> -        if (method == null) {
>>> -            LOGGER.error("No base64 converter");
>>> -        } else {
>>> -            try {
>>> -                return (byte[]) method.invoke(decoder, encoded);
>>> -            } catch (final IllegalAccessException ex) {
>>> -                LOGGER.error("Error decoding string - " +
>>> ex.getMessage());
>>> -            } catch (final InvocationTargetException ex) {
>>> -                LOGGER.error("Error decoding string - " +
>>> ex.getMessage());
>>> -            }
>>> -        }
>>> -        return new byte[0];
>>> -    }
>>> -}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>>> similarity index 98%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>> copy to
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>>> index dc833f0..00e6da7 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>> +++
>>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>>> @@ -30,13 +30,14 @@ import java.nio.file.Path;
>>> import java.nio.file.Paths;
>>> import java.security.Provider;
>>> import java.security.Security;
>>> +import java.util.Base64;
>>> import java.util.UUID;
>>> import java.util.regex.Pattern;
>>> 
>>> import org.apache.logging.log4j.Level;
>>> import org.apache.logging.log4j.Logger;
>>> import org.apache.logging.log4j.core.appender.rolling.action.Duration;
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> import org.apache.logging.log4j.core.util.CronExpression;
>>> import org.apache.logging.log4j.status.StatusLogger;
>>> import org.apache.logging.log4j.util.LoaderUtil;
>>> @@ -56,6 +57,8 @@ public final class TypeConverters {
>>>     */
>>>    public static final String CATEGORY = "TypeConverter";
>>> 
>>> +    private static final Base64.Decoder decoder = Base64.getDecoder();
>>> +
>>>    /**
>>>     * Parses a {@link String} into a {@link BigDecimal}.
>>>     */
>>> @@ -112,7 +115,7 @@ public final class TypeConverters {
>>>                bytes = new byte[0];
>>>            } else if (value.startsWith(PREFIX_BASE64)) {
>>>                final String lexicalXSDBase64Binary =
>>> value.substring(PREFIX_BASE64.length());
>>> -                bytes =
>>> Base64Converter.parseBase64Binary(lexicalXSDBase64Binary);
>>> +                bytes = decoder.decode(lexicalXSDBase64Binary);
>>>            } else if (value.startsWith(PREFIX_0x)) {
>>>                final String lexicalXSDHexBinary =
>>> value.substring(PREFIX_0x.length());
>>>                bytes = HexConverter.parseHexBinary(lexicalXSDHexBinary);
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>>> index 8ee5abb..27ac5fe 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>>> +++
>>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>>> @@ -20,12 +20,12 @@ import static org.junit.Assert.assertEquals;
>>> import static org.junit.Assert.assertNotNull;
>>> import static org.junit.Assert.assertNull;
>>> 
>>> -import org.apache.logging.log4j.core.config.Node;
>>> +import org.apache.logging.log4j.plugins.Node;
>>> import org.apache.logging.log4j.core.config.NullConfiguration;
>>> -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;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.ValidatingPluginWithGenericBuilder;
>>> +import org.apache.logging.log4j.plugins.util.PluginBuilder;
>>> +import org.apache.logging.log4j.plugins.util.PluginManager;
>>> +import org.apache.logging.log4j.plugins.util.PluginType;
>>> +import
>>> org.apache.logging.log4j.plugins.validation.ValidatingPluginWithGenericBuilder;
>>> import org.junit.Before;
>>> import org.junit.Test;
>>> 
>>> diff --git a/log4j-plugins-java9/pom.xml b/log4j-plugins-java9/pom.xml
>>> new file mode 100644
>>> index 0000000..49f81c6
>>> --- /dev/null
>>> +++ b/log4j-plugins-java9/pom.xml
>>> @@ -0,0 +1,157 @@
>>> +<?xml version="1.0" encoding="UTF-8"?>
>>> +<!--
>>> +  ~ 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.
>>> +  -->
>>> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
>>> http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
>>> http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
>>> ">
>>> +  <modelVersion>4.0.0</modelVersion>
>>> +  <parent>
>>> +    <groupId>org.apache.logging.log4j</groupId>
>>> +    <artifactId>log4j</artifactId>
>>> +    <version>3.0.0-SNAPSHOT</version>
>>> +    <relativePath>../</relativePath>
>>> +  </parent>
>>> +  <artifactId>log4j-plugins-java9</artifactId>
>>> +  <packaging>pom</packaging>
>>> +  <name>Apache Log4j Plugins Module support</name>
>>> +  <description>Apache Log4j Plugin Moduels Support</description>
>>> +  <properties>
>>> +    <log4jParentDir>${basedir}/..</log4jParentDir>
>>> +    <docLabel>Log4j Plugins Documentation</docLabel>
>>> +    <projectDir>/plugins</projectDir>
>>> +  </properties>
>>> +  <dependencies>
>>> +    <dependency>
>>> +      <groupId>org.apache.logging.log4j</groupId>
>>> +      <artifactId>log4j-api</artifactId>
>>> +    </dependency>
>>> +    <dependency>
>>> +      <groupId>junit</groupId>
>>> +      <artifactId>junit</artifactId>
>>> +      <scope>test</scope>
>>> +    </dependency>
>>> +    <dependency>
>>> +      <groupId>org.apache.maven</groupId>
>>> +      <artifactId>maven-core</artifactId>
>>> +      <scope>test</scope>
>>> +    </dependency>
>>> +  </dependencies>
>>> +  <build>
>>> +    <plugins>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-toolchains-plugin</artifactId>
>>> +        <version>1.1</version>
>>> +        <executions>
>>> +          <execution>
>>> +            <goals>
>>> +              <goal>toolchain</goal>
>>> +            </goals>
>>> +          </execution>
>>> +        </executions>
>>> +        <configuration>
>>> +          <toolchains>
>>> +            <jdk>
>>> +              <version>[9, )</version>
>>> +            </jdk>
>>> +          </toolchains>
>>> +        </configuration>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-compiler-plugin</artifactId>
>>> +        <executions>
>>> +          <execution>
>>> +            <id>default-compile</id>
>>> +            <phase>compile</phase>
>>> +            <goals>
>>> +              <goal>compile</goal>
>>> +            </goals>
>>> +          </execution>
>>> +          <execution>
>>> +            <id>default-test-compile</id>
>>> +            <phase>test-compile</phase>
>>> +            <goals>
>>> +              <goal>testCompile</goal>
>>> +            </goals>
>>> +          </execution>
>>> +        </executions>
>>> +        <configuration>
>>> +          <source>9</source>
>>> +          <target>9</target>
>>> +          <release>9</release>
>>> +          <proc>none</proc>
>>> +          <!-- disable errorprone -->
>>> +          <compilerId>javac</compilerId>
>>> +        </configuration>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-surefire-plugin</artifactId>
>>> +        <!-- Do not upgrade until
>>> https://issues.apache.org/jira/browse/SUREFIRE-720 is fixed -->
>>> +        <version>2.13</version>
>>> +        <executions>
>>> +          <execution>
>>> +            <id>test</id>
>>> +            <phase>test</phase>
>>> +            <goals>
>>> +              <goal>test</goal>
>>> +            </goals>
>>> +          </execution>
>>> +        </executions>
>>> +        <configuration>
>>> +          <systemPropertyVariables>
>>> +            <java.awt.headless>true</java.awt.headless>
>>> +          </systemPropertyVariables>
>>> +          <includes>
>>> +            <include>**/Test*.java</include>
>>> +            <include>**/*Test.java</include>
>>> +          </includes>
>>> +          <excludes>
>>> +            <exclude>**/*FuncTest.java</exclude>
>>> +          </excludes>
>>> +        </configuration>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <artifactId>maven-assembly-plugin</artifactId>
>>> +        <executions>
>>> +          <execution>
>>> +            <id>zip</id>
>>> +            <phase>package</phase>
>>> +            <goals>
>>> +              <goal>single</goal>
>>> +            </goals>
>>> +            <configuration>
>>> +
>>> <finalName>log4j-plugins-java9-${project.version}</finalName>
>>> +              <appendAssemblyId>false</appendAssemblyId>
>>> +              <descriptors>
>>> +                <descriptor>src/assembly/java9.xml</descriptor>
>>> +              </descriptors>
>>> +            </configuration>
>>> +          </execution>
>>> +        </executions>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-deploy-plugin</artifactId>
>>> +        <version>${deploy.plugin.version}</version>
>>> +        <configuration>
>>> +          <skip>true</skip>
>>> +        </configuration>
>>> +      </plugin>
>>> +    </plugins>
>>> +  </build>
>>> +</project>
>>> +
>>> diff --git a/log4j-plugins-java9/src/assembly/java9.xml
>>> b/log4j-plugins-java9/src/assembly/java9.xml
>>> new file mode 100644
>>> index 0000000..34649d4
>>> --- /dev/null
>>> +++ b/log4j-plugins-java9/src/assembly/java9.xml
>>> @@ -0,0 +1,40 @@
>>> +<?xml version='1.0' encoding='UTF-8'?>
>>> +<!--
>>> +  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.
>>> +-->
>>> +
>>> +<assembly>
>>> +  <id>src</id>
>>> +  <formats>
>>> +    <format>zip</format>
>>> +  </formats>
>>> +  <baseDirectory>/</baseDirectory>
>>> +  <fileSets>
>>> +    <fileSet>
>>> +      <directory>${project.build.outputDirectory}</directory>
>>> +      <outputDirectory>/classes/META-INF/versions/9</outputDirectory>
>>> +      <includes>
>>> +        <include>module-info.class</include>
>>> +      </includes>
>>> +      <excludes>
>>> +        <exclude>**/Dummy.class</exclude>
>>> +        <exclude>**/PluginService.class</exclude>
>>> +      </excludes>
>>> +    </fileSet>
>>> +  </fileSets>
>>> +</assembly>
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins-java9/src/main/java/module-info.java
>>> similarity index 65%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to log4j-plugins-java9/src/main/java/module-info.java
>>> index f22ba49..9802622 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++ b/log4j-plugins-java9/src/main/java/module-info.java
>>> @@ -14,10 +14,13 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> +module org.apache.logging.log4j.plugins {
>>> +    exports org.apache.logging.log4j.plugins;
>>> +    exports org.apache.logging.log4j.plugins.convert;
>>> +    exports org.apache.logging.log4j.plugins.processor;
>>> +    exports org.apache.logging.log4j.plugins.util;
>>> +    exports org.apache.logging.log4j.plugins.validation;
>>> +    exports org.apache.logging.log4j.plugins.visitors;
>>> 
>>> -/**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> - */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +    uses org.apache.logging.log4j.plugins.processor.PluginService;
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>>> similarity index 80%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>>> index f22ba49..14a90ed 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>>> @@ -14,10 +14,11 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> +package org.apache.logging.log4j.plugins;
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * This is a dummy class and is only here to allow module-info.java to
>>> compile. It will not
>>> + * be copied into the log4j-api module.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +public class Dummy {
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>>> similarity index 79%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>>> index f22ba49..10923e8 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>>> @@ -14,10 +14,11 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> +package org.apache.logging.log4j.plugins.convert;
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * This is a dummy class and is only here to allow module-info.java to
>>> compile. It will not
>>> + * be copied into the log4j-api module.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +public class Dummy {
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>> similarity index 79%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>> index f22ba49..b93ef59 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>> @@ -14,10 +14,11 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> +package org.apache.logging.log4j.plugins.processor;
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * This is a dummy class and is only here to allow module-info.java to
>>> compile. It will not
>>> + * be copied into the log4j-api module.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +public class PluginService {
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>>> similarity index 80%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>>> index f22ba49..5940b03 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>>> @@ -14,10 +14,11 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> +package org.apache.logging.log4j.plugins.util;
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * This is a dummy class and is only here to allow module-info.java to
>>> compile. It will not
>>> + * be copied into the log4j-api module.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +public class Dummy {
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>>> similarity index 79%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>>> index f22ba49..14882b5 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>>> @@ -14,10 +14,11 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * This is a dummy class and is only here to allow module-info.java to
>>> compile. It will not
>>> + * be copied into the log4j-api module.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +public class Dummy {
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>>> similarity index 79%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>>> index f22ba49..5596338 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>>> @@ -14,10 +14,11 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * This is a dummy class and is only here to allow module-info.java to
>>> compile. It will not
>>> + * be copied into the log4j-api module.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +public class Dummy {
>>> +}
>>> diff --git a/log4j-plugins/pom.xml b/log4j-plugins/pom.xml
>>> new file mode 100644
>>> index 0000000..3551d51
>>> --- /dev/null
>>> +++ b/log4j-plugins/pom.xml
>>> @@ -0,0 +1,360 @@
>>> +<?xml version="1.0" encoding="UTF-8"?>
>>> +<!--
>>> +  ~ 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.
>>> +  -->
>>> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
>>> http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
>>> http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
>>> ">
>>> +  <modelVersion>4.0.0</modelVersion>
>>> +  <parent>
>>> +    <groupId>org.apache.logging.log4j</groupId>
>>> +    <artifactId>log4j</artifactId>
>>> +    <version>3.0.0-SNAPSHOT</version>
>>> +    <relativePath>../</relativePath>
>>> +  </parent>
>>> +  <artifactId>log4j-plugins</artifactId>
>>> +  <packaging>jar</packaging>
>>> +  <name>Apache Log4j Plugins</name>
>>> +  <description>Log4j Plugin Support</description>
>>> +  <properties>
>>> +    <log4jParentDir>${basedir}/..</log4jParentDir>
>>> +    <docLabel>Plugin Documentation</docLabel>
>>> +    <projectDir>/plugins</projectDir>
>>> +  </properties>
>>> +  <dependencies>
>>> +    <dependency>
>>> +      <groupId>org.apache.logging.log4j</groupId>
>>> +      <artifactId>log4j-api</artifactId>
>>> +    </dependency>
>>> +    <!-- Classes and resources to be shaded into the core jar -->
>>> +    <dependency>
>>> +      <groupId>org.apache.logging.log4j</groupId>
>>> +      <artifactId>log4j-plugins-java9</artifactId>
>>> +      <scope>provided</scope>
>>> +      <type>zip</type>
>>> +    </dependency>
>>> +    <!-- Used for OSGi bundle support -->
>>> +    <dependency>
>>> +      <groupId>org.osgi</groupId>
>>> +      <artifactId>org.osgi.core</artifactId>
>>> +      <scope>provided</scope>
>>> +    </dependency>
>>> +
>>> +    <!-- TEST DEPENDENCIES -->
>>> +
>>> +    <!-- Pull in useful test classes from API -->
>>> +    <dependency>
>>> +      <groupId>org.apache.logging.log4j</groupId>
>>> +      <artifactId>log4j-api</artifactId>
>>> +      <type>test-jar</type>
>>> +      <scope>test</scope>
>>> +    </dependency>
>>> +    <dependency>
>>> +      <groupId>junit</groupId>
>>> +      <artifactId>junit</artifactId>
>>> +      <scope>test</scope>
>>> +    </dependency>
>>> +    <dependency>
>>> +      <groupId>org.hamcrest</groupId>
>>> +      <artifactId>hamcrest-all</artifactId>
>>> +      <scope>test</scope>
>>> +    </dependency>
>>> +  </dependencies>
>>> +  <build>
>>> +    <plugins>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-dependency-plugin</artifactId>
>>> +        <version>3.0.2</version>
>>> +        <executions>
>>> +          <execution>
>>> +            <id>unpack-classes</id>
>>> +            <phase>prepare-package</phase>
>>> +            <goals>
>>> +              <goal>unpack</goal>
>>> +            </goals>
>>> +            <configuration>
>>> +              <artifactItems>
>>> +                <artifactItem>
>>> +                  <groupId>org.apache.logging.log4j</groupId>
>>> +                  <artifactId>log4j-plugins-java9</artifactId>
>>> +                  <version>${project.version}</version>
>>> +                  <type>zip</type>
>>> +                  <overWrite>false</overWrite>
>>> +                </artifactItem>
>>> +              </artifactItems>
>>> +              <includes>**/*.class</includes>
>>> +              <excludes>**/*.java</excludes>
>>> +
>>> <outputDirectory>${project.build.directory}</outputDirectory>
>>> +              <overWriteReleases>false</overWriteReleases>
>>> +              <overWriteSnapshots>true</overWriteSnapshots>
>>> +            </configuration>
>>> +          </execution>
>>> +        </executions>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <artifactId>maven-compiler-plugin</artifactId>
>>> +        <executions>
>>> +          <execution>
>>> +            <!-- disable annotation processing for first pass -->
>>> +            <id>generate-plugins</id>
>>> +            <phase>process-classes</phase>
>>> +            <goals>
>>> +              <goal>compile</goal>
>>> +            </goals>
>>> +            <configuration>
>>> +              <excludes>
>>> +                <exclude>module-info.java</exclude>
>>> +              </excludes>
>>> +            </configuration>
>>> +          </execution>
>>> +          <execution>
>>> +            <!-- disable annotation processing for first pass -->
>>> +            <id>generate-test-plugins</id>
>>> +            <phase>generate-test-sources</phase>
>>> +            <goals>
>>> +              <goal>compile</goal>
>>> +            </goals>
>>> +            <configuration>
>>> +              <excludes>
>>> +                <exclude>module-info.java</exclude>
>>> +              </excludes>
>>> +              <proc>only</proc>
>>> +            </configuration>
>>> +          </execution>
>>> +          <execution>
>>> +            <!-- disable annotation processing for first pass -->
>>> +            <id>default-compile</id>
>>> +            <configuration>
>>> +              <excludes>
>>> +                <exclude>module-info.java</exclude>
>>> +              </excludes>
>>> +              <proc>none</proc>
>>> +            </configuration>
>>> +          </execution>
>>> +        </executions>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <artifactId>maven-surefire-plugin</artifactId>
>>> +        <configuration>
>>> +          <excludedGroups>
>>> +            org.apache.logging.log4j.categories.PerformanceTests
>>> +          </excludedGroups>
>>> +          <systemPropertyVariables>
>>> +
>>> <org.apache.activemq.SERIALIZABLE_PACKAGES>*</org.apache.activemq.SERIALIZABLE_PACKAGES>
>>> +          </systemPropertyVariables>
>>> +        </configuration>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-failsafe-plugin</artifactId>
>>> +        <configuration>
>>> +          <skipTests>true</skipTests>
>>> +        </configuration>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-jar-plugin</artifactId>
>>> +        <executions>
>>> +          <execution>
>>> +            <id>default-jar</id>
>>> +            <goals>
>>> +              <goal>jar</goal>
>>> +            </goals>
>>> +            <configuration combine.self="override">
>>> +              <archive>
>>> +                <manifestFile>${manifestfile}</manifestFile>
>>> +                <manifestEntries>
>>> +                  <Specification-Title>${project.name
>>> }</Specification-Title>
>>> +
>>> <Specification-Version>${project.version}</Specification-Version>
>>> +                  <Specification-Vendor>${project.organization.name
>>> }</Specification-Vendor>
>>> +                  <Implementation-Title>${project.name
>>> }</Implementation-Title>
>>> +
>>> <Implementation-Version>${project.version}</Implementation-Version>
>>> +                  <Implementation-Vendor>${project.organization.name
>>> }</Implementation-Vendor>
>>> +
>>> <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
>>> +
>>> <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
>>> +
>>> <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
>>> +
>>> <Automatic-Module-Name>org.apache.logging.log4j.plugins</Automatic-Module-Name>
>>> +                  <Multi-Release>true</Multi-Release>
>>> +                </manifestEntries>
>>> +              </archive>
>>> +            </configuration>
>>> +          </execution>
>>> +          <execution>
>>> +            <id>default</id>
>>> +            <goals>
>>> +              <goal>test-jar</goal>
>>> +            </goals>
>>> +            <configuration>
>>> +              <archive>
>>> +                <manifestFile>${manifestfile}</manifestFile>
>>> +                <manifestEntries>
>>> +                  <Specification-Title>${project.name
>>> }</Specification-Title>
>>> +
>>> <Specification-Version>${project.version}</Specification-Version>
>>> +                  <Specification-Vendor>${project.organization.name
>>> }</Specification-Vendor>
>>> +                  <Implementation-Title>${project.name
>>> }</Implementation-Title>
>>> +
>>> <Implementation-Version>${project.version}</Implementation-Version>
>>> +                  <Implementation-Vendor>${project.organization.name
>>> }</Implementation-Vendor>
>>> +
>>> <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
>>> +
>>> <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
>>> +
>>> <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
>>> +                </manifestEntries>
>>> +              </archive>
>>> +            </configuration>
>>> +          </execution>
>>> +        </executions>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.felix</groupId>
>>> +        <artifactId>maven-bundle-plugin</artifactId>
>>> +        <configuration>
>>> +          <instructions>
>>> +
>>> <Bundle-SymbolicName>org.apache.logging.log4j.plugins</Bundle-SymbolicName>
>>> +            <!-- TODO: exclude internal classes from export -->
>>> +
>>> <Export-Package>org.apache.logging.log4j.plugins.*</Export-Package>
>>> +            <Import-Package>
>>> +              sun.reflect;resolution:=optional,
>>> +              org.apache.logging.log4j.util,
>>> +              *
>>> +            </Import-Package>
>>> +
>>> <Bundle-Activator>org.apache.logging.log4j.plugins.osgi.Activator</Bundle-Activator>
>>> +          </instructions>
>>> +        </configuration>
>>> +      </plugin>
>>> +    </plugins>
>>> +  </build>
>>> +  <reporting>
>>> +    <plugins>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-changes-plugin</artifactId>
>>> +        <version>${changes.plugin.version}</version>
>>> +        <reportSets>
>>> +          <reportSet>
>>> +            <reports>
>>> +              <report>changes-report</report>
>>> +            </reports>
>>> +          </reportSet>
>>> +        </reportSets>
>>> +        <configuration>
>>> +
>>> <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
>>> +          <useJql>true</useJql>
>>> +        </configuration>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-checkstyle-plugin</artifactId>
>>> +        <version>${checkstyle.plugin.version}</version>
>>> +        <configuration>
>>> +
>>> <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation>
>>> -->
>>> +
>>> <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
>>> +
>>> <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
>>> +          <enableRulesSummary>false</enableRulesSummary>
>>> +          <propertyExpansion>basedir=${basedir}</propertyExpansion>
>>> +
>>> <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
>>> +        </configuration>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-javadoc-plugin</artifactId>
>>> +        <version>${javadoc.plugin.version}</version>
>>> +        <configuration>
>>> +          <failOnError>false</failOnError>
>>> +          <bottom><![CDATA[<p align="center">Copyright &#169;
>>> {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
>>> +            Apache Logging, Apache Log4j, Log4j, Apache, the Apache
>>> feather logo, the Apache Logging project logo,
>>> +            and the Apache Log4j logo are trademarks of The Apache
>>> Software Foundation.</p>]]></bottom>
>>> +          <!-- module link generation is completely broken in the javadoc
>>> plugin for a multi-module non-aggregating
>>> +               project -->
>>> +          <additionalparam>${javadoc.opts}</additionalparam>
>>> +          <detectOfflineLinks>false</detectOfflineLinks>
>>> +          <linksource>true</linksource>
>>> +          <links>
>>> +            <link>http://docs.oracle.com/javaee/6/api/</link>
>>> +            <link>http://www.osgi.org/javadoc/r4v43/core/</link>
>>> +            <link>
>>> https://commons.apache.org/proper/commons-lang/javadocs/api-release/
>>> </link>
>>> +          </links>
>>> +          <groups>
>>> +            <group>
>>> +              <title>Core API</title>
>>> +              <packages>org.apache.logging.log4j.core</packages>
>>> +            </group>
>>> +            <group>
>>> +              <title>Configuration</title>
>>> +
>>> <packages>org.apache.logging.log4j.core.config*:org.apache.logging.log4j.core.selector</packages>
>>> +            </group>
>>> +            <group>
>>> +              <title>Core Plugins</title>
>>> +
>>> <packages>org.apache.logging.log4j.core.appender*:org.apache.logging.log4j.core.filter:org.apache.logging.log4j.core.layout:org.apache.logging.log4j.core.lookup:org.apache.logging.log4j.core.pattern:org.apache.logging.log4j.core.script</packages>
>>> +            </group>
>>> +            <group>
>>> +              <title>Tools</title>
>>> +              <packages>org.apache.logging.log4j.core.net
>>> *:org.apache.logging.log4j.core.tools</packages>
>>> +            </group>
>>> +            <group>
>>> +              <title>Internals</title>
>>> +
>>> <packages>org.apache.logging.log4j.core.async:org.apache.logging.log4j.core.impl:org.apache.logging.log4j.core.util*:org.apache.logging.log4j.core.osgi:org.apache.logging.log4j.core.jackson:org.apache.logging.log4j.core.jmx</packages>
>>> +            </group>
>>> +          </groups>
>>> +        </configuration>
>>> +        <reportSets>
>>> +          <reportSet>
>>> +            <id>non-aggregate</id>
>>> +            <reports>
>>> +              <report>javadoc</report>
>>> +            </reports>
>>> +          </reportSet>
>>> +        </reportSets>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>com.github.spotbugs</groupId>
>>> +        <artifactId>spotbugs-maven-plugin</artifactId>
>>> +        <configuration>
>>> +          <fork>true</fork>
>>> +          <jvmArgs>-Duser.language=en</jvmArgs>
>>> +          <threshold>Normal</threshold>
>>> +          <effort>Default</effort>
>>> +
>>> <excludeFilterFile>${log4jParentDir}/spotbugs-exclude-filter.xml</excludeFilterFile>
>>> +        </configuration>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-jxr-plugin</artifactId>
>>> +        <version>${jxr.plugin.version}</version>
>>> +        <reportSets>
>>> +          <reportSet>
>>> +            <id>non-aggregate</id>
>>> +            <reports>
>>> +              <report>jxr</report>
>>> +            </reports>
>>> +          </reportSet>
>>> +          <reportSet>
>>> +            <id>aggregate</id>
>>> +            <reports>
>>> +              <report>aggregate</report>
>>> +            </reports>
>>> +          </reportSet>
>>> +        </reportSets>
>>> +      </plugin>
>>> +      <plugin>
>>> +        <groupId>org.apache.maven.plugins</groupId>
>>> +        <artifactId>maven-pmd-plugin</artifactId>
>>> +        <version>${pmd.plugin.version}</version>
>>> +        <configuration>
>>> +          <targetJdk>${maven.compiler.target}</targetJdk>
>>> +        </configuration>
>>> +      </plugin>
>>> +    </plugins>
>>> +  </reporting>
>>> +</project>
>>> +
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>>> similarity index 97%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>>> index c92c904..22fd9bf 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>>> @@ -14,15 +14,15 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config;
>>> +package org.apache.logging.log4j.plugins;
>>> +
>>> +import org.apache.logging.log4j.plugins.util.PluginType;
>>> 
>>> import java.util.ArrayList;
>>> import java.util.HashMap;
>>> import java.util.List;
>>> import java.util.Map;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>>> -
>>> /**
>>> * A Configuration node.
>>> */
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>>> similarity index 97%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>>> index 8aaf117..348754f 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>>> @@ -14,7 +14,9 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> +
>>> +import org.apache.logging.log4j.util.Strings;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>>> import java.lang.annotation.RetentionPolicy;
>>> import java.lang.annotation.Target;
>>> 
>>> -import org.apache.logging.log4j.util.Strings;
>>> -
>>> /**
>>> * Annotation that identifies a Class as a Plugin.
>>> */
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>>> similarity index 87%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>>> index 7be3dea..4dce103 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>>> @@ -14,7 +14,7 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> @@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy;
>>> import java.lang.annotation.Target;
>>> 
>>> /**
>>> - * Identifies a list of aliases for a {@link Plugin}, {@link
>>> PluginAttribute}, or {@link PluginBuilderAttribute}.
>>> + * Identifies a list of aliases for a Plugin, PluginAttribute, or
>>> PluginBuilderAttribute.
>>> */
>>> @Documented
>>> @Retention(RetentionPolicy.RUNTIME)
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>>> similarity index 96%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>>> index bd88220..b9d4684 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>>> @@ -14,7 +14,10 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> +
>>> +import org.apache.logging.log4j.plugins.visitors.PluginAttributeVisitor;
>>> +import org.apache.logging.log4j.util.Strings;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> @@ -22,9 +25,6 @@ import java.lang.annotation.Retention;
>>> import java.lang.annotation.RetentionPolicy;
>>> import java.lang.annotation.Target;
>>> 
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginAttributeVisitor;
>>> -import org.apache.logging.log4j.util.Strings;
>>> -
>>> /**
>>> * Identifies a Plugin Attribute and its default value. Note that only
>>> one of the defaultFoo attributes will be
>>> * used based on the type this annotation is attached to. Thus, for
>>> primitive types, the default<i>Type</i>
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>>> similarity index 92%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>>> index 675d78f..c7fce2f 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>>> @@ -15,7 +15,10 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> +
>>> +import
>>> org.apache.logging.log4j.plugins.visitors.PluginBuilderAttributeVisitor;
>>> +import org.apache.logging.log4j.util.Strings;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> @@ -23,9 +26,6 @@ import java.lang.annotation.Retention;
>>> import java.lang.annotation.RetentionPolicy;
>>> import java.lang.annotation.Target;
>>> 
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginBuilderAttributeVisitor;
>>> -import org.apache.logging.log4j.util.Strings;
>>> -
>>> /**
>>> * Marks a field as a Plugin Attribute.
>>> */
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>>> similarity index 95%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>>> index 4e69262..035b025 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>>> @@ -15,7 +15,7 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>>> similarity index 91%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>>> index 7ea358b..6cfb6fa 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>>> @@ -14,7 +14,9 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> +
>>> +import org.apache.logging.log4j.plugins.visitors.PluginElementVisitor;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>>> import java.lang.annotation.RetentionPolicy;
>>> import java.lang.annotation.Target;
>>> 
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor;
>>> -
>>> /**
>>> * Identifies a parameter as a Plugin and corresponds with an XML element
>>> (or equivalent) in configuration files.
>>> */
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>>> similarity index 96%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>>> index 1c04106..b071510 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>>> @@ -14,7 +14,7 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>>> similarity index 90%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>>> index d60f1b5..b172268 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>>> @@ -14,7 +14,9 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> +
>>> +import org.apache.logging.log4j.plugins.visitors.PluginNodeVisitor;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>>> import java.lang.annotation.RetentionPolicy;
>>> import java.lang.annotation.Target;
>>> 
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginNodeVisitor;
>>> -
>>> /**
>>> * Identifies a Plugin configuration Node.
>>> */
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>>> similarity index 91%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>>> index 9c20cc2..31e5a23 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>>> @@ -14,7 +14,9 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> +
>>> +import org.apache.logging.log4j.plugins.visitors.PluginValueVisitor;
>>> 
>>> import java.lang.annotation.Documented;
>>> import java.lang.annotation.ElementType;
>>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>>> import java.lang.annotation.RetentionPolicy;
>>> import java.lang.annotation.Target;
>>> 
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginValueVisitor;
>>> -
>>> /**
>>> * Identifies a parameter as a value. These correspond with property
>>> values generally, but are meant as values to be
>>> * used as a placeholder value somewhere.
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>>> similarity index 89%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>>> index 65fcb76..093cc50 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>>> @@ -15,7 +15,9 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins;
>>> +package org.apache.logging.log4j.plugins;
>>> +
>>> +import org.apache.logging.log4j.plugins.visitors.PluginVisitor;
>>> 
>>> import java.lang.annotation.Annotation;
>>> import java.lang.annotation.Documented;
>>> @@ -24,8 +26,6 @@ import java.lang.annotation.Retention;
>>> import java.lang.annotation.RetentionPolicy;
>>> import java.lang.annotation.Target;
>>> 
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor;
>>> -
>>> /**
>>> * Meta-annotation to denote the class name to use that implements
>>> * {@link
>>> org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor} for
>>> the annotated annotation.
>>> @@ -40,5 +40,5 @@ public @interface PluginVisitorStrategy {
>>>     * for the given annotation. The generic type in {@code
>>> PluginVisitor} should match the annotation this annotation
>>>     * is applied to.
>>>     */
>>> -    Class<? extends PluginVisitor<? extends Annotation>> value();
>>> +    Class<? extends PluginVisitor<? extends Annotation, ?>> value();
>>> }
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>>> similarity index 95%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>> copy to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>>> index 15a162c..fd8012a 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>>> @@ -14,7 +14,7 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>> +package org.apache.logging.log4j.plugins.convert;
>>> 
>>> import org.apache.logging.log4j.util.EnglishEnums;
>>> 
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>>> similarity index 95%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>>> index e629657..f9037b3 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>>> @@ -14,7 +14,7 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>> +package org.apache.logging.log4j.plugins.convert;
>>> 
>>> /**
>>> * Converts Strings to hex. This is used in place of
>>> java.xml.bind.DataTypeConverter which is not available by
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>>> similarity index 95%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>>> index e67e213..aaa5b4d 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>>> @@ -15,7 +15,7 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>> +package org.apache.logging.log4j.plugins.convert;
>>> 
>>> /**
>>> * Interface for doing automatic String conversion to a specific type.
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>>> similarity index 92%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>>> index 5088f15..fb5b27e 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>>> @@ -14,7 +14,14 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>> +package org.apache.logging.log4j.plugins.convert;
>>> +
>>> +import org.apache.logging.log4j.Logger;
>>> +import org.apache.logging.log4j.plugins.util.PluginManager;
>>> +import org.apache.logging.log4j.plugins.util.PluginType;
>>> +import org.apache.logging.log4j.plugins.util.TypeUtil;
>>> +import org.apache.logging.log4j.util.ReflectionUtil;
>>> +import org.apache.logging.log4j.status.StatusLogger;
>>> 
>>> import java.lang.reflect.ParameterizedType;
>>> import java.lang.reflect.Type;
>>> @@ -25,13 +32,6 @@ import java.util.UnknownFormatConversionException;
>>> import java.util.concurrent.ConcurrentHashMap;
>>> import java.util.concurrent.ConcurrentMap;
>>> 
>>> -import org.apache.logging.log4j.Logger;
>>> -import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
>>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>>> -import org.apache.logging.log4j.core.util.ReflectionUtil;
>>> -import org.apache.logging.log4j.core.util.TypeUtil;
>>> -import org.apache.logging.log4j.status.StatusLogger;
>>> -
>>> /**
>>> * Registry for {@link TypeConverter} plugins.
>>> *
>>> @@ -152,7 +152,12 @@ public class TypeConverterRegistry {
>>>    }
>>> 
>>>    private void registerTypeAlias(final Type knownType, final Type
>>> aliasType) {
>>> -        registry.putIfAbsent(aliasType, registry.get(knownType));
>>> +        TypeConverter<?> converter = registry.get(knownType);
>>> +        if (converter != null) {
>>> +            registry.putIfAbsent(aliasType, converter);
>>> +        } else {
>>> +            LOGGER.error("Cannot locate converter for {}", knownType);
>>> +        }
>>>    }
>>> 
>>> }
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>>> similarity index 92%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>>> index dc833f0..7a71b4a 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>>> @@ -15,32 +15,27 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>> +package org.apache.logging.log4j.plugins.convert;
>>> +
>>> +import org.apache.logging.log4j.Level;
>>> +import org.apache.logging.log4j.Logger;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> +import org.apache.logging.log4j.status.StatusLogger;
>>> +import org.apache.logging.log4j.util.LoaderUtil;
>>> 
>>> import java.io.File;
>>> import java.math.BigDecimal;
>>> import java.math.BigInteger;
>>> -import java.net.InetAddress;
>>> -import java.net.MalformedURLException;
>>> -import java.net.URI;
>>> -import java.net.URISyntaxException;
>>> -import java.net.URL;
>>> +import java.net.*;
>>> import java.nio.charset.Charset;
>>> import java.nio.file.Path;
>>> import java.nio.file.Paths;
>>> import java.security.Provider;
>>> import java.security.Security;
>>> +import java.util.Base64;
>>> import java.util.UUID;
>>> import java.util.regex.Pattern;
>>> 
>>> -import org.apache.logging.log4j.Level;
>>> -import org.apache.logging.log4j.Logger;
>>> -import org.apache.logging.log4j.core.appender.rolling.action.Duration;
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import org.apache.logging.log4j.core.util.CronExpression;
>>> -import org.apache.logging.log4j.status.StatusLogger;
>>> -import org.apache.logging.log4j.util.LoaderUtil;
>>> -
>>> /**
>>> * Collection of basic TypeConverter implementations. May be used to
>>> register additional TypeConverters or find
>>> * registered TypeConverters.
>>> @@ -56,6 +51,8 @@ public final class TypeConverters {
>>>     */
>>>    public static final String CATEGORY = "TypeConverter";
>>> 
>>> +    private static final Base64.Decoder decoder = Base64.getDecoder();
>>> +
>>>    /**
>>>     * Parses a {@link String} into a {@link BigDecimal}.
>>>     */
>>> @@ -112,7 +109,7 @@ public final class TypeConverters {
>>>                bytes = new byte[0];
>>>            } else if (value.startsWith(PREFIX_BASE64)) {
>>>                final String lexicalXSDBase64Binary =
>>> value.substring(PREFIX_BASE64.length());
>>> -                bytes =
>>> Base64Converter.parseBase64Binary(lexicalXSDBase64Binary);
>>> +                bytes = decoder.decode(lexicalXSDBase64Binary);
>>>            } else if (value.startsWith(PREFIX_0x)) {
>>>                final String lexicalXSDHexBinary =
>>> value.substring(PREFIX_0x.length());
>>>                bytes = HexConverter.parseHexBinary(lexicalXSDHexBinary);
>>> @@ -203,14 +200,6 @@ public final class TypeConverters {
>>>        }
>>>    }
>>> 
>>> -    @Plugin(name = "CronExpression", category = CATEGORY)
>>> -    public static class CronExpressionConverter implements
>>> TypeConverter<CronExpression> {
>>> -        @Override
>>> -        public CronExpression convert(final String s) throws Exception {
>>> -            return new CronExpression(s);
>>> -        }
>>> -    }
>>> -
>>>    /**
>>>     * Converts a {@link String} into a {@link Double}.
>>>     */
>>> @@ -223,18 +212,6 @@ public final class TypeConverters {
>>>    }
>>> 
>>>    /**
>>> -     * Converts a {@link String} into a {@link Duration}.
>>> -     * @since 2.5
>>> -     */
>>> -    @Plugin(name = "Duration", category = CATEGORY)
>>> -    public static class DurationConverter implements
>>> TypeConverter<Duration> {
>>> -        @Override
>>> -        public Duration convert(final String s) {
>>> -            return Duration.parse(s);
>>> -        }
>>> -    }
>>> -
>>> -    /**
>>>     * Converts a {@link String} into a {@link File}.
>>>     */
>>>    @Plugin(name = "File", category = CATEGORY)
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>>> similarity index 80%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>>> index f22ba49..958beb4 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>>> @@ -16,8 +16,7 @@
>>> */
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * TypeConverter plugins for converter strings into various types. These
>>> plugins are used for parsing plugin
>>> + * attributes in plugin factory methods.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +package org.apache.logging.log4j.plugins.convert;
>>> diff --git
>>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>>> new file mode 100644
>>> index 0000000..518bee7
>>> --- /dev/null
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>>> @@ -0,0 +1,103 @@
>>> +/*
>>> + * 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.plugins.osgi;
>>> +
>>> +import org.apache.logging.log4j.LogManager;
>>> +import org.apache.logging.log4j.Logger;
>>> +import org.apache.logging.log4j.plugins.processor.PluginService;
>>> +import org.apache.logging.log4j.plugins.util.PluginRegistry;
>>> +import org.apache.logging.log4j.spi.Provider;
>>> +import org.apache.logging.log4j.status.StatusLogger;
>>> +import org.apache.logging.log4j.util.PropertiesUtil;
>>> +import org.osgi.framework.*;
>>> +import org.osgi.framework.wiring.BundleWiring;
>>> +
>>> +import java.util.Hashtable;
>>> +import java.util.concurrent.atomic.AtomicReference;
>>> +
>>> +/**
>>> + * OSGi BundleActivator.
>>> + */
>>> +public final class Activator implements BundleActivator,
>>> SynchronousBundleListener {
>>> +
>>> +    private static final Logger LOGGER = StatusLogger.getLogger();
>>> +
>>> +    private final AtomicReference<BundleContext> contextRef = new
>>> AtomicReference<>();
>>> +
>>> +    ServiceRegistration provideRegistration = null;
>>> +
>>> +    @Override
>>> +    public void start(final BundleContext context) throws Exception {
>>> +        final PluginService pluginService = new Log4jProvider();
>>> +        final Hashtable<String, String> props = new Hashtable<>();
>>> +        props.put("APIVersion", "3.0");
>>> +        provideRegistration =
>>> context.registerService(pluginService.class.getName(), provider, props);
>>> +        if (this.contextRef.compareAndSet(null, context)) {
>>> +            context.addBundleListener(this);
>>> +            // done after the BundleListener as to not miss any new
>>> bundle installs in the interim
>>> +            scanInstalledBundlesForPlugins(context);
>>> +        }
>>> +    }
>>> +
>>> +    private static void scanInstalledBundlesForPlugins(final
>>> BundleContext context) {
>>> +        final Bundle[] bundles = context.getBundles();
>>> +        for (final Bundle bundle : bundles) {
>>> +            // TODO: bundle state can change during this
>>> +            scanBundleForPlugins(bundle);
>>> +        }
>>> +    }
>>> +
>>> +    private static void scanBundleForPlugins(final Bundle bundle) {
>>> +        final long bundleId = bundle.getBundleId();
>>> +        // LOG4J2-920: don't scan system bundle for plugins
>>> +        if (bundle.getState() == Bundle.ACTIVE && bundleId != 0) {
>>> +            LOGGER.trace("Scanning bundle [{}, id=%d] for plugins.",
>>> bundle.getSymbolicName(), bundleId);
>>> +            PluginRegistry.getInstance().loadFromBundle(bundleId,
>>> +                    bundle.adapt(BundleWiring.class).getClassLoader());
>>> +        }
>>> +    }
>>> +
>>> +    private static void stopBundlePlugins(final Bundle bundle) {
>>> +        LOGGER.trace("Stopping bundle [{}] plugins.",
>>> bundle.getSymbolicName());
>>> +        // TODO: plugin lifecycle code
>>> +
>>> PluginRegistry.getInstance().clearBundlePlugins(bundle.getBundleId());
>>> +    }
>>> +
>>> +    @Override
>>> +    public void stop(final BundleContext context) throws Exception {
>>> +        provideRegistration.unregister();
>>> +        this.contextRef.compareAndSet(context, null);
>>> +    }
>>> +
>>> +    @Override
>>> +    public void bundleChanged(final BundleEvent event) {
>>> +        switch (event.getType()) {
>>> +            // FIXME: STARTING instead of STARTED?
>>> +            case BundleEvent.STARTED:
>>> +                scanBundleForPlugins(event.getBundle());
>>> +                break;
>>> +
>>> +            case BundleEvent.STOPPING:
>>> +                stopBundlePlugins(event.getBundle());
>>> +                break;
>>> +
>>> +            default:
>>> +                break;
>>> +        }
>>> +    }
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>>> similarity index 87%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>>> index f22ba49..37dadd4 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>>> @@ -16,8 +16,6 @@
>>> */
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * Collection of OSGi-specific classes for bundles.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +package org.apache.logging.log4j.plugins.osgi;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>>> similarity index 87%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>>> index f22ba49..b161185 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>>> @@ -16,8 +16,6 @@
>>> */
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * Annotations for Log4j 2 plugins.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +package org.apache.logging.log4j.plugins;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>>> similarity index 71%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>>> index 2fd4160..784dece 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>>> @@ -15,7 +15,7 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>> +package org.apache.logging.log4j.plugins.processor;
>>> 
>>> import java.io.BufferedInputStream;
>>> import java.io.BufferedOutputStream;
>>> @@ -60,34 +60,6 @@ public class PluginCache {
>>>    }
>>> 
>>>    /**
>>> -     * Stores the plugin cache to a given OutputStream.
>>> -     *
>>> -     * @param os destination to save cache to.
>>> -     * @throws IOException if an I/O exception occurs.
>>> -     */
>>> -    // NOTE: if this file format is to be changed, the filename should
>>> change and this format should still be readable
>>> -    public void writeCache(final OutputStream os) throws IOException {
>>> -        try (final DataOutputStream out = new DataOutputStream(new
>>> BufferedOutputStream(os))) {
>>> -            // See PluginManager.readFromCacheFiles for the corresponding
>>> decoder. Format may not be changed
>>> -            // without breaking existing Log4j2Plugins.dat files.
>>> -            out.writeInt(categories.size());
>>> -            for (final Map.Entry<String, Map<String, PluginEntry>>
>>> category : categories.entrySet()) {
>>> -                out.writeUTF(category.getKey());
>>> -                final Map<String, PluginEntry> m = category.getValue();
>>> -                out.writeInt(m.size());
>>> -                for (final Map.Entry<String, PluginEntry> entry :
>>> m.entrySet()) {
>>> -                    final PluginEntry plugin = entry.getValue();
>>> -                    out.writeUTF(plugin.getKey());
>>> -                    out.writeUTF(plugin.getClassName());
>>> -                    out.writeUTF(plugin.getName());
>>> -                    out.writeBoolean(plugin.isPrintable());
>>> -                    out.writeBoolean(plugin.isDefer());
>>> -                }
>>> -            }
>>> -        }
>>> -    }
>>> -
>>> -    /**
>>>     * Loads and merges all the Log4j plugin cache files specified.
>>> Usually, this is obtained via a ClassLoader.
>>>     *
>>>     * @param resources URLs to all the desired plugin cache files to
>>> load.
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>>> similarity index 85%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>>> index dd43601..bd452d3 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>>> @@ -15,7 +15,7 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>> +package org.apache.logging.log4j.plugins.processor;
>>> 
>>> import java.io.Serializable;
>>> 
>>> @@ -32,6 +32,18 @@ public class PluginEntry implements Serializable {
>>>    private boolean defer;
>>>    private transient String category;
>>> 
>>> +    public PluginEntry() {
>>> +    }
>>> +
>>> +    public PluginEntry(String key, String className, String name, boolean
>>> printable, boolean defer, String category) {
>>> +        this.key = key;
>>> +        this.className = className;
>>> +        this.name = name;
>>> +        this.printable = printable;
>>> +        this.defer = defer;
>>> +        this.category = category;
>>> +    }
>>> +
>>>    public String getKey() {
>>>        return key;
>>>    }
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>>> similarity index 54%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>>> index 2f3b53f..975d2ab 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>>> @@ -15,38 +15,47 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>> +package org.apache.logging.log4j.plugins.processor;
>>> +
>>> +import org.apache.logging.log4j.LoggingException;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> +import org.apache.logging.log4j.plugins.PluginAliases;
>>> +import org.apache.logging.log4j.util.Strings;
>>> 
>>> -import java.io.IOException;
>>> -import java.io.OutputStream;
>>> -import java.util.ArrayList;
>>> -import java.util.Collection;
>>> -import java.util.Collections;
>>> -import java.util.Locale;
>>> -import java.util.Map;
>>> -import java.util.Objects;
>>> -import java.util.Set;
>>> import javax.annotation.processing.AbstractProcessor;
>>> +import javax.annotation.processing.Messager;
>>> import javax.annotation.processing.RoundEnvironment;
>>> import javax.annotation.processing.SupportedAnnotationTypes;
>>> import javax.lang.model.SourceVersion;
>>> import javax.lang.model.element.Element;
>>> import javax.lang.model.element.ElementVisitor;
>>> +import javax.lang.model.element.Name;
>>> import javax.lang.model.element.TypeElement;
>>> import javax.lang.model.util.Elements;
>>> import javax.lang.model.util.SimpleElementVisitor7;
>>> import javax.tools.Diagnostic.Kind;
>>> import javax.tools.FileObject;
>>> +import javax.tools.JavaFileObject;
>>> import javax.tools.StandardLocation;
>>> +import java.io.BufferedWriter;
>>> +import java.io.IOException;
>>> +import java.io.OutputStreamWriter;
>>> +import java.io.PrintWriter;
>>> +import java.util.ArrayList;
>>> +import java.util.Collection;
>>> +import java.util.Collections;
>>> +import java.util.List;
>>> +import java.util.Locale;
>>> +import java.util.Map;
>>> +import java.util.Objects;
>>> +import java.util.Set;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>>> -import org.apache.logging.log4j.util.Strings;
>>> +import static java.nio.charset.StandardCharsets.UTF_8;
>>> 
>>> /**
>>> * Annotation processor for pre-scanning Log4j 2 plugins.
>>> */
>>> 
>>> -@SupportedAnnotationTypes("org.apache.logging.log4j.core.config.plugins.*")
>>> +@SupportedAnnotationTypes({"org.apache.logging.log4j.plugins.*",
>>> "org.apache.logging.log4j.core.config.plugins.*"})
>>> public class PluginProcessor extends AbstractProcessor {
>>> 
>>>    // TODO: this could be made more abstract to allow for compile-time
>>> and run-time plugin processing
>>> @@ -57,8 +66,8 @@ public class PluginProcessor extends AbstractProcessor {
>>>     */
>>>    public static final String PLUGIN_CACHE_FILE =
>>> 
>>> "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat";
>>> -
>>> -    private final PluginCache pluginCache = new PluginCache();
>>> +    private static final String SERVICE_FILE_NAME =
>>> +
>>> "META-INF/services/org.apache.logging.log4j.plugins.processor.PluginService";
>>> 
>>>    @Override
>>>    public SourceVersion getSupportedSourceVersion() {
>>> @@ -67,16 +76,21 @@ public class PluginProcessor extends AbstractProcessor
>>> {
>>> 
>>>    @Override
>>>    public boolean process(final Set<? extends TypeElement> annotations,
>>> final RoundEnvironment roundEnv) {
>>> -        System.out.println("Processing annotations");
>>> +        Map<String, String> options = processingEnv.getOptions();
>>> +        String packageName = options.get("pluginPackage");
>>> +        Messager messager = processingEnv.getMessager();
>>> +        messager.printMessage(Kind.NOTE, "Processing Log4j annotations");
>>>        try {
>>>            final Set<? extends Element> elements =
>>> roundEnv.getElementsAnnotatedWith(Plugin.class);
>>>            if (elements.isEmpty()) {
>>> -                System.out.println("No elements to process");
>>> +                messager.printMessage(Kind.NOTE, "No elements to
>>> process");
>>>                return false;
>>>            }
>>> -            collectPlugins(elements);
>>> -            writeCacheFile(elements.toArray(new
>>> Element[elements.size()]));
>>> -            System.out.println("Annotations processed");
>>> +            List<PluginEntry> list = new ArrayList<>();
>>> +            packageName = collectPlugins(packageName, elements, list);
>>> +            writeClassFile(packageName, list);
>>> +            writeServiceFile(packageName);
>>> +            messager.printMessage(Kind.NOTE, "Annotations processed");
>>>            return true;
>>>        } catch (final IOException e) {
>>>            e.printStackTrace();
>>> @@ -93,7 +107,8 @@ public class PluginProcessor extends AbstractProcessor {
>>>        processingEnv.getMessager().printMessage(Kind.ERROR, message);
>>>    }
>>> 
>>> -    private void collectPlugins(final Iterable<? extends Element>
>>> elements) {
>>> +    private String collectPlugins(String packageName, final Iterable<?
>>> extends Element> elements, List<PluginEntry> list) {
>>> +        boolean calculatePackage = packageName == null;
>>>        final Elements elementUtils = processingEnv.getElementUtils();
>>>        final ElementVisitor<PluginEntry, Plugin> pluginVisitor = new
>>> PluginElementVisitor(elementUtils);
>>>        final ElementVisitor<Collection<PluginEntry>, Plugin>
>>> pluginAliasesVisitor = new PluginAliasesElementVisitor(
>>> @@ -104,23 +119,93 @@ public class PluginProcessor extends
>>> AbstractProcessor {
>>>                continue;
>>>            }
>>>            final PluginEntry entry = element.accept(pluginVisitor,
>>> plugin);
>>> -            final Map<String, PluginEntry> category =
>>> pluginCache.getCategory(entry.getCategory());
>>> -            category.put(entry.getKey(), entry);
>>> +            list.add(entry);
>>> +            if (calculatePackage) {
>>> +                packageName = calculatePackage(elementUtils, element,
>>> packageName);
>>> +            }
>>>            final Collection<PluginEntry> entries =
>>> element.accept(pluginAliasesVisitor, plugin);
>>>            for (final PluginEntry pluginEntry : entries) {
>>> -                category.put(pluginEntry.getKey(), pluginEntry);
>>> +                list.add(pluginEntry);
>>>            }
>>>        }
>>> +        return packageName;
>>>    }
>>> 
>>> -    private void writeCacheFile(final Element... elements) throws
>>> IOException {
>>> +    private String calculatePackage(Elements elements, Element element,
>>> String packageName) {
>>> +        Name name = elements.getPackageOf(element).getQualifiedName();
>>> +        if (name == null) {
>>> +            return null;
>>> +        }
>>> +        String pkgName = name.toString();
>>> +        if (packageName == null) {
>>> +            return pkgName;
>>> +        }
>>> +        if (pkgName.length() == packageName.length()) {
>>> +            return packageName;
>>> +        }
>>> +        if (pkgName.length() < packageName.length() &&
>>> packageName.startsWith(pkgName)) {
>>> +            return pkgName;
>>> +        }
>>> +
>>> +        return commonPrefix(pkgName, packageName);
>>> +    }
>>> +
>>> +    private void writeServiceFile(String pkgName) throws IOException {
>>>        final FileObject fileObject =
>>> processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
>>> Strings.EMPTY,
>>> -                PLUGIN_CACHE_FILE, elements);
>>> -        try (final OutputStream out = fileObject.openOutputStream()) {
>>> -            pluginCache.writeCache(out);
>>> +                SERVICE_FILE_NAME);
>>> +        try (final PrintWriter writer = new PrintWriter(new
>>> BufferedWriter(new OutputStreamWriter(fileObject.openOutputStream(),
>>> UTF_8)))) {
>>> +            writer.println(createFqcn(pkgName));
>>> +        }
>>> +    }
>>> +
>>> +    private void writeClassFile(String pkg, List<PluginEntry> list) {
>>> +        String fqcn = createFqcn(pkg);
>>> +        try (final PrintWriter writer = createSourceFile(fqcn)) {
>>> +            writer.println("package " + pkg + ".plugins;");
>>> +            writer.println("");
>>> +            writer.println("import
>>> org.apache.logging.log4j.plugins.processor.PluginEntry;");
>>> +            writer.println("import
>>> org.apache.logging.log4j.plugins.processor.PluginService;");
>>> +            writer.println("");
>>> +            writer.println("public class Log4jPlugins extends
>>> PluginService {");
>>> +            writer.println("");
>>> +            writer.println("    private static PluginEntry[] entries =
>>> new PluginEntry[] {");
>>> +            StringBuilder sb = new StringBuilder();
>>> +            int max = list.size() - 1;
>>> +            for (int i = 0; i < list.size(); ++i) {
>>> +                PluginEntry entry = list.get(i);
>>> +                sb.append("        ").append("new PluginEntry(\"");
>>> +                sb.append(entry.getKey()).append("\", \"");
>>> +                sb.append(entry.getClassName()).append("\", \"");
>>> +                sb.append(entry.getName()).append("\", ");
>>> +                sb.append(entry.isPrintable()).append(", ");
>>> +                sb.append(entry.isDefer()).append(", \"");
>>> +                sb.append(entry.getCategory()).append("\")");
>>> +                if (i < max) {
>>> +                    sb.append(",");
>>> +                }
>>> +                writer.println(sb.toString());
>>> +                sb.setLength(0);
>>> +            }
>>> +            writer.println("    };");
>>> +            writer.println("    @Override");
>>> +            writer.println("    public PluginEntry[] getEntries() {
>>> return entries;}");
>>> +            writer.println("}");
>>>        }
>>>    }
>>> 
>>> +    private PrintWriter createSourceFile(String fqcn) {
>>> +        try {
>>> +            JavaFileObject sourceFile =
>>> processingEnv.getFiler().createSourceFile(fqcn);
>>> +            return new PrintWriter(sourceFile.openWriter());
>>> +        } catch (IOException e) {
>>> +            throw new LoggingException("Unable to create Plugin Service
>>> Class " + fqcn, e);
>>> +        }
>>> +    }
>>> +
>>> +    private String createFqcn(String packageName) {
>>> +        return packageName + ".plugins.Log4jPlugins";
>>> +    }
>>> +
>>>    /**
>>>     * ElementVisitor to scan the Plugin annotation.
>>>     */
>>> @@ -146,6 +231,20 @@ public class PluginProcessor extends
>>> AbstractProcessor {
>>>        }
>>>    }
>>> 
>>> +    private String commonPrefix(String str1, String str2) {
>>> +        int minLength = str1.length() < str2.length() ? str1.length() :
>>> str2.length();
>>> +        for (int i = 0; i < minLength; i++) {
>>> +            if (str1.charAt(i) != str2.charAt(i)) {
>>> +                if (i > 1 && str1.charAt(i-1) == '.') {
>>> +                    return str1.substring(0, i-1);
>>> +                } else {
>>> +                    return str1.substring(0, i);
>>> +                }
>>> +            }
>>> +        }
>>> +        return str1.substring(0, minLength);
>>> +    }
>>> +
>>>    /**
>>>     * ElementVisitor to scan the PluginAliases annotation.
>>>     */
>>> diff --git
>>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>> new file mode 100644
>>> index 0000000..5042456
>>> --- /dev/null
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>>> @@ -0,0 +1,56 @@
>>> +/*
>>> + * 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.plugins.processor;
>>> +
>>> +import java.util.Collections;
>>> +import java.util.LinkedHashMap;
>>> +import java.util.Map;
>>> +
>>> +/**
>>> + * Class Description goes here.
>>> + */
>>> +public abstract class PluginService {
>>> +
>>> +    private final Map<String, Map<String, PluginEntry>> categories = new
>>> LinkedHashMap<>();
>>> +
>>> +    public PluginService() {
>>> +        PluginEntry[] entries = getEntries();
>>> +        for (PluginEntry entry : entries) {
>>> +            String category = entry.getCategory().toLowerCase();
>>> +            if (!categories.containsKey(category)) {
>>> +                categories.put(category, new LinkedHashMap<>());
>>> +            }
>>> +            Map<String, PluginEntry> map = categories.get(category);
>>> +            map.put(entry.getKey(), entry);
>>> +        }
>>> +    }
>>> +
>>> +    public abstract PluginEntry[] getEntries();
>>> +
>>> +    public Map<String, Map<String, PluginEntry>> getCategories() {
>>> +        return Collections.unmodifiableMap(categories);
>>> +    }
>>> +
>>> +    public Map<String, PluginEntry> getCategory(String category) {
>>> +        return
>>> Collections.unmodifiableMap(categories.get(category.toLowerCase()));
>>> +    }
>>> +
>>> +    public long size() {
>>> +        return categories.size();
>>> +    }
>>> +
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>>> similarity index 94%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>> copy to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>>> index 4f6ddda..2c296f9 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>>> @@ -19,4 +19,4 @@
>>> * Java annotation processor for pre-scanning Log4j 2 plugins. This is
>>> provided as an alternative to using the
>>> * executable {@link
>>> org.apache.logging.log4j.core.config.plugins.util.PluginManager} class in
>>> your build process.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>> +package org.apache.logging.log4j.plugins.processor;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>>> similarity index 93%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>>> index 0935ce8..ec8a07f 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>>> @@ -15,7 +15,7 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.util;
>>> +package org.apache.logging.log4j.plugins.util;
>>> 
>>> /**
>>> * A type of builder that can be used to configure and create a instances
>>> using a Java DSL instead of
>>> @@ -25,7 +25,7 @@ package org.apache.logging.log4j.core.util;
>>> * <p>
>>> *     When creating <em>plugin</em> builders, it is customary to create
>>> the builder class as a public static inner class
>>> *     called {@code Builder}. For instance, the builder class for
>>> - *     {@link org.apache.logging.log4j.core.layout.PatternLayout
>>> PatternLayout} would be
>>> + *     org.apache.logging.log4j.core.layout.PatternLayout PatternLayout
>>> would be
>>> *     {@code PatternLayout.Builder}.
>>> * </p>
>>> *
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>>> similarity index 96%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>>> index 6f38d0e..b6f02f5 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>>> @@ -15,17 +15,13 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>> +package org.apache.logging.log4j.plugins.util;
>>> 
>>> import org.apache.logging.log4j.Logger;
>>> import org.apache.logging.log4j.status.StatusLogger;
>>> import org.apache.logging.log4j.util.Strings;
>>> 
>>> -import java.util.Collection;
>>> -import java.util.HashMap;
>>> -import java.util.LinkedHashMap;
>>> -import java.util.List;
>>> -import java.util.Map;
>>> +import java.util.*;
>>> import java.util.concurrent.CopyOnWriteArrayList;
>>> 
>>> /**
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>>> similarity index 81%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>>> index 99fa610..9e8c6e2 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>>> @@ -15,32 +15,28 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>> +package org.apache.logging.log4j.plugins.util;
>>> +
>>> +import org.apache.logging.log4j.Logger;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> +import org.apache.logging.log4j.plugins.PluginAliases;
>>> +import org.apache.logging.log4j.plugins.processor.PluginCache;
>>> +import org.apache.logging.log4j.plugins.processor.PluginEntry;
>>> +import org.apache.logging.log4j.plugins.processor.PluginProcessor;
>>> +import org.apache.logging.log4j.plugins.processor.PluginService;
>>> +import org.apache.logging.log4j.status.StatusLogger;
>>> +import org.apache.logging.log4j.util.LoaderUtil;
>>> +import org.apache.logging.log4j.util.Strings;
>>> 
>>> import java.io.IOException;
>>> import java.net.URI;
>>> import java.net.URL;
>>> import java.text.DecimalFormat;
>>> -import java.util.ArrayList;
>>> -import java.util.Collections;
>>> -import java.util.Enumeration;
>>> -import java.util.HashMap;
>>> -import java.util.List;
>>> -import java.util.Map;
>>> +import java.util.*;
>>> import java.util.concurrent.ConcurrentHashMap;
>>> import java.util.concurrent.ConcurrentMap;
>>> import java.util.concurrent.atomic.AtomicReference;
>>> 
>>> -import org.apache.logging.log4j.Logger;
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginCache;
>>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor;
>>> -import org.apache.logging.log4j.core.util.Loader;
>>> -import org.apache.logging.log4j.status.StatusLogger;
>>> -import org.apache.logging.log4j.util.Strings;
>>> -
>>> /**
>>> * Registry singleton for PluginType maps partitioned by source type and
>>> then by category names.
>>> */
>>> @@ -116,7 +112,8 @@ public class PluginRegistry {
>>>            // already loaded
>>>            return existing;
>>>        }
>>> -        final Map<String, List<PluginType<?>>> newPluginsByCategory =
>>> decodeCacheFiles(Loader.getClassLoader());
>>> +        final Map<String, List<PluginType<?>>> newPluginsByCategory =
>>> decodeCacheFiles(LoaderUtil.getClassLoader());
>>> +        loadPlugins(newPluginsByCategory);
>>> 
>>>        // Note multiple threads could be calling this method
>>> concurrently. Both will do the work,
>>>        // but only one will be allowed to store the result in the
>>> AtomicReference.
>>> @@ -144,6 +141,7 @@ public class PluginRegistry {
>>>            return existing;
>>>        }
>>>        final Map<String, List<PluginType<?>>> newPluginsByCategory =
>>> decodeCacheFiles(loader);
>>> +        loadPlugins(loader, newPluginsByCategory);
>>> 
>>>        // Note multiple threads could be calling this method
>>> concurrently. Both will do the work,
>>>        // but only one will be allowed to store the result in the outer
>>> map.
>>> @@ -155,6 +153,51 @@ public class PluginRegistry {
>>>        return newPluginsByCategory;
>>>    }
>>> 
>>> +    /**
>>> +     * @since 3.0
>>> +     */
>>> +    public void loadPlugins(Map<String, List<PluginType<?>>> map) {
>>> +        for (ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
>>> +            try {
>>> +                loadPlugins(classLoader, map);
>>> +            } catch (Throwable ex) {
>>> +                LOGGER.debug("Unable to retrieve provider from
>>> ClassLoader {}", classLoader, ex);
>>> +            }
>>> +        }
>>> +    }
>>> +
>>> +    /**
>>> +     * @since 3.0
>>> +     */
>>> +    public void loadPlugins(ClassLoader classLoader, Map<String,
>>> List<PluginType<?>>> map) {
>>> +        final long startTime = System.nanoTime();
>>> +        final ServiceLoader<PluginService> serviceLoader =
>>> ServiceLoader.load(PluginService.class, classLoader);
>>> +        int pluginCount = 0;
>>> +        for (final PluginService pluginService : serviceLoader) {
>>> +            PluginEntry[] entries = pluginService.getEntries();
>>> +            for (PluginEntry entry : entries) {
>>> +                try {
>>> +                    final Class<?> clazz =
>>> classLoader.loadClass(entry.getClassName());
>>> +                    final PluginType<?> type = new PluginType(entry,
>>> clazz, entry.getName());
>>> +                    String category = entry.getCategory().toLowerCase();
>>> +                    if (!map.containsKey(category)) {
>>> +                        map.put(category, new ArrayList<>());
>>> +                    }
>>> +                    List<PluginType<?>> list = map.get(category);
>>> +                    list.add(type);
>>> +                    ++pluginCount;
>>> +                } catch (final ClassNotFoundException e) {
>>> +                    LOGGER.info("Plugin [{}] could not be loaded due to
>>> missing classes.", entry.getClassName(), e);
>>> +                }
>>> +            }
>>> +        }
>>> +        final long endTime = System.nanoTime();
>>> +        final DecimalFormat numFormat = new DecimalFormat("#0.000000");
>>> +        final double seconds = (endTime - startTime) * 1e-9;
>>> +        LOGGER.debug("Took {} seconds to load {} plugins from {}",
>>> +                numFormat.format(seconds), pluginCount, classLoader);
>>> +    }
>>> +
>>>    private Map<String, List<PluginType<?>>> decodeCacheFiles(final
>>> ClassLoader loader) {
>>>        final long startTime = System.nanoTime();
>>>        final PluginCache cache = new PluginCache();
>>> @@ -214,7 +257,7 @@ public class PluginRegistry {
>>> 
>>>        final long startTime = System.nanoTime();
>>>        final ResolverUtil resolver = new ResolverUtil();
>>> -        final ClassLoader classLoader = Loader.getClassLoader();
>>> +        final ClassLoader classLoader = LoaderUtil.getClassLoader();
>>>        if (classLoader != null) {
>>>            resolver.setClassLoader(classLoader);
>>>        }
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>>> similarity index 92%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>>> index cc6bc66..c213f64 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>>> @@ -14,16 +14,16 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>> +package org.apache.logging.log4j.plugins.util;
>>> 
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry;
>>> +import org.apache.logging.log4j.plugins.processor.PluginEntry;
>>> 
>>> /**
>>> * Plugin Descriptor. This is a memento object for Plugin annotations
>>> paired to their annotated classes.
>>> *
>>> * @param <T> The plug-in class, which can be any kind of class.
>>> - * @see org.apache.logging.log4j.core.config.plugins.Plugin
>>> + * @see org.apache.logging.log4j.plugins.Plugin
>>> */
>>> public class PluginType<T> {
>>> 
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>>> similarity index 97%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>>> index 73b5fc0..a57356c 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>>> @@ -14,33 +14,24 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>> +package org.apache.logging.log4j.plugins.util;
>>> 
>>> -import java.io.File;
>>> -import java.io.FileInputStream;
>>> -import java.io.IOException;
>>> -import java.io.InputStream;
>>> -import java.io.UnsupportedEncodingException;
>>> +import org.apache.logging.log4j.Logger;
>>> +import org.apache.logging.log4j.util.LoaderUtil;
>>> +import org.apache.logging.log4j.status.StatusLogger;
>>> +import org.osgi.framework.FrameworkUtil;
>>> +import org.osgi.framework.wiring.BundleWiring;
>>> +
>>> +import java.io.*;
>>> import java.net.URI;
>>> import java.net.URISyntaxException;
>>> import java.net.URL;
>>> import java.net.URLDecoder;
>>> import java.nio.charset.StandardCharsets;
>>> -import java.util.Arrays;
>>> -import java.util.Collection;
>>> -import java.util.Enumeration;
>>> -import java.util.HashSet;
>>> -import java.util.List;
>>> -import java.util.Set;
>>> +import java.util.*;
>>> import java.util.jar.JarEntry;
>>> import java.util.jar.JarInputStream;
>>> 
>>> -import org.apache.logging.log4j.Logger;
>>> -import org.apache.logging.log4j.core.util.Loader;
>>> -import org.apache.logging.log4j.status.StatusLogger;
>>> -import org.osgi.framework.FrameworkUtil;
>>> -import org.osgi.framework.wiring.BundleWiring;
>>> -
>>> /**
>>> * <p>
>>> * ResolverUtil is used to locate classes that are available in the/a
>>> class path and meet arbitrary conditions. The two
>>> @@ -126,7 +117,7 @@ public class ResolverUtil {
>>>     * @return the ClassLoader that will be used to scan for classes
>>>     */
>>>    public ClassLoader getClassLoader() {
>>> -        return classloader != null ? classloader : (classloader =
>>> Loader.getClassLoader(ResolverUtil.class, null));
>>> +        return classloader != null ? classloader : (classloader =
>>> LoaderUtil.getClassLoader(ResolverUtil.class, null));
>>>    }
>>> 
>>>    /**
>>> diff --git
>>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>>> new file mode 100644
>>> index 0000000..e2bb462
>>> --- /dev/null
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>>> @@ -0,0 +1,217 @@
>>> +/*
>>> + * 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.plugins.util;
>>> +
>>> +import java.lang.reflect.*;
>>> +import java.util.ArrayList;
>>> +import java.util.List;
>>> +import java.util.Objects;
>>> +
>>> +/**
>>> + * Utility class for working with Java {@link Type}s and derivatives.
>>> This class is adapted heavily from the
>>> + * <a href="http://projects.spring.io/spring-framework/">Spring
>>> Framework</a>, specifically the
>>> + * <a href="
>>> http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/TypeUtils.html
>>> ">TypeUtils</a>
>>> + * class.
>>> + *
>>> + * @see Type
>>> + * @see GenericArrayType
>>> + * @see ParameterizedType
>>> + * @see WildcardType
>>> + * @see Class
>>> + * @since 2.1
>>> + */
>>> +public final class TypeUtil {
>>> +
>>> +    private TypeUtil() {
>>> +    }
>>> +
>>> +    /**
>>> +     * Gets all declared fields for the given class (including
>>> superclasses).
>>> +     *
>>> +     * @param cls the class to examine
>>> +     * @return all declared fields for the given class (including
>>> superclasses).
>>> +     * @see Class#getDeclaredFields()
>>> +     */
>>> +    public static List<Field> getAllDeclaredFields(Class<?> cls) {
>>> +        final List<Field> fields = new ArrayList<>();
>>> +        while (cls != null) {
>>> +            for (final Field field : cls.getDeclaredFields()) {
>>> +                fields.add(field);
>>> +            }
>>> +            cls = cls.getSuperclass();
>>> +        }
>>> +        return fields;
>>> +    }
>>> +    /**
>>> +     * Indicates if two {@link Type}s are assignment compatible.
>>> +     *
>>> +     * @param lhs the left hand side to check assignability to
>>> +     * @param rhs the right hand side to check assignability from
>>> +     * @return {@code true} if it is legal to assign a variable of type
>>> {@code rhs} to a variable of type {@code lhs}
>>> +     * @see Class#isAssignableFrom(Class)
>>> +     */
>>> +    public static boolean isAssignable(final Type lhs, final Type rhs) {
>>> +        Objects.requireNonNull(lhs, "No left hand side type provided");
>>> +        Objects.requireNonNull(rhs, "No right hand side type provided");
>>> +        if (lhs.equals(rhs)) {
>>> +            return true;
>>> +        }
>>> +        if (Object.class.equals(lhs)) {
>>> +            // everything is assignable to Object
>>> +            return true;
>>> +        }
>>> +        // raw type on left
>>> +        if (lhs instanceof Class<?>) {
>>> +            final Class<?> lhsClass = (Class<?>) lhs;
>>> +            if (rhs instanceof Class<?>) {
>>> +                // no generics involved
>>> +                final Class<?> rhsClass = (Class<?>) rhs;
>>> +                return lhsClass.isAssignableFrom(rhsClass);
>>> +            }
>>> +            if (rhs instanceof ParameterizedType) {
>>> +                // check to see if the parameterized type has the same
>>> raw type as the lhs; this is legal
>>> +                final Type rhsRawType = ((ParameterizedType)
>>> rhs).getRawType();
>>> +                if (rhsRawType instanceof Class<?>) {
>>> +                    return lhsClass.isAssignableFrom((Class<?>)
>>> rhsRawType);
>>> +                }
>>> +            }
>>> +            if (lhsClass.isArray() && rhs instanceof GenericArrayType) {
>>> +                // check for compatible array component types
>>> +                return isAssignable(lhsClass.getComponentType(),
>>> ((GenericArrayType) rhs).getGenericComponentType());
>>> +            }
>>> +        }
>>> +        // parameterized type on left
>>> +        if (lhs instanceof ParameterizedType) {
>>> +            final ParameterizedType lhsType = (ParameterizedType) lhs;
>>> +            if (rhs instanceof Class<?>) {
>>> +                final Type lhsRawType = lhsType.getRawType();
>>> +                if (lhsRawType instanceof Class<?>) {
>>> +                    return ((Class<?>)
>>> lhsRawType).isAssignableFrom((Class<?>) rhs);
>>> +                }
>>> +            } else if (rhs instanceof ParameterizedType) {
>>> +                final ParameterizedType rhsType = (ParameterizedType) rhs;
>>> +                return isParameterizedAssignable(lhsType, rhsType);
>>> +            }
>>> +        }
>>> +        // generic array type on left
>>> +        if (lhs instanceof GenericArrayType) {
>>> +            final Type lhsComponentType = ((GenericArrayType)
>>> lhs).getGenericComponentType();
>>> +            if (rhs instanceof Class<?>) {
>>> +                // raw type on right
>>> +                final Class<?> rhsClass = (Class<?>) rhs;
>>> +                if (rhsClass.isArray()) {
>>> +                    return isAssignable(lhsComponentType,
>>> rhsClass.getComponentType());
>>> +                }
>>> +            } else if (rhs instanceof GenericArrayType) {
>>> +                return isAssignable(lhsComponentType, ((GenericArrayType)
>>> rhs).getGenericComponentType());
>>> +            }
>>> +        }
>>> +        // wildcard type on left
>>> +        if (lhs instanceof WildcardType) {
>>> +            return isWildcardAssignable((WildcardType) lhs, rhs);
>>> +        }
>>> +        // strange...
>>> +        return false;
>>> +    }
>>> +
>>> +    private static boolean isParameterizedAssignable(final
>>> ParameterizedType lhs, final ParameterizedType rhs) {
>>> +        if (lhs.equals(rhs)) {
>>> +            // that was easy
>>> +            return true;
>>> +        }
>>> +        final Type[] lhsTypeArguments = lhs.getActualTypeArguments();
>>> +        final Type[] rhsTypeArguments = rhs.getActualTypeArguments();
>>> +        final int size = lhsTypeArguments.length;
>>> +        if (rhsTypeArguments.length != size) {
>>> +            // clearly incompatible types
>>> +            return false;
>>> +        }
>>> +        for (int i = 0; i < size; i++) {
>>> +            // verify all type arguments are assignable
>>> +            final Type lhsArgument = lhsTypeArguments[i];
>>> +            final Type rhsArgument = rhsTypeArguments[i];
>>> +            if (!lhsArgument.equals(rhsArgument) &&
>>> +                !(lhsArgument instanceof WildcardType &&
>>> +                    isWildcardAssignable((WildcardType) lhsArgument,
>>> rhsArgument))) {
>>> +                return false;
>>> +            }
>>> +        }
>>> +        return true;
>>> +    }
>>> +
>>> +    private static boolean isWildcardAssignable(final WildcardType lhs,
>>> final Type rhs) {
>>> +        final Type[] lhsUpperBounds = getEffectiveUpperBounds(lhs);
>>> +        final Type[] lhsLowerBounds = getEffectiveLowerBounds(lhs);
>>> +        if (rhs instanceof WildcardType) {
>>> +            // oh boy, this scenario requires checking a lot of
>>> assignability!
>>> +            final WildcardType rhsType = (WildcardType) rhs;
>>> +            final Type[] rhsUpperBounds =
>>> getEffectiveUpperBounds(rhsType);
>>> +            final Type[] rhsLowerBounds =
>>> getEffectiveLowerBounds(rhsType);
>>> +            for (final Type lhsUpperBound : lhsUpperBounds) {
>>> +                for (final Type rhsUpperBound : rhsUpperBounds) {
>>> +                    if (!isBoundAssignable(lhsUpperBound, rhsUpperBound))
>>> {
>>> +                        return false;
>>> +                    }
>>> +                }
>>> +                for (final Type rhsLowerBound : rhsLowerBounds) {
>>> +                    if (!isBoundAssignable(lhsUpperBound, rhsLowerBound))
>>> {
>>> +                        return false;
>>> +                    }
>>> +                }
>>> +            }
>>> +            for (final Type lhsLowerBound : lhsLowerBounds) {
>>> +                for (final Type rhsUpperBound : rhsUpperBounds) {
>>> +                    if (!isBoundAssignable(rhsUpperBound, lhsLowerBound))
>>> {
>>> +                        return false;
>>> +                    }
>>> +                }
>>> +                for (final Type rhsLowerBound : rhsLowerBounds) {
>>> +                    if (!isBoundAssignable(rhsLowerBound, lhsLowerBound))
>>> {
>>> +                        return false;
>>> +                    }
>>> +                }
>>> +            }
>>> +        } else {
>>> +            // phew, far less bounds to check
>>> +            for (final Type lhsUpperBound : lhsUpperBounds) {
>>> +                if (!isBoundAssignable(lhsUpperBound, rhs)) {
>>> +                    return false;
>>> +                }
>>> +            }
>>> +            for (final Type lhsLowerBound : lhsLowerBounds) {
>>> +                if (!isBoundAssignable(lhsLowerBound, rhs)) {
>>> +                    return false;
>>> +                }
>>> +            }
>>> +        }
>>> +        return true;
>>> +    }
>>> +
>>> +    private static Type[] getEffectiveUpperBounds(final WildcardType
>>> type) {
>>> +        final Type[] upperBounds = type.getUpperBounds();
>>> +        return upperBounds.length == 0 ? new Type[]{Object.class} :
>>> upperBounds;
>>> +    }
>>> +
>>> +    private static Type[] getEffectiveLowerBounds(final WildcardType
>>> type) {
>>> +        final Type[] lowerBounds = type.getLowerBounds();
>>> +        return lowerBounds.length == 0 ? new Type[]{null} : lowerBounds;
>>> +    }
>>> +
>>> +    private static boolean isBoundAssignable(final Type lhs, final Type
>>> rhs) {
>>> +        return (rhs == null) || ((lhs != null) && isAssignable(lhs, rhs));
>>> +    }
>>> +}
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>>> similarity index 94%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>>> index 4f6ddda..fae7580 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>>> @@ -19,4 +19,4 @@
>>> * Java annotation processor for pre-scanning Log4j 2 plugins. This is
>>> provided as an alternative to using the
>>> * executable {@link
>>> org.apache.logging.log4j.core.config.plugins.util.PluginManager} class in
>>> your build process.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>> +package org.apache.logging.log4j.plugins.util;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>>> similarity index 81%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>>> index 0ac2223..4586315 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>>> @@ -14,14 +14,9 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> -import java.lang.annotation.Annotation;
>>> -import java.lang.annotation.Documented;
>>> -import java.lang.annotation.ElementType;
>>> -import java.lang.annotation.Retention;
>>> -import java.lang.annotation.RetentionPolicy;
>>> -import java.lang.annotation.Target;
>>> +import java.lang.annotation.*;
>>> 
>>> /**
>>> * Meta annotation to mark an annotation as a validation constraint. This
>>> annotation must specify a
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>>> similarity index 96%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>>> index 1d8c0c5..2f638a7 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>>> @@ -14,7 +14,7 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> import java.lang.annotation.Annotation;
>>> 
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>>> similarity index 93%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>>> index 374c8ec..6236bb6 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>>> @@ -14,7 +14,9 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> +
>>> +import org.apache.logging.log4j.util.ReflectionUtil;
>>> 
>>> import java.lang.annotation.Annotation;
>>> import java.lang.reflect.ParameterizedType;
>>> @@ -22,8 +24,6 @@ import java.lang.reflect.Type;
>>> import java.util.ArrayList;
>>> import java.util.Collection;
>>> 
>>> -import org.apache.logging.log4j.core.util.ReflectionUtil;
>>> -
>>> /**
>>> * Utility class to locate an appropriate {@link ConstraintValidator}
>>> implementation for an annotation.
>>> *
>>> @@ -36,7 +36,7 @@ public final class ConstraintValidators {
>>> 
>>>    /**
>>>     * Finds all relevant {@link ConstraintValidator} objects from an
>>> array of annotations. All validators will be
>>> -     * {@link
>>> ConstraintValidator#initialize(java.lang.annotation.Annotation)
>>> initialized} before being returned.
>>> +     * {@link ConstraintValidator#initialize(Annotation) initialized}
>>> before being returned.
>>>     *
>>>     * @param annotations the annotations to find constraint validators
>>> for
>>>     * @return a collection of ConstraintValidators for the given
>>> annotations
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>>> similarity index 73%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>>> index e6f3c56..9b8a75d 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>>> @@ -15,16 +15,12 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +package org.apache.logging.log4j.plugins.validation.constraints;
>>> 
>>> -import java.lang.annotation.Documented;
>>> -import java.lang.annotation.ElementType;
>>> -import java.lang.annotation.Retention;
>>> -import java.lang.annotation.RetentionPolicy;
>>> -import java.lang.annotation.Target;
>>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>>> +import
>>> org.apache.logging.log4j.plugins.validation.validators.RequiredValidator;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.validators.RequiredValidator;
>>> +import java.lang.annotation.*;
>>> 
>>> /**
>>> * Marks a plugin builder field or plugin factory parameter as required.
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>>> similarity index 84%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>>> index c652d40..14dd9a8 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>>> @@ -14,10 +14,10 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +package org.apache.logging.log4j.plugins.validation.constraints;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.validators.ValidHostValidator;
>>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>>> +import
>>> org.apache.logging.log4j.plugins.validation.validators.ValidHostValidator;
>>> 
>>> import java.lang.annotation.*;
>>> import java.net.InetAddress;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>>> similarity index 74%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>>> index a7c68b1..c4aba16 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>>> @@ -14,16 +14,12 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +package org.apache.logging.log4j.plugins.validation.constraints;
>>> 
>>> -import java.lang.annotation.Documented;
>>> -import java.lang.annotation.ElementType;
>>> -import java.lang.annotation.Retention;
>>> -import java.lang.annotation.RetentionPolicy;
>>> -import java.lang.annotation.Target;
>>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>>> +import
>>> org.apache.logging.log4j.plugins.validation.validators.ValidPortValidator;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.validators.ValidPortValidator;
>>> +import java.lang.annotation.*;
>>> 
>>> /**
>>> * Indicates that a plugin attribute must be a valid port number. A valid
>>> port number is an integer between 0 and
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>>> similarity index 91%
>>> copy from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> copy to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>>> index f22ba49..298cd5a 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>>> @@ -20,4 +20,4 @@
>>> *
>>> * @since 2.1
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +package org.apache.logging.log4j.plugins.validation.constraints;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>>> similarity index 93%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>>> index 171b25a..15955cb 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>>> @@ -20,4 +20,4 @@
>>> *
>>> * @since 2.1
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>>> similarity index 86%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>>> index 98c0a71..9df6d3b 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>>> @@ -14,17 +14,17 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>>> -
>>> -import java.util.Collection;
>>> -import java.util.Map;
>>> +package org.apache.logging.log4j.plugins.validation.validators;
>>> 
>>> import org.apache.logging.log4j.Logger;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>>> -import org.apache.logging.log4j.core.util.Assert;
>>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>> +import org.apache.logging.log4j.util.Assert;
>>> import org.apache.logging.log4j.status.StatusLogger;
>>> 
>>> +import java.util.Collection;
>>> +import java.util.Map;
>>> +
>>> /**
>>> * Validator that checks an object for emptiness. Emptiness is defined
>>> here as:
>>> * <ul>
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>>> similarity index 89%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>>> index 6c01753..41abbfd 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>>> @@ -14,11 +14,11 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>>> +package org.apache.logging.log4j.plugins.validation.validators;
>>> 
>>> import org.apache.logging.log4j.Logger;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
>>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
>>> import org.apache.logging.log4j.status.StatusLogger;
>>> 
>>> import java.net.InetAddress;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>>> similarity index 85%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>>> index a59742c..27e97f0 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>>> @@ -14,12 +14,12 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>>> +package org.apache.logging.log4j.plugins.validation.validators;
>>> 
>>> import org.apache.logging.log4j.Logger;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
>>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
>>> +import org.apache.logging.log4j.plugins.convert.TypeConverters;
>>> import org.apache.logging.log4j.status.StatusLogger;
>>> 
>>> /**
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>>> similarity index 92%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>>> index a8ac560..cfe2041 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>>> @@ -20,4 +20,4 @@
>>> *
>>> * @since 2.1
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>>> +package org.apache.logging.log4j.plugins.validation.validators;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>>> similarity index 84%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>>> index 560cbe3..b98dc09 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>>> @@ -15,18 +15,18 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> +
>>> +import org.apache.logging.log4j.Logger;
>>> +import org.apache.logging.log4j.plugins.convert.TypeConverters;
>>> +import org.apache.logging.log4j.status.StatusLogger;
>>> +import org.apache.logging.log4j.util.Strings;
>>> 
>>> import java.lang.annotation.Annotation;
>>> import java.lang.reflect.Member;
>>> import java.util.Map;
>>> import java.util.Objects;
>>> -
>>> -import org.apache.logging.log4j.Logger;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
>>> -import org.apache.logging.log4j.core.lookup.StrSubstitutor;
>>> -import org.apache.logging.log4j.status.StatusLogger;
>>> -import org.apache.logging.log4j.util.Strings;
>>> +import java.util.function.Function;
>>> 
>>> /**
>>> * Base class for PluginVisitor implementations. Provides convenience
>>> methods as well as all method implementations
>>> @@ -34,7 +34,7 @@ import org.apache.logging.log4j.util.Strings;
>>> *
>>> * @param <A> the Plugin annotation type.
>>> */
>>> -public abstract class AbstractPluginVisitor<A extends Annotation>
>>> implements PluginVisitor<A> {
>>> +public abstract class AbstractPluginVisitor<A extends Annotation, T>
>>> implements PluginVisitor<A, T> {
>>> 
>>>    /** Status logger. */
>>>    protected static final Logger LOGGER = StatusLogger.getLogger();
>>> @@ -58,10 +58,6 @@ public abstract class AbstractPluginVisitor<A extends
>>> Annotation> implements Plu
>>>    /**
>>>     *
>>>     */
>>> -    protected StrSubstitutor substitutor;
>>> -    /**
>>> -     *
>>> -     */
>>>    protected Member member;
>>> 
>>>    /**
>>> @@ -75,7 +71,7 @@ public abstract class AbstractPluginVisitor<A extends
>>> Annotation> implements Plu
>>> 
>>>    @SuppressWarnings("unchecked")
>>>    @Override
>>> -    public PluginVisitor<A> setAnnotation(final Annotation anAnnotation) {
>>> +    public PluginVisitor<A, T> setAnnotation(final Annotation
>>> anAnnotation) {
>>>        final Annotation a = Objects.requireNonNull(anAnnotation, "No
>>> annotation was provided");
>>>        if (this.clazz.isInstance(a)) {
>>>            this.annotation = (A) a;
>>> @@ -84,25 +80,19 @@ public abstract class AbstractPluginVisitor<A extends
>>> Annotation> implements Plu
>>>    }
>>> 
>>>    @Override
>>> -    public PluginVisitor<A> setAliases(final String... someAliases) {
>>> +    public PluginVisitor<A, T> setAliases(final String... someAliases) {
>>>        this.aliases = someAliases;
>>>        return this;
>>>    }
>>> 
>>>    @Override
>>> -    public PluginVisitor<A> setConversionType(final Class<?>
>>> aConversionType) {
>>> +    public PluginVisitor<A, T> setConversionType(final Class<?>
>>> aConversionType) {
>>>        this.conversionType = Objects.requireNonNull(aConversionType, "No
>>> conversion type class was provided");
>>>        return this;
>>>    }
>>> 
>>>    @Override
>>> -    public PluginVisitor<A> setStrSubstitutor(final StrSubstitutor
>>> aSubstitutor) {
>>> -        this.substitutor = Objects.requireNonNull(aSubstitutor, "No
>>> StrSubstitutor was provided");
>>> -        return this;
>>> -    }
>>> -
>>> -    @Override
>>> -    public PluginVisitor<A> setMember(final Member aMember) {
>>> +    public PluginVisitor<A, T> setMember(final Member aMember) {
>>>        this.member = aMember;
>>>        return this;
>>>    }
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>>> similarity index 80%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>>> index f4da42b..fbd28b9 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>>> @@ -15,40 +15,39 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> 
>>> -import java.util.Map;
>>> -
>>> -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.PluginAttribute;
>>> -import org.apache.logging.log4j.core.util.NameUtil;
>>> +import org.apache.logging.log4j.plugins.Node;
>>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>>> +import org.apache.logging.log4j.util.NameUtil;
>>> import org.apache.logging.log4j.util.StringBuilders;
>>> 
>>> +import java.util.Map;
>>> +import java.util.function.Function;
>>> +
>>> /**
>>> * PluginVisitor implementation for {@link PluginAttribute}.
>>> */
>>> -public class PluginAttributeVisitor extends
>>> AbstractPluginVisitor<PluginAttribute> {
>>> +public class PluginAttributeVisitor extends
>>> AbstractPluginVisitor<PluginAttribute, Object> {
>>>    public PluginAttributeVisitor() {
>>>        super(PluginAttribute.class);
>>>    }
>>> 
>>>    @Override
>>> -    public Object visit(final Configuration configuration, final Node
>>> node, final LogEvent event,
>>> +    public Object visit(final Object unused, final Node node, final
>>> Function<String, String> substitutor,
>>>                        final StringBuilder log) {
>>>        final String name = this.annotation.value();
>>>        final Map<String, String> attributes = node.getAttributes();
>>>        final String rawValue = removeAttributeValue(attributes, name,
>>> this.aliases);
>>> -        final String replacedValue = this.substitutor.replace(event,
>>> rawValue);
>>> -        final Object defaultValue = findDefaultValue(event);
>>> +        final String replacedValue = substitutor.apply(rawValue);
>>> +        final Object defaultValue = findDefaultValue(substitutor);
>>>        final Object value = convert(replacedValue, defaultValue);
>>>        final Object debugValue = this.annotation.sensitive() ?
>>> NameUtil.md5(value + this.getClass().getName()) : value;
>>>        StringBuilders.appendKeyDqValue(log, name, debugValue);
>>>        return value;
>>>    }
>>> 
>>> -    private Object findDefaultValue(final LogEvent event) {
>>> +    private Object findDefaultValue(Function<String, String> substitutor)
>>> {
>>>        if (this.conversionType == int.class || this.conversionType ==
>>> Integer.class) {
>>>            return this.annotation.defaultInt();
>>>        }
>>> @@ -76,6 +75,6 @@ public class PluginAttributeVisitor extends
>>> AbstractPluginVisitor<PluginAttribut
>>>        if (this.conversionType == Class.class) {
>>>            return this.annotation.defaultClass();
>>>        }
>>> -        return this.substitutor.replace(event,
>>> this.annotation.defaultString());
>>> +        return substitutor.apply(this.annotation.defaultString());
>>>    }
>>> }
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>>> similarity index 74%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>>> index e951456..398ff1c 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>>> @@ -15,38 +15,37 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> 
>>> -import java.util.Map;
>>> -
>>> -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.PluginBuilderAttribute;
>>> -import org.apache.logging.log4j.core.util.NameUtil;
>>> +import org.apache.logging.log4j.plugins.Node;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>> +import org.apache.logging.log4j.util.NameUtil;
>>> import org.apache.logging.log4j.util.StringBuilders;
>>> 
>>> +import java.util.Map;
>>> +import java.util.function.Function;
>>> +
>>> /**
>>> * PluginVisitor for PluginBuilderAttribute. If {@code null} is returned
>>> for the
>>> - * {@link #visit(org.apache.logging.log4j.core.config.Configuration,
>>> org.apache.logging.log4j.core.config.Node,
>>> org.apache.logging.log4j.core.LogEvent, StringBuilder)}
>>> + * {@link #visit(org.apache.logging.log4j.core.config.Configuration,
>>> org.apache.logging.log4j.plugins.Node,
>>> org.apache.logging.log4j.core.LogEvent, StringBuilder)}
>>> * method, then the default value of the field should remain untouched.
>>> *
>>> * @see org.apache.logging.log4j.core.config.plugins.util.PluginBuilder
>>> */
>>> -public class PluginBuilderAttributeVisitor extends
>>> AbstractPluginVisitor<PluginBuilderAttribute> {
>>> +public class PluginBuilderAttributeVisitor extends
>>> AbstractPluginVisitor<PluginBuilderAttribute, Object> {
>>> 
>>>    public PluginBuilderAttributeVisitor() {
>>>        super(PluginBuilderAttribute.class);
>>>    }
>>> 
>>>    @Override
>>> -    public Object visit(final Configuration configuration, final Node
>>> node, final LogEvent event,
>>> +    public Object visit(final Object unused, final Node node, final
>>> Function<String, String> substitutor,
>>>                        final StringBuilder log) {
>>>        final String overridden = this.annotation.value();
>>>        final String name = overridden.isEmpty() ? this.member.getName()
>>> : overridden;
>>>        final Map<String, String> attributes = node.getAttributes();
>>>        final String rawValue = removeAttributeValue(attributes, name,
>>> this.aliases);
>>> -        final String replacedValue = this.substitutor.replace(event,
>>> rawValue);
>>> +        final String replacedValue = substitutor.apply(rawValue);
>>>        final Object value = convert(replacedValue, null);
>>>        final Object debugValue = this.annotation.sensitive() ?
>>> NameUtil.md5(value + this.getClass().getName()) : value;
>>>        StringBuilders.appendKeyDqValue(log, name, debugValue);
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>>> similarity index 90%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>>> index 2e6e6ef..f8197f1 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>>> @@ -15,30 +15,29 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> +
>>> +import org.apache.logging.log4j.plugins.Node;
>>> +import org.apache.logging.log4j.plugins.PluginElement;
>>> +import org.apache.logging.log4j.plugins.util.PluginType;
>>> 
>>> import java.lang.reflect.Array;
>>> import java.util.ArrayList;
>>> import java.util.Arrays;
>>> import java.util.Collection;
>>> import java.util.List;
>>> -
>>> -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.PluginElement;
>>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>>> +import java.util.function.Function;
>>> 
>>> /**
>>> * PluginVisitor implementation for {@link PluginElement}. Supports
>>> arrays as well as singular values.
>>> */
>>> -public class PluginElementVisitor extends
>>> AbstractPluginVisitor<PluginElement> {
>>> +public class PluginElementVisitor extends
>>> AbstractPluginVisitor<PluginElement, Object> {
>>>    public PluginElementVisitor() {
>>>        super(PluginElement.class);
>>>    }
>>> 
>>>    @Override
>>> -    public Object visit(final Configuration configuration, final Node
>>> node, final LogEvent event,
>>> +    public Object visit(final Object unused, final Node node, final
>>> Function<String, String> substitutor,
>>>                        final StringBuilder log) {
>>>        final String name = this.annotation.value();
>>>        if (this.conversionType.isArray()) {
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>>> similarity index 77%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>>> index 7f15392..9438b39 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>>> @@ -15,23 +15,23 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> 
>>> -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.PluginNode;
>>> +import org.apache.logging.log4j.plugins.Node;
>>> +import org.apache.logging.log4j.plugins.PluginNode;
>>> +
>>> +import java.util.function.Function;
>>> 
>>> /**
>>> * PluginVisitor implementation for {@link PluginNode}.
>>> */
>>> -public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode> {
>>> +public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode,
>>> Object> {
>>>    public PluginNodeVisitor() {
>>>        super(PluginNode.class);
>>>    }
>>> 
>>>    @Override
>>> -    public Object visit(final Configuration configuration, final Node
>>> node, final LogEvent event,
>>> +    public Object visit(final Object unused, final Node node, final
>>> Function<String, String> substitutor,
>>>                        final StringBuilder log) {
>>>        if (this.conversionType.isInstance(node)) {
>>>            log.append("Node=").append(node.getName());
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>>> similarity index 79%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>>> index 8544570..2f68f04 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>>> @@ -15,26 +15,26 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> 
>>> -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.PluginValue;
>>> +import org.apache.logging.log4j.plugins.Node;
>>> +import org.apache.logging.log4j.plugins.PluginValue;
>>> import org.apache.logging.log4j.util.StringBuilders;
>>> import org.apache.logging.log4j.util.Strings;
>>> 
>>> +import java.util.function.Function;
>>> +
>>> /**
>>> * PluginVisitor implementation for {@link PluginValue}.
>>> */
>>> -public class PluginValueVisitor extends
>>> AbstractPluginVisitor<PluginValue> {
>>> +public class PluginValueVisitor extends
>>> AbstractPluginVisitor<PluginValue, Object> {
>>>    public PluginValueVisitor() {
>>>        super(PluginValue.class);
>>>    }
>>> 
>>>    @Override
>>> -    public Object visit(final Configuration configuration, final Node
>>> node, final LogEvent event,
>>> -            final StringBuilder log) {
>>> +    public Object visit(final Object unused, final Node node, final
>>> Function<String, String> substitutor,
>>> +                        final StringBuilder log) {
>>>        final String name = this.annotation.value();
>>>        final String elementValue = node.getValue();
>>>        final String attributeValue = node.getAttributes().get("value");
>>> @@ -49,7 +49,7 @@ public class PluginValueVisitor extends
>>> AbstractPluginVisitor<PluginValue> {
>>>        } else {
>>>            rawValue = removeAttributeValue(node.getAttributes(),
>>> "value");
>>>        }
>>> -        final String value = this.substitutor.replace(event, rawValue);
>>> +        final String value = substitutor.apply(rawValue);
>>>        StringBuilders.appendKeyDqValue(log, name, value);
>>>        return value;
>>>    }
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>>> similarity index 68%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>>> index 34e2b78..fb7aca4 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>>> @@ -15,15 +15,13 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> +
>>> +import org.apache.logging.log4j.plugins.Node;
>>> 
>>> import java.lang.annotation.Annotation;
>>> import java.lang.reflect.Member;
>>> -
>>> -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.lookup.StrSubstitutor;
>>> +import java.util.function.Function;
>>> 
>>> /**
>>> * Visitor strategy for parsing data from a {@link Node}, doing any
>>> relevant type conversion, and returning a
>>> @@ -31,7 +29,7 @@ import
>>> org.apache.logging.log4j.core.lookup.StrSubstitutor;
>>> *
>>> * @param <A> the Annotation type.
>>> */
>>> -public interface PluginVisitor<A extends Annotation> {
>>> +public interface PluginVisitor<A extends Annotation, T> {
>>> 
>>>    /**
>>>     * Sets the Annotation to be used for this. If the given Annotation
>>> is not compatible with this class's type, then
>>> @@ -41,7 +39,7 @@ public interface PluginVisitor<A extends Annotation> {
>>>     * @return {@code this}.
>>>     * @throws NullPointerException if the argument is {@code null}.
>>>     */
>>> -    PluginVisitor<A> setAnnotation(Annotation annotation);
>>> +    PluginVisitor<A, T> setAnnotation(Annotation annotation);
>>> 
>>>    /**
>>>     * Sets the list of aliases to use for this visit. No aliases are
>>> required, however.
>>> @@ -49,7 +47,7 @@ public interface PluginVisitor<A extends Annotation> {
>>>     * @param aliases the list of aliases to use.
>>>     * @return {@code this}.
>>>     */
>>> -    PluginVisitor<A> setAliases(String... aliases);
>>> +    PluginVisitor<A, T> setAliases(String... aliases);
>>> 
>>>    /**
>>>     * Sets the class to convert the plugin value to on this visit. This
>>> should correspond with a class obtained from
>>> @@ -59,17 +57,7 @@ public interface PluginVisitor<A extends Annotation> {
>>>     * @return {@code this}.
>>>     * @throws NullPointerException if the argument is {@code null}.
>>>     */
>>> -    PluginVisitor<A> setConversionType(Class<?> conversionType);
>>> -
>>> -    /**
>>> -     * Sets the StrSubstitutor to use for converting raw strings before
>>> type conversion. Generally obtained from a
>>> -     * {@link org.apache.logging.log4j.core.config.Configuration}.
>>> -     *
>>> -     * @param substitutor the StrSubstitutor to use on plugin values.
>>> -     * @return {@code this}.
>>> -     * @throws NullPointerException if the argument is {@code null}.
>>> -     */
>>> -    PluginVisitor<A> setStrSubstitutor(StrSubstitutor substitutor);
>>> +    PluginVisitor<A, T> setConversionType(Class<?> conversionType);
>>> 
>>>    /**
>>>     * Sets the Member that this visitor is being used for injection
>>> upon. For instance, this could be the Field
>>> @@ -79,16 +67,16 @@ public interface PluginVisitor<A extends Annotation> {
>>>     * @param member the member this visitor is parsing a value for.
>>>     * @return {@code this}.
>>>     */
>>> -    PluginVisitor<A> setMember(Member member);
>>> +    PluginVisitor<A, T> setMember(Member member);
>>> 
>>>    /**
>>>     * Visits a Node to obtain a value for constructing a Plugin object.
>>>     *
>>>     * @param configuration the current Configuration.
>>>     * @param node          the current Node corresponding to the Plugin
>>> object being created.
>>> -     * @param event         the current LogEvent that caused this Plugin
>>> object to be made (optional).
>>> -     * @param log           the StringBuilder being used to build a debug
>>> message.
>>> +     * @param substitutor   the function to perform String substitutions.
>>> +     * @param log           th e StringBuilder being used to build a
>>> debug message.
>>>     * @return the converted value to be used for Plugin creation.
>>>     */
>>> -    Object visit(Configuration configuration, Node node, LogEvent event,
>>> StringBuilder log);
>>> +    Object visit(T configuration, Node node, Function<String, String>
>>> substitutor, StringBuilder log);
>>> }
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>>> similarity index 86%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>>> index 10ee0df..695d387 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>>> @@ -15,14 +15,14 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>>> -
>>> -import java.lang.annotation.Annotation;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> 
>>> import org.apache.logging.log4j.Logger;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginVisitorStrategy;
>>> +import org.apache.logging.log4j.plugins.PluginVisitorStrategy;
>>> import org.apache.logging.log4j.status.StatusLogger;
>>> 
>>> +import java.lang.annotation.Annotation;
>>> +
>>> /**
>>> * Utility class to locate an appropriate {@link PluginVisitor}
>>> implementation for an annotation.
>>> */
>>> @@ -41,13 +41,13 @@ public final class PluginVisitors {
>>>     * @param annotation the Plugin annotation class to find a
>>> PluginVisitor for.
>>>     * @return a PluginVisitor instance if one could be created, or
>>> {@code null} otherwise.
>>>     */
>>> -    public static PluginVisitor<? extends Annotation> findVisitor(final
>>> Class<? extends Annotation> annotation) {
>>> +    public static <T> PluginVisitor<? extends Annotation, T>
>>> findVisitor(final Class<? extends Annotation> annotation) {
>>>        final PluginVisitorStrategy strategy =
>>> annotation.getAnnotation(PluginVisitorStrategy.class);
>>>        if (strategy == null) {
>>>            return null;
>>>        }
>>>        try {
>>> -            return strategy.value().newInstance();
>>> +            return (PluginVisitor<? extends Annotation, T>)
>>> strategy.value().newInstance();
>>>        } catch (final Exception e) {
>>>            LOGGER.error("Error loading PluginVisitor [{}] for annotation
>>> [{}].", strategy.value(), annotation, e);
>>>            return null;
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>>> similarity index 67%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> rename to
>>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>>> index f22ba49..0855b16 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>>> +++
>>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>>> @@ -16,8 +16,9 @@
>>> */
>>> 
>>> /**
>>> - * Validation annotations.
>>> - *
>>> - * @since 2.1
>>> + * Visitor classes for extracting values from a Configuration or Node
>>> corresponding to a plugin annotation.
>>> + * Visitor implementations must implement {@link
>>> org.apache.logging.log4j.plugins.visitors.PluginVisitor},
>>> + * and the corresponding annotation must be annotated with
>>> + * {@link org.apache.logging.log4j.plugins.PluginVisitorStrategy}.
>>> */
>>> -package
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>>> +package org.apache.logging.log4j.plugins.visitors;
>>> diff --git
>>> a/log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>> b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>> similarity index 91%
>>> rename from
>>> log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>> rename to
>>> log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>> index bb9dcb9..5d6951a 100644
>>> ---
>>> a/log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>> +++
>>> b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>>> @@ -14,4 +14,4 @@
>>> # See the license for the specific language governing permissions and
>>> # limitations under the license.
>>> #
>>> -org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor
>>> +org.apache.logging.log4j.plugins.processor.PluginProcessor
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>>> similarity index 97%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>>> index f9e757d..6e4b059 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>>> @@ -14,7 +14,7 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>> +package org.apache.logging.log4j.plugins.convert;
>>> 
>>> import org.junit.Test;
>>> 
>>> @@ -63,7 +63,7 @@ public class TypeConverterRegistryTest {
>>>        // TODO: is there a specific converter this should return?
>>>    }
>>> 
>>> -    public static enum Foo {
>>> +    public enum Foo {
>>>        I, PITY, THE
>>>    }
>>> 
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>>> similarity index 84%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>>> index f4ceb41..48ea7dc 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>>> @@ -15,10 +15,10 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>> +package org.apache.logging.log4j.plugins.processor;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> +import org.apache.logging.log4j.plugins.PluginAliases;
>>> 
>>> /**
>>> * Test plugin class for unit tests.
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>>> similarity index 75%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>>> index 9c37af4..034705c 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>>> @@ -15,17 +15,19 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.processor;
>>> +package org.apache.logging.log4j.plugins.processor;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> +import org.apache.logging.log4j.plugins.PluginAliases;
>>> import org.junit.BeforeClass;
>>> import org.junit.Test;
>>> import org.junit.runner.RunWith;
>>> import org.junit.runners.JUnit4;
>>> 
>>> import java.net.URL;
>>> +import java.util.ArrayList;
>>> import java.util.Enumeration;
>>> +import java.util.List;
>>> import java.util.Map;
>>> 
>>> import static org.junit.Assert.*;
>>> @@ -33,29 +35,29 @@ import static org.junit.Assert.*;
>>> @RunWith(JUnit4.class)
>>> public class PluginProcessorTest {
>>> 
>>> -    private static final PluginCache pluginCache = new PluginCache();
>>> +    private static PluginService pluginService;
>>> 
>>>    private final Plugin p = FakePlugin.class.getAnnotation(Plugin.class);
>>> 
>>>    @BeforeClass
>>>    public static void setUpClass() throws Exception {
>>> -        final Enumeration<URL> resources =
>>> -
>>> PluginProcessor.class.getClassLoader().getResources(PluginProcessor.PLUGIN_CACHE_FILE);
>>> -        pluginCache.loadCacheFiles(resources);
>>> +        Class<?> clazz =
>>> PluginProcessor.class.getClassLoader().loadClass("org.apache.logging.log4j.plugins.plugins.Log4jPlugins");
>>> +        assertNotNull("Could not locate plugins class", clazz);
>>> +        pluginService = (PluginService)
>>> clazz.getDeclaredConstructor().newInstance();;
>>>    }
>>> 
>>>    @Test
>>>    public void testTestCategoryFound() throws Exception {
>>>        assertNotNull("No plugin annotation on FakePlugin.", p);
>>> -        final Map<String, PluginEntry> testCategory =
>>> pluginCache.getCategory(p.category());
>>> -        assertNotEquals("No plugins were found.", 0, pluginCache.size());
>>> +        final Map<String, PluginEntry> testCategory =
>>> pluginService.getCategory(p.category());
>>> +        assertNotEquals("No plugins were found.", 0,
>>> pluginService.size());
>>>        assertNotNull("The category '" + p.category() + "' was not
>>> found.", testCategory);
>>>        assertFalse(testCategory.isEmpty());
>>>    }
>>> 
>>>    @Test
>>>    public void testFakePluginFoundWithCorrectInformation() throws
>>> Exception {
>>> -        final PluginEntry fake =
>>> pluginCache.getCategory(p.category()).get(p.name().toLowerCase());
>>> +        final PluginEntry fake =
>>> pluginService.getCategory(p.category()).get(p.name().toLowerCase());
>>>        verifyFakePluginEntry(p.name(), fake);
>>>    }
>>> 
>>> @@ -63,7 +65,7 @@ public class PluginProcessorTest {
>>>    public void testFakePluginAliasesContainSameInformation() throws
>>> Exception {
>>>        final PluginAliases aliases =
>>> FakePlugin.class.getAnnotation(PluginAliases.class);
>>>        for (final String alias : aliases.value()) {
>>> -            final PluginEntry fake =
>>> pluginCache.getCategory(p.category()).get(alias.toLowerCase());
>>> +            final PluginEntry fake =
>>> pluginService.getCategory(p.category()).get(alias.toLowerCase());
>>>            verifyFakePluginEntry(alias, fake);
>>>        }
>>>    }
>>> @@ -81,7 +83,7 @@ public class PluginProcessorTest {
>>>    @Test
>>>    public void testNestedPlugin() throws Exception {
>>>        final Plugin p =
>>> FakePlugin.Nested.class.getAnnotation(Plugin.class);
>>> -        final PluginEntry nested =
>>> pluginCache.getCategory(p.category()).get(p.name().toLowerCase());
>>> +        final PluginEntry nested =
>>> pluginService.getCategory(p.category()).get(p.name().toLowerCase());
>>>        assertNotNull(nested);
>>>        assertEquals(p.name().toLowerCase(), nested.getKey());
>>>        assertEquals(FakePlugin.Nested.class.getName(),
>>> nested.getClassName());
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>>> similarity index 93%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>>> index 33e0ee1..d0b35d1 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>>> @@ -15,27 +15,21 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>> +package org.apache.logging.log4j.plugins.util;
>>> 
>>> -import static org.junit.Assert.assertEquals;
>>> +import org.apache.logging.log4j.junit.CleanFolders;
>>> +import org.apache.logging.log4j.junit.URLStreamHandlerFactoryRule;
>>> +import org.junit.Rule;
>>> +import org.junit.Test;
>>> +import org.junit.rules.RuleChain;
>>> 
>>> import java.io.IOException;
>>> -import java.net.Proxy;
>>> -import java.net.URL;
>>> -import java.net.URLClassLoader;
>>> -import java.net.URLConnection;
>>> -import java.net.URLStreamHandler;
>>> -import java.net.URLStreamHandlerFactory;
>>> +import java.net.*;
>>> import java.util.Arrays;
>>> import java.util.Collections;
>>> import java.util.Enumeration;
>>> 
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest;
>>> -import org.apache.logging.log4j.junit.CleanFolders;
>>> -import org.apache.logging.log4j.junit.URLStreamHandlerFactoryRule;
>>> -import org.junit.Rule;
>>> -import org.junit.Test;
>>> -import org.junit.rules.RuleChain;
>>> +import static org.junit.Assert.assertEquals;
>>> 
>>> /**
>>> * Tests the ResolverUtil class for custom protocol like bundleresource,
>>> vfs, vfszip.
>>> @@ -187,9 +181,9 @@ public class ResolverUtilCustomProtocolTest {
>>>            final ResolverUtil resolverUtil = new ResolverUtil();
>>>            resolverUtil
>>>                    .setClassLoader(new SingleURLClassLoader(new
>>> URL("vfs:/" + ResolverUtilTest.WORK_DIR + "/resolverutil3/customplugin3/"),
>>> cl));
>>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin3");
>>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>>> "customplugin3");
>>>            assertEquals("Class not found in packages", 1,
>>> resolverUtil.getClasses().size());
>>> -            assertEquals("Unexpected class resolved",
>>> cl.loadClass("customplugin3.FixedString3Layout"),
>>> +            assertEquals("Unexpected class resolved",
>>> cl.loadClass("customplugin3.FixedString3"),
>>>                    resolverUtil.getClasses().iterator().next());
>>>        }
>>>    }
>>> @@ -200,9 +194,9 @@ public class ResolverUtilCustomProtocolTest {
>>>            final ResolverUtil resolverUtil = new ResolverUtil();
>>>            resolverUtil.setClassLoader(new SingleURLClassLoader(
>>>                    new URL("vfs:/" + ResolverUtilTest.WORK_DIR +
>>> "/resolverutil4/customplugin4.jar/customplugin4/"), cl));
>>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin4");
>>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>>> "customplugin4");
>>>            assertEquals("Class not found in packages", 1,
>>> resolverUtil.getClasses().size());
>>> -            assertEquals("Unexpected class resolved",
>>> cl.loadClass("customplugin4.FixedString4Layout"),
>>> +            assertEquals("Unexpected class resolved",
>>> cl.loadClass("customplugin4.FixedString4"),
>>>                    resolverUtil.getClasses().iterator().next());
>>>        }
>>>    }
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>>> similarity index 82%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>>> index 1c6371b..361fe7b 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>>> @@ -15,33 +15,25 @@
>>> * limitations under the license.
>>> */
>>> 
>>> -package org.apache.logging.log4j.core.config.plugins.util;
>>> +package org.apache.logging.log4j.plugins.util;
>>> 
>>> -import static org.junit.Assert.assertEquals;
>>> -import static org.junit.Assert.assertTrue;
>>> -
>>> -import java.io.File;
>>> -import java.io.IOException;
>>> -import java.io.UnsupportedEncodingException;
>>> -import java.net.MalformedURLException;
>>> -import java.net.URI;
>>> -import java.net.URISyntaxException;
>>> -import java.net.URL;
>>> -import java.net.URLClassLoader;
>>> -import java.nio.file.FileSystem;
>>> -import java.nio.file.FileSystems;
>>> -import java.nio.file.Files;
>>> -import java.nio.file.Path;
>>> -import java.nio.file.StandardCopyOption;
>>> -import java.util.HashMap;
>>> -import java.util.Map;
>>> -
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest;
>>> import org.apache.logging.log4j.junit.CleanFolders;
>>> import org.junit.Rule;
>>> import org.junit.Test;
>>> import org.junit.rules.RuleChain;
>>> 
>>> +import javax.tools.*;
>>> +import java.io.File;
>>> +import java.io.IOException;
>>> +import java.io.UnsupportedEncodingException;
>>> +import java.net.*;
>>> +import java.nio.file.*;
>>> +import java.util.*;
>>> +
>>> +import static org.junit.Assert.assertEquals;
>>> +import static org.junit.Assert.assertTrue;
>>> +import static org.junit.Assert.assertNotNull;
>>> +
>>> /**
>>> * Tests the ResolverUtil class.
>>> */
>>> @@ -67,6 +59,7 @@ public class ResolverUtilTest {
>>>    private void testExtractPathFromJarUrlNotDecodedIfFileExists(final
>>> String existingFile)
>>>            throws MalformedURLException, UnsupportedEncodingException,
>>> URISyntaxException {
>>>        URL url = ResolverUtilTest.class.getResource(existingFile);
>>> +        assertNotNull("No url returned for " + existingFile, url);
>>>        if (!url.getProtocol().equals("jar")) {
>>>            // create fake jar: URL that resolves to existing file
>>>            url = new URL("jar:" + url.toExternalForm() + "!/some/entry");
>>> @@ -152,9 +145,9 @@ public class ResolverUtilTest {
>>>        try (final URLClassLoader cl = compileAndCreateClassLoader("1")) {
>>>            final ResolverUtil resolverUtil = new ResolverUtil();
>>>            resolverUtil.setClassLoader(cl);
>>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin1");
>>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>>> "customplugin1");
>>>            assertEquals("Class not found in packages", 1,
>>> resolverUtil.getClasses().size());
>>> -            assertEquals("Unexpected class resolved",
>>> cl.loadClass("customplugin1.FixedString1Layout"),
>>> +            assertEquals("Unexpected class resolved",
>>> cl.loadClass("customplugin1.FixedString1"),
>>>                    resolverUtil.getClasses().iterator().next());
>>>        }
>>>    }
>>> @@ -164,9 +157,9 @@ public class ResolverUtilTest {
>>>        try (final URLClassLoader cl =
>>> compileJarAndCreateClassLoader("2")) {
>>>            final ResolverUtil resolverUtil = new ResolverUtil();
>>>            resolverUtil.setClassLoader(cl);
>>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin2");
>>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>>> "customplugin2");
>>>            assertEquals("Class not found in packages", 1,
>>> resolverUtil.getClasses().size());
>>> -            assertEquals("Unexpected class resolved",
>>> cl.loadClass("customplugin2.FixedString2Layout"),
>>> +            assertEquals("Unexpected class resolved",
>>> cl.loadClass("customplugin2.FixedString2"),
>>>                    resolverUtil.getClasses().iterator().next());
>>>        }
>>>    }
>>> @@ -176,7 +169,7 @@ public class ResolverUtilTest {
>>>        final File jarFile = new File(workDir, "customplugin" + suffix +
>>> ".jar");
>>>        final URI jarURI = jarFile.toURI();
>>>        createJar(jarURI, workDir, new File(workDir,
>>> -              "customplugin" + suffix + "/FixedString" + suffix +
>>> "Layout.class"));
>>> +              "customplugin" + suffix + "/FixedString" + suffix +
>>> ".class"));
>>>        return URLClassLoader.newInstance(new URL[] {jarURI.toURL()});
>>>    }
>>> 
>>> @@ -186,9 +179,9 @@ public class ResolverUtilTest {
>>>    }
>>> 
>>>    static File compile(final String suffix) throws IOException {
>>> -        final File orig = new
>>> File("target/test-classes/customplugin/FixedStringLayout.java.source");
>>> +        final File orig = new
>>> File("target/test-classes/customplugin/FixedString.java.source");
>>>        final File workDir = new File(WORK_DIR, "resolverutil" + suffix);
>>> -        final File f = new File(workDir, "customplugin" + suffix +
>>> "/FixedString" + suffix + "Layout.java");
>>> +        final File f = new File(workDir, "customplugin" + suffix +
>>> "/FixedString" + suffix + ".java");
>>>        final File parent = f.getParentFile();
>>>        if (!parent.exists()) {
>>>          assertTrue("Create customplugin" + suffix + " folder KO",
>>> f.getParentFile().mkdirs());
>>> @@ -199,7 +192,7 @@ public class ResolverUtilTest {
>>>          .replaceAll("customplugin", "customplugin" + suffix);
>>>        Files.write(f.toPath(), content.getBytes());
>>> 
>>> -        PluginManagerPackagesTest.compile(f);
>>> +        compile(f);
>>>        return workDir;
>>>    }
>>> 
>>> @@ -218,4 +211,29 @@ public class ResolverUtilTest {
>>>        }
>>>    }
>>> 
>>> +    static void compile(final File f) throws IOException {
>>> +        // set up compiler
>>> +        final JavaCompiler compiler =
>>> ToolProvider.getSystemJavaCompiler();
>>> +        final DiagnosticCollector<JavaFileObject> diagnostics = new
>>> DiagnosticCollector<>();
>>> +        final List<String> errors = new ArrayList<>();
>>> +        try (final StandardJavaFileManager fileManager =
>>> compiler.getStandardFileManager(diagnostics, null, null)) {
>>> +            final Iterable<? extends JavaFileObject> compilationUnits =
>>> fileManager.getJavaFileObjectsFromFiles(Arrays
>>> +                .asList(f));
>>> +
>>> +            // compile generated source
>>> +            // (switch off annotation processing: no need to create
>>> Log4j2Plugins.dat)
>>> +            final List<String> options = Arrays.asList("-proc:none");
>>> +            compiler.getTask(null, fileManager, diagnostics, options,
>>> null, compilationUnits).call();
>>> +
>>> +            // check we don't have any compilation errors
>>> +            for (final Diagnostic<? extends JavaFileObject> diagnostic :
>>> diagnostics.getDiagnostics()) {
>>> +                if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
>>> +                    errors.add(String.format("Compile error at line %d,
>>> column %d: %s%n", diagnostic.getLineNumber(),
>>> +                        diagnostic.getColumnNumber(),
>>> diagnostic.getMessage(Locale.getDefault())));
>>> +                }
>>> +            }
>>> +        }
>>> +        assertTrue(errors.toString(), errors.isEmpty());
>>> +    }
>>> +
>>> }
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>>> similarity index 87%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>>> index 5689e29..0e243f2 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>>> @@ -14,10 +14,10 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>> 
>>> /**
>>> *
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>>> similarity index 78%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>>> index 34123c0..626798e 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>>> @@ -14,15 +14,15 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> -import java.net.InetSocketAddress;
>>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
>>> +import java.net.InetSocketAddress;
>>> 
>>> @Plugin(name = "HostAndPort", category = "Test")
>>> public class HostAndPort {
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>> similarity index 81%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>> index 3f2b15a..c3fe6c5 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>>> @@ -14,18 +14,18 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>> -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> 
>>> @Plugin(name = "PluginWithGenericSubclassFoo1Builder", category = "Test")
>>> public class PluginWithGenericSubclassFoo1Builder extends
>>> AbstractPluginWithGenericBuilder {
>>> 
>>>    public static class Builder<B extends Builder<B>> extends
>>> AbstractPluginWithGenericBuilder.Builder<B>
>>> -            implements
>>> org.apache.logging.log4j.core.util.Builder<PluginWithGenericSubclassFoo1Builder>
>>> {
>>> +            implements
>>> org.apache.logging.log4j.plugins.util.Builder<PluginWithGenericSubclassFoo1Builder>
>>> {
>>> 
>>>        @PluginBuilderFactory
>>>        public static <B extends Builder<B>> B newBuilder() {
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>>> similarity index 80%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>>> index 95a4209..9caf453 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>>> @@ -14,15 +14,15 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> -import java.util.Objects;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>> -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.validation.constraints.Required;
>>> +import java.util.Objects;
>>> 
>>> /**
>>> *
>>> @@ -51,7 +51,7 @@ public class ValidatingPlugin {
>>>        return new Builder();
>>>    }
>>> 
>>> -    public static class Builder implements
>>> org.apache.logging.log4j.core.util.Builder<ValidatingPlugin> {
>>> +    public static class Builder implements
>>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPlugin> {
>>> 
>>>        @PluginBuilderAttribute
>>>        @Required(message = "The name given by the builder is null")
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>> similarity index 80%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>> index 81b9d6f..b0bec53 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>>> @@ -14,15 +14,16 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> -import java.util.Objects;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> +
>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>> -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.validation.constraints.Required;
>>> +import java.util.Objects;
>>> 
>>> /**
>>> *
>>> @@ -51,7 +52,7 @@ public class ValidatingPluginWithGenericBuilder {
>>>        return new Builder<B>().asBuilder();
>>>    }
>>> 
>>> -    public static class Builder<B extends Builder<B>> implements
>>> org.apache.logging.log4j.core.util.Builder<ValidatingPluginWithGenericBuilder>
>>> {
>>> +    public static class Builder<B extends Builder<B>> implements
>>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithGenericBuilder>
>>> {
>>> 
>>>        @PluginBuilderAttribute
>>>        @Required(message = "The name given by the builder is null")
>>> diff --git
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>> similarity index 80%
>>> rename from
>>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>> rename to
>>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>> index 74a6477..256181c 100644
>>> ---
>>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>> +++
>>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>>> @@ -14,15 +14,15 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.validation;
>>> +package org.apache.logging.log4j.plugins.validation;
>>> 
>>> -import java.util.Objects;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> 
>>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>>> -import
>>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>>> -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.validation.constraints.Required;
>>> +import java.util.Objects;
>>> 
>>> /**
>>> *
>>> @@ -51,7 +51,7 @@ public class ValidatingPluginWithTypedBuilder {
>>>        return new Builder<>();
>>>    }
>>> 
>>> -    public static class Builder<T> implements
>>> org.apache.logging.log4j.core.util.Builder<ValidatingPluginWithTypedBuilder>
>>> {
>>> +    public static class Builder<T> implements
>>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithTypedBuilder>
>>> {
>>> 
>>>        @PluginBuilderAttribute
>>>        @Required(message = "The name given by the builder is null")
>>> diff --git
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>> b/log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>>> similarity index 52%
>>> rename from
>>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>> rename to
>>> log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>>> index 15a162c..85a62ec 100644
>>> ---
>>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>>> +++ b/log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>>> @@ -14,25 +14,32 @@
>>> * See the license for the specific language governing permissions and
>>> * limitations under the license.
>>> */
>>> -package org.apache.logging.log4j.core.config.plugins.convert;
>>> 
>>> -import org.apache.logging.log4j.util.EnglishEnums;
>>> +package customplugin;
>>> 
>>> -/**
>>> - * Converts a {@link String} into a {@link Enum}. Returns {@code null}
>>> for invalid enum names.
>>> - *
>>> - * @param <E> the enum class to parse.
>>> - * @since 2.1 moved from TypeConverters
>>> - */
>>> -public class EnumConverter<E extends Enum<E>> implements TypeConverter<E>
>>> {
>>> -    private final Class<E> clazz;
>>> +import java.util.Collections;
>>> +import java.util.Map;
>>> +
>>> +import org.apache.logging.log4j.plugins.Plugin;
>>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>>> +import org.apache.logging.log4j.plugins.PluginFactory;
>>> +
>>> +@Plugin(name = "FixedString", category = "Core", elementType = "plugin",
>>> printObject = true)
>>> +public class FixedString  {
>>> +
>>> +    private String fixedString;
>>> +
>>> +    @PluginFactory
>>> +    public static FixedString create(
>>> +            @PluginAttribute("fixedString") final String fixedString) {
>>> +        return new FixedString(fixedString);
>>> +    }
>>> 
>>> -    public EnumConverter(final Class<E> clazz) {
>>> -        this.clazz = clazz;
>>> +    public FixedString(String fixedString) {
>>> +        this.fixedString = fixedString;
>>>    }
>>> 
>>> -    @Override
>>> -    public E convert(final String s) {
>>> -        return EnglishEnums.valueOf(clazz, s);
>>> +    public Map<String, String> getContentFormat() {
>>> +        return Collections.emptyMap();
>>>    }
>>> }
>>> diff --git
>>> a/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>>> b/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>>> new file mode 100644
>>> index 0000000..b85475a
>>> --- /dev/null
>>> +++
>>> b/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>>> @@ -0,0 +1,31 @@
>>> +<?xml version="1.0" encoding="UTF-8"?>
>>> +<!--
>>> + 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.
>>> +
>>> +-->
>>> +<Configuration status="OFF" name="XMLConfigTest">
>>> +
>>> +  <Appenders>
>>> +    <List name="List">
>>> +    </List>
>>> +  </Appenders>
>>> +  <Loggers>
>>> +    <Root level="trace">
>>> +      <AppenderRef ref="List"/>
>>> +    </Root>
>>> +  </Loggers>
>>> +
>>> +</Configuration>
>>> \ No newline at end of file
>>> diff --git a/log4j-plugins/src/test/resources/s p a c e
>>> s/log4j+config+with+plus+characters.xml
>>> b/log4j-plugins/src/test/resources/s p a c e
>>> s/log4j+config+with+plus+characters.xml
>>> new file mode 100644
>>> index 0000000..b85475a
>>> --- /dev/null
>>> +++ b/log4j-plugins/src/test/resources/s p a c e
>>> s/log4j+config+with+plus+characters.xml
>>> @@ -0,0 +1,31 @@
>>> +<?xml version="1.0" encoding="UTF-8"?>
>>> +<!--
>>> + 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.
>>> +
>>> +-->
>>> +<Configuration status="OFF" name="XMLConfigTest">
>>> +
>>> +  <Appenders>
>>> +    <List name="List">
>>> +    </List>
>>> +  </Appenders>
>>> +  <Loggers>
>>> +    <Root level="trace">
>>> +      <AppenderRef ref="List"/>
>>> +    </Root>
>>> +  </Loggers>
>>> +
>>> +</Configuration>
>>> \ No newline at end of file
>>> 
>>> 
> 
> 
> 



Re: [logging-log4j2] 01/02: LOG4J2-2621 - Initial commit

Posted by Ralph Goers <ra...@dslextreme.com>.
Yes, but it shows up in the correct place in the git repo and the diff in the email shows the correct directory.

Ralph

> On Jun 3, 2019, at 3:56 AM, Gary Gregory <ga...@gmail.com> wrote:
> 
> This is weird, note the "}":
> 
> .../org/apache/logging/log4j}/util/Assert.java     |   0
> 
> Gary
> 
> On Sun, Jun 2, 2019 at 6:38 PM <rg...@apache.org> wrote:
> 
>> This is an automated email from the ASF dual-hosted git repository.
>> 
>> rgoers pushed a commit to branch LOG4J2-2621
>> in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git
>> 
>> commit b69c2d9e4b79ee7830a69463c6f89de1c50fe84d
>> Author: Ralph Goers <rg...@apache.org>
>> AuthorDate: Sun Jun 2 13:18:36 2019 -0700
>> 
>>    LOG4J2-2621 - Initial commit
>> ---
>> .../org/apache/logging/log4j}/util/Assert.java     |   0
>> .../logging/log4j/util/InternalException.java      |  56 ++++
>> .../org/apache/logging/log4j}/util/NameUtil.java   |   0
>> .../apache/logging/log4j}/util/ReflectionUtil.java |   6 +-
>> .../log4j/junit/AbstractExternalFileCleaner.java   |   0
>> .../org/apache/logging/log4j/junit/CleanFiles.java |   0
>> .../apache/logging/log4j/junit/CleanFolders.java   |   0
>> .../log4j/junit/URLStreamHandlerFactoryRule.java   |   0
>> .../org/apache/logging/log4j}/util/AssertTest.java |   2 +-
>> .../config/plugins/convert/Base64Converter.java    |  79 -----
>> ...TypeConverters.java => CoreTypeConverters.java} |   7 +-
>> .../ValidatingPluginWithGenericBuilderTest.java    |  10 +-
>> log4j-plugins-java9/pom.xml                        | 157 +++++++++
>> log4j-plugins-java9/src/assembly/java9.xml         |  40 +++
>> .../src/main/java/module-info.java                 |  15 +-
>> .../org/apache/logging/log4j/plugins/Dummy.java    |   9 +-
>> .../logging/log4j/plugins/convert/Dummy.java       |   9 +-
>> .../log4j/plugins/processor/PluginService.java     |   9 +-
>> .../apache/logging/log4j/plugins/util/Dummy.java   |   9 +-
>> .../logging/log4j/plugins/validation/Dummy.java    |   9 +-
>> .../logging/log4j/plugins/visitors/Dummy.java      |   9 +-
>> log4j-plugins/pom.xml                              | 360
>> +++++++++++++++++++++
>> .../org/apache/logging/log4j/plugins}/Node.java    |   6 +-
>> .../org/apache/logging/log4j}/plugins/Plugin.java  |   6 +-
>> .../logging/log4j}/plugins/PluginAliases.java      |   4 +-
>> .../logging/log4j}/plugins/PluginAttribute.java    |   8 +-
>> .../log4j}/plugins/PluginBuilderAttribute.java     |   8 +-
>> .../log4j}/plugins/PluginBuilderFactory.java       |   2 +-
>> .../logging/log4j}/plugins/PluginElement.java      |   6 +-
>> .../logging/log4j}/plugins/PluginFactory.java      |   2 +-
>> .../apache/logging/log4j}/plugins/PluginNode.java  |   6 +-
>> .../apache/logging/log4j}/plugins/PluginValue.java |   6 +-
>> .../log4j}/plugins/PluginVisitorStrategy.java      |   8 +-
>> .../log4j}/plugins/convert/EnumConverter.java      |   2 +-
>> .../log4j}/plugins/convert/HexConverter.java       |   2 +-
>> .../log4j}/plugins/convert/TypeConverter.java      |   2 +-
>> .../plugins/convert/TypeConverterRegistry.java     |  23 +-
>> .../log4j}/plugins/convert/TypeConverters.java     |  47 +--
>> .../log4j/plugins/convert}/package-info.java       |   7 +-
>> .../logging/log4j/plugins/osgi/Activator.java      | 103 ++++++
>> .../logging/log4j/plugins/osgi}/package-info.java  |   6 +-
>> .../logging/log4j/plugins}/package-info.java       |   6 +-
>> .../log4j}/plugins/processor/PluginCache.java      |  30 +-
>> .../log4j}/plugins/processor/PluginEntry.java      |  14 +-
>> .../log4j}/plugins/processor/PluginProcessor.java  | 157 +++++++--
>> .../log4j/plugins/processor/PluginService.java     |  56 ++++
>> .../log4j}/plugins/processor/package-info.java     |   2 +-
>> .../logging/log4j/plugins}/util/Builder.java       |   4 +-
>> .../logging/log4j}/plugins/util/PluginManager.java |   8 +-
>> .../log4j}/plugins/util/PluginRegistry.java        |  81 +++--
>> .../logging/log4j}/plugins/util/PluginType.java    |   6 +-
>> .../logging/log4j}/plugins/util/ResolverUtil.java  |  29 +-
>> .../logging/log4j/plugins/util/TypeUtil.java       | 217 +++++++++++++
>> .../logging/log4j/plugins/util}/package-info.java  |   2 +-
>> .../log4j}/plugins/validation/Constraint.java      |   9 +-
>> .../plugins/validation/ConstraintValidator.java    |   2 +-
>> .../plugins/validation/ConstraintValidators.java   |   8 +-
>> .../plugins/validation/constraints/Required.java   |  12 +-
>> .../plugins/validation/constraints/ValidHost.java  |   6 +-
>> .../plugins/validation/constraints/ValidPort.java  |  12 +-
>> .../validation/constraints/package-info.java       |   2 +-
>> .../log4j}/plugins/validation/package-info.java    |   2 +-
>> .../validation/validators/RequiredValidator.java   |  14 +-
>> .../validation/validators/ValidHostValidator.java  |   6 +-
>> .../validation/validators/ValidPortValidator.java  |   8 +-
>> .../validation/validators/package-info.java        |   2 +-
>> .../plugins/visitors/AbstractPluginVisitor.java    |  34 +-
>> .../plugins/visitors/PluginAttributeVisitor.java   |  27 +-
>> .../visitors/PluginBuilderAttributeVisitor.java    |  23 +-
>> .../plugins/visitors/PluginElementVisitor.java     |  17 +-
>> .../log4j}/plugins/visitors/PluginNodeVisitor.java |  14 +-
>> .../plugins/visitors/PluginValueVisitor.java       |  18 +-
>> .../log4j}/plugins/visitors/PluginVisitor.java     |  36 +--
>> .../log4j}/plugins/visitors/PluginVisitors.java    |  12 +-
>> .../log4j/plugins/visitors}/package-info.java      |   9 +-
>> .../services/javax.annotation.processing.Processor |   2 +-
>> .../plugins/convert/TypeConverterRegistryTest.java |   4 +-
>> .../log4j}/plugins/processor/FakePlugin.java       |   6 +-
>> .../plugins/processor/PluginProcessorTest.java     |  26 +-
>> .../util/ResolverUtilCustomProtocolTest.java       |  30 +-
>> .../log4j}/plugins/util/ResolverUtilTest.java      |  76 +++--
>> .../AbstractPluginWithGenericBuilder.java          |   6 +-
>> .../log4j}/plugins/validation/HostAndPort.java     |  14 +-
>> .../PluginWithGenericSubclassFoo1Builder.java      |  12 +-
>> .../plugins/validation/ValidatingPlugin.java       |  16 +-
>> .../ValidatingPluginWithGenericBuilder.java        |  17 +-
>> .../ValidatingPluginWithTypedBuilder.java          |  16 +-
>> .../resources/customplugin/FixedString.java.source |  37 ++-
>> .../log4j+config+with+plus+characters.xml          |  31 ++
>> .../log4j+config+with+plus+characters.xml          |  31 ++
>> 90 files changed, 1655 insertions(+), 594 deletions(-)
>> 
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Assert.java
>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/Assert.java
>> similarity index 100%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/Assert.java
>> rename to log4j-api/src/main/java/org/apache/logging/log4j/util/Assert.java
>> diff --git
>> a/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>> new file mode 100644
>> index 0000000..8c433db
>> --- /dev/null
>> +++
>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/InternalException.java
>> @@ -0,0 +1,56 @@
>> +/*
>> + * 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;
>> +
>> +/**
>> + * Exception thrown when an error occurs while logging.  In most cases
>> exceptions will be handled
>> + * within Log4j but certain Appenders may be configured to allow
>> exceptions to propagate to the
>> + * application. This is a RuntimeException so that the exception may be
>> thrown in those cases without
>> + * requiring all Logger methods be contained with try/catch blocks.
>> + */
>> +public class LoggingException extends RuntimeException {
>> +
>> +    private static final long serialVersionUID = 6366395965071580537L;
>> +
>> +    /**
>> +     * Construct an exception with a message.
>> +     *
>> +     * @param message The reason for the exception
>> +     */
>> +    public LoggingException(final String message) {
>> +        super(message);
>> +    }
>> +
>> +    /**
>> +     * Construct an exception with a message and underlying cause.
>> +     *
>> +     * @param message The reason for the exception
>> +     * @param cause The underlying cause of the exception
>> +     */
>> +    public LoggingException(final String message, final Throwable cause) {
>> +        super(message, cause);
>> +    }
>> +
>> +    /**
>> +     * Construct an exception with an underlying cause.
>> +     *
>> +     * @param cause The underlying cause of the exception
>> +     */
>> +    public LoggingException(final Throwable cause) {
>> +        super(cause);
>> +    }
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/NameUtil.java
>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
>> similarity index 100%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/NameUtil.java
>> rename to
>> log4j-api/src/main/java/org/apache/logging/log4j/util/NameUtil.java
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>> similarity index 98%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>> rename to
>> log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>> index ffee439..f00e64a 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/ReflectionUtil.java
>> +++
>> b/log4j-api/src/main/java/org/apache/logging/log4j/util/ReflectionUtil.java
>> @@ -193,8 +193,10 @@ public final class ReflectionUtil {
>>         } catch (final IllegalAccessException e) {
>>             throw new IllegalStateException(e);
>>         } catch (final InvocationTargetException e) {
>> -            Throwables.rethrow(e.getCause());
>> -            throw new InternalError("Unreachable");
>> +            if (e.getCause() instanceof RuntimeException) {
>> +                throw (RuntimeException) e.getCause();
>> +            }
>> +            throw new
>>         }
>>     }
>> }
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>> similarity index 100%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>> rename to
>> log4j-api/src/test/java/org/apache/logging/log4j/junit/AbstractExternalFileCleaner.java
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>> similarity index 100%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>> rename to
>> log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFiles.java
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>> similarity index 100%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>> rename to
>> log4j-api/src/test/java/org/apache/logging/log4j/junit/CleanFolders.java
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>> b/log4j-api/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>> similarity index 100%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>> rename to
>> log4j-api/src/test/java/org/apache/logging/log4j/junit/URLStreamHandlerFactoryRule.java
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>> b/log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>> similarity index 99%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>> rename to
>> log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>> index 242c41e..7e46036 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/util/AssertTest.java
>> +++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/AssertTest.java
>> @@ -65,4 +65,4 @@ public class AssertTest {
>>         assertEquals(isEmpty, Assert.isEmpty(value));
>>     }
>> 
>> -}
>> \ No newline at end of file
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>> deleted file mode 100644
>> index f4e421f..0000000
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/Base64Converter.java
>> +++ /dev/null
>> @@ -1,79 +0,0 @@
>> -/*
>> - * 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.convert;
>> -
>> -import java.lang.reflect.InvocationTargetException;
>> -import java.lang.reflect.Method;
>> -
>> -import org.apache.logging.log4j.Logger;
>> -import org.apache.logging.log4j.status.StatusLogger;
>> -import org.apache.logging.log4j.util.LoaderUtil;
>> -
>> -/**
>> - * @Since 2.9
>> - */
>> -public class Base64Converter {
>> -
>> -    private static final Logger LOGGER = StatusLogger.getLogger();
>> -    private static Method method = null;
>> -    private static Object decoder = null;
>> -
>> -    static {
>> -        try {
>> -            // Base64 is available in Java 8 and up.
>> -            Class<?> clazz = LoaderUtil.loadClass("java.util.Base64");
>> -            final Method getDecoder = clazz.getMethod("getDecoder",
>> (Class[]) null);
>> -            decoder = getDecoder.invoke(null, (Object[]) null);
>> -            clazz = decoder.getClass();
>> -            method = clazz.getMethod("decode", String.class);
>> -        } catch (final ClassNotFoundException ex) {
>> -
>> -        } catch (final NoSuchMethodException ex) {
>> -
>> -        } catch (final IllegalAccessException ex) {
>> -
>> -        } catch (final InvocationTargetException ex) {
>> -
>> -        }
>> -        if (method == null) {
>> -            try {
>> -                // DatatypeConverter is not in the default module in Java
>> 9.
>> -                final Class<?> clazz =
>> LoaderUtil.loadClass("javax.xml.bind.DatatypeConverter");
>> -                method = clazz.getMethod("parseBase64Binary",
>> String.class);
>> -            } catch (final ClassNotFoundException ex) {
>> -                LOGGER.error("No Base64 Converter is available");
>> -            } catch (final NoSuchMethodException ex) {
>> -
>> -            }
>> -        }
>> -    }
>> -
>> -    public static byte[] parseBase64Binary(final String encoded) {
>> -        if (method == null) {
>> -            LOGGER.error("No base64 converter");
>> -        } else {
>> -            try {
>> -                return (byte[]) method.invoke(decoder, encoded);
>> -            } catch (final IllegalAccessException ex) {
>> -                LOGGER.error("Error decoding string - " +
>> ex.getMessage());
>> -            } catch (final InvocationTargetException ex) {
>> -                LOGGER.error("Error decoding string - " +
>> ex.getMessage());
>> -            }
>> -        }
>> -        return new byte[0];
>> -    }
>> -}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>> similarity index 98%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>> copy to
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>> index dc833f0..00e6da7 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>> +++
>> b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/CoreTypeConverters.java
>> @@ -30,13 +30,14 @@ import java.nio.file.Path;
>> import java.nio.file.Paths;
>> import java.security.Provider;
>> import java.security.Security;
>> +import java.util.Base64;
>> import java.util.UUID;
>> import java.util.regex.Pattern;
>> 
>> import org.apache.logging.log4j.Level;
>> import org.apache.logging.log4j.Logger;
>> import org.apache.logging.log4j.core.appender.rolling.action.Duration;
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> import org.apache.logging.log4j.core.util.CronExpression;
>> import org.apache.logging.log4j.status.StatusLogger;
>> import org.apache.logging.log4j.util.LoaderUtil;
>> @@ -56,6 +57,8 @@ public final class TypeConverters {
>>      */
>>     public static final String CATEGORY = "TypeConverter";
>> 
>> +    private static final Base64.Decoder decoder = Base64.getDecoder();
>> +
>>     /**
>>      * Parses a {@link String} into a {@link BigDecimal}.
>>      */
>> @@ -112,7 +115,7 @@ public final class TypeConverters {
>>                 bytes = new byte[0];
>>             } else if (value.startsWith(PREFIX_BASE64)) {
>>                 final String lexicalXSDBase64Binary =
>> value.substring(PREFIX_BASE64.length());
>> -                bytes =
>> Base64Converter.parseBase64Binary(lexicalXSDBase64Binary);
>> +                bytes = decoder.decode(lexicalXSDBase64Binary);
>>             } else if (value.startsWith(PREFIX_0x)) {
>>                 final String lexicalXSDHexBinary =
>> value.substring(PREFIX_0x.length());
>>                 bytes = HexConverter.parseHexBinary(lexicalXSDHexBinary);
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>> index 8ee5abb..27ac5fe 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>> +++
>> b/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidatingPluginWithGenericBuilderTest.java
>> @@ -20,12 +20,12 @@ import static org.junit.Assert.assertEquals;
>> import static org.junit.Assert.assertNotNull;
>> import static org.junit.Assert.assertNull;
>> 
>> -import org.apache.logging.log4j.core.config.Node;
>> +import org.apache.logging.log4j.plugins.Node;
>> import org.apache.logging.log4j.core.config.NullConfiguration;
>> -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;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.ValidatingPluginWithGenericBuilder;
>> +import org.apache.logging.log4j.plugins.util.PluginBuilder;
>> +import org.apache.logging.log4j.plugins.util.PluginManager;
>> +import org.apache.logging.log4j.plugins.util.PluginType;
>> +import
>> org.apache.logging.log4j.plugins.validation.ValidatingPluginWithGenericBuilder;
>> import org.junit.Before;
>> import org.junit.Test;
>> 
>> diff --git a/log4j-plugins-java9/pom.xml b/log4j-plugins-java9/pom.xml
>> new file mode 100644
>> index 0000000..49f81c6
>> --- /dev/null
>> +++ b/log4j-plugins-java9/pom.xml
>> @@ -0,0 +1,157 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<!--
>> +  ~ 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.
>> +  -->
>> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
>> http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
>> http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
>> ">
>> +  <modelVersion>4.0.0</modelVersion>
>> +  <parent>
>> +    <groupId>org.apache.logging.log4j</groupId>
>> +    <artifactId>log4j</artifactId>
>> +    <version>3.0.0-SNAPSHOT</version>
>> +    <relativePath>../</relativePath>
>> +  </parent>
>> +  <artifactId>log4j-plugins-java9</artifactId>
>> +  <packaging>pom</packaging>
>> +  <name>Apache Log4j Plugins Module support</name>
>> +  <description>Apache Log4j Plugin Moduels Support</description>
>> +  <properties>
>> +    <log4jParentDir>${basedir}/..</log4jParentDir>
>> +    <docLabel>Log4j Plugins Documentation</docLabel>
>> +    <projectDir>/plugins</projectDir>
>> +  </properties>
>> +  <dependencies>
>> +    <dependency>
>> +      <groupId>org.apache.logging.log4j</groupId>
>> +      <artifactId>log4j-api</artifactId>
>> +    </dependency>
>> +    <dependency>
>> +      <groupId>junit</groupId>
>> +      <artifactId>junit</artifactId>
>> +      <scope>test</scope>
>> +    </dependency>
>> +    <dependency>
>> +      <groupId>org.apache.maven</groupId>
>> +      <artifactId>maven-core</artifactId>
>> +      <scope>test</scope>
>> +    </dependency>
>> +  </dependencies>
>> +  <build>
>> +    <plugins>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-toolchains-plugin</artifactId>
>> +        <version>1.1</version>
>> +        <executions>
>> +          <execution>
>> +            <goals>
>> +              <goal>toolchain</goal>
>> +            </goals>
>> +          </execution>
>> +        </executions>
>> +        <configuration>
>> +          <toolchains>
>> +            <jdk>
>> +              <version>[9, )</version>
>> +            </jdk>
>> +          </toolchains>
>> +        </configuration>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-compiler-plugin</artifactId>
>> +        <executions>
>> +          <execution>
>> +            <id>default-compile</id>
>> +            <phase>compile</phase>
>> +            <goals>
>> +              <goal>compile</goal>
>> +            </goals>
>> +          </execution>
>> +          <execution>
>> +            <id>default-test-compile</id>
>> +            <phase>test-compile</phase>
>> +            <goals>
>> +              <goal>testCompile</goal>
>> +            </goals>
>> +          </execution>
>> +        </executions>
>> +        <configuration>
>> +          <source>9</source>
>> +          <target>9</target>
>> +          <release>9</release>
>> +          <proc>none</proc>
>> +          <!-- disable errorprone -->
>> +          <compilerId>javac</compilerId>
>> +        </configuration>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-surefire-plugin</artifactId>
>> +        <!-- Do not upgrade until
>> https://issues.apache.org/jira/browse/SUREFIRE-720 is fixed -->
>> +        <version>2.13</version>
>> +        <executions>
>> +          <execution>
>> +            <id>test</id>
>> +            <phase>test</phase>
>> +            <goals>
>> +              <goal>test</goal>
>> +            </goals>
>> +          </execution>
>> +        </executions>
>> +        <configuration>
>> +          <systemPropertyVariables>
>> +            <java.awt.headless>true</java.awt.headless>
>> +          </systemPropertyVariables>
>> +          <includes>
>> +            <include>**/Test*.java</include>
>> +            <include>**/*Test.java</include>
>> +          </includes>
>> +          <excludes>
>> +            <exclude>**/*FuncTest.java</exclude>
>> +          </excludes>
>> +        </configuration>
>> +      </plugin>
>> +      <plugin>
>> +        <artifactId>maven-assembly-plugin</artifactId>
>> +        <executions>
>> +          <execution>
>> +            <id>zip</id>
>> +            <phase>package</phase>
>> +            <goals>
>> +              <goal>single</goal>
>> +            </goals>
>> +            <configuration>
>> +
>> <finalName>log4j-plugins-java9-${project.version}</finalName>
>> +              <appendAssemblyId>false</appendAssemblyId>
>> +              <descriptors>
>> +                <descriptor>src/assembly/java9.xml</descriptor>
>> +              </descriptors>
>> +            </configuration>
>> +          </execution>
>> +        </executions>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-deploy-plugin</artifactId>
>> +        <version>${deploy.plugin.version}</version>
>> +        <configuration>
>> +          <skip>true</skip>
>> +        </configuration>
>> +      </plugin>
>> +    </plugins>
>> +  </build>
>> +</project>
>> +
>> diff --git a/log4j-plugins-java9/src/assembly/java9.xml
>> b/log4j-plugins-java9/src/assembly/java9.xml
>> new file mode 100644
>> index 0000000..34649d4
>> --- /dev/null
>> +++ b/log4j-plugins-java9/src/assembly/java9.xml
>> @@ -0,0 +1,40 @@
>> +<?xml version='1.0' encoding='UTF-8'?>
>> +<!--
>> +  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.
>> +-->
>> +
>> +<assembly>
>> +  <id>src</id>
>> +  <formats>
>> +    <format>zip</format>
>> +  </formats>
>> +  <baseDirectory>/</baseDirectory>
>> +  <fileSets>
>> +    <fileSet>
>> +      <directory>${project.build.outputDirectory}</directory>
>> +      <outputDirectory>/classes/META-INF/versions/9</outputDirectory>
>> +      <includes>
>> +        <include>module-info.class</include>
>> +      </includes>
>> +      <excludes>
>> +        <exclude>**/Dummy.class</exclude>
>> +        <exclude>**/PluginService.class</exclude>
>> +      </excludes>
>> +    </fileSet>
>> +  </fileSets>
>> +</assembly>
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins-java9/src/main/java/module-info.java
>> similarity index 65%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to log4j-plugins-java9/src/main/java/module-info.java
>> index f22ba49..9802622 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++ b/log4j-plugins-java9/src/main/java/module-info.java
>> @@ -14,10 +14,13 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> +module org.apache.logging.log4j.plugins {
>> +    exports org.apache.logging.log4j.plugins;
>> +    exports org.apache.logging.log4j.plugins.convert;
>> +    exports org.apache.logging.log4j.plugins.processor;
>> +    exports org.apache.logging.log4j.plugins.util;
>> +    exports org.apache.logging.log4j.plugins.validation;
>> +    exports org.apache.logging.log4j.plugins.visitors;
>> 
>> -/**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> - */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +    uses org.apache.logging.log4j.plugins.processor.PluginService;
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>> similarity index 80%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>> index f22ba49..14a90ed 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/Dummy.java
>> @@ -14,10 +14,11 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> +package org.apache.logging.log4j.plugins;
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * This is a dummy class and is only here to allow module-info.java to
>> compile. It will not
>> + * be copied into the log4j-api module.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +public class Dummy {
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>> similarity index 79%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>> index f22ba49..10923e8 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/convert/Dummy.java
>> @@ -14,10 +14,11 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> +package org.apache.logging.log4j.plugins.convert;
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * This is a dummy class and is only here to allow module-info.java to
>> compile. It will not
>> + * be copied into the log4j-api module.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +public class Dummy {
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>> similarity index 79%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>> index f22ba49..b93ef59 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>> @@ -14,10 +14,11 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> +package org.apache.logging.log4j.plugins.processor;
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * This is a dummy class and is only here to allow module-info.java to
>> compile. It will not
>> + * be copied into the log4j-api module.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +public class PluginService {
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>> similarity index 80%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>> index f22ba49..5940b03 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/util/Dummy.java
>> @@ -14,10 +14,11 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> +package org.apache.logging.log4j.plugins.util;
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * This is a dummy class and is only here to allow module-info.java to
>> compile. It will not
>> + * be copied into the log4j-api module.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +public class Dummy {
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>> similarity index 79%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>> index f22ba49..14882b5 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/validation/Dummy.java
>> @@ -14,10 +14,11 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * This is a dummy class and is only here to allow module-info.java to
>> compile. It will not
>> + * be copied into the log4j-api module.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +public class Dummy {
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>> similarity index 79%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>> index f22ba49..5596338 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins-java9/src/main/java/org/apache/logging/log4j/plugins/visitors/Dummy.java
>> @@ -14,10 +14,11 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> +package org.apache.logging.log4j.plugins.visitors;
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * This is a dummy class and is only here to allow module-info.java to
>> compile. It will not
>> + * be copied into the log4j-api module.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +public class Dummy {
>> +}
>> diff --git a/log4j-plugins/pom.xml b/log4j-plugins/pom.xml
>> new file mode 100644
>> index 0000000..3551d51
>> --- /dev/null
>> +++ b/log4j-plugins/pom.xml
>> @@ -0,0 +1,360 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<!--
>> +  ~ 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.
>> +  -->
>> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="
>> http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="
>> http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
>> ">
>> +  <modelVersion>4.0.0</modelVersion>
>> +  <parent>
>> +    <groupId>org.apache.logging.log4j</groupId>
>> +    <artifactId>log4j</artifactId>
>> +    <version>3.0.0-SNAPSHOT</version>
>> +    <relativePath>../</relativePath>
>> +  </parent>
>> +  <artifactId>log4j-plugins</artifactId>
>> +  <packaging>jar</packaging>
>> +  <name>Apache Log4j Plugins</name>
>> +  <description>Log4j Plugin Support</description>
>> +  <properties>
>> +    <log4jParentDir>${basedir}/..</log4jParentDir>
>> +    <docLabel>Plugin Documentation</docLabel>
>> +    <projectDir>/plugins</projectDir>
>> +  </properties>
>> +  <dependencies>
>> +    <dependency>
>> +      <groupId>org.apache.logging.log4j</groupId>
>> +      <artifactId>log4j-api</artifactId>
>> +    </dependency>
>> +    <!-- Classes and resources to be shaded into the core jar -->
>> +    <dependency>
>> +      <groupId>org.apache.logging.log4j</groupId>
>> +      <artifactId>log4j-plugins-java9</artifactId>
>> +      <scope>provided</scope>
>> +      <type>zip</type>
>> +    </dependency>
>> +    <!-- Used for OSGi bundle support -->
>> +    <dependency>
>> +      <groupId>org.osgi</groupId>
>> +      <artifactId>org.osgi.core</artifactId>
>> +      <scope>provided</scope>
>> +    </dependency>
>> +
>> +    <!-- TEST DEPENDENCIES -->
>> +
>> +    <!-- Pull in useful test classes from API -->
>> +    <dependency>
>> +      <groupId>org.apache.logging.log4j</groupId>
>> +      <artifactId>log4j-api</artifactId>
>> +      <type>test-jar</type>
>> +      <scope>test</scope>
>> +    </dependency>
>> +    <dependency>
>> +      <groupId>junit</groupId>
>> +      <artifactId>junit</artifactId>
>> +      <scope>test</scope>
>> +    </dependency>
>> +    <dependency>
>> +      <groupId>org.hamcrest</groupId>
>> +      <artifactId>hamcrest-all</artifactId>
>> +      <scope>test</scope>
>> +    </dependency>
>> +  </dependencies>
>> +  <build>
>> +    <plugins>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-dependency-plugin</artifactId>
>> +        <version>3.0.2</version>
>> +        <executions>
>> +          <execution>
>> +            <id>unpack-classes</id>
>> +            <phase>prepare-package</phase>
>> +            <goals>
>> +              <goal>unpack</goal>
>> +            </goals>
>> +            <configuration>
>> +              <artifactItems>
>> +                <artifactItem>
>> +                  <groupId>org.apache.logging.log4j</groupId>
>> +                  <artifactId>log4j-plugins-java9</artifactId>
>> +                  <version>${project.version}</version>
>> +                  <type>zip</type>
>> +                  <overWrite>false</overWrite>
>> +                </artifactItem>
>> +              </artifactItems>
>> +              <includes>**/*.class</includes>
>> +              <excludes>**/*.java</excludes>
>> +
>> <outputDirectory>${project.build.directory}</outputDirectory>
>> +              <overWriteReleases>false</overWriteReleases>
>> +              <overWriteSnapshots>true</overWriteSnapshots>
>> +            </configuration>
>> +          </execution>
>> +        </executions>
>> +      </plugin>
>> +      <plugin>
>> +        <artifactId>maven-compiler-plugin</artifactId>
>> +        <executions>
>> +          <execution>
>> +            <!-- disable annotation processing for first pass -->
>> +            <id>generate-plugins</id>
>> +            <phase>process-classes</phase>
>> +            <goals>
>> +              <goal>compile</goal>
>> +            </goals>
>> +            <configuration>
>> +              <excludes>
>> +                <exclude>module-info.java</exclude>
>> +              </excludes>
>> +            </configuration>
>> +          </execution>
>> +          <execution>
>> +            <!-- disable annotation processing for first pass -->
>> +            <id>generate-test-plugins</id>
>> +            <phase>generate-test-sources</phase>
>> +            <goals>
>> +              <goal>compile</goal>
>> +            </goals>
>> +            <configuration>
>> +              <excludes>
>> +                <exclude>module-info.java</exclude>
>> +              </excludes>
>> +              <proc>only</proc>
>> +            </configuration>
>> +          </execution>
>> +          <execution>
>> +            <!-- disable annotation processing for first pass -->
>> +            <id>default-compile</id>
>> +            <configuration>
>> +              <excludes>
>> +                <exclude>module-info.java</exclude>
>> +              </excludes>
>> +              <proc>none</proc>
>> +            </configuration>
>> +          </execution>
>> +        </executions>
>> +      </plugin>
>> +      <plugin>
>> +        <artifactId>maven-surefire-plugin</artifactId>
>> +        <configuration>
>> +          <excludedGroups>
>> +            org.apache.logging.log4j.categories.PerformanceTests
>> +          </excludedGroups>
>> +          <systemPropertyVariables>
>> +
>> <org.apache.activemq.SERIALIZABLE_PACKAGES>*</org.apache.activemq.SERIALIZABLE_PACKAGES>
>> +          </systemPropertyVariables>
>> +        </configuration>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-failsafe-plugin</artifactId>
>> +        <configuration>
>> +          <skipTests>true</skipTests>
>> +        </configuration>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-jar-plugin</artifactId>
>> +        <executions>
>> +          <execution>
>> +            <id>default-jar</id>
>> +            <goals>
>> +              <goal>jar</goal>
>> +            </goals>
>> +            <configuration combine.self="override">
>> +              <archive>
>> +                <manifestFile>${manifestfile}</manifestFile>
>> +                <manifestEntries>
>> +                  <Specification-Title>${project.name
>> }</Specification-Title>
>> +
>> <Specification-Version>${project.version}</Specification-Version>
>> +                  <Specification-Vendor>${project.organization.name
>> }</Specification-Vendor>
>> +                  <Implementation-Title>${project.name
>> }</Implementation-Title>
>> +
>> <Implementation-Version>${project.version}</Implementation-Version>
>> +                  <Implementation-Vendor>${project.organization.name
>> }</Implementation-Vendor>
>> +
>> <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
>> +
>> <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
>> +
>> <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
>> +
>> <Automatic-Module-Name>org.apache.logging.log4j.plugins</Automatic-Module-Name>
>> +                  <Multi-Release>true</Multi-Release>
>> +                </manifestEntries>
>> +              </archive>
>> +            </configuration>
>> +          </execution>
>> +          <execution>
>> +            <id>default</id>
>> +            <goals>
>> +              <goal>test-jar</goal>
>> +            </goals>
>> +            <configuration>
>> +              <archive>
>> +                <manifestFile>${manifestfile}</manifestFile>
>> +                <manifestEntries>
>> +                  <Specification-Title>${project.name
>> }</Specification-Title>
>> +
>> <Specification-Version>${project.version}</Specification-Version>
>> +                  <Specification-Vendor>${project.organization.name
>> }</Specification-Vendor>
>> +                  <Implementation-Title>${project.name
>> }</Implementation-Title>
>> +
>> <Implementation-Version>${project.version}</Implementation-Version>
>> +                  <Implementation-Vendor>${project.organization.name
>> }</Implementation-Vendor>
>> +
>> <Implementation-Vendor-Id>org.apache</Implementation-Vendor-Id>
>> +
>> <X-Compile-Source-JDK>${maven.compiler.source}</X-Compile-Source-JDK>
>> +
>> <X-Compile-Target-JDK>${maven.compiler.target}</X-Compile-Target-JDK>
>> +                </manifestEntries>
>> +              </archive>
>> +            </configuration>
>> +          </execution>
>> +        </executions>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.felix</groupId>
>> +        <artifactId>maven-bundle-plugin</artifactId>
>> +        <configuration>
>> +          <instructions>
>> +
>> <Bundle-SymbolicName>org.apache.logging.log4j.plugins</Bundle-SymbolicName>
>> +            <!-- TODO: exclude internal classes from export -->
>> +
>> <Export-Package>org.apache.logging.log4j.plugins.*</Export-Package>
>> +            <Import-Package>
>> +              sun.reflect;resolution:=optional,
>> +              org.apache.logging.log4j.util,
>> +              *
>> +            </Import-Package>
>> +
>> <Bundle-Activator>org.apache.logging.log4j.plugins.osgi.Activator</Bundle-Activator>
>> +          </instructions>
>> +        </configuration>
>> +      </plugin>
>> +    </plugins>
>> +  </build>
>> +  <reporting>
>> +    <plugins>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-changes-plugin</artifactId>
>> +        <version>${changes.plugin.version}</version>
>> +        <reportSets>
>> +          <reportSet>
>> +            <reports>
>> +              <report>changes-report</report>
>> +            </reports>
>> +          </reportSet>
>> +        </reportSets>
>> +        <configuration>
>> +
>> <issueLinkTemplate>%URL%/show_bug.cgi?id=%ISSUE%</issueLinkTemplate>
>> +          <useJql>true</useJql>
>> +        </configuration>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-checkstyle-plugin</artifactId>
>> +        <version>${checkstyle.plugin.version}</version>
>> +        <configuration>
>> +
>> <!--<propertiesLocation>${vfs.parent.dir}/checkstyle.properties</propertiesLocation>
>> -->
>> +
>> <configLocation>${log4jParentDir}/checkstyle.xml</configLocation>
>> +
>> <suppressionsLocation>${log4jParentDir}/checkstyle-suppressions.xml</suppressionsLocation>
>> +          <enableRulesSummary>false</enableRulesSummary>
>> +          <propertyExpansion>basedir=${basedir}</propertyExpansion>
>> +
>> <propertyExpansion>licensedir=${log4jParentDir}/checkstyle-header.txt</propertyExpansion>
>> +        </configuration>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-javadoc-plugin</artifactId>
>> +        <version>${javadoc.plugin.version}</version>
>> +        <configuration>
>> +          <failOnError>false</failOnError>
>> +          <bottom><![CDATA[<p align="center">Copyright &#169;
>> {inceptionYear}-{currentYear} {organizationName}. All Rights Reserved.<br />
>> +            Apache Logging, Apache Log4j, Log4j, Apache, the Apache
>> feather logo, the Apache Logging project logo,
>> +            and the Apache Log4j logo are trademarks of The Apache
>> Software Foundation.</p>]]></bottom>
>> +          <!-- module link generation is completely broken in the javadoc
>> plugin for a multi-module non-aggregating
>> +               project -->
>> +          <additionalparam>${javadoc.opts}</additionalparam>
>> +          <detectOfflineLinks>false</detectOfflineLinks>
>> +          <linksource>true</linksource>
>> +          <links>
>> +            <link>http://docs.oracle.com/javaee/6/api/</link>
>> +            <link>http://www.osgi.org/javadoc/r4v43/core/</link>
>> +            <link>
>> https://commons.apache.org/proper/commons-lang/javadocs/api-release/
>> </link>
>> +          </links>
>> +          <groups>
>> +            <group>
>> +              <title>Core API</title>
>> +              <packages>org.apache.logging.log4j.core</packages>
>> +            </group>
>> +            <group>
>> +              <title>Configuration</title>
>> +
>> <packages>org.apache.logging.log4j.core.config*:org.apache.logging.log4j.core.selector</packages>
>> +            </group>
>> +            <group>
>> +              <title>Core Plugins</title>
>> +
>> <packages>org.apache.logging.log4j.core.appender*:org.apache.logging.log4j.core.filter:org.apache.logging.log4j.core.layout:org.apache.logging.log4j.core.lookup:org.apache.logging.log4j.core.pattern:org.apache.logging.log4j.core.script</packages>
>> +            </group>
>> +            <group>
>> +              <title>Tools</title>
>> +              <packages>org.apache.logging.log4j.core.net
>> *:org.apache.logging.log4j.core.tools</packages>
>> +            </group>
>> +            <group>
>> +              <title>Internals</title>
>> +
>> <packages>org.apache.logging.log4j.core.async:org.apache.logging.log4j.core.impl:org.apache.logging.log4j.core.util*:org.apache.logging.log4j.core.osgi:org.apache.logging.log4j.core.jackson:org.apache.logging.log4j.core.jmx</packages>
>> +            </group>
>> +          </groups>
>> +        </configuration>
>> +        <reportSets>
>> +          <reportSet>
>> +            <id>non-aggregate</id>
>> +            <reports>
>> +              <report>javadoc</report>
>> +            </reports>
>> +          </reportSet>
>> +        </reportSets>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>com.github.spotbugs</groupId>
>> +        <artifactId>spotbugs-maven-plugin</artifactId>
>> +        <configuration>
>> +          <fork>true</fork>
>> +          <jvmArgs>-Duser.language=en</jvmArgs>
>> +          <threshold>Normal</threshold>
>> +          <effort>Default</effort>
>> +
>> <excludeFilterFile>${log4jParentDir}/spotbugs-exclude-filter.xml</excludeFilterFile>
>> +        </configuration>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-jxr-plugin</artifactId>
>> +        <version>${jxr.plugin.version}</version>
>> +        <reportSets>
>> +          <reportSet>
>> +            <id>non-aggregate</id>
>> +            <reports>
>> +              <report>jxr</report>
>> +            </reports>
>> +          </reportSet>
>> +          <reportSet>
>> +            <id>aggregate</id>
>> +            <reports>
>> +              <report>aggregate</report>
>> +            </reports>
>> +          </reportSet>
>> +        </reportSets>
>> +      </plugin>
>> +      <plugin>
>> +        <groupId>org.apache.maven.plugins</groupId>
>> +        <artifactId>maven-pmd-plugin</artifactId>
>> +        <version>${pmd.plugin.version}</version>
>> +        <configuration>
>> +          <targetJdk>${maven.compiler.target}</targetJdk>
>> +        </configuration>
>> +      </plugin>
>> +    </plugins>
>> +  </reporting>
>> +</project>
>> +
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>> similarity index 97%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>> index c92c904..22fd9bf 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Node.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Node.java
>> @@ -14,15 +14,15 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config;
>> +package org.apache.logging.log4j.plugins;
>> +
>> +import org.apache.logging.log4j.plugins.util.PluginType;
>> 
>> import java.util.ArrayList;
>> import java.util.HashMap;
>> import java.util.List;
>> import java.util.Map;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>> -
>> /**
>>  * A Configuration node.
>>  */
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>> similarity index 97%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>> index 8aaf117..348754f 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/Plugin.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/Plugin.java
>> @@ -14,7 +14,9 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> +
>> +import org.apache.logging.log4j.util.Strings;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>> import java.lang.annotation.RetentionPolicy;
>> import java.lang.annotation.Target;
>> 
>> -import org.apache.logging.log4j.util.Strings;
>> -
>> /**
>>  * Annotation that identifies a Class as a Plugin.
>>  */
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>> similarity index 87%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>> index 7be3dea..4dce103 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAliases.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAliases.java
>> @@ -14,7 +14,7 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> @@ -23,7 +23,7 @@ import java.lang.annotation.RetentionPolicy;
>> import java.lang.annotation.Target;
>> 
>> /**
>> - * Identifies a list of aliases for a {@link Plugin}, {@link
>> PluginAttribute}, or {@link PluginBuilderAttribute}.
>> + * Identifies a list of aliases for a Plugin, PluginAttribute, or
>> PluginBuilderAttribute.
>>  */
>> @Documented
>> @Retention(RetentionPolicy.RUNTIME)
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>> similarity index 96%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>> index bd88220..b9d4684 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginAttribute.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginAttribute.java
>> @@ -14,7 +14,10 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> +
>> +import org.apache.logging.log4j.plugins.visitors.PluginAttributeVisitor;
>> +import org.apache.logging.log4j.util.Strings;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> @@ -22,9 +25,6 @@ import java.lang.annotation.Retention;
>> import java.lang.annotation.RetentionPolicy;
>> import java.lang.annotation.Target;
>> 
>> -import
>> org.apache.logging.log4j.core.config.plugins.visitors.PluginAttributeVisitor;
>> -import org.apache.logging.log4j.util.Strings;
>> -
>> /**
>>  * Identifies a Plugin Attribute and its default value. Note that only
>> one of the defaultFoo attributes will be
>>  * used based on the type this annotation is attached to. Thus, for
>> primitive types, the default<i>Type</i>
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>> similarity index 92%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>> index 675d78f..c7fce2f 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderAttribute.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderAttribute.java
>> @@ -15,7 +15,10 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> +
>> +import
>> org.apache.logging.log4j.plugins.visitors.PluginBuilderAttributeVisitor;
>> +import org.apache.logging.log4j.util.Strings;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> @@ -23,9 +26,6 @@ import java.lang.annotation.Retention;
>> import java.lang.annotation.RetentionPolicy;
>> import java.lang.annotation.Target;
>> 
>> -import
>> org.apache.logging.log4j.core.config.plugins.visitors.PluginBuilderAttributeVisitor;
>> -import org.apache.logging.log4j.util.Strings;
>> -
>> /**
>>  * Marks a field as a Plugin Attribute.
>>  */
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>> similarity index 95%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>> index 4e69262..035b025 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginBuilderFactory.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginBuilderFactory.java
>> @@ -15,7 +15,7 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>> similarity index 91%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>> index 7ea358b..6cfb6fa 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginElement.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginElement.java
>> @@ -14,7 +14,9 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> +
>> +import org.apache.logging.log4j.plugins.visitors.PluginElementVisitor;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>> import java.lang.annotation.RetentionPolicy;
>> import java.lang.annotation.Target;
>> 
>> -import
>> org.apache.logging.log4j.core.config.plugins.visitors.PluginElementVisitor;
>> -
>> /**
>>  * Identifies a parameter as a Plugin and corresponds with an XML element
>> (or equivalent) in configuration files.
>>  */
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>> similarity index 96%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>> index 1c04106..b071510 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginFactory.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginFactory.java
>> @@ -14,7 +14,7 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>> similarity index 90%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>> index d60f1b5..b172268 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginNode.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginNode.java
>> @@ -14,7 +14,9 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> +
>> +import org.apache.logging.log4j.plugins.visitors.PluginNodeVisitor;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>> import java.lang.annotation.RetentionPolicy;
>> import java.lang.annotation.Target;
>> 
>> -import
>> org.apache.logging.log4j.core.config.plugins.visitors.PluginNodeVisitor;
>> -
>> /**
>>  * Identifies a Plugin configuration Node.
>>  */
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>> similarity index 91%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>> index 9c20cc2..31e5a23 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginValue.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginValue.java
>> @@ -14,7 +14,9 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> +
>> +import org.apache.logging.log4j.plugins.visitors.PluginValueVisitor;
>> 
>> import java.lang.annotation.Documented;
>> import java.lang.annotation.ElementType;
>> @@ -22,8 +24,6 @@ import java.lang.annotation.Retention;
>> import java.lang.annotation.RetentionPolicy;
>> import java.lang.annotation.Target;
>> 
>> -import
>> org.apache.logging.log4j.core.config.plugins.visitors.PluginValueVisitor;
>> -
>> /**
>>  * Identifies a parameter as a value. These correspond with property
>> values generally, but are meant as values to be
>>  * used as a placeholder value somewhere.
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>> similarity index 89%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>> index 65fcb76..093cc50 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/PluginVisitorStrategy.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/PluginVisitorStrategy.java
>> @@ -15,7 +15,9 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins;
>> +package org.apache.logging.log4j.plugins;
>> +
>> +import org.apache.logging.log4j.plugins.visitors.PluginVisitor;
>> 
>> import java.lang.annotation.Annotation;
>> import java.lang.annotation.Documented;
>> @@ -24,8 +26,6 @@ import java.lang.annotation.Retention;
>> import java.lang.annotation.RetentionPolicy;
>> import java.lang.annotation.Target;
>> 
>> -import
>> org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor;
>> -
>> /**
>>  * Meta-annotation to denote the class name to use that implements
>>  * {@link
>> org.apache.logging.log4j.core.config.plugins.visitors.PluginVisitor} for
>> the annotated annotation.
>> @@ -40,5 +40,5 @@ public @interface PluginVisitorStrategy {
>>      * for the given annotation. The generic type in {@code
>> PluginVisitor} should match the annotation this annotation
>>      * is applied to.
>>      */
>> -    Class<? extends PluginVisitor<? extends Annotation>> value();
>> +    Class<? extends PluginVisitor<? extends Annotation, ?>> value();
>> }
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>> similarity index 95%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>> copy to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>> index 15a162c..fd8012a 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/EnumConverter.java
>> @@ -14,7 +14,7 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.convert;
>> +package org.apache.logging.log4j.plugins.convert;
>> 
>> import org.apache.logging.log4j.util.EnglishEnums;
>> 
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>> similarity index 95%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>> index e629657..f9037b3 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/HexConverter.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/HexConverter.java
>> @@ -14,7 +14,7 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.convert;
>> +package org.apache.logging.log4j.plugins.convert;
>> 
>> /**
>>  * Converts Strings to hex. This is used in place of
>> java.xml.bind.DataTypeConverter which is not available by
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>> similarity index 95%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>> index e67e213..aaa5b4d 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverter.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverter.java
>> @@ -15,7 +15,7 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.convert;
>> +package org.apache.logging.log4j.plugins.convert;
>> 
>> /**
>>  * Interface for doing automatic String conversion to a specific type.
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>> similarity index 92%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>> index 5088f15..fb5b27e 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistry.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistry.java
>> @@ -14,7 +14,14 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.convert;
>> +package org.apache.logging.log4j.plugins.convert;
>> +
>> +import org.apache.logging.log4j.Logger;
>> +import org.apache.logging.log4j.plugins.util.PluginManager;
>> +import org.apache.logging.log4j.plugins.util.PluginType;
>> +import org.apache.logging.log4j.plugins.util.TypeUtil;
>> +import org.apache.logging.log4j.util.ReflectionUtil;
>> +import org.apache.logging.log4j.status.StatusLogger;
>> 
>> import java.lang.reflect.ParameterizedType;
>> import java.lang.reflect.Type;
>> @@ -25,13 +32,6 @@ import java.util.UnknownFormatConversionException;
>> import java.util.concurrent.ConcurrentHashMap;
>> import java.util.concurrent.ConcurrentMap;
>> 
>> -import org.apache.logging.log4j.Logger;
>> -import org.apache.logging.log4j.core.config.plugins.util.PluginManager;
>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>> -import org.apache.logging.log4j.core.util.ReflectionUtil;
>> -import org.apache.logging.log4j.core.util.TypeUtil;
>> -import org.apache.logging.log4j.status.StatusLogger;
>> -
>> /**
>>  * Registry for {@link TypeConverter} plugins.
>>  *
>> @@ -152,7 +152,12 @@ public class TypeConverterRegistry {
>>     }
>> 
>>     private void registerTypeAlias(final Type knownType, final Type
>> aliasType) {
>> -        registry.putIfAbsent(aliasType, registry.get(knownType));
>> +        TypeConverter<?> converter = registry.get(knownType);
>> +        if (converter != null) {
>> +            registry.putIfAbsent(aliasType, converter);
>> +        } else {
>> +            LOGGER.error("Cannot locate converter for {}", knownType);
>> +        }
>>     }
>> 
>> }
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>> similarity index 92%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>> index dc833f0..7a71b4a 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverters.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/TypeConverters.java
>> @@ -15,32 +15,27 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.convert;
>> +package org.apache.logging.log4j.plugins.convert;
>> +
>> +import org.apache.logging.log4j.Level;
>> +import org.apache.logging.log4j.Logger;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> +import org.apache.logging.log4j.status.StatusLogger;
>> +import org.apache.logging.log4j.util.LoaderUtil;
>> 
>> import java.io.File;
>> import java.math.BigDecimal;
>> import java.math.BigInteger;
>> -import java.net.InetAddress;
>> -import java.net.MalformedURLException;
>> -import java.net.URI;
>> -import java.net.URISyntaxException;
>> -import java.net.URL;
>> +import java.net.*;
>> import java.nio.charset.Charset;
>> import java.nio.file.Path;
>> import java.nio.file.Paths;
>> import java.security.Provider;
>> import java.security.Security;
>> +import java.util.Base64;
>> import java.util.UUID;
>> import java.util.regex.Pattern;
>> 
>> -import org.apache.logging.log4j.Level;
>> -import org.apache.logging.log4j.Logger;
>> -import org.apache.logging.log4j.core.appender.rolling.action.Duration;
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import org.apache.logging.log4j.core.util.CronExpression;
>> -import org.apache.logging.log4j.status.StatusLogger;
>> -import org.apache.logging.log4j.util.LoaderUtil;
>> -
>> /**
>>  * Collection of basic TypeConverter implementations. May be used to
>> register additional TypeConverters or find
>>  * registered TypeConverters.
>> @@ -56,6 +51,8 @@ public final class TypeConverters {
>>      */
>>     public static final String CATEGORY = "TypeConverter";
>> 
>> +    private static final Base64.Decoder decoder = Base64.getDecoder();
>> +
>>     /**
>>      * Parses a {@link String} into a {@link BigDecimal}.
>>      */
>> @@ -112,7 +109,7 @@ public final class TypeConverters {
>>                 bytes = new byte[0];
>>             } else if (value.startsWith(PREFIX_BASE64)) {
>>                 final String lexicalXSDBase64Binary =
>> value.substring(PREFIX_BASE64.length());
>> -                bytes =
>> Base64Converter.parseBase64Binary(lexicalXSDBase64Binary);
>> +                bytes = decoder.decode(lexicalXSDBase64Binary);
>>             } else if (value.startsWith(PREFIX_0x)) {
>>                 final String lexicalXSDHexBinary =
>> value.substring(PREFIX_0x.length());
>>                 bytes = HexConverter.parseHexBinary(lexicalXSDHexBinary);
>> @@ -203,14 +200,6 @@ public final class TypeConverters {
>>         }
>>     }
>> 
>> -    @Plugin(name = "CronExpression", category = CATEGORY)
>> -    public static class CronExpressionConverter implements
>> TypeConverter<CronExpression> {
>> -        @Override
>> -        public CronExpression convert(final String s) throws Exception {
>> -            return new CronExpression(s);
>> -        }
>> -    }
>> -
>>     /**
>>      * Converts a {@link String} into a {@link Double}.
>>      */
>> @@ -223,18 +212,6 @@ public final class TypeConverters {
>>     }
>> 
>>     /**
>> -     * Converts a {@link String} into a {@link Duration}.
>> -     * @since 2.5
>> -     */
>> -    @Plugin(name = "Duration", category = CATEGORY)
>> -    public static class DurationConverter implements
>> TypeConverter<Duration> {
>> -        @Override
>> -        public Duration convert(final String s) {
>> -            return Duration.parse(s);
>> -        }
>> -    }
>> -
>> -    /**
>>      * Converts a {@link String} into a {@link File}.
>>      */
>>     @Plugin(name = "File", category = CATEGORY)
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>> similarity index 80%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>> index f22ba49..958beb4 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/convert/package-info.java
>> @@ -16,8 +16,7 @@
>>  */
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * TypeConverter plugins for converter strings into various types. These
>> plugins are used for parsing plugin
>> + * attributes in plugin factory methods.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +package org.apache.logging.log4j.plugins.convert;
>> diff --git
>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>> new file mode 100644
>> index 0000000..518bee7
>> --- /dev/null
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/Activator.java
>> @@ -0,0 +1,103 @@
>> +/*
>> + * 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.plugins.osgi;
>> +
>> +import org.apache.logging.log4j.LogManager;
>> +import org.apache.logging.log4j.Logger;
>> +import org.apache.logging.log4j.plugins.processor.PluginService;
>> +import org.apache.logging.log4j.plugins.util.PluginRegistry;
>> +import org.apache.logging.log4j.spi.Provider;
>> +import org.apache.logging.log4j.status.StatusLogger;
>> +import org.apache.logging.log4j.util.PropertiesUtil;
>> +import org.osgi.framework.*;
>> +import org.osgi.framework.wiring.BundleWiring;
>> +
>> +import java.util.Hashtable;
>> +import java.util.concurrent.atomic.AtomicReference;
>> +
>> +/**
>> + * OSGi BundleActivator.
>> + */
>> +public final class Activator implements BundleActivator,
>> SynchronousBundleListener {
>> +
>> +    private static final Logger LOGGER = StatusLogger.getLogger();
>> +
>> +    private final AtomicReference<BundleContext> contextRef = new
>> AtomicReference<>();
>> +
>> +    ServiceRegistration provideRegistration = null;
>> +
>> +    @Override
>> +    public void start(final BundleContext context) throws Exception {
>> +        final PluginService pluginService = new Log4jProvider();
>> +        final Hashtable<String, String> props = new Hashtable<>();
>> +        props.put("APIVersion", "3.0");
>> +        provideRegistration =
>> context.registerService(pluginService.class.getName(), provider, props);
>> +        if (this.contextRef.compareAndSet(null, context)) {
>> +            context.addBundleListener(this);
>> +            // done after the BundleListener as to not miss any new
>> bundle installs in the interim
>> +            scanInstalledBundlesForPlugins(context);
>> +        }
>> +    }
>> +
>> +    private static void scanInstalledBundlesForPlugins(final
>> BundleContext context) {
>> +        final Bundle[] bundles = context.getBundles();
>> +        for (final Bundle bundle : bundles) {
>> +            // TODO: bundle state can change during this
>> +            scanBundleForPlugins(bundle);
>> +        }
>> +    }
>> +
>> +    private static void scanBundleForPlugins(final Bundle bundle) {
>> +        final long bundleId = bundle.getBundleId();
>> +        // LOG4J2-920: don't scan system bundle for plugins
>> +        if (bundle.getState() == Bundle.ACTIVE && bundleId != 0) {
>> +            LOGGER.trace("Scanning bundle [{}, id=%d] for plugins.",
>> bundle.getSymbolicName(), bundleId);
>> +            PluginRegistry.getInstance().loadFromBundle(bundleId,
>> +                    bundle.adapt(BundleWiring.class).getClassLoader());
>> +        }
>> +    }
>> +
>> +    private static void stopBundlePlugins(final Bundle bundle) {
>> +        LOGGER.trace("Stopping bundle [{}] plugins.",
>> bundle.getSymbolicName());
>> +        // TODO: plugin lifecycle code
>> +
>> PluginRegistry.getInstance().clearBundlePlugins(bundle.getBundleId());
>> +    }
>> +
>> +    @Override
>> +    public void stop(final BundleContext context) throws Exception {
>> +        provideRegistration.unregister();
>> +        this.contextRef.compareAndSet(context, null);
>> +    }
>> +
>> +    @Override
>> +    public void bundleChanged(final BundleEvent event) {
>> +        switch (event.getType()) {
>> +            // FIXME: STARTING instead of STARTED?
>> +            case BundleEvent.STARTED:
>> +                scanBundleForPlugins(event.getBundle());
>> +                break;
>> +
>> +            case BundleEvent.STOPPING:
>> +                stopBundlePlugins(event.getBundle());
>> +                break;
>> +
>> +            default:
>> +                break;
>> +        }
>> +    }
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>> similarity index 87%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>> index f22ba49..37dadd4 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/osgi/package-info.java
>> @@ -16,8 +16,6 @@
>>  */
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * Collection of OSGi-specific classes for bundles.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +package org.apache.logging.log4j.plugins.osgi;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>> similarity index 87%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>> index f22ba49..b161185 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/package-info.java
>> @@ -16,8 +16,6 @@
>>  */
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * Annotations for Log4j 2 plugins.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +package org.apache.logging.log4j.plugins;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>> similarity index 71%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>> index 2fd4160..784dece 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginCache.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginCache.java
>> @@ -15,7 +15,7 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.processor;
>> +package org.apache.logging.log4j.plugins.processor;
>> 
>> import java.io.BufferedInputStream;
>> import java.io.BufferedOutputStream;
>> @@ -60,34 +60,6 @@ public class PluginCache {
>>     }
>> 
>>     /**
>> -     * Stores the plugin cache to a given OutputStream.
>> -     *
>> -     * @param os destination to save cache to.
>> -     * @throws IOException if an I/O exception occurs.
>> -     */
>> -    // NOTE: if this file format is to be changed, the filename should
>> change and this format should still be readable
>> -    public void writeCache(final OutputStream os) throws IOException {
>> -        try (final DataOutputStream out = new DataOutputStream(new
>> BufferedOutputStream(os))) {
>> -            // See PluginManager.readFromCacheFiles for the corresponding
>> decoder. Format may not be changed
>> -            // without breaking existing Log4j2Plugins.dat files.
>> -            out.writeInt(categories.size());
>> -            for (final Map.Entry<String, Map<String, PluginEntry>>
>> category : categories.entrySet()) {
>> -                out.writeUTF(category.getKey());
>> -                final Map<String, PluginEntry> m = category.getValue();
>> -                out.writeInt(m.size());
>> -                for (final Map.Entry<String, PluginEntry> entry :
>> m.entrySet()) {
>> -                    final PluginEntry plugin = entry.getValue();
>> -                    out.writeUTF(plugin.getKey());
>> -                    out.writeUTF(plugin.getClassName());
>> -                    out.writeUTF(plugin.getName());
>> -                    out.writeBoolean(plugin.isPrintable());
>> -                    out.writeBoolean(plugin.isDefer());
>> -                }
>> -            }
>> -        }
>> -    }
>> -
>> -    /**
>>      * Loads and merges all the Log4j plugin cache files specified.
>> Usually, this is obtained via a ClassLoader.
>>      *
>>      * @param resources URLs to all the desired plugin cache files to
>> load.
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>> similarity index 85%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>> index dd43601..bd452d3 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginEntry.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginEntry.java
>> @@ -15,7 +15,7 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.processor;
>> +package org.apache.logging.log4j.plugins.processor;
>> 
>> import java.io.Serializable;
>> 
>> @@ -32,6 +32,18 @@ public class PluginEntry implements Serializable {
>>     private boolean defer;
>>     private transient String category;
>> 
>> +    public PluginEntry() {
>> +    }
>> +
>> +    public PluginEntry(String key, String className, String name, boolean
>> printable, boolean defer, String category) {
>> +        this.key = key;
>> +        this.className = className;
>> +        this.name = name;
>> +        this.printable = printable;
>> +        this.defer = defer;
>> +        this.category = category;
>> +    }
>> +
>>     public String getKey() {
>>         return key;
>>     }
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>> similarity index 54%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>> index 2f3b53f..975d2ab 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessor.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginProcessor.java
>> @@ -15,38 +15,47 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.processor;
>> +package org.apache.logging.log4j.plugins.processor;
>> +
>> +import org.apache.logging.log4j.LoggingException;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> +import org.apache.logging.log4j.plugins.PluginAliases;
>> +import org.apache.logging.log4j.util.Strings;
>> 
>> -import java.io.IOException;
>> -import java.io.OutputStream;
>> -import java.util.ArrayList;
>> -import java.util.Collection;
>> -import java.util.Collections;
>> -import java.util.Locale;
>> -import java.util.Map;
>> -import java.util.Objects;
>> -import java.util.Set;
>> import javax.annotation.processing.AbstractProcessor;
>> +import javax.annotation.processing.Messager;
>> import javax.annotation.processing.RoundEnvironment;
>> import javax.annotation.processing.SupportedAnnotationTypes;
>> import javax.lang.model.SourceVersion;
>> import javax.lang.model.element.Element;
>> import javax.lang.model.element.ElementVisitor;
>> +import javax.lang.model.element.Name;
>> import javax.lang.model.element.TypeElement;
>> import javax.lang.model.util.Elements;
>> import javax.lang.model.util.SimpleElementVisitor7;
>> import javax.tools.Diagnostic.Kind;
>> import javax.tools.FileObject;
>> +import javax.tools.JavaFileObject;
>> import javax.tools.StandardLocation;
>> +import java.io.BufferedWriter;
>> +import java.io.IOException;
>> +import java.io.OutputStreamWriter;
>> +import java.io.PrintWriter;
>> +import java.util.ArrayList;
>> +import java.util.Collection;
>> +import java.util.Collections;
>> +import java.util.List;
>> +import java.util.Locale;
>> +import java.util.Map;
>> +import java.util.Objects;
>> +import java.util.Set;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>> -import org.apache.logging.log4j.util.Strings;
>> +import static java.nio.charset.StandardCharsets.UTF_8;
>> 
>> /**
>>  * Annotation processor for pre-scanning Log4j 2 plugins.
>>  */
>> 
>> -@SupportedAnnotationTypes("org.apache.logging.log4j.core.config.plugins.*")
>> +@SupportedAnnotationTypes({"org.apache.logging.log4j.plugins.*",
>> "org.apache.logging.log4j.core.config.plugins.*"})
>> public class PluginProcessor extends AbstractProcessor {
>> 
>>     // TODO: this could be made more abstract to allow for compile-time
>> and run-time plugin processing
>> @@ -57,8 +66,8 @@ public class PluginProcessor extends AbstractProcessor {
>>      */
>>     public static final String PLUGIN_CACHE_FILE =
>> 
>> "META-INF/org/apache/logging/log4j/core/config/plugins/Log4j2Plugins.dat";
>> -
>> -    private final PluginCache pluginCache = new PluginCache();
>> +    private static final String SERVICE_FILE_NAME =
>> +
>> "META-INF/services/org.apache.logging.log4j.plugins.processor.PluginService";
>> 
>>     @Override
>>     public SourceVersion getSupportedSourceVersion() {
>> @@ -67,16 +76,21 @@ public class PluginProcessor extends AbstractProcessor
>> {
>> 
>>     @Override
>>     public boolean process(final Set<? extends TypeElement> annotations,
>> final RoundEnvironment roundEnv) {
>> -        System.out.println("Processing annotations");
>> +        Map<String, String> options = processingEnv.getOptions();
>> +        String packageName = options.get("pluginPackage");
>> +        Messager messager = processingEnv.getMessager();
>> +        messager.printMessage(Kind.NOTE, "Processing Log4j annotations");
>>         try {
>>             final Set<? extends Element> elements =
>> roundEnv.getElementsAnnotatedWith(Plugin.class);
>>             if (elements.isEmpty()) {
>> -                System.out.println("No elements to process");
>> +                messager.printMessage(Kind.NOTE, "No elements to
>> process");
>>                 return false;
>>             }
>> -            collectPlugins(elements);
>> -            writeCacheFile(elements.toArray(new
>> Element[elements.size()]));
>> -            System.out.println("Annotations processed");
>> +            List<PluginEntry> list = new ArrayList<>();
>> +            packageName = collectPlugins(packageName, elements, list);
>> +            writeClassFile(packageName, list);
>> +            writeServiceFile(packageName);
>> +            messager.printMessage(Kind.NOTE, "Annotations processed");
>>             return true;
>>         } catch (final IOException e) {
>>             e.printStackTrace();
>> @@ -93,7 +107,8 @@ public class PluginProcessor extends AbstractProcessor {
>>         processingEnv.getMessager().printMessage(Kind.ERROR, message);
>>     }
>> 
>> -    private void collectPlugins(final Iterable<? extends Element>
>> elements) {
>> +    private String collectPlugins(String packageName, final Iterable<?
>> extends Element> elements, List<PluginEntry> list) {
>> +        boolean calculatePackage = packageName == null;
>>         final Elements elementUtils = processingEnv.getElementUtils();
>>         final ElementVisitor<PluginEntry, Plugin> pluginVisitor = new
>> PluginElementVisitor(elementUtils);
>>         final ElementVisitor<Collection<PluginEntry>, Plugin>
>> pluginAliasesVisitor = new PluginAliasesElementVisitor(
>> @@ -104,23 +119,93 @@ public class PluginProcessor extends
>> AbstractProcessor {
>>                 continue;
>>             }
>>             final PluginEntry entry = element.accept(pluginVisitor,
>> plugin);
>> -            final Map<String, PluginEntry> category =
>> pluginCache.getCategory(entry.getCategory());
>> -            category.put(entry.getKey(), entry);
>> +            list.add(entry);
>> +            if (calculatePackage) {
>> +                packageName = calculatePackage(elementUtils, element,
>> packageName);
>> +            }
>>             final Collection<PluginEntry> entries =
>> element.accept(pluginAliasesVisitor, plugin);
>>             for (final PluginEntry pluginEntry : entries) {
>> -                category.put(pluginEntry.getKey(), pluginEntry);
>> +                list.add(pluginEntry);
>>             }
>>         }
>> +        return packageName;
>>     }
>> 
>> -    private void writeCacheFile(final Element... elements) throws
>> IOException {
>> +    private String calculatePackage(Elements elements, Element element,
>> String packageName) {
>> +        Name name = elements.getPackageOf(element).getQualifiedName();
>> +        if (name == null) {
>> +            return null;
>> +        }
>> +        String pkgName = name.toString();
>> +        if (packageName == null) {
>> +            return pkgName;
>> +        }
>> +        if (pkgName.length() == packageName.length()) {
>> +            return packageName;
>> +        }
>> +        if (pkgName.length() < packageName.length() &&
>> packageName.startsWith(pkgName)) {
>> +            return pkgName;
>> +        }
>> +
>> +        return commonPrefix(pkgName, packageName);
>> +    }
>> +
>> +    private void writeServiceFile(String pkgName) throws IOException {
>>         final FileObject fileObject =
>> processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT,
>> Strings.EMPTY,
>> -                PLUGIN_CACHE_FILE, elements);
>> -        try (final OutputStream out = fileObject.openOutputStream()) {
>> -            pluginCache.writeCache(out);
>> +                SERVICE_FILE_NAME);
>> +        try (final PrintWriter writer = new PrintWriter(new
>> BufferedWriter(new OutputStreamWriter(fileObject.openOutputStream(),
>> UTF_8)))) {
>> +            writer.println(createFqcn(pkgName));
>> +        }
>> +    }
>> +
>> +    private void writeClassFile(String pkg, List<PluginEntry> list) {
>> +        String fqcn = createFqcn(pkg);
>> +        try (final PrintWriter writer = createSourceFile(fqcn)) {
>> +            writer.println("package " + pkg + ".plugins;");
>> +            writer.println("");
>> +            writer.println("import
>> org.apache.logging.log4j.plugins.processor.PluginEntry;");
>> +            writer.println("import
>> org.apache.logging.log4j.plugins.processor.PluginService;");
>> +            writer.println("");
>> +            writer.println("public class Log4jPlugins extends
>> PluginService {");
>> +            writer.println("");
>> +            writer.println("    private static PluginEntry[] entries =
>> new PluginEntry[] {");
>> +            StringBuilder sb = new StringBuilder();
>> +            int max = list.size() - 1;
>> +            for (int i = 0; i < list.size(); ++i) {
>> +                PluginEntry entry = list.get(i);
>> +                sb.append("        ").append("new PluginEntry(\"");
>> +                sb.append(entry.getKey()).append("\", \"");
>> +                sb.append(entry.getClassName()).append("\", \"");
>> +                sb.append(entry.getName()).append("\", ");
>> +                sb.append(entry.isPrintable()).append(", ");
>> +                sb.append(entry.isDefer()).append(", \"");
>> +                sb.append(entry.getCategory()).append("\")");
>> +                if (i < max) {
>> +                    sb.append(",");
>> +                }
>> +                writer.println(sb.toString());
>> +                sb.setLength(0);
>> +            }
>> +            writer.println("    };");
>> +            writer.println("    @Override");
>> +            writer.println("    public PluginEntry[] getEntries() {
>> return entries;}");
>> +            writer.println("}");
>>         }
>>     }
>> 
>> +    private PrintWriter createSourceFile(String fqcn) {
>> +        try {
>> +            JavaFileObject sourceFile =
>> processingEnv.getFiler().createSourceFile(fqcn);
>> +            return new PrintWriter(sourceFile.openWriter());
>> +        } catch (IOException e) {
>> +            throw new LoggingException("Unable to create Plugin Service
>> Class " + fqcn, e);
>> +        }
>> +    }
>> +
>> +    private String createFqcn(String packageName) {
>> +        return packageName + ".plugins.Log4jPlugins";
>> +    }
>> +
>>     /**
>>      * ElementVisitor to scan the Plugin annotation.
>>      */
>> @@ -146,6 +231,20 @@ public class PluginProcessor extends
>> AbstractProcessor {
>>         }
>>     }
>> 
>> +    private String commonPrefix(String str1, String str2) {
>> +        int minLength = str1.length() < str2.length() ? str1.length() :
>> str2.length();
>> +        for (int i = 0; i < minLength; i++) {
>> +            if (str1.charAt(i) != str2.charAt(i)) {
>> +                if (i > 1 && str1.charAt(i-1) == '.') {
>> +                    return str1.substring(0, i-1);
>> +                } else {
>> +                    return str1.substring(0, i);
>> +                }
>> +            }
>> +        }
>> +        return str1.substring(0, minLength);
>> +    }
>> +
>>     /**
>>      * ElementVisitor to scan the PluginAliases annotation.
>>      */
>> diff --git
>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>> new file mode 100644
>> index 0000000..5042456
>> --- /dev/null
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/PluginService.java
>> @@ -0,0 +1,56 @@
>> +/*
>> + * 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.plugins.processor;
>> +
>> +import java.util.Collections;
>> +import java.util.LinkedHashMap;
>> +import java.util.Map;
>> +
>> +/**
>> + * Class Description goes here.
>> + */
>> +public abstract class PluginService {
>> +
>> +    private final Map<String, Map<String, PluginEntry>> categories = new
>> LinkedHashMap<>();
>> +
>> +    public PluginService() {
>> +        PluginEntry[] entries = getEntries();
>> +        for (PluginEntry entry : entries) {
>> +            String category = entry.getCategory().toLowerCase();
>> +            if (!categories.containsKey(category)) {
>> +                categories.put(category, new LinkedHashMap<>());
>> +            }
>> +            Map<String, PluginEntry> map = categories.get(category);
>> +            map.put(entry.getKey(), entry);
>> +        }
>> +    }
>> +
>> +    public abstract PluginEntry[] getEntries();
>> +
>> +    public Map<String, Map<String, PluginEntry>> getCategories() {
>> +        return Collections.unmodifiableMap(categories);
>> +    }
>> +
>> +    public Map<String, PluginEntry> getCategory(String category) {
>> +        return
>> Collections.unmodifiableMap(categories.get(category.toLowerCase()));
>> +    }
>> +
>> +    public long size() {
>> +        return categories.size();
>> +    }
>> +
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>> similarity index 94%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>> copy to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>> index 4f6ddda..2c296f9 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/processor/package-info.java
>> @@ -19,4 +19,4 @@
>>  * Java annotation processor for pre-scanning Log4j 2 plugins. This is
>> provided as an alternative to using the
>>  * executable {@link
>> org.apache.logging.log4j.core.config.plugins.util.PluginManager} class in
>> your build process.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.processor;
>> +package org.apache.logging.log4j.plugins.processor;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>> similarity index 93%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>> index 0935ce8..ec8a07f 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/util/Builder.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/Builder.java
>> @@ -15,7 +15,7 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.util;
>> +package org.apache.logging.log4j.plugins.util;
>> 
>> /**
>>  * A type of builder that can be used to configure and create a instances
>> using a Java DSL instead of
>> @@ -25,7 +25,7 @@ package org.apache.logging.log4j.core.util;
>>  * <p>
>>  *     When creating <em>plugin</em> builders, it is customary to create
>> the builder class as a public static inner class
>>  *     called {@code Builder}. For instance, the builder class for
>> - *     {@link org.apache.logging.log4j.core.layout.PatternLayout
>> PatternLayout} would be
>> + *     org.apache.logging.log4j.core.layout.PatternLayout PatternLayout
>> would be
>>  *     {@code PatternLayout.Builder}.
>>  * </p>
>>  *
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>> similarity index 96%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>> index 6f38d0e..b6f02f5 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginManager.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginManager.java
>> @@ -15,17 +15,13 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.util;
>> +package org.apache.logging.log4j.plugins.util;
>> 
>> import org.apache.logging.log4j.Logger;
>> import org.apache.logging.log4j.status.StatusLogger;
>> import org.apache.logging.log4j.util.Strings;
>> 
>> -import java.util.Collection;
>> -import java.util.HashMap;
>> -import java.util.LinkedHashMap;
>> -import java.util.List;
>> -import java.util.Map;
>> +import java.util.*;
>> import java.util.concurrent.CopyOnWriteArrayList;
>> 
>> /**
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>> similarity index 81%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>> index 99fa610..9e8c6e2 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginRegistry.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginRegistry.java
>> @@ -15,32 +15,28 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.util;
>> +package org.apache.logging.log4j.plugins.util;
>> +
>> +import org.apache.logging.log4j.Logger;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> +import org.apache.logging.log4j.plugins.PluginAliases;
>> +import org.apache.logging.log4j.plugins.processor.PluginCache;
>> +import org.apache.logging.log4j.plugins.processor.PluginEntry;
>> +import org.apache.logging.log4j.plugins.processor.PluginProcessor;
>> +import org.apache.logging.log4j.plugins.processor.PluginService;
>> +import org.apache.logging.log4j.status.StatusLogger;
>> +import org.apache.logging.log4j.util.LoaderUtil;
>> +import org.apache.logging.log4j.util.Strings;
>> 
>> import java.io.IOException;
>> import java.net.URI;
>> import java.net.URL;
>> import java.text.DecimalFormat;
>> -import java.util.ArrayList;
>> -import java.util.Collections;
>> -import java.util.Enumeration;
>> -import java.util.HashMap;
>> -import java.util.List;
>> -import java.util.Map;
>> +import java.util.*;
>> import java.util.concurrent.ConcurrentHashMap;
>> import java.util.concurrent.ConcurrentMap;
>> import java.util.concurrent.atomic.AtomicReference;
>> 
>> -import org.apache.logging.log4j.Logger;
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginCache;
>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry;
>> -import
>> org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor;
>> -import org.apache.logging.log4j.core.util.Loader;
>> -import org.apache.logging.log4j.status.StatusLogger;
>> -import org.apache.logging.log4j.util.Strings;
>> -
>> /**
>>  * Registry singleton for PluginType maps partitioned by source type and
>> then by category names.
>>  */
>> @@ -116,7 +112,8 @@ public class PluginRegistry {
>>             // already loaded
>>             return existing;
>>         }
>> -        final Map<String, List<PluginType<?>>> newPluginsByCategory =
>> decodeCacheFiles(Loader.getClassLoader());
>> +        final Map<String, List<PluginType<?>>> newPluginsByCategory =
>> decodeCacheFiles(LoaderUtil.getClassLoader());
>> +        loadPlugins(newPluginsByCategory);
>> 
>>         // Note multiple threads could be calling this method
>> concurrently. Both will do the work,
>>         // but only one will be allowed to store the result in the
>> AtomicReference.
>> @@ -144,6 +141,7 @@ public class PluginRegistry {
>>             return existing;
>>         }
>>         final Map<String, List<PluginType<?>>> newPluginsByCategory =
>> decodeCacheFiles(loader);
>> +        loadPlugins(loader, newPluginsByCategory);
>> 
>>         // Note multiple threads could be calling this method
>> concurrently. Both will do the work,
>>         // but only one will be allowed to store the result in the outer
>> map.
>> @@ -155,6 +153,51 @@ public class PluginRegistry {
>>         return newPluginsByCategory;
>>     }
>> 
>> +    /**
>> +     * @since 3.0
>> +     */
>> +    public void loadPlugins(Map<String, List<PluginType<?>>> map) {
>> +        for (ClassLoader classLoader : LoaderUtil.getClassLoaders()) {
>> +            try {
>> +                loadPlugins(classLoader, map);
>> +            } catch (Throwable ex) {
>> +                LOGGER.debug("Unable to retrieve provider from
>> ClassLoader {}", classLoader, ex);
>> +            }
>> +        }
>> +    }
>> +
>> +    /**
>> +     * @since 3.0
>> +     */
>> +    public void loadPlugins(ClassLoader classLoader, Map<String,
>> List<PluginType<?>>> map) {
>> +        final long startTime = System.nanoTime();
>> +        final ServiceLoader<PluginService> serviceLoader =
>> ServiceLoader.load(PluginService.class, classLoader);
>> +        int pluginCount = 0;
>> +        for (final PluginService pluginService : serviceLoader) {
>> +            PluginEntry[] entries = pluginService.getEntries();
>> +            for (PluginEntry entry : entries) {
>> +                try {
>> +                    final Class<?> clazz =
>> classLoader.loadClass(entry.getClassName());
>> +                    final PluginType<?> type = new PluginType(entry,
>> clazz, entry.getName());
>> +                    String category = entry.getCategory().toLowerCase();
>> +                    if (!map.containsKey(category)) {
>> +                        map.put(category, new ArrayList<>());
>> +                    }
>> +                    List<PluginType<?>> list = map.get(category);
>> +                    list.add(type);
>> +                    ++pluginCount;
>> +                } catch (final ClassNotFoundException e) {
>> +                    LOGGER.info("Plugin [{}] could not be loaded due to
>> missing classes.", entry.getClassName(), e);
>> +                }
>> +            }
>> +        }
>> +        final long endTime = System.nanoTime();
>> +        final DecimalFormat numFormat = new DecimalFormat("#0.000000");
>> +        final double seconds = (endTime - startTime) * 1e-9;
>> +        LOGGER.debug("Took {} seconds to load {} plugins from {}",
>> +                numFormat.format(seconds), pluginCount, classLoader);
>> +    }
>> +
>>     private Map<String, List<PluginType<?>>> decodeCacheFiles(final
>> ClassLoader loader) {
>>         final long startTime = System.nanoTime();
>>         final PluginCache cache = new PluginCache();
>> @@ -214,7 +257,7 @@ public class PluginRegistry {
>> 
>>         final long startTime = System.nanoTime();
>>         final ResolverUtil resolver = new ResolverUtil();
>> -        final ClassLoader classLoader = Loader.getClassLoader();
>> +        final ClassLoader classLoader = LoaderUtil.getClassLoader();
>>         if (classLoader != null) {
>>             resolver.setClassLoader(classLoader);
>>         }
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>> similarity index 92%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>> index cc6bc66..c213f64 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/PluginType.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/PluginType.java
>> @@ -14,16 +14,16 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.util;
>> +package org.apache.logging.log4j.plugins.util;
>> 
>> 
>> -import org.apache.logging.log4j.core.config.plugins.processor.PluginEntry;
>> +import org.apache.logging.log4j.plugins.processor.PluginEntry;
>> 
>> /**
>>  * Plugin Descriptor. This is a memento object for Plugin annotations
>> paired to their annotated classes.
>>  *
>>  * @param <T> The plug-in class, which can be any kind of class.
>> - * @see org.apache.logging.log4j.core.config.plugins.Plugin
>> + * @see org.apache.logging.log4j.plugins.Plugin
>>  */
>> public class PluginType<T> {
>> 
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>> similarity index 97%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>> index 73b5fc0..a57356c 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtil.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/ResolverUtil.java
>> @@ -14,33 +14,24 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.util;
>> +package org.apache.logging.log4j.plugins.util;
>> 
>> -import java.io.File;
>> -import java.io.FileInputStream;
>> -import java.io.IOException;
>> -import java.io.InputStream;
>> -import java.io.UnsupportedEncodingException;
>> +import org.apache.logging.log4j.Logger;
>> +import org.apache.logging.log4j.util.LoaderUtil;
>> +import org.apache.logging.log4j.status.StatusLogger;
>> +import org.osgi.framework.FrameworkUtil;
>> +import org.osgi.framework.wiring.BundleWiring;
>> +
>> +import java.io.*;
>> import java.net.URI;
>> import java.net.URISyntaxException;
>> import java.net.URL;
>> import java.net.URLDecoder;
>> import java.nio.charset.StandardCharsets;
>> -import java.util.Arrays;
>> -import java.util.Collection;
>> -import java.util.Enumeration;
>> -import java.util.HashSet;
>> -import java.util.List;
>> -import java.util.Set;
>> +import java.util.*;
>> import java.util.jar.JarEntry;
>> import java.util.jar.JarInputStream;
>> 
>> -import org.apache.logging.log4j.Logger;
>> -import org.apache.logging.log4j.core.util.Loader;
>> -import org.apache.logging.log4j.status.StatusLogger;
>> -import org.osgi.framework.FrameworkUtil;
>> -import org.osgi.framework.wiring.BundleWiring;
>> -
>> /**
>>  * <p>
>>  * ResolverUtil is used to locate classes that are available in the/a
>> class path and meet arbitrary conditions. The two
>> @@ -126,7 +117,7 @@ public class ResolverUtil {
>>      * @return the ClassLoader that will be used to scan for classes
>>      */
>>     public ClassLoader getClassLoader() {
>> -        return classloader != null ? classloader : (classloader =
>> Loader.getClassLoader(ResolverUtil.class, null));
>> +        return classloader != null ? classloader : (classloader =
>> LoaderUtil.getClassLoader(ResolverUtil.class, null));
>>     }
>> 
>>     /**
>> diff --git
>> a/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>> new file mode 100644
>> index 0000000..e2bb462
>> --- /dev/null
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/TypeUtil.java
>> @@ -0,0 +1,217 @@
>> +/*
>> + * 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.plugins.util;
>> +
>> +import java.lang.reflect.*;
>> +import java.util.ArrayList;
>> +import java.util.List;
>> +import java.util.Objects;
>> +
>> +/**
>> + * Utility class for working with Java {@link Type}s and derivatives.
>> This class is adapted heavily from the
>> + * <a href="http://projects.spring.io/spring-framework/">Spring
>> Framework</a>, specifically the
>> + * <a href="
>> http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/util/TypeUtils.html
>> ">TypeUtils</a>
>> + * class.
>> + *
>> + * @see Type
>> + * @see GenericArrayType
>> + * @see ParameterizedType
>> + * @see WildcardType
>> + * @see Class
>> + * @since 2.1
>> + */
>> +public final class TypeUtil {
>> +
>> +    private TypeUtil() {
>> +    }
>> +
>> +    /**
>> +     * Gets all declared fields for the given class (including
>> superclasses).
>> +     *
>> +     * @param cls the class to examine
>> +     * @return all declared fields for the given class (including
>> superclasses).
>> +     * @see Class#getDeclaredFields()
>> +     */
>> +    public static List<Field> getAllDeclaredFields(Class<?> cls) {
>> +        final List<Field> fields = new ArrayList<>();
>> +        while (cls != null) {
>> +            for (final Field field : cls.getDeclaredFields()) {
>> +                fields.add(field);
>> +            }
>> +            cls = cls.getSuperclass();
>> +        }
>> +        return fields;
>> +    }
>> +    /**
>> +     * Indicates if two {@link Type}s are assignment compatible.
>> +     *
>> +     * @param lhs the left hand side to check assignability to
>> +     * @param rhs the right hand side to check assignability from
>> +     * @return {@code true} if it is legal to assign a variable of type
>> {@code rhs} to a variable of type {@code lhs}
>> +     * @see Class#isAssignableFrom(Class)
>> +     */
>> +    public static boolean isAssignable(final Type lhs, final Type rhs) {
>> +        Objects.requireNonNull(lhs, "No left hand side type provided");
>> +        Objects.requireNonNull(rhs, "No right hand side type provided");
>> +        if (lhs.equals(rhs)) {
>> +            return true;
>> +        }
>> +        if (Object.class.equals(lhs)) {
>> +            // everything is assignable to Object
>> +            return true;
>> +        }
>> +        // raw type on left
>> +        if (lhs instanceof Class<?>) {
>> +            final Class<?> lhsClass = (Class<?>) lhs;
>> +            if (rhs instanceof Class<?>) {
>> +                // no generics involved
>> +                final Class<?> rhsClass = (Class<?>) rhs;
>> +                return lhsClass.isAssignableFrom(rhsClass);
>> +            }
>> +            if (rhs instanceof ParameterizedType) {
>> +                // check to see if the parameterized type has the same
>> raw type as the lhs; this is legal
>> +                final Type rhsRawType = ((ParameterizedType)
>> rhs).getRawType();
>> +                if (rhsRawType instanceof Class<?>) {
>> +                    return lhsClass.isAssignableFrom((Class<?>)
>> rhsRawType);
>> +                }
>> +            }
>> +            if (lhsClass.isArray() && rhs instanceof GenericArrayType) {
>> +                // check for compatible array component types
>> +                return isAssignable(lhsClass.getComponentType(),
>> ((GenericArrayType) rhs).getGenericComponentType());
>> +            }
>> +        }
>> +        // parameterized type on left
>> +        if (lhs instanceof ParameterizedType) {
>> +            final ParameterizedType lhsType = (ParameterizedType) lhs;
>> +            if (rhs instanceof Class<?>) {
>> +                final Type lhsRawType = lhsType.getRawType();
>> +                if (lhsRawType instanceof Class<?>) {
>> +                    return ((Class<?>)
>> lhsRawType).isAssignableFrom((Class<?>) rhs);
>> +                }
>> +            } else if (rhs instanceof ParameterizedType) {
>> +                final ParameterizedType rhsType = (ParameterizedType) rhs;
>> +                return isParameterizedAssignable(lhsType, rhsType);
>> +            }
>> +        }
>> +        // generic array type on left
>> +        if (lhs instanceof GenericArrayType) {
>> +            final Type lhsComponentType = ((GenericArrayType)
>> lhs).getGenericComponentType();
>> +            if (rhs instanceof Class<?>) {
>> +                // raw type on right
>> +                final Class<?> rhsClass = (Class<?>) rhs;
>> +                if (rhsClass.isArray()) {
>> +                    return isAssignable(lhsComponentType,
>> rhsClass.getComponentType());
>> +                }
>> +            } else if (rhs instanceof GenericArrayType) {
>> +                return isAssignable(lhsComponentType, ((GenericArrayType)
>> rhs).getGenericComponentType());
>> +            }
>> +        }
>> +        // wildcard type on left
>> +        if (lhs instanceof WildcardType) {
>> +            return isWildcardAssignable((WildcardType) lhs, rhs);
>> +        }
>> +        // strange...
>> +        return false;
>> +    }
>> +
>> +    private static boolean isParameterizedAssignable(final
>> ParameterizedType lhs, final ParameterizedType rhs) {
>> +        if (lhs.equals(rhs)) {
>> +            // that was easy
>> +            return true;
>> +        }
>> +        final Type[] lhsTypeArguments = lhs.getActualTypeArguments();
>> +        final Type[] rhsTypeArguments = rhs.getActualTypeArguments();
>> +        final int size = lhsTypeArguments.length;
>> +        if (rhsTypeArguments.length != size) {
>> +            // clearly incompatible types
>> +            return false;
>> +        }
>> +        for (int i = 0; i < size; i++) {
>> +            // verify all type arguments are assignable
>> +            final Type lhsArgument = lhsTypeArguments[i];
>> +            final Type rhsArgument = rhsTypeArguments[i];
>> +            if (!lhsArgument.equals(rhsArgument) &&
>> +                !(lhsArgument instanceof WildcardType &&
>> +                    isWildcardAssignable((WildcardType) lhsArgument,
>> rhsArgument))) {
>> +                return false;
>> +            }
>> +        }
>> +        return true;
>> +    }
>> +
>> +    private static boolean isWildcardAssignable(final WildcardType lhs,
>> final Type rhs) {
>> +        final Type[] lhsUpperBounds = getEffectiveUpperBounds(lhs);
>> +        final Type[] lhsLowerBounds = getEffectiveLowerBounds(lhs);
>> +        if (rhs instanceof WildcardType) {
>> +            // oh boy, this scenario requires checking a lot of
>> assignability!
>> +            final WildcardType rhsType = (WildcardType) rhs;
>> +            final Type[] rhsUpperBounds =
>> getEffectiveUpperBounds(rhsType);
>> +            final Type[] rhsLowerBounds =
>> getEffectiveLowerBounds(rhsType);
>> +            for (final Type lhsUpperBound : lhsUpperBounds) {
>> +                for (final Type rhsUpperBound : rhsUpperBounds) {
>> +                    if (!isBoundAssignable(lhsUpperBound, rhsUpperBound))
>> {
>> +                        return false;
>> +                    }
>> +                }
>> +                for (final Type rhsLowerBound : rhsLowerBounds) {
>> +                    if (!isBoundAssignable(lhsUpperBound, rhsLowerBound))
>> {
>> +                        return false;
>> +                    }
>> +                }
>> +            }
>> +            for (final Type lhsLowerBound : lhsLowerBounds) {
>> +                for (final Type rhsUpperBound : rhsUpperBounds) {
>> +                    if (!isBoundAssignable(rhsUpperBound, lhsLowerBound))
>> {
>> +                        return false;
>> +                    }
>> +                }
>> +                for (final Type rhsLowerBound : rhsLowerBounds) {
>> +                    if (!isBoundAssignable(rhsLowerBound, lhsLowerBound))
>> {
>> +                        return false;
>> +                    }
>> +                }
>> +            }
>> +        } else {
>> +            // phew, far less bounds to check
>> +            for (final Type lhsUpperBound : lhsUpperBounds) {
>> +                if (!isBoundAssignable(lhsUpperBound, rhs)) {
>> +                    return false;
>> +                }
>> +            }
>> +            for (final Type lhsLowerBound : lhsLowerBounds) {
>> +                if (!isBoundAssignable(lhsLowerBound, rhs)) {
>> +                    return false;
>> +                }
>> +            }
>> +        }
>> +        return true;
>> +    }
>> +
>> +    private static Type[] getEffectiveUpperBounds(final WildcardType
>> type) {
>> +        final Type[] upperBounds = type.getUpperBounds();
>> +        return upperBounds.length == 0 ? new Type[]{Object.class} :
>> upperBounds;
>> +    }
>> +
>> +    private static Type[] getEffectiveLowerBounds(final WildcardType
>> type) {
>> +        final Type[] lowerBounds = type.getLowerBounds();
>> +        return lowerBounds.length == 0 ? new Type[]{null} : lowerBounds;
>> +    }
>> +
>> +    private static boolean isBoundAssignable(final Type lhs, final Type
>> rhs) {
>> +        return (rhs == null) || ((lhs != null) && isAssignable(lhs, rhs));
>> +    }
>> +}
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>> similarity index 94%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>> index 4f6ddda..fae7580 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/processor/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/util/package-info.java
>> @@ -19,4 +19,4 @@
>>  * Java annotation processor for pre-scanning Log4j 2 plugins. This is
>> provided as an alternative to using the
>>  * executable {@link
>> org.apache.logging.log4j.core.config.plugins.util.PluginManager} class in
>> your build process.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.processor;
>> +package org.apache.logging.log4j.plugins.util;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>> similarity index 81%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>> index 0ac2223..4586315 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/Constraint.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/Constraint.java
>> @@ -14,14 +14,9 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> -import java.lang.annotation.Annotation;
>> -import java.lang.annotation.Documented;
>> -import java.lang.annotation.ElementType;
>> -import java.lang.annotation.Retention;
>> -import java.lang.annotation.RetentionPolicy;
>> -import java.lang.annotation.Target;
>> +import java.lang.annotation.*;
>> 
>> /**
>>  * Meta annotation to mark an annotation as a validation constraint. This
>> annotation must specify a
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>> similarity index 96%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>> index 1d8c0c5..2f638a7 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidator.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidator.java
>> @@ -14,7 +14,7 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> import java.lang.annotation.Annotation;
>> 
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>> similarity index 93%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>> index 374c8ec..6236bb6 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/ConstraintValidators.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/ConstraintValidators.java
>> @@ -14,7 +14,9 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> +
>> +import org.apache.logging.log4j.util.ReflectionUtil;
>> 
>> import java.lang.annotation.Annotation;
>> import java.lang.reflect.ParameterizedType;
>> @@ -22,8 +24,6 @@ import java.lang.reflect.Type;
>> import java.util.ArrayList;
>> import java.util.Collection;
>> 
>> -import org.apache.logging.log4j.core.util.ReflectionUtil;
>> -
>> /**
>>  * Utility class to locate an appropriate {@link ConstraintValidator}
>> implementation for an annotation.
>>  *
>> @@ -36,7 +36,7 @@ public final class ConstraintValidators {
>> 
>>     /**
>>      * Finds all relevant {@link ConstraintValidator} objects from an
>> array of annotations. All validators will be
>> -     * {@link
>> ConstraintValidator#initialize(java.lang.annotation.Annotation)
>> initialized} before being returned.
>> +     * {@link ConstraintValidator#initialize(Annotation) initialized}
>> before being returned.
>>      *
>>      * @param annotations the annotations to find constraint validators
>> for
>>      * @return a collection of ConstraintValidators for the given
>> annotations
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>> similarity index 73%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>> index e6f3c56..9b8a75d 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/Required.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/Required.java
>> @@ -15,16 +15,12 @@
>>  * limitations under the license.
>>  */
>> 
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +package org.apache.logging.log4j.plugins.validation.constraints;
>> 
>> -import java.lang.annotation.Documented;
>> -import java.lang.annotation.ElementType;
>> -import java.lang.annotation.Retention;
>> -import java.lang.annotation.RetentionPolicy;
>> -import java.lang.annotation.Target;
>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>> +import
>> org.apache.logging.log4j.plugins.validation.validators.RequiredValidator;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.validators.RequiredValidator;
>> +import java.lang.annotation.*;
>> 
>> /**
>>  * Marks a plugin builder field or plugin factory parameter as required.
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>> similarity index 84%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>> index c652d40..14dd9a8 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidHost.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidHost.java
>> @@ -14,10 +14,10 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +package org.apache.logging.log4j.plugins.validation.constraints;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.validators.ValidHostValidator;
>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>> +import
>> org.apache.logging.log4j.plugins.validation.validators.ValidHostValidator;
>> 
>> import java.lang.annotation.*;
>> import java.net.InetAddress;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>> similarity index 74%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>> index a7c68b1..c4aba16 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/ValidPort.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/ValidPort.java
>> @@ -14,16 +14,12 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +package org.apache.logging.log4j.plugins.validation.constraints;
>> 
>> -import java.lang.annotation.Documented;
>> -import java.lang.annotation.ElementType;
>> -import java.lang.annotation.Retention;
>> -import java.lang.annotation.RetentionPolicy;
>> -import java.lang.annotation.Target;
>> +import org.apache.logging.log4j.plugins.validation.Constraint;
>> +import
>> org.apache.logging.log4j.plugins.validation.validators.ValidPortValidator;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.validation.Constraint;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.validators.ValidPortValidator;
>> +import java.lang.annotation.*;
>> 
>> /**
>>  * Indicates that a plugin attribute must be a valid port number. A valid
>> port number is an integer between 0 and
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>> similarity index 91%
>> copy from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> copy to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>> index f22ba49..298cd5a 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/constraints/package-info.java
>> @@ -20,4 +20,4 @@
>>  *
>>  * @since 2.1
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +package org.apache.logging.log4j.plugins.validation.constraints;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>> similarity index 93%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>> index 171b25a..15955cb 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/package-info.java
>> @@ -20,4 +20,4 @@
>>  *
>>  * @since 2.1
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>> similarity index 86%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>> index 98c0a71..9df6d3b 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/RequiredValidator.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/RequiredValidator.java
>> @@ -14,17 +14,17 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>> -
>> -import java.util.Collection;
>> -import java.util.Map;
>> +package org.apache.logging.log4j.plugins.validation.validators;
>> 
>> import org.apache.logging.log4j.Logger;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>> -import org.apache.logging.log4j.core.util.Assert;
>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>> +import org.apache.logging.log4j.util.Assert;
>> import org.apache.logging.log4j.status.StatusLogger;
>> 
>> +import java.util.Collection;
>> +import java.util.Map;
>> +
>> /**
>>  * Validator that checks an object for emptiness. Emptiness is defined
>> here as:
>>  * <ul>
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>> similarity index 89%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>> index 6c01753..41abbfd 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidHostValidator.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidHostValidator.java
>> @@ -14,11 +14,11 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>> +package org.apache.logging.log4j.plugins.validation.validators;
>> 
>> import org.apache.logging.log4j.Logger;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
>> import org.apache.logging.log4j.status.StatusLogger;
>> 
>> import java.net.InetAddress;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>> similarity index 85%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>> index a59742c..27e97f0 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/ValidPortValidator.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/ValidPortValidator.java
>> @@ -14,12 +14,12 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>> +package org.apache.logging.log4j.plugins.validation.validators;
>> 
>> import org.apache.logging.log4j.Logger;
>> -import
>> org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.ConstraintValidator;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
>> +import org.apache.logging.log4j.plugins.validation.ConstraintValidator;
>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
>> +import org.apache.logging.log4j.plugins.convert.TypeConverters;
>> import org.apache.logging.log4j.status.StatusLogger;
>> 
>> /**
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>> similarity index 92%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>> index a8ac560..cfe2041 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/validators/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/validation/validators/package-info.java
>> @@ -20,4 +20,4 @@
>>  *
>>  * @since 2.1
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.validators;
>> +package org.apache.logging.log4j.plugins.validation.validators;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>> similarity index 84%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>> index 560cbe3..b98dc09 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/AbstractPluginVisitor.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/AbstractPluginVisitor.java
>> @@ -15,18 +15,18 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>> +package org.apache.logging.log4j.plugins.visitors;
>> +
>> +import org.apache.logging.log4j.Logger;
>> +import org.apache.logging.log4j.plugins.convert.TypeConverters;
>> +import org.apache.logging.log4j.status.StatusLogger;
>> +import org.apache.logging.log4j.util.Strings;
>> 
>> import java.lang.annotation.Annotation;
>> import java.lang.reflect.Member;
>> import java.util.Map;
>> import java.util.Objects;
>> -
>> -import org.apache.logging.log4j.Logger;
>> -import
>> org.apache.logging.log4j.core.config.plugins.convert.TypeConverters;
>> -import org.apache.logging.log4j.core.lookup.StrSubstitutor;
>> -import org.apache.logging.log4j.status.StatusLogger;
>> -import org.apache.logging.log4j.util.Strings;
>> +import java.util.function.Function;
>> 
>> /**
>>  * Base class for PluginVisitor implementations. Provides convenience
>> methods as well as all method implementations
>> @@ -34,7 +34,7 @@ import org.apache.logging.log4j.util.Strings;
>>  *
>>  * @param <A> the Plugin annotation type.
>>  */
>> -public abstract class AbstractPluginVisitor<A extends Annotation>
>> implements PluginVisitor<A> {
>> +public abstract class AbstractPluginVisitor<A extends Annotation, T>
>> implements PluginVisitor<A, T> {
>> 
>>     /** Status logger. */
>>     protected static final Logger LOGGER = StatusLogger.getLogger();
>> @@ -58,10 +58,6 @@ public abstract class AbstractPluginVisitor<A extends
>> Annotation> implements Plu
>>     /**
>>      *
>>      */
>> -    protected StrSubstitutor substitutor;
>> -    /**
>> -     *
>> -     */
>>     protected Member member;
>> 
>>     /**
>> @@ -75,7 +71,7 @@ public abstract class AbstractPluginVisitor<A extends
>> Annotation> implements Plu
>> 
>>     @SuppressWarnings("unchecked")
>>     @Override
>> -    public PluginVisitor<A> setAnnotation(final Annotation anAnnotation) {
>> +    public PluginVisitor<A, T> setAnnotation(final Annotation
>> anAnnotation) {
>>         final Annotation a = Objects.requireNonNull(anAnnotation, "No
>> annotation was provided");
>>         if (this.clazz.isInstance(a)) {
>>             this.annotation = (A) a;
>> @@ -84,25 +80,19 @@ public abstract class AbstractPluginVisitor<A extends
>> Annotation> implements Plu
>>     }
>> 
>>     @Override
>> -    public PluginVisitor<A> setAliases(final String... someAliases) {
>> +    public PluginVisitor<A, T> setAliases(final String... someAliases) {
>>         this.aliases = someAliases;
>>         return this;
>>     }
>> 
>>     @Override
>> -    public PluginVisitor<A> setConversionType(final Class<?>
>> aConversionType) {
>> +    public PluginVisitor<A, T> setConversionType(final Class<?>
>> aConversionType) {
>>         this.conversionType = Objects.requireNonNull(aConversionType, "No
>> conversion type class was provided");
>>         return this;
>>     }
>> 
>>     @Override
>> -    public PluginVisitor<A> setStrSubstitutor(final StrSubstitutor
>> aSubstitutor) {
>> -        this.substitutor = Objects.requireNonNull(aSubstitutor, "No
>> StrSubstitutor was provided");
>> -        return this;
>> -    }
>> -
>> -    @Override
>> -    public PluginVisitor<A> setMember(final Member aMember) {
>> +    public PluginVisitor<A, T> setMember(final Member aMember) {
>>         this.member = aMember;
>>         return this;
>>     }
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>> similarity index 80%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>> index f4da42b..fbd28b9 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginAttributeVisitor.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginAttributeVisitor.java
>> @@ -15,40 +15,39 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>> +package org.apache.logging.log4j.plugins.visitors;
>> 
>> -import java.util.Map;
>> -
>> -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.PluginAttribute;
>> -import org.apache.logging.log4j.core.util.NameUtil;
>> +import org.apache.logging.log4j.plugins.Node;
>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>> +import org.apache.logging.log4j.util.NameUtil;
>> import org.apache.logging.log4j.util.StringBuilders;
>> 
>> +import java.util.Map;
>> +import java.util.function.Function;
>> +
>> /**
>>  * PluginVisitor implementation for {@link PluginAttribute}.
>>  */
>> -public class PluginAttributeVisitor extends
>> AbstractPluginVisitor<PluginAttribute> {
>> +public class PluginAttributeVisitor extends
>> AbstractPluginVisitor<PluginAttribute, Object> {
>>     public PluginAttributeVisitor() {
>>         super(PluginAttribute.class);
>>     }
>> 
>>     @Override
>> -    public Object visit(final Configuration configuration, final Node
>> node, final LogEvent event,
>> +    public Object visit(final Object unused, final Node node, final
>> Function<String, String> substitutor,
>>                         final StringBuilder log) {
>>         final String name = this.annotation.value();
>>         final Map<String, String> attributes = node.getAttributes();
>>         final String rawValue = removeAttributeValue(attributes, name,
>> this.aliases);
>> -        final String replacedValue = this.substitutor.replace(event,
>> rawValue);
>> -        final Object defaultValue = findDefaultValue(event);
>> +        final String replacedValue = substitutor.apply(rawValue);
>> +        final Object defaultValue = findDefaultValue(substitutor);
>>         final Object value = convert(replacedValue, defaultValue);
>>         final Object debugValue = this.annotation.sensitive() ?
>> NameUtil.md5(value + this.getClass().getName()) : value;
>>         StringBuilders.appendKeyDqValue(log, name, debugValue);
>>         return value;
>>     }
>> 
>> -    private Object findDefaultValue(final LogEvent event) {
>> +    private Object findDefaultValue(Function<String, String> substitutor)
>> {
>>         if (this.conversionType == int.class || this.conversionType ==
>> Integer.class) {
>>             return this.annotation.defaultInt();
>>         }
>> @@ -76,6 +75,6 @@ public class PluginAttributeVisitor extends
>> AbstractPluginVisitor<PluginAttribut
>>         if (this.conversionType == Class.class) {
>>             return this.annotation.defaultClass();
>>         }
>> -        return this.substitutor.replace(event,
>> this.annotation.defaultString());
>> +        return substitutor.apply(this.annotation.defaultString());
>>     }
>> }
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>> similarity index 74%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>> index e951456..398ff1c 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginBuilderAttributeVisitor.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginBuilderAttributeVisitor.java
>> @@ -15,38 +15,37 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>> +package org.apache.logging.log4j.plugins.visitors;
>> 
>> -import java.util.Map;
>> -
>> -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.PluginBuilderAttribute;
>> -import org.apache.logging.log4j.core.util.NameUtil;
>> +import org.apache.logging.log4j.plugins.Node;
>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>> +import org.apache.logging.log4j.util.NameUtil;
>> import org.apache.logging.log4j.util.StringBuilders;
>> 
>> +import java.util.Map;
>> +import java.util.function.Function;
>> +
>> /**
>>  * PluginVisitor for PluginBuilderAttribute. If {@code null} is returned
>> for the
>> - * {@link #visit(org.apache.logging.log4j.core.config.Configuration,
>> org.apache.logging.log4j.core.config.Node,
>> org.apache.logging.log4j.core.LogEvent, StringBuilder)}
>> + * {@link #visit(org.apache.logging.log4j.core.config.Configuration,
>> org.apache.logging.log4j.plugins.Node,
>> org.apache.logging.log4j.core.LogEvent, StringBuilder)}
>>  * method, then the default value of the field should remain untouched.
>>  *
>>  * @see org.apache.logging.log4j.core.config.plugins.util.PluginBuilder
>>  */
>> -public class PluginBuilderAttributeVisitor extends
>> AbstractPluginVisitor<PluginBuilderAttribute> {
>> +public class PluginBuilderAttributeVisitor extends
>> AbstractPluginVisitor<PluginBuilderAttribute, Object> {
>> 
>>     public PluginBuilderAttributeVisitor() {
>>         super(PluginBuilderAttribute.class);
>>     }
>> 
>>     @Override
>> -    public Object visit(final Configuration configuration, final Node
>> node, final LogEvent event,
>> +    public Object visit(final Object unused, final Node node, final
>> Function<String, String> substitutor,
>>                         final StringBuilder log) {
>>         final String overridden = this.annotation.value();
>>         final String name = overridden.isEmpty() ? this.member.getName()
>> : overridden;
>>         final Map<String, String> attributes = node.getAttributes();
>>         final String rawValue = removeAttributeValue(attributes, name,
>> this.aliases);
>> -        final String replacedValue = this.substitutor.replace(event,
>> rawValue);
>> +        final String replacedValue = substitutor.apply(rawValue);
>>         final Object value = convert(replacedValue, null);
>>         final Object debugValue = this.annotation.sensitive() ?
>> NameUtil.md5(value + this.getClass().getName()) : value;
>>         StringBuilders.appendKeyDqValue(log, name, debugValue);
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>> similarity index 90%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>> index 2e6e6ef..f8197f1 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginElementVisitor.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginElementVisitor.java
>> @@ -15,30 +15,29 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>> +package org.apache.logging.log4j.plugins.visitors;
>> +
>> +import org.apache.logging.log4j.plugins.Node;
>> +import org.apache.logging.log4j.plugins.PluginElement;
>> +import org.apache.logging.log4j.plugins.util.PluginType;
>> 
>> import java.lang.reflect.Array;
>> import java.util.ArrayList;
>> import java.util.Arrays;
>> import java.util.Collection;
>> import java.util.List;
>> -
>> -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.PluginElement;
>> -import org.apache.logging.log4j.core.config.plugins.util.PluginType;
>> +import java.util.function.Function;
>> 
>> /**
>>  * PluginVisitor implementation for {@link PluginElement}. Supports
>> arrays as well as singular values.
>>  */
>> -public class PluginElementVisitor extends
>> AbstractPluginVisitor<PluginElement> {
>> +public class PluginElementVisitor extends
>> AbstractPluginVisitor<PluginElement, Object> {
>>     public PluginElementVisitor() {
>>         super(PluginElement.class);
>>     }
>> 
>>     @Override
>> -    public Object visit(final Configuration configuration, final Node
>> node, final LogEvent event,
>> +    public Object visit(final Object unused, final Node node, final
>> Function<String, String> substitutor,
>>                         final StringBuilder log) {
>>         final String name = this.annotation.value();
>>         if (this.conversionType.isArray()) {
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>> similarity index 77%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>> index 7f15392..9438b39 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginNodeVisitor.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginNodeVisitor.java
>> @@ -15,23 +15,23 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>> +package org.apache.logging.log4j.plugins.visitors;
>> 
>> -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.PluginNode;
>> +import org.apache.logging.log4j.plugins.Node;
>> +import org.apache.logging.log4j.plugins.PluginNode;
>> +
>> +import java.util.function.Function;
>> 
>> /**
>>  * PluginVisitor implementation for {@link PluginNode}.
>>  */
>> -public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode> {
>> +public class PluginNodeVisitor extends AbstractPluginVisitor<PluginNode,
>> Object> {
>>     public PluginNodeVisitor() {
>>         super(PluginNode.class);
>>     }
>> 
>>     @Override
>> -    public Object visit(final Configuration configuration, final Node
>> node, final LogEvent event,
>> +    public Object visit(final Object unused, final Node node, final
>> Function<String, String> substitutor,
>>                         final StringBuilder log) {
>>         if (this.conversionType.isInstance(node)) {
>>             log.append("Node=").append(node.getName());
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>> similarity index 79%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>> index 8544570..2f68f04 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginValueVisitor.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginValueVisitor.java
>> @@ -15,26 +15,26 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>> +package org.apache.logging.log4j.plugins.visitors;
>> 
>> -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.PluginValue;
>> +import org.apache.logging.log4j.plugins.Node;
>> +import org.apache.logging.log4j.plugins.PluginValue;
>> import org.apache.logging.log4j.util.StringBuilders;
>> import org.apache.logging.log4j.util.Strings;
>> 
>> +import java.util.function.Function;
>> +
>> /**
>>  * PluginVisitor implementation for {@link PluginValue}.
>>  */
>> -public class PluginValueVisitor extends
>> AbstractPluginVisitor<PluginValue> {
>> +public class PluginValueVisitor extends
>> AbstractPluginVisitor<PluginValue, Object> {
>>     public PluginValueVisitor() {
>>         super(PluginValue.class);
>>     }
>> 
>>     @Override
>> -    public Object visit(final Configuration configuration, final Node
>> node, final LogEvent event,
>> -            final StringBuilder log) {
>> +    public Object visit(final Object unused, final Node node, final
>> Function<String, String> substitutor,
>> +                        final StringBuilder log) {
>>         final String name = this.annotation.value();
>>         final String elementValue = node.getValue();
>>         final String attributeValue = node.getAttributes().get("value");
>> @@ -49,7 +49,7 @@ public class PluginValueVisitor extends
>> AbstractPluginVisitor<PluginValue> {
>>         } else {
>>             rawValue = removeAttributeValue(node.getAttributes(),
>> "value");
>>         }
>> -        final String value = this.substitutor.replace(event, rawValue);
>> +        final String value = substitutor.apply(rawValue);
>>         StringBuilders.appendKeyDqValue(log, name, value);
>>         return value;
>>     }
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>> similarity index 68%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>> index 34e2b78..fb7aca4 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitor.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitor.java
>> @@ -15,15 +15,13 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>> +package org.apache.logging.log4j.plugins.visitors;
>> +
>> +import org.apache.logging.log4j.plugins.Node;
>> 
>> import java.lang.annotation.Annotation;
>> import java.lang.reflect.Member;
>> -
>> -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.lookup.StrSubstitutor;
>> +import java.util.function.Function;
>> 
>> /**
>>  * Visitor strategy for parsing data from a {@link Node}, doing any
>> relevant type conversion, and returning a
>> @@ -31,7 +29,7 @@ import
>> org.apache.logging.log4j.core.lookup.StrSubstitutor;
>>  *
>>  * @param <A> the Annotation type.
>>  */
>> -public interface PluginVisitor<A extends Annotation> {
>> +public interface PluginVisitor<A extends Annotation, T> {
>> 
>>     /**
>>      * Sets the Annotation to be used for this. If the given Annotation
>> is not compatible with this class's type, then
>> @@ -41,7 +39,7 @@ public interface PluginVisitor<A extends Annotation> {
>>      * @return {@code this}.
>>      * @throws NullPointerException if the argument is {@code null}.
>>      */
>> -    PluginVisitor<A> setAnnotation(Annotation annotation);
>> +    PluginVisitor<A, T> setAnnotation(Annotation annotation);
>> 
>>     /**
>>      * Sets the list of aliases to use for this visit. No aliases are
>> required, however.
>> @@ -49,7 +47,7 @@ public interface PluginVisitor<A extends Annotation> {
>>      * @param aliases the list of aliases to use.
>>      * @return {@code this}.
>>      */
>> -    PluginVisitor<A> setAliases(String... aliases);
>> +    PluginVisitor<A, T> setAliases(String... aliases);
>> 
>>     /**
>>      * Sets the class to convert the plugin value to on this visit. This
>> should correspond with a class obtained from
>> @@ -59,17 +57,7 @@ public interface PluginVisitor<A extends Annotation> {
>>      * @return {@code this}.
>>      * @throws NullPointerException if the argument is {@code null}.
>>      */
>> -    PluginVisitor<A> setConversionType(Class<?> conversionType);
>> -
>> -    /**
>> -     * Sets the StrSubstitutor to use for converting raw strings before
>> type conversion. Generally obtained from a
>> -     * {@link org.apache.logging.log4j.core.config.Configuration}.
>> -     *
>> -     * @param substitutor the StrSubstitutor to use on plugin values.
>> -     * @return {@code this}.
>> -     * @throws NullPointerException if the argument is {@code null}.
>> -     */
>> -    PluginVisitor<A> setStrSubstitutor(StrSubstitutor substitutor);
>> +    PluginVisitor<A, T> setConversionType(Class<?> conversionType);
>> 
>>     /**
>>      * Sets the Member that this visitor is being used for injection
>> upon. For instance, this could be the Field
>> @@ -79,16 +67,16 @@ public interface PluginVisitor<A extends Annotation> {
>>      * @param member the member this visitor is parsing a value for.
>>      * @return {@code this}.
>>      */
>> -    PluginVisitor<A> setMember(Member member);
>> +    PluginVisitor<A, T> setMember(Member member);
>> 
>>     /**
>>      * Visits a Node to obtain a value for constructing a Plugin object.
>>      *
>>      * @param configuration the current Configuration.
>>      * @param node          the current Node corresponding to the Plugin
>> object being created.
>> -     * @param event         the current LogEvent that caused this Plugin
>> object to be made (optional).
>> -     * @param log           the StringBuilder being used to build a debug
>> message.
>> +     * @param substitutor   the function to perform String substitutions.
>> +     * @param log           th e StringBuilder being used to build a
>> debug message.
>>      * @return the converted value to be used for Plugin creation.
>>      */
>> -    Object visit(Configuration configuration, Node node, LogEvent event,
>> StringBuilder log);
>> +    Object visit(T configuration, Node node, Function<String, String>
>> substitutor, StringBuilder log);
>> }
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>> similarity index 86%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>> index 10ee0df..695d387 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/visitors/PluginVisitors.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/PluginVisitors.java
>> @@ -15,14 +15,14 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.visitors;
>> -
>> -import java.lang.annotation.Annotation;
>> +package org.apache.logging.log4j.plugins.visitors;
>> 
>> import org.apache.logging.log4j.Logger;
>> -import org.apache.logging.log4j.core.config.plugins.PluginVisitorStrategy;
>> +import org.apache.logging.log4j.plugins.PluginVisitorStrategy;
>> import org.apache.logging.log4j.status.StatusLogger;
>> 
>> +import java.lang.annotation.Annotation;
>> +
>> /**
>>  * Utility class to locate an appropriate {@link PluginVisitor}
>> implementation for an annotation.
>>  */
>> @@ -41,13 +41,13 @@ public final class PluginVisitors {
>>      * @param annotation the Plugin annotation class to find a
>> PluginVisitor for.
>>      * @return a PluginVisitor instance if one could be created, or
>> {@code null} otherwise.
>>      */
>> -    public static PluginVisitor<? extends Annotation> findVisitor(final
>> Class<? extends Annotation> annotation) {
>> +    public static <T> PluginVisitor<? extends Annotation, T>
>> findVisitor(final Class<? extends Annotation> annotation) {
>>         final PluginVisitorStrategy strategy =
>> annotation.getAnnotation(PluginVisitorStrategy.class);
>>         if (strategy == null) {
>>             return null;
>>         }
>>         try {
>> -            return strategy.value().newInstance();
>> +            return (PluginVisitor<? extends Annotation, T>)
>> strategy.value().newInstance();
>>         } catch (final Exception e) {
>>             LOGGER.error("Error loading PluginVisitor [{}] for annotation
>> [{}].", strategy.value(), annotation, e);
>>             return null;
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>> similarity index 67%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> rename to
>> log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>> index f22ba49..0855b16 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/validation/constraints/package-info.java
>> +++
>> b/log4j-plugins/src/main/java/org/apache/logging/log4j/plugins/visitors/package-info.java
>> @@ -16,8 +16,9 @@
>>  */
>> 
>> /**
>> - * Validation annotations.
>> - *
>> - * @since 2.1
>> + * Visitor classes for extracting values from a Configuration or Node
>> corresponding to a plugin annotation.
>> + * Visitor implementations must implement {@link
>> org.apache.logging.log4j.plugins.visitors.PluginVisitor},
>> + * and the corresponding annotation must be annotated with
>> + * {@link org.apache.logging.log4j.plugins.PluginVisitorStrategy}.
>>  */
>> -package
>> org.apache.logging.log4j.core.config.plugins.validation.constraints;
>> +package org.apache.logging.log4j.plugins.visitors;
>> diff --git
>> a/log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>> b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>> similarity index 91%
>> rename from
>> log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>> rename to
>> log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>> index bb9dcb9..5d6951a 100644
>> ---
>> a/log4j-core/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>> +++
>> b/log4j-plugins/src/main/resources/META-INF/services/javax.annotation.processing.Processor
>> @@ -14,4 +14,4 @@
>> # See the license for the specific language governing permissions and
>> # limitations under the license.
>> #
>> -org.apache.logging.log4j.core.config.plugins.processor.PluginProcessor
>> +org.apache.logging.log4j.plugins.processor.PluginProcessor
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>> similarity index 97%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>> index f9e757d..6e4b059 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/convert/TypeConverterRegistryTest.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/convert/TypeConverterRegistryTest.java
>> @@ -14,7 +14,7 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.convert;
>> +package org.apache.logging.log4j.plugins.convert;
>> 
>> import org.junit.Test;
>> 
>> @@ -63,7 +63,7 @@ public class TypeConverterRegistryTest {
>>         // TODO: is there a specific converter this should return?
>>     }
>> 
>> -    public static enum Foo {
>> +    public enum Foo {
>>         I, PITY, THE
>>     }
>> 
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>> similarity index 84%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>> index f4ceb41..48ea7dc 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/FakePlugin.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/FakePlugin.java
>> @@ -15,10 +15,10 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.processor;
>> +package org.apache.logging.log4j.plugins.processor;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> +import org.apache.logging.log4j.plugins.PluginAliases;
>> 
>> /**
>>  * Test plugin class for unit tests.
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>> similarity index 75%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>> index 9c37af4..034705c 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/processor/PluginProcessorTest.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/processor/PluginProcessorTest.java
>> @@ -15,17 +15,19 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.processor;
>> +package org.apache.logging.log4j.plugins.processor;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import org.apache.logging.log4j.core.config.plugins.PluginAliases;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> +import org.apache.logging.log4j.plugins.PluginAliases;
>> import org.junit.BeforeClass;
>> import org.junit.Test;
>> import org.junit.runner.RunWith;
>> import org.junit.runners.JUnit4;
>> 
>> import java.net.URL;
>> +import java.util.ArrayList;
>> import java.util.Enumeration;
>> +import java.util.List;
>> import java.util.Map;
>> 
>> import static org.junit.Assert.*;
>> @@ -33,29 +35,29 @@ import static org.junit.Assert.*;
>> @RunWith(JUnit4.class)
>> public class PluginProcessorTest {
>> 
>> -    private static final PluginCache pluginCache = new PluginCache();
>> +    private static PluginService pluginService;
>> 
>>     private final Plugin p = FakePlugin.class.getAnnotation(Plugin.class);
>> 
>>     @BeforeClass
>>     public static void setUpClass() throws Exception {
>> -        final Enumeration<URL> resources =
>> -
>> PluginProcessor.class.getClassLoader().getResources(PluginProcessor.PLUGIN_CACHE_FILE);
>> -        pluginCache.loadCacheFiles(resources);
>> +        Class<?> clazz =
>> PluginProcessor.class.getClassLoader().loadClass("org.apache.logging.log4j.plugins.plugins.Log4jPlugins");
>> +        assertNotNull("Could not locate plugins class", clazz);
>> +        pluginService = (PluginService)
>> clazz.getDeclaredConstructor().newInstance();;
>>     }
>> 
>>     @Test
>>     public void testTestCategoryFound() throws Exception {
>>         assertNotNull("No plugin annotation on FakePlugin.", p);
>> -        final Map<String, PluginEntry> testCategory =
>> pluginCache.getCategory(p.category());
>> -        assertNotEquals("No plugins were found.", 0, pluginCache.size());
>> +        final Map<String, PluginEntry> testCategory =
>> pluginService.getCategory(p.category());
>> +        assertNotEquals("No plugins were found.", 0,
>> pluginService.size());
>>         assertNotNull("The category '" + p.category() + "' was not
>> found.", testCategory);
>>         assertFalse(testCategory.isEmpty());
>>     }
>> 
>>     @Test
>>     public void testFakePluginFoundWithCorrectInformation() throws
>> Exception {
>> -        final PluginEntry fake =
>> pluginCache.getCategory(p.category()).get(p.name().toLowerCase());
>> +        final PluginEntry fake =
>> pluginService.getCategory(p.category()).get(p.name().toLowerCase());
>>         verifyFakePluginEntry(p.name(), fake);
>>     }
>> 
>> @@ -63,7 +65,7 @@ public class PluginProcessorTest {
>>     public void testFakePluginAliasesContainSameInformation() throws
>> Exception {
>>         final PluginAliases aliases =
>> FakePlugin.class.getAnnotation(PluginAliases.class);
>>         for (final String alias : aliases.value()) {
>> -            final PluginEntry fake =
>> pluginCache.getCategory(p.category()).get(alias.toLowerCase());
>> +            final PluginEntry fake =
>> pluginService.getCategory(p.category()).get(alias.toLowerCase());
>>             verifyFakePluginEntry(alias, fake);
>>         }
>>     }
>> @@ -81,7 +83,7 @@ public class PluginProcessorTest {
>>     @Test
>>     public void testNestedPlugin() throws Exception {
>>         final Plugin p =
>> FakePlugin.Nested.class.getAnnotation(Plugin.class);
>> -        final PluginEntry nested =
>> pluginCache.getCategory(p.category()).get(p.name().toLowerCase());
>> +        final PluginEntry nested =
>> pluginService.getCategory(p.category()).get(p.name().toLowerCase());
>>         assertNotNull(nested);
>>         assertEquals(p.name().toLowerCase(), nested.getKey());
>>         assertEquals(FakePlugin.Nested.class.getName(),
>> nested.getClassName());
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>> similarity index 93%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>> index 33e0ee1..d0b35d1 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilCustomProtocolTest.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilCustomProtocolTest.java
>> @@ -15,27 +15,21 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.util;
>> +package org.apache.logging.log4j.plugins.util;
>> 
>> -import static org.junit.Assert.assertEquals;
>> +import org.apache.logging.log4j.junit.CleanFolders;
>> +import org.apache.logging.log4j.junit.URLStreamHandlerFactoryRule;
>> +import org.junit.Rule;
>> +import org.junit.Test;
>> +import org.junit.rules.RuleChain;
>> 
>> import java.io.IOException;
>> -import java.net.Proxy;
>> -import java.net.URL;
>> -import java.net.URLClassLoader;
>> -import java.net.URLConnection;
>> -import java.net.URLStreamHandler;
>> -import java.net.URLStreamHandlerFactory;
>> +import java.net.*;
>> import java.util.Arrays;
>> import java.util.Collections;
>> import java.util.Enumeration;
>> 
>> -import
>> org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest;
>> -import org.apache.logging.log4j.junit.CleanFolders;
>> -import org.apache.logging.log4j.junit.URLStreamHandlerFactoryRule;
>> -import org.junit.Rule;
>> -import org.junit.Test;
>> -import org.junit.rules.RuleChain;
>> +import static org.junit.Assert.assertEquals;
>> 
>> /**
>>  * Tests the ResolverUtil class for custom protocol like bundleresource,
>> vfs, vfszip.
>> @@ -187,9 +181,9 @@ public class ResolverUtilCustomProtocolTest {
>>             final ResolverUtil resolverUtil = new ResolverUtil();
>>             resolverUtil
>>                     .setClassLoader(new SingleURLClassLoader(new
>> URL("vfs:/" + ResolverUtilTest.WORK_DIR + "/resolverutil3/customplugin3/"),
>> cl));
>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin3");
>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>> "customplugin3");
>>             assertEquals("Class not found in packages", 1,
>> resolverUtil.getClasses().size());
>> -            assertEquals("Unexpected class resolved",
>> cl.loadClass("customplugin3.FixedString3Layout"),
>> +            assertEquals("Unexpected class resolved",
>> cl.loadClass("customplugin3.FixedString3"),
>>                     resolverUtil.getClasses().iterator().next());
>>         }
>>     }
>> @@ -200,9 +194,9 @@ public class ResolverUtilCustomProtocolTest {
>>             final ResolverUtil resolverUtil = new ResolverUtil();
>>             resolverUtil.setClassLoader(new SingleURLClassLoader(
>>                     new URL("vfs:/" + ResolverUtilTest.WORK_DIR +
>> "/resolverutil4/customplugin4.jar/customplugin4/"), cl));
>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin4");
>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>> "customplugin4");
>>             assertEquals("Class not found in packages", 1,
>> resolverUtil.getClasses().size());
>> -            assertEquals("Unexpected class resolved",
>> cl.loadClass("customplugin4.FixedString4Layout"),
>> +            assertEquals("Unexpected class resolved",
>> cl.loadClass("customplugin4.FixedString4"),
>>                     resolverUtil.getClasses().iterator().next());
>>         }
>>     }
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>> similarity index 82%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>> index 1c6371b..361fe7b 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/util/ResolverUtilTest.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/util/ResolverUtilTest.java
>> @@ -15,33 +15,25 @@
>>  * limitations under the license.
>>  */
>> 
>> -package org.apache.logging.log4j.core.config.plugins.util;
>> +package org.apache.logging.log4j.plugins.util;
>> 
>> -import static org.junit.Assert.assertEquals;
>> -import static org.junit.Assert.assertTrue;
>> -
>> -import java.io.File;
>> -import java.io.IOException;
>> -import java.io.UnsupportedEncodingException;
>> -import java.net.MalformedURLException;
>> -import java.net.URI;
>> -import java.net.URISyntaxException;
>> -import java.net.URL;
>> -import java.net.URLClassLoader;
>> -import java.nio.file.FileSystem;
>> -import java.nio.file.FileSystems;
>> -import java.nio.file.Files;
>> -import java.nio.file.Path;
>> -import java.nio.file.StandardCopyOption;
>> -import java.util.HashMap;
>> -import java.util.Map;
>> -
>> -import
>> org.apache.logging.log4j.core.config.plugins.util.PluginRegistry.PluginTest;
>> import org.apache.logging.log4j.junit.CleanFolders;
>> import org.junit.Rule;
>> import org.junit.Test;
>> import org.junit.rules.RuleChain;
>> 
>> +import javax.tools.*;
>> +import java.io.File;
>> +import java.io.IOException;
>> +import java.io.UnsupportedEncodingException;
>> +import java.net.*;
>> +import java.nio.file.*;
>> +import java.util.*;
>> +
>> +import static org.junit.Assert.assertEquals;
>> +import static org.junit.Assert.assertTrue;
>> +import static org.junit.Assert.assertNotNull;
>> +
>> /**
>>  * Tests the ResolverUtil class.
>>  */
>> @@ -67,6 +59,7 @@ public class ResolverUtilTest {
>>     private void testExtractPathFromJarUrlNotDecodedIfFileExists(final
>> String existingFile)
>>             throws MalformedURLException, UnsupportedEncodingException,
>> URISyntaxException {
>>         URL url = ResolverUtilTest.class.getResource(existingFile);
>> +        assertNotNull("No url returned for " + existingFile, url);
>>         if (!url.getProtocol().equals("jar")) {
>>             // create fake jar: URL that resolves to existing file
>>             url = new URL("jar:" + url.toExternalForm() + "!/some/entry");
>> @@ -152,9 +145,9 @@ public class ResolverUtilTest {
>>         try (final URLClassLoader cl = compileAndCreateClassLoader("1")) {
>>             final ResolverUtil resolverUtil = new ResolverUtil();
>>             resolverUtil.setClassLoader(cl);
>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin1");
>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>> "customplugin1");
>>             assertEquals("Class not found in packages", 1,
>> resolverUtil.getClasses().size());
>> -            assertEquals("Unexpected class resolved",
>> cl.loadClass("customplugin1.FixedString1Layout"),
>> +            assertEquals("Unexpected class resolved",
>> cl.loadClass("customplugin1.FixedString1"),
>>                     resolverUtil.getClasses().iterator().next());
>>         }
>>     }
>> @@ -164,9 +157,9 @@ public class ResolverUtilTest {
>>         try (final URLClassLoader cl =
>> compileJarAndCreateClassLoader("2")) {
>>             final ResolverUtil resolverUtil = new ResolverUtil();
>>             resolverUtil.setClassLoader(cl);
>> -            resolverUtil.findInPackage(new PluginTest(), "customplugin2");
>> +            resolverUtil.findInPackage(new PluginRegistry.PluginTest(),
>> "customplugin2");
>>             assertEquals("Class not found in packages", 1,
>> resolverUtil.getClasses().size());
>> -            assertEquals("Unexpected class resolved",
>> cl.loadClass("customplugin2.FixedString2Layout"),
>> +            assertEquals("Unexpected class resolved",
>> cl.loadClass("customplugin2.FixedString2"),
>>                     resolverUtil.getClasses().iterator().next());
>>         }
>>     }
>> @@ -176,7 +169,7 @@ public class ResolverUtilTest {
>>         final File jarFile = new File(workDir, "customplugin" + suffix +
>> ".jar");
>>         final URI jarURI = jarFile.toURI();
>>         createJar(jarURI, workDir, new File(workDir,
>> -              "customplugin" + suffix + "/FixedString" + suffix +
>> "Layout.class"));
>> +              "customplugin" + suffix + "/FixedString" + suffix +
>> ".class"));
>>         return URLClassLoader.newInstance(new URL[] {jarURI.toURL()});
>>     }
>> 
>> @@ -186,9 +179,9 @@ public class ResolverUtilTest {
>>     }
>> 
>>     static File compile(final String suffix) throws IOException {
>> -        final File orig = new
>> File("target/test-classes/customplugin/FixedStringLayout.java.source");
>> +        final File orig = new
>> File("target/test-classes/customplugin/FixedString.java.source");
>>         final File workDir = new File(WORK_DIR, "resolverutil" + suffix);
>> -        final File f = new File(workDir, "customplugin" + suffix +
>> "/FixedString" + suffix + "Layout.java");
>> +        final File f = new File(workDir, "customplugin" + suffix +
>> "/FixedString" + suffix + ".java");
>>         final File parent = f.getParentFile();
>>         if (!parent.exists()) {
>>           assertTrue("Create customplugin" + suffix + " folder KO",
>> f.getParentFile().mkdirs());
>> @@ -199,7 +192,7 @@ public class ResolverUtilTest {
>>           .replaceAll("customplugin", "customplugin" + suffix);
>>         Files.write(f.toPath(), content.getBytes());
>> 
>> -        PluginManagerPackagesTest.compile(f);
>> +        compile(f);
>>         return workDir;
>>     }
>> 
>> @@ -218,4 +211,29 @@ public class ResolverUtilTest {
>>         }
>>     }
>> 
>> +    static void compile(final File f) throws IOException {
>> +        // set up compiler
>> +        final JavaCompiler compiler =
>> ToolProvider.getSystemJavaCompiler();
>> +        final DiagnosticCollector<JavaFileObject> diagnostics = new
>> DiagnosticCollector<>();
>> +        final List<String> errors = new ArrayList<>();
>> +        try (final StandardJavaFileManager fileManager =
>> compiler.getStandardFileManager(diagnostics, null, null)) {
>> +            final Iterable<? extends JavaFileObject> compilationUnits =
>> fileManager.getJavaFileObjectsFromFiles(Arrays
>> +                .asList(f));
>> +
>> +            // compile generated source
>> +            // (switch off annotation processing: no need to create
>> Log4j2Plugins.dat)
>> +            final List<String> options = Arrays.asList("-proc:none");
>> +            compiler.getTask(null, fileManager, diagnostics, options,
>> null, compilationUnits).call();
>> +
>> +            // check we don't have any compilation errors
>> +            for (final Diagnostic<? extends JavaFileObject> diagnostic :
>> diagnostics.getDiagnostics()) {
>> +                if (diagnostic.getKind() == Diagnostic.Kind.ERROR) {
>> +                    errors.add(String.format("Compile error at line %d,
>> column %d: %s%n", diagnostic.getLineNumber(),
>> +                        diagnostic.getColumnNumber(),
>> diagnostic.getMessage(Locale.getDefault())));
>> +                }
>> +            }
>> +        }
>> +        assertTrue(errors.toString(), errors.isEmpty());
>> +    }
>> +
>> }
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>> similarity index 87%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>> index 5689e29..0e243f2 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/AbstractPluginWithGenericBuilder.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/AbstractPluginWithGenericBuilder.java
>> @@ -14,10 +14,10 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> -import
>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>> 
>> /**
>>  *
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>> similarity index 78%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>> index 34123c0..626798e 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/HostAndPort.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/HostAndPort.java
>> @@ -14,15 +14,15 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> -import java.net.InetSocketAddress;
>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>> +import org.apache.logging.log4j.plugins.PluginFactory;
>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidHost;
>> +import org.apache.logging.log4j.plugins.validation.constraints.ValidPort;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
>> -import org.apache.logging.log4j.core.config.plugins.PluginFactory;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidHost;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.constraints.ValidPort;
>> +import java.net.InetSocketAddress;
>> 
>> @Plugin(name = "HostAndPort", category = "Test")
>> public class HostAndPort {
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>> similarity index 81%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>> index 3f2b15a..c3fe6c5 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/PluginWithGenericSubclassFoo1Builder.java
>> @@ -14,18 +14,18 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import
>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>> -import org.apache.logging.log4j.core.config.plugins.PluginBuilderFactory;
>> -import
>> org.apache.logging.log4j.core.config.plugins.validation.constraints.Required;
>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> 
>> @Plugin(name = "PluginWithGenericSubclassFoo1Builder", category = "Test")
>> public class PluginWithGenericSubclassFoo1Builder extends
>> AbstractPluginWithGenericBuilder {
>> 
>>     public static class Builder<B extends Builder<B>> extends
>> AbstractPluginWithGenericBuilder.Builder<B>
>> -            implements
>> org.apache.logging.log4j.core.util.Builder<PluginWithGenericSubclassFoo1Builder>
>> {
>> +            implements
>> org.apache.logging.log4j.plugins.util.Builder<PluginWithGenericSubclassFoo1Builder>
>> {
>> 
>>         @PluginBuilderFactory
>>         public static <B extends Builder<B>> B newBuilder() {
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>> similarity index 80%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>> index 95a4209..9caf453 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPlugin.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPlugin.java
>> @@ -14,15 +14,15 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> -import java.util.Objects;
>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>> +import org.apache.logging.log4j.plugins.PluginFactory;
>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import
>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>> -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.validation.constraints.Required;
>> +import java.util.Objects;
>> 
>> /**
>>  *
>> @@ -51,7 +51,7 @@ public class ValidatingPlugin {
>>         return new Builder();
>>     }
>> 
>> -    public static class Builder implements
>> org.apache.logging.log4j.core.util.Builder<ValidatingPlugin> {
>> +    public static class Builder implements
>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPlugin> {
>> 
>>         @PluginBuilderAttribute
>>         @Required(message = "The name given by the builder is null")
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>> similarity index 80%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>> index 81b9d6f..b0bec53 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithGenericBuilder.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithGenericBuilder.java
>> @@ -14,15 +14,16 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> -import java.util.Objects;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> +
>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>> +import org.apache.logging.log4j.plugins.PluginFactory;
>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import
>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>> -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.validation.constraints.Required;
>> +import java.util.Objects;
>> 
>> /**
>>  *
>> @@ -51,7 +52,7 @@ public class ValidatingPluginWithGenericBuilder {
>>         return new Builder<B>().asBuilder();
>>     }
>> 
>> -    public static class Builder<B extends Builder<B>> implements
>> org.apache.logging.log4j.core.util.Builder<ValidatingPluginWithGenericBuilder>
>> {
>> +    public static class Builder<B extends Builder<B>> implements
>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithGenericBuilder>
>> {
>> 
>>         @PluginBuilderAttribute
>>         @Required(message = "The name given by the builder is null")
>> diff --git
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>> similarity index 80%
>> rename from
>> log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>> rename to
>> log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>> index 74a6477..256181c 100644
>> ---
>> a/log4j-core/src/test/java/org/apache/logging/log4j/core/config/plugins/validation/ValidatingPluginWithTypedBuilder.java
>> +++
>> b/log4j-plugins/src/test/java/org/apache/logging/log4j/plugins/validation/ValidatingPluginWithTypedBuilder.java
>> @@ -14,15 +14,15 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.validation;
>> +package org.apache.logging.log4j.plugins.validation;
>> 
>> -import java.util.Objects;
>> +import org.apache.logging.log4j.plugins.PluginBuilderAttribute;
>> +import org.apache.logging.log4j.plugins.PluginBuilderFactory;
>> +import org.apache.logging.log4j.plugins.PluginFactory;
>> +import org.apache.logging.log4j.plugins.validation.constraints.Required;
>> +import org.apache.logging.log4j.plugins.Plugin;
>> 
>> -import org.apache.logging.log4j.core.config.plugins.Plugin;
>> -import
>> org.apache.logging.log4j.core.config.plugins.PluginBuilderAttribute;
>> -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.validation.constraints.Required;
>> +import java.util.Objects;
>> 
>> /**
>>  *
>> @@ -51,7 +51,7 @@ public class ValidatingPluginWithTypedBuilder {
>>         return new Builder<>();
>>     }
>> 
>> -    public static class Builder<T> implements
>> org.apache.logging.log4j.core.util.Builder<ValidatingPluginWithTypedBuilder>
>> {
>> +    public static class Builder<T> implements
>> org.apache.logging.log4j.plugins.util.Builder<ValidatingPluginWithTypedBuilder>
>> {
>> 
>>         @PluginBuilderAttribute
>>         @Required(message = "The name given by the builder is null")
>> diff --git
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>> b/log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>> similarity index 52%
>> rename from
>> log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>> rename to
>> log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>> index 15a162c..85a62ec 100644
>> ---
>> a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/plugins/convert/EnumConverter.java
>> +++ b/log4j-plugins/src/test/resources/customplugin/FixedString.java.source
>> @@ -14,25 +14,32 @@
>>  * See the license for the specific language governing permissions and
>>  * limitations under the license.
>>  */
>> -package org.apache.logging.log4j.core.config.plugins.convert;
>> 
>> -import org.apache.logging.log4j.util.EnglishEnums;
>> +package customplugin;
>> 
>> -/**
>> - * Converts a {@link String} into a {@link Enum}. Returns {@code null}
>> for invalid enum names.
>> - *
>> - * @param <E> the enum class to parse.
>> - * @since 2.1 moved from TypeConverters
>> - */
>> -public class EnumConverter<E extends Enum<E>> implements TypeConverter<E>
>> {
>> -    private final Class<E> clazz;
>> +import java.util.Collections;
>> +import java.util.Map;
>> +
>> +import org.apache.logging.log4j.plugins.Plugin;
>> +import org.apache.logging.log4j.plugins.PluginAttribute;
>> +import org.apache.logging.log4j.plugins.PluginFactory;
>> +
>> +@Plugin(name = "FixedString", category = "Core", elementType = "plugin",
>> printObject = true)
>> +public class FixedString  {
>> +
>> +    private String fixedString;
>> +
>> +    @PluginFactory
>> +    public static FixedString create(
>> +            @PluginAttribute("fixedString") final String fixedString) {
>> +        return new FixedString(fixedString);
>> +    }
>> 
>> -    public EnumConverter(final Class<E> clazz) {
>> -        this.clazz = clazz;
>> +    public FixedString(String fixedString) {
>> +        this.fixedString = fixedString;
>>     }
>> 
>> -    @Override
>> -    public E convert(final String s) {
>> -        return EnglishEnums.valueOf(clazz, s);
>> +    public Map<String, String> getContentFormat() {
>> +        return Collections.emptyMap();
>>     }
>> }
>> diff --git
>> a/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>> b/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>> new file mode 100644
>> index 0000000..b85475a
>> --- /dev/null
>> +++
>> b/log4j-plugins/src/test/resources/log4j+config+with+plus+characters.xml
>> @@ -0,0 +1,31 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<!--
>> + 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.
>> +
>> +-->
>> +<Configuration status="OFF" name="XMLConfigTest">
>> +
>> +  <Appenders>
>> +    <List name="List">
>> +    </List>
>> +  </Appenders>
>> +  <Loggers>
>> +    <Root level="trace">
>> +      <AppenderRef ref="List"/>
>> +    </Root>
>> +  </Loggers>
>> +
>> +</Configuration>
>> \ No newline at end of file
>> diff --git a/log4j-plugins/src/test/resources/s p a c e
>> s/log4j+config+with+plus+characters.xml
>> b/log4j-plugins/src/test/resources/s p a c e
>> s/log4j+config+with+plus+characters.xml
>> new file mode 100644
>> index 0000000..b85475a
>> --- /dev/null
>> +++ b/log4j-plugins/src/test/resources/s p a c e
>> s/log4j+config+with+plus+characters.xml
>> @@ -0,0 +1,31 @@
>> +<?xml version="1.0" encoding="UTF-8"?>
>> +<!--
>> + 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.
>> +
>> +-->
>> +<Configuration status="OFF" name="XMLConfigTest">
>> +
>> +  <Appenders>
>> +    <List name="List">
>> +    </List>
>> +  </Appenders>
>> +  <Loggers>
>> +    <Root level="trace">
>> +      <AppenderRef ref="List"/>
>> +    </Root>
>> +  </Loggers>
>> +
>> +</Configuration>
>> \ No newline at end of file
>> 
>>