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

pkarwasz pushed a commit to branch fix/apply-property-environment
in repository https://gitbox.apache.org/repos/asf/logging-log4j2.git

commit c646ed075f82dc7e3d1708808483428581d9c798
Author: Piotr P. Karwasz <[email protected]>
AuthorDate: Mon Mar 4 13:12:25 2024 +0100

    Generalize DI usage
    
    This commit ensures that:
    
    * an `InstanceFactory` is created in the Log4j `Provider`,
    * the same factory is injected as parameters to all
      the components of the chain `Log4jContextFactory`, `ContextSelector`,
      `LoggerContext` (child), `Configuration` (grand-child).
    * `DI.createInstanceFactory` is called only when strictly necessary.
---
 .../src/main/java/org/apache/log4j/Category.java   |   2 +-
 .../org/apache/log4j/bridge/AppenderAdapter.java   |   2 +-
 .../org/apache/log4j/bridge/LogEventAdapter.java   |  13 ++
 .../org/apache/log4j/bridge/LogEventWrapper.java   |   8 +
 .../log4j/config/Log4j1ConfigurationFactory.java   |   6 +-
 .../config/PropertiesConfigurationFactory.java     |  10 +-
 .../apache/log4j/xml/XmlConfigurationFactory.java  |  10 +-
 .../apache/log4j/BasicConfigurationFactory.java    |   4 +-
 .../test/java/org/apache/log4j/CategoryTest.java   |  35 ++++-
 .../test/java/org/apache/log4j/ListAppender.java   |   7 +-
 .../config/PropertiesConfigurationFactoryTest.java |   4 +-
 .../log4j/config/XmlConfigurationFactoryTest.java  |   4 +-
 .../properties/JavaPropsConfigurationFactory.java  |   6 +-
 .../config/yaml/YamlConfigurationFactory.java      |   6 +-
 .../log4j/core/test/BasicConfigurationFactory.java |   4 +-
 .../core/test/junit/ConfigurationFactoryType.java  |   4 +-
 .../apache/logging/log4j/core/LoggerContext.java   |   1 -
 .../core/config/AbstractConfigurationFactory.java  | 172 +++++++++++++++++++++
 .../log4j/core/config/ConfigurationSource.java     |  14 +-
 .../apache/logging/log4j/core/config/Order.java    |   2 +-
 .../core/config/json/JsonConfigurationFactory.java |   8 +-
 .../core/config/xml/XmlConfigurationFactory.java   |   6 +-
 .../log4j/core/impl/SystemPropertyBundle.java      |   4 +-
 .../osgi/tests/CustomConfigurationFactory.java     |   6 +-
 .../config/builder/CustomConfigurationFactory.java |   6 +-
 25 files changed, 280 insertions(+), 64 deletions(-)

diff --git a/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java 
b/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
index 7d3014b23f..3e5e34a09d 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/Category.java
@@ -237,7 +237,7 @@ public class Category implements AppenderAttachable {
      */
     public void callAppenders(final LoggingEvent event) {
         if (LogManager.isLog4jCorePresent()) {
-            CategoryUtil.log(logger, new LogEventWrapper(event));
+            CategoryUtil.log(logger, LogEventWrapper.adapt(event));
             return;
         }
         int writes = 0;
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java 
b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
index 411258e20f..297d9ae248 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/AppenderAdapter.java
@@ -85,7 +85,7 @@ public final class AppenderAdapter {
 
         @Override
         public void append(final LogEvent event) {
-            appender.doAppend(new LogEventAdapter(event));
+            appender.doAppend(LogEventAdapter.adapt(event));
         }
 
         @Override
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java 
b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java
index 40209ef813..8be75614d7 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventAdapter.java
@@ -41,6 +41,10 @@ public class LogEventAdapter extends LoggingEvent {
 
     private final LogEvent event;
 
+    public static LoggingEvent adapt(final LogEvent event) {
+        return event instanceof final LogEventWrapper wrapper ? 
wrapper.getLoggingEvent() : new LogEventAdapter(event);
+    }
+
     public LogEventAdapter(final LogEvent event) {
         this.event = event;
     }
@@ -213,4 +217,13 @@ public class LogEventAdapter extends LoggingEvent {
     public Map getProperties() {
         return event.getContextData().toMap();
     }
+
+    public LoggingEvent toImmutable() {
+        final LogEvent immutable = event.toImmutable();
+        return event == immutable ? this : adapt(immutable);
+    }
+
+    LogEvent getLogEvent() {
+        return event;
+    }
 }
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java 
b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java
index e0db478fa1..df63b8aa59 100644
--- a/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java
+++ b/log4j-1.2-api/src/main/java/org/apache/log4j/bridge/LogEventWrapper.java
@@ -49,6 +49,10 @@ public class LogEventWrapper implements LogEvent {
     private final MutableThreadContextStack contextStack;
     private Thread thread;
 
+    public static LogEvent adapt(final LoggingEvent event) {
+        return event instanceof final LogEventAdapter adapter ? 
adapter.getLogEvent() : new LogEventWrapper(event);
+    }
+
     public LogEventWrapper(final LoggingEvent event) {
         this.event = event;
         this.contextData = new ContextDataMap(event.getProperties());
@@ -182,6 +186,10 @@ public class LogEventWrapper implements LogEvent {
         return 0;
     }
 
+    LoggingEvent getLoggingEvent() {
+        return event;
+    }
+
     private static class ContextDataMap extends HashMap<String, String> 
implements ReadOnlyStringMap {
 
         ContextDataMap(final Map<String, String> map) {
diff --git 
a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
 
b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
index 5454ad7c0b..b4f2ff0e76 100644
--- 
a/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
+++ 
b/log4j-1.2-api/src/main/java/org/apache/log4j/config/Log4j1ConfigurationFactory.java
@@ -19,9 +19,9 @@ package org.apache.log4j.config;
 import java.io.IOException;
 import java.io.InputStream;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 import org.apache.logging.log4j.core.config.Configuration;
 import org.apache.logging.log4j.core.config.ConfigurationException;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
 import org.apache.logging.log4j.core.config.ConfigurationSource;
 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
 import org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
@@ -35,7 +35,7 @@ import 
org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
 //
 // Best Value?
 // @Order(50)
-public class Log4j1ConfigurationFactory extends ConfigurationFactory {
+public class Log4j1ConfigurationFactory extends AbstractConfigurationFactory {
 
     private static final String[] SUFFIXES = {".properties"};
 
@@ -51,7 +51,7 @@ public class Log4j1ConfigurationFactory extends 
ConfigurationFactory {
     }
 
     @Override
-    protected String[] getSupportedTypes() {
+    public String[] getSupportedTypes() {
         return SUFFIXES;
     }
 }
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
index 7ca6314c66..5286db9e24 100644
--- 
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
@@ -17,8 +17,8 @@
 package org.apache.log4j.config;
 
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.plugins.Namespace;
@@ -28,10 +28,10 @@ import org.apache.logging.log4j.util.PropertiesUtil;
 /**
  * Configures Log4j from a log4j 1 format properties file.
  */
-@Namespace(ConfigurationFactory.NAMESPACE)
+@Namespace(AbstractConfigurationFactory.NAMESPACE)
 @Plugin("Log4j1PropertiesConfigurationFactory")
 @Order(2)
-public class PropertiesConfigurationFactory extends ConfigurationFactory {
+public class PropertiesConfigurationFactory extends 
AbstractConfigurationFactory {
 
     static final String FILE_EXTENSION = ".properties";
 
@@ -46,9 +46,9 @@ public class PropertiesConfigurationFactory extends 
ConfigurationFactory {
     protected static final String DEFAULT_PREFIX = "log4j";
 
     @Override
-    protected String[] getSupportedTypes() {
+    public String[] getSupportedTypes() {
         if (!PropertiesUtil.getProperties()
-                .getBooleanProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, 
Boolean.FALSE)) {
+                
.getBooleanProperty(AbstractConfigurationFactory.LOG4J1_EXPERIMENTAL, 
Boolean.FALSE)) {
             return null;
         }
         return new String[] {FILE_EXTENSION};
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 78d1cae463..5734304b60 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
@@ -18,8 +18,8 @@ package org.apache.log4j.xml;
 
 import org.apache.log4j.config.Log4j1Configuration;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.plugins.Namespace;
@@ -29,10 +29,10 @@ import org.apache.logging.log4j.util.PropertiesUtil;
 /**
  * Constructs a Configuration usable in Log4j 2 from a Log4j 1 configuration 
file.
  */
-@Namespace(ConfigurationFactory.NAMESPACE)
+@Namespace(AbstractConfigurationFactory.NAMESPACE)
 @Plugin("Log4j1XmlConfigurationFactory")
 @Order(2)
-public class XmlConfigurationFactory extends ConfigurationFactory {
+public class XmlConfigurationFactory extends AbstractConfigurationFactory {
 
     public static final String FILE_EXTENSION = ".xml";
 
@@ -47,9 +47,9 @@ public class XmlConfigurationFactory extends 
ConfigurationFactory {
     protected static final String DEFAULT_PREFIX = "log4j";
 
     @Override
-    protected String[] getSupportedTypes() {
+    public String[] getSupportedTypes() {
         if (!PropertiesUtil.getProperties()
-                .getBooleanProperty(ConfigurationFactory.LOG4J1_EXPERIMENTAL, 
Boolean.FALSE)) {
+                
.getBooleanProperty(AbstractConfigurationFactory.LOG4J1_EXPERIMENTAL, 
Boolean.FALSE)) {
             return null;
         }
         return new String[] {FILE_EXTENSION};
diff --git 
a/log4j-1.2-api/src/test/java/org/apache/log4j/BasicConfigurationFactory.java 
b/log4j-1.2-api/src/test/java/org/apache/log4j/BasicConfigurationFactory.java
index fbf5ba1d5f..0c817d234c 100644
--- 
a/log4j-1.2-api/src/test/java/org/apache/log4j/BasicConfigurationFactory.java
+++ 
b/log4j-1.2-api/src/test/java/org/apache/log4j/BasicConfigurationFactory.java
@@ -20,15 +20,15 @@ import java.net.URI;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.AbstractConfiguration;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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;
 
 /**
  *
  */
-public class BasicConfigurationFactory extends ConfigurationFactory {
+public class BasicConfigurationFactory extends AbstractConfigurationFactory {
 
     @Override
     protected String[] getSupportedTypes() {
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java 
b/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java
index 0dc789bcf5..8beb7acb1d 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/CategoryTest.java
@@ -16,6 +16,7 @@
  */
 package org.apache.log4j;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
 import static org.junit.jupiter.api.Assertions.assertNotNull;
@@ -334,7 +335,7 @@ public class CategoryTest {
     public void testAddAppender() {
         try {
             final Logger rootLogger = LogManager.getRootLogger();
-            int count = version1Appender.getEvents().size();
+            version1Appender.clear();
             rootLogger.addAppender(version1Appender);
             final Logger logger = LogManager.getLogger(CategoryTest.class);
             final org.apache.log4j.ListAppender appender = new 
org.apache.log4j.ListAppender();
@@ -342,17 +343,35 @@ public class CategoryTest {
             logger.addAppender(appender);
             // Root logger
             rootLogger.info("testAddLogger");
-            assertEquals(++count, version1Appender.getEvents().size(), "adding 
at root works");
-            assertEquals(0, appender.getEvents().size(), "adding at child 
works");
+            assertThat(version1Appender.getEvents())
+                    .as("check root logger events")
+                    .extracting(LoggingEvent::getRenderedMessage)
+                    .containsExactly("testAddLogger");
+            assertThat(appender.getEvents())
+                    .as("check logger '%s' events", logger.getName())
+                    .isEmpty();
             // Another logger
             logger.info("testAddLogger2");
-            assertEquals(++count, version1Appender.getEvents().size(), "adding 
at root works");
-            assertEquals(1, appender.getEvents().size(), "adding at child 
works");
+            assertThat(version1Appender.getEvents())
+                    .as("check root logger events")
+                    .extracting(LoggingEvent::getRenderedMessage)
+                    .containsExactly("testAddLogger", "testAddLogger2");
+            assertThat(appender.getEvents())
+                    .as("check logger '%s' events", logger.getName())
+                    .extracting(LoggingEvent::getRenderedMessage)
+                    .containsExactly("testAddLogger2");
             // Call appenders
-            final LoggingEvent event = new LoggingEvent();
+            version1Appender.clear();
+            appender.clear();
+            class MyCustomEvent extends LoggingEvent {}
+            final LoggingEvent event = new MyCustomEvent();
             logger.callAppenders(event);
-            assertEquals(++count, version1Appender.getEvents().size(), 
"callAppenders");
-            assertEquals(2, appender.getEvents().size(), "callAppenders");
+            assertThat(version1Appender.getEvents())
+                    .as("check root logger events")
+                    .containsExactly(event);
+            assertThat(appender.getEvents())
+                    .as("check logger '%s' events", logger.getName())
+                    .containsExactly(event);
         } finally {
             LogManager.resetConfiguration();
         }
diff --git a/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java 
b/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java
index cfc9fe49bc..efe01197ec 100644
--- a/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java
+++ b/log4j-1.2-api/src/test/java/org/apache/log4j/ListAppender.java
@@ -22,6 +22,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.concurrent.TimeUnit;
+import org.apache.log4j.bridge.LogEventAdapter;
 import org.apache.log4j.spi.LoggingEvent;
 
 /**
@@ -45,13 +46,17 @@ public class ListAppender extends AppenderSkeleton {
                 messages.add(result);
             }
         } else {
-            events.add(event);
+            events.add(event instanceof final LogEventAdapter adapter ? 
adapter.toImmutable() : event);
         }
     }
 
     @Override
     public void close() {}
 
+    public void clear() {
+        events.clear();
+    }
+
     @Override
     public boolean requiresLayout() {
         return false;
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
index fc4fd25d0e..6d4a9b358a 100644
--- 
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
@@ -21,7 +21,7 @@ import static org.junit.Assert.assertTrue;
 import java.io.File;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -33,7 +33,7 @@ public class PropertiesConfigurationFactoryTest {
     @BeforeClass
     public static void beforeClass() {
         System.setProperty(
-                
ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY.getSystemKey(),
+                
AbstractConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY.getSystemKey(),
                 "target/test-classes/log4j1-file-1.properties");
     }
 
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 49bb5a7792..afa80683c4 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
@@ -21,7 +21,7 @@ import static org.junit.Assert.assertTrue;
 import java.io.File;
 import org.apache.log4j.LogManager;
 import org.apache.log4j.Logger;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -33,7 +33,7 @@ public class XmlConfigurationFactoryTest {
     @BeforeClass
     public static void beforeClass() {
         System.setProperty(
-                
ConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY.getSystemKey(),
+                
AbstractConfigurationFactory.LOG4J1_CONFIGURATION_FILE_PROPERTY.getSystemKey(),
                 "target/test-classes/log4j1-file.xml");
     }
 
diff --git 
a/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfigurationFactory.java
 
b/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfigurationFactory.java
index b585cdc6e5..b2e64d8070 100644
--- 
a/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfigurationFactory.java
+++ 
b/log4j-config-properties/src/main/java/org/apache/logging/log4j/config/properties/JavaPropsConfigurationFactory.java
@@ -17,17 +17,17 @@
 package org.apache.logging.log4j.config.properties;
 
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.plugins.Namespace;
 import org.apache.logging.log4j.plugins.Plugin;
 
-@Namespace(ConfigurationFactory.NAMESPACE)
+@Namespace(AbstractConfigurationFactory.NAMESPACE)
 @Plugin
 @Order(8)
-public class JavaPropsConfigurationFactory extends ConfigurationFactory {
+public class JavaPropsConfigurationFactory extends 
AbstractConfigurationFactory {
 
     /**
      * The file extensions supported by this factory.
diff --git 
a/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactory.java
 
b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactory.java
index ae6c4d9503..fc61eccd0a 100644
--- 
a/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactory.java
+++ 
b/log4j-config-yaml/src/main/java/org/apache/logging/log4j/config/yaml/YamlConfigurationFactory.java
@@ -17,17 +17,17 @@
 package org.apache.logging.log4j.config.yaml;
 
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.plugins.Namespace;
 import org.apache.logging.log4j.plugins.Plugin;
 
-@Namespace(ConfigurationFactory.NAMESPACE)
+@Namespace(AbstractConfigurationFactory.NAMESPACE)
 @Plugin("YamlConfigurationFactory")
 @Order(7)
-public class YamlConfigurationFactory extends ConfigurationFactory {
+public class YamlConfigurationFactory extends AbstractConfigurationFactory {
 
     /**
      * The file extensions supported by this factory.
diff --git 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
index 643b77741d..5dedf79ae8 100644
--- 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
+++ 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/BasicConfigurationFactory.java
@@ -20,8 +20,8 @@ import java.net.URI;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.config.AbstractConfiguration;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.plugins.di.ConfigurableInstanceFactory;
@@ -31,7 +31,7 @@ import org.apache.logging.log4j.util.PropertiesUtil;
 /**
  *
  */
-public class BasicConfigurationFactory extends ConfigurationFactory {
+public class BasicConfigurationFactory extends AbstractConfigurationFactory {
 
     @Override
     public Configuration getConfiguration(
diff --git 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationFactoryType.java
 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationFactoryType.java
index be40bc61b0..097265c178 100644
--- 
a/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationFactoryType.java
+++ 
b/log4j-core-test/src/main/java/org/apache/logging/log4j/core/test/junit/ConfigurationFactoryType.java
@@ -21,11 +21,11 @@ import java.lang.annotation.Inherited;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 import org.apache.logging.log4j.core.config.URIConfigurationFactory;
 
 /**
- * Specifies a particular {@link ConfigurationFactory} class to use for a test 
class or method instead of the default.
+ * Specifies a particular {@link AbstractConfigurationFactory} class to use 
for a test class or method instead of the default.
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target({ElementType.TYPE, ElementType.METHOD})
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
index 6b2a2898c1..44f1849639 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/LoggerContext.java
@@ -201,7 +201,6 @@ public class LoggerContext extends AbstractLifeCycle
         }
     }
 
-    @Override
     public PropertyEnvironment getEnvironment() {
         return environment;
     }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfigurationFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfigurationFactory.java
new file mode 100644
index 0000000000..f1dd503d10
--- /dev/null
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/AbstractConfigurationFactory.java
@@ -0,0 +1,172 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to you under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.logging.log4j.core.config;
+
+import java.net.URI;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.core.LoggerContext;
+import 
org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilderFactory;
+import org.apache.logging.log4j.core.impl.Log4jPropertyKey;
+import org.apache.logging.log4j.plugins.Namespace;
+import org.apache.logging.log4j.plugins.di.ConfigurableInstanceFactory;
+import org.apache.logging.log4j.plugins.di.Key;
+import org.apache.logging.log4j.plugins.model.PluginNamespace;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.LoaderUtil;
+import org.apache.logging.log4j.util.PropertyKey;
+
+/**
+ * Factory class for parsed {@link Configuration} objects from a configuration 
file.
+ * ConfigurationFactory allows the configuration implementation to be
+ * dynamically chosen in 1 of 3 ways:
+ * <ol>
+ * <li>A system property named "log4j.configurationFactory" can be set with the
+ * name of the ConfigurationFactory to be used.</li>
+ * <li>A {@link ConfigurableInstanceFactory} binding for ConfigurationFactory 
may be registered.</li>
+ * <li>
+ * A ConfigurationFactory implementation can be added to the classpath and 
configured as a plugin in the
+ * {@link #NAMESPACE ConfigurationFactory} category. The {@link Order} 
annotation should be used to configure the
+ * factory to be the first one inspected. See
+ * {@linkplain 
org.apache.logging.log4j.core.config.xml.XmlConfigurationFactory} for an 
example.</li>
+ * </ol>
+ *
+ * If the ConfigurationFactory that was added returns null on a call to
+ * getConfiguration then any other ConfigurationFactories found as plugins will
+ * be called in their respective order. DefaultConfiguration is always called
+ * last if no configuration has been returned.
+ */
+public abstract class AbstractConfigurationFactory extends 
ConfigurationBuilderFactory implements ConfigurationFactory {
+
+    public static final PropertyKey LOG4J1_CONFIGURATION_FILE_PROPERTY = 
Log4jPropertyKey.CONFIG_V1_FILE_NAME;
+
+    public static final PropertyKey LOG4J1_EXPERIMENTAL = 
Log4jPropertyKey.CONFIG_V1_COMPATIBILITY_ENABLED;
+
+    /**
+     * Plugin category used to inject a ConfigurationFactory {@link 
org.apache.logging.log4j.plugins.Plugin}
+     * class.
+     *
+     * @since 2.1
+     */
+    public static final String NAMESPACE = "ConfigurationFactory";
+
+    public static final Key<ConfigurationFactory> KEY = new Key<>() {};
+
+    public static final Key<PluginNamespace> PLUGIN_NAMESPACE_KEY = new 
@Namespace(NAMESPACE) Key<>() {};
+
+    /**
+     * Allows subclasses access to the status logger without creating another 
instance.
+     */
+    protected static final Logger LOGGER = StatusLogger.getLogger();
+
+    /**
+     * File name prefix for test configurations.
+     */
+    protected static final String TEST_PREFIX = "log4j2-test";
+
+    /**
+     * File name prefix for standard configurations.
+     */
+    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.
+     */
+    private static final String CLASS_LOADER_SCHEME = "classloader";
+
+    /**
+     * The name of the classpath URI scheme, synonymous with the classloader 
URI scheme.
+     */
+    private static final String CLASS_PATH_SCHEME = "classpath";
+
+    @Override
+    public String getTestPrefix() {
+        return TEST_PREFIX;
+    }
+
+    @Override
+    public String getDefaultPrefix() {
+        return DEFAULT_PREFIX;
+    }
+
+    @Override
+    public String getVersion() {
+        return LOG4J2_VERSION;
+    }
+
+    /**
+     * Returns the Configuration.
+     * @param loggerContext The logger context
+     * @param name The configuration name.
+     * @param configLocation The configuration location.
+     * @return The Configuration.
+     */
+    @Override
+    public Configuration getConfiguration(
+            final LoggerContext loggerContext, final String name, final URI 
configLocation) {
+        if (configLocation != null) {
+            final ConfigurationSource source = 
ConfigurationSource.fromUri(configLocation);
+            if (source != null) {
+                return getConfiguration(loggerContext, source);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Returns the Configuration obtained using a given ClassLoader.
+     * @param loggerContext The logger context
+     * @param name The configuration name.
+     * @param configLocation A URI representing the location of the 
configuration.
+     * @param loader The default ClassLoader to use. If this is {@code null}, 
then the
+     *               {@linkplain LoaderUtil#getThreadContextClassLoader() 
default ClassLoader} will be used.
+     *
+     * @return The Configuration.
+     */
+    @Override
+    public Configuration getConfiguration(
+            final LoggerContext loggerContext, final String name, final URI 
configLocation, final ClassLoader loader) {
+        if (loader == null) {
+            return getConfiguration(loggerContext, name, configLocation);
+        }
+        if (isClassLoaderUri(configLocation)) {
+            final String path = extractClassLoaderUriPath(configLocation);
+            final ConfigurationSource source = 
ConfigurationSource.fromResource(path, loader);
+            if (source != null) {
+                final Configuration configuration = 
getConfiguration(loggerContext, source);
+                if (configuration != null) {
+                    return configuration;
+                }
+            }
+        }
+        return getConfiguration(loggerContext, name, configLocation);
+    }
+
+    static boolean isClassLoaderUri(final URI uri) {
+        if (uri == null) {
+            return false;
+        }
+        final String scheme = uri.getScheme();
+        return scheme == null || scheme.equals(CLASS_LOADER_SCHEME) || 
scheme.equals(CLASS_PATH_SCHEME);
+    }
+
+    static String extractClassLoaderUriPath(final URI uri) {
+        return uri.getScheme() == null ? uri.getPath() : 
uri.getSchemeSpecificPart();
+    }
+}
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
index 86f932d888..15619d6b5c 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/ConfigurationSource.java
@@ -290,23 +290,23 @@ public class ConfigurationSource {
             try {
                 return new ConfigurationSource(new 
FileInputStream(configFile), configFile);
             } catch (final FileNotFoundException ex) {
-                ConfigurationFactory.LOGGER.error("Cannot locate file {}", 
configLocation.getPath(), ex);
+                AbstractConfigurationFactory.LOGGER.error("Cannot locate file 
{}", configLocation.getPath(), ex);
             }
         }
-        if (ConfigurationFactory.isClassLoaderUri(configLocation)) {
+        if (AbstractConfigurationFactory.isClassLoaderUri(configLocation)) {
             final ClassLoader loader = 
LoaderUtil.getThreadContextClassLoader();
-            final String path = 
ConfigurationFactory.extractClassLoaderUriPath(configLocation);
+            final String path = 
AbstractConfigurationFactory.extractClassLoaderUriPath(configLocation);
             return fromResource(path, loader);
         }
         if (!configLocation.isAbsolute()) { // LOG4J2-704 avoid confusing 
error message thrown by uri.toURL()
-            ConfigurationFactory.LOGGER.error(
+            AbstractConfigurationFactory.LOGGER.error(
                     "File not found in file system or classpath: {}", 
configLocation.toString());
             return null;
         }
         try {
             return getConfigurationSource(configLocation.toURL());
         } catch (final MalformedURLException ex) {
-            ConfigurationFactory.LOGGER.error("Invalid URL {}", 
configLocation.toString(), ex);
+            AbstractConfigurationFactory.LOGGER.error("Invalid URL {}", 
configLocation.toString(), ex);
         }
         return null;
     }
@@ -360,11 +360,11 @@ public class ConfigurationSource {
                             urlConnection.getInputStream(), url, 
urlConnection.getLastModified());
                 }
             } catch (final FileNotFoundException ex) {
-                ConfigurationFactory.LOGGER.info("Unable to locate file {}, 
ignoring.", url.toString());
+                AbstractConfigurationFactory.LOGGER.info("Unable to locate 
file {}, ignoring.", url.toString());
                 return null;
             }
         } catch (final IOException | URISyntaxException ex) {
-            ConfigurationFactory.LOGGER.warn(
+            AbstractConfigurationFactory.LOGGER.warn(
                     "Error accessing {} due to {}, ignoring.", url.toString(), 
ex.getMessage());
             return null;
         }
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Order.java 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Order.java
index 2421f42021..8fe1d7b4c9 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Order.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/Order.java
@@ -22,7 +22,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Identifies the relative ordering of a {@link ConfigurationFactory} plugin.
+ * Identifies the relative ordering of a {@link AbstractConfigurationFactory} 
plugin.
  *
  * @see OrderComparator
  */
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java
index 048b0a9f62..d8147c12f5 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/json/JsonConfigurationFactory.java
@@ -17,17 +17,17 @@
 package org.apache.logging.log4j.core.config.json;
 
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.plugins.Namespace;
 import org.apache.logging.log4j.plugins.Plugin;
 
-@Namespace(ConfigurationFactory.NAMESPACE)
+@Namespace(AbstractConfigurationFactory.NAMESPACE)
 @Plugin("JsonConfigurationFactory")
 @Order(6)
-public class JsonConfigurationFactory extends ConfigurationFactory {
+public class JsonConfigurationFactory extends AbstractConfigurationFactory {
 
     /**
      * The file extensions supported by this factory.
@@ -35,7 +35,7 @@ public class JsonConfigurationFactory extends 
ConfigurationFactory {
     private static final String[] SUFFIXES = new String[] {".json", ".jsn"};
 
     @Override
-    protected String[] getSupportedTypes() {
+    public String[] getSupportedTypes() {
         return SUFFIXES;
     }
 
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java
index 0e75d5cc20..fb7ebb9972 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/config/xml/XmlConfigurationFactory.java
@@ -17,8 +17,8 @@
 package org.apache.logging.log4j.core.config.xml;
 
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.plugins.Namespace;
@@ -27,10 +27,10 @@ import org.apache.logging.log4j.plugins.Plugin;
 /**
  * Factory to construct an XmlConfiguration.
  */
-@Namespace(ConfigurationFactory.NAMESPACE)
+@Namespace(AbstractConfigurationFactory.NAMESPACE)
 @Plugin("XmlConfigurationFactory")
 @Order(5)
-public class XmlConfigurationFactory extends ConfigurationFactory {
+public class XmlConfigurationFactory extends AbstractConfigurationFactory {
 
     /**
      * Valid file extensions for XML files.
diff --git 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/SystemPropertyBundle.java
 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/SystemPropertyBundle.java
index fc9fba3fb3..22dc3c91e7 100644
--- 
a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/SystemPropertyBundle.java
+++ 
b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/SystemPropertyBundle.java
@@ -19,7 +19,7 @@ package org.apache.logging.log4j.core.impl;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.ContextDataInjector;
 import org.apache.logging.log4j.core.annotation.ConditionalOnPropertyKey;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 import org.apache.logging.log4j.core.config.composite.MergeStrategy;
 import org.apache.logging.log4j.core.selector.ContextSelector;
 import org.apache.logging.log4j.core.util.ShutdownCallbackRegistry;
@@ -40,7 +40,7 @@ import org.apache.logging.log4j.util.PropertyKey;
  * @see Log4jPropertyKey
  * @see ContextSelector
  * @see ShutdownCallbackRegistry
- * @see ConfigurationFactory
+ * @see AbstractConfigurationFactory
  * @see MergeStrategy
  * @see ContextDataInjector
  * @see LogEventFactory
diff --git 
a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java
 
b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java
index 6ce34c37bc..08a7a8505c 100644
--- 
a/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java
+++ 
b/log4j-osgi-test/src/test/java/org/apache/logging/log4j/osgi/tests/CustomConfigurationFactory.java
@@ -18,8 +18,8 @@ package org.apache.logging.log4j.osgi.tests;
 
 import java.net.URI;
 import org.apache.logging.log4j.core.LoggerContext;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.plugins.Namespace;
@@ -28,10 +28,10 @@ import org.apache.logging.log4j.plugins.Plugin;
 /**
  * Factory to construct a  CustomConfiguration.
  */
-@Namespace(ConfigurationFactory.NAMESPACE)
+@Namespace(AbstractConfigurationFactory.NAMESPACE)
 @Plugin("CustomConfigurationFactory")
 @Order(50)
-public final class CustomConfigurationFactory extends ConfigurationFactory {
+public final class CustomConfigurationFactory extends 
AbstractConfigurationFactory {
 
     /**
      * Valid file extensions for XML files.
diff --git 
a/log4j-script/src/test/java/org/apache/logging/log4j/script/config/builder/CustomConfigurationFactory.java
 
b/log4j-script/src/test/java/org/apache/logging/log4j/script/config/builder/CustomConfigurationFactory.java
index 441156af84..459d9839f9 100644
--- 
a/log4j-script/src/test/java/org/apache/logging/log4j/script/config/builder/CustomConfigurationFactory.java
+++ 
b/log4j-script/src/test/java/org/apache/logging/log4j/script/config/builder/CustomConfigurationFactory.java
@@ -21,8 +21,8 @@ import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.core.Filter;
 import org.apache.logging.log4j.core.LoggerContext;
 import org.apache.logging.log4j.core.appender.ConsoleAppender;
+import org.apache.logging.log4j.core.config.AbstractConfigurationFactory;
 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.builder.api.AppenderComponentBuilder;
 import org.apache.logging.log4j.core.config.builder.api.ConfigurationBuilder;
@@ -35,7 +35,7 @@ import 
org.apache.logging.log4j.core.config.builder.impl.BuiltConfiguration;
 // @Category(ConfigurationFactory.CATEGORY)
 // @Plugin("CustomConfigurationFactory")
 // @Order(50)
-public class CustomConfigurationFactory extends ConfigurationFactory {
+public class CustomConfigurationFactory extends AbstractConfigurationFactory {
 
     public static Configuration addTestFixtures(
             final String name, final ConfigurationBuilder<BuiltConfiguration> 
builder) {
@@ -77,7 +77,7 @@ public class CustomConfigurationFactory extends 
ConfigurationFactory {
     }
 
     @Override
-    protected String[] getSupportedTypes() {
+    public String[] getSupportedTypes() {
         return new String[] {"*"};
     }
 }


Reply via email to