You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rg...@apache.org on 2019/11/17 23:49:34 UTC

[logging-log4j2] branch release-2.x updated: LOG4J2-63 - Support Log4j 1 XML and Properties configurations

This is an automated email from the ASF dual-hosted git repository.

rgoers pushed a commit to branch release-2.x
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git


The following commit(s) were added to refs/heads/release-2.x by this push:
     new 57bfd48  LOG4J2-63 - Support Log4j 1 XML and Properties configurations
57bfd48 is described below

commit 57bfd4851c0e4f0d5d8df496bc5697d0743e7dfd
Author: Ralph Goers <rg...@apache.org>
AuthorDate: Sun Nov 17 16:49:21 2019 -0700

    LOG4J2-63 - Support Log4j 1 XML and Properties configurations
---
 .../org/apache/log4j/bridge/AppenderWrapper.java   |  21 +-
 .../org/apache/log4j/builders/AbstractBuilder.java |  58 ++
 .../org/apache/log4j/builders/BuilderManager.java  |  69 +-
 .../log4j/builders/appender/AppenderBuilder.java   |  11 +-
 .../builders/appender/ConsoleAppenderBuilder.java  |  66 +-
 .../appender/DailyRollingFileAppenderBuilder.java  |  88 ++-
 .../builders/appender/FileAppenderBuilder.java     |  87 ++-
 .../builders/appender/NullAppenderBuilder.java     |  14 +-
 .../appender/RollingFileAppenderBuilder.java       |  90 ++-
 .../builders/filter/DenyAllFilterBuilder.java      |  14 +-
 .../log4j/builders/filter/FilterBuilder.java       |   7 +-
 .../builders/filter/LevelMatchFilterBuilder.java   |  44 +-
 .../builders/filter/LevelRangeFilterBuilder.java   |  49 +-
 .../builders/filter/StringMatchFilterBuilder.java  |  37 +-
 .../log4j/builders/layout/HtmlLayoutBuilder.java   |  43 +-
 .../log4j/builders/layout/LayoutBuilder.java       |   6 +-
 .../builders/layout/PatternLayoutBuilder.java      |  70 +-
 .../log4j/builders/layout/SimpleLayoutBuilder.java |  18 +-
 .../log4j/builders/layout/TTCCLayoutBuilder.java   |  70 +-
 .../log4j/builders/layout/XmlLayoutBuilder.java    |  47 +-
 .../apache/log4j/config/Log4j1Configuration.java   |  14 +-
 .../log4j/config/PropertiesConfiguration.java      | 592 ++++++++++++++
 .../config/PropertiesConfigurationFactory.java     |  74 ++
 .../log4j/helpers/AppenderAttachableImpl.java      |  70 ++
 .../org/apache/log4j/helpers/OptionConverter.java  |  46 +-
 ...igurationFactory.java => XmlConfiguration.java} | 459 ++++-------
 .../apache/log4j/xml/XmlConfigurationFactory.java  | 868 +--------------------
 .../org/apache/log4j/config/AutoConfigTest.java    |   8 +-
 .../config/PropertiesConfigurationFactoryTest.java |  52 ++
 ...yTest.java => PropertiesConfigurationTest.java} |  35 +-
 .../log4j/config/XmlConfigurationFactoryTest.java  |  43 +-
 ...nFactoryTest.java => XmlConfigurationTest.java} |  31 +-
 .../src/test/resources/log4j1-file.properties      |  31 +
 .../src/test/resources/log4j1-list.properties      |  20 +
 .../log4j/core/config/ConfigurationFactory.java    |  28 +-
 .../logging/log4j/core/config/Configurator.java    |   5 +
 36 files changed, 1825 insertions(+), 1460 deletions(-)

diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
index f06f909..eb39fe7 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderWrapper.java
@@ -18,16 +18,26 @@ package org.apache.log4j.bridge;
 
 import org.apache.log4j.Appender;
 import org.apache.log4j.Layout;
+import org.apache.log4j.helpers.AppenderAttachableImpl;
+import org.apache.log4j.spi.AppenderAttachable;
 import org.apache.log4j.spi.ErrorHandler;
 import org.apache.log4j.spi.Filter;
 import org.apache.log4j.spi.LoggingEvent;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.filter.AbstractFilterable;
+import org.apache.logging.log4j.status.StatusLogger;
+
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
 
 /**
  * Holds a Log4j 2 Appender in an empty Log4j 1 Appender so it can be extracted when constructing the configuration.
  * Allows a Log4j 1 Appender to reference a Log4j 2 Appender.
  */
-public class AppenderWrapper implements Appender {
+public class AppenderWrapper extends AppenderAttachableImpl implements Appender {
 
+    private static final Logger LOGGER = StatusLogger.getLogger();
     private final org.apache.logging.log4j.core.Appender appender;
 
     public AppenderWrapper(org.apache.logging.log4j.core.Appender appender) {
@@ -40,6 +50,15 @@ public class AppenderWrapper implements Appender {
 
     @Override
     public void addFilter(Filter newFilter) {
+        if (appender instanceof AbstractFilterable) {
+            if (newFilter instanceof FilterWrapper) {
+                ((AbstractFilterable) appender).addFilter(((FilterWrapper) newFilter).getFilter());
+            } else {
+                ((AbstractFilterable) appender).addFilter(new FilterAdapter(newFilter));
+            }
+        } else {
+            LOGGER.warn("Unable to add filter to appender {}, it does not support filters", appender.getName());
+        }
     }
 
     @Override
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
new file mode 100644
index 0000000..d4e1b37
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/AbstractBuilder.java
@@ -0,0 +1,58 @@
+/*
+ * 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.log4j.builders;
+
+import java.util.Properties;
+
+/**
+ * Class Description goes here.
+ */
+public abstract class AbstractBuilder {
+
+    protected static final String FILE_PARAM = "File";
+    protected static final String APPEND_PARAM = "Append";
+    protected static final String BUFFERED_IO_PARAM = "BufferedIO";
+    protected static final String BUFFER_SIZE_PARAM = "BufferSize";
+    protected static final String MAX_SIZE_PARAM = "MaxFileSize";
+    protected static final String MAX_BACKUP_INDEX = "MaxBackupIndex";
+    protected static final String RELATIVE = "RELATIVE";
+
+    private final String prefix;
+    private final Properties props;
+
+    public AbstractBuilder() {
+        this.prefix = null;
+        this.props = new Properties();
+    }
+
+    public AbstractBuilder(String prefix, Properties props) {
+        this.prefix = prefix + ".";
+        this.props = props;
+    }
+
+    public String getProperty(String key) {
+        return props.getProperty(prefix + key);
+    }
+
+    public String getProperty(String key, String defaultValue) {
+        return props.getProperty(prefix + key, defaultValue);
+    }
+
+    public boolean getBooleanProperty(String key) {
+        return Boolean.parseBoolean(props.getProperty(prefix + key, Boolean.FALSE.toString()));
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
index c677513..5d571bb 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/BuilderManager.java
@@ -21,8 +21,9 @@ import org.apache.log4j.Layout;
 import org.apache.log4j.builders.appender.AppenderBuilder;
 import org.apache.log4j.builders.filter.FilterBuilder;
 import org.apache.log4j.builders.layout.LayoutBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 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;
@@ -30,8 +31,10 @@ import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.LoaderUtil;
 import org.w3c.dom.Element;
 
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.Map;
+import java.util.Properties;
 
 /**
  *
@@ -41,6 +44,7 @@ public class BuilderManager {
     public static final String CATEGORY = "Log4j Builder";
     private static final Logger LOGGER = StatusLogger.getLogger();
     private final Map<String, PluginType<?>> plugins;
+    private static Class<?>[] constructorParams = new Class[] { String.class, Properties.class};
 
     public BuilderManager() {
         final PluginManager manager = new PluginManager(CATEGORY);
@@ -48,13 +52,13 @@ public class BuilderManager {
         plugins = manager.getPlugins();
     }
 
-    public Appender parseAppender(String className, Element appenderElement, XmlConfigurationFactory factory) {
+    public Appender parseAppender(String className, Element appenderElement, XmlConfiguration config) {
         PluginType<?> plugin = plugins.get(className.toLowerCase());
         if (plugin != null) {
             try {
                 @SuppressWarnings("unchecked")
                 AppenderBuilder builder = (AppenderBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
-                return builder.parseAppender(appenderElement, factory);
+                return builder.parseAppender(appenderElement, config);
             } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
                 LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
             }
@@ -62,13 +66,25 @@ public class BuilderManager {
         return null;
     }
 
-    public Filter parseFilter(String className, Element filterElement, XmlConfigurationFactory factory) {
+    public Appender parseAppender(String name, String className, String prefix, String layoutPrefix,
+            String filterPrefix, Properties props, PropertiesConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            AppenderBuilder builder = createBuilder(plugin, prefix, props);
+            if (builder != null) {
+                return builder.parseAppender(name, layoutPrefix, filterPrefix, props, config);
+            }
+        }
+        return null;
+    }
+
+    public Filter parseFilter(String className, Element filterElement, XmlConfiguration config) {
         PluginType<?> plugin = plugins.get(className.toLowerCase());
         if (plugin != null) {
             try {
                 @SuppressWarnings("unchecked")
                 FilterBuilder builder = (FilterBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
-                return builder.parseFilter(filterElement, factory);
+                return builder.parseFilter(filterElement, config);
             } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
                 LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
             }
@@ -76,19 +92,58 @@ public class BuilderManager {
         return null;
     }
 
+    public Filter parseFilter(String className, String filterPrefix, Properties props, PropertiesConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            FilterBuilder builder = createBuilder(plugin, filterPrefix, props);
+            if (builder != null) {
+                return builder.parseFilter(config);
+            }
+        }
+        return null;
+    }
 
-    public Layout parseLayout(String className, Element layoutElement, XmlConfigurationFactory factory) {
+    public Layout parseLayout(String className, Element layoutElement, XmlConfiguration config) {
         PluginType<?> plugin = plugins.get(className.toLowerCase());
         if (plugin != null) {
             try {
                 @SuppressWarnings("unchecked")
                 LayoutBuilder builder = (LayoutBuilder) LoaderUtil.newInstanceOf(plugin.getPluginClass());
-                return builder.parseLayout(layoutElement, factory);
+                return builder.parseLayout(layoutElement, config);
             } catch (InstantiationException | IllegalAccessException | InvocationTargetException ex) {
                 LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
             }
         }
         return null;
     }
+    public Layout parseLayout(String className, String layoutPrefix, Properties props, PropertiesConfiguration config) {
+        PluginType<?> plugin = plugins.get(className.toLowerCase());
+        if (plugin != null) {
+            LayoutBuilder builder = createBuilder(plugin, layoutPrefix, props);
+            if (builder != null) {
+                return builder.parseLayout(config);
+            }
+        }
+        return null;
+    }
+
+    private <T extends AbstractBuilder> T createBuilder(PluginType<?> plugin, String prefix, Properties props) {
+        try {
+            Class<?> clazz = plugin.getPluginClass();
+            if (AbstractBuilder.class.isAssignableFrom(clazz)) {
+                @SuppressWarnings("unchecked")
+                Constructor<T> constructor =
+                        (Constructor<T>) clazz.getConstructor(constructorParams);
+                return constructor.newInstance(prefix, props);
+            } else {
+                @SuppressWarnings("unchecked")
+                T builder = (T) LoaderUtil.newInstanceOf(clazz);
+                return builder;
+            }
+        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException ex) {
+            LOGGER.warn("Unable to load plugin: {} due to: {}", plugin.getKey(), ex.getMessage());
+            return null;
+        }
+    }
 
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java
index 2b72efd..0572b86 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/AppenderBuilder.java
@@ -17,17 +17,20 @@
 package org.apache.log4j.builders.appender;
 
 import org.apache.log4j.Appender;
-import org.apache.log4j.xml.XmlConfigurationFactory;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.w3c.dom.Element;
 
-import java.util.function.BiFunction;
+import java.util.Properties;
 
 /**
  * Define an Appender Builder.
  */
 public interface AppenderBuilder {
 
-    Appender parseAppender(Element element, XmlConfigurationFactory factory);
+    Appender parseAppender(Element element, XmlConfiguration configuration);
+
+    Appender parseAppender(String name, String layoutPrefix, String filterPrefix, Properties props,
+            PropertiesConfiguration configuration);
 
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
index bfb7ff8..8c754bd 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/ConsoleAppenderBuilder.java
@@ -23,42 +23,60 @@ import org.apache.log4j.bridge.FilterAdapter;
 import org.apache.log4j.bridge.FilterWrapper;
 import org.apache.log4j.bridge.LayoutAdapter;
 import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.appender.ConsoleAppender;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
 
 /**
  * Build a Console Appender
  */
 @Plugin(name = "org.apache.log4j.ConsoleAppender", category = CATEGORY)
-public class ConsoleAppenderBuilder implements AppenderBuilder {
+public class ConsoleAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
     private static final String SYSTEM_OUT = "System.out";
     private static final String SYSTEM_ERR = "System.err";
     private static final String TARGET = "target";
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
+    public ConsoleAppenderBuilder() {
+    }
+
+    public ConsoleAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
     @Override
-    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
-        String name = appenderElement.getAttribute(XmlConfigurationFactory.NAME_ATTR);
+    public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
+        String name = appenderElement.getAttribute(NAME_ATTR);
         Holder<String> target = new Holder<>(SYSTEM_OUT);
         Holder<Layout> layout = new Holder<>();
         Holder<Filter> filter = new Holder<>();
         forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
             switch (currentElement.getTagName()) {
                 case LAYOUT_TAG:
-                    layout.set(factory.parseLayout(currentElement));
+                    layout.set(config.parseLayout(currentElement));
                     break;
                 case FILTER_TAG:
-                    filter.set(factory.parseFilters(currentElement));
+                    filter.set(config.parseFilters(currentElement));
                     break;
                 case PARAM_TAG: {
                     if (currentElement.getAttribute(NAME_ATTR).equalsIgnoreCase(TARGET)) {
@@ -83,29 +101,43 @@ public class ConsoleAppenderBuilder implements AppenderBuilder {
                 }
             }
         });
+        return createAppender(name, layout.get(), filter.get(), target.get(), config);
+    }
+
+    @Override
+    public Appender parseAppender(final String name, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String target = getProperty(TARGET);
+        return createAppender(name, layout, filter, target, configuration);
+    }
+
+    private <T extends Log4j1Configuration> Appender createAppender(String name, Layout layout, Filter filter,
+            String target, T configuration) {
         org.apache.logging.log4j.core.Layout<?> consoleLayout = null;
         org.apache.logging.log4j.core.Filter consoleFilter = null;
 
-        if (layout.get() instanceof LayoutWrapper) {
-            consoleLayout = ((LayoutWrapper) layout.get()).getLayout();
-        } else if (layout.get() != null) {
-            consoleLayout = new LayoutAdapter(layout.get());
+        if (layout instanceof LayoutWrapper) {
+            consoleLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            consoleLayout = new LayoutAdapter(layout);
         }
-        if (filter.get() != null) {
-            if (filter.get() instanceof FilterWrapper) {
-                consoleFilter = ((FilterWrapper) filter.get()).getFilter();
+        if (filter != null) {
+            if (filter instanceof FilterWrapper) {
+                consoleFilter = ((FilterWrapper) filter).getFilter();
             } else {
-                consoleFilter = new FilterAdapter(filter.get());
+                consoleFilter = new FilterAdapter(filter);
             }
         }
-        ConsoleAppender.Target consoleTarget = SYSTEM_ERR.equals(target.get())
+        ConsoleAppender.Target consoleTarget = SYSTEM_ERR.equals(target)
                 ? ConsoleAppender.Target.SYSTEM_ERR : ConsoleAppender.Target.SYSTEM_OUT;
         return new AppenderWrapper(ConsoleAppender.newBuilder()
                 .setName(name)
                 .setTarget(consoleTarget)
                 .setLayout(consoleLayout)
                 .setFilter(consoleFilter)
-                .setConfiguration(factory.getConfiguration())
+                .setConfiguration(configuration)
                 .build());
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
index 878020f..ae50e45 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/DailyRollingFileAppenderBuilder.java
@@ -23,12 +23,14 @@ import org.apache.log4j.bridge.FilterAdapter;
 import org.apache.log4j.bridge.FilterWrapper;
 import org.apache.log4j.bridge.LayoutAdapter;
 import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.core.appender.FileAppender;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
 import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
 import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
@@ -38,19 +40,35 @@ import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
 
 /**
  * Build a Daily Rolling File Appender
  */
 @Plugin(name = "org.apache.log4j.DailyRollingFileAppender", category = CATEGORY)
-public class DailyRollingFileAppenderBuilder implements AppenderBuilder {
+public class DailyRollingFileAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
+    public DailyRollingFileAppenderBuilder() {
+    }
+
+    public DailyRollingFileAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
+
     @Override
-    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+    public Appender parseAppender(final Element appenderElement, final XmlConfiguration config) {
         String name = appenderElement.getAttribute(NAME_ATTR);
         Holder<Layout> layout = new Holder<>();
         Holder<Filter> filter = new Holder<>();
@@ -62,13 +80,13 @@ public class DailyRollingFileAppenderBuilder implements AppenderBuilder {
         forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
             switch (currentElement.getTagName()) {
                 case LAYOUT_TAG:
-                    layout.set(factory.parseLayout(currentElement));
+                    layout.set(config.parseLayout(currentElement));
                     break;
                 case FILTER_TAG:
-                    filter.set(factory.parseFilters(currentElement));
+                    filter.set(config.parseFilters(currentElement));
                     break;
                 case PARAM_TAG: {
-                    switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
                         case FILE_PARAM:
                             fileName.set(currentElement.getAttribute(VALUE_ATTR));
                             break;
@@ -103,41 +121,63 @@ public class DailyRollingFileAppenderBuilder implements AppenderBuilder {
                 }
             }
         });
+        return createAppender(name, layout.get(), filter.get(), fileName.get(), append.get(), immediateFlush.get(),
+                bufferedIo.get(), bufferSize.get(), config);
+    }
+
+    @Override
+    public Appender parseAppender(final String name, final String layoutPrefix, final String filterPrefix,
+            final Properties props, final PropertiesConfiguration configuration) {
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String fileName = getProperty(FILE_PARAM);
+        boolean append = getBooleanProperty(APPEND_PARAM);
+        boolean immediateFlush = false;
+        boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
+        int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM, "8192"));
+        return createAppender(name, layout, filter, fileName, append, immediateFlush,
+                bufferedIo, bufferSize, configuration);
+    }
+
+    private <T extends Log4j1Configuration> Appender createAppender(final String name, final Layout layout,
+            final Filter filter, final String fileName, final boolean append, boolean immediateFlush,
+            final boolean bufferedIo, final int bufferSize, final T configuration) {
 
         org.apache.logging.log4j.core.Layout<?> fileLayout = null;
         org.apache.logging.log4j.core.Filter fileFilter = null;
-        if (bufferedIo.get()) {
-            immediateFlush.set(Boolean.TRUE);
+        if (bufferedIo) {
+            immediateFlush = true;
         }
-        if (layout.get() instanceof LayoutWrapper) {
-            fileLayout = ((LayoutWrapper) layout.get()).getLayout();
-        } else if (layout.get() != null) {
-            fileLayout = new LayoutAdapter(layout.get());
+        if (layout instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            fileLayout = new LayoutAdapter(layout);
         }
-        if (filter.get() != null) {
-            if (filter.get() instanceof FilterWrapper) {
-                fileFilter = ((FilterWrapper) filter.get()).getFilter();
+        if (filter != null) {
+            if (filter instanceof FilterWrapper) {
+                fileFilter = ((FilterWrapper) filter).getFilter();
             } else {
-                fileFilter = new FilterAdapter(filter.get());
+                fileFilter = new FilterAdapter(filter);
             }
         }
-        if (fileName.get() == null) {
+        if (fileName == null) {
             LOGGER.warn("Unable to create File Appender, no file name provided");
             return null;
         }
-        String filePattern = fileName.get() +"%d{yyy-MM-dd}";
+        String filePattern = fileName +"%d{yyy-MM-dd}";
         TriggeringPolicy policy = TimeBasedTriggeringPolicy.newBuilder().withModulate(true).build();
         RolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
-                .withConfig(factory.getConfiguration())
+                .withConfig(configuration)
                 .withMax(Integer.toString(Integer.MAX_VALUE))
                 .build();
         return new AppenderWrapper(RollingFileAppender.newBuilder()
                 .setName(name)
-                .setConfiguration(factory.getConfiguration())
+                .setConfiguration(configuration)
                 .setLayout(fileLayout)
                 .setFilter(fileFilter)
-                .withFileName(fileName.get())
-                .withImmediateFlush(immediateFlush.get())
+                .withFileName(fileName)
+                .withBufferSize(bufferSize)
+                .withImmediateFlush(immediateFlush)
                 .withFilePattern(filePattern)
                 .withPolicy(policy)
                 .withStrategy(strategy)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
index 4224c5d..76f2788 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/FileAppenderBuilder.java
@@ -23,29 +23,46 @@ import org.apache.log4j.bridge.FilterAdapter;
 import org.apache.log4j.bridge.FilterWrapper;
 import org.apache.log4j.bridge.LayoutAdapter;
 import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.appender.FileAppender;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
 
 /**
  * Build a File Appender
  */
 @Plugin(name = "org.apache.log4j.FileAppender", category = CATEGORY)
-public class FileAppenderBuilder implements AppenderBuilder {
+public class FileAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
+    public FileAppenderBuilder() {
+    }
+
+    public FileAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
     @Override
-    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+    public Appender parseAppender(Element appenderElement, XmlConfiguration config) {
         String name = appenderElement.getAttribute(NAME_ATTR);
         Holder<Layout> layout = new Holder<>();
         Holder<Filter> filter = new Holder<>();
@@ -57,13 +74,13 @@ public class FileAppenderBuilder implements AppenderBuilder {
         forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
             switch (currentElement.getTagName()) {
                 case LAYOUT_TAG:
-                    layout.set(factory.parseLayout(currentElement));
+                    layout.set(config.parseLayout(currentElement));
                     break;
                 case FILTER_TAG:
-                    filter.set(factory.parseFilters(currentElement));
+                    filter.set(config.parseFilters(currentElement));
                     break;
                 case PARAM_TAG: {
-                    switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
                         case FILE_PARAM:
                             fileName.set(currentElement.getAttribute(VALUE_ATTR));
                             break;
@@ -99,37 +116,59 @@ public class FileAppenderBuilder implements AppenderBuilder {
             }
         });
 
+        return createAppender(name, config, layout.get(), filter.get(), fileName.get(), immediateFlush.get(),
+                append.get(), bufferedIo.get(), bufferSize.get());
+    }
+
+
+    @Override
+    public Appender parseAppender(final String name, final String layoutPrefix, final String filterPrefix,
+            final Properties props, final PropertiesConfiguration configuration) {
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String fileName = getProperty(FILE_PARAM);
+        boolean append = getBooleanProperty(APPEND_PARAM);
+        boolean immediateFlush = false;
+        boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
+        int bufferSize = Integer.parseInt(getProperty(BUFFER_SIZE_PARAM, "8192"));
+        return createAppender(name, configuration, layout, filter, fileName, immediateFlush,
+                append, bufferedIo, bufferSize);
+    }
+
+    private Appender createAppender(final String name, final Log4j1Configuration configuration, final Layout layout,
+            final Filter filter, final String fileName, boolean immediateFlush, final boolean append,
+            final boolean bufferedIo, final int bufferSize) {
         org.apache.logging.log4j.core.Layout<?> fileLayout = null;
         org.apache.logging.log4j.core.Filter fileFilter = null;
-        if (bufferedIo.get()) {
-            immediateFlush.set(Boolean.TRUE);
+        if (bufferedIo) {
+            immediateFlush = true;
         }
-        if (layout.get() instanceof LayoutWrapper) {
-            fileLayout = ((LayoutWrapper) layout.get()).getLayout();
-        } else if (layout.get() != null) {
-            fileLayout = new LayoutAdapter(layout.get());
+        if (layout instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            fileLayout = new LayoutAdapter(layout);
         }
-        if (filter.get() != null) {
-            if (filter.get() instanceof FilterWrapper) {
-                fileFilter = ((FilterWrapper) filter.get()).getFilter();
+        if (filter != null) {
+            if (filter instanceof FilterWrapper) {
+                fileFilter = ((FilterWrapper) filter).getFilter();
             } else {
-                fileFilter = new FilterAdapter(filter.get());
+                fileFilter = new FilterAdapter(filter);
             }
         }
-        if (fileName.get() == null) {
+        if (fileName == null) {
             LOGGER.warn("Unable to create File Appender, no file name provided");
             return null;
         }
         return new AppenderWrapper(FileAppender.newBuilder()
                 .setName(name)
-                .setConfiguration(factory.getConfiguration())
+                .setConfiguration(configuration)
                 .setLayout(fileLayout)
                 .setFilter(fileFilter)
-                .withFileName(fileName.get())
-                .withImmediateFlush(immediateFlush.get())
-                .withAppend(append.get())
-                .withBufferedIo(bufferedIo.get())
-                .withBufferSize(bufferSize.get())
+                .withFileName(fileName)
+                .withImmediateFlush(immediateFlush)
+                .withAppend(append)
+                .withBufferedIo(bufferedIo)
+                .withBufferSize(bufferSize)
                 .build());
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java
index 857203e..b2b9eb6 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/NullAppenderBuilder.java
@@ -18,13 +18,16 @@ package org.apache.log4j.builders.appender;
 
 import org.apache.log4j.Appender;
 import org.apache.log4j.bridge.AppenderWrapper;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.appender.NullAppender;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
 
 /**
@@ -36,8 +39,15 @@ public class NullAppenderBuilder implements AppenderBuilder {
     private static final Logger LOGGER = StatusLogger.getLogger();
 
     @Override
-    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+    public Appender parseAppender(Element appenderElement, XmlConfiguration config) {
         String name = appenderElement.getAttribute("name");
         return new AppenderWrapper(NullAppender.createAppender(name));
     }
+
+
+    @Override
+    public Appender parseAppender(final String name, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        return new AppenderWrapper(NullAppender.createAppender(name));
+    }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
index 08a5129..d6e33c5 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/appender/RollingFileAppenderBuilder.java
@@ -23,10 +23,13 @@ import org.apache.log4j.bridge.FilterAdapter;
 import org.apache.log4j.bridge.FilterWrapper;
 import org.apache.log4j.bridge.LayoutAdapter;
 import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.appender.RollingFileAppender;
 import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
@@ -39,19 +42,34 @@ import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfiguration.FILTER_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.LAYOUT_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.NAME_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
+
 
 /**
  * Build a File Appender
  */
 @Plugin(name = "org.apache.log4j.RollingFileAppender", category = CATEGORY)
-public class RollingFileAppenderBuilder implements AppenderBuilder {
+public class RollingFileAppenderBuilder extends AbstractBuilder implements AppenderBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
+    public RollingFileAppenderBuilder() {
+    }
+
+    public RollingFileAppenderBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
     @Override
-    public Appender parseAppender(Element appenderElement, XmlConfigurationFactory factory) {
+    public Appender parseAppender(Element appenderElement, XmlConfiguration config) {
         String name = appenderElement.getAttribute(NAME_ATTR);
         Holder<Layout> layout = new Holder<>();
         Holder<Filter> filter = new Holder<>();
@@ -65,13 +83,13 @@ public class RollingFileAppenderBuilder implements AppenderBuilder {
         forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
             switch (currentElement.getTagName()) {
                 case LAYOUT_TAG:
-                    layout.set(factory.parseLayout(currentElement));
+                    layout.set(config.parseLayout(currentElement));
                     break;
                 case FILTER_TAG:
-                    filter.set(factory.parseFilters(currentElement));
+                    filter.set(config.parseFilters(currentElement));
                     break;
                 case PARAM_TAG: {
-                    switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                    switch (currentElement.getAttribute(NAME_ATTR)) {
                         case FILE_PARAM:
                             fileName.set(currentElement.getAttribute(VALUE_ATTR));
                             break;
@@ -125,43 +143,65 @@ public class RollingFileAppenderBuilder implements AppenderBuilder {
                 }
             }
         });
+        return createAppender(name, config, layout.get(), filter.get(), bufferedIo.get(), immediateFlush.get(),
+                fileName.get(), maxSize.get(), maxBackups.get());
+    }
+
+
+    @Override
+    public Appender parseAppender(final String name, final String layoutPrefix,
+            final String filterPrefix, final Properties props, final PropertiesConfiguration configuration) {
+        Layout layout = configuration.parseLayout(layoutPrefix, name, props);
+        Filter filter = configuration.parseAppenderFilters(props, filterPrefix, name);
+        String fileName = getProperty(FILE_PARAM);
+        boolean immediateFlush = false;
+        boolean bufferedIo = getBooleanProperty(BUFFERED_IO_PARAM);
+        String maxSize = getProperty(MAX_SIZE_PARAM);
+        String maxBackups = getProperty(MAX_BACKUP_INDEX);
+        return createAppender(name, configuration, layout, filter, bufferedIo, immediateFlush, fileName, maxSize,
+                maxBackups);
+    }
 
+    private Appender createAppender(final String name, final Log4j1Configuration config, final Layout layout,
+            final Filter filter, final boolean bufferedIo, boolean immediateFlush, final String fileName,
+            final String maxSize, final String maxBackups) {
         org.apache.logging.log4j.core.Layout<?> fileLayout = null;
         org.apache.logging.log4j.core.Filter fileFilter = null;
-        if (bufferedIo.get()) {
-            immediateFlush.set(Boolean.TRUE);
+        if (bufferedIo) {
+            immediateFlush = true;
         }
-        if (layout.get() instanceof LayoutWrapper) {
-            fileLayout = ((LayoutWrapper) layout.get()).getLayout();
-        } else if (layout.get() != null) {
-            fileLayout = new LayoutAdapter(layout.get());
+        if (layout instanceof LayoutWrapper) {
+            fileLayout = ((LayoutWrapper) layout).getLayout();
+        } else if (layout != null) {
+            fileLayout = new LayoutAdapter(layout);
         }
-        if (filter.get() != null) {
-            if (filter.get() instanceof FilterWrapper) {
-                fileFilter = ((FilterWrapper) filter.get()).getFilter();
+        if (filter != null) {
+            if (filter instanceof FilterWrapper) {
+                fileFilter = ((FilterWrapper) filter).getFilter();
             } else {
-                fileFilter = new FilterAdapter(filter.get());
+                fileFilter = new FilterAdapter(filter);
             }
         }
-        if (fileName.get() == null) {
+        if (fileName == null) {
             LOGGER.warn("Unable to create File Appender, no file name provided");
             return null;
         }
-        String filePattern = fileName.get() +"%d{yyy-MM-dd}";
+        String filePattern = fileName +"%d{yyy-MM-dd}";
         TriggeringPolicy timePolicy = TimeBasedTriggeringPolicy.newBuilder().withModulate(true).build();
-        SizeBasedTriggeringPolicy sizePolicy = SizeBasedTriggeringPolicy.createPolicy(maxSize.get());
+        SizeBasedTriggeringPolicy sizePolicy = SizeBasedTriggeringPolicy.createPolicy(maxSize);
         CompositeTriggeringPolicy policy = CompositeTriggeringPolicy.createPolicy(sizePolicy, timePolicy);
         RolloverStrategy strategy = DefaultRolloverStrategy.newBuilder()
-                .withConfig(factory.getConfiguration())
-                .withMax(maxBackups.get())
+                .withConfig(config)
+                .withMax(maxBackups)
                 .build();
         return new AppenderWrapper(RollingFileAppender.newBuilder()
                 .setName(name)
-                .setConfiguration(factory.getConfiguration())
+                .setConfiguration(config)
                 .setLayout(fileLayout)
                 .setFilter(fileFilter)
-                .withImmediateFlush(immediateFlush.get())
-                .withFileName(fileName.get())
+                .withBufferedIo(bufferedIo)
+                .withImmediateFlush(immediateFlush)
+                .withFileName(fileName)
                 .withFilePattern(filePattern)
                 .withPolicy(policy)
                 .withStrategy(strategy)
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java
index e942b34..c897500 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/DenyAllFilterBuilder.java
@@ -16,16 +16,13 @@
  */
 package org.apache.log4j.builders.filter;
 
-import org.apache.log4j.Layout;
 import org.apache.log4j.bridge.FilterWrapper;
-import org.apache.log4j.bridge.LayoutWrapper;
-import org.apache.log4j.builders.layout.LayoutBuilder;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.filter.DenyAllFilter;
-import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
@@ -40,7 +37,12 @@ public class DenyAllFilterBuilder implements FilterBuilder {
     private static final Logger LOGGER = StatusLogger.getLogger();
 
     @Override
-    public Filter parseFilter(Element filterElement, XmlConfigurationFactory factory) {
+    public Filter parseFilter(Element filterElement, XmlConfiguration config) {
+        return new FilterWrapper(DenyAllFilter.newBuilder().build());
+    }
+
+    @Override
+    public Filter parseFilter(PropertiesConfiguration config) {
         return new FilterWrapper(DenyAllFilter.newBuilder().build());
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
index fbeaefb..f26e7cb 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/FilterBuilder.java
@@ -16,8 +16,9 @@
  */
 package org.apache.log4j.builders.filter;
 
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.w3c.dom.Element;
 
 /**
@@ -25,6 +26,8 @@ import org.w3c.dom.Element;
  */
 public interface FilterBuilder {
 
-    Filter parseFilter(Element element, XmlConfigurationFactory factory);
+    Filter parseFilter(Element element, XmlConfiguration config);
+
+    Filter parseFilter(PropertiesConfiguration config);
 
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java
index b5df7ff..d7f85bb 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelMatchFilterBuilder.java
@@ -17,10 +17,12 @@
 package org.apache.log4j.builders.filter;
 
 import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
@@ -28,27 +30,36 @@ import org.apache.logging.log4j.core.filter.LevelMatchFilter;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
-import static org.apache.log4j.xml.XmlConfigurationFactory.VALUE_ATTR;
+import static org.apache.log4j.xml.XmlConfiguration.*;
+import static org.apache.log4j.xml.XmlConfiguration.VALUE_ATTR;
 
 /**
  * Build a Level match failter.
  */
 @Plugin(name = "org.apache.log4j.varia.LevelMatchFilter", category = CATEGORY)
-public class LevelMatchFilterBuilder implements FilterBuilder {
+public class LevelMatchFilterBuilder extends AbstractBuilder implements FilterBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
-    private static final String LEVEL = "level";
-    private static final String ACCEPT_ON_MATCH = "acceptonmatch";
+    private static final String LEVEL = "LevelToMatch";
+    private static final String ACCEPT_ON_MATCH = "AcceptOnMatch";
+
+    public LevelMatchFilterBuilder() {
+    }
+
+    public LevelMatchFilterBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
 
     @Override
-    public Filter parseFilter(Element filterElement, XmlConfigurationFactory factory) {
+    public Filter parseFilter(Element filterElement, XmlConfiguration config) {
         final Holder<String> level = new Holder<>();
         final Holder<Boolean> acceptOnMatch = new BooleanHolder();
         forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
             if (currentElement.getTagName().equals("param")) {
-                switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                switch (currentElement.getAttribute(NAME_ATTR)) {
                     case LEVEL:
                         level.set(currentElement.getAttribute(VALUE_ATTR));
                         break;
@@ -58,11 +69,22 @@ public class LevelMatchFilterBuilder implements FilterBuilder {
                 }
             }
         });
+        return createFilter(level.get(), acceptOnMatch.get());
+    }
+
+    @Override
+    public Filter parseFilter(PropertiesConfiguration config) {
+        String level = getProperty(LEVEL);
+        boolean acceptOnMatch = getBooleanProperty(ACCEPT_ON_MATCH);
+        return createFilter(level, acceptOnMatch);
+    }
+
+    private Filter createFilter(String level, boolean acceptOnMatch) {
         Level lvl = Level.ERROR;
-        if (level.get() != null) {
-            lvl = Level.toLevel(level.get(), Level.ERROR);
+        if (level != null) {
+            lvl = Level.toLevel(level, Level.ERROR);
         }
-        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch.get() != null && acceptOnMatch.get()
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch
                 ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
                 : org.apache.logging.log4j.core.Filter.Result.DENY;
         return new FilterWrapper(LevelMatchFilter.newBuilder()
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java
index 1082245..43ce0ec 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/LevelRangeFilterBuilder.java
@@ -17,10 +17,12 @@
 package org.apache.log4j.builders.filter;
 
 import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
@@ -29,28 +31,37 @@ import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfiguration.*;
 
 /**
  * Build a Level match failter.
  */
 @Plugin(name = "org.apache.log4j.varia.LevelRangeFilter", category = CATEGORY)
-public class LevelRangeFilterBuilder implements FilterBuilder {
+public class LevelRangeFilterBuilder extends AbstractBuilder implements FilterBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
-    private static final String LEVEL_MAX = "levelmax";
-    private static final String LEVEL_MIN = "levelmin";
-    private static final String ACCEPT_ON_MATCH = "acceptonmatch";
+    private static final String LEVEL_MAX = "LevelMax";
+    private static final String LEVEL_MIN = "LevelMin";
+    private static final String ACCEPT_ON_MATCH = "AcceptOnMatch";
+
+    public LevelRangeFilterBuilder() {
+    }
+
+    public LevelRangeFilterBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
 
     @Override
-    public Filter parseFilter(Element filterElement, XmlConfigurationFactory factory) {
+    public Filter parseFilter(Element filterElement, XmlConfiguration config) {
         final Holder<String> levelMax = new Holder<>();
         final Holder<String> levelMin = new Holder<>();
         final Holder<Boolean> acceptOnMatch = new BooleanHolder();
         forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
             if (currentElement.getTagName().equals("param")) {
-                switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                switch (currentElement.getAttribute(NAME_ATTR)) {
                     case LEVEL_MAX:
                         levelMax.set(currentElement.getAttribute(VALUE_ATTR));
                         break;
@@ -63,15 +74,27 @@ public class LevelRangeFilterBuilder implements FilterBuilder {
                 }
             }
         });
+        return createFilter(levelMax.get(), levelMin.get(), acceptOnMatch.get());
+    }
+
+    @Override
+    public Filter parseFilter(PropertiesConfiguration config) {
+        String levelMax = getProperty(LEVEL_MAX);
+        String levelMin = getProperty(LEVEL_MIN);
+        boolean acceptOnMatch = getBooleanProperty(ACCEPT_ON_MATCH);
+        return createFilter(levelMax, levelMin, acceptOnMatch);
+    }
+
+    private Filter createFilter(String levelMax, String levelMin, boolean acceptOnMatch) {
         Level max = Level.FATAL;
         Level min = Level.TRACE;
-        if (levelMax.get() != null) {
-            max = Level.toLevel(levelMax.get(), Level.FATAL);
+        if (levelMax != null) {
+            max = Level.toLevel(levelMax, Level.FATAL);
         }
-        if (levelMin.get() != null) {
-            min = Level.toLevel(levelMin.get(), Level.DEBUG);
+        if (levelMin != null) {
+            min = Level.toLevel(levelMin, Level.DEBUG);
         }
-        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch.get() != null && acceptOnMatch.get()
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch
                 ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
                 : org.apache.logging.log4j.core.Filter.Result.NEUTRAL;
 
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java
index 8e4f71a..4d2a453 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/filter/StringMatchFilterBuilder.java
@@ -17,38 +17,40 @@
 package org.apache.log4j.builders.filter;
 
 import org.apache.log4j.bridge.FilterWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
+import org.apache.log4j.config.PropertiesConfiguration;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.xml.XmlConfigurationFactory;
-import org.apache.logging.log4j.Level;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.filter.LevelMatchFilter;
 import org.apache.logging.log4j.core.filter.StringMatchFilter;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfiguration.*;
 
 /**
  * Build a String match filter.
  */
 @Plugin(name = "org.apache.log4j.varia.StringMatchFilter", category = CATEGORY)
-public class StringMatchFilterBuilder implements FilterBuilder {
+public class StringMatchFilterBuilder extends AbstractBuilder implements FilterBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
-    private static final String STRING_TO_MATCH = "stringtomatch";
-    private static final String ACCEPT_ON_MATCH = "acceptonmatch";
+    private static final String STRING_TO_MATCH = "StringToMatch";
+    private static final String ACCEPT_ON_MATCH = "AcceptOnMatch";
 
     @Override
-    public Filter parseFilter(Element filterElement, XmlConfigurationFactory factory) {
+    public Filter parseFilter(Element filterElement, XmlConfiguration config) {
         final Holder<Boolean> acceptOnMatch = new BooleanHolder();
         final Holder<String> text = new Holder<>();
         forEachElement(filterElement.getElementsByTagName("param"), (currentElement) -> {
             if (currentElement.getTagName().equals("param")) {
-                switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+                switch (currentElement.getAttribute(NAME_ATTR)) {
                     case STRING_TO_MATCH:
                         text.set(currentElement.getAttribute(VALUE_ATTR));
                         break;
@@ -59,15 +61,26 @@ public class StringMatchFilterBuilder implements FilterBuilder {
                 }
             }
         });
-        if (text.get() == null) {
+        return createFilter(text.get(), acceptOnMatch.get());
+    }
+
+    @Override
+    public Filter parseFilter(PropertiesConfiguration config) {
+        String text = getProperty(STRING_TO_MATCH);
+        boolean acceptOnMatch = getBooleanProperty(ACCEPT_ON_MATCH);
+        return createFilter(text, acceptOnMatch);
+    }
+
+    private Filter createFilter(String text, boolean acceptOnMatch) {
+        if (text == null) {
             LOGGER.warn("No text provided for StringMatchFilter");
             return null;
         }
-        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch.get() != null && acceptOnMatch.get()
+        org.apache.logging.log4j.core.Filter.Result onMatch = acceptOnMatch
                 ? org.apache.logging.log4j.core.Filter.Result.ACCEPT
                 : org.apache.logging.log4j.core.Filter.Result.DENY;
         return new FilterWrapper(StringMatchFilter.newBuilder()
-                .setMatchString(text.get())
+                .setMatchString(text)
                 .setOnMatch(onMatch)
                 .setOnMismatch(org.apache.logging.log4j.core.Filter.Result.NEUTRAL)
                 .build());
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
index 78b5f40..5f70a7b 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/HtmlLayoutBuilder.java
@@ -18,43 +18,68 @@ package org.apache.log4j.builders.layout;
 
 import org.apache.log4j.Layout;
 import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.layout.HtmlLayout;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfiguration.*;
 
 /**
  * Build a Pattern Layout
  */
 @Plugin(name = "org.apache.log4j.HTMLLayout", category = CATEGORY)
-public class HtmlLayoutBuilder implements LayoutBuilder {
+public class HtmlLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
+    private static final String TITLE = "Title";
+    private static final String LOCATION_INFO = "LocationInfo";
+
+    public HtmlLayoutBuilder() {
+    }
+
+    public HtmlLayoutBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
 
     @Override
-    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
         final Holder<String> title = new Holder<>();
         final Holder<Boolean> locationInfo = new BooleanHolder();
         forEachElement(layoutElement.getElementsByTagName("param"), (currentElement) -> {
-            if (currentElement.getTagName().equals("param")) {
-                if ("title".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+            if (currentElement.getTagName().equals(PARAM_TAG)) {
+                if (TITLE.equalsIgnoreCase(currentElement.getAttribute("name"))) {
                     title.set(currentElement.getAttribute("value"));
-                } else if ("locationInfo".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                } else if (LOCATION_INFO.equalsIgnoreCase(currentElement.getAttribute("name"))) {
                     locationInfo.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
                 }
             }
         });
+        return createLayout(title.get(), locationInfo.get());
+    }
+
+    @Override
+    public Layout parseLayout(PropertiesConfiguration config) {
+        String title = getProperty(TITLE);
+        boolean locationInfo = getBooleanProperty(LOCATION_INFO);
+        return createLayout(title, locationInfo);
+    }
+
+    private Layout createLayout(String title, boolean locationInfo) {
         return new LayoutWrapper(HtmlLayout.newBuilder()
-                .withTitle(title.get())
-                .withLocationInfo(locationInfo.get())
+                .withTitle(title)
+                .withLocationInfo(locationInfo)
                 .build());
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
index 9dc88f3..4f28284 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/LayoutBuilder.java
@@ -17,7 +17,8 @@
 package org.apache.log4j.builders.layout;
 
 import org.apache.log4j.Layout;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.w3c.dom.Element;
 
 /**
@@ -25,6 +26,7 @@ import org.w3c.dom.Element;
  */
 public interface LayoutBuilder {
 
-    Layout parseLayout(Element element, XmlConfigurationFactory factory);
+    Layout parseLayout(Element element, XmlConfiguration config);
 
+    Layout parseLayout(PropertiesConfiguration config);
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java
index b6a1964..264aa58 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/PatternLayoutBuilder.java
@@ -18,7 +18,10 @@ package org.apache.log4j.builders.layout;
 
 import org.apache.log4j.Layout;
 import org.apache.log4j.bridge.LayoutWrapper;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.builders.AbstractBuilder;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAliases;
@@ -28,19 +31,30 @@ import org.w3c.dom.Element;
 import org.w3c.dom.Node;
 import org.w3c.dom.NodeList;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
 
 /**
  * Build a Pattern Layout
  */
 @Plugin(name = "org.apache.log4j.PatternLayout", category = CATEGORY)
 @PluginAliases("org.apache.log4j.EnhancedPatternLayout")
-public class PatternLayoutBuilder implements LayoutBuilder {
+public class PatternLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String PATTERN = "ConversionPattern";
+
+    public PatternLayoutBuilder() {
+    }
+
+    public PatternLayoutBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
 
     @Override
-    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+    public Layout parseLayout(final Element layoutElement, final XmlConfiguration config) {
         NodeList params = layoutElement.getElementsByTagName("param");
         final int length = params.getLength();
         String pattern = null;
@@ -48,30 +62,44 @@ public class PatternLayoutBuilder implements LayoutBuilder {
             Node currentNode = params.item(index);
             if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
                 Element currentElement = (Element) currentNode;
-                if (currentElement.getTagName().equals("param")) {
-                    if ("conversionPattern".equalsIgnoreCase(currentElement.getAttribute("name"))) {
-                        pattern = currentElement.getAttribute("value")
-                                // Log4j 2's %x (NDC) is not compatible with Log4j 1's
-                                // %x
-                                // Log4j 1: "foo bar baz"
-                                // Log4j 2: "[foo, bar, baz]"
-                                // Use %ndc to get the Log4j 1 format
-                                .replace("%x", "%ndc")
-
-                                // Log4j 2's %X (MDC) is not compatible with Log4j 1's
-                                // %X
-                                // Log4j 1: "{{foo,bar}{hoo,boo}}"
-                                // Log4j 2: "{foo=bar,hoo=boo}"
-                                // Use %properties to get the Log4j 1 format
-                                .replace("%X", "%properties");
+                if (currentElement.getTagName().equals(PARAM_TAG)) {
+                    if (PATTERN.equalsIgnoreCase(currentElement.getAttribute("name"))) {
+                        pattern = currentElement.getAttribute("value");
                         break;
                     }
                 }
             }
         }
+        return createLayout(pattern, config);
+    }
+
+    @Override
+    public Layout parseLayout(final PropertiesConfiguration config) {
+        String pattern = getProperty(PATTERN);
+        return createLayout(pattern, config);
+    }
+
+    private Layout createLayout(String pattern, final Log4j1Configuration config) {
+        if (pattern == null) {
+            LOGGER.info("No pattern provided for pattern layout, using default pattern");
+            pattern = PatternLayout.DEFAULT_CONVERSION_PATTERN;
+        }
         return new LayoutWrapper(PatternLayout.newBuilder()
-                .withPattern(pattern)
-                .withConfiguration(factory.getConfiguration())
+                .withPattern(pattern
+                        // Log4j 2's %x (NDC) is not compatible with Log4j 1's
+                        // %x
+                        // Log4j 1: "foo bar baz"
+                        // Log4j 2: "[foo, bar, baz]"
+                        // Use %ndc to get the Log4j 1 format
+                        .replace("%x", "%ndc")
+
+                        // Log4j 2's %X (MDC) is not compatible with Log4j 1's
+                        // %X
+                        // Log4j 1: "{{foo,bar}{hoo,boo}}"
+                        // Log4j 2: "{foo=bar,hoo=boo}"
+                        // Use %properties to get the Log4j 1 format
+                        .replace("%X", "%properties"))
+                .withConfiguration(config)
                 .build());
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java
index 4f09bc2..efdc9bd 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/SimpleLayoutBuilder.java
@@ -18,15 +18,17 @@ package org.apache.log4j.builders.layout;
 
 import org.apache.log4j.Layout;
 import org.apache.log4j.bridge.LayoutWrapper;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
 
 /**
  * Build a Pattern Layout
@@ -37,10 +39,18 @@ public class SimpleLayoutBuilder implements LayoutBuilder {
     private static final Logger LOGGER = StatusLogger.getLogger();
 
     @Override
-    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
+        return new LayoutWrapper(PatternLayout.newBuilder()
+                .withPattern("%level - %m%n")
+                .withConfiguration(config)
+                .build());
+    }
+
+    @Override
+    public Layout parseLayout(PropertiesConfiguration config) {
         return new LayoutWrapper(PatternLayout.newBuilder()
                 .withPattern("%level - %m%n")
-                .withConfiguration(factory.getConfiguration())
+                .withConfiguration(config)
                 .build());
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java
index b15d351..583f8b7 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/TTCCLayoutBuilder.java
@@ -18,42 +18,54 @@ package org.apache.log4j.builders.layout;
 
 import org.apache.log4j.Layout;
 import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.config.Log4j1Configuration;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.layout.PatternLayout;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.*;
+import static org.apache.log4j.xml.XmlConfiguration.*;
 
 /**
  * Build a Pattern Layout
  */
 @Plugin(name = "org.apache.log4j.TTCCLayout", category = CATEGORY)
-public class TTCCLayoutBuilder implements LayoutBuilder {
+public class TTCCLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
-    private static final String THREAD_PRINTING_PARAM = "threadprinting";
-    private static final String CATEGORY_PREFIXING_PARAM = "categoryprefixing";
-    private static final String CONTEXT_PRINTING_PARAM = "contextprinting";
-    private static final String DATE_FORMAT_PARAM = "dateformat";
-    private static final String TIMEZONE_FORMAT = "timezone";
+    private static final String THREAD_PRINTING_PARAM = "ThreadPrinting";
+    private static final String CATEGORY_PREFIXING_PARAM = "CategoryPrefixing";
+    private static final String CONTEXT_PRINTING_PARAM = "ContextPrinting";
+    private static final String DATE_FORMAT_PARAM = "DateFormat";
+    private static final String TIMEZONE_FORMAT = "TimeZone";
+
+    public TTCCLayoutBuilder() {
+    }
+
+    public TTCCLayoutBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
 
     @Override
-    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
         final Holder<Boolean> threadPrinting = new BooleanHolder();
         final Holder<Boolean> categoryPrefixing = new BooleanHolder();
         final Holder<Boolean> contextPrinting = new BooleanHolder();
         final Holder<String> dateFormat = new Holder<>();
         final Holder<String> timezone = new Holder<>();
         forEachElement(layoutElement.getElementsByTagName("param"), (currentElement) -> {
-            if (currentElement.getTagName().equals("param")) {
-                switch (currentElement.getAttribute(NAME_ATTR).toLowerCase()) {
+            if (currentElement.getTagName().equals(PARAM_TAG)) {
+                switch (currentElement.getAttribute(NAME_ATTR)) {
                     case THREAD_PRINTING_PARAM:
                         threadPrinting.set(Boolean.parseBoolean(currentElement.getAttribute(VALUE_ATTR)));
                         break;
@@ -72,32 +84,50 @@ public class TTCCLayoutBuilder implements LayoutBuilder {
                 }
             }
         });
+        return createLayout(threadPrinting.get(), categoryPrefixing.get(), contextPrinting.get(),
+                dateFormat.get(), timezone.get(), config);
+    }
+
+    @Override
+    public Layout parseLayout(PropertiesConfiguration config) {
+        boolean threadPrinting = getBooleanProperty(THREAD_PRINTING_PARAM);
+        boolean categoryPrefixing = getBooleanProperty(CATEGORY_PREFIXING_PARAM);
+        boolean contextPrinting = getBooleanProperty(CONTEXT_PRINTING_PARAM);
+        String dateFormat = getProperty(DATE_FORMAT_PARAM);
+        String timezone = getProperty(TIMEZONE_FORMAT);
+
+        return createLayout(threadPrinting, categoryPrefixing, contextPrinting,
+                dateFormat, timezone, config);
+    }
+
+    private Layout createLayout(boolean threadPrinting, boolean categoryPrefixing, boolean contextPrinting,
+            String dateFormat, String timezone, Log4j1Configuration config) {
         StringBuilder sb = new StringBuilder();
-        if (dateFormat.get() != null) {
-            if (RELATIVE.equalsIgnoreCase(dateFormat.get())) {
+        if (dateFormat != null) {
+            if (RELATIVE.equalsIgnoreCase(dateFormat)) {
                 sb.append("%r ");
             } else {
-                sb.append("%d{").append(dateFormat.get()).append("}");
-                if (timezone.get() != null) {
-                    sb.append("{").append(timezone.get()).append("}");
+                sb.append("%d{").append(dateFormat).append("}");
+                if (timezone != null) {
+                    sb.append("{").append(timezone).append("}");
                 }
                 sb.append(" ");
             }
         }
-        if (threadPrinting.get()) {
+        if (threadPrinting) {
             sb.append("[%t] ");
         }
         sb.append("%p ");
-        if (categoryPrefixing.get()) {
+        if (categoryPrefixing) {
             sb.append("%c ");
         }
-        if (contextPrinting.get()) {
+        if (contextPrinting) {
             sb.append("%notEmpty{%ndc }");
         }
         sb.append("- %m%n");
         return new LayoutWrapper(PatternLayout.newBuilder()
                 .withPattern(sb.toString())
-                .withConfiguration(factory.getConfiguration())
+                .withConfiguration(config)
                 .build());
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java
index 5436e5c..89d2dca 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/builders/layout/XmlLayoutBuilder.java
@@ -18,42 +18,67 @@ package org.apache.log4j.builders.layout;
 
 import org.apache.log4j.Layout;
 import org.apache.log4j.bridge.LayoutWrapper;
+import org.apache.log4j.builders.AbstractBuilder;
 import org.apache.log4j.builders.BooleanHolder;
 import org.apache.log4j.builders.Holder;
-import org.apache.log4j.xml.XmlConfigurationFactory;
+import org.apache.log4j.config.PropertiesConfiguration;
+import org.apache.log4j.xml.XmlConfiguration;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.layout.HtmlLayout;
 import org.apache.logging.log4j.core.layout.XmlLayout;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.w3c.dom.Element;
 
+import java.util.Properties;
+
 import static org.apache.log4j.builders.BuilderManager.CATEGORY;
-import static org.apache.log4j.xml.XmlConfigurationFactory.forEachElement;
+import static org.apache.log4j.xml.XmlConfiguration.PARAM_TAG;
+import static org.apache.log4j.xml.XmlConfiguration.forEachElement;
 
 /**
- * Build a Pattern Layout
+ * Build an XML Layout
  */
 @Plugin(name = "org.apache.log4j.xml.XMLLayout", category = CATEGORY)
-public class XmlLayoutBuilder implements LayoutBuilder {
+public class XmlLayoutBuilder extends AbstractBuilder implements LayoutBuilder {
 
     private static final Logger LOGGER = StatusLogger.getLogger();
 
+    private static final String LOCATION_INFO = "LocationInfo";
+    private static final String PROPERTIES = "Properties";
+
+    public XmlLayoutBuilder() {
+    }
+
+    public XmlLayoutBuilder(String prefix, Properties props) {
+        super(prefix, props);
+    }
+
 
     @Override
-    public Layout parseLayout(Element layoutElement, XmlConfigurationFactory factory) {
+    public Layout parseLayout(Element layoutElement, XmlConfiguration config) {
         final Holder<Boolean> properties = new BooleanHolder();
         final Holder<Boolean> locationInfo = new BooleanHolder();
-        forEachElement(layoutElement.getElementsByTagName("param"), (currentElement) -> {
-            if ("properties".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+        forEachElement(layoutElement.getElementsByTagName(PARAM_TAG), (currentElement) -> {
+            if (PROPERTIES.equalsIgnoreCase(currentElement.getAttribute("name"))) {
                 properties.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
-            } else if ("locationInfo".equalsIgnoreCase(currentElement.getAttribute("name"))) {
+            } else if (LOCATION_INFO.equalsIgnoreCase(currentElement.getAttribute("name"))) {
                 locationInfo.set(Boolean.parseBoolean(currentElement.getAttribute("value")));
             }
         });
+        return createLayout(properties.get(), locationInfo.get());
+    }
+
+    @Override
+    public Layout parseLayout(PropertiesConfiguration config) {
+        boolean properties = getBooleanProperty(PROPERTIES);
+        boolean locationInfo = getBooleanProperty(LOCATION_INFO);
+        return createLayout(properties, locationInfo);
+    }
+
+    private Layout createLayout(boolean properties, boolean locationInfo) {
         return new LayoutWrapper(XmlLayout.newBuilder()
-                .setLocationInfo(locationInfo.get())
-                .setProperties(properties.get())
+                .setLocationInfo(locationInfo)
+                .setProperties(properties)
                 .build());
     }
 }
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
index 5a6b50d..ffa45d8 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1Configuration.java
@@ -28,23 +28,25 @@ import org.apache.logging.log4j.core.config.Reconfigurable;
  */
 public class Log4j1Configuration extends AbstractConfiguration implements Reconfigurable {
 
+    public static final String MONITOR_INTERVAL = "log4j1.monitorInterval";
+
+    public static final String INHERITED = "inherited";
+
+    public static final String NULL = "null";
+
     public Log4j1Configuration(final LoggerContext loggerContext, final ConfigurationSource source,
             int monitorIntervalSeconds) {
         super(loggerContext, source);
         initializeWatchers(this, source, monitorIntervalSeconds);
     }
 
-    @Override
-    protected void doConfigure() {
-        super.getScheduler().start();
-
-    }
-
     /**
      * Initialize the configuration.
      */
     @Override
     public void initialize() {
+        getStrSubstitutor().setConfiguration(this);
+        super.getScheduler().start();
         doConfigure();
         setState(State.INITIALIZED);
         LOGGER.debug("Configuration {} initialized", this);
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
new file mode 100644
index 0000000..0152d4a
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfiguration.java
@@ -0,0 +1,592 @@
+/*
+ * 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.log4j.config;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.Layout;
+import org.apache.log4j.LogManager;
+import org.apache.log4j.PatternLayout;
+import org.apache.log4j.bridge.AppenderAdapter;
+import org.apache.log4j.bridge.AppenderWrapper;
+import org.apache.log4j.builders.BuilderManager;
+import org.apache.log4j.helpers.OptionConverter;
+import org.apache.log4j.spi.ErrorHandler;
+import org.apache.log4j.spi.Filter;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.LoggerConfig;
+import org.apache.logging.log4j.core.config.status.StatusConfiguration;
+import org.apache.logging.log4j.core.filter.AbstractFilterable;
+import org.apache.logging.log4j.util.LoaderUtil;
+
+import java.io.InputStream;
+import java.lang.reflect.InvocationTargetException;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.SortedMap;
+import java.util.StringTokenizer;
+import java.util.TreeMap;
+
+/**
+ * Construct a configuration based on Log4j 1 properties.
+ */
+public class PropertiesConfiguration  extends Log4j1Configuration {
+
+    private static final String CATEGORY_PREFIX = "log4j.category.";
+    private static final String LOGGER_PREFIX = "log4j.logger.";
+    private static final String ADDITIVITY_PREFIX = "log4j.additivity.";
+    private static final String ROOT_CATEGORY_PREFIX = "log4j.rootCategory";
+    private static final String ROOT_LOGGER_PREFIX = "log4j.rootLogger";
+    private static final String APPENDER_PREFIX = "log4j.appender.";
+    private static final String LOGGER_REF	= "logger-ref";
+    private static final String ROOT_REF		= "root-ref";
+    private static final String APPENDER_REF_TAG = "appender-ref";
+    public static final long DEFAULT_DELAY = 60000;
+    public static final String DEBUG_KEY="log4j.debug";
+
+    private static final String INTERNAL_ROOT_NAME = "root";
+
+    private final Map<String, Appender> registry;
+
+    private final BuilderManager manager;
+
+    /**
+     * No argument constructor.
+     */
+    public PropertiesConfiguration(final LoggerContext loggerContext, final ConfigurationSource source,
+            int monitorIntervalSeconds) {
+        super(loggerContext, source, monitorIntervalSeconds);
+        registry = new HashMap<>();
+        manager = new BuilderManager();
+    }
+
+    public void doConfigure() {
+        InputStream is = getConfigurationSource().getInputStream();
+        Properties props = new Properties();
+        try {
+            props.load(is);
+        } catch (Exception e) {
+            LOGGER.error("Could not read configuration file [{}].", getConfigurationSource().toString(), e);
+            return;
+        }
+        // If we reach here, then the config file is alright.
+        doConfigure(props);
+    }
+
+    /**
+     * Read configuration from a file. <b>The existing configuration is
+     * not cleared nor reset.</b> If you require a different behavior,
+     * then call {@link  LogManager#resetConfiguration
+     * resetConfiguration} method before calling
+     * <code>doConfigure</code>.
+     *
+     * <p>The configuration file consists of statements in the format
+     * <code>key=value</code>. The syntax of different configuration
+     * elements are discussed below.
+     *
+     * <p>The level value can consist of the string values OFF, FATAL,
+     * ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
+     * custom level value can be specified in the form
+     * level#classname. By default the repository-wide threshold is set
+     * to the lowest possible value, namely the level <code>ALL</code>.
+     * </p>
+     *
+     *
+     * <h3>Appender configuration</h3>
+     *
+     * <p>Appender configuration syntax is:
+     * <pre>
+     * # For appender named <i>appenderName</i>, set its class.
+     * # Note: The appender name can contain dots.
+     * log4j.appender.appenderName=fully.qualified.name.of.appender.class
+     *
+     * # Set appender specific options.
+     * log4j.appender.appenderName.option1=value1
+     * ...
+     * log4j.appender.appenderName.optionN=valueN
+     * </pre>
+     * <p>
+     * For each named appender you can configure its {@link Layout}. The
+     * syntax for configuring an appender's layout is:
+     * <pre>
+     * log4j.appender.appenderName.layout=fully.qualified.name.of.layout.class
+     * log4j.appender.appenderName.layout.option1=value1
+     * ....
+     * log4j.appender.appenderName.layout.optionN=valueN
+     * </pre>
+     * <p>
+     * The syntax for adding {@link Filter}s to an appender is:
+     * <pre>
+     * log4j.appender.appenderName.filter.ID=fully.qualified.name.of.filter.class
+     * log4j.appender.appenderName.filter.ID.option1=value1
+     * ...
+     * log4j.appender.appenderName.filter.ID.optionN=valueN
+     * </pre>
+     * The first line defines the class name of the filter identified by ID;
+     * subsequent lines with the same ID specify filter option - value
+     * pairs. Multiple filters are added to the appender in the lexicographic
+     * order of IDs.
+     * <p>
+     * The syntax for adding an {@link ErrorHandler} to an appender is:
+     * <pre>
+     * log4j.appender.appenderName.errorhandler=fully.qualified.name.of.errorhandler.class
+     * log4j.appender.appenderName.errorhandler.appender-ref=appenderName
+     * log4j.appender.appenderName.errorhandler.option1=value1
+     * ...
+     * log4j.appender.appenderName.errorhandler.optionN=valueN
+     * </pre>
+     *
+     * <h3>Configuring loggers</h3>
+     *
+     * <p>The syntax for configuring the root logger is:
+     * <pre>
+     * log4j.rootLogger=[level], appenderName, appenderName, ...
+     * </pre>
+     *
+     * <p>This syntax means that an optional <em>level</em> can be
+     * supplied followed by appender names separated by commas.
+     *
+     * <p>The level value can consist of the string values OFF, FATAL,
+     * ERROR, WARN, INFO, DEBUG, ALL or a <em>custom level</em> value. A
+     * custom level value can be specified in the form
+     * <code>level#classname</code>.
+     *
+     * <p>If a level value is specified, then the root level is set
+     * to the corresponding level.  If no level value is specified,
+     * then the root level remains untouched.
+     *
+     * <p>The root logger can be assigned multiple appenders.
+     *
+     * <p>Each <i>appenderName</i> (separated by commas) will be added to
+     * the root logger. The named appender is defined using the
+     * appender syntax defined above.
+     *
+     * <p>For non-root categories the syntax is almost the same:
+     * <pre>
+     * log4j.logger.logger_name=[level|INHERITED|NULL], appenderName, appenderName, ...
+     * </pre>
+     *
+     * <p>The meaning of the optional level value is discussed above
+     * in relation to the root logger. In addition however, the value
+     * INHERITED can be specified meaning that the named logger should
+     * inherit its level from the logger hierarchy.
+     *
+     * <p>If no level value is supplied, then the level of the
+     * named logger remains untouched.
+     *
+     * <p>By default categories inherit their level from the
+     * hierarchy. However, if you set the level of a logger and later
+     * decide that that logger should inherit its level, then you should
+     * specify INHERITED as the value for the level value. NULL is a
+     * synonym for INHERITED.
+     *
+     * <p>Similar to the root logger syntax, each <i>appenderName</i>
+     * (separated by commas) will be attached to the named logger.
+     *
+     * <p>See the <a href="../../../../manual.html#additivity">appender
+     * additivity rule</a> in the user manual for the meaning of the
+     * <code>additivity</code> flag.
+     *
+     *
+     * # Set options for appender named "A1".
+     * # Appender "A1" will be a SyslogAppender
+     * log4j.appender.A1=org.apache.log4j.net.SyslogAppender
+     *
+     * # The syslog daemon resides on www.abc.net
+     * log4j.appender.A1.SyslogHost=www.abc.net
+     *
+     * # A1's layout is a PatternLayout, using the conversion pattern
+     * # <b>%r %-5p %c{2} %M.%L %x - %m\n</b>. Thus, the log output will
+     * # include # the relative time since the start of the application in
+     * # milliseconds, followed by the level of the log request,
+     * # followed by the two rightmost components of the logger name,
+     * # followed by the callers method name, followed by the line number,
+     * # the nested diagnostic context and finally the message itself.
+     * # Refer to the documentation of {@link PatternLayout} for further information
+     * # on the syntax of the ConversionPattern key.
+     * log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+     * log4j.appender.A1.layout.ConversionPattern=%-4r %-5p %c{2} %M.%L %x - %m\n
+     *
+     * # Set options for appender named "A2"
+     * # A2 should be a RollingFileAppender, with maximum file size of 10 MB
+     * # using at most one backup file. A2's layout is TTCC, using the
+     * # ISO8061 date format with context printing enabled.
+     * log4j.appender.A2=org.apache.log4j.RollingFileAppender
+     * log4j.appender.A2.MaxFileSize=10MB
+     * log4j.appender.A2.MaxBackupIndex=1
+     * log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
+     * log4j.appender.A2.layout.ContextPrinting=enabled
+     * log4j.appender.A2.layout.DateFormat=ISO8601
+     *
+     * # Root logger set to DEBUG using the A2 appender defined above.
+     * log4j.rootLogger=DEBUG, A2
+     *
+     * # Logger definitions:
+     * # The SECURITY logger inherits is level from root. However, it's output
+     * # will go to A1 appender defined above. It's additivity is non-cumulative.
+     * log4j.logger.SECURITY=INHERIT, A1
+     * log4j.additivity.SECURITY=false
+     *
+     * # Only warnings or above will be logged for the logger "SECURITY.access".
+     * # Output will go to A1.
+     * log4j.logger.SECURITY.access=WARN
+     *
+     *
+     * # The logger "class.of.the.day" inherits its level from the
+     * # logger hierarchy.  Output will go to the appender's of the root
+     * # logger, A2 in this case.
+     * log4j.logger.class.of.the.day=INHERIT
+     * </pre>
+     *
+     * <p>Refer to the <b>setOption</b> method in each Appender and
+     * Layout for class specific options.
+     *
+     * <p>Use the <code>#</code> or <code>!</code> characters at the
+     * beginning of a line for comments.
+     *
+     * <p>
+     */
+    private void doConfigure(Properties properties) {
+        String status = "error";
+        String value = properties.getProperty(DEBUG_KEY);
+        if (value == null) {
+            value = properties.getProperty("log4j.configDebug");
+            if (value != null) {
+                LOGGER.warn("[log4j.configDebug] is deprecated. Use [log4j.debug] instead.");
+            }
+        }
+
+        if (value != null) {
+            status = OptionConverter.toBoolean(value, false) ? "debug" : "error";
+        }
+
+        final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(status);
+        statusConfig.initialize();
+
+        configureRoot(properties);
+        parseLoggers(properties);
+
+        LOGGER.debug("Finished configuring.");
+    }
+
+    // --------------------------------------------------------------------------
+    // Internal stuff
+    // --------------------------------------------------------------------------
+
+    private void configureRoot(Properties props) {
+        String effectiveFrefix = ROOT_LOGGER_PREFIX;
+        String value = OptionConverter.findAndSubst(ROOT_LOGGER_PREFIX, props);
+
+        if (value == null) {
+            value = OptionConverter.findAndSubst(ROOT_CATEGORY_PREFIX, props);
+            effectiveFrefix = ROOT_CATEGORY_PREFIX;
+        }
+
+        if (value == null) {
+            LOGGER.debug("Could not find root logger information. Is this OK?");
+        } else {
+            LoggerConfig root = getRootLogger();
+            parseLogger(props, root, effectiveFrefix, INTERNAL_ROOT_NAME, value);
+        }
+    }
+
+    /**
+     * Parse non-root elements, such non-root categories and renderers.
+     */
+    private void parseLoggers(Properties props) {
+        Enumeration enumeration = props.propertyNames();
+        while (enumeration.hasMoreElements()) {
+            String key = (String) enumeration.nextElement();
+            if (key.startsWith(CATEGORY_PREFIX) || key.startsWith(LOGGER_PREFIX)) {
+                String loggerName = null;
+                if (key.startsWith(CATEGORY_PREFIX)) {
+                    loggerName = key.substring(CATEGORY_PREFIX.length());
+                } else if (key.startsWith(LOGGER_PREFIX)) {
+                    loggerName = key.substring(LOGGER_PREFIX.length());
+                }
+                String value = OptionConverter.findAndSubst(key, props);
+                LoggerConfig loggerConfig = getLogger(loggerName);
+                if (loggerConfig == null) {
+                    boolean additivity = getAdditivityForLogger(props, loggerName);
+                    loggerConfig = new LoggerConfig(loggerName, org.apache.logging.log4j.Level.ERROR, additivity);
+                    addLogger(loggerName, loggerConfig);
+                }
+                parseLogger(props, loggerConfig, key, loggerName, value);
+            }
+        }
+    }
+
+    /**
+     * Parse the additivity option for a non-root category.
+     */
+    private boolean getAdditivityForLogger(Properties props, String loggerName) {
+        boolean additivity = true;
+        String key = ADDITIVITY_PREFIX + loggerName;
+        String value = OptionConverter.findAndSubst(key, props);
+        LOGGER.debug("Handling {}=[{}]", key, value);
+        // touch additivity only if necessary
+        if ((value != null) && (!value.equals(""))) {
+            additivity = OptionConverter.toBoolean(value, true);
+        }
+        return additivity;
+    }
+
+    /**
+     * This method must work for the root category as well.
+     */
+    private void parseLogger(Properties props, LoggerConfig logger, String optionKey, String loggerName, String value) {
+
+        LOGGER.debug("Parsing for [{}] with value=[{}].", loggerName, value);
+        // We must skip over ',' but not white space
+        StringTokenizer st = new StringTokenizer(value, ",");
+
+        // If value is not in the form ", appender.." or "", then we should set the level of the logger.
+
+        if (!(value.startsWith(",") || value.equals(""))) {
+
+            // just to be on the safe side...
+            if (!st.hasMoreTokens()) {
+                return;
+            }
+
+            String levelStr = st.nextToken();
+            LOGGER.debug("Level token is [{}].", levelStr);
+
+            org.apache.logging.log4j.Level level = levelStr == null ? org.apache.logging.log4j.Level.ERROR :
+                    OptionConverter.convertLevel(levelStr, org.apache.logging.log4j.Level.DEBUG);
+            logger.setLevel(level);
+            LOGGER.debug("Logger {} level set to {}", loggerName, level);
+        }
+
+        Appender appender;
+        String appenderName;
+        while (st.hasMoreTokens()) {
+            appenderName = st.nextToken().trim();
+            if (appenderName == null || appenderName.equals(",")) {
+                continue;
+            }
+            LOGGER.debug("Parsing appender named \"{}\".", appenderName);
+            appender = parseAppender(props, appenderName);
+            if (appender != null) {
+                LOGGER.debug("Adding appender named [{}] to loggerConfig [{}].", appenderName,
+                        logger.getName());
+                logger.addAppender(getAppender(appenderName), null, null);
+            } else {
+                LOGGER.debug("Appender named [{}}] not found.", appenderName);
+            }
+        }
+    }
+
+    public Appender parseAppender(Properties props, String appenderName) {
+        Appender appender = registry.get(appenderName);
+        if ((appender != null)) {
+            LOGGER.debug("Appender \"" + appenderName + "\" was already parsed.");
+            return appender;
+        }
+        // Appender was not previously initialized.
+        final String prefix = APPENDER_PREFIX + appenderName;
+        final String layoutPrefix = prefix + ".layout";
+        final String filterPrefix = APPENDER_PREFIX + appenderName + ".filter.";
+        String className = OptionConverter.findAndSubst(prefix, props);
+        appender = manager.parseAppender(appenderName, className, prefix, layoutPrefix, filterPrefix, props, this);
+        if (appender == null) {
+            appender = buildAppender(appenderName, className, prefix, layoutPrefix, filterPrefix, props);
+        } else {
+            registry.put(appenderName, appender);
+            if (appender instanceof AppenderWrapper) {
+                addAppender(((AppenderWrapper) appender).getAppender());
+            } else {
+                addAppender(new AppenderAdapter(appender).getAdapter());
+            }
+        }
+        return appender;
+    }
+
+    private Appender buildAppender(final String appenderName, final String className, final String prefix,
+            final String layoutPrefix, final String filterPrefix, final Properties props) {
+        Appender appender = newInstanceOf(className, "Appender");
+        if (appender == null) {
+            return null;
+        }
+        appender.setName(appenderName);
+        appender.setLayout(parseLayout(layoutPrefix, appenderName, props));
+        final String errorHandlerPrefix = prefix + ".errorhandler";
+        String errorHandlerClass = OptionConverter.findAndSubst(errorHandlerPrefix, props);
+        if (errorHandlerClass != null) {
+            ErrorHandler eh = parseErrorHandler(props, errorHandlerPrefix, errorHandlerClass, appender);
+            if (eh != null) {
+                appender.setErrorHandler(eh);
+            }
+        }
+        parseAppenderFilters(props, filterPrefix, appenderName);
+        String[] keys = new String[] {
+                layoutPrefix,
+        };
+        addProperties(appender, keys, props, prefix);
+        if (appender instanceof AppenderWrapper) {
+            addAppender(((AppenderWrapper) appender).getAppender());
+        } else {
+            addAppender(new AppenderAdapter(appender).getAdapter());
+        }
+        registry.put(appenderName, appender);
+        return appender;
+    }
+
+    public Layout parseLayout(String layoutPrefix, String appenderName, Properties props) {
+        String layoutClass = OptionConverter.findAndSubst(layoutPrefix, props);
+        if (layoutClass == null) {
+            return null;
+        }
+        Layout layout = manager.parseLayout(layoutClass, layoutPrefix, props, this);
+        if (layout == null) {
+            layout = buildLayout(layoutPrefix, layoutClass, appenderName, props);
+        }
+        return layout;
+    }
+
+    private Layout buildLayout(String layoutPrefix, String className, String appenderName, Properties props) {
+        Layout layout = newInstanceOf(className, "Layout");
+        if (layout == null) {
+            return null;
+        }
+        LOGGER.debug("Parsing layout options for \"{}\".", appenderName);
+        PropertySetter.setProperties(layout, props, layoutPrefix + ".");
+        LOGGER.debug("End of parsing for \"{}\".", appenderName);
+        return layout;
+    }
+
+    public ErrorHandler parseErrorHandler(final Properties props, final String errorHandlerPrefix,
+            final String errorHandlerClass, final Appender appender) {
+        ErrorHandler eh = newInstanceOf(errorHandlerClass, "ErrorHandler");
+        final String[] keys = new String[] {
+                errorHandlerPrefix + "." + ROOT_REF,
+                errorHandlerPrefix + "." + LOGGER_REF,
+                errorHandlerPrefix + "." + APPENDER_REF_TAG
+        };
+        addProperties(eh, keys, props, errorHandlerPrefix);
+        return eh;
+    }
+
+    public void addProperties(final Object obj, final String[] keys, final Properties props, final String prefix) {
+        final Properties edited = new Properties();
+        props.stringPropertyNames().stream().filter((name) -> {
+            if (name.startsWith(prefix)) {
+                for (String key : keys) {
+                    if (name.equals(key)) {
+                        return false;
+                    }
+                }
+                return true;
+            }
+            return false;
+        }).forEach((name) -> edited.put(name, props.getProperty(name)));
+        PropertySetter.setProperties(obj, edited, prefix + ".");
+    }
+
+
+    public Filter parseAppenderFilters(Properties props, String filterPrefix, String appenderName) {
+        // extract filters and filter options from props into a hashtable mapping
+        // the property name defining the filter class to a list of pre-parsed
+        // name-value pairs associated to that filter
+        int fIdx = filterPrefix.length();
+        SortedMap<String, List<NameValue>> filters = new TreeMap<>();
+        Enumeration e = props.keys();
+        String name = "";
+        while (e.hasMoreElements()) {
+            String key = (String) e.nextElement();
+            if (key.startsWith(filterPrefix)) {
+                int dotIdx = key.indexOf('.', fIdx);
+                String filterKey = key;
+                if (dotIdx != -1) {
+                    filterKey = key.substring(0, dotIdx);
+                    name = key.substring(dotIdx + 1);
+                }
+                List<NameValue> filterOpts = filters.computeIfAbsent(filterKey, k -> new ArrayList<>());
+                if (dotIdx != -1) {
+                    String value = OptionConverter.findAndSubst(key, props);
+                    filterOpts.add(new NameValue(name, value));
+                }
+            }
+        }
+
+        Filter head = null;
+        Filter next = null;
+        for (Map.Entry<String, List<NameValue>> entry : filters.entrySet()) {
+            String clazz = props.getProperty(entry.getKey());
+            Filter filter = null;
+            if (clazz != null) {
+                filter = manager.parseFilter(clazz, filterPrefix, props, this);
+                if (filter == null) {
+                    LOGGER.debug("Filter key: [{}] class: [{}] props: {}", entry.getKey(), clazz, entry.getValue());
+                    filter = buildFilter(clazz, appenderName, entry.getValue());
+                }
+            }
+            if (filter != null) {
+                if (head != null) {
+                    head = filter;
+                    next = filter;
+                } else {
+                    next.setNext(filter);
+                    next = filter;
+                }
+            }
+        }
+        return head;
+    }
+
+    private Filter buildFilter(String className, String appenderName, List<NameValue> props) {
+        Filter filter = newInstanceOf(className, "Filter");
+        if (filter != null) {
+            PropertySetter propSetter = new PropertySetter(filter);
+            for (NameValue property : props) {
+                propSetter.setProperty(property.key, property.value);
+            }
+            propSetter.activate();
+        }
+        return filter;
+    }
+
+
+    private static <T> T newInstanceOf(String className, String type) {
+        try {
+            return LoaderUtil.newInstanceOf(className);
+        } catch (ClassNotFoundException | IllegalAccessException | NoSuchMethodException |
+                InstantiationException | InvocationTargetException ex) {
+            LOGGER.error("Unable to create {} {} due to {}:{}", type,  className,
+                    ex.getClass().getSimpleName(), ex.getMessage());
+            return null;
+        }
+    }
+
+    private static class NameValue {
+        String key, value;
+
+        NameValue(String key, String value) {
+            this.key = key;
+            this.value = value;
+        }
+
+        public String toString() {
+            return key + "=" + value;
+        }
+    }
+
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java
new file mode 100644
index 0000000..6413214
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/config/PropertiesConfigurationFactory.java
@@ -0,0 +1,74 @@
+/*
+ * 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.log4j.config;
+
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Order;
+import org.apache.logging.log4j.core.config.plugins.Plugin;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+/**
+ * Configures Log4j from a log4j 1 format properties file.
+ */
+@Plugin(name = "Log4j1PropertiesConfigurationFactory", category = ConfigurationFactory.CATEGORY)
+@Order(2)
+public class PropertiesConfigurationFactory extends ConfigurationFactory {
+
+
+    /**
+     * File name prefix for test configurations.
+     */
+    protected static final String TEST_PREFIX = "log4j-test";
+
+    /**
+     * File name prefix for standard configurations.
+     */
+    protected static final String DEFAULT_PREFIX = "log4j";
+
+    @Override
+    protected String[] getSupportedTypes() {
+        if (!PropertiesUtil.getProperties().getBooleanProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, Boolean.FALSE)) {
+            return null;
+        }
+        return new String[] {".properties"};
+    }
+
+    @Override
+    public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
+        int interval = PropertiesUtil.getProperties().getIntegerProperty(Log4j1Configuration.MONITOR_INTERVAL, 0);
+        return new PropertiesConfiguration(loggerContext, source, interval);
+    }
+
+    @Override
+    protected String getTestPrefix() {
+        return TEST_PREFIX;
+    }
+
+    @Override
+    protected String getDefaultPrefix() {
+        return DEFAULT_PREFIX;
+    }
+
+    @Override
+    protected String getVersion() {
+        return LOG4J1_VERSION;
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/AppenderAttachableImpl.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/AppenderAttachableImpl.java
new file mode 100644
index 0000000..fe9530d
--- /dev/null
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/AppenderAttachableImpl.java
@@ -0,0 +1,70 @@
+/*
+ * 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.log4j.helpers;
+
+import org.apache.log4j.Appender;
+import org.apache.log4j.spi.AppenderAttachable;
+
+import java.util.Collections;
+import java.util.Enumeration;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+
+/**
+ * Allows Classes to attach Appenders.
+ */
+public class AppenderAttachableImpl implements AppenderAttachable {
+
+    private final ConcurrentMap<String, Appender> appenders = new ConcurrentHashMap<>();
+
+    @Override
+    public void addAppender(Appender newAppender) {
+        if (newAppender != null) {
+            appenders.put(newAppender.getName(), newAppender);
+        }
+    }
+
+    @Override
+    public Enumeration getAllAppenders() {
+        return Collections.enumeration(appenders.values());
+    }
+
+    @Override
+    public Appender getAppender(String name) {
+        return appenders.get(name);
+    }
+
+    @Override
+    public boolean isAttached(Appender appender) {
+        return appenders.containsValue(appender);
+    }
+
+    @Override
+    public void removeAllAppenders() {
+        appenders.clear();
+    }
+
+    @Override
+    public void removeAppender(Appender appender) {
+        appenders.remove(appender.getName(), appender);
+    }
+
+    @Override
+    public void removeAppender(String name) {
+        appenders.remove(name);
+    }
+}
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java
index 8ee0ea5..e09e26b 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/helpers/OptionConverter.java
@@ -18,7 +18,6 @@
 package org.apache.log4j.helpers;
 
 import org.apache.log4j.Level;
-
 import org.apache.logging.log4j.LogManager;
 import org.apache.logging.log4j.Logger;
 import org.apache.logging.log4j.util.LoaderUtil;
@@ -332,6 +331,51 @@ public class OptionConverter {
             }
         }
     }
+
+    public static org.apache.logging.log4j.Level convertLevel(String level,
+            org.apache.logging.log4j.Level defaultLevel) {
+        Level l = toLevel(level, null);
+        return l != null ? convertLevel(l) : defaultLevel;
+    }
+
+    public static  org.apache.logging.log4j.Level convertLevel(Level level) {
+        if (level == null) {
+            return org.apache.logging.log4j.Level.ERROR;
+        }
+        if (level.isGreaterOrEqual(Level.FATAL)) {
+            return org.apache.logging.log4j.Level.FATAL;
+        } else if (level.isGreaterOrEqual(Level.ERROR)) {
+            return org.apache.logging.log4j.Level.ERROR;
+        } else if (level.isGreaterOrEqual(Level.WARN)) {
+            return org.apache.logging.log4j.Level.WARN;
+        } else if (level.isGreaterOrEqual(Level.INFO)) {
+            return org.apache.logging.log4j.Level.INFO;
+        } else if (level.isGreaterOrEqual(Level.DEBUG)) {
+            return org.apache.logging.log4j.Level.DEBUG;
+        } else if (level.isGreaterOrEqual(Level.TRACE)) {
+            return org.apache.logging.log4j.Level.TRACE;
+        }
+        return org.apache.logging.log4j.Level.ALL;
+    }
+
+    /**
+     * Find the value corresponding to <code>key</code> in
+     * <code>props</code>. Then perform variable substitution on the
+     * found value.
+     */
+    public static String findAndSubst(String key, Properties props) {
+        String value = props.getProperty(key);
+        if (value == null) {
+            return null;
+        }
+
+        try {
+            return substVars(value, props);
+        } catch (IllegalArgumentException e) {
+            LOGGER.error("Bad option value [{}].", value, e);
+            return value;
+        }
+    }
     
     private static class CharMap {
         final char key;
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
similarity index 64%
copy from log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
copy to log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
index a2f7dc7..a82b773 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfiguration.java
@@ -1,20 +1,19 @@
 /*
  * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
+ * 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 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
+ * 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.
+ * See the license for the specific language governing permissions and
+ * limitations under the license.
  */
-
 package org.apache.log4j.xml;
 
 import org.apache.log4j.Appender;
@@ -22,39 +21,17 @@ import org.apache.log4j.Layout;
 import org.apache.log4j.Level;
 import org.apache.log4j.bridge.AppenderAdapter;
 import org.apache.log4j.bridge.AppenderWrapper;
-import org.apache.log4j.bridge.FilterAdapter;
-import org.apache.log4j.bridge.LayoutAdapter;
-import org.apache.log4j.bridge.LayoutWrapper;
 import org.apache.log4j.builders.BuilderManager;
 import org.apache.log4j.config.Log4j1Configuration;
 import org.apache.log4j.config.PropertySetter;
 import org.apache.log4j.helpers.OptionConverter;
 import org.apache.log4j.spi.AppenderAttachable;
-import org.apache.log4j.spi.Configurator;
 import org.apache.log4j.spi.ErrorHandler;
 import org.apache.log4j.spi.Filter;
-import org.apache.log4j.spi.LoggerRepository;
 import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.appender.ConsoleAppender;
-import org.apache.logging.log4j.core.appender.FileAppender;
-import org.apache.logging.log4j.core.appender.NullAppender;
-import org.apache.logging.log4j.core.appender.RollingFileAppender;
-import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
-import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
-import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
-import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
-import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
-import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.apache.logging.log4j.core.config.LoggerConfig;
-import org.apache.logging.log4j.core.config.Order;
-import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.status.StatusConfiguration;
-import org.apache.logging.log4j.core.layout.HtmlLayout;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.apache.logging.log4j.core.layout.XmlLayout;
 import org.apache.logging.log4j.status.StatusLogger;
 import org.apache.logging.log4j.util.LoaderUtil;
 import org.w3c.dom.Document;
@@ -69,26 +46,19 @@ import org.xml.sax.SAXParseException;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
 import javax.xml.parsers.FactoryConfigurationError;
-import java.io.File;
-import java.io.FileInputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.InterruptedIOException;
-import java.io.Reader;
 import java.lang.reflect.Method;
-import java.net.URL;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
-import java.util.concurrent.TimeUnit;
 import java.util.function.Consumer;
 
 /**
- * Constructs a Configuration usable in Log4j 2 from a Log4j 1 configuration file.
+ * Class Description goes here.
  */
-@Plugin(name = "Log4j1XmlConfigurationFactory", category = ConfigurationFactory.CATEGORY)
-@Order(2)
-public class XmlConfigurationFactory extends ConfigurationFactory implements Configurator {
+public class XmlConfiguration extends Log4j1Configuration {
+
     private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
 
     private static final String CONFIGURATION_TAG = "log4j:configuration";
@@ -118,20 +88,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
     private static final Class[] ONE_STRING_PARAM = new Class[]{String.class};
     private static final String dbfKey = "javax.xml.parsers.DocumentBuilderFactory";
     private static final String THROWABLE_RENDERER_TAG = "throwableRenderer";
-    private static final String SYSTEM_OUT = "System.out";
-    private static final String SYSTEM_ERR = "System.err";
-    private static final String THREAD_PRINTING_PARAM = "threadprinting";
-    private static final String CATEGORY_PREFIXING_PARAM = "categoryprefixing";
-    private static final String CONTEXT_PRINTING_PARAM = "contextprinting";
-    private static final String DATE_FORMAT_PARAM = "dateformat";
-    private static final String TIMEZONE_FORMAT = "timezone";
-    public static final String FILE_PARAM = "file";
-    public static final String APPEND_PARAM = "append";
-    public static final String BUFFERED_IO_PARAM = "bufferedio";
-    public static final String BUFFER_SIZE_PARAM = "buffersize";
-    public static final String MAX_SIZE_PARAM = "maxfileSize";
-    public static final String MAX_BACKUP_INDEX = "maxbackupindex";
-    public static final String RELATIVE = "RELATIVE";
+
     public static final long DEFAULT_DELAY = 60000;
     /**
      * File name prefix for test configurations.
@@ -146,68 +103,79 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
     private final BuilderManager manager;
 
     // key: appenderName, value: appender
-    private Map<String, Appender> appenderBag;
+    private Map<String, Appender> appenderMap;
 
     private Properties props = null;
 
-    private final LoggerContext loggerContext;
-    private Log4j1Configuration configuration;
-
-    /**
-     * No argument constructor.
-     */
-    public XmlConfigurationFactory() {
-        appenderBag = new HashMap<>();
-        loggerContext = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+    public XmlConfiguration(final LoggerContext loggerContext, final ConfigurationSource source,
+            int monitorIntervalSeconds) {
+        super(loggerContext, source, monitorIntervalSeconds);
+        appenderMap = new HashMap<>();
         manager = new BuilderManager();
     }
 
+    /**
+     * Configure log4j by reading in a log4j.dtd compliant XML
+     * configuration file.
+     */
+    @Override
+    public void doConfigure() throws FactoryConfigurationError {
+        ConfigurationSource source = getConfigurationSource();
+        ParseAction action = new ParseAction() {
+            public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
+                InputSource inputSource = new InputSource(source.getInputStream());
+                inputSource.setSystemId("dummy://log4j.dtd");
+                return parser.parse(inputSource);
+            }
 
-    private XmlConfigurationFactory(ConfigurationSource source, int monitorIntervalSeconds) {
-        appenderBag = new HashMap<>();
-        loggerContext = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
-        configuration = new Log4j1Configuration(loggerContext, source, monitorIntervalSeconds);
-        manager = new BuilderManager();
+            public String toString() {
+                return getConfigurationSource().getLocation();
+            }
+        };
+        doConfigure(action);
     }
 
-    @Override
-    protected String[] getSupportedTypes() {
-        return new String[] {".xml"};
-    }
+    private void doConfigure(final ParseAction action) throws FactoryConfigurationError {
+        DocumentBuilderFactory dbf;
+        try {
+            LOGGER.debug("System property is : {}", OptionConverter.getSystemProperty(dbfKey, null));
+            dbf = DocumentBuilderFactory.newInstance();
+            LOGGER.debug("Standard DocumentBuilderFactory search succeded.");
+            LOGGER.debug("DocumentBuilderFactory is: " + dbf.getClass().getName());
+        } catch (FactoryConfigurationError fce) {
+            Exception e = fce.getException();
+            LOGGER.debug("Could not instantiate a DocumentBuilderFactory.", e);
+            throw fce;
+        }
 
-    @Override
-    public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
-        configuration = new Log4j1Configuration(loggerContext, source, 0);
-        doConfigure();
-        return configuration;
-    }
+        try {
+            dbf.setValidating(true);
 
-    public Configuration getConfiguration() {
-        return configuration;
-    }
+            DocumentBuilder docBuilder = dbf.newDocumentBuilder();
 
-    @Override
-    protected String getTestPrefix() {
-        return TEST_PREFIX;
-    }
+            docBuilder.setErrorHandler(new SAXErrorHandler());
+            docBuilder.setEntityResolver(new Log4jEntityResolver());
 
-    @Override
-    protected String getDefaultPrefix() {
-        return DEFAULT_PREFIX;
+            Document doc = action.parse(docBuilder);
+            parse(doc.getDocumentElement());
+        } catch (Exception e) {
+            if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            // I know this is miserable...
+            LOGGER.error("Could not parse " + action.toString() + ".", e);
+        }
     }
 
     /**
-     * Delegates unrecognized content to created instance if
-     * it supports UnrecognizedElementParser.
+     * Delegates unrecognized content to created instance if it supports UnrecognizedElementParser.
      *
      * @param instance instance, may be null.
      * @param element  element, may not be null.
      * @param props    properties
-     * @throws IOException thrown if configuration of owner object
-     *                     should be abandoned.
-     * @since 1.2.15
+     * @throws IOException thrown if configuration of owner object should be abandoned.
      */
-    private static void parseUnrecognizedElement(final Object instance, final Element element,
+    private void parseUnrecognizedElement(final Object instance, final Element element,
             final Properties props) throws Exception {
         boolean recognized = false;
         if (instance instanceof UnrecognizedElementHandler) {
@@ -229,7 +197,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
      * @param props    properties
      * @since 1.2.15
      */
-    private static void quietParseUnrecognizedElement(final Object instance,
+    private void quietParseUnrecognizedElement(final Object instance,
             final Element element,
             final Properties props) {
         try {
@@ -243,64 +211,6 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
     }
 
     /**
-     * Like {@link #configureAndWatch(String, long)} except that the
-     * default delay is used.
-     *
-     * @param configFilename A log4j configuration file in XML format.
-     */
-    public static void configureAndWatch(final String configFilename) {
-        configureAndWatch(configFilename, DEFAULT_DELAY);
-    }
-
-    /**
-     * Read the configuration file <code>configFilename</code> if it
-     * exists. Moreover, a thread will be created that will periodically
-     * check if <code>configFilename</code> has been created or
-     * modified. The period is determined by the <code>delay</code>
-     * argument. If a change or file creation is detected, then
-     * <code>configFilename</code> is read to configure log4j.
-     *
-     * @param configFilename A log4j configuration file in XML format.
-     * @param delay          The delay in milliseconds to wait between each check.
-     */
-    public static void configureAndWatch(final String configFilename, final long delay) {
-        try {
-            File file = new File(configFilename);
-            InputStream is = new FileInputStream(file);
-            ConfigurationSource source = new ConfigurationSource(is, file);
-            int seconds = (int) TimeUnit.MILLISECONDS.toSeconds(delay);
-            XmlConfigurationFactory factory = new XmlConfigurationFactory(source, seconds);
-            factory.doConfigure();
-            org.apache.logging.log4j.core.config.Configurator.reconfigure(factory.getConfiguration());
-
-        } catch (IOException ioe) {
-            LOGGER.error("Unable to process configuration file {} due to {}", configFilename, ioe.getMessage());
-        }
-    }
-
-    /**
-     * A static version of doConfigure(String).
-     */
-    public static void configure(final String filename) throws FactoryConfigurationError {
-        configureAndWatch(filename, 0);
-    }
-
-    /**
-     * A static version of doConfigure(URL).
-     */
-    public static void configure(final URL url) throws FactoryConfigurationError {
-        try {
-            InputStream is = url.openStream();
-            ConfigurationSource source = new ConfigurationSource(is, url);
-            XmlConfigurationFactory factory = new XmlConfigurationFactory(source, 0);
-            factory.doConfigure();
-            org.apache.logging.log4j.core.config.Configurator.reconfigure(factory.getConfiguration());
-        } catch (IOException ioe) {
-            LOGGER.error("Unable to process configuration {} due to {}", url.toString(), ioe.getMessage());
-        }
-    }
-
-    /**
      * Substitutes property value for any references in expression.
      *
      * @param value value from configuration file, may contain
@@ -309,7 +219,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
      * @return evaluated expression, may still contain expressions
      * if unable to expand.
      */
-    public static String subst(final String value, final Properties props) {
+    public String subst(final String value, final Properties props) {
         try {
             return OptionConverter.substVars(value, props);
         } catch (IllegalArgumentException e) {
@@ -326,7 +236,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
      * @param props      properties
      * @since 1.2.15
      */
-    public static void setParameter(final Element elem, final PropertySetter propSetter, final Properties props) {
+    public void setParameter(final Element elem, final PropertySetter propSetter, final Properties props) {
         String name = subst(elem.getAttribute("name"), props);
         String value = (elem.getAttribute("value"));
         value = subst(OptionConverter.convertSpecialChars(value), props);
@@ -347,7 +257,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
      * @throws Exception thrown if the contain object should be abandoned.
      * @since 1.2.15
      */
-    public static Object parseElement(final Element element, final Properties props,
+    public Object parseElement(final Element element, final Properties props,
             @SuppressWarnings("rawtypes") final Class expectedClass) throws Exception {
         String clazz = subst(element.getAttribute("class"), props);
         Object instance = OptionConverter.instantiateByClassName(clazz,
@@ -379,7 +289,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
      * Used internally to parse appenders by IDREF name.
      */
     private Appender findAppenderByName(Document doc, String appenderName) {
-        Appender appender = appenderBag.get(appenderName);
+        Appender appender = appenderMap.get(appenderName);
 
         if (appender != null) {
             return appender;
@@ -408,7 +318,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
             } else {
                 appender = parseAppender(element);
                 if (appender != null) {
-                    appenderBag.put(appenderName, appender);
+                    appenderMap.put(appenderName, appender);
                 }
                 return appender;
             }
@@ -438,69 +348,69 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
     }
 
     private Appender buildAppender(String className, Element appenderElement) {
-            try {
-                Appender appender = LoaderUtil.newInstanceOf(className);
-                PropertySetter propSetter = new PropertySetter(appender);
-
-                appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
-                forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
-                    // Parse appender parameters
-                    switch (currentElement.getTagName()) {
-                        case PARAM_TAG:
-                            setParameter(currentElement, propSetter);
-                            break;
-                        case LAYOUT_TAG:
-                            appender.setLayout(parseLayout(currentElement));
-                            break;
-                        case FILTER_TAG:
-                            Filter filter = parseFilters(currentElement);
-                            if (filter != null) {
-                                LOGGER.debug("Adding filter of type [{}] to appender named [{}]",
-                                        filter.getClass(), appender.getName());
-                                appender.addFilter(filter);
-                            }
-                            break;
-                        case ERROR_HANDLER_TAG:
-                            parseErrorHandler(currentElement, appender);
-                            break;
-                        case APPENDER_REF_TAG:
-                            String refName = subst(currentElement.getAttribute(REF_ATTR));
-                            if (appender instanceof AppenderAttachable) {
-                                AppenderAttachable aa = (AppenderAttachable) appender;
-                                Appender child = findAppenderByReference(currentElement);
-                                LOGGER.debug("Attaching appender named [{}] to appender named [{}].", refName,
-                                        appender.getName());
-                                aa.addAppender(child);
-                            } else {
-                                LOGGER.error("Requesting attachment of appender named [{}] to appender named [{}}]"
-                                                + "which does not implement org.apache.log4j.spi.AppenderAttachable.",
-                                        refName, appender.getName());
-                            }
-                            break;
-                        default:
-                            try {
-                                parseUnrecognizedElement(appender, currentElement, props);
-                            } catch (Exception ex) {
-                                throw new ConsumerException(ex);
-                            }
-                    }
-                });
-                propSetter.activate();
-                return appender;
-            } catch (ConsumerException ex) {
-                Throwable t = ex.getCause();
-                if (t instanceof InterruptedException || t instanceof InterruptedIOException) {
-                    Thread.currentThread().interrupt();
-                }
-                LOGGER.error("Could not create an Appender. Reported error follows.", t);
-            } catch (Exception oops) {
-                if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
-                    Thread.currentThread().interrupt();
+        try {
+            Appender appender = LoaderUtil.newInstanceOf(className);
+            PropertySetter propSetter = new PropertySetter(appender);
+
+            appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
+            forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
+                // Parse appender parameters
+                switch (currentElement.getTagName()) {
+                    case PARAM_TAG:
+                        setParameter(currentElement, propSetter);
+                        break;
+                    case LAYOUT_TAG:
+                        appender.setLayout(parseLayout(currentElement));
+                        break;
+                    case FILTER_TAG:
+                        Filter filter = parseFilters(currentElement);
+                        if (filter != null) {
+                            LOGGER.debug("Adding filter of type [{}] to appender named [{}]",
+                                    filter.getClass(), appender.getName());
+                            appender.addFilter(filter);
+                        }
+                        break;
+                    case ERROR_HANDLER_TAG:
+                        parseErrorHandler(currentElement, appender);
+                        break;
+                    case APPENDER_REF_TAG:
+                        String refName = subst(currentElement.getAttribute(REF_ATTR));
+                        if (appender instanceof AppenderAttachable) {
+                            AppenderAttachable aa = (AppenderAttachable) appender;
+                            Appender child = findAppenderByReference(currentElement);
+                            LOGGER.debug("Attaching appender named [{}] to appender named [{}].", refName,
+                                    appender.getName());
+                            aa.addAppender(child);
+                        } else {
+                            LOGGER.error("Requesting attachment of appender named [{}] to appender named [{}}]"
+                                            + "which does not implement org.apache.log4j.spi.AppenderAttachable.",
+                                    refName, appender.getName());
+                        }
+                        break;
+                    default:
+                        try {
+                            parseUnrecognizedElement(appender, currentElement, props);
+                        } catch (Exception ex) {
+                            throw new ConsumerException(ex);
+                        }
                 }
-                LOGGER.error("Could not create an Appender. Reported error follows.", oops);
+            });
+            propSetter.activate();
+            return appender;
+        } catch (ConsumerException ex) {
+            Throwable t = ex.getCause();
+            if (t instanceof InterruptedException || t instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
+            }
+            LOGGER.error("Could not create an Appender. Reported error follows.", t);
+        } catch (Exception oops) {
+            if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
+                Thread.currentThread().interrupt();
             }
-            return null;
+            LOGGER.error("Could not create an Appender. Reported error follows.", oops);
         }
+        return null;
+    }
 
     /**
      * Used internally to parse an {@link ErrorHandler} element.
@@ -555,10 +465,10 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
         // Create a new org.apache.log4j.Category object from the <category> element.
         String catName = subst(loggerElement.getAttribute(NAME_ATTR));
         boolean additivity = OptionConverter.toBoolean(subst(loggerElement.getAttribute(ADDITIVITY_ATTR)), true);
-        LoggerConfig loggerConfig = configuration.getLogger(catName);
+        LoggerConfig loggerConfig = getLogger(catName);
         if (loggerConfig == null) {
             loggerConfig = new LoggerConfig(catName, org.apache.logging.log4j.Level.ERROR, additivity);
-            configuration.addLogger(catName, loggerConfig);
+            addLogger(catName, loggerConfig);
         } else {
             loggerConfig.setAdditive(additivity);
         }
@@ -569,7 +479,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
      * Used internally to parse the roor category element.
      */
     private void parseRoot(Element rootElement) {
-        LoggerConfig root = configuration.getRootLogger();
+        LoggerConfig root = getRootLogger();
         parseChildrenOfLoggerElement(rootElement, root, true);
     }
 
@@ -588,7 +498,7 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
                     if (appender != null) {
                         LOGGER.debug("Adding appender named [{}] to loggerConfig [{}].", refName,
                                 loggerConfig.getName());
-                        loggerConfig.addAppender(configuration.getAppender(refName), null, null);
+                        loggerConfig.addAppender(getAppender(refName), null, null);
                     } else {
                         LOGGER.debug("Appender named [{}}] not found.", refName);
                     }
@@ -678,14 +588,14 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
         } else {
             String className = subst(element.getAttribute(CLASS_ATTR));
             if (EMPTY_STR.equals(className)) {
-                logger.setLevel(convertLevel(OptionConverter.toLevel(priStr, Level.DEBUG)));
+                logger.setLevel(OptionConverter.convertLevel(priStr, org.apache.logging.log4j.Level.DEBUG));
             } else {
                 LOGGER.debug("Desired Level sub-class: [{}]", className);
                 try {
                     Class<?> clazz = LoaderUtil.loadClass(className);
                     Method toLevelMethod = clazz.getMethod("toLevel", ONE_STRING_PARAM);
                     Level pri = (Level) toLevelMethod.invoke(null, new Object[]{priStr});
-                    logger.setLevel(convertLevel(pri));
+                    logger.setLevel(OptionConverter.convertLevel(pri));
                 } catch (Exception oops) {
                     if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
                         Thread.currentThread().interrupt();
@@ -707,80 +617,6 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
     }
 
     /**
-     * Configure log4j by reading in a log4j.dtd compliant XML
-     * configuration file.
-     */
-    private void doConfigure() throws FactoryConfigurationError {
-        ConfigurationSource source = configuration.getConfigurationSource();
-        ParseAction action = new ParseAction() {
-            public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
-                InputSource inputSource = new InputSource(source.getInputStream());
-                inputSource.setSystemId("dummy://log4j.dtd");
-                return parser.parse(inputSource);
-            }
-
-            public String toString() {
-                return configuration.getConfigurationSource().getLocation();
-            }
-        };
-        doConfigure(action);
-    }
-
-    private void doConfigure(final ParseAction action) throws FactoryConfigurationError {
-        DocumentBuilderFactory dbf;
-        try {
-            LOGGER.debug("System property is : {}", OptionConverter.getSystemProperty(dbfKey, null));
-            dbf = DocumentBuilderFactory.newInstance();
-            LOGGER.debug("Standard DocumentBuilderFactory search succeded.");
-            LOGGER.debug("DocumentBuilderFactory is: " + dbf.getClass().getName());
-        } catch (FactoryConfigurationError fce) {
-            Exception e = fce.getException();
-            LOGGER.debug("Could not instantiate a DocumentBuilderFactory.", e);
-            throw fce;
-        }
-
-        try {
-            dbf.setValidating(true);
-
-            DocumentBuilder docBuilder = dbf.newDocumentBuilder();
-
-            docBuilder.setErrorHandler(new SAXErrorHandler());
-            docBuilder.setEntityResolver(new Log4jEntityResolver());
-
-            Document doc = action.parse(docBuilder);
-            parse(doc.getDocumentElement());
-        } catch (Exception e) {
-            if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
-                Thread.currentThread().interrupt();
-            }
-            // I know this is miserable...
-            LOGGER.error("Could not parse " + action.toString() + ".", e);
-        }
-    }
-
-    @Override
-    public void doConfigure(InputStream inputStream, LoggerContext loggerContext) {
-        try {
-            ConfigurationSource source = new ConfigurationSource(inputStream);
-            configuration = new Log4j1Configuration(loggerContext, source, 0);
-            doConfigure();
-        } catch (IOException ioe) {
-            LOGGER.error("Unable to process configuration due to {}",  ioe.getMessage());
-        }
-    }
-
-    @Override
-    public void doConfigure(URL url, LoggerContext loggerContext) {
-        try {
-            ConfigurationSource source = new ConfigurationSource(url.openStream(), url);
-            configuration = new Log4j1Configuration(loggerContext, source, 0);
-            doConfigure();
-        } catch (IOException ioe) {
-            LOGGER.error("Unable to process configuration due to {}",  ioe.getMessage());
-        }
-    }
-
-    /**
      * Used internally to configure the log4j framework by parsing a DOM
      * tree of XML elements based on <a
      * href="doc-files/log4j.dtd">log4j.dtd</a>.
@@ -842,11 +678,11 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
                     break;
                 case APPENDER_TAG:
                     Appender appender = parseAppender(currentElement);
-                    appenderBag.put(appender.getName(), appender);
+                    appenderMap.put(appender.getName(), appender);
                     if (appender instanceof AppenderWrapper) {
-                        configuration.addAppender(((AppenderWrapper) appender).getAppender());
+                        addAppender(((AppenderWrapper) appender).getAppender());
                     } else {
-                        configuration.addAppender(new AppenderAdapter(appender).getAdapter());
+                        addAppender(new AppenderAdapter(appender).getAdapter());
                     }
                     break;
                 default:
@@ -855,28 +691,8 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
         });
     }
 
-    private org.apache.logging.log4j.Level convertLevel(Level level) {
-        if (level == null) {
-            return org.apache.logging.log4j.Level.ERROR;
-        }
-        if (level.isGreaterOrEqual(Level.FATAL)) {
-            return org.apache.logging.log4j.Level.FATAL;
-        } else if (level.isGreaterOrEqual(Level.ERROR)) {
-            return org.apache.logging.log4j.Level.ERROR;
-        } else if (level.isGreaterOrEqual(Level.WARN)) {
-            return org.apache.logging.log4j.Level.WARN;
-        } else if (level.isGreaterOrEqual(Level.INFO)) {
-            return org.apache.logging.log4j.Level.INFO;
-        } else if (level.isGreaterOrEqual(Level.DEBUG)) {
-            return org.apache.logging.log4j.Level.DEBUG;
-        } else if (level.isGreaterOrEqual(Level.TRACE)) {
-            return org.apache.logging.log4j.Level.TRACE;
-        }
-        return org.apache.logging.log4j.Level.ALL;
-    }
-
     private String subst(final String value) {
-        return configuration.getStrSubstitutor().replace(value);
+        return getStrSubstitutor().replace(value);
     }
 
     public static void forEachElement(NodeList list, Consumer<Element> consumer) {
@@ -923,4 +739,3 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
         }
     }
 }
-
diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
index a2f7dc7..001b53a 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/xml/XmlConfigurationFactory.java
@@ -17,122 +17,24 @@
 
 package org.apache.log4j.xml;
 
-import org.apache.log4j.Appender;
-import org.apache.log4j.Layout;
-import org.apache.log4j.Level;
-import org.apache.log4j.bridge.AppenderAdapter;
-import org.apache.log4j.bridge.AppenderWrapper;
-import org.apache.log4j.bridge.FilterAdapter;
-import org.apache.log4j.bridge.LayoutAdapter;
-import org.apache.log4j.bridge.LayoutWrapper;
-import org.apache.log4j.builders.BuilderManager;
 import org.apache.log4j.config.Log4j1Configuration;
-import org.apache.log4j.config.PropertySetter;
-import org.apache.log4j.helpers.OptionConverter;
-import org.apache.log4j.spi.AppenderAttachable;
-import org.apache.log4j.spi.Configurator;
-import org.apache.log4j.spi.ErrorHandler;
-import org.apache.log4j.spi.Filter;
-import org.apache.log4j.spi.LoggerRepository;
 import org.apache.logging.log4j.core.LoggerContext;
-import org.apache.logging.log4j.core.appender.ConsoleAppender;
-import org.apache.logging.log4j.core.appender.FileAppender;
-import org.apache.logging.log4j.core.appender.NullAppender;
-import org.apache.logging.log4j.core.appender.RollingFileAppender;
-import org.apache.logging.log4j.core.appender.rolling.CompositeTriggeringPolicy;
-import org.apache.logging.log4j.core.appender.rolling.DefaultRolloverStrategy;
-import org.apache.logging.log4j.core.appender.rolling.RolloverStrategy;
-import org.apache.logging.log4j.core.appender.rolling.SizeBasedTriggeringPolicy;
-import org.apache.logging.log4j.core.appender.rolling.TimeBasedTriggeringPolicy;
-import org.apache.logging.log4j.core.appender.rolling.TriggeringPolicy;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
-import org.apache.logging.log4j.core.config.LoggerConfig;
 import org.apache.logging.log4j.core.config.Order;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.config.status.StatusConfiguration;
-import org.apache.logging.log4j.core.layout.HtmlLayout;
-import org.apache.logging.log4j.core.layout.PatternLayout;
-import org.apache.logging.log4j.core.layout.XmlLayout;
 import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.LoaderUtil;
-import org.w3c.dom.Document;
-import org.w3c.dom.Element;
-import org.w3c.dom.NamedNodeMap;
-import org.w3c.dom.Node;
-import org.w3c.dom.NodeList;
-import org.xml.sax.InputSource;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
-
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
-import javax.xml.parsers.FactoryConfigurationError;
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InterruptedIOException;
-import java.io.Reader;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.concurrent.TimeUnit;
-import java.util.function.Consumer;
+import org.apache.logging.log4j.util.PropertiesUtil;
 
 /**
  * Constructs a Configuration usable in Log4j 2 from a Log4j 1 configuration file.
  */
 @Plugin(name = "Log4j1XmlConfigurationFactory", category = ConfigurationFactory.CATEGORY)
 @Order(2)
-public class XmlConfigurationFactory extends ConfigurationFactory implements Configurator {
+public class XmlConfigurationFactory extends ConfigurationFactory {
     private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
 
-    private static final String CONFIGURATION_TAG = "log4j:configuration";
-    private static final String OLD_CONFIGURATION_TAG = "configuration";
-    private static final String RENDERER_TAG = "renderer";
-    private static final String APPENDER_TAG = "appender";
-    private static final String APPENDER_REF_TAG = "appender-ref";
-    public  static final String PARAM_TAG = "param";
-    public static final String LAYOUT_TAG = "layout";
-    private static final String CATEGORY = "category";
-    private static final String LOGGER_ELEMENT = "logger";
-    private static final String CATEGORY_FACTORY_TAG = "categoryFactory";
-    private static final String LOGGER_FACTORY_TAG = "loggerFactory";
-    public static final String NAME_ATTR = "name";
-    private static final String CLASS_ATTR = "class";
-    public static final String VALUE_ATTR = "value";
-    private static final String ROOT_TAG = "root";
-    private static final String LEVEL_TAG = "level";
-    private static final String PRIORITY_TAG = "priority";
-    public static final String FILTER_TAG = "filter";
-    private static final String ERROR_HANDLER_TAG = "errorHandler";
-    private static final String REF_ATTR = "ref";
-    private static final String ADDITIVITY_ATTR = "additivity";
-    private static final String CONFIG_DEBUG_ATTR = "configDebug";
-    private static final String INTERNAL_DEBUG_ATTR = "debug";
-    private static final String EMPTY_STR = "";
-    private static final Class[] ONE_STRING_PARAM = new Class[]{String.class};
-    private static final String dbfKey = "javax.xml.parsers.DocumentBuilderFactory";
-    private static final String THROWABLE_RENDERER_TAG = "throwableRenderer";
-    private static final String SYSTEM_OUT = "System.out";
-    private static final String SYSTEM_ERR = "System.err";
-    private static final String THREAD_PRINTING_PARAM = "threadprinting";
-    private static final String CATEGORY_PREFIXING_PARAM = "categoryprefixing";
-    private static final String CONTEXT_PRINTING_PARAM = "contextprinting";
-    private static final String DATE_FORMAT_PARAM = "dateformat";
-    private static final String TIMEZONE_FORMAT = "timezone";
-    public static final String FILE_PARAM = "file";
-    public static final String APPEND_PARAM = "append";
-    public static final String BUFFERED_IO_PARAM = "bufferedio";
-    public static final String BUFFER_SIZE_PARAM = "buffersize";
-    public static final String MAX_SIZE_PARAM = "maxfileSize";
-    public static final String MAX_BACKUP_INDEX = "maxbackupindex";
-    public static final String RELATIVE = "RELATIVE";
-    public static final long DEFAULT_DELAY = 60000;
     /**
      * File name prefix for test configurations.
      */
@@ -143,47 +45,18 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
      */
     protected static final String DEFAULT_PREFIX = "log4j";
 
-    private final BuilderManager manager;
-
-    // key: appenderName, value: appender
-    private Map<String, Appender> appenderBag;
-
-    private Properties props = null;
-
-    private final LoggerContext loggerContext;
-    private Log4j1Configuration configuration;
-
-    /**
-     * No argument constructor.
-     */
-    public XmlConfigurationFactory() {
-        appenderBag = new HashMap<>();
-        loggerContext = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
-        manager = new BuilderManager();
-    }
-
-
-    private XmlConfigurationFactory(ConfigurationSource source, int monitorIntervalSeconds) {
-        appenderBag = new HashMap<>();
-        loggerContext = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
-        configuration = new Log4j1Configuration(loggerContext, source, monitorIntervalSeconds);
-        manager = new BuilderManager();
-    }
-
     @Override
     protected String[] getSupportedTypes() {
+        if (!PropertiesUtil.getProperties().getBooleanProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, Boolean.FALSE)) {
+            return null;
+        }
         return new String[] {".xml"};
     }
 
     @Override
     public Configuration getConfiguration(LoggerContext loggerContext, ConfigurationSource source) {
-        configuration = new Log4j1Configuration(loggerContext, source, 0);
-        doConfigure();
-        return configuration;
-    }
-
-    public Configuration getConfiguration() {
-        return configuration;
+        int interval = PropertiesUtil.getProperties().getIntegerProperty(Log4j1Configuration.MONITOR_INTERVAL, 0);
+        return new XmlConfiguration(loggerContext, source, interval);
     }
 
     @Override
@@ -196,731 +69,8 @@ public class XmlConfigurationFactory extends ConfigurationFactory implements Con
         return DEFAULT_PREFIX;
     }
 
-    /**
-     * Delegates unrecognized content to created instance if
-     * it supports UnrecognizedElementParser.
-     *
-     * @param instance instance, may be null.
-     * @param element  element, may not be null.
-     * @param props    properties
-     * @throws IOException thrown if configuration of owner object
-     *                     should be abandoned.
-     * @since 1.2.15
-     */
-    private static void parseUnrecognizedElement(final Object instance, final Element element,
-            final Properties props) throws Exception {
-        boolean recognized = false;
-        if (instance instanceof UnrecognizedElementHandler) {
-            recognized = ((UnrecognizedElementHandler) instance).parseUnrecognizedElement(
-                    element, props);
-        }
-        if (!recognized) {
-            LOGGER.warn("Unrecognized element {}", element.getNodeName());
-        }
-    }
-
-    /**
-     * Delegates unrecognized content to created instance if
-     * it supports UnrecognizedElementParser and catches and
-     * logs any exception.
-     *
-     * @param instance instance, may be null.
-     * @param element  element, may not be null.
-     * @param props    properties
-     * @since 1.2.15
-     */
-    private static void quietParseUnrecognizedElement(final Object instance,
-            final Element element,
-            final Properties props) {
-        try {
-            parseUnrecognizedElement(instance, element, props);
-        } catch (Exception ex) {
-            if (ex instanceof InterruptedException || ex instanceof InterruptedIOException) {
-                Thread.currentThread().interrupt();
-            }
-            LOGGER.error("Error in extension content: ", ex);
-        }
-    }
-
-    /**
-     * Like {@link #configureAndWatch(String, long)} except that the
-     * default delay is used.
-     *
-     * @param configFilename A log4j configuration file in XML format.
-     */
-    public static void configureAndWatch(final String configFilename) {
-        configureAndWatch(configFilename, DEFAULT_DELAY);
-    }
-
-    /**
-     * Read the configuration file <code>configFilename</code> if it
-     * exists. Moreover, a thread will be created that will periodically
-     * check if <code>configFilename</code> has been created or
-     * modified. The period is determined by the <code>delay</code>
-     * argument. If a change or file creation is detected, then
-     * <code>configFilename</code> is read to configure log4j.
-     *
-     * @param configFilename A log4j configuration file in XML format.
-     * @param delay          The delay in milliseconds to wait between each check.
-     */
-    public static void configureAndWatch(final String configFilename, final long delay) {
-        try {
-            File file = new File(configFilename);
-            InputStream is = new FileInputStream(file);
-            ConfigurationSource source = new ConfigurationSource(is, file);
-            int seconds = (int) TimeUnit.MILLISECONDS.toSeconds(delay);
-            XmlConfigurationFactory factory = new XmlConfigurationFactory(source, seconds);
-            factory.doConfigure();
-            org.apache.logging.log4j.core.config.Configurator.reconfigure(factory.getConfiguration());
-
-        } catch (IOException ioe) {
-            LOGGER.error("Unable to process configuration file {} due to {}", configFilename, ioe.getMessage());
-        }
-    }
-
-    /**
-     * A static version of doConfigure(String).
-     */
-    public static void configure(final String filename) throws FactoryConfigurationError {
-        configureAndWatch(filename, 0);
-    }
-
-    /**
-     * A static version of doConfigure(URL).
-     */
-    public static void configure(final URL url) throws FactoryConfigurationError {
-        try {
-            InputStream is = url.openStream();
-            ConfigurationSource source = new ConfigurationSource(is, url);
-            XmlConfigurationFactory factory = new XmlConfigurationFactory(source, 0);
-            factory.doConfigure();
-            org.apache.logging.log4j.core.config.Configurator.reconfigure(factory.getConfiguration());
-        } catch (IOException ioe) {
-            LOGGER.error("Unable to process configuration {} due to {}", url.toString(), ioe.getMessage());
-        }
-    }
-
-    /**
-     * Substitutes property value for any references in expression.
-     *
-     * @param value value from configuration file, may contain
-     *              literal text, property references or both
-     * @param props properties.
-     * @return evaluated expression, may still contain expressions
-     * if unable to expand.
-     */
-    public static String subst(final String value, final Properties props) {
-        try {
-            return OptionConverter.substVars(value, props);
-        } catch (IllegalArgumentException e) {
-            LOGGER.warn("Could not perform variable substitution.", e);
-            return value;
-        }
-    }
-
-    /**
-     * Sets a parameter based from configuration file content.
-     *
-     * @param elem       param element, may not be null.
-     * @param propSetter property setter, may not be null.
-     * @param props      properties
-     * @since 1.2.15
-     */
-    public static void setParameter(final Element elem, final PropertySetter propSetter, final Properties props) {
-        String name = subst(elem.getAttribute("name"), props);
-        String value = (elem.getAttribute("value"));
-        value = subst(OptionConverter.convertSpecialChars(value), props);
-        propSetter.setProperty(name, value);
-    }
-
-    /**
-     * Creates an object and processes any nested param elements
-     * but does not call activateOptions.  If the class also supports
-     * UnrecognizedElementParser, the parseUnrecognizedElement method
-     * will be call for any child elements other than param.
-     *
-     * @param element       element, may not be null.
-     * @param props         properties
-     * @param expectedClass interface or class expected to be implemented
-     *                      by created class
-     * @return created class or null.
-     * @throws Exception thrown if the contain object should be abandoned.
-     * @since 1.2.15
-     */
-    public static Object parseElement(final Element element, final Properties props,
-            @SuppressWarnings("rawtypes") final Class expectedClass) throws Exception {
-        String clazz = subst(element.getAttribute("class"), props);
-        Object instance = OptionConverter.instantiateByClassName(clazz,
-                expectedClass, null);
-
-        if (instance != null) {
-            PropertySetter propSetter = new PropertySetter(instance);
-            NodeList children = element.getChildNodes();
-            final int length = children.getLength();
-
-            for (int loop = 0; loop < length; loop++) {
-                Node currentNode = children.item(loop);
-                if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
-                    Element currentElement = (Element) currentNode;
-                    String tagName = currentElement.getTagName();
-                    if (tagName.equals("param")) {
-                        setParameter(currentElement, propSetter, props);
-                    } else {
-                        parseUnrecognizedElement(instance, currentElement, props);
-                    }
-                }
-            }
-            return instance;
-        }
-        return null;
-    }
-
-    /**
-     * Used internally to parse appenders by IDREF name.
-     */
-    private Appender findAppenderByName(Document doc, String appenderName) {
-        Appender appender = appenderBag.get(appenderName);
-
-        if (appender != null) {
-            return appender;
-        } else {
-            // Doesn't work on DOM Level 1 :
-            // Element element = doc.getElementById(appenderName);
-
-            // Endre's hack:
-            Element element = null;
-            NodeList list = doc.getElementsByTagName("appender");
-            for (int t = 0; t < list.getLength(); t++) {
-                Node node = list.item(t);
-                NamedNodeMap map = node.getAttributes();
-                Node attrNode = map.getNamedItem("name");
-                if (appenderName.equals(attrNode.getNodeValue())) {
-                    element = (Element) node;
-                    break;
-                }
-            }
-            // Hack finished.
-
-            if (element == null) {
-
-                LOGGER.error("No appender named [{}] could be found.", appenderName);
-                return null;
-            } else {
-                appender = parseAppender(element);
-                if (appender != null) {
-                    appenderBag.put(appenderName, appender);
-                }
-                return appender;
-            }
-        }
-    }
-
-    /**
-     * Used internally to parse appenders by IDREF element.
-     */
-    private Appender findAppenderByReference(Element appenderRef) {
-        String appenderName = subst(appenderRef.getAttribute(REF_ATTR));
-        Document doc = appenderRef.getOwnerDocument();
-        return findAppenderByName(doc, appenderName);
-    }
-
-    /**
-     * Used internally to parse an appender element.
-     */
-    private Appender parseAppender(Element appenderElement) {
-        String className = subst(appenderElement.getAttribute(CLASS_ATTR));
-        LOGGER.debug("Class name: [" + className + ']');
-        Appender appender = manager.parseAppender(className, appenderElement, this);
-        if (appender == null) {
-            appender = buildAppender(className, appenderElement);
-        }
-        return appender;
-    }
-
-    private Appender buildAppender(String className, Element appenderElement) {
-            try {
-                Appender appender = LoaderUtil.newInstanceOf(className);
-                PropertySetter propSetter = new PropertySetter(appender);
-
-                appender.setName(subst(appenderElement.getAttribute(NAME_ATTR)));
-                forEachElement(appenderElement.getChildNodes(), (currentElement) -> {
-                    // Parse appender parameters
-                    switch (currentElement.getTagName()) {
-                        case PARAM_TAG:
-                            setParameter(currentElement, propSetter);
-                            break;
-                        case LAYOUT_TAG:
-                            appender.setLayout(parseLayout(currentElement));
-                            break;
-                        case FILTER_TAG:
-                            Filter filter = parseFilters(currentElement);
-                            if (filter != null) {
-                                LOGGER.debug("Adding filter of type [{}] to appender named [{}]",
-                                        filter.getClass(), appender.getName());
-                                appender.addFilter(filter);
-                            }
-                            break;
-                        case ERROR_HANDLER_TAG:
-                            parseErrorHandler(currentElement, appender);
-                            break;
-                        case APPENDER_REF_TAG:
-                            String refName = subst(currentElement.getAttribute(REF_ATTR));
-                            if (appender instanceof AppenderAttachable) {
-                                AppenderAttachable aa = (AppenderAttachable) appender;
-                                Appender child = findAppenderByReference(currentElement);
-                                LOGGER.debug("Attaching appender named [{}] to appender named [{}].", refName,
-                                        appender.getName());
-                                aa.addAppender(child);
-                            } else {
-                                LOGGER.error("Requesting attachment of appender named [{}] to appender named [{}}]"
-                                                + "which does not implement org.apache.log4j.spi.AppenderAttachable.",
-                                        refName, appender.getName());
-                            }
-                            break;
-                        default:
-                            try {
-                                parseUnrecognizedElement(appender, currentElement, props);
-                            } catch (Exception ex) {
-                                throw new ConsumerException(ex);
-                            }
-                    }
-                });
-                propSetter.activate();
-                return appender;
-            } catch (ConsumerException ex) {
-                Throwable t = ex.getCause();
-                if (t instanceof InterruptedException || t instanceof InterruptedIOException) {
-                    Thread.currentThread().interrupt();
-                }
-                LOGGER.error("Could not create an Appender. Reported error follows.", t);
-            } catch (Exception oops) {
-                if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
-                    Thread.currentThread().interrupt();
-                }
-                LOGGER.error("Could not create an Appender. Reported error follows.", oops);
-            }
-            return null;
-        }
-
-    /**
-     * Used internally to parse an {@link ErrorHandler} element.
-     */
-    private void parseErrorHandler(Element element, Appender appender) {
-        ErrorHandler eh = (ErrorHandler) OptionConverter.instantiateByClassName(
-                subst(element.getAttribute(CLASS_ATTR)),
-                ErrorHandler.class,
-                null);
-
-        if (eh != null) {
-            eh.setAppender(appender);
-
-            PropertySetter propSetter = new PropertySetter(eh);
-            forEachElement(element.getChildNodes(), (currentElement) -> {
-                String tagName = currentElement.getTagName();
-                if (tagName.equals(PARAM_TAG)) {
-                    setParameter(currentElement, propSetter);
-                }
-            });
-            propSetter.activate();
-            appender.setErrorHandler(eh);
-        }
-    }
-
-    /**
-     * Used internally to parse a filter element.
-     */
-    public Filter parseFilters(Element filterElement) {
-        String className = subst(filterElement.getAttribute(CLASS_ATTR));
-        LOGGER.debug("Class name: [" + className + ']');
-        Filter filter = manager.parseFilter(className, filterElement, this);
-        if (filter == null) {
-            PropertySetter propSetter = new PropertySetter(filter);
-            forEachElement(filterElement.getChildNodes(), (currentElement) -> {
-                String tagName = currentElement.getTagName();
-                if (tagName.equals(PARAM_TAG)) {
-                    setParameter(currentElement, propSetter);
-                } else {
-                    quietParseUnrecognizedElement(filter, currentElement, props);
-                }
-            });
-            propSetter.activate();
-        }
-        return filter;
-    }
-
-    /**
-     * Used internally to parse an category element.
-     */
-    private void parseCategory(Element loggerElement) {
-        // Create a new org.apache.log4j.Category object from the <category> element.
-        String catName = subst(loggerElement.getAttribute(NAME_ATTR));
-        boolean additivity = OptionConverter.toBoolean(subst(loggerElement.getAttribute(ADDITIVITY_ATTR)), true);
-        LoggerConfig loggerConfig = configuration.getLogger(catName);
-        if (loggerConfig == null) {
-            loggerConfig = new LoggerConfig(catName, org.apache.logging.log4j.Level.ERROR, additivity);
-            configuration.addLogger(catName, loggerConfig);
-        } else {
-            loggerConfig.setAdditive(additivity);
-        }
-        parseChildrenOfLoggerElement(loggerElement, loggerConfig, false);
-    }
-
-    /**
-     * Used internally to parse the roor category element.
-     */
-    private void parseRoot(Element rootElement) {
-        LoggerConfig root = configuration.getRootLogger();
-        parseChildrenOfLoggerElement(rootElement, root, true);
-    }
-
-    /**
-     * Used internally to parse the children of a LoggerConfig element.
-     */
-    private void parseChildrenOfLoggerElement(Element catElement, LoggerConfig loggerConfig, boolean isRoot) {
-
-        final PropertySetter propSetter = new PropertySetter(loggerConfig);
-        loggerConfig.getAppenderRefs().clear();
-        forEachElement(catElement.getChildNodes(), (currentElement) -> {
-            switch (currentElement.getTagName()) {
-                case APPENDER_REF_TAG: {
-                    Appender appender = findAppenderByReference(currentElement);
-                    String refName = subst(currentElement.getAttribute(REF_ATTR));
-                    if (appender != null) {
-                        LOGGER.debug("Adding appender named [{}] to loggerConfig [{}].", refName,
-                                loggerConfig.getName());
-                        loggerConfig.addAppender(configuration.getAppender(refName), null, null);
-                    } else {
-                        LOGGER.debug("Appender named [{}}] not found.", refName);
-                    }
-                    break;
-                }
-                case LEVEL_TAG: case PRIORITY_TAG: {
-                    parseLevel(currentElement, loggerConfig, isRoot);
-                    break;
-                }
-                case PARAM_TAG: {
-                    setParameter(currentElement, propSetter);
-                    break;
-                }
-                default: {
-                    quietParseUnrecognizedElement(loggerConfig, currentElement, props);
-                }
-            }
-        });
-        propSetter.activate();
-    }
-
-    /**
-     * Used internally to parse a layout element.
-     */
-    public Layout parseLayout(Element layoutElement) {
-        String className = subst(layoutElement.getAttribute(CLASS_ATTR));
-        LOGGER.debug("Parsing layout of class: \"{}\"", className);
-        Layout layout = manager.parseLayout(className, layoutElement, this);
-        if (layout == null) {
-            layout = buildLayout(className, layoutElement);
-        }
-        return layout;
-    }
-
-    private Layout buildLayout(String className, Element layout_element) {
-        try {
-            Layout layout = LoaderUtil.newInstanceOf(className);
-            PropertySetter propSetter = new PropertySetter(layout);
-            forEachElement(layout_element.getChildNodes(), (currentElement) -> {
-                String tagName = currentElement.getTagName();
-                if (tagName.equals(PARAM_TAG)) {
-                    setParameter(currentElement, propSetter);
-                } else {
-                    try {
-                        parseUnrecognizedElement(layout, currentElement, props);
-                    } catch (Exception ex) {
-                        throw new ConsumerException(ex);
-                    }
-                }
-            });
-
-            propSetter.activate();
-            return layout;
-        } catch (ConsumerException ce) {
-            Throwable cause = ce.getCause();
-            if (cause instanceof InterruptedException || cause instanceof InterruptedIOException) {
-                Thread.currentThread().interrupt();
-            }
-            LOGGER.error("Could not create the Layout. Reported error follows.", cause);
-        } catch (Exception oops) {
-            if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
-                Thread.currentThread().interrupt();
-            }
-            LOGGER.error("Could not create the Layout. Reported error follows.", oops);
-        }
-        return null;
-    }
-
-    /**
-     * Used internally to parse a level  element.
-     */
-    private void parseLevel(Element element, LoggerConfig logger, boolean isRoot) {
-        String catName = logger.getName();
-        if (isRoot) {
-            catName = "root";
-        }
-
-        String priStr = subst(element.getAttribute(VALUE_ATTR));
-        LOGGER.debug("Level value for {} is [{}}].", catName, priStr);
-
-        if (INHERITED.equalsIgnoreCase(priStr) || NULL.equalsIgnoreCase(priStr)) {
-            if (isRoot) {
-                LOGGER.error("Root level cannot be inherited. Ignoring directive.");
-            } else {
-                logger.setLevel(null);
-            }
-        } else {
-            String className = subst(element.getAttribute(CLASS_ATTR));
-            if (EMPTY_STR.equals(className)) {
-                logger.setLevel(convertLevel(OptionConverter.toLevel(priStr, Level.DEBUG)));
-            } else {
-                LOGGER.debug("Desired Level sub-class: [{}]", className);
-                try {
-                    Class<?> clazz = LoaderUtil.loadClass(className);
-                    Method toLevelMethod = clazz.getMethod("toLevel", ONE_STRING_PARAM);
-                    Level pri = (Level) toLevelMethod.invoke(null, new Object[]{priStr});
-                    logger.setLevel(convertLevel(pri));
-                } catch (Exception oops) {
-                    if (oops instanceof InterruptedException || oops instanceof InterruptedIOException) {
-                        Thread.currentThread().interrupt();
-                    }
-                    LOGGER.error("Could not create level [" + priStr +
-                            "]. Reported error follows.", oops);
-                    return;
-                }
-            }
-        }
-        LOGGER.debug("{} level set to {}", catName,  logger.getLevel());
-    }
-
-    private void setParameter(Element elem, PropertySetter propSetter) {
-        String name = subst(elem.getAttribute(NAME_ATTR));
-        String value = (elem.getAttribute(VALUE_ATTR));
-        value = subst(OptionConverter.convertSpecialChars(value));
-        propSetter.setProperty(name, value);
-    }
-
-    /**
-     * Configure log4j by reading in a log4j.dtd compliant XML
-     * configuration file.
-     */
-    private void doConfigure() throws FactoryConfigurationError {
-        ConfigurationSource source = configuration.getConfigurationSource();
-        ParseAction action = new ParseAction() {
-            public Document parse(final DocumentBuilder parser) throws SAXException, IOException {
-                InputSource inputSource = new InputSource(source.getInputStream());
-                inputSource.setSystemId("dummy://log4j.dtd");
-                return parser.parse(inputSource);
-            }
-
-            public String toString() {
-                return configuration.getConfigurationSource().getLocation();
-            }
-        };
-        doConfigure(action);
-    }
-
-    private void doConfigure(final ParseAction action) throws FactoryConfigurationError {
-        DocumentBuilderFactory dbf;
-        try {
-            LOGGER.debug("System property is : {}", OptionConverter.getSystemProperty(dbfKey, null));
-            dbf = DocumentBuilderFactory.newInstance();
-            LOGGER.debug("Standard DocumentBuilderFactory search succeded.");
-            LOGGER.debug("DocumentBuilderFactory is: " + dbf.getClass().getName());
-        } catch (FactoryConfigurationError fce) {
-            Exception e = fce.getException();
-            LOGGER.debug("Could not instantiate a DocumentBuilderFactory.", e);
-            throw fce;
-        }
-
-        try {
-            dbf.setValidating(true);
-
-            DocumentBuilder docBuilder = dbf.newDocumentBuilder();
-
-            docBuilder.setErrorHandler(new SAXErrorHandler());
-            docBuilder.setEntityResolver(new Log4jEntityResolver());
-
-            Document doc = action.parse(docBuilder);
-            parse(doc.getDocumentElement());
-        } catch (Exception e) {
-            if (e instanceof InterruptedException || e instanceof InterruptedIOException) {
-                Thread.currentThread().interrupt();
-            }
-            // I know this is miserable...
-            LOGGER.error("Could not parse " + action.toString() + ".", e);
-        }
-    }
-
     @Override
-    public void doConfigure(InputStream inputStream, LoggerContext loggerContext) {
-        try {
-            ConfigurationSource source = new ConfigurationSource(inputStream);
-            configuration = new Log4j1Configuration(loggerContext, source, 0);
-            doConfigure();
-        } catch (IOException ioe) {
-            LOGGER.error("Unable to process configuration due to {}",  ioe.getMessage());
-        }
-    }
-
-    @Override
-    public void doConfigure(URL url, LoggerContext loggerContext) {
-        try {
-            ConfigurationSource source = new ConfigurationSource(url.openStream(), url);
-            configuration = new Log4j1Configuration(loggerContext, source, 0);
-            doConfigure();
-        } catch (IOException ioe) {
-            LOGGER.error("Unable to process configuration due to {}",  ioe.getMessage());
-        }
-    }
-
-    /**
-     * Used internally to configure the log4j framework by parsing a DOM
-     * tree of XML elements based on <a
-     * href="doc-files/log4j.dtd">log4j.dtd</a>.
-     */
-    private void parse(Element element) {
-        String rootElementName = element.getTagName();
-
-        if (!rootElementName.equals(CONFIGURATION_TAG)) {
-            if (rootElementName.equals(OLD_CONFIGURATION_TAG)) {
-                LOGGER.warn("The <" + OLD_CONFIGURATION_TAG +
-                        "> element has been deprecated.");
-                LOGGER.warn("Use the <" + CONFIGURATION_TAG + "> element instead.");
-            } else {
-                LOGGER.error("DOM element is - not a <" + CONFIGURATION_TAG + "> element.");
-                return;
-            }
-        }
-
-
-        String debugAttrib = subst(element.getAttribute(INTERNAL_DEBUG_ATTR));
-
-        LOGGER.debug("debug attribute= \"" + debugAttrib + "\".");
-        // if the log4j.dtd is not specified in the XML file, then the
-        // "debug" attribute is returned as the empty string.
-        String status = "error";
-        if (!debugAttrib.equals("") && !debugAttrib.equals("null")) {
-            status = OptionConverter.toBoolean(debugAttrib, true) ? "debug" : "error";
-
-        } else {
-            LOGGER.debug("Ignoring " + INTERNAL_DEBUG_ATTR + " attribute.");
-        }
-
-        String confDebug = subst(element.getAttribute(CONFIG_DEBUG_ATTR));
-        if (!confDebug.equals("") && !confDebug.equals("null")) {
-            LOGGER.warn("The \"" + CONFIG_DEBUG_ATTR + "\" attribute is deprecated.");
-            LOGGER.warn("Use the \"" + INTERNAL_DEBUG_ATTR + "\" attribute instead.");
-            status = OptionConverter.toBoolean(confDebug, true) ? "debug" : "error";
-        }
-
-        final StatusConfiguration statusConfig = new StatusConfiguration().withStatus(status);
-        statusConfig.initialize();
-
-        forEachElement(element.getChildNodes(), (currentElement) -> {
-            switch (currentElement.getTagName()) {
-                case CATEGORY: case LOGGER_ELEMENT:
-                    parseCategory(currentElement);
-                    break;
-                case ROOT_TAG:
-                    parseRoot(currentElement);
-                    break;
-                case RENDERER_TAG:
-                    LOGGER.warn("Renderers are not supported by Log4j 2 and will be ignored.");
-                    break;
-                case THROWABLE_RENDERER_TAG:
-                    LOGGER.warn("Throwable Renderers are not supported by Log4j 2 and will be ignored.");
-                    break;
-                case CATEGORY_FACTORY_TAG: case LOGGER_FACTORY_TAG:
-                    LOGGER.warn("Log4j 1 Logger factories are not supported by Log4j 2 and will be ignored.");
-                    break;
-                case APPENDER_TAG:
-                    Appender appender = parseAppender(currentElement);
-                    appenderBag.put(appender.getName(), appender);
-                    if (appender instanceof AppenderWrapper) {
-                        configuration.addAppender(((AppenderWrapper) appender).getAppender());
-                    } else {
-                        configuration.addAppender(new AppenderAdapter(appender).getAdapter());
-                    }
-                    break;
-                default:
-                    quietParseUnrecognizedElement(null, currentElement, props);
-            }
-        });
-    }
-
-    private org.apache.logging.log4j.Level convertLevel(Level level) {
-        if (level == null) {
-            return org.apache.logging.log4j.Level.ERROR;
-        }
-        if (level.isGreaterOrEqual(Level.FATAL)) {
-            return org.apache.logging.log4j.Level.FATAL;
-        } else if (level.isGreaterOrEqual(Level.ERROR)) {
-            return org.apache.logging.log4j.Level.ERROR;
-        } else if (level.isGreaterOrEqual(Level.WARN)) {
-            return org.apache.logging.log4j.Level.WARN;
-        } else if (level.isGreaterOrEqual(Level.INFO)) {
-            return org.apache.logging.log4j.Level.INFO;
-        } else if (level.isGreaterOrEqual(Level.DEBUG)) {
-            return org.apache.logging.log4j.Level.DEBUG;
-        } else if (level.isGreaterOrEqual(Level.TRACE)) {
-            return org.apache.logging.log4j.Level.TRACE;
-        }
-        return org.apache.logging.log4j.Level.ALL;
-    }
-
-    private String subst(final String value) {
-        return configuration.getStrSubstitutor().replace(value);
-    }
-
-    public static void forEachElement(NodeList list, Consumer<Element> consumer) {
-        final int length = list.getLength();
-        for (int loop = 0; loop < length; loop++) {
-            Node currentNode = list.item(loop);
-
-            if (currentNode.getNodeType() == Node.ELEMENT_NODE) {
-                Element currentElement = (Element) currentNode;
-                consumer.accept(currentElement);
-            }
-        }
-    }
-
-    private interface ParseAction {
-        Document parse(final DocumentBuilder parser) throws SAXException, IOException;
-    }
-
-    private static class SAXErrorHandler implements org.xml.sax.ErrorHandler {
-        private static final org.apache.logging.log4j.Logger LOGGER = StatusLogger.getLogger();
-
-        public void error(final SAXParseException ex) {
-            emitMessage("Continuable parsing error ", ex);
-        }
-
-        public void fatalError(final SAXParseException ex) {
-            emitMessage("Fatal parsing error ", ex);
-        }
-
-        public void warning(final SAXParseException ex) {
-            emitMessage("Parsing warning ", ex);
-        }
-
-        private static void emitMessage(final String msg, final SAXParseException ex) {
-            LOGGER.warn("{} {} and column {}", msg, ex.getLineNumber(), ex.getColumnNumber());
-            LOGGER.warn(ex.getMessage(), ex.getException());
-        }
-    }
-
-    private static class ConsumerException extends RuntimeException {
-
-        ConsumerException(Exception ex) {
-            super(ex);
-        }
+    protected String getVersion() {
+        return LOG4J1_VERSION;
     }
 }
-
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AutoConfigTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AutoConfigTest.java
index 764f612..5b4412d 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/config/AutoConfigTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/AutoConfigTest.java
@@ -21,10 +21,11 @@ import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
 import org.apache.log4j.bridge.AppenderAdapter;
 import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.xml.XmlConfigurationFactory;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.config.Configuration;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.spi.LoggerContext;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.io.File;
@@ -39,6 +40,11 @@ import static org.junit.Assert.assertTrue;
  */
 public class AutoConfigTest {
 
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, "true");
+    }
+
     @Test
     public void testListAppender() {
         Logger logger = LogManager.getLogger("test");
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationFactoryTest.java
new file mode 100644
index 0000000..de81b63
--- /dev/null
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationFactoryTest.java
@@ -0,0 +1,52 @@
+/*
+ * 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.log4j.config;
+
+import org.apache.log4j.LogManager;
+import org.apache.log4j.Logger;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.File;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+/**
+ * Test configuration from Properties.
+ */
+public class PropertiesConfigurationFactoryTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j1-file.properties");
+    }
+
+    @Test
+    public void testProperties() throws Exception {
+        Logger logger = LogManager.getLogger("test");
+        logger.debug("This is a test of the root logger");
+        File file = new File("target/temp.A1");
+        assertTrue("File A1 was not created", file.exists());
+        assertTrue("File A1 is empty", file.length() > 0);
+        file = new File("target/temp.A2");
+        assertTrue("File A2 was not created", file.exists());
+        assertTrue("File A2 is empty", file.length() > 0);
+    }
+
+}
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
similarity index 69%
copy from log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
copy to log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
index d522a18..72ff293 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/PropertiesConfigurationTest.java
@@ -21,29 +21,30 @@ import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
 import org.apache.log4j.bridge.AppenderAdapter;
 import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.xml.DOMConfigurator;
-import org.apache.log4j.xml.XmlConfigurationFactory;
 import org.apache.logging.log4j.core.Appender;
+import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Configurator;
 import org.junit.Test;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
 /**
- * Test configuration from XML.
+ * Test configuration from Properties.
  */
-public class XmlConfigurationFactoryTest {
+public class PropertiesConfigurationTest {
 
     @Test
-    public void testXML() throws Exception {
-        XmlConfigurationFactory.configure("target/test-classes/log4j1-file.xml");
+    public void testProperties() throws Exception {
+        configure("target/test-classes/log4j1-file.properties");
         Logger logger = LogManager.getLogger("test");
         logger.debug("This is a test of the root logger");
         File file = new File("target/temp.A1");
@@ -55,12 +56,11 @@ public class XmlConfigurationFactoryTest {
     }
 
     @Test
-    public void testListAppender() {
-        XmlConfigurationFactory.configure("target/test-classes/log4j1-list.xml");
+    public void testListAppender() throws Exception {
+        LoggerContext loggerContext = configure("target/test-classes/log4j1-list.properties");
         Logger logger = LogManager.getLogger("test");
         logger.debug("This is a test of the root logger");
-        LoggerContext loggerContext = org.apache.logging.log4j.LogManager.getContext(false);
-        Configuration configuration = ((org.apache.logging.log4j.core.LoggerContext) loggerContext).getConfiguration();
+        Configuration configuration = loggerContext.getConfiguration();
         Map<String, Appender> appenders = configuration.getAppenders();
         ListAppender eventAppender = null;
         ListAppender messageAppender = null;
@@ -79,4 +79,15 @@ public class XmlConfigurationFactoryTest {
         assertTrue("No messages", messages != null && messages.size() > 0);
     }
 
+    private LoggerContext configure(String configLocation) throws Exception {
+        File file = new File(configLocation);
+        InputStream is = new FileInputStream(file);
+        ConfigurationSource source = new ConfigurationSource(is, file);
+        LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = new PropertiesConfigurationFactory().getConfiguration(context, source);
+        assertNotNull("No configuration created", configuration);
+        Configurator.reconfigure(configuration);
+        return context;
+    }
+
 }
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
index d522a18..65b8d47 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
@@ -16,23 +16,18 @@
  */
 package org.apache.log4j.config;
 
-import org.apache.log4j.ListAppender;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
-import org.apache.log4j.bridge.AppenderAdapter;
-import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.xml.DOMConfigurator;
-import org.apache.log4j.xml.XmlConfigurationFactory;
-import org.apache.logging.log4j.core.Appender;
-import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.junit.BeforeClass;
 import org.junit.Test;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
 import java.util.List;
 import java.util.Map;
 
-import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertTrue;
 
@@ -41,9 +36,12 @@ import static org.junit.Assert.assertTrue;
  */
 public class XmlConfigurationFactoryTest {
 
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY, "target/test-classes/log4j1-file.xml");
+    }
     @Test
     public void testXML() throws Exception {
-        XmlConfigurationFactory.configure("target/test-classes/log4j1-file.xml");
         Logger logger = LogManager.getLogger("test");
         logger.debug("This is a test of the root logger");
         File file = new File("target/temp.A1");
@@ -54,29 +52,4 @@ public class XmlConfigurationFactoryTest {
         assertTrue("File A2 is empty", file.length() > 0);
     }
 
-    @Test
-    public void testListAppender() {
-        XmlConfigurationFactory.configure("target/test-classes/log4j1-list.xml");
-        Logger logger = LogManager.getLogger("test");
-        logger.debug("This is a test of the root logger");
-        LoggerContext loggerContext = org.apache.logging.log4j.LogManager.getContext(false);
-        Configuration configuration = ((org.apache.logging.log4j.core.LoggerContext) loggerContext).getConfiguration();
-        Map<String, Appender> appenders = configuration.getAppenders();
-        ListAppender eventAppender = null;
-        ListAppender messageAppender = null;
-        for (Map.Entry<String, Appender> entry : appenders.entrySet()) {
-            if (entry.getKey().equals("list")) {
-                messageAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
-            } else if (entry.getKey().equals("events")) {
-                eventAppender = (ListAppender) ((AppenderAdapter.Adapter) entry.getValue()).getAppender();
-            }
-        }
-        assertNotNull("No Event Appender", eventAppender);
-        assertNotNull("No Message Appender", messageAppender);
-        List<LoggingEvent> events = eventAppender.getEvents();
-        assertTrue("No events", events != null && events.size() > 0);
-        List<String> messages = messageAppender.getMessages();
-        assertTrue("No messages", messages != null && messages.size() > 0);
-    }
-
 }
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
similarity index 70%
copy from log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
copy to log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
index d522a18..c4cc360 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationFactoryTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/config/XmlConfigurationTest.java
@@ -21,14 +21,18 @@ import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
 import org.apache.log4j.bridge.AppenderAdapter;
 import org.apache.log4j.spi.LoggingEvent;
-import org.apache.log4j.xml.DOMConfigurator;
 import org.apache.log4j.xml.XmlConfigurationFactory;
 import org.apache.logging.log4j.core.Appender;
 import org.apache.logging.log4j.core.config.Configuration;
-import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.core.config.ConfigurationSource;
+import org.apache.logging.log4j.core.config.Configurator;
+import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.spi.LoggerContextFactory;
 import org.junit.Test;
 
 import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStream;
 import java.util.List;
 import java.util.Map;
 
@@ -39,11 +43,11 @@ import static org.junit.Assert.assertTrue;
 /**
  * Test configuration from XML.
  */
-public class XmlConfigurationFactoryTest {
+public class XmlConfigurationTest {
 
     @Test
     public void testXML() throws Exception {
-        XmlConfigurationFactory.configure("target/test-classes/log4j1-file.xml");
+        configure("target/test-classes/log4j1-file.xml");
         Logger logger = LogManager.getLogger("test");
         logger.debug("This is a test of the root logger");
         File file = new File("target/temp.A1");
@@ -55,12 +59,11 @@ public class XmlConfigurationFactoryTest {
     }
 
     @Test
-    public void testListAppender() {
-        XmlConfigurationFactory.configure("target/test-classes/log4j1-list.xml");
+    public void testListAppender() throws Exception {
+        LoggerContext loggerContext = configure("target/test-classes/log4j1-list.xml");
         Logger logger = LogManager.getLogger("test");
         logger.debug("This is a test of the root logger");
-        LoggerContext loggerContext = org.apache.logging.log4j.LogManager.getContext(false);
-        Configuration configuration = ((org.apache.logging.log4j.core.LoggerContext) loggerContext).getConfiguration();
+        Configuration configuration = loggerContext.getConfiguration();
         Map<String, Appender> appenders = configuration.getAppenders();
         ListAppender eventAppender = null;
         ListAppender messageAppender = null;
@@ -79,4 +82,16 @@ public class XmlConfigurationFactoryTest {
         assertTrue("No messages", messages != null && messages.size() > 0);
     }
 
+    private LoggerContext configure(String configLocation) throws Exception {
+        File file = new File(configLocation);
+        InputStream is = new FileInputStream(file);
+        ConfigurationSource source = new ConfigurationSource(is, file);
+        LoggerContextFactory factory = org.apache.logging.log4j.LogManager.getFactory();
+        LoggerContext context = (LoggerContext) org.apache.logging.log4j.LogManager.getContext(false);
+        Configuration configuration = new XmlConfigurationFactory().getConfiguration(context, source);
+        assertNotNull("No configuration created", configuration);
+        Configurator.reconfigure(configuration);
+        return context;
+    }
+
 }
diff --git a/log4j-1.2-api/src/test/resources/log4j1-file.properties b/log4j-1.2-api/src/test/resources/log4j1-file.properties
new file mode 100644
index 0000000..ee870df
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-file.properties
@@ -0,0 +1,31 @@
+# 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.
+
+log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
+log4j.appender.CONSOLE.Target=System.out
+log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
+log4j.appender.CONSOLE.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
+log4j.appender.A1=org.apache.log4j.FileAppender
+log4j.appender.A1.File=target/temp.A1
+log4j.appender.A1.Append=false
+log4j.appender.A1.layout=org.apache.log4j.PatternLayout
+log4j.appender.A1.layout.ConversionPattern=%-5p %c{2} - %m%n
+log4j.appender.A2=org.apache.log4j.FileAppender
+log4j.appender.A2.File=target/temp.A2
+log4j.appender.A2.Append=false
+log4j.appender.A2.layout=org.apache.log4j.TTCCLayout
+log4j.appender.A2.layout.DateFormat=ISO8601
+log4j.logger.org.apache.log4j.xml=trace, A1
+log4j.rootLogger=trace, A1, A2
\ No newline at end of file
diff --git a/log4j-1.2-api/src/test/resources/log4j1-list.properties b/log4j-1.2-api/src/test/resources/log4j1-list.properties
new file mode 100644
index 0000000..43d6208
--- /dev/null
+++ b/log4j-1.2-api/src/test/resources/log4j1-list.properties
@@ -0,0 +1,20 @@
+# 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.
+
+log4j.appender.list=org.apache.log4j.ListAppender
+log4j.appender.list.layout=org.apache.log4j.PatternLayout
+log4j.appender.list.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p %c{1}:%L - %m%n
+log4j.appender.events=org.apache.log4j.ListAppender
+log4j.rootLogger=trace, list, events
\ No newline at end of file
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
index 5f22433..9aba1c6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationFactory.java
@@ -91,6 +91,10 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
      */
     public static final String CONFIGURATION_FILE_PROPERTY = "log4j.configurationFile";
 
+    public static final String LOG4J1_CONFIGURATION_FILE_PROPERTY = "log4j.configuration";
+
+    public static final String LOG4J1_EXPERIMENTAL = "log4j1.experimental";
+
     public static final String AUTHORIZATION_PROVIDER = "log4j2.authorizationProvider";
 
     /**
@@ -116,6 +120,9 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
      */
     protected static final String DEFAULT_PREFIX = "log4j2";
 
+    protected static final String LOG4J1_VERSION = "1";
+    protected static final String LOG4J2_VERSION = "2";
+
     /**
      * The name of the classloader URI scheme.
      */
@@ -263,6 +270,10 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
         return DEFAULT_PREFIX;
     }
 
+    protected String getVersion() {
+        return LOG4J2_VERSION;
+    }
+
     protected boolean isActive() {
         return true;
     }
@@ -397,6 +408,13 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
                         return new CompositeConfiguration(configs);
                     }
                     return getConfiguration(loggerContext, configLocationStr);
+                } else {
+                    final String log4j1ConfigStr = this.substitutor.replace(PropertiesUtil.getProperties()
+                            .getStringProperty(LOG4J1_CONFIGURATION_FILE_PROPERTY));
+                    if (log4j1ConfigStr != null) {
+                        System.setProperty(LOG4J1_EXPERIMENTAL, "true");
+                        return getConfiguration(LOG4J1_VERSION, loggerContext, log4j1ConfigStr);
+                    }
                 }
                 for (final ConfigurationFactory factory : getFactories()) {
                     final String[] types = factory.getSupportedTypes();
@@ -442,7 +460,7 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
             if (config != null) {
                 return config;
             }
-            LOGGER.error("No Log4j 2 configuration file found. " +
+            LOGGER.warn("No Log4j 2 configuration file found. " +
                     "Using default configuration (logging only errors to the console), " +
                     "or user programmatically provided configurations. " +
                     "Set system property 'log4j2.debug' " +
@@ -452,6 +470,11 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
         }
 
         private Configuration getConfiguration(final LoggerContext loggerContext, final String configLocationStr) {
+            return getConfiguration(null, loggerContext, configLocationStr);
+        }
+
+        private Configuration getConfiguration(String requiredVersion, final LoggerContext loggerContext,
+                final String configLocationStr) {
             ConfigurationSource source = null;
             try {
                 source = ConfigurationSource.fromUri(NetUtils.toURI(configLocationStr));
@@ -465,6 +488,9 @@ public abstract class ConfigurationFactory extends ConfigurationBuilderFactory {
             }
             if (source != null) {
                 for (final ConfigurationFactory factory : getFactories()) {
+                    if (requiredVersion != null && !factory.getVersion().equals(requiredVersion)) {
+                        continue;
+                    }
                     final String[] types = factory.getSupportedTypes();
                     if (types != null) {
                         for (final String type : types) {
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
index a9000c3..57e0da7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Configurator.java
@@ -226,6 +226,11 @@ public final class Configurator {
         return null;
     }
 
+    /**
+     * Reconfigure using an already constructed Configuration.
+     * @param configuration The configuration.
+     * @since 2.13.0
+     */
     public static void reconfigure(final Configuration configuration) {
         try {
             final Log4jContextFactory factory = getFactory();