You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by rp...@apache.org on 2016/09/11 06:27:42 UTC

[01/50] logging-log4j2 git commit: LOG4J2-1010 document that the factory method for ContextDataInjectors may be called multiple times

Repository: logging-log4j2
Updated Branches:
  refs/heads/master a331f95e6 -> 7ec63ce9b


LOG4J2-1010 document that the factory method for ContextDataInjectors may be called multiple times


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/947d9d62
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/947d9d62
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/947d9d62

Branch: refs/heads/master
Commit: 947d9d626ae157f501dc10fdc930d69080623e6c
Parents: 16bcf3f
Author: rpopma <rp...@apache.org>
Authored: Sun Aug 28 22:20:25 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Aug 28 22:20:25 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/core/impl/ContextDataInjectorFactory.java    | 6 ++++++
 1 file changed, 6 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/947d9d62/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
index ac5c38c..f35e30a 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
@@ -46,6 +46,12 @@ public class ContextDataInjectorFactory {
      * <p>
      * Users may use this system property to specify the fully qualified class name of a class that implements the
      * {@code ContextDataInjector} interface.
+     * </p><p>
+     * When providing a custom {@code ContextDataInjector}, be aware that this method may be invoked multiple times by
+     * the various components in Log4j that need access to context data.
+     * This includes the object(s) that populate log events, but also various lookups and filters that look at
+     * context data to determine whether an event should be logged.
+     * </p>
      *
      * @return a ContextDataInjector that populates the {@code ContextData} of all {@code LogEvent} objects
      */


[25/50] logging-log4j2 git commit: LOG4J2-1349 added test

Posted by rp...@apache.org.
LOG4J2-1349 added test


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/c5d8f76b
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/c5d8f76b
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/c5d8f76b

Branch: refs/heads/master
Commit: c5d8f76b877afe8ba5d5d8ca8deb0a2158a22412
Parents: 1e4f0ff
Author: rpopma <rp...@apache.org>
Authored: Fri Sep 2 23:20:47 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Sep 2 23:20:47 2016 +0900

----------------------------------------------------------------------
 ...AsyncLoggerGarbageFreeThreadContextTest.java | 83 ++++++++++++++++++++
 1 file changed, 83 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c5d8f76b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerGarbageFreeThreadContextTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerGarbageFreeThreadContextTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerGarbageFreeThreadContextTest.java
new file mode 100644
index 0000000..da232bd
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerGarbageFreeThreadContextTest.java
@@ -0,0 +1,83 @@
+/*
+ * 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.async;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.core.CoreLoggerContexts;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.util.Unbox;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class AsyncLoggerGarbageFreeThreadContextTest {
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty("log4j2.garbagefree.threadContextMap", "true");
+        System.setProperty("AsyncLogger.RingBufferSize", "128"); // minimum ringbuffer size
+        System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,
+                AsyncLoggerContextSelector.class.getName());
+        System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
+                "AsyncLoggerThreadContextTest.xml");
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
+    }
+
+    @Test
+    public void testAsyncLogWritesToLog() throws Exception {
+        final File file = new File("target", "AsyncLoggerTest.log");
+        // System.out.println(f.getAbsolutePath());
+        file.delete();
+
+        ThreadContext.push("stackvalue");
+        ThreadContext.put("KEY", "mapvalue");
+
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        final String msg = "Async logger msg";
+        for (int i = 0; i < 128; i++) {
+            log.info("init message #{}", Unbox.box(i));
+        }
+        log.info(msg, new InternalError("this is not a real error"));
+        CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
+
+        final BufferedReader reader = new BufferedReader(new FileReader(file));
+        for (int i = 0; i < 128; i++) {
+            reader.readLine();
+        }
+        final String line1 = reader.readLine();
+        reader.close();
+        file.delete();
+        assertNotNull("line1", line1);
+        assertTrue("line1 correct", line1.contains(msg));
+
+        assertTrue("ThreadContext.map", line1.contains("mapvalue"));
+        assertTrue("ThreadContext.stack", line1.contains("stackvalue"));
+    }
+}


[47/50] logging-log4j2 git commit: LOG4J2-1349 extend context data injector tests to cover all combinations default threadcontextmap, copyOnWriteThreadContextData and garbage-free threadcontextdata with all combinations of synchronous, async appender, as

Posted by rp...@apache.org.
LOG4J2-1349 extend context data injector tests to cover all combinations default threadcontextmap, copyOnWriteThreadContextData and garbage-free threadcontextdata with all combinations of synchronous, async appender, async logger (pure), async logger (mixed), asyncAppender + asyncLogger(pure), asyncAppender+asyncLogger(mixed) and asyncAppender+asyncLogger(pure)+asyncLogger(mixed)


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e8a25a97
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e8a25a97
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e8a25a97

Branch: refs/heads/master
Commit: e8a25a97cb0c1746383c11f7d9b4b5db81ebf9c7
Parents: 25615a4
Author: rpopma <rp...@apache.org>
Authored: Sat Sep 10 01:35:27 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sat Sep 10 01:35:27 2016 +0900

----------------------------------------------------------------------
 ...ggerAllThreadContextImplementationsTest.java | 25 ++++++++++++--------
 ...nfigAllThreadContextImplementationsTest.java | 19 +++++++++++----
 .../AsyncLoggerConfigThreadContextTest.xml      | 20 ++++++++++++++++
 3 files changed, 49 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e8a25a97/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
index 6cd89f4..4283cbb 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
@@ -132,12 +132,15 @@ public class AsyncLoggerAllThreadContextImplementationsTest {
 
     @Test
     public void testAsyncLogWritesToLog() throws Exception {
-        final File file = new File("target", "AsyncLoggerTest.log");
-        // System.out.println(f.getAbsolutePath());
-        file.delete();
-
-        final File sync = new File("target", "SynchronousContextTest.log");
-        sync.delete();
+        final File[] files = new File[] {
+                new File("target", "AsyncLoggerTest.log"), //
+                new File("target", "SynchronousContextTest.log"), //
+                new File("target", "AsyncLoggerAndAsyncAppenderTest.log"), //
+                new File("target", "AsyncAppenderContextTest.log"), //
+        };
+        for (final File f : files) {
+            f.delete();
+        }
 
         ThreadContext.push("stackvalue");
         ThreadContext.put("KEY", "mapvalue");
@@ -159,11 +162,13 @@ public class AsyncLoggerAllThreadContextImplementationsTest {
             log.info("{} {} {} i={}", contextImpl, contextmap, loggerContextName, Unbox.box(i));
         }
         ThreadContext.pop();
-        CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
+        CoreLoggerContexts.stopLoggerContext(false, files[0]); // stop async thread
 
-        checkResult(file, loggerContextName);
+        checkResult(files[0], loggerContextName);
         if (asyncMode == Mode.MIXED || asyncMode == Mode.BOTH_ALL_ASYNC_AND_MIXED) {
-            checkResult(sync, loggerContextName);
+            for (int i = 1; i < files.length; i++) {
+                checkResult(files[i], loggerContextName);
+            }
         }
         LogManager.shutdown();
     }
@@ -180,7 +185,7 @@ public class AsyncLoggerAllThreadContextImplementationsTest {
                 } else {
                     expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue} " + contextDesc + " i=" + i;
                 }
-                assertEquals("line " + i, expect, line);
+                assertEquals(file.getName() + ": line " + i, expect, line);
             }
             final String noMoreLines = reader.readLine();
             assertNull("done", noMoreLines);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e8a25a97/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
index 74de230..3c3d69c 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
@@ -105,8 +105,15 @@ public class AsyncLoggerConfigAllThreadContextImplementationsTest {
 
     @Test
     public void testAsyncLogWritesToLog() throws Exception {
-        final File file = new File("target", "SynchronousContextTest.log");
-        file.delete();
+        final File[] files = new File[] {
+                new File("target", "AsyncLoggerTest.log"), //
+                new File("target", "SynchronousContextTest.log"), //
+                new File("target", "AsyncLoggerAndAsyncAppenderTest.log"), //
+                new File("target", "AsyncAppenderContextTest.log"), //
+        };
+        for (final File f : files) {
+            f.delete();
+        }
 
         ThreadContext.push("stackvalue");
         ThreadContext.put("KEY", "mapvalue");
@@ -129,9 +136,11 @@ public class AsyncLoggerConfigAllThreadContextImplementationsTest {
             log.info("{} {} {} i={}", contextImpl, contextmap, loggerContextName, Unbox.box(i));
         }
         ThreadContext.pop();
-        CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
+        CoreLoggerContexts.stopLoggerContext(false, files[files.length - 1]); // stop async thread
 
-        checkResult(file, loggerContextName);
+        for (final File f : files) {
+            checkResult(f, loggerContextName);
+        }
         LogManager.shutdown();
     }
 
@@ -147,7 +156,7 @@ public class AsyncLoggerConfigAllThreadContextImplementationsTest {
                 } else {
                     expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue} " + contextDesc + " i=" + i;
                 }
-                assertEquals("line " + i, expect, line);
+                assertEquals(file.getName() + ": line " + i, expect, line);
             }
             final String noMoreLines = reader.readLine();
             assertNull("done", noMoreLines);

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e8a25a97/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml b/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
index 5419e20..1ce6faa 100644
--- a/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
+++ b/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
@@ -4,6 +4,24 @@
     <Property name="configProp">configValue</Property>
   </Properties>
   <Appenders>
+    <RandomAccessFile name="AsyncLoggerAndAsyncAppenderFile" fileName="target/AsyncLoggerAndAsyncAppenderTest.log"
+        immediateFlush="false" append="false">
+      <PatternLayout>
+        <Pattern>%p %c{1.} %X{KEY} %x %X %m%ex%n</Pattern>
+      </PatternLayout>
+    </RandomAccessFile>
+    <Async name="AsyncLoggerAndAsyncAppender">
+      <AppenderRef ref="AsyncLoggerAndAsyncAppenderFile" />
+    </Async>
+    <RandomAccessFile name="AsyncAppenderFile" fileName="target/AsyncAppenderContextTest.log"
+        immediateFlush="false" append="false">
+      <PatternLayout>
+        <Pattern>%p %c{1.} %X{KEY} %x %X %m%ex%n</Pattern>
+      </PatternLayout>
+    </RandomAccessFile>
+    <Async name="AsyncAppender">
+      <AppenderRef ref="AsyncAppenderFile" />
+    </Async>
     <RandomAccessFile name="RandomAccessFile" fileName="target/AsyncLoggerTest.log"
         immediateFlush="false" append="false">
       <PatternLayout>
@@ -21,9 +39,11 @@
   <Loggers>
     <AsyncLogger name="com.foo" level="info" includeLocation="false" additivity="true">
       <AppenderRef ref="RandomAccessFile"/>
+      <AppenderRef ref="AsyncLoggerAndAsyncAppender"/>
     </AsyncLogger>
     <Root level="info" includeLocation="false">
       <AppenderRef ref="SynchronousRandomAccessFile"/>
+      <AppenderRef ref="AsyncAppender"/>
     </Root>
   </Loggers>
 </Configuration>
\ No newline at end of file


[49/50] logging-log4j2 git commit: Merge remote-tracking branch 'remotes/origin/master' into LOG4J2-1349-gcfree-threadcontext

Posted by rp...@apache.org.
Merge remote-tracking branch 'remotes/origin/master' into LOG4J2-1349-gcfree-threadcontext


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/213ad7c4
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/213ad7c4
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/213ad7c4

Branch: refs/heads/master
Commit: 213ad7c4f8efd7ce3ca89db969ef82e279818634
Parents: 7c1406c f2a07e6
Author: rpopma <rp...@apache.org>
Authored: Sat Sep 10 02:27:12 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sat Sep 10 02:27:12 2016 +0900

----------------------------------------------------------------------
 .../log4j/core/appender/ConsoleAppender.java    |   6 +-
 .../rolling/CompositeTriggeringPolicy.java      |   5 +-
 .../appender/rolling/RollingFileManager.java    | 962 ++++++++++---------
 .../core/appender/rolling/TriggeringPolicy.java |   3 +-
 .../logging/log4j/core/config/LoggerConfig.java |  40 +
 .../logging/log4j/core/impl/ThrowableProxy.java | 282 +++---
 .../log4j/core/appender/AsyncAppenderTest.java  |  21 +-
 .../async/AsyncLoggerClassLoadDeadlock.java     |  32 +
 .../async/AsyncLoggerClassLoadDeadlockTest.java |  45 +
 .../logging/log4j/junit/LoggerContextRule.java  |  11 +
 .../logging/log4j/test/ExtendedLevels.java      |   2 +-
 .../log4j/test/appender/ListAppender.java       |  12 +
 .../test/resources/AsyncLoggerConsoleTest.xml   |  16 +
 .../src/test/resources/log4j-customLevel.xml    |   7 +-
 src/changes/changes.xml                         |   6 +-
 15 files changed, 799 insertions(+), 651 deletions(-)
----------------------------------------------------------------------



[50/50] logging-log4j2 git commit: Merge branch 'master' into LOG4J2-1349-gcfree-threadcontext

Posted by rp...@apache.org.
Merge branch 'master' into LOG4J2-1349-gcfree-threadcontext


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7ec63ce9
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7ec63ce9
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7ec63ce9

Branch: refs/heads/master
Commit: 7ec63ce9b1eb0aff62777a559732382a959100c1
Parents: 213ad7c a331f95
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 11 15:25:39 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 11 15:25:39 2016 +0900

----------------------------------------------------------------------
 .../core/appender/RollingFileAppender.java      | 749 ++++++++++---------
 .../rolling/RollingFileAppenderLayoutTest.java  |  39 +
 .../logging/log4j/core/config/PropertyTest.java |  63 ++
 .../src/test/resources/configPropertyTest.xml   |  36 +
 log4j-core/src/test/resources/log4j2-1573.xml   |  12 +
 src/changes/announcement.vm                     |   6 +-
 src/changes/changes.xml                         | 157 ++--
 7 files changed, 608 insertions(+), 454 deletions(-)
----------------------------------------------------------------------



[45/50] logging-log4j2 git commit: Merge branch 'master' into LOG4J2-1349-gcfree-threadcontext

Posted by rp...@apache.org.
Merge branch 'master' into LOG4J2-1349-gcfree-threadcontext


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/46714209
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/46714209
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/46714209

Branch: refs/heads/master
Commit: 467142097fb973900a9dc6e31c3c019d6a9a82a6
Parents: 523df26 d1e2e96
Author: rpopma <rp...@apache.org>
Authored: Thu Sep 8 23:52:46 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Sep 8 23:52:46 2016 +0900

----------------------------------------------------------------------
 log4j-api-scala_2.10/pom.xml                    |   4 +-
 log4j-api-scala_2.11/pom.xml                    |   4 +-
 .../simple/SimpleLoggerContextFactory.java      |   1 +
 .../logging/log4j/core/AbstractLifeCycle.java   |  12 +
 .../apache/logging/log4j/core/LifeCycle.java    |   2 +
 .../log4j/core/appender/AbstractManager.java    | 436 +++++------
 .../core/appender/MemoryMappedFileManager.java  | 718 +++++++++----------
 .../core/appender/RandomAccessFileManager.java  | 432 +++++------
 .../rolling/CompositeTriggeringPolicy.java      |  41 +-
 .../appender/rolling/CronTriggeringPolicy.java  |  12 +-
 .../rolling/DefaultRolloverStrategy.java        |   7 +-
 .../rolling/OnStartupTriggeringPolicy.java      |   1 -
 .../rolling/RollingRandomAccessFileManager.java | 530 +++++++-------
 .../rolling/SizeBasedTriggeringPolicy.java      |   1 -
 .../rolling/TimeBasedTriggeringPolicy.java      |   1 -
 .../core/appender/rolling/TriggeringPolicy.java |   6 +-
 .../core/appender/routing/IdlePurgePolicy.java  |   6 +-
 .../core/appender/routing/PurgePolicy.java      |   6 +-
 .../builder/api/ConfigurationBuilder.java       |  10 +-
 .../impl/DefaultConfigurationBuilder.java       |   2 +-
 .../log4j/core/net/TcpSocketManager.java        | 654 ++++++++---------
 .../apache/logging/log4j/core/util/Closer.java  |   4 +-
 .../log4j/core/util/NullOutputStream.java       |  16 +-
 .../logging/log4j/core/util/WatchManager.java   |   4 +-
 .../appender/RandomAccessFileManagerTest.java   |   8 +-
 .../db/AbstractDatabaseAppenderTest.java        |   8 +-
 .../db/AbstractDatabaseManagerTest.java         |  18 +-
 .../RollingRandomAccessFileManagerTest.java     |   6 +-
 .../builder/ConfigurationBuilderTest.java       |  49 +-
 .../nosql/appender/NoSqlDatabaseManager.java    | 441 ++++++------
 pom.xml                                         |   2 +-
 src/changes/changes.xml                         |   3 +
 32 files changed, 1740 insertions(+), 1705 deletions(-)
----------------------------------------------------------------------



[39/50] logging-log4j2 git commit: LOG4J2-1349 fixed imports

Posted by rp...@apache.org.
LOG4J2-1349 fixed imports


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/d1ab367c
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/d1ab367c
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/d1ab367c

Branch: refs/heads/master
Commit: d1ab367cf3df72e2b3e77b71c2c0a8c1875a3512
Parents: 6fb6b70
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 16:27:23 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 16:27:23 2016 +0900

----------------------------------------------------------------------
 .../main/java/org/apache/logging/log4j/spi/MutableContextData.java  | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d1ab367c/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
index 1ee60c9..14de7ca 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
@@ -16,7 +16,6 @@
  */
 package org.apache.logging.log4j.spi;
 
-import org.apache.logging.log4j.spi.ContextData;
 import org.apache.logging.log4j.util.BiConsumer;
 import org.apache.logging.log4j.util.TriConsumer;
 


[17/50] logging-log4j2 git commit: LOG4J2-1349 select ThreadContextMap implementation based on system properties configuration

Posted by rp...@apache.org.
LOG4J2-1349 select ThreadContextMap implementation based on system properties configuration


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/ca735dd9
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/ca735dd9
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/ca735dd9

Branch: refs/heads/master
Commit: ca735dd963f81d69167c6d28c8e8f51154175f26
Parents: 8250cc2
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 22:02:06 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 22:02:06 2016 +0900

----------------------------------------------------------------------
 .../org/apache/logging/log4j/ThreadContext.java   | 18 ++++++++++++++++--
 1 file changed, 16 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/ca735dd9/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
index e0a88dc..0ca13ab 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
@@ -27,13 +27,16 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 
 import org.apache.logging.log4j.message.ParameterizedMessage;
+import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
+import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap;
 import org.apache.logging.log4j.spi.Provider;
 import org.apache.logging.log4j.spi.ThreadContextMap;
 import org.apache.logging.log4j.spi.ThreadContextMap2;
 import org.apache.logging.log4j.spi.ThreadContextStack;
 import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Constants;
 import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.ProviderUtil;
 
@@ -190,6 +193,7 @@ public final class ThreadContext {
     private static final String DISABLE_STACK = "disableThreadContextStack";
     private static final String DISABLE_ALL = "disableThreadContext";
     private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
+    private static final String GC_FREE_THREAD_CONTEXT_KEY = "log4j2.garbagefree.threadContextMap";
 
     private static boolean disableAll;
     private static boolean useMap;
@@ -243,17 +247,27 @@ public final class ThreadContext {
                         } catch (final Exception e) {
                             LOGGER.error("Unable to locate or load configured ThreadContextMap {}",
                                     provider.getThreadContextMap(), e);
-                            contextMap = new DefaultThreadContextMap(useMap);
+                            contextMap = createThreadContextMap(useMap);
                         }
                     }
                 }
             }
         }
         if (contextMap == null) {
-            contextMap = new DefaultThreadContextMap(useMap);
+            contextMap = createThreadContextMap(useMap);
         }
     }
 
+    private static ThreadContextMap createThreadContextMap(final boolean doUseMap) {
+        if (Constants.ENABLE_THREADLOCALS) {
+            if (PropertiesUtil.getProperties().getBooleanProperty(GC_FREE_THREAD_CONTEXT_KEY)) {
+                return new GarbageFreeSortedArrayThreadContextMap();
+            }
+            return new CopyOnWriteSortedArrayThreadContextMap();
+        }
+        return new DefaultThreadContextMap(doUseMap);
+    }
+
     /**
      * Puts a context value (the <code>value</code> parameter) as identified with the <code>key</code> parameter into
      * the current thread's context map.


[38/50] logging-log4j2 git commit: Merge remote-tracking branch 'remotes/origin/master' into LOG4J2-1349-gcfree-threadcontext

Posted by rp...@apache.org.
Merge remote-tracking branch 'remotes/origin/master' into LOG4J2-1349-gcfree-threadcontext


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/6fb6b708
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/6fb6b708
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/6fb6b708

Branch: refs/heads/master
Commit: 6fb6b708ae895aad935b1690307b958c26111c3c
Parents: 189f87d dbbeb5c
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 16:21:10 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 16:21:10 2016 +0900

----------------------------------------------------------------------
 .gitignore                                      |  14 +-
 README.md                                       |   8 +
 log4j-1.2-api/.gitignore                        |   5 -
 .../config/Log4j1ConfigurationConverter.java    |  41 +++
 .../config/Log4j1ConfigurationFactory.java      |   1 -
 .../log4j/config/Log4j1ConfigurationParser.java |  20 +-
 log4j-api-scala_2.10/.gitignore                 |   3 -
 log4j-api-scala_2.10/pom.xml                    |   2 +-
 log4j-api-scala_2.11/.gitignore                 |   3 -
 log4j-api-scala_2.11/pom.xml                    |   2 +-
 log4j-api/.gitignore                            |   5 -
 log4j-bom/.gitignore                            |   3 -
 log4j-core/.gitignore                           |   6 -
 .../log4j/core/appender/AbstractManager.java    |  41 ++-
 .../appender/AbstractOutputStreamAppender.java  |  29 +-
 .../core/appender/AbstractWriterAppender.java   |   2 +-
 .../log4j/core/appender/AsyncAppender.java      |   5 +-
 .../log4j/core/appender/FileAppender.java       |  30 +-
 .../log4j/core/appender/FileManager.java        |  27 +-
 .../core/appender/MemoryMappedFileManager.java  |   2 +-
 .../core/appender/OutputStreamManager.java      |  12 +-
 .../core/appender/RandomAccessFileAppender.java |  14 +-
 .../core/appender/RandomAccessFileManager.java  |   2 +-
 .../core/appender/RollingFileAppender.java      |  33 +-
 .../log4j/core/appender/SocketAppender.java     | 254 ++++++++++---
 .../log4j/core/appender/SyslogAppender.java     |   7 +-
 .../log4j/core/appender/WriterManager.java      |   4 +-
 .../appender/db/AbstractDatabaseAppender.java   |   4 +-
 .../appender/db/AbstractDatabaseManager.java    |   2 +-
 .../log4j/core/appender/mom/JmsAppender.java    |   2 +-
 .../log4j/core/appender/mom/JmsManager.java     |   2 +-
 .../appender/mom/jeromq/JeroMqAppender.java     | 362 +++++++++----------
 .../core/appender/mom/kafka/KafkaAppender.java  |   2 +-
 .../appender/rolling/RollingFileManager.java    |   2 +-
 .../rolling/RollingRandomAccessFileManager.java |   2 +-
 .../core/config/builder/api/Component.java      |   4 +-
 .../builder/impl/DefaultComponentBuilder.java   |   4 +-
 .../impl/DefaultConfigurationBuilder.java       |  28 +-
 .../log4j/core/filter/LevelRangeFilter.java     |   2 +-
 .../logging/log4j/core/lookup/JndiLookup.java   |   2 +-
 .../log4j/core/net/AbstractSocketManager.java   |   6 +-
 .../log4j/core/net/DatagramSocketManager.java   |  21 +-
 .../log4j/core/net/SslSocketManager.java        |  31 +-
 .../log4j/core/net/TcpSocketManager.java        | 102 +++---
 .../log4j/core/net/server/JmsServer.java        |   2 +-
 .../log4j/core/net/server/TcpSocketServer.java  |   2 +-
 .../core/selector/JndiContextSelector.java      |   2 +-
 .../logging/log4j/core/util/CachedClock.java    |   2 +-
 .../log4j/core/util/CoarseCachedClock.java      |   2 +-
 .../log4j/core/util/NullOutputStream.java       |   4 +
 .../log4j/core/appender/FileAppenderTest.java   |  11 +-
 .../appender/MemoryMappedFileManagerTest.java   |  25 +-
 .../appender/SocketAppenderBufferSizeTest.java  |  77 ++++
 .../log4j/core/appender/SocketAppenderTest.java | 252 +++++++++----
 .../db/AbstractDatabaseAppenderTest.java        |  10 +-
 .../db/jdbc/AbstractJdbcAppenderTest.java       |   2 +-
 .../db/jpa/AbstractJpaAppenderTest.java         |   2 +-
 .../log4j/core/appender/mom/JmsAppenderIT.java  |   2 +-
 .../rolling/OnStartupTriggeringPolicyTest.java  |   7 +-
 .../core/config/CompositeConfigurationTest.java |   5 +-
 .../builder/ConfigurationBuilderTest.java       |  63 ++--
 .../log4j/core/filter/LevelRangeFilterTest.java |   9 +
 .../core/net/mock/MockUdpSyslogServer.java      |   6 +-
 .../net/server/AbstractSocketServerTest.java    |  16 +-
 .../core/net/server/SslXmlSocketServerTest.java |  23 +-
 .../logging/log4j/junit/LoggerContextRule.java  |   7 +
 .../src/test/resources/log4j-advertiser.xml     |   4 +-
 log4j-core/src/test/resources/log4j-empty.xml   |  20 +
 log4j-distribution/.gitignore                   |   2 -
 log4j-flume-ng/.gitignore                       |   4 -
 .../log4j/flume/appender/FlumeAppender.java     |   2 +-
 .../flume/appender/FlumePersistentManager.java  |   3 +-
 log4j-iostreams/.gitignore                      | Bin 69 -> 0 bytes
 log4j-jcl/.gitignore                            |   4 -
 log4j-jmx-gui/.gitignore                        |   4 -
 log4j-jul/.gitignore                            |   3 -
 log4j-liquibase/.gitignore                      |   3 -
 log4j-nosql/.gitignore                          |   4 -
 .../appender/NoSqlDatabaseManagerTest.java      |  81 ++---
 log4j-perf/.gitignore                           |   4 -
 .../log4j/perf/jmh/JdbcAppenderBenchmark.java   |   4 +-
 .../log4j/perf/jmh/JpaAppenderBenchmark.java    |   4 +-
 log4j-samples/.gitignore                        |   5 -
 log4j-slf4j-impl/.gitignore                     |   4 -
 log4j-taglib/.gitignore                         |   4 -
 log4j-to-slf4j/.gitignore                       |   4 -
 log4j-web/.gitignore                            |   4 -
 src/changes/changes.xml                         |  22 +-
 src/site/xdoc/manual/appenders.xml              |  11 +
 89 files changed, 1157 insertions(+), 727 deletions(-)
----------------------------------------------------------------------



[26/50] logging-log4j2 git commit: LOG4J2-1349 update tests to prove garbage-free context map does not allocate

Posted by rp...@apache.org.
LOG4J2-1349 update tests to prove garbage-free context map does not allocate


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/4882847a
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/4882847a
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/4882847a

Branch: refs/heads/master
Commit: 4882847a464c045d8c54607231c09f99390a4955
Parents: c5d8f76
Author: rpopma <rp...@apache.org>
Authored: Fri Sep 2 23:21:10 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Sep 2 23:21:10 2016 +0900

----------------------------------------------------------------------
 log4j-core/src/test/resources/gcFreeLogging.xml               | 2 +-
 log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4882847a/log4j-core/src/test/resources/gcFreeLogging.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/gcFreeLogging.xml b/log4j-core/src/test/resources/gcFreeLogging.xml
index 81a8055..3a3c07e 100644
--- a/log4j-core/src/test/resources/gcFreeLogging.xml
+++ b/log4j-core/src/test/resources/gcFreeLogging.xml
@@ -47,7 +47,7 @@
     </RandomAccessFile>
   </Appenders>
   <Loggers>
-    <Root level="info" includeLocation="false">
+    <Root level="trace" includeLocation="false">
       <appender-ref ref="Console" level="FATAL" />
       <appender-ref ref="File"/>
       <appender-ref ref="RandomAccessFile"/>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4882847a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml b/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
index 714ea9f..03d55b5 100644
--- a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
+++ b/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
@@ -47,7 +47,7 @@
   </Appenders>
   <Loggers>
     <AsyncLogger name="org.apache.logging.log4j.core.GcFreeMixedSyncAyncLoggingTest"
-        level="info" includeLocation="false">
+        level="trace" includeLocation="false">
       <appender-ref ref="Console" level="FATAL" />
       <appender-ref ref="File"/>
       <appender-ref ref="RandomAccessFile"/>
@@ -57,7 +57,7 @@
       <appender-ref ref="MemoryMappedFile"/>
       <appender-ref ref="RandomAccessFileGelf"/>
     </AsyncLogger>
-    <Root level="info" includeLocation="false">
+    <Root level="trace" includeLocation="false">
       <appender-ref ref="Console" level="FATAL" />
       <appender-ref ref="File"/>
       <appender-ref ref="RandomAccessFile"/>


[18/50] logging-log4j2 git commit: LOG4J2-1349 fix broken test: getContext() should return mutable map

Posted by rp...@apache.org.
LOG4J2-1349 fix broken test: getContext() should return mutable map


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/70807a58
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/70807a58
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/70807a58

Branch: refs/heads/master
Commit: 70807a5812978a58df5d11bae4ff508a2aa33907
Parents: ca735dd
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 22:52:11 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 22:52:11 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java | 3 ++-
 .../logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/70807a58/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
index afa9d99..1ccb81b 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.spi;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.logging.log4j.util.PropertiesUtil;
@@ -148,7 +149,7 @@ public class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap,
     @Override
     public Map<String, String> getCopy() {
         final MutableContextData map = localMap.get();
-        return map == null ? Collections.<String, String>emptyMap() : map.asMap();
+        return map == null ? new HashMap<String, String>() : map.asMap();
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/70807a58/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
index 7d94831..da04829 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
@@ -17,6 +17,7 @@
 package org.apache.logging.log4j.spi;
 
 import java.util.Collections;
+import java.util.HashMap;
 import java.util.Map;
 
 import org.apache.logging.log4j.util.PropertiesUtil;
@@ -150,7 +151,7 @@ public class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap,
     @Override
     public Map<String, String> getCopy() {
         final MutableContextData map = localMap.get();
-        return map == null ? Collections.<String, String>emptyMap() : map.asMap();
+        return map == null ? new HashMap<String, String>() : map.asMap();
     }
 
     /**


[41/50] logging-log4j2 git commit: LOG4J2-1349 implement support for freeze() and isFrozen() in OpenHashMapContextData (for MutableContextData interface change)

Posted by rp...@apache.org.
LOG4J2-1349 implement support for freeze() and isFrozen() in OpenHashMapContextData (for MutableContextData interface change)


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7615afad
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7615afad
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7615afad

Branch: refs/heads/master
Commit: 7615afadd1ba368ed07e8967c270940f624925bb
Parents: 191c3f9
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 19:33:46 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 19:33:46 2016 +0900

----------------------------------------------------------------------
 .../log4j/perf/nogc/OpenHashMapContextData.java | 85 +++++++++++++++-----
 1 file changed, 67 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7615afad/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashMapContextData.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashMapContextData.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashMapContextData.java
index 26bdf53..a7357b8 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashMapContextData.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/OpenHashMapContextData.java
@@ -67,6 +67,7 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
     /** The default load factor of a hash table. */
     public static final float DEFAULT_LOAD_FACTOR = .75f;
 
+    private static final String FROZEN = "Frozen collection cannot be modified";
     private static final long serialVersionUID = -1486744623338827187L;
 
     /** The array of keys. */
@@ -89,6 +90,8 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
     protected final float loadFactor;
 
     private V defRetValue = null;
+    private boolean immutable;
+    private transient boolean iterating;
 
     /**
      * Creates a new hash map with initial expected
@@ -193,6 +196,18 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
         }
     };
 
+    private void assertNotFrozen() {
+        if (immutable) {
+            throw new UnsupportedOperationException(FROZEN);
+        }
+    }
+
+    private void assertNoConcurrentModification() {
+        if (iterating) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
     @SuppressWarnings("unchecked")
     private void initFrom0(final OpenHashMapContextData other) {
         // this.loadFactor = other.loadFactor; // final field
@@ -250,6 +265,9 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
         if (size == 0) {
             return;
         }
+        assertNotFrozen();
+        assertNoConcurrentModification();
+
         size = 0;
         containsNullKey = false;
         Arrays.fill(keys, (null));
@@ -323,20 +341,26 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
         final int startSize = size;
         final K myKeys[] = this.keys;
         int pos = arraySize;
-        if (containsNullKey) {
-            action.accept((String) myKeys[pos], (VAL) values[pos]);
-            if (size != startSize) {
-                throw new ConcurrentModificationException();
-            }
-        }
-        --pos;
-        for (; pos >= 0; pos--) {
-            if (myKeys[pos] != null) {
+
+        iterating = true;
+        try {
+            if (containsNullKey) {
                 action.accept((String) myKeys[pos], (VAL) values[pos]);
                 if (size != startSize) {
                     throw new ConcurrentModificationException();
                 }
             }
+            --pos;
+            for (; pos >= 0; pos--) {
+                if (myKeys[pos] != null) {
+                    action.accept((String) myKeys[pos], (VAL) values[pos]);
+                    if (size != startSize) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+            }
+        } finally {
+            iterating = false;
         }
     }
 
@@ -346,20 +370,26 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
         final int startSize = size;
         final K myKeys[] = this.keys;
         int pos = arraySize;
-        if (containsNullKey) {
-            action.accept((String) myKeys[pos], (VAL) values[pos], state);
-            if (size != startSize) {
-                throw new ConcurrentModificationException();
-            }
-        }
-        --pos;
-        for (; pos >= 0; pos--) {
-            if (myKeys[pos] != null) {
+
+        iterating = true;
+        try {
+            if (containsNullKey) {
                 action.accept((String) myKeys[pos], (VAL) values[pos], state);
                 if (size != startSize) {
                     throw new ConcurrentModificationException();
                 }
             }
+            --pos;
+            for (; pos >= 0; pos--) {
+                if (myKeys[pos] != null) {
+                    action.accept((String) myKeys[pos], (VAL) values[pos], state);
+                    if (size != startSize) {
+                        throw new ConcurrentModificationException();
+                    }
+                }
+            }
+        } finally {
+            iterating = false;
         }
     }
 
@@ -453,6 +483,9 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
 
     @Override
     public void putAll(final ContextData source) {
+        assertNotFrozen();
+        assertNoConcurrentModification();
+
         if (size() == 0 && source instanceof OpenHashMapContextData) {
             initFrom0((OpenHashMapContextData) source);
         } else if (source != null) {
@@ -475,6 +508,9 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
     }
 
     private V putObjectValue(final K k, final V v) {
+        assertNotFrozen();
+        assertNoConcurrentModification();
+
         final int pos = insert(k, v);
         if (pos < 0) {
             return defRetValue;
@@ -495,8 +531,21 @@ public class OpenHashMapContextData<K, V> implements MutableContextData, ThreadC
         removeObjectKey((Object) key);
     }
 
+    @Override
+    public void freeze() {
+        immutable = true;
+    }
+
+    @Override
+    public boolean isFrozen() {
+        return immutable;
+    }
+
     @SuppressWarnings("unchecked")
     private V removeObjectKey(final Object k) {
+        assertNotFrozen();
+        assertNoConcurrentModification();
+
         if (k == null) {
             if (containsNullKey) {
                 return removeNullEntry();


[20/50] logging-log4j2 git commit: LOG4J2-1349 system properties disableThreadContextMap and disableThreadContext must work regardless of ThreadContextMap implementation

Posted by rp...@apache.org.
LOG4J2-1349 system properties disableThreadContextMap and disableThreadContext must work regardless of ThreadContextMap implementation


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/b4c02959
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/b4c02959
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/b4c02959

Branch: refs/heads/master
Commit: b4c0295938a83b085d641b1bcf9353b02c9a6115
Parents: 996d54b
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 22:54:55 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 22:54:55 2016 +0900

----------------------------------------------------------------------
 .../java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java    | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/b4c02959/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
index a9f8a57..222d6f8 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
@@ -25,7 +25,7 @@ import java.util.Map;
  *
  * @since 2.7
  */
-class NoOpThreadContextMap implements ThreadContextMap {
+public class NoOpThreadContextMap implements ThreadContextMap {
     @Override
     public void clear() {
     }


[27/50] logging-log4j2 git commit: LOG4J2-1349 bugfix when AsyncLoggerConfig ringbuffer MutableLogEvent initializes from a synchronous MutableLogEvent, it should not keep a reference to the other event's context data but should always copy the contents,

Posted by rp...@apache.org.
LOG4J2-1349 bugfix when AsyncLoggerConfig ringbuffer MutableLogEvent initializes from a synchronous MutableLogEvent, it should not keep a reference to the other event's context data but should always copy the contents, since the events and their context data object are accessed and modified in different threads


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/f2818eb6
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/f2818eb6
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/f2818eb6

Branch: refs/heads/master
Commit: f2818eb6bf517e6b3e394e37b8a188ab57061981
Parents: 4882847
Author: rpopma <rp...@apache.org>
Authored: Fri Sep 2 23:24:52 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Sep 2 23:24:52 2016 +0900

----------------------------------------------------------------------
 .../apache/logging/log4j/core/impl/MutableLogEvent.java  | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/f2818eb6/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index bcdc40d..97cb5d6 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -89,11 +89,12 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
         this.timeMillis = event.getTimeMillis();
         this.thrown = event.getThrown();
         this.thrownProxy = event.getThrownProxy();
-        if (event.getContextData() instanceof MutableContextData) {
-            this.contextData = (MutableContextData) event.getContextData();
-        } else {
-            this.contextData.putAll(event.getContextData());
-        }
+
+        // NOTE: this ringbuffer event SHOULD NOT keep a reference to the specified
+        // thread-local MutableLogEvent's context data, because then two threads would call
+        // ContextData.clear() on the same shared instance, resulting in data corruption.
+        this.contextData.putAll(event.getContextData());
+
         this.contextStack = event.getContextStack();
         this.source = event.isIncludeLocation() ? event.getSource() : null;
         this.threadId = event.getThreadId();


[13/50] logging-log4j2 git commit: LOG4J2-1349 package fix

Posted by rp...@apache.org.
LOG4J2-1349 package fix


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/5f6319fd
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/5f6319fd
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/5f6319fd

Branch: refs/heads/master
Commit: 5f6319fda1990fd059623fc760af7246a527c6b2
Parents: 463d484
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 21:35:46 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 21:35:46 2016 +0900

----------------------------------------------------------------------
 .../org/apache/logging/log4j/core/impl/ContextDataInjector.java     | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/5f6319fd/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
index 32b2caa..a74201b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
@@ -18,7 +18,6 @@ package org.apache.logging.log4j.core.impl;
 
 import java.util.List;
 
-import org.apache.logging.log4j.core.ContextData;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.spi.ContextData;
 import org.apache.logging.log4j.spi.MutableContextData;


[22/50] logging-log4j2 git commit: reset Unbox buffer to default size after configurable test

Posted by rp...@apache.org.
reset Unbox buffer to default size after configurable test


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/c0368dac
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/c0368dac
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/c0368dac

Branch: refs/heads/master
Commit: c0368dac6a3f7749203e308a73a7b2d2429785a4
Parents: 12ea0e2
Author: rpopma <rp...@apache.org>
Authored: Thu Sep 1 00:20:23 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Sep 1 00:20:23 2016 +0900

----------------------------------------------------------------------
 .../org/apache/logging/log4j/util/UnboxConfigurableTest.java   | 6 ++++++
 1 file changed, 6 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/c0368dac/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java
index ff72716..01fb6a1 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java
@@ -48,6 +48,12 @@ public class UnboxConfigurableTest {
         modifierField.setInt(field, field.getModifiers() &~ Modifier.FINAL); // make non-final
 
         field.set(null, 32); // reset to default
+
+        final Field threadLocalField = Unbox.class.getDeclaredField("threadLocalState");
+        threadLocalField.setAccessible(true);
+        final ThreadLocal<?> threadLocal = (ThreadLocal<?>) threadLocalField.get(null);
+        threadLocal.remove();
+        threadLocalField.set(null, new ThreadLocal<>());
     }
 
     @Test


[36/50] logging-log4j2 git commit: LOG4J2-1349 bugfix: putAll() should not overwrite existing values

Posted by rp...@apache.org.
LOG4J2-1349 bugfix: putAll() should not overwrite existing values


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/863cc124
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/863cc124
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/863cc124

Branch: refs/heads/master
Commit: 863cc124dfdc0fe05128a8c144c6413f92b5d99f
Parents: e59f15f
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 15:56:02 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 15:56:02 2016 +0900

----------------------------------------------------------------------
 .../main/java/org/apache/logging/log4j/util/ArrayContextData.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/863cc124/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
index 3b665b3..01b2c8c 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
@@ -243,7 +243,7 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
         assertNotFrozen();
         assertNoConcurrentModification();
 
-        if (source instanceof ArrayContextData) {
+        if (source instanceof ArrayContextData && this.size == 0) {
             initFrom0((ArrayContextData) source);
         } else if (source != null) {
             if (source == this) {


[35/50] logging-log4j2 git commit: LOG4J2-1349 implement support for freeze() and isFrozen(); add tests

Posted by rp...@apache.org.
LOG4J2-1349 implement support for freeze() and isFrozen(); add tests


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e59f15f6
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e59f15f6
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e59f15f6

Branch: refs/heads/master
Commit: e59f15f65a7b1b39f0f61b9b7e2b3f28ada387c0
Parents: 950b62f
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 15:55:10 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 15:55:10 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/util/ArrayContextData.java    |  63 +++++-
 .../log4j/util/ArrayContextDataTest.java        | 208 +++++++++++++++++++
 2 files changed, 267 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e59f15f6/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
index bdc9951..3b665b3 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
@@ -20,6 +20,7 @@ import java.io.IOException;
 import java.io.InvalidObjectException;
 import java.util.Arrays;
 import java.util.Collections;
+import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Objects;
@@ -70,6 +71,7 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
      * An empty array instance to share when the table is not inflated.
      */
     private static final String[] EMPTY = {};
+    private static final String FROZEN = "Frozen collection cannot be modified";
 
     private transient String[] keys = EMPTY;
     private transient Object[] values = EMPTY;
@@ -86,6 +88,8 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
     // If table == EMPTY_TABLE then this is the initial capacity at which the
     // table will be created when inflated.
     private int threshold;
+    private boolean immutable;
+    private transient boolean iterating;
 
     public ArrayContextData() {
         this(DEFAULT_INITIAL_CAPACITY);
@@ -107,8 +111,26 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
         }
     }
 
+    private void assertNotFrozen() {
+        if (immutable) {
+            throw new UnsupportedOperationException(FROZEN);
+        }
+    }
+
+    private void assertNoConcurrentModification() {
+        if (iterating) {
+            throw new ConcurrentModificationException();
+        }
+    }
+
     @Override
     public void clear() {
+        if (keys == EMPTY) {
+            return;
+        }
+        assertNotFrozen();
+        assertNoConcurrentModification();
+
         Arrays.fill(keys, 0, size, null);
         Arrays.fill(values, 0, size, null);
         size = 0;
@@ -130,6 +152,16 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
     }
 
     @Override
+    public void freeze() {
+        immutable = true;
+    }
+
+    @Override
+    public boolean isFrozen() {
+        return immutable;
+    }
+
+    @Override
     public Map<String, String> getCopy() {
         return asMap();
     }
@@ -182,6 +214,9 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
 
     @Override
     public void putValue(final String key, final Object value) {
+        assertNotFrozen();
+        assertNoConcurrentModification();
+
         if (keys == EMPTY) {
             inflateTable(threshold);
         }
@@ -205,9 +240,15 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
 
     @Override
     public void putAll(final ContextData source) {
+        assertNotFrozen();
+        assertNoConcurrentModification();
+
         if (source instanceof ArrayContextData) {
             initFrom0((ArrayContextData) source);
         } else if (source != null) {
+            if (source == this) {
+                return; // this.putAll(this) does not modify this collection
+            }
             source.forEach(PUT_ALL, this);
         }
     }
@@ -261,8 +302,12 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
         if (keys == EMPTY) {
             return;
         }
+
         final int index = indexOfKey(key);
         if (index >= 0) {
+            assertNotFrozen();
+            assertNoConcurrentModification();
+
             System.arraycopy(keys, index + 1, keys, index, size - index);
             System.arraycopy(values, index + 1, values, index, size - index);
             size--;
@@ -292,16 +337,26 @@ public class ArrayContextData implements MutableContextData, ThreadContextMap {
     @SuppressWarnings("unchecked")
     @Override
     public <V> void forEach(BiConsumer<String, ? super V> action) {
-        for (int i = 0; i < size; i++) {
-            action.accept(keys[i], (V) values[i]);
+        iterating = true;
+        try {
+            for (int i = 0; i < size; i++) {
+                action.accept(keys[i], (V) values[i]);
+            }
+        } finally {
+            iterating = false;
         }
     }
 
     @SuppressWarnings("unchecked")
     @Override
     public <V, T> void forEach(TriConsumer<String, ? super V, T> action, T state) {
-        for (int i = 0; i < size; i++) {
-            action.accept(keys[i], (V) values[i], state);
+        iterating = true;
+        try {
+            for (int i = 0; i < size; i++) {
+                action.accept(keys[i], (V) values[i], state);
+            }
+        } finally {
+            iterating = false;
         }
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e59f15f6/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
index e3ac0a4..ae79888 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
@@ -21,6 +21,7 @@ import java.io.IOException;
 import java.io.ObjectInputStream;
 import java.io.ObjectOutputStream;
 import java.lang.reflect.Field;
+import java.util.ConcurrentModificationException;
 import java.util.HashMap;
 import java.util.Map;
 
@@ -181,6 +182,213 @@ public class ArrayContextDataTest {
     }
 
     @Test
+    public void testPutAll_KeepsExistingValues() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.put("b", "bbb");
+        original.put("c", "ccc");
+        assertEquals("size", 3, original.size());
+
+        // add empty context data
+        original.putAll(new ArrayContextData());
+        assertEquals("size after put empty", 3, original.size());
+        assertEquals("aaa", original.get("a"));
+        assertEquals("bbb", original.get("b"));
+        assertEquals("ccc", original.get("c"));
+
+        final ArrayContextData other = new ArrayContextData();
+        other.put("1", "111");
+        other.put("2", "222");
+        other.put("3", "333");
+        original.putAll(other);
+
+        assertEquals("size after put other", 6, original.size());
+        assertEquals("aaa", original.get("a"));
+        assertEquals("bbb", original.get("b"));
+        assertEquals("ccc", original.get("c"));
+        assertEquals("111", original.get("1"));
+        assertEquals("222", original.get("2"));
+        assertEquals("333", original.get("3"));
+    }
+
+    @Test
+    public void testPutAllSelfDoesNotModify() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.put("b", "bbb");
+        original.put("c", "ccc");
+        assertEquals("size", 3, original.size());
+
+        // putAll with self
+        original.putAll(original);
+        assertEquals("size after put empty", 3, original.size());
+        assertEquals("aaa", original.get("a"));
+        assertEquals("bbb", original.get("b"));
+        assertEquals("ccc", original.get("c"));
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void testConcurrentModificationBiConsumerPut() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.forEach(new BiConsumer<String, Object>() {
+            @Override
+            public void accept(final String s, final Object o) {
+                original.put("c", "other");
+            }
+        });
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void testConcurrentModificationBiConsumerPutValue() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.forEach(new BiConsumer<String, Object>() {
+            @Override
+            public void accept(final String s, final Object o) {
+                original.putValue("c", "other");
+            }
+        });
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void testConcurrentModificationBiConsumerRemove() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.forEach(new BiConsumer<String, Object>() {
+            @Override
+            public void accept(final String s, final Object o) {
+                original.remove("a");
+            }
+        });
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void testConcurrentModificationBiConsumerClear() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.forEach(new BiConsumer<String, Object>() {
+            @Override
+            public void accept(final String s, final Object o) {
+                original.clear();
+            }
+        });
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void testConcurrentModificationTriConsumerPut() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.forEach(new TriConsumer<String, Object, Object>() {
+            @Override
+            public void accept(final String s, final Object o, final Object o2) {
+                original.put("c", "other");
+            }
+        }, null);
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void testConcurrentModificationTriConsumerPutValue() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.forEach(new TriConsumer<String, Object, Object>() {
+            @Override
+            public void accept(final String s, final Object o, final Object o2) {
+                original.putValue("c", "other");
+            }
+        }, null);
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void testConcurrentModificationTriConsumerRemove() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.forEach(new TriConsumer<String, Object, Object>() {
+            @Override
+            public void accept(final String s, final Object o, final Object o2) {
+                original.remove("a");
+            }
+        }, null);
+    }
+
+    @Test(expected = ConcurrentModificationException.class)
+    public void testConcurrentModificationTriConsumerClear() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.forEach(new TriConsumer<String, Object, Object>() {
+            @Override
+            public void accept(final String s, final Object o, final Object o2) {
+                original.clear();
+            }
+        }, null);
+    }
+
+    @Test
+    public void testInitiallyNotFrozen() {
+        assertFalse(new ArrayContextData().isFrozen());
+    }
+
+    @Test
+    public void testIsFrozenAfterCallingFreeze() {
+        final ArrayContextData original = new ArrayContextData();
+        assertFalse("before freeze", original.isFrozen());
+        original.freeze();
+        assertTrue("after freeze", original.isFrozen());
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testFreezeProhibitsPut() {
+        final ArrayContextData original = new ArrayContextData();
+        original.freeze();
+        original.put("a", "aaa");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testFreezeProhibitsPutValue() {
+        final ArrayContextData original = new ArrayContextData();
+        original.freeze();
+        original.putValue("a", "aaa");
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testFreezeProhibitsRemove() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("b", "bbb");
+        original.freeze();
+        original.remove("b"); // existing key: modifies the collection
+    }
+
+    @Test
+    public void testFreezeAllowsRemoveOfNonExistingKey() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("b", "bbb");
+        original.freeze();
+        original.remove("a"); // no actual modification
+    }
+
+    @Test
+    public void testFreezeAllowsRemoveIfEmpty() {
+        final ArrayContextData original = new ArrayContextData();
+        original.freeze();
+        original.remove("a"); // no exception
+    }
+
+    @Test(expected = UnsupportedOperationException.class)
+    public void testFreezeProhibitsClear() {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "aaa");
+        original.freeze();
+        original.clear();
+    }
+
+    @Test
+    public void testFreezeAllowsClearIfEmpty() {
+        final ArrayContextData original = new ArrayContextData();
+        original.freeze();
+        original.clear();
+    }
+
+    @Test
     public void testPutInsertsInAlphabeticOrder() throws Exception {
         final ArrayContextData original = new ArrayContextData();
         original.put("a", "avalue");


[34/50] logging-log4j2 git commit: LOG4J2-1349 freeze context data so that shared copies cannot be modified

Posted by rp...@apache.org.
LOG4J2-1349 freeze context data so that shared copies cannot be modified


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/950b62f6
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/950b62f6
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/950b62f6

Branch: refs/heads/master
Commit: 950b62f6272ea1d6a44d49320614f5113ff8aea2
Parents: 945bfe0
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 15:54:02 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 15:54:02 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java | 3 +++
 1 file changed, 3 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/950b62f6/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
index 81c69d5..57348dd 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
@@ -104,6 +104,7 @@ class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, Thread
         MutableContextData map = localMap.get();
         map = map == null ? createMutableContextData() : createMutableContextData(map);
         map.putValue(key, value);
+        map.freeze();
         localMap.set(map);
     }
 
@@ -117,6 +118,7 @@ class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, Thread
         for (final Map.Entry<String, String> entry : values.entrySet()) {
             map.putValue(entry.getKey(), entry.getValue());
         }
+        map.freeze();
         localMap.set(map);
     }
 
@@ -132,6 +134,7 @@ class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, Thread
         if (map != null) {
             final MutableContextData copy = createMutableContextData(map);
             copy.remove(key);
+            copy.freeze();
             localMap.set(copy);
         }
     }


[23/50] logging-log4j2 git commit: LOG4J2-1349 MutableContextDataSupplier::getMutableContextData must not return null

Posted by rp...@apache.org.
LOG4J2-1349 MutableContextDataSupplier::getMutableContextData must not return null


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/22ef566e
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/22ef566e
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/22ef566e

Branch: refs/heads/master
Commit: 22ef566e6f3524a13b2d1a3ff238908f81b2326a
Parents: c0368da
Author: rpopma <rp...@apache.org>
Authored: Thu Sep 1 00:21:43 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Sep 1 00:21:43 2016 +0900

----------------------------------------------------------------------
 .../spi/CopyOnWriteSortedArrayThreadContextMap.java     |  3 ++-
 .../spi/GarbageFreeSortedArrayThreadContextMap.java     | 12 ++++++++++--
 2 files changed, 12 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/22ef566e/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
index 1ccb81b..08bac8e 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
@@ -157,7 +157,8 @@ public class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap,
      */
     @Override
     public MutableContextData getMutableContextData() {
-        return localMap.get();
+        final MutableContextData map = localMap.get();
+        return map == null ? createMutableContextData() : map;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/22ef566e/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
index da04829..1fe2f65 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
@@ -139,7 +139,10 @@ public class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap,
 
     @Override
     public void clear() {
-        localMap.remove();
+        final MutableContextData map = localMap.get();
+        if (map != null) {
+            map.clear();
+        }
     }
 
     @Override
@@ -159,7 +162,12 @@ public class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap,
      */
     @Override
     public MutableContextData getMutableContextData() {
-        return localMap.get();
+        MutableContextData map = localMap.get();
+        if (map == null) {
+            map = createMutableContextData();
+            localMap.set(map);
+        }
+        return map;
     }
 
     @Override


[10/50] logging-log4j2 git commit: Merge branch 'LOG4J2-1010&LOG4J2-1447-injectable-contextdata&better-datastructure' into LOG4J2-1349-gcfree-threadcontext

Posted by rp...@apache.org.
Merge branch 'LOG4J2-1010&LOG4J2-1447-injectable-contextdata&better-datastructure' into LOG4J2-1349-gcfree-threadcontext


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/927251f9
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/927251f9
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/927251f9

Branch: refs/heads/master
Commit: 927251f9d7f31a9f394451c49302d82c0daed85c
Parents: def057f d3d3069
Author: rpopma <rp...@apache.org>
Authored: Tue Aug 30 23:45:20 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Tue Aug 30 23:45:20 2016 +0900

----------------------------------------------------------------------
 log4j-1.2-api/pom.xml                           |   4 -
 .../apache/log4j/layout/Log4j1XmlLayout.java    |   4 +-
 .../pattern/Log4j1NdcPatternConverter.java      |   4 +-
 .../org/apache/logging/log4j/util/Strings.java  |  63 +++++++++
 log4j-core/pom.xml                              |  10 ++
 .../core/appender/routing/IdlePurgePolicy.java  |  57 +++++---
 .../core/appender/routing/RoutingAppender.java  |  35 ++---
 .../builder/api/ConfigurationBuilder.java       |  16 +++
 .../impl/DefaultConfigurationBuilder.java       | 129 +++++++++++++++++++
 .../log4j/core/layout/AbstractCsvLayout.java    |  10 +-
 .../apache/logging/log4j/core/DeadlockTest.java |   2 +-
 .../logging/log4j/core/LoggerUpdateTest.java    |   2 +-
 .../CsvJsonParameterLayoutFileAppenderTest.java | 117 +++++++++++++++++
 .../appender/JsonCompleteFileAppenderTest.java  |   2 +-
 .../appender/RandomAccessFileAppenderTests.java |   2 +-
 .../db/jdbc/AbstractJdbcAppenderTest.java       |  12 +-
 .../db/jpa/AbstractJpaAppenderTest.java         |  12 +-
 .../core/appender/db/jpa/JpaH2AppenderTest.java |  28 ++--
 .../db/jpa/JpaHyperSqlAppenderTest.java         |  28 ++--
 .../RollingAppenderCronOnceADayTest.java        |   4 +-
 .../rolling/RollingAppenderCronTest.java        |   2 +-
 .../routing/PropertiesRoutingAppenderTest.java  |   2 +-
 .../appender/routing/RoutingAppenderTest.java   |   2 +-
 .../routing/RoutingAppenderWithPurgingTest.java |  21 ++-
 .../routing/RoutingDefaultAppenderTest.java     |   2 +-
 .../log4j/core/config/ConfigurationTest.java    |   2 +-
 .../core/config/CustomConfigurationTest.java    |   2 +-
 .../core/config/MissingRootLoggerTest.java      |   2 +-
 .../logging/log4j/core/config/XIncludeTest.java |   2 +-
 .../builder/ConfigurationBuilderTest.java       |  91 +++++++++++++
 .../core/util/ShutdownCallbackRegistryTest.java |   2 +-
 .../logging/log4j/junit/LoggerContextRule.java  |  22 ++--
 .../test/resources/log4j-cvs-json-parameter.xml |  32 +++++
 log4j-samples/scala-api/.gitignore              |   3 +
 pom.xml                                         |  12 ++
 src/changes/changes.xml                         |  19 ++-
 36 files changed, 629 insertions(+), 130 deletions(-)
----------------------------------------------------------------------



[48/50] logging-log4j2 git commit: LOG4J2-1349 updated the user manual to document the context data injector and garbage-free ThreadContext map

Posted by rp...@apache.org.
LOG4J2-1349 updated the user manual to document the context data injector and garbage-free ThreadContext map


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7c1406ce
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7c1406ce
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7c1406ce

Branch: refs/heads/master
Commit: 7c1406ce5920cdee4f523a50c1e956156539c1ba
Parents: e8a25a9
Author: rpopma <rp...@apache.org>
Authored: Sat Sep 10 02:10:11 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sat Sep 10 02:10:11 2016 +0900

----------------------------------------------------------------------
 src/site/site.xml                         |  1 +
 src/site/xdoc/manual/configuration.xml.vm | 14 ++++++++++++++
 src/site/xdoc/manual/extending.xml        | 16 ++++++++++++++++
 src/site/xdoc/manual/garbagefree.xml      |  6 +++++-
 src/site/xdoc/manual/thread-context.xml   | 16 ++++++++++++++++
 5 files changed, 52 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7c1406ce/src/site/site.xml
----------------------------------------------------------------------
diff --git a/src/site/site.xml b/src/site/site.xml
index cf289e8..971e444 100644
--- a/src/site/site.xml
+++ b/src/site/site.xml
@@ -205,6 +205,7 @@
         <item name="Layouts" href="/manual/extending.html#Layouts"/>
         <item name="PatternConverters" href="/manual/extending.html#PatternConverters"/>
         <item name="Plugin Builders" href="/manual/extending.html#Plugin_Builders"/>
+        <item name="Custom ContextDataInjector" href="/manual/extending.html#Custom_ContextDataInjector"/>
         <item name="Custom Plugins" href="/manual/extending.html#Custom_Plugins"/>
       </item>
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7c1406ce/src/site/xdoc/manual/configuration.xml.vm
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/configuration.xml.vm b/src/site/xdoc/manual/configuration.xml.vm
index a7edfce..60419a4 100644
--- a/src/site/xdoc/manual/configuration.xml.vm
+++ b/src/site/xdoc/manual/configuration.xml.vm
@@ -1688,6 +1688,20 @@ public class AwesomeTest {
     </td>
   </tr>
   <tr>
+    <td><a name="log4j2.ContextDataInjector"/>log4j2.ContextDataInjector</td>
+    <td>&nbsp;</td>
+    <td>
+      Fully specified class name of a custom <tt>ContextDataInjector</tt> implementation class.
+    </td>
+  </tr>
+  <tr>
+    <td><a name="log4j2.garbagefree.threadContextMap"/>log4j2.garbagefree.threadContextMap</td>
+    <td>false</td>
+    <td>
+      Specify "true" to make the ThreadContext map garbage-free.
+    </td>
+  </tr>
+  <tr>
     <td><a name="log4j2.disable.jmx"/>log4j2.disable.jmx</td>
     <td>false</td>
     <td>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7c1406ce/src/site/xdoc/manual/extending.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/extending.xml b/src/site/xdoc/manual/extending.xml
index 2bcdef2..fae89a5 100644
--- a/src/site/xdoc/manual/extending.xml
+++ b/src/site/xdoc/manual/extending.xml
@@ -516,6 +516,22 @@ ListAppender list1 = ListAppender.createAppender("List1", true, false, null, nul
 ListAppender list2 = ListAppender.newBuilder().setName("List1").setEntryPerNewLine(true).build();
 ]]></pre>
           </subsection>
+        <subsection name="Custom ContextDataInjector">
+          <p>
+            The <code>ContextDataInjector</code> (introduced in Log4j 2.7) is responsible for
+            populating the LogEvent's <code>ContextData</code> with key-value pairs
+            or replacing it completely.
+            The default implementation is ThreadContextDataInjector, which obtains context attributes from the ThreadContext.
+          </p><p>
+          Applications may replace the default ContextDataInjector by setting the value of the system property
+          log4j2.ContextDataInjector to the name of the custom ContextDataInjector class.
+        </p><p>
+          Implementors should be aware there are some subtleties related to thread-safety and implementing a
+          context data injector in a garbage-free manner.
+          See the <a class="javadoc" href="../log4j-core/apidocs/org/apache/logging/log4j/core/impl/ContextDataInjector.html">ContextDataInjector</a>
+          javadoc for detail.
+        </p>
+        </subsection>
           <subsection name="Custom Plugins">
             <p>See the <a href="plugins.html">Plugins</a> section of the manual.</p>
 <!-- TODO: some documentation here! -->

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7c1406ce/src/site/xdoc/manual/garbagefree.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/garbagefree.xml b/src/site/xdoc/manual/garbagefree.xml
index 46499d5..fb683fe 100644
--- a/src/site/xdoc/manual/garbagefree.xml
+++ b/src/site/xdoc/manual/garbagefree.xml
@@ -133,6 +133,8 @@
               synchronization on the shared buffer. If your application is multi-threaded and logging performance
               is important, consider using Async Loggers.
               </li>
+            <li>The ThreadContext map is <em>not</em> garbage-free by default, but from Log4j 2.7 it can be configured
+              to be garbage-free by setting system property <tt>log4j2.garbagefree.threadContextMap</tt> to "true".</li>
           </ul>
           <p>
             Instead of system properties, the above properties can also be specified in a file named
@@ -355,7 +357,9 @@ public void garbageFree() {
               <b>Note:</b> not all logging is garbage free. Specifically:
             </p>
             <ul>
-              <li>The ThreadContext map and stack are not garbage-free yet.</li>
+              <li>The ThreadContext map is not garbage-free by default, but can be configured to be garbage-free
+              by setting system property <tt>log4j2.garbagefree.threadContextMap</tt> to "true".</li>
+              <li>The ThreadContext stack is not garbage-free.</li>
               <li>Logging more than 10 parameters creates vararg arrays.</li>
               <li>Logging very large messages (more than 518 characters) when all loggers are Async Loggers
                 will cause the internal StringBuilder in the RingBuffer to be trimmed back to their max size.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7c1406ce/src/site/xdoc/manual/thread-context.xml
----------------------------------------------------------------------
diff --git a/src/site/xdoc/manual/thread-context.xml b/src/site/xdoc/manual/thread-context.xml
index 316de96..5ca874f 100644
--- a/src/site/xdoc/manual/thread-context.xml
+++ b/src/site/xdoc/manual/thread-context.xml
@@ -167,6 +167,22 @@ try (final CloseableThreadContext.Instance ctc = CloseableThreadContext.put("id"
               Use <code>%x</code> to include the full contents of the <a href="http://docs.oracle.com/javase/6/docs/api/java/util/Stack.html">Stack</a>.
             </li>
           </ul>
+          <h4>Non thread-local context data </h4>
+          <p>
+            The ThreadContext allows us to tag logging statements so we can link log entries that were related
+            in some way. The limitation is that this only works for logging done on the same application thread
+            (or child threads when configured).
+          </p>
+          <p>
+            Some applications have a thread model that delegates work to other threads, and
+            in such models, tagging attributes that are put into a thread-local map in one thread are not visible
+            in the other threads and logging done in the other threads will not show these attributes.
+          </p>
+          <p>
+            Log4j 2.7 adds a flexible mechanism to tag logging statements with context data coming from
+            other sources than the ThreadContext.
+            See the manual page on <a href="extending.html#Custom_ContextDataInjector">extending Log4j</a> for details.
+          </p>
         </subsection>
       </section>
     </body>


[03/50] logging-log4j2 git commit: LOG4J2-1010 added method ContextDataInjector::rawContextData()

Posted by rp...@apache.org.
LOG4J2-1010 added method ContextDataInjector::rawContextData()

 This method is intended to give fast access to the underlying context data, for use in filters and lookups.
 The idea is that this method does *not* need to guarantee that the returned object can safely be passed off to another thread, and this looser guarantee allows us to avoid making a copy of the data.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/d057eb20
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/d057eb20
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/d057eb20

Branch: refs/heads/master
Commit: d057eb204aac88bc4a58c6aa694dfac6063d228a
Parents: 07162be
Author: rpopma <rp...@apache.org>
Authored: Sun Aug 28 23:57:12 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Aug 28 23:57:12 2016 +0900

----------------------------------------------------------------------
 .../log4j/core/impl/ContextDataInjector.java        | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/d057eb20/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
index c1bd4b4..7fe4c53 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
@@ -18,6 +18,7 @@ package org.apache.logging.log4j.core.impl;
 
 import java.util.List;
 
+import org.apache.logging.log4j.core.ContextData;
 import org.apache.logging.log4j.core.config.Property;
 
 /**
@@ -47,6 +48,10 @@ public interface ContextDataInjector {
     /**
      * Returns a {@code MutableContextData} object initialized with the specified properties and the appropriate
      * context data. The returned value may be the specified parameter or a different object.
+     * <p>
+     * Thread-safety note: The returned object can safely be passed off to another thread: future changes in the
+     * underlying context data will not be reflected in the returned object.
+     * </p>
      *
      * @param properties Properties from the log4j configuration to be added to the resulting ContextData. May be
      *          {@code null} or empty
@@ -55,4 +60,15 @@ public interface ContextDataInjector {
      *          context data. The returned value may be the specified parameter or a different object.
      */
     MutableContextData injectContextData(final List<Property> properties, final MutableContextData reusable);
+
+    /**
+     * Returns a {@code ContextData} object reflecting the current state of the context.
+     * <p>
+     * Thread-safety note: The returned object can only be safely used <em>in the current thread</em>. Changes in the
+     * underlying context may or may not be reflected in the returned object, depending on the context data source and
+     * the implementation of this method. It is not safe to pass the returned object to another thread.
+     * </p>
+     * @return a {@code ContextData} object reflecting the current state of the context
+     */
+    ContextData rawContextData();
 }


[29/50] logging-log4j2 git commit: LOG4J2-1349 javadoc fixes

Posted by rp...@apache.org.
LOG4J2-1349 javadoc fixes


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/fb7c8ea1
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/fb7c8ea1
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/fb7c8ea1

Branch: refs/heads/master
Commit: fb7c8ea14b8e87d42cfbaec74ac3afb84b56b1a7
Parents: 1dbe39e
Author: rpopma <rp...@apache.org>
Authored: Fri Sep 2 23:39:31 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Sep 2 23:39:31 2016 +0900

----------------------------------------------------------------------
 .../src/main/java/org/apache/logging/log4j/util/BiConsumer.java    | 2 +-
 .../src/main/java/org/apache/logging/log4j/util/TriConsumer.java   | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fb7c8ea1/log4j-api/src/main/java/org/apache/logging/log4j/util/BiConsumer.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/BiConsumer.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/BiConsumer.java
index 3dad0e4..375cc57 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/BiConsumer.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/BiConsumer.java
@@ -5,7 +5,7 @@ package org.apache.logging.log4j.util;
  *
  * @param <K> type of the first argument
  * @param <V> type of the second argument
- * @see org.apache.logging.log4j.core.ContextData
+ * @see org.apache.logging.log4j.spi.ContextData
  * @since 2.7
  */
 public interface BiConsumer<K, V> {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/fb7c8ea1/log4j-api/src/main/java/org/apache/logging/log4j/util/TriConsumer.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/TriConsumer.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/TriConsumer.java
index 63960be..b5605ae 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/util/TriConsumer.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/TriConsumer.java
@@ -6,7 +6,7 @@ package org.apache.logging.log4j.util;
  * @param <K> type of the first argument
  * @param <V> type of the second argument
  * @param <S> type of the third argument
- * @see org.apache.logging.log4j.core.ContextData
+ * @see org.apache.logging.log4j.spi.ContextData
  * @since 2.7
  */
 public interface TriConsumer<K, V, S> {


[21/50] logging-log4j2 git commit: reset Unbox buffer to default size after configurable test

Posted by rp...@apache.org.
reset Unbox buffer to default size after configurable test


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/12ea0e2c
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/12ea0e2c
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/12ea0e2c

Branch: refs/heads/master
Commit: 12ea0e2cfa4602bf6f4833fe404ff56998d2d833
Parents: b4c0295
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 23:06:44 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 23:06:44 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/util/UnboxConfigurableTest.java    | 15 ++++++++++++++-
 1 file changed, 14 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/12ea0e2c/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java
index 30d6ddc..ff72716 100644
--- a/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/UnboxConfigurableTest.java
@@ -16,6 +16,9 @@
  */
 package org.apache.logging.log4j.util;
 
+import java.lang.reflect.Field;
+import java.lang.reflect.Modifier;
+
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
 import org.junit.Test;
@@ -33,8 +36,18 @@ public class UnboxConfigurableTest {
     }
 
     @AfterClass
-    public static void afterClass() {
+    public static void afterClass() throws Exception {
         System.clearProperty("log4j.unbox.ringbuffer.size");
+
+        // ensure subsequent tests (which assume 32 slots) pass
+        final Field field = Unbox.class.getDeclaredField("RINGBUFFER_SIZE");
+        field.setAccessible(true); // make non-private
+
+        final Field modifierField = Field.class.getDeclaredField("modifiers");
+        modifierField.setAccessible(true);
+        modifierField.setInt(field, field.getModifiers() &~ Modifier.FINAL); // make non-final
+
+        field.set(null, 32); // reset to default
     }
 
     @Test


[42/50] logging-log4j2 git commit: LOG4J2-1349 addiditional tests

Posted by rp...@apache.org.
LOG4J2-1349 addiditional tests


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/57eb2514
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/57eb2514
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/57eb2514

Branch: refs/heads/master
Commit: 57eb25143cc3ff8e4b5688da4e7b301749cc8ce0
Parents: 7615afa
Author: rpopma <rp...@apache.org>
Authored: Mon Sep 5 23:13:15 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Mon Sep 5 23:13:15 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/ThreadContextTestAccess.java  |  34 ++++
 ...ggerAllThreadContextImplementationsTest.java | 186 +++++++++++++++++++
 ...AsyncLoggerGarbageFreeThreadContextTest.java |  83 ---------
 .../AsyncLoggerConfigThreadContextTest.xml      |  29 +++
 .../resources/AsyncLoggerThreadContextTest.xml  |   9 +-
 5 files changed, 255 insertions(+), 86 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/57eb2514/log4j-core/src/test/java/org/apache/logging/log4j/ThreadContextTestAccess.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/ThreadContextTestAccess.java b/log4j-core/src/test/java/org/apache/logging/log4j/ThreadContextTestAccess.java
new file mode 100644
index 0000000..67c2d98
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/ThreadContextTestAccess.java
@@ -0,0 +1,34 @@
+/*
+ * 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;
+
+/**
+ * <p>
+ * Utility class to access package protected methods in {@code ThreadContext}.
+ * </p>
+ *
+ * @see ThreadContext
+ * @since 2.7
+ */
+public final class ThreadContextTestAccess {
+    private ThreadContextTestAccess() { // prevent instantiation
+    }
+
+    public static void init() {
+        ThreadContext.init();
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/57eb2514/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
new file mode 100644
index 0000000..58b9bec
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
@@ -0,0 +1,186 @@
+/*
+ * 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.async;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.ThreadContextAccess;
+import org.apache.logging.log4j.ThreadContextTestAccess;
+import org.apache.logging.log4j.core.CoreLoggerContexts;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.spi.DefaultThreadContextMap;
+import org.apache.logging.log4j.util.Unbox;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.*;
+
+@RunWith(Parameterized.class)
+public class AsyncLoggerAllThreadContextImplementationsTest {
+
+    final static int LINE_COUNT = 130;
+    private ContextImpl contextImpl;
+    private Mode asyncMode;
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty("AsyncLogger.RingBufferSize", "128"); // minimum ringbuffer size
+        System.setProperty("AsyncLoggerConfig.RingBufferSize", "128"); // minimum ringbuffer size
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        System.clearProperty("AsyncLogger.RingBufferSize");
+        System.clearProperty("AsyncLoggerConfig.RingBufferSize");
+        System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
+        System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
+        System.clearProperty("log4j2.garbagefree.threadContextMap");
+        System.clearProperty("log4j2.is.webapp");
+        System.clearProperty("log4j2.threadContextMap");
+    }
+
+    static enum Mode {
+        ALL_ASYNC, MIXED, BOTH;
+
+        void initSelector() {
+            if (this == ALL_ASYNC || this == BOTH) {
+                System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,  AsyncLoggerContextSelector.class.getName());
+            } else {
+                System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
+            }
+        }
+
+        void initConfigFile() {
+            System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, this == ALL_ASYNC //
+                    ? "AsyncLoggerThreadContextTest.xml" //
+                    : "AsyncLoggerConfigThreadContextTest.xml");
+        }
+    }
+
+    static enum ContextImpl {
+        WEBAPP, GARBAGE_FREE, COPY_ON_WRITE;
+
+        void init() {
+            System.clearProperty("log4j2.threadContextMap");
+            final String PACKAGE = "org.apache.logging.log4j.spi.";
+            System.setProperty("log4j2.threadContextMap", PACKAGE + implClassSimpleName());
+            ThreadContextTestAccess.init();
+        }
+
+        public String implClassSimpleName() {
+            switch (this) {
+                case WEBAPP:
+                    return DefaultThreadContextMap.class.getSimpleName();
+                case GARBAGE_FREE:
+                    return "GarbageFreeSortedArrayThreadContextMap";
+                case COPY_ON_WRITE:
+                    return "CopyOnWriteSortedArrayThreadContextMap";
+            }
+            throw new IllegalStateException("Unknown state " + this);
+        }
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+                { ContextImpl.WEBAPP, Mode.ALL_ASYNC},
+                { ContextImpl.WEBAPP, Mode.MIXED },
+                { ContextImpl.WEBAPP, Mode.BOTH },
+                { ContextImpl.GARBAGE_FREE, Mode.ALL_ASYNC},
+                { ContextImpl.GARBAGE_FREE, Mode.MIXED},
+                { ContextImpl.GARBAGE_FREE, Mode.BOTH},
+                { ContextImpl.COPY_ON_WRITE, Mode.ALL_ASYNC},
+                { ContextImpl.COPY_ON_WRITE, Mode.MIXED},
+                { ContextImpl.COPY_ON_WRITE, Mode.BOTH}
+        });
+    }
+
+    public AsyncLoggerAllThreadContextImplementationsTest(ContextImpl contextImpl, Mode asyncMode) {
+        this.contextImpl = contextImpl;
+        this.asyncMode = asyncMode;
+
+        asyncMode.initSelector();
+        asyncMode.initConfigFile();
+
+        contextImpl.init();
+    }
+
+    @Test
+    public void testAsyncLogWritesToLog() throws Exception {
+        final File file = new File("target", "AsyncLoggerTest.log");
+        // System.out.println(f.getAbsolutePath());
+        file.delete();
+
+        final File sync = new File("target", "SynchronousContextTest.log");
+        sync.delete();
+
+        ThreadContext.push("stackvalue");
+        ThreadContext.put("KEY", "mapvalue");
+
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        for (int i = 0; i < LINE_COUNT; i++) {
+            if ((i & 1) == 1) {
+                ThreadContext.put("count", String.valueOf(i));
+            } else {
+                ThreadContext.remove("count");
+            }
+            final String contextmap = ThreadContextAccess.getThreadContextMap().getClass().getSimpleName();
+            log.info("{} {} i={}", contextImpl, contextmap, Unbox.box(i));
+        }
+        ThreadContext.pop();
+        CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
+
+        checkResult(file);
+        if (asyncMode == Mode.MIXED || asyncMode == Mode.BOTH) {
+            checkResult(sync);
+        }
+        LogManager.shutdown();
+    }
+
+    private void checkResult(final File file) throws IOException {
+        final String contextDesc = contextImpl + " " + contextImpl.implClassSimpleName();
+        try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
+            String expect = null;
+            for (int i = 0; i < LINE_COUNT; i++) {
+                String line = reader.readLine();
+                if ((i & 1) == 1) {
+                    expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, count=" + i + "} "
+                            + contextDesc + " i=" + i;
+                } else {
+                    expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue} " + contextDesc + " i=" + i;
+                }
+                assertEquals("line " + i, expect, line);
+            }
+            final String noMoreLines = reader.readLine();
+            assertNull("done", noMoreLines);
+        } finally {
+            file.delete();
+        }
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/57eb2514/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerGarbageFreeThreadContextTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerGarbageFreeThreadContextTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerGarbageFreeThreadContextTest.java
deleted file mode 100644
index da232bd..0000000
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerGarbageFreeThreadContextTest.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.core.async;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-
-import org.apache.logging.log4j.LogManager;
-import org.apache.logging.log4j.Logger;
-import org.apache.logging.log4j.ThreadContext;
-import org.apache.logging.log4j.core.CoreLoggerContexts;
-import org.apache.logging.log4j.core.config.ConfigurationFactory;
-import org.apache.logging.log4j.core.util.Constants;
-import org.apache.logging.log4j.util.Unbox;
-import org.junit.AfterClass;
-import org.junit.BeforeClass;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-public class AsyncLoggerGarbageFreeThreadContextTest {
-
-    @BeforeClass
-    public static void beforeClass() {
-        System.setProperty("log4j2.garbagefree.threadContextMap", "true");
-        System.setProperty("AsyncLogger.RingBufferSize", "128"); // minimum ringbuffer size
-        System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,
-                AsyncLoggerContextSelector.class.getName());
-        System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY,
-                "AsyncLoggerThreadContextTest.xml");
-    }
-
-    @AfterClass
-    public static void afterClass() {
-        System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
-    }
-
-    @Test
-    public void testAsyncLogWritesToLog() throws Exception {
-        final File file = new File("target", "AsyncLoggerTest.log");
-        // System.out.println(f.getAbsolutePath());
-        file.delete();
-
-        ThreadContext.push("stackvalue");
-        ThreadContext.put("KEY", "mapvalue");
-
-        final Logger log = LogManager.getLogger("com.foo.Bar");
-        final String msg = "Async logger msg";
-        for (int i = 0; i < 128; i++) {
-            log.info("init message #{}", Unbox.box(i));
-        }
-        log.info(msg, new InternalError("this is not a real error"));
-        CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
-
-        final BufferedReader reader = new BufferedReader(new FileReader(file));
-        for (int i = 0; i < 128; i++) {
-            reader.readLine();
-        }
-        final String line1 = reader.readLine();
-        reader.close();
-        file.delete();
-        assertNotNull("line1", line1);
-        assertTrue("line1 correct", line1.contains(msg));
-
-        assertTrue("ThreadContext.map", line1.contains("mapvalue"));
-        assertTrue("ThreadContext.stack", line1.contains("stackvalue"));
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/57eb2514/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml b/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
new file mode 100644
index 0000000..5419e20
--- /dev/null
+++ b/log4j-core/src/test/resources/AsyncLoggerConfigThreadContextTest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<Configuration status="ERROR">
+  <Properties>
+    <Property name="configProp">configValue</Property>
+  </Properties>
+  <Appenders>
+    <RandomAccessFile name="RandomAccessFile" fileName="target/AsyncLoggerTest.log"
+        immediateFlush="false" append="false">
+      <PatternLayout>
+        <Pattern>%p %c{1.} %X{KEY} %x %X %m%ex%n</Pattern>
+      </PatternLayout>
+    </RandomAccessFile>
+    <RandomAccessFile name="SynchronousRandomAccessFile" fileName="target/SynchronousContextTest.log"
+	    		immediateFlush="true" append="false">
+      <PatternLayout>
+        <Pattern>%p %c{1.} %X{KEY} %x %X %m%ex%n</Pattern>
+      </PatternLayout>
+    </RandomAccessFile>
+  </Appenders>
+
+  <Loggers>
+    <AsyncLogger name="com.foo" level="info" includeLocation="false" additivity="true">
+      <AppenderRef ref="RandomAccessFile"/>
+    </AsyncLogger>
+    <Root level="info" includeLocation="false">
+      <AppenderRef ref="SynchronousRandomAccessFile"/>
+    </Root>
+  </Loggers>
+</Configuration>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/57eb2514/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml b/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
index 734fb9e..6e507d2 100644
--- a/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
+++ b/log4j-core/src/test/resources/AsyncLoggerThreadContextTest.xml
@@ -1,14 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <Configuration status="ERROR">
+  <Properties>
+    <Property name="configProp">configValue</Property>
+  </Properties>
   <Appenders>
-    <RandomAccessFile name="RandomAccessFile" fileName="target/AsyncLoggerTest.log" 
+    <RandomAccessFile name="RandomAccessFile" fileName="target/AsyncLoggerTest.log"
 	    		immediateFlush="false" append="false">
       <PatternLayout>
-        <Pattern>%d %p %c{1.} [%t] %X{KEY} %x %location %m %ex%n</Pattern>
+        <Pattern>%p %c{1.} %X{KEY} %x %X %m%ex%n</Pattern>
       </PatternLayout>
     </RandomAccessFile>
   </Appenders>
-  
+
   <Loggers>
     <Root level="info" includeLocation="false">
       <AppenderRef ref="RandomAccessFile"/>


[11/50] logging-log4j2 git commit: LOG4J2-1010 added javadoc example implementation for 3rd party implementors

Posted by rp...@apache.org.
LOG4J2-1010 added javadoc example implementation for 3rd party implementors


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/2a976a99
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/2a976a99
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/2a976a99

Branch: refs/heads/master
Commit: 2a976a990f9002b49f5fabaa0858be9464e5aa99
Parents: d3d3069
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 00:11:20 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 00:11:20 2016 +0900

----------------------------------------------------------------------
 .../log4j/core/impl/ContextDataInjector.java    | 34 ++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/2a976a99/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
index 7fe4c53..058ffe1 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
@@ -33,9 +33,13 @@ import org.apache.logging.log4j.core.config.Property;
  * in order to initialize log events with context data from any arbitrary context.
  * </p><p>
  * When providing a custom {@code ContextDataInjector}, be aware that the {@code ContextDataFactory} may be invoked
- * multiple times by the various components in Log4j that need access to context data.
+ * multiple times and the various components in Log4j that need access to context data may each have their own instance
+ * of {@code ContextDataInjector}.
  * This includes the object(s) that populate log events, but also various lookups and filters that look at
  * context data to determine whether an event should be logged.
+ * </p><p>
+ * Implementors should take particular note of how the different methods in the interface have different thread-safety
+ * guarantees to enable optimal performance.
  * </p>
  *
  * @see ContextDataInjectorFactory
@@ -49,21 +53,47 @@ public interface ContextDataInjector {
      * Returns a {@code MutableContextData} object initialized with the specified properties and the appropriate
      * context data. The returned value may be the specified parameter or a different object.
      * <p>
+     * This method will be called for each log event to initialize its context data and implementors should take
+     * care to make this method as performant as possible while preserving at least the following thread-safety
+     * guarantee.
+     * </p><p>
      * Thread-safety note: The returned object can safely be passed off to another thread: future changes in the
      * underlying context data will not be reflected in the returned object.
+     * </p><p>
+     * Example implementation:
      * </p>
+     * <pre>
+     * public MutableContextData injectContextData(List<Property> properties, MutableContextData reusable) {
+     *     if (properties == null || properties.isEmpty()) {
+     *         // assume context data is stored in a copy-on-write data structure that is safe to pass to another thread
+     *         return (MutableContextData) rawContextData();
+     *     }
+     *     // first copy configuration properties into the result
+     *     ThreadContextDataInjector.copyProperties(properties, reusable);
+     *
+     *     // then copy context data key-value pairs (may overwrite configuration properties)
+     *     reusable.addAll(rawContextData());
+     *     return reusable;
+     * }
+     * </pre>
      *
      * @param properties Properties from the log4j configuration to be added to the resulting ContextData. May be
      *          {@code null} or empty
      * @param reusable a {@code MutableContextData} instance that may be reused to avoid creating temporary objects
      * @return a {@code MutableContextData} instance initialized with the specified properties and the appropriate
      *          context data. The returned value may be the specified parameter or a different object.
+     * @see ThreadContextDataInjector#copyProperties(List, MutableContextData)
      */
     MutableContextData injectContextData(final List<Property> properties, final MutableContextData reusable);
 
     /**
-     * Returns a {@code ContextData} object reflecting the current state of the context.
+     * Returns a {@code ContextData} object reflecting the current state of the context. Configuration properties
+     * are not included in the result.
      * <p>
+     * This method may be called multiple times for each log event by Filters and Lookups and implementors should take
+     * care to make this method as performant as possible while preserving at least the following thread-safety
+     * guarantee.
+     * </p><p>
      * Thread-safety note: The returned object can only be safely used <em>in the current thread</em>. Changes in the
      * underlying context may or may not be reflected in the returned object, depending on the context data source and
      * the implementation of this method. It is not safe to pass the returned object to another thread.


[15/50] logging-log4j2 git commit: LOG4J2-1349 simplified: collapsed abstract with concrete thread context map classes

Posted by rp...@apache.org.
LOG4J2-1349 simplified: collapsed abstract with concrete thread context map classes


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/4b166868
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/4b166868
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/4b166868

Branch: refs/heads/master
Commit: 4b1668684d92a41f26e185d942bd33550c4c5464
Parents: 65a551e
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 21:50:25 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 21:50:25 2016 +0900

----------------------------------------------------------------------
 ...AbstractCopyOnWriteMutableThreadContext.java | 191 ------------------
 ...AbstractGarbageFreeMutableThreadContext.java | 193 -------------------
 .../CopyOnWriteSortedArrayThreadContextMap.java | 183 +++++++++++++++++-
 .../GarbageFreeSortedArrayThreadContextMap.java | 186 +++++++++++++++++-
 .../CopyOnWriteOpenHashMapThreadContextMap.java |   4 +-
 .../GarbageFreeOpenHashMapThreadContextMap.java |   4 +-
 6 files changed, 361 insertions(+), 400 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractCopyOnWriteMutableThreadContext.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractCopyOnWriteMutableThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractCopyOnWriteMutableThreadContext.java
deleted file mode 100644
index c71ed95..0000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractCopyOnWriteMutableThreadContext.java
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.spi;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.logging.log4j.util.PropertiesUtil;
-
-/**
- * ThreadContextMap implementation backed by {@code MutableContextData}.
- * A new ThreadContext Map is created each time it is updated and the Map stored is always
- * immutable. This means the Map can be passed to other threads without concern that it will be updated. Since it is
- * expected that the Map will be passed to many more log events than the number of keys it contains the performance
- * should be much better than if the Map was copied for each event.
- *
- * @since 2.7
- */
-public abstract class AbstractCopyOnWriteMutableThreadContext implements ThreadContextMap, ThreadContextMap2,
-        CopyOnWrite, MutableContextDataSupplier {
-
-    /**
-     * The default initial capacity.
-     */
-    protected static final int DEFAULT_INITIAL_CAPACITY = 16;
-
-    /**
-     * System property name that can be used to control the data structure's initial capacity.
-     */
-    protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity";
-
-    /**
-     * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain
-     * {@code ThreadLocal} (value is not "true") in the implementation.
-     */
-    public static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
-
-    private final ThreadLocal<MutableContextData> localMap;
-
-    public AbstractCopyOnWriteMutableThreadContext() {
-        this.localMap = createThreadLocalMap();
-    }
-
-    // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured.
-    // (This method is package protected for JUnit tests.)
-    private ThreadLocal<MutableContextData> createThreadLocalMap() {
-        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
-        final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP);
-        if (inheritable) {
-            return new InheritableThreadLocal<MutableContextData>() {
-                @Override
-                protected MutableContextData childValue(final MutableContextData parentValue) {
-                    return parentValue != null ? createMutableContextData(parentValue) : null;
-                }
-            };
-        }
-        // if not inheritable, return plain ThreadLocal with null as initial value
-        return new ThreadLocal<>();
-    }
-
-    protected abstract MutableContextData createMutableContextData();
-
-    protected abstract MutableContextData createMutableContextData(final ContextData original);
-
-    @Override
-    public void put(final String key, final String value) {
-        MutableContextData map = localMap.get();
-        map = map == null ? createMutableContextData() : createMutableContextData(map);
-        map.putValue(key, value);
-        localMap.set(map);
-    }
-
-    @Override
-    public void putAll(final Map<String, String> values) {
-        if (values == null || values.isEmpty()) {
-            return;
-        }
-        MutableContextData map = localMap.get();
-        map = map == null ? createMutableContextData() : createMutableContextData(map);
-        for (final Map.Entry<String, String> entry : values.entrySet()) {
-            map.putValue(entry.getKey(), entry.getValue());
-        }
-        localMap.set(map);
-    }
-
-    @Override
-    public String get(final String key) {
-        final MutableContextData map = localMap.get();
-        return map == null ? null : (String) map.getValue(key);
-    }
-
-    @Override
-    public void remove(final String key) {
-        final MutableContextData map = localMap.get();
-        if (map != null) {
-            final MutableContextData copy = createMutableContextData(map);
-            copy.remove(key);
-            localMap.set(copy);
-        }
-    }
-
-    @Override
-    public void clear() {
-        localMap.remove();
-    }
-
-    @Override
-    public boolean containsKey(final String key) {
-        final MutableContextData map = localMap.get();
-        return map != null && map.containsKey(key);
-    }
-
-    @Override
-    public Map<String, String> getCopy() {
-        final MutableContextData map = localMap.get();
-        return map == null ? Collections.<String, String>emptyMap() : map.asMap();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public MutableContextData getMutableContextData() {
-        return localMap.get();
-    }
-
-    @Override
-    public Map<String, String> getImmutableMapOrNull() {
-        final MutableContextData map = localMap.get();
-        return map == null ? null : Collections.unmodifiableMap(map.asMap());
-    }
-
-    @Override
-    public boolean isEmpty() {
-        final MutableContextData map = localMap.get();
-        return map == null || map.size() == 0;
-    }
-
-    @Override
-    public String toString() {
-        final MutableContextData map = localMap.get();
-        return map == null ? "{}" : map.toString();
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        final MutableContextData map = this.localMap.get();
-        result = prime * result + ((map == null) ? 0 : map.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (!(obj instanceof ThreadContextMap)) {
-            return false;
-        }
-        final ThreadContextMap other = (ThreadContextMap) obj;
-        final Map<String, String> map = this.getImmutableMapOrNull();
-        final Map<String, String> otherMap = other.getImmutableMapOrNull();
-        if (map == null) {
-            if (otherMap != null) {
-                return false;
-            }
-        } else if (!map.equals(otherMap)) {
-            return false;
-        }
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractGarbageFreeMutableThreadContext.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractGarbageFreeMutableThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractGarbageFreeMutableThreadContext.java
deleted file mode 100644
index 4e86761..0000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/AbstractGarbageFreeMutableThreadContext.java
+++ /dev/null
@@ -1,193 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.spi;
-
-import java.util.Collections;
-import java.util.Map;
-
-import org.apache.logging.log4j.util.PropertiesUtil;
-
-/**
- * Garbage-free ThreadContextMap implementation backed by {@code MutableContextData}.
- * <p>
- * This implementation does <em>not</em> make a copy of its contents on every operation, so this data structure cannot
- * be passed to log events. It is advisable to provide a fast way to copy data from this data structure into log
- * events.
- * </p>
- * @since 2.7
- */
-public abstract class AbstractGarbageFreeMutableThreadContext implements ThreadContextMap, ThreadContextMap2,
-        MutableContextDataSupplier {
-
-    /**
-     * The default initial capacity.
-     */
-    protected static final int DEFAULT_INITIAL_CAPACITY = 16;
-
-    /**
-     * System property name that can be used to control the data structure's initial capacity.
-     */
-    protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity";
-
-    /**
-     * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain
-     * {@code ThreadLocal} (value is not "true") in the implementation.
-     */
-    public static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
-
-    private final ThreadLocal<MutableContextData> localMap;
-
-    public AbstractGarbageFreeMutableThreadContext() {
-        this.localMap = createThreadLocalMap();
-    }
-
-    // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured.
-    // (This method is package protected for JUnit tests.)
-    private ThreadLocal<MutableContextData> createThreadLocalMap() {
-        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
-        final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP);
-        if (inheritable) {
-            return new InheritableThreadLocal<MutableContextData>() {
-                @Override
-                protected MutableContextData childValue(final MutableContextData parentValue) {
-                    return parentValue != null ? createMutableContextData(parentValue) : null;
-                }
-            };
-        }
-        // if not inheritable, return plain ThreadLocal with null as initial value
-        return new ThreadLocal<>();
-    }
-
-    protected abstract MutableContextData createMutableContextData();
-
-    protected abstract MutableContextData createMutableContextData(final ContextData original);
-
-    private MutableContextData getThreadLocalMap() {
-        MutableContextData map = localMap.get();
-        if (map == null) {
-            map = createMutableContextData();
-            localMap.set(map);
-        }
-        return map;
-    }
-
-    @Override
-    public void put(final String key, final String value) {
-        getThreadLocalMap().putValue(key, value);
-    }
-
-    @Override
-    public void putAll(final Map<String, String> values) {
-        if (values == null || values.isEmpty()) {
-            return;
-        }
-        final MutableContextData map = getThreadLocalMap();
-        for (final Map.Entry<String, String> entry : values.entrySet()) {
-            map.putValue(entry.getKey(), entry.getValue());
-        }
-    }
-
-    @Override
-    public String get(final String key) {
-        final MutableContextData map = localMap.get();
-        return map == null ? null : (String) map.getValue(key);
-    }
-
-    @Override
-    public void remove(final String key) {
-        final MutableContextData map = localMap.get();
-        if (map != null) {
-            map.remove(key);
-        }
-    }
-
-    @Override
-    public void clear() {
-        localMap.remove();
-    }
-
-    @Override
-    public boolean containsKey(final String key) {
-        final MutableContextData map = localMap.get();
-        return map != null && map.containsKey(key);
-    }
-
-    @Override
-    public Map<String, String> getCopy() {
-        final MutableContextData map = localMap.get();
-        return map == null ? Collections.<String, String>emptyMap() : map.asMap();
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-    public MutableContextData getMutableContextData() {
-        return localMap.get();
-    }
-
-    @Override
-    public Map<String, String> getImmutableMapOrNull() {
-        final MutableContextData map = localMap.get();
-        return map == null ? null : Collections.unmodifiableMap(map.asMap());
-    }
-
-    @Override
-    public boolean isEmpty() {
-        final MutableContextData map = localMap.get();
-        return map == null || map.size() == 0;
-    }
-
-    @Override
-    public String toString() {
-        final MutableContextData map = localMap.get();
-        return map == null ? "{}" : map.toString();
-    }
-
-    @Override
-    public int hashCode() {
-        final int prime = 31;
-        int result = 1;
-        final MutableContextData map = this.localMap.get();
-        result = prime * result + ((map == null) ? 0 : map.hashCode());
-        return result;
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (this == obj) {
-            return true;
-        }
-        if (obj == null) {
-            return false;
-        }
-        if (!(obj instanceof ThreadContextMap)) {
-            return false;
-        }
-        final ThreadContextMap other = (ThreadContextMap) obj;
-        final Map<String, String> map = this.getImmutableMapOrNull();
-        final Map<String, String> otherMap = other.getImmutableMapOrNull();
-        if (map == null) {
-            if (otherMap != null) {
-                return false;
-            }
-        } else if (!map.equals(otherMap)) {
-            return false;
-        }
-        return true;
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
index f1bf509..afa9d99 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
@@ -16,24 +16,197 @@
  */
 package org.apache.logging.log4j.spi;
 
+import java.util.Collections;
+import java.util.Map;
+
 import org.apache.logging.log4j.util.PropertiesUtil;
 
 /**
- * {@code SortedArrayContextData}-based implementation of the {@code ThreadContextMap} interface that creates a copy of
+ * {@code ArrayContextData}-based implementation of the {@code ThreadContextMap} interface that creates a copy of
  * the data structure on every modification. Any particular instance of the data structure is a snapshot of the
- * ThreadContext at some point in time and can safely be passed off to other threads
+ * ThreadContext at some point in time and can safely be passed off to other threads.  Since it is
+ * expected that the Map will be passed to many more log events than the number of keys it contains the performance
+ * should be much better than if the Map was copied for each event.
  *
  * @since 2.7
  */
-public class CopyOnWriteSortedArrayThreadContextMap extends AbstractCopyOnWriteMutableThreadContext {
-    @Override
+public class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
+        CopyOnWrite, MutableContextDataSupplier {
+
+    /**
+     * The default initial capacity.
+     */
+    protected static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * System property name that can be used to control the data structure's initial capacity.
+     */
+    protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity";
+
+    /**
+     * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain
+     * {@code ThreadLocal} (value is not "true") in the implementation.
+     */
+    public static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
+
+    private final ThreadLocal<MutableContextData> localMap;
+
+    public CopyOnWriteSortedArrayThreadContextMap() {
+        this.localMap = createThreadLocalMap();
+    }
+
+    // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured.
+    // (This method is package protected for JUnit tests.)
+    private ThreadLocal<MutableContextData> createThreadLocalMap() {
+        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
+        final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP);
+        if (inheritable) {
+            return new InheritableThreadLocal<MutableContextData>() {
+                @Override
+                protected MutableContextData childValue(final MutableContextData parentValue) {
+                    return parentValue != null ? createMutableContextData(parentValue) : null;
+                }
+            };
+        }
+        // if not inheritable, return plain ThreadLocal with null as initial value
+        return new ThreadLocal<>();
+    }
+
+    /**
+     * Returns an implementation of the {@code MutableContextData} used to back this thread context map.
+     * <p>
+     * Subclasses may override.
+     * </p>
+     * @return an implementation of the {@code MutableContextData} used to back this thread context map
+     */
     protected MutableContextData createMutableContextData() {
         return new ArrayContextData(PropertiesUtil.getProperties().getIntegerProperty(
                 PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
     }
 
-    @Override
+    /**
+     * Returns an implementation of the {@code MutableContextData} used to back this thread context map, pre-populated
+     * with the contents of the specified context data.
+     * <p>
+     * Subclasses may override.
+     * </p>
+     * @param original the key-value pairs to initialize the returned context data with
+     * @return an implementation of the {@code MutableContextData} used to back this thread context map
+     */
     protected MutableContextData createMutableContextData(final ContextData original) {
         return new ArrayContextData(original);
     }
+
+    @Override
+    public void put(final String key, final String value) {
+        MutableContextData map = localMap.get();
+        map = map == null ? createMutableContextData() : createMutableContextData(map);
+        map.putValue(key, value);
+        localMap.set(map);
+    }
+
+    @Override
+    public void putAll(final Map<String, String> values) {
+        if (values == null || values.isEmpty()) {
+            return;
+        }
+        MutableContextData map = localMap.get();
+        map = map == null ? createMutableContextData() : createMutableContextData(map);
+        for (final Map.Entry<String, String> entry : values.entrySet()) {
+            map.putValue(entry.getKey(), entry.getValue());
+        }
+        localMap.set(map);
+    }
+
+    @Override
+    public String get(final String key) {
+        final MutableContextData map = localMap.get();
+        return map == null ? null : (String) map.getValue(key);
+    }
+
+    @Override
+    public void remove(final String key) {
+        final MutableContextData map = localMap.get();
+        if (map != null) {
+            final MutableContextData copy = createMutableContextData(map);
+            copy.remove(key);
+            localMap.set(copy);
+        }
+    }
+
+    @Override
+    public void clear() {
+        localMap.remove();
+    }
+
+    @Override
+    public boolean containsKey(final String key) {
+        final MutableContextData map = localMap.get();
+        return map != null && map.containsKey(key);
+    }
+
+    @Override
+    public Map<String, String> getCopy() {
+        final MutableContextData map = localMap.get();
+        return map == null ? Collections.<String, String>emptyMap() : map.asMap();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public MutableContextData getMutableContextData() {
+        return localMap.get();
+    }
+
+    @Override
+    public Map<String, String> getImmutableMapOrNull() {
+        final MutableContextData map = localMap.get();
+        return map == null ? null : Collections.unmodifiableMap(map.asMap());
+    }
+
+    @Override
+    public boolean isEmpty() {
+        final MutableContextData map = localMap.get();
+        return map == null || map.size() == 0;
+    }
+
+    @Override
+    public String toString() {
+        final MutableContextData map = localMap.get();
+        return map == null ? "{}" : map.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        final MutableContextData map = this.localMap.get();
+        result = prime * result + ((map == null) ? 0 : map.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof ThreadContextMap)) {
+            return false;
+        }
+        final ThreadContextMap other = (ThreadContextMap) obj;
+        final Map<String, String> map = this.getImmutableMapOrNull();
+        final Map<String, String> otherMap = other.getImmutableMapOrNull();
+        if (map == null) {
+            if (otherMap != null) {
+                return false;
+            }
+        } else if (!map.equals(otherMap)) {
+            return false;
+        }
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
index 241af5c..5b4a938 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
@@ -16,27 +16,199 @@
  */
 package org.apache.logging.log4j.spi;
 
+import java.util.Collections;
+import java.util.Map;
+
 import org.apache.logging.log4j.util.PropertiesUtil;
 
 /**
- * {@code SortedArrayContextData}-based implementation of the {@code ThreadContextMap} interface that attempts not to
+ * {@code ArrayContextData}-based implementation of the {@code ThreadContextMap} interface that attempts not to
  * create temporary objects. Adding and removing key-value pairs will not create temporary objects.
  * <p>
- * Since the underlying data structure is modified directly it is not suitable for passing by reference to other
- * threads. Instead, client code needs to copy the contents when interacting with another thread.
+ * This implementation does <em>not</em> make a copy of its contents on every operation, so this data structure cannot
+ * be passed to log events. Instead, client code needs to copy the contents when interacting with another thread.
  * </p>
- *
  * @since 2.7
  */
-public class GarbageFreeSortedArrayThreadContextMap extends AbstractGarbageFreeMutableThreadContext {
-    @Override
+public abstract class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
+        MutableContextDataSupplier {
+
+    /**
+     * The default initial capacity.
+     */
+    protected static final int DEFAULT_INITIAL_CAPACITY = 16;
+
+    /**
+     * System property name that can be used to control the data structure's initial capacity.
+     */
+    protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity";
+
+    /**
+     * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain
+     * {@code ThreadLocal} (value is not "true") in the implementation.
+     */
+    public static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
+
+    private final ThreadLocal<MutableContextData> localMap;
+
+    public GarbageFreeSortedArrayThreadContextMap() {
+        this.localMap = createThreadLocalMap();
+    }
+
+    // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured.
+    // (This method is package protected for JUnit tests.)
+    private ThreadLocal<MutableContextData> createThreadLocalMap() {
+        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
+        final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP);
+        if (inheritable) {
+            return new InheritableThreadLocal<MutableContextData>() {
+                @Override
+                protected MutableContextData childValue(final MutableContextData parentValue) {
+                    return parentValue != null ? createMutableContextData(parentValue) : null;
+                }
+            };
+        }
+        // if not inheritable, return plain ThreadLocal with null as initial value
+        return new ThreadLocal<>();
+    }
+
+    /**
+     * Returns an implementation of the {@code MutableContextData} used to back this thread context map.
+     * <p>
+     * Subclasses may override.
+     * </p>
+     * @return an implementation of the {@code MutableContextData} used to back this thread context map
+     */
     protected MutableContextData createMutableContextData() {
         return new ArrayContextData(PropertiesUtil.getProperties().getIntegerProperty(
                 PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
     }
 
-    @Override
+    /**
+     * Returns an implementation of the {@code MutableContextData} used to back this thread context map, pre-populated
+     * with the contents of the specified context data.
+     * <p>
+     * Subclasses may override.
+     * </p>
+     * @param original the key-value pairs to initialize the returned context data with
+     * @return an implementation of the {@code MutableContextData} used to back this thread context map
+     */
     protected MutableContextData createMutableContextData(final ContextData original) {
         return new ArrayContextData(original);
     }
+
+    private MutableContextData getThreadLocalMap() {
+        MutableContextData map = localMap.get();
+        if (map == null) {
+            map = createMutableContextData();
+            localMap.set(map);
+        }
+        return map;
+    }
+
+    @Override
+    public void put(final String key, final String value) {
+        getThreadLocalMap().putValue(key, value);
+    }
+
+    @Override
+    public void putAll(final Map<String, String> values) {
+        if (values == null || values.isEmpty()) {
+            return;
+        }
+        final MutableContextData map = getThreadLocalMap();
+        for (final Map.Entry<String, String> entry : values.entrySet()) {
+            map.putValue(entry.getKey(), entry.getValue());
+        }
+    }
+
+    @Override
+    public String get(final String key) {
+        final MutableContextData map = localMap.get();
+        return map == null ? null : (String) map.getValue(key);
+    }
+
+    @Override
+    public void remove(final String key) {
+        final MutableContextData map = localMap.get();
+        if (map != null) {
+            map.remove(key);
+        }
+    }
+
+    @Override
+    public void clear() {
+        localMap.remove();
+    }
+
+    @Override
+    public boolean containsKey(final String key) {
+        final MutableContextData map = localMap.get();
+        return map != null && map.containsKey(key);
+    }
+
+    @Override
+    public Map<String, String> getCopy() {
+        final MutableContextData map = localMap.get();
+        return map == null ? Collections.<String, String>emptyMap() : map.asMap();
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public MutableContextData getMutableContextData() {
+        return localMap.get();
+    }
+
+    @Override
+    public Map<String, String> getImmutableMapOrNull() {
+        final MutableContextData map = localMap.get();
+        return map == null ? null : Collections.unmodifiableMap(map.asMap());
+    }
+
+    @Override
+    public boolean isEmpty() {
+        final MutableContextData map = localMap.get();
+        return map == null || map.size() == 0;
+    }
+
+    @Override
+    public String toString() {
+        final MutableContextData map = localMap.get();
+        return map == null ? "{}" : map.toString();
+    }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        final MutableContextData map = this.localMap.get();
+        result = prime * result + ((map == null) ? 0 : map.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null) {
+            return false;
+        }
+        if (!(obj instanceof ThreadContextMap)) {
+            return false;
+        }
+        final ThreadContextMap other = (ThreadContextMap) obj;
+        final Map<String, String> map = this.getImmutableMapOrNull();
+        final Map<String, String> otherMap = other.getImmutableMapOrNull();
+        if (map == null) {
+            if (otherMap != null) {
+                return false;
+            }
+        } else if (!map.equals(otherMap)) {
+            return false;
+        }
+        return true;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java
index f219c90..e34c031 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java
@@ -16,7 +16,7 @@
  */
 package org.apache.logging.log4j.perf.nogc;
 
-import org.apache.logging.log4j.spi.AbstractCopyOnWriteMutableThreadContext;
+import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
 import org.apache.logging.log4j.spi.ContextData;
 import org.apache.logging.log4j.spi.MutableContextData;
 import org.apache.logging.log4j.util.PropertiesUtil;
@@ -28,7 +28,7 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  *
  * @since 2.7
  */
-public class CopyOnWriteOpenHashMapThreadContextMap extends AbstractCopyOnWriteMutableThreadContext {
+public class CopyOnWriteOpenHashMapThreadContextMap extends CopyOnWriteSortedArrayThreadContextMap {
     @Override
     protected MutableContextData createMutableContextData() {
         return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/4b166868/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java
index 400a76c..cb97936 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java
@@ -16,7 +16,7 @@
  */
 package org.apache.logging.log4j.perf.nogc;
 
-import org.apache.logging.log4j.spi.AbstractGarbageFreeMutableThreadContext;
+import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap;
 import org.apache.logging.log4j.spi.ContextData;
 import org.apache.logging.log4j.spi.MutableContextData;
 import org.apache.logging.log4j.util.PropertiesUtil;
@@ -31,7 +31,7 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  *
  * @since 2.7
  */
-public class GarbageFreeOpenHashMapThreadContextMap extends AbstractGarbageFreeMutableThreadContext {
+public class GarbageFreeOpenHashMapThreadContextMap extends GarbageFreeSortedArrayThreadContextMap {
     @Override
     protected MutableContextData createMutableContextData() {
         return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(


[14/50] logging-log4j2 git commit: LOG4J2-1349 organized imports

Posted by rp...@apache.org.
LOG4J2-1349 organized imports


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/65a551eb
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/65a551eb
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/65a551eb

Branch: refs/heads/master
Commit: 65a551eb73c86dd786d00b424cb1c7d5bdc0682f
Parents: 5f6319f
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 21:49:24 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 21:49:24 2016 +0900

----------------------------------------------------------------------
 .../apache/logging/log4j/core/impl/ContextDataInjectorFactory.java  | 1 -
 1 file changed, 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/65a551eb/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
index e8e4607..511a618 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
@@ -18,7 +18,6 @@ package org.apache.logging.log4j.core.impl;
 
 import org.apache.logging.log4j.ThreadContextAccess;
 import org.apache.logging.log4j.core.LogEvent;
-import org.apache.logging.log4j.spi.AbstractGarbageFreeMutableThreadContext;
 import org.apache.logging.log4j.spi.ContextData;
 import org.apache.logging.log4j.spi.CopyOnWrite;
 import org.apache.logging.log4j.spi.MutableContextDataSupplier;


[40/50] logging-log4j2 git commit: LOG4J2-1349 updated javadoc related to freeze()

Posted by rp...@apache.org.
LOG4J2-1349 updated javadoc related to freeze()


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/191c3f95
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/191c3f95
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/191c3f95

Branch: refs/heads/master
Commit: 191c3f958bafc59b70757dbd0120a1da32e53120
Parents: d1ab367
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 16:30:54 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 16:30:54 2016 +0900

----------------------------------------------------------------------
 .../java/org/apache/logging/log4j/spi/MutableContextData.java | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/191c3f95/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
index 14de7ca..96251ef 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
@@ -32,6 +32,7 @@ public interface MutableContextData extends ContextData {
      * @throws java.util.ConcurrentModificationException some implementations may not support structural modifications
      *          to this context data while iterating over the contents with {@link #forEach(BiConsumer)} or
      *          {@link #forEach(TriConsumer, Object)}.
+     * @throws UnsupportedOperationException if this collection has been {@linkplain #isFrozen() frozen}.
      */
     void clear();
 
@@ -43,6 +44,7 @@ public interface MutableContextData extends ContextData {
      * @throws java.util.ConcurrentModificationException some implementations may not support structural modifications
      *          to this context data while iterating over the contents with {@link #forEach(BiConsumer)} or
      *          {@link #forEach(TriConsumer, Object)}.
+     * @throws UnsupportedOperationException if this collection has been {@linkplain #isFrozen() frozen}.
      */
     void putValue(final String key, final Object value);
 
@@ -52,6 +54,7 @@ public interface MutableContextData extends ContextData {
      * @throws java.util.ConcurrentModificationException some implementations may not support structural modifications
      *          to this context data while iterating over the contents with {@link #forEach(BiConsumer)} or
      *          {@link #forEach(TriConsumer, Object)}.
+     * @throws UnsupportedOperationException if this collection has been {@linkplain #isFrozen() frozen}.
      */
     void putAll(final ContextData source);
 
@@ -62,11 +65,13 @@ public interface MutableContextData extends ContextData {
      * @throws java.util.ConcurrentModificationException some implementations may not support structural modifications
      *          to this context data while iterating over the contents with {@link #forEach(BiConsumer)} or
      *          {@link #forEach(TriConsumer, Object)}.
+     * @throws UnsupportedOperationException if this collection has been {@linkplain #isFrozen() frozen}.
      */
     void remove(final String key);
 
     /**
-     * Ensures that further changes to this object are ignored.
+     * Makes this collection immutable. Attempts to modify the collection after the {@code freeze()} method was called
+     * will result in an {@code UnsupportedOperationException} being thrown.
      */
     void freeze();
 


[09/50] logging-log4j2 git commit: Merge remote-tracking branch 'remotes/origin/master' into LOG4J2-1010&LOG4J2-1447-injectable-contextdata&better-datastructure

Posted by rp...@apache.org.
Merge remote-tracking branch 'remotes/origin/master' into LOG4J2-1010&LOG4J2-1447-injectable-contextdata&better-datastructure


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/d3d3069a
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/d3d3069a
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/d3d3069a

Branch: refs/heads/master
Commit: d3d3069a178e8ef6484d257b7be397fa40429685
Parents: 25148ca 2c0b7db
Author: rpopma <rp...@apache.org>
Authored: Tue Aug 30 23:44:10 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Tue Aug 30 23:44:10 2016 +0900

----------------------------------------------------------------------
 log4j-1.2-api/pom.xml                           |   4 -
 .../apache/log4j/layout/Log4j1XmlLayout.java    |   4 +-
 .../pattern/Log4j1NdcPatternConverter.java      |   4 +-
 .../org/apache/logging/log4j/util/Strings.java  |  63 +++++++++
 log4j-core/pom.xml                              |  10 ++
 .../core/appender/routing/IdlePurgePolicy.java  |  57 +++++---
 .../core/appender/routing/RoutingAppender.java  |  35 ++---
 .../builder/api/ConfigurationBuilder.java       |  16 +++
 .../impl/DefaultConfigurationBuilder.java       | 129 +++++++++++++++++++
 .../log4j/core/layout/AbstractCsvLayout.java    |  10 +-
 .../apache/logging/log4j/core/DeadlockTest.java |   2 +-
 .../logging/log4j/core/LoggerUpdateTest.java    |   2 +-
 .../CsvJsonParameterLayoutFileAppenderTest.java | 117 +++++++++++++++++
 .../appender/JsonCompleteFileAppenderTest.java  |   2 +-
 .../appender/RandomAccessFileAppenderTests.java |   2 +-
 .../db/jdbc/AbstractJdbcAppenderTest.java       |  12 +-
 .../db/jpa/AbstractJpaAppenderTest.java         |  12 +-
 .../core/appender/db/jpa/JpaH2AppenderTest.java |  28 ++--
 .../db/jpa/JpaHyperSqlAppenderTest.java         |  28 ++--
 .../RollingAppenderCronOnceADayTest.java        |   4 +-
 .../rolling/RollingAppenderCronTest.java        |   2 +-
 .../routing/PropertiesRoutingAppenderTest.java  |   2 +-
 .../appender/routing/RoutingAppenderTest.java   |   2 +-
 .../routing/RoutingAppenderWithPurgingTest.java |  21 ++-
 .../routing/RoutingDefaultAppenderTest.java     |   2 +-
 .../log4j/core/config/ConfigurationTest.java    |   2 +-
 .../core/config/CustomConfigurationTest.java    |   2 +-
 .../core/config/MissingRootLoggerTest.java      |   2 +-
 .../logging/log4j/core/config/XIncludeTest.java |   2 +-
 .../builder/ConfigurationBuilderTest.java       |  91 +++++++++++++
 .../core/util/ShutdownCallbackRegistryTest.java |   2 +-
 .../logging/log4j/junit/LoggerContextRule.java  |  22 ++--
 .../test/resources/log4j-cvs-json-parameter.xml |  32 +++++
 log4j-samples/scala-api/.gitignore              |   3 +
 pom.xml                                         |  12 ++
 src/changes/changes.xml                         |  19 ++-
 36 files changed, 629 insertions(+), 130 deletions(-)
----------------------------------------------------------------------



[16/50] logging-log4j2 git commit: LOG4J2-1349 simplified: collapsed abstract with concrete thread context map classes

Posted by rp...@apache.org.
LOG4J2-1349 simplified: collapsed abstract with concrete thread context map classes


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/8250cc22
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/8250cc22
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/8250cc22

Branch: refs/heads/master
Commit: 8250cc22b60700e227349b90ea78727375dcf55b
Parents: 4b16686
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 22:01:09 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 22:01:09 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java  | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/8250cc22/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
index 5b4a938..7d94831 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
@@ -30,7 +30,7 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  * </p>
  * @since 2.7
  */
-public abstract class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
+public class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
         MutableContextDataSupplier {
 
     /**


[06/50] logging-log4j2 git commit: LOG4J2-1349: merged branch LOG4J2-1010&LOG4J2-1447 into branch LOG4J2-1349

Posted by rp...@apache.org.
LOG4J2-1349: merged branch LOG4J2-1010&LOG4J2-1447 into branch LOG4J2-1349


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7994789d
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7994789d
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7994789d

Branch: refs/heads/master
Commit: 7994789d2d2cf85dcbb6518d36693d18082961f1
Parents: 5edcfe8 25148ca
Author: rpopma <rp...@apache.org>
Authored: Mon Aug 29 00:11:12 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Mon Aug 29 00:11:12 2016 +0900

----------------------------------------------------------------------
 log4j-api-scala_2.10/.gitignore                 |   3 +
 log4j-api-scala_2.10/pom.xml                    | 150 +++++
 .../org/apache/logging/log4j/scala/Logger.scala | 592 +++++++++++++++++++
 .../logging/log4j/scala/LoggerMacro.scala       | 425 +++++++++++++
 .../apache/logging/log4j/scala/Logging.scala    |  30 +
 .../apache/logging/log4j/scala/LoggerTest.scala | 550 +++++++++++++++++
 log4j-api-scala_2.11/.gitignore                 |   3 +
 log4j-api-scala_2.11/pom.xml                    | 150 +++++
 .../org/apache/logging/log4j/scala/Logger.scala | 592 +++++++++++++++++++
 .../logging/log4j/scala/LoggerMacro.scala       | 425 +++++++++++++
 .../apache/logging/log4j/scala/Logging.scala    |  30 +
 .../apache/logging/log4j/scala/LoggerTest.scala | 550 +++++++++++++++++
 log4j-bom/pom.xml                               |  12 +
 .../core/filter/DynamicThresholdFilter.java     |   8 +-
 .../core/filter/ThreadContextMapFilter.java     |   8 +-
 .../log4j/core/impl/ContextDataInjector.java    |  28 +-
 .../core/impl/ContextDataInjectorFactory.java   |   6 +
 .../core/impl/ThreadContextDataInjector.java    |  22 +
 .../log4j/core/jackson/Initializers.java        |  10 +-
 .../log4j/core/jackson/Log4jJsonModule.java     |   9 +-
 .../core/jackson/Log4jJsonObjectMapper.java     |   6 +-
 .../log4j/core/jackson/Log4jXmlModule.java      |   6 +-
 .../core/jackson/Log4jXmlObjectMapper.java      |   9 +-
 .../log4j/core/jackson/Log4jYamlModule.java     |   9 +-
 .../core/jackson/Log4jYamlObjectMapper.java     |   6 +-
 .../ThrowableProxyWithoutStacktraceMixIn.java   |  77 +++
 .../log4j/core/layout/JacksonFactory.java       |  22 +-
 .../logging/log4j/core/layout/JsonLayout.java   |  14 +-
 .../logging/log4j/core/layout/XmlLayout.java    |  15 +-
 .../logging/log4j/core/layout/YamlLayout.java   |  13 +-
 .../log4j/core/lookup/ContextMapLookup.java     |   8 +-
 .../server/JsonInputStreamLogEventBridge.java   |   2 +-
 .../logging/log4j/MarkerMixInXmlTest.java       |   2 +-
 .../log4j/core/jackson/LevelMixInJsonTest.java  |   2 +-
 .../jackson/StackTraceElementMixInTest.java     |   2 +-
 .../log4j/core/layout/JsonLayoutTest.java       |  59 +-
 .../log4j/core/layout/LogEventFixtures.java     |   6 +-
 .../log4j/core/layout/XmlLayoutTest.java        |  59 +-
 .../log4j/core/layout/YamlLayoutTest.java       |  55 +-
 .../net/server/AbstractSocketServerTest.java    |   4 +-
 log4j-samples/pom.xml                           |   1 +
 log4j-samples/scala-api/pom.xml                 |  65 ++
 .../scala-api/src/main/resources/log4j2.xml     |  32 +
 .../logging/log4j/scalasample/LoggingApp.scala  |  31 +
 pom.xml                                         |  12 +
 src/changes/changes.xml                         |   6 +
 src/site/site.xml                               |   1 +
 src/site/xdoc/manual/layouts.xml.vm             |  15 +
 src/site/xdoc/manual/scala-api.xml              |  91 +++
 src/site/xdoc/maven-artifacts.xml.vm            |  28 +
 src/site/xdoc/runtime-dependencies.xml          |   7 +
 51 files changed, 4140 insertions(+), 128 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7994789d/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7994789d/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7994789d/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
----------------------------------------------------------------------
diff --cc log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
index 30d099e,7fe4c53..e26616d
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
@@@ -18,9 -18,8 +18,10 @@@ package org.apache.logging.log4j.core.i
  
  import java.util.List;
  
+ import org.apache.logging.log4j.core.ContextData;
  import org.apache.logging.log4j.core.config.Property;
 +import org.apache.logging.log4j.spi.ContextData;
 +import org.apache.logging.log4j.spi.MutableContextData;
  
  /**
   * Responsible for initializing the ContextData of LogEvents. Context data is data that is set by the application to be
@@@ -30,12 -29,17 +31,17 @@@
   * </p><p>
   * In some asynchronous models, work may be delegated to several threads, while conceptually this work shares the same
   * context. In such models, storing context data in {@code ThreadLocal} variables is not convenient or desirable.
-  * By specifying a custom {@code ContextDataInjectorFactory}, users can initialize log events with context data from
-  * any arbitrary context.
+  * Users can configure the {@code ContextDataInjectorFactory} to provide custom {@code ContextDataInjector} objects,
+  * in order to initialize log events with context data from any arbitrary context.
+  * </p><p>
+  * When providing a custom {@code ContextDataInjector}, be aware that the {@code ContextDataFactory} may be invoked
+  * multiple times by the various components in Log4j that need access to context data.
+  * This includes the object(s) that populate log events, but also various lookups and filters that look at
+  * context data to determine whether an event should be logged.
   * </p>
   *
 + * @see ContextData
   * @see ContextDataInjectorFactory
 - * @see org.apache.logging.log4j.core.ContextData
   * @see org.apache.logging.log4j.ThreadContext
   * @see ThreadContextDataInjector
   * @since 2.7

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7994789d/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjectorFactory.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7994789d/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
----------------------------------------------------------------------
diff --cc log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
index eeaaf4c,1e81f1d..0e31a9a
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
@@@ -106,11 -111,19 +114,18 @@@ public class ThreadContextDataInjecto
              // modified.
              copyProperties(props, reusable);
  
 -            // TODO LOG4J2-1349
 -//            final MutableContextData immutableCopy = ((AbstractGarbageFreeMutableThreadContext)
 -//                    ThreadContext.getThreadContextMap()).getContextData();
 -//            reusable.putAll(immutableCopy);
 +            final ContextData immutableCopy = ((MutableContextDataSupplier) ThreadContextAccess.getThreadContextMap())
 +                    .getMutableContextData();
 +            reusable.putAll(immutableCopy);
              return reusable;
          }
+ 
+         @Override
+         public ContextData rawContextData() {
+             // TODO LOG4J2-1349
+             //return ((AbstractGarbageFreeMutableThreadContext) ThreadContext.getThreadContextMap()).getContextData();
+             return null;
+         }
      }
  
      /**
@@@ -133,19 -146,28 +148,26 @@@
           */
          @Override
          public MutableContextData injectContextData(final List<Property> props, final MutableContextData reusable) {
 -            // TODO LOG4J2-1349
 -
 -//            // If there are no configuration properties we want to just return the ThreadContext's MutableContextData:
 -//            // it is a copy-on-write data structure so we are sure ThreadContext changes will not affect our copy.
 -//            final MutableContextData immutableCopy = ((AbstractCopyOnWriteMutableThreadContext)
 -//                    ThreadContext.getThreadContextMap()).getContextData();
 -//            if (props == null || props.isEmpty()) {
 -//                return immutableCopy;
 -//            }
 -//            // However, if the list of Properties is non-empty we need to combine the properties and the ThreadContext
 -//            // data. In that case we will copy the key-value pairs into the specified reusable MutableContextData.
 -//            copyProperties(props, reusable);
 -//            reusable.putAll(immutableCopy);
 +            // If there are no configuration properties we want to just return the ThreadContext's MutableContextData:
 +            // it is a copy-on-write data structure so we are sure ThreadContext changes will not affect our copy.
 +            final MutableContextData immutableCopy =
 +                    ((MutableContextDataSupplier) ThreadContextAccess.getThreadContextMap()).getMutableContextData();
 +            if (props == null || props.isEmpty()) {
 +                return immutableCopy;
 +            }
 +            // However, if the list of Properties is non-empty we need to combine the properties and the ThreadContext
 +            // data. In that case we will copy the key-value pairs into the specified reusable MutableContextData.
 +            copyProperties(props, reusable);
 +            reusable.putAll(immutableCopy);
              return reusable;
          }
+ 
+         @Override
+         public ContextData rawContextData() {
+             // TODO LOG4J2-1349
+             //return ((AbstractCopyOnWriteMutableThreadContext) ThreadContext.getThreadContextMap()).getContextData();
+             return null;
+         }
      }
  
      /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7994789d/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
----------------------------------------------------------------------
diff --cc log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
index eec5ad3,bfbc5ea..6bffb2b
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
@@@ -17,13 -17,11 +17,12 @@@
  package org.apache.logging.log4j.core.lookup;
  
  import org.apache.logging.log4j.ThreadContext;
 -import org.apache.logging.log4j.core.ContextData;
  import org.apache.logging.log4j.core.LogEvent;
  import org.apache.logging.log4j.core.config.plugins.Plugin;
- import org.apache.logging.log4j.core.impl.ContextDataFactory;
  import org.apache.logging.log4j.core.impl.ContextDataInjector;
  import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
 +import org.apache.logging.log4j.spi.ContextData;
 +import org.apache.logging.log4j.spi.MutableContextData;
  
  /**
   * Looks up keys from the context. By default this is the {@link ThreadContext}, but users may


[44/50] logging-log4j2 git commit: LOG4J2-1349 add info to test output

Posted by rp...@apache.org.
LOG4J2-1349 add info to test output


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/523df26c
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/523df26c
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/523df26c

Branch: refs/heads/master
Commit: 523df26c15f75655f73c7bf39a3fdff38c23352e
Parents: 822f106
Author: rpopma <rp...@apache.org>
Authored: Thu Sep 8 23:50:21 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Sep 8 23:50:21 2016 +0900

----------------------------------------------------------------------
 .../async/AsyncLoggerAllThreadContextImplementationsTest.java     | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/523df26c/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
index 58b9bec..2bbee67 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
@@ -164,7 +164,8 @@ public class AsyncLoggerAllThreadContextImplementationsTest {
     }
 
     private void checkResult(final File file) throws IOException {
-        final String contextDesc = contextImpl + " " + contextImpl.implClassSimpleName();
+        final String contextDesc = contextImpl + " " + contextImpl.implClassSimpleName() + " "
+                + LogManager.getContext(false).getClass().getSimpleName();
         try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
             String expect = null;
             for (int i = 0; i < LINE_COUNT; i++) {


[28/50] logging-log4j2 git commit: LOG4J2-1349 added test

Posted by rp...@apache.org.
LOG4J2-1349 added test


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/1dbe39e0
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/1dbe39e0
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/1dbe39e0

Branch: refs/heads/master
Commit: 1dbe39e0aa3dc0a29b8efc0f21c3cc82f85dd19c
Parents: f2818eb
Author: rpopma <rp...@apache.org>
Authored: Fri Sep 2 23:25:12 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Sep 2 23:25:12 2016 +0900

----------------------------------------------------------------------
 .../apache/logging/log4j/core/layout/PatternLayoutTest.java | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1dbe39e0/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
index 185432e..aab5896 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/layout/PatternLayoutTest.java
@@ -75,7 +75,7 @@ public class PatternLayoutTest {
     Logger root = ctx.getRootLogger();
 
     @Rule
-    public final ThreadContextRule threadContextRule = new ThreadContextRule(); 
+    public final ThreadContextRule threadContextRule = new ThreadContextRule();
 
     private static class Destination implements ByteBufferDestination {
         ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[2048]);
@@ -203,6 +203,11 @@ public class PatternLayoutTest {
     }
 
     @Test
+    public void testMdcPattern0() throws Exception {
+        testMdcPattern("%m : %X", "Hello : {key1=value1, key2=value2}", true);
+    }
+
+    @Test
     public void testMdcPattern1() throws Exception {
         testMdcPattern("%m : %X", "Hello : {}", false);
     }
@@ -241,7 +246,7 @@ public class PatternLayoutTest {
                 .setIncludeLocation(true)
                 .setMessage(new SimpleMessage("entry")).build();
         final String result1 = new FauxLogger().formatEvent(event1, layout);
-        final String expectSuffix1 = String.format("====== PatternLayoutTest.testPatternSelector:243 entry ======%n");
+        final String expectSuffix1 = String.format("====== PatternLayoutTest.testPatternSelector:248 entry ======%n");
         assertTrue("Unexpected result: " + result1, result1.endsWith(expectSuffix1));
         final LogEvent event2 = Log4jLogEvent.newBuilder() //
                 .setLoggerName(this.getClass().getName()).setLoggerFqcn("org.apache.logging.log4j.core.Logger") //


[05/50] logging-log4j2 git commit: LOG4J2-1010 implement the new ContextDataInjector::rawContextData() method as good as we can.

Posted by rp...@apache.org.
LOG4J2-1010 implement the new ContextDataInjector::rawContextData() method as good as we can.

Note: at this stage the rawContextData() method implementation does not perform better than the inject method.
In LOG4J2-1349 we move the ContextData interface to the log4j-api module and we introduce ContextData-based implementations of the ThreadContextMap interface. Here we can provide a much more efficiently performing implementation.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/25148ca3
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/25148ca3
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/25148ca3

Branch: refs/heads/master
Commit: 25148ca31ea2ba8f96f03bc36eb3963b802db46b
Parents: 16eca7f
Author: rpopma <rp...@apache.org>
Authored: Mon Aug 29 00:04:03 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Mon Aug 29 00:04:03 2016 +0900

----------------------------------------------------------------------
 .../core/impl/ThreadContextDataInjector.java    | 22 ++++++++++++++++++++
 1 file changed, 22 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/25148ca3/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
index af534fb..1e81f1d 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
@@ -66,6 +66,14 @@ public class ThreadContextDataInjector  {
             return reusable;
         }
 
+        @Override
+        public ContextData rawContextData() {
+            // TODO LOG4J2-1349: DefaultThreadContextMap itself implements the ContextData interface
+            final MutableContextData result = ContextDataFactory.createContextData();
+            copyThreadContextMap(ThreadContext.getImmutableContext(), result);
+            return result;
+        }
+
         /**
          * Copies key-value pairs from the specified map into the specified {@code MutableContextData}.
          *
@@ -109,6 +117,13 @@ public class ThreadContextDataInjector  {
 //            reusable.putAll(immutableCopy);
             return reusable;
         }
+
+        @Override
+        public ContextData rawContextData() {
+            // TODO LOG4J2-1349
+            //return ((AbstractGarbageFreeMutableThreadContext) ThreadContext.getThreadContextMap()).getContextData();
+            return null;
+        }
     }
 
     /**
@@ -146,6 +161,13 @@ public class ThreadContextDataInjector  {
 //            reusable.putAll(immutableCopy);
             return reusable;
         }
+
+        @Override
+        public ContextData rawContextData() {
+            // TODO LOG4J2-1349
+            //return ((AbstractCopyOnWriteMutableThreadContext) ThreadContext.getThreadContextMap()).getContextData();
+            return null;
+        }
     }
 
     /**


[33/50] logging-log4j2 git commit: LOG4J2-1349 add ability to freeze() context data for use in copy-on-write scenarios

Posted by rp...@apache.org.
LOG4J2-1349 add ability to freeze() context data for use in copy-on-write scenarios


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/945bfe04
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/945bfe04
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/945bfe04

Branch: refs/heads/master
Commit: 945bfe041caa7b645c7f838234b1331a2ab96609
Parents: 7aac69c
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 15:53:17 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 15:53:17 2016 +0900

----------------------------------------------------------------------
 .../org/apache/logging/log4j/spi/MutableContextData.java | 11 +++++++++++
 1 file changed, 11 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/945bfe04/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
index 8bc64e8..1ee60c9 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/MutableContextData.java
@@ -65,4 +65,15 @@ public interface MutableContextData extends ContextData {
      *          {@link #forEach(TriConsumer, Object)}.
      */
     void remove(final String key);
+
+    /**
+     * Ensures that further changes to this object are ignored.
+     */
+    void freeze();
+
+    /**
+     * Returns {@code true} if this object has been {@linkplain #freeze() frozen}, {@code false} otherwise.
+     * @return  {@code true} if this object has been {@linkplain #freeze() frozen}, {@code false} otherwise
+     */
+    boolean isFrozen();
 }
\ No newline at end of file


[24/50] logging-log4j2 git commit: LOG4J2-1349 (work in progress) update tests to prove garbage-free context map does not allocate

Posted by rp...@apache.org.
LOG4J2-1349 (work in progress) update tests to prove garbage-free context map does not allocate


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/1e4f0ffb
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/1e4f0ffb
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/1e4f0ffb

Branch: refs/heads/master
Commit: 1e4f0ffbe9ac4611ea11b0c23f0b2d0918760a3e
Parents: 22ef566
Author: rpopma <rp...@apache.org>
Authored: Thu Sep 1 01:26:54 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Sep 1 01:26:54 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/core/GcFreeAsynchronousLoggingTest.java    | 2 ++
 .../org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java | 8 ++++++--
 .../logging/log4j/core/GcFreeMixedSyncAyncLoggingTest.java   | 1 +
 .../logging/log4j/core/GcFreeSynchronousLoggingTest.java     | 1 +
 log4j-core/src/test/resources/gcFreeLogging.xml              | 2 +-
 .../src/test/resources/gcFreeMixedSyncAsyncLogging.xml       | 2 +-
 6 files changed, 12 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e4f0ffb/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeAsynchronousLoggingTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeAsynchronousLoggingTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeAsynchronousLoggingTest.java
index 0e22b3e..188605a 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeAsynchronousLoggingTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeAsynchronousLoggingTest.java
@@ -35,6 +35,8 @@ public class GcFreeAsynchronousLoggingTest {
      * This code runs in a separate process, instrumented with the Google Allocation Instrumenter.
      */
     public static void main(final String[] args) throws Exception {
+        System.setProperty("log4j2.garbagefree.threadContextMap", "true");
+        System.setProperty("AsyncLogger.RingBufferSize", "128"); // minimum ringbuffer size
         System.setProperty("Log4jContextSelector", AsyncLoggerContextSelector.class.getName());
         GcFreeLoggingTestUtil.executeLogging("gcFreeLogging.xml", GcFreeAsynchronousLoggingTest.class);
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e4f0ffb/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java
index 1394b9f..9cf4164 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeLoggingTestUtil.java
@@ -53,12 +53,16 @@ public class GcFreeLoggingTestUtil {
 
         // initialize LoggerContext etc.
         // This is not steady-state logging and will allocate objects.
+
+        ThreadContext.put("aKey", "value1");
+        ThreadContext.put("key2", "value2");
+
         final org.apache.logging.log4j.Logger logger = LogManager.getLogger(testClass.getName());
         logger.debug("debug not set");
         logger.fatal("This message is logged to the console");
         logger.error("Sample error message");
         logger.error("Test parameterized message {}", "param");
-        for (int i = 0; i < 128; i++) {
+        for (int i = 0; i < 256; i++) {
             logger.debug("ensure all ringbuffer slots have been used once"); // allocate MutableLogEvent.messageText
         }
 
@@ -128,7 +132,7 @@ public class GcFreeLoggingTestUtil {
         final String text = new String(Files.readAllBytes(tempFile.toPath()));
         final List<String> lines = Files.readAllLines(tempFile.toPath(), Charset.defaultCharset());
         final String className = cls.getSimpleName();
-        assertEquals(text, "FATAL o.a.l.l.c." + className + " [main]  This message is logged to the console",
+        assertEquals(text, "FATAL o.a.l.l.c." + className + " [main] value1 {aKey=value1, key2=value2} This message is logged to the console",
                 lines.get(0));
 
         final String LINESEP = System.getProperty("line.separator");

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e4f0ffb/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeMixedSyncAyncLoggingTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeMixedSyncAyncLoggingTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeMixedSyncAyncLoggingTest.java
index 8ed4d1b..93ddc2c 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeMixedSyncAyncLoggingTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeMixedSyncAyncLoggingTest.java
@@ -34,6 +34,7 @@ public class GcFreeMixedSyncAyncLoggingTest {
      * This code runs in a separate process, instrumented with the Google Allocation Instrumenter.
      */
     public static void main(final String[] args) throws Exception {
+        System.setProperty("log4j2.garbagefree.threadContextMap", "true");
         System.setProperty("AsyncLoggerConfig.RingBufferSize", "128"); // minimum ringbuffer size
         GcFreeLoggingTestUtil.executeLogging("gcFreeMixedSyncAsyncLogging.xml", GcFreeMixedSyncAyncLoggingTest.class);
     }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e4f0ffb/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeSynchronousLoggingTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeSynchronousLoggingTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeSynchronousLoggingTest.java
index 2d0ecc6..8ab6e8b 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeSynchronousLoggingTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/GcFreeSynchronousLoggingTest.java
@@ -34,6 +34,7 @@ public class GcFreeSynchronousLoggingTest {
      * This code runs in a separate process, instrumented with the Google Allocation Instrumenter.
      */
     public static void main(final String[] args) throws Exception {
+        System.setProperty("log4j2.garbagefree.threadContextMap", "true");
         GcFreeLoggingTestUtil.executeLogging("gcFreeLogging.xml", GcFreeSynchronousLoggingTest.class);
     }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e4f0ffb/log4j-core/src/test/resources/gcFreeLogging.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/gcFreeLogging.xml b/log4j-core/src/test/resources/gcFreeLogging.xml
index d4b597f..81a8055 100644
--- a/log4j-core/src/test/resources/gcFreeLogging.xml
+++ b/log4j-core/src/test/resources/gcFreeLogging.xml
@@ -2,7 +2,7 @@
 <Configuration status="OFF">
   <Appenders>
     <Console name="Console" target="SYSTEM_OUT">
-      <PatternLayout pattern="%p %c{1.} [%t] %X{aKey} %m%ex%n" />
+      <PatternLayout pattern="%p %c{1.} [%t] %X{aKey} %X %m%ex%n" />
     </Console>
     <File name="File" fileName="target/gcfreefile.log" bufferedIO="false">
       <PatternLayout>

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1e4f0ffb/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml b/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
index f1937be..714ea9f 100644
--- a/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
+++ b/log4j-core/src/test/resources/gcFreeMixedSyncAsyncLogging.xml
@@ -2,7 +2,7 @@
 <Configuration status="OFF">
   <Appenders>
     <Console name="Console" target="SYSTEM_OUT">
-      <PatternLayout pattern="%p %c{1.} [%t] %X{aKey} %m%ex%n" />
+      <PatternLayout pattern="%p %c{1.} [%t] %X{aKey} %X %m%ex%n" />
     </Console>
     <File name="File" fileName="target/gcfreefileMixed.log" bufferedIO="false">
       <PatternLayout>


[46/50] logging-log4j2 git commit: LOG4J2-1349 fixed test and extended for AsyncLoggerConfig

Posted by rp...@apache.org.
LOG4J2-1349 fixed test and extended for AsyncLoggerConfig


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/25615a46
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/25615a46
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/25615a46

Branch: refs/heads/master
Commit: 25615a468d0c267e20d21721f7f71a4874a12ee9
Parents: 4671420
Author: rpopma <rp...@apache.org>
Authored: Fri Sep 9 22:06:15 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Sep 9 22:06:15 2016 +0900

----------------------------------------------------------------------
 ...ggerAllThreadContextImplementationsTest.java |  34 ++--
 ...nfigAllThreadContextImplementationsTest.java | 158 +++++++++++++++++++
 2 files changed, 177 insertions(+), 15 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/25615a46/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
index 2bbee67..6cd89f4 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerAllThreadContextImplementationsTest.java
@@ -30,8 +30,10 @@ import org.apache.logging.log4j.ThreadContextAccess;
 import org.apache.logging.log4j.ThreadContextTestAccess;
 import org.apache.logging.log4j.core.CoreLoggerContexts;
 import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
 import org.apache.logging.log4j.core.util.Constants;
 import org.apache.logging.log4j.spi.DefaultThreadContextMap;
+import org.apache.logging.log4j.spi.LoggerContext;
 import org.apache.logging.log4j.util.Unbox;
 import org.junit.AfterClass;
 import org.junit.BeforeClass;
@@ -66,10 +68,10 @@ public class AsyncLoggerAllThreadContextImplementationsTest {
     }
 
     static enum Mode {
-        ALL_ASYNC, MIXED, BOTH;
+        ALL_ASYNC, MIXED, BOTH_ALL_ASYNC_AND_MIXED;
 
         void initSelector() {
-            if (this == ALL_ASYNC || this == BOTH) {
+            if (this == ALL_ASYNC || this == BOTH_ALL_ASYNC_AND_MIXED) {
                 System.setProperty(Constants.LOG4J_CONTEXT_SELECTOR,  AsyncLoggerContextSelector.class.getName());
             } else {
                 System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
@@ -110,14 +112,11 @@ public class AsyncLoggerAllThreadContextImplementationsTest {
     public static Collection<Object[]> data() {
         return Arrays.asList(new Object[][] {
                 { ContextImpl.WEBAPP, Mode.ALL_ASYNC},
-                { ContextImpl.WEBAPP, Mode.MIXED },
-                { ContextImpl.WEBAPP, Mode.BOTH },
+                { ContextImpl.WEBAPP, Mode.BOTH_ALL_ASYNC_AND_MIXED},
                 { ContextImpl.GARBAGE_FREE, Mode.ALL_ASYNC},
-                { ContextImpl.GARBAGE_FREE, Mode.MIXED},
-                { ContextImpl.GARBAGE_FREE, Mode.BOTH},
+                { ContextImpl.GARBAGE_FREE, Mode.BOTH_ALL_ASYNC_AND_MIXED},
                 { ContextImpl.COPY_ON_WRITE, Mode.ALL_ASYNC},
-                { ContextImpl.COPY_ON_WRITE, Mode.MIXED},
-                { ContextImpl.COPY_ON_WRITE, Mode.BOTH}
+                { ContextImpl.COPY_ON_WRITE, Mode.BOTH_ALL_ASYNC_AND_MIXED}
         });
     }
 
@@ -144,28 +143,33 @@ public class AsyncLoggerAllThreadContextImplementationsTest {
         ThreadContext.put("KEY", "mapvalue");
 
         final Logger log = LogManager.getLogger("com.foo.Bar");
+        final LoggerContext loggerContext = LogManager.getContext(false);
+        final String loggerContextName = loggerContext.getClass().getSimpleName();
+        final RingBufferAdmin ring = ((AsyncLoggerContext) loggerContext).createRingBufferAdmin();
         for (int i = 0; i < LINE_COUNT; i++) {
+            while (i >= 128 && ring.getRemainingCapacity() == 0) { // buffer may be full
+                Thread.sleep(1);
+            }
             if ((i & 1) == 1) {
                 ThreadContext.put("count", String.valueOf(i));
             } else {
                 ThreadContext.remove("count");
             }
             final String contextmap = ThreadContextAccess.getThreadContextMap().getClass().getSimpleName();
-            log.info("{} {} i={}", contextImpl, contextmap, Unbox.box(i));
+            log.info("{} {} {} i={}", contextImpl, contextmap, loggerContextName, Unbox.box(i));
         }
         ThreadContext.pop();
         CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
 
-        checkResult(file);
-        if (asyncMode == Mode.MIXED || asyncMode == Mode.BOTH) {
-            checkResult(sync);
+        checkResult(file, loggerContextName);
+        if (asyncMode == Mode.MIXED || asyncMode == Mode.BOTH_ALL_ASYNC_AND_MIXED) {
+            checkResult(sync, loggerContextName);
         }
         LogManager.shutdown();
     }
 
-    private void checkResult(final File file) throws IOException {
-        final String contextDesc = contextImpl + " " + contextImpl.implClassSimpleName() + " "
-                + LogManager.getContext(false).getClass().getSimpleName();
+    private void checkResult(final File file, final String loggerContextName) throws IOException {
+        final String contextDesc = contextImpl + " " + contextImpl.implClassSimpleName() + " " + loggerContextName;
         try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
             String expect = null;
             for (int i = 0; i < LINE_COUNT; i++) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/25615a46/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
new file mode 100644
index 0000000..74de230
--- /dev/null
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/async/AsyncLoggerConfigAllThreadContextImplementationsTest.java
@@ -0,0 +1,158 @@
+/*
+ * 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.async;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileReader;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collection;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.ThreadContext;
+import org.apache.logging.log4j.ThreadContextAccess;
+import org.apache.logging.log4j.ThreadContextTestAccess;
+import org.apache.logging.log4j.core.CoreLoggerContexts;
+import org.apache.logging.log4j.core.config.ConfigurationFactory;
+import org.apache.logging.log4j.core.jmx.RingBufferAdmin;
+import org.apache.logging.log4j.core.util.Constants;
+import org.apache.logging.log4j.spi.DefaultThreadContextMap;
+import org.apache.logging.log4j.spi.LoggerContext;
+import org.apache.logging.log4j.util.Unbox;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.Parameterized;
+
+import static org.junit.Assert.*;
+
+@RunWith(Parameterized.class)
+public class AsyncLoggerConfigAllThreadContextImplementationsTest {
+
+    final static int LINE_COUNT = 130;
+    private ContextImpl contextImpl;
+
+    @BeforeClass
+    public static void beforeClass() {
+        System.setProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY, "AsyncLoggerConfigThreadContextTest.xml");
+        System.setProperty("AsyncLoggerConfig.RingBufferSize", "128"); // minimum ringbuffer size
+    }
+
+    @AfterClass
+    public static void afterClass() {
+        System.clearProperty("AsyncLogger.RingBufferSize");
+        System.clearProperty("AsyncLoggerConfig.RingBufferSize");
+        System.clearProperty(Constants.LOG4J_CONTEXT_SELECTOR);
+        System.clearProperty(ConfigurationFactory.CONFIGURATION_FILE_PROPERTY);
+        System.clearProperty("log4j2.garbagefree.threadContextMap");
+        System.clearProperty("log4j2.is.webapp");
+        System.clearProperty("log4j2.threadContextMap");
+    }
+
+    static enum ContextImpl {
+        WEBAPP, GARBAGE_FREE, COPY_ON_WRITE;
+
+        void init() {
+            System.clearProperty("log4j2.threadContextMap");
+            final String PACKAGE = "org.apache.logging.log4j.spi.";
+            System.setProperty("log4j2.threadContextMap", PACKAGE + implClassSimpleName());
+            ThreadContextTestAccess.init();
+        }
+
+        public String implClassSimpleName() {
+            switch (this) {
+                case WEBAPP:
+                    return DefaultThreadContextMap.class.getSimpleName();
+                case GARBAGE_FREE:
+                    return "GarbageFreeSortedArrayThreadContextMap";
+                case COPY_ON_WRITE:
+                    return "CopyOnWriteSortedArrayThreadContextMap";
+            }
+            throw new IllegalStateException("Unknown state " + this);
+        }
+    }
+
+    @Parameterized.Parameters
+    public static Collection<Object[]> data() {
+        return Arrays.asList(new Object[][] {
+                { ContextImpl.WEBAPP, },
+                { ContextImpl.GARBAGE_FREE, },
+                { ContextImpl.COPY_ON_WRITE, }
+        });
+    }
+
+    public AsyncLoggerConfigAllThreadContextImplementationsTest(ContextImpl contextImpl) {
+        this.contextImpl = contextImpl;
+        contextImpl.init();
+    }
+
+    @Test
+    public void testAsyncLogWritesToLog() throws Exception {
+        final File file = new File("target", "SynchronousContextTest.log");
+        file.delete();
+
+        ThreadContext.push("stackvalue");
+        ThreadContext.put("KEY", "mapvalue");
+
+        final Logger log = LogManager.getLogger("com.foo.Bar");
+        final LoggerContext loggerContext = LogManager.getContext(false);
+        final String loggerContextName = loggerContext.getClass().getSimpleName();
+        final RingBufferAdmin ring = ((AsyncLoggerConfig) ((org.apache.logging.log4j.core.Logger) log).get())
+                .createRingBufferAdmin("");
+        for (int i = 0; i < LINE_COUNT; i++) {
+            while (i >= 128 && ring.getRemainingCapacity() == 0) { // buffer may be full
+                Thread.sleep(1);
+            }
+            if ((i & 1) == 1) {
+                ThreadContext.put("count", String.valueOf(i));
+            } else {
+                ThreadContext.remove("count");
+            }
+            final String contextmap = ThreadContextAccess.getThreadContextMap().getClass().getSimpleName();
+            log.info("{} {} {} i={}", contextImpl, contextmap, loggerContextName, Unbox.box(i));
+        }
+        ThreadContext.pop();
+        CoreLoggerContexts.stopLoggerContext(false, file); // stop async thread
+
+        checkResult(file, loggerContextName);
+        LogManager.shutdown();
+    }
+
+    private void checkResult(final File file, final String loggerContextName) throws IOException {
+        final String contextDesc = contextImpl + " " + contextImpl.implClassSimpleName() + " " + loggerContextName;
+        try (final BufferedReader reader = new BufferedReader(new FileReader(file))) {
+            String expect = null;
+            for (int i = 0; i < LINE_COUNT; i++) {
+                String line = reader.readLine();
+                if ((i & 1) == 1) {
+                    expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue, count=" + i + "} "
+                            + contextDesc + " i=" + i;
+                } else {
+                    expect = "INFO c.f.Bar mapvalue [stackvalue] {KEY=mapvalue} " + contextDesc + " i=" + i;
+                }
+                assertEquals("line " + i, expect, line);
+            }
+            final String noMoreLines = reader.readLine();
+            assertNull("done", noMoreLines);
+        } finally {
+            file.delete();
+        }
+    }
+}


[08/50] logging-log4j2 git commit: LOG4J2-1349 let DefaultThreadContextMap implement the ContextData interface. This results in a much more efficiently performing implementation of the new ContextDataInjector::rawContextData() method introduced in LOG4J2

Posted by rp...@apache.org.
LOG4J2-1349 let DefaultThreadContextMap implement the ContextData interface. This results in a much more efficiently performing implementation of the new ContextDataInjector::rawContextData() method introduced in LOG4J2-1010.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/def057ff
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/def057ff
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/def057ff

Branch: refs/heads/master
Commit: def057ff0bab9054a80cfee9d7b408c28fe6a4bd
Parents: 1600bb2
Author: rpopma <rp...@apache.org>
Authored: Mon Aug 29 00:32:39 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Mon Aug 29 00:32:39 2016 +0900

----------------------------------------------------------------------
 .../log4j/spi/DefaultThreadContextMap.java      | 44 +++++++++++++++++++-
 1 file changed, 43 insertions(+), 1 deletion(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/def057ff/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
index b659c19..0bd100c 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
@@ -20,7 +20,9 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.logging.log4j.util.BiConsumer;
 import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.TriConsumer;
 
 /**
  * The actual ThreadContext Map. A new ThreadContext Map is created each time it is updated and the Map stored is always
@@ -28,7 +30,7 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  * expected that the Map will be passed to many more log events than the number of keys it contains the performance
  * should be much better than if the Map was copied for each event.
  */
-public class DefaultThreadContextMap implements ThreadContextMap2 {
+public class DefaultThreadContextMap implements ThreadContextMap2, ContextData {
 
     /**
      * Property name ({@value} ) for selecting {@code InheritableThreadLocal} (value "true") or plain
@@ -113,12 +115,46 @@ public class DefaultThreadContextMap implements ThreadContextMap2 {
     }
 
     @Override
+    public Map<String, String> asMap() {
+        return getCopy();
+    }
+
+    @Override
     public boolean containsKey(final String key) {
         final Map<String, String> map = localMap.get();
         return map != null && map.containsKey(key);
     }
 
     @Override
+    public <V> void forEach(final BiConsumer<String, ? super V> action) {
+        final Map<String, String> map = localMap.get();
+        if (map == null) {
+            return;
+        }
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            action.accept(entry.getKey(), (V) entry.getValue());
+        }
+    }
+
+    @Override
+    public <V, S> void forEach(final TriConsumer<String, ? super V, S> action, final S state) {
+        final Map<String, String> map = localMap.get();
+        if (map == null) {
+            return;
+        }
+        for (Map.Entry<String, String> entry : map.entrySet()) {
+            action.accept(entry.getKey(), (V) entry.getValue(), state);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <V> V getValue(final String key) {
+        final Map<String, String> map = localMap.get();
+        return (V) (map == null ? null : map.get(key));
+    }
+
+    @Override
     public Map<String, String> getCopy() {
         final Map<String, String> map = localMap.get();
         return map == null ? new HashMap<String, String>() : new HashMap<>(map);
@@ -136,6 +172,12 @@ public class DefaultThreadContextMap implements ThreadContextMap2 {
     }
 
     @Override
+    public int size() {
+        final Map<String, String> map = localMap.get();
+        return map == null ? 0 : map.size();
+    }
+
+    @Override
     public String toString() {
         final Map<String, String> map = localMap.get();
         return map == null ? "{}" : map.toString();


[32/50] logging-log4j2 git commit: LOG4J2-1349 make new ThreadContextMap implementations package-private and introduce factory to instantiate them in ThreadContext

Posted by rp...@apache.org.
LOG4J2-1349 make new ThreadContextMap implementations package-private and introduce factory to instantiate them in ThreadContext


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/7aac69c8
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/7aac69c8
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/7aac69c8

Branch: refs/heads/master
Commit: 7aac69c81b2a8cbb8267424c1c6604b08f6009f5
Parents: e6cf7c9
Author: rpopma <rp...@apache.org>
Authored: Sat Sep 3 00:13:43 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sat Sep 3 00:13:43 2016 +0900

----------------------------------------------------------------------
 .../org/apache/logging/log4j/ThreadContext.java | 60 ++-----------
 .../CopyOnWriteSortedArrayThreadContextMap.java |  4 +-
 .../GarbageFreeSortedArrayThreadContextMap.java |  2 +-
 .../log4j/spi/ThreadContextMapFactory.java      | 91 ++++++++++++++++++++
 .../log4j/perf/jmh/ThreadContextBenchmark.java  | 14 ++-
 .../CopyOnWriteOpenHashMapThreadContextMap.java | 42 ---------
 .../GarbageFreeOpenHashMapThreadContextMap.java | 45 ----------
 .../CopyOnWriteOpenHashMapThreadContextMap.java | 44 ++++++++++
 .../GarbageFreeOpenHashMapThreadContextMap.java | 47 ++++++++++
 9 files changed, 196 insertions(+), 153 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
index bc01bf8..4636469 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
@@ -27,19 +27,14 @@ import java.util.Map;
 import java.util.NoSuchElementException;
 
 import org.apache.logging.log4j.message.ParameterizedMessage;
-import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
-import org.apache.logging.log4j.spi.DefaultThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
-import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap;
 import org.apache.logging.log4j.spi.NoOpThreadContextMap;
-import org.apache.logging.log4j.spi.Provider;
 import org.apache.logging.log4j.spi.ThreadContextMap;
 import org.apache.logging.log4j.spi.ThreadContextMap2;
+import org.apache.logging.log4j.spi.ThreadContextMapFactory;
 import org.apache.logging.log4j.spi.ThreadContextStack;
 import org.apache.logging.log4j.status.StatusLogger;
-import org.apache.logging.log4j.util.Constants;
 import org.apache.logging.log4j.util.PropertiesUtil;
-import org.apache.logging.log4j.util.ProviderUtil;
 
 /**
  * The ThreadContext allows applications to store information either in a Map or a Stack.
@@ -193,8 +188,6 @@ public final class ThreadContext {
     private static final String DISABLE_MAP = "disableThreadContextMap";
     private static final String DISABLE_STACK = "disableThreadContextStack";
     private static final String DISABLE_ALL = "disableThreadContext";
-    private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
-    private static final String GC_FREE_THREAD_CONTEXT_KEY = "log4j2.garbagefree.threadContextMap";
 
     private static boolean disableAll;
     private static boolean useMap;
@@ -222,54 +215,11 @@ public final class ThreadContext {
         useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
 
         contextStack = new DefaultThreadContextStack(useStack);
-        final String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY);
-        final ClassLoader cl = ProviderUtil.findClassLoader();
-        if (threadContextMapName != null) {
-            try {
-                final Class<?> clazz = cl.loadClass(threadContextMapName);
-                if (ThreadContextMap.class.isAssignableFrom(clazz)) {
-                    contextMap = (ThreadContextMap) clazz.newInstance();
-                }
-            } catch (final ClassNotFoundException cnfe) {
-                LOGGER.error("Unable to locate configured ThreadContextMap {}", threadContextMapName);
-            } catch (final Exception ex) {
-                LOGGER.error("Unable to create configured ThreadContextMap {}", threadContextMapName, ex);
-            }
-        }
-        if (contextMap == null && ProviderUtil.hasProviders()) {
-            final String factoryClassName = LogManager.getFactory().getClass().getName();
-            for (final Provider provider : ProviderUtil.getProviders()) {
-                if (factoryClassName.equals(provider.getClassName())) {
-                    final Class<? extends ThreadContextMap> clazz = provider.loadThreadContextMap();
-                    if (clazz != null) {
-                        try {
-                            contextMap = clazz.newInstance();
-                            break;
-                        } catch (final Exception e) {
-                            LOGGER.error("Unable to locate or load configured ThreadContextMap {}",
-                                    provider.getThreadContextMap(), e);
-                            contextMap = createThreadContextMap(useMap);
-                        }
-                    }
-                }
-            }
-        }
-        if (contextMap == null) {
-            contextMap = createThreadContextMap(useMap);
-        }
-    }
-
-    private static ThreadContextMap createThreadContextMap(final boolean doUseMap) {
-        if (!doUseMap) {
-            return new NoOpThreadContextMap();
-        }
-        if (Constants.ENABLE_THREADLOCALS) {
-            if (PropertiesUtil.getProperties().getBooleanProperty(GC_FREE_THREAD_CONTEXT_KEY)) {
-                return new GarbageFreeSortedArrayThreadContextMap();
-            }
-            return new CopyOnWriteSortedArrayThreadContextMap();
+        if (!useMap) {
+            contextMap = new NoOpThreadContextMap();
+        } else {
+            contextMap = ThreadContextMapFactory.createThreadContextMap();
         }
-        return new DefaultThreadContextMap(doUseMap);
     }
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
index 80c0e4d..81c69d5 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
@@ -32,8 +32,8 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  *
  * @since 2.7
  */
-public class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
-        CopyOnWrite, MutableContextDataSupplier {
+class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2, CopyOnWrite,
+        MutableContextDataSupplier {
 
     /**
      * The default initial capacity.

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
index 04705dd..cf93367 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
@@ -32,7 +32,7 @@ import org.apache.logging.log4j.util.PropertiesUtil;
  * </p>
  * @since 2.7
  */
-public class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
+class GarbageFreeSortedArrayThreadContextMap implements ThreadContextMap, ThreadContextMap2,
         MutableContextDataSupplier {
 
     /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMapFactory.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMapFactory.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMapFactory.java
new file mode 100644
index 0000000..b44f883
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ThreadContextMapFactory.java
@@ -0,0 +1,91 @@
+/*
+ * 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.spi;
+
+import org.apache.logging.log4j.LogManager;
+import org.apache.logging.log4j.Logger;
+import org.apache.logging.log4j.status.StatusLogger;
+import org.apache.logging.log4j.util.Constants;
+import org.apache.logging.log4j.util.PropertiesUtil;
+import org.apache.logging.log4j.util.ProviderUtil;
+
+/**
+ * Creates the ThreadContextMap instance used by the ThreadContext.
+ *
+ * @see ThreadContextMap
+ * @see org.apache.logging.log4j.ThreadContext
+ * @since 2.7
+ */
+public final class ThreadContextMapFactory {
+    private static final Logger LOGGER = StatusLogger.getLogger();
+    private static final String THREAD_CONTEXT_KEY = "log4j2.threadContextMap";
+    private static final String GC_FREE_THREAD_CONTEXT_KEY = "log4j2.garbagefree.threadContextMap";
+
+    private ThreadContextMapFactory() {
+    }
+
+    public static ThreadContextMap createThreadContextMap() {
+        final PropertiesUtil managerProps = PropertiesUtil.getProperties();
+        final String threadContextMapName = managerProps.getStringProperty(THREAD_CONTEXT_KEY);
+        final ClassLoader cl = ProviderUtil.findClassLoader();
+        ThreadContextMap result = null;
+        if (threadContextMapName != null) {
+            try {
+                final Class<?> clazz = cl.loadClass(threadContextMapName);
+                if (ThreadContextMap.class.isAssignableFrom(clazz)) {
+                    result = (ThreadContextMap) clazz.newInstance();
+                }
+            } catch (final ClassNotFoundException cnfe) {
+                LOGGER.error("Unable to locate configured ThreadContextMap {}", threadContextMapName);
+            } catch (final Exception ex) {
+                LOGGER.error("Unable to create configured ThreadContextMap {}", threadContextMapName, ex);
+            }
+        }
+        if (result == null && ProviderUtil.hasProviders()) {
+            final String factoryClassName = LogManager.getFactory().getClass().getName();
+            for (final Provider provider : ProviderUtil.getProviders()) {
+                if (factoryClassName.equals(provider.getClassName())) {
+                    final Class<? extends ThreadContextMap> clazz = provider.loadThreadContextMap();
+                    if (clazz != null) {
+                        try {
+                            result = clazz.newInstance();
+                            break;
+                        } catch (final Exception e) {
+                            LOGGER.error("Unable to locate or load configured ThreadContextMap {}",
+                                    provider.getThreadContextMap(), e);
+                            result = createDefaultThreadContextMap();
+                        }
+                    }
+                }
+            }
+        }
+        if (result == null) {
+            result = createDefaultThreadContextMap();
+        }
+        return result;
+    }
+
+    private static ThreadContextMap createDefaultThreadContextMap() {
+        if (Constants.ENABLE_THREADLOCALS) {
+            if (PropertiesUtil.getProperties().getBooleanProperty(GC_FREE_THREAD_CONTEXT_KEY)) {
+                return new GarbageFreeSortedArrayThreadContextMap();
+            }
+            return new CopyOnWriteSortedArrayThreadContextMap();
+        }
+        return new DefaultThreadContextMap(true);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
index 6e07abb..c45f4c6 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
@@ -30,15 +30,13 @@ import org.apache.logging.log4j.ThreadContextBenchmarkAccess;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.impl.ContextDataInjector;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
-import org.apache.logging.log4j.util.ArrayContextData;
-import org.apache.logging.log4j.perf.nogc.CopyOnWriteOpenHashMapThreadContextMap;
-import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
+import org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
+import org.apache.logging.log4j.spi.CopyOnWriteOpenHashMapThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextMap;
-import org.apache.logging.log4j.perf.nogc.GarbageFreeOpenHashMapThreadContextMap;
-import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap;
+import org.apache.logging.log4j.spi.GarbageFreeOpenHashMapThreadContextMap;
 import org.apache.logging.log4j.spi.MutableContextData;
-import org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
 import org.apache.logging.log4j.spi.ThreadContextMap;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.openjdk.jmh.annotations.Benchmark;
 import org.openjdk.jmh.annotations.BenchmarkMode;
 import org.openjdk.jmh.annotations.Fork;
@@ -83,9 +81,9 @@ public class ThreadContextBenchmark {
     static {
         IMPLEMENTATIONS.put(DEFAULT_CONTEXT_MAP, DefaultThreadContextMap.class);
         IMPLEMENTATIONS.put(COPY_OPENHASH_MAP, CopyOnWriteOpenHashMapThreadContextMap.class);
-        IMPLEMENTATIONS.put(COPY_ARRAY_MAP, CopyOnWriteSortedArrayThreadContextMap.class);
+        IMPLEMENTATIONS.put(COPY_ARRAY_MAP, CopyOnWriteOpenHashMapThreadContextMap.SUPER); //CopyOnWriteSortedArrayThreadContextMap.class);
         IMPLEMENTATIONS.put(NO_GC_OPENHASH_MAP, GarbageFreeOpenHashMapThreadContextMap.class);
-        IMPLEMENTATIONS.put(NO_GC_ARRAY_MAP, GarbageFreeSortedArrayThreadContextMap.class);
+        IMPLEMENTATIONS.put(NO_GC_ARRAY_MAP, GarbageFreeOpenHashMapThreadContextMap.SUPER); //GarbageFreeSortedArrayThreadContextMap.class);
     }
 
     @Param({ "Default", "CopyOpenHash", "CopySortedArray", "NoGcOpenHash", "NoGcSortedArray"})

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java
deleted file mode 100644
index e34c031..0000000
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/CopyOnWriteOpenHashMapThreadContextMap.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.perf.nogc;
-
-import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
-import org.apache.logging.log4j.spi.ContextData;
-import org.apache.logging.log4j.spi.MutableContextData;
-import org.apache.logging.log4j.util.PropertiesUtil;
-
-/**
- * {@code OpenHashMapContextData}-based implementation of the {@code ThreadContextMap} interface that creates a copy of
- * the data structure on every modification. Any particular instance of the data structure is a snapshot of the
- * ThreadContext at some point in time and can safely be passed off to other threads
- *
- * @since 2.7
- */
-public class CopyOnWriteOpenHashMapThreadContextMap extends CopyOnWriteSortedArrayThreadContextMap {
-    @Override
-    protected MutableContextData createMutableContextData() {
-        return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
-                PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
-    }
-
-    @Override
-    protected MutableContextData createMutableContextData(final ContextData original) {
-        return new OpenHashMapContextData<>(original);
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java
deleted file mode 100644
index cb97936..0000000
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/nogc/GarbageFreeOpenHashMapThreadContextMap.java
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.perf.nogc;
-
-import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap;
-import org.apache.logging.log4j.spi.ContextData;
-import org.apache.logging.log4j.spi.MutableContextData;
-import org.apache.logging.log4j.util.PropertiesUtil;
-
-/**
- * {@code OpenHashMapContextData}-based implementation of the {@code ThreadContextMap} interface that attempts not to
- * create temporary objects. Adding and removing key-value pairs will not create temporary objects.
- * <p>
- * Since the underlying data structure is modified directly it is not suitable for passing by reference to other
- * threads. Instead, client code needs to copy the contents when interacting with another thread.
- * </p>
- *
- * @since 2.7
- */
-public class GarbageFreeOpenHashMapThreadContextMap extends GarbageFreeSortedArrayThreadContextMap {
-    @Override
-    protected MutableContextData createMutableContextData() {
-        return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
-                PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
-    }
-
-    @Override
-    protected MutableContextData createMutableContextData(final ContextData original) {
-        return new OpenHashMapContextData<>(original);
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-perf/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteOpenHashMapThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteOpenHashMapThreadContextMap.java
new file mode 100644
index 0000000..463e3ed
--- /dev/null
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteOpenHashMapThreadContextMap.java
@@ -0,0 +1,44 @@
+/*
+ * 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.spi;
+
+import org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+/**
+ * {@code OpenHashMapContextData}-based implementation of the {@code ThreadContextMap} interface that creates a copy of
+ * the data structure on every modification. Any particular instance of the data structure is a snapshot of the
+ * ThreadContext at some point in time and can safely be passed off to other threads
+ *
+ * @since 2.7
+ */
+public class CopyOnWriteOpenHashMapThreadContextMap extends CopyOnWriteSortedArrayThreadContextMap {
+
+    /** Constant used in benchmark code */
+    public static final Class<? extends ThreadContextMap> SUPER = CopyOnWriteSortedArrayThreadContextMap.class;
+
+    @Override
+    protected MutableContextData createMutableContextData() {
+        return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
+                PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
+    }
+
+    @Override
+    protected MutableContextData createMutableContextData(final ContextData original) {
+        return new OpenHashMapContextData<>(original);
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/7aac69c8/log4j-perf/src/main/java/org/apache/logging/log4j/spi/GarbageFreeOpenHashMapThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/spi/GarbageFreeOpenHashMapThreadContextMap.java b/log4j-perf/src/main/java/org/apache/logging/log4j/spi/GarbageFreeOpenHashMapThreadContextMap.java
new file mode 100644
index 0000000..5df5dda
--- /dev/null
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/spi/GarbageFreeOpenHashMapThreadContextMap.java
@@ -0,0 +1,47 @@
+/*
+ * 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.spi;
+
+import org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
+import org.apache.logging.log4j.util.PropertiesUtil;
+
+/**
+ * {@code OpenHashMapContextData}-based implementation of the {@code ThreadContextMap} interface that attempts not to
+ * create temporary objects. Adding and removing key-value pairs will not create temporary objects.
+ * <p>
+ * Since the underlying data structure is modified directly it is not suitable for passing by reference to other
+ * threads. Instead, client code needs to copy the contents when interacting with another thread.
+ * </p>
+ *
+ * @since 2.7
+ */
+public class GarbageFreeOpenHashMapThreadContextMap extends GarbageFreeSortedArrayThreadContextMap {
+
+    /** Constant used in benchmark code */
+    public static final Class<? extends ThreadContextMap> SUPER = GarbageFreeSortedArrayThreadContextMap.class;
+
+    @Override
+    protected MutableContextData createMutableContextData() {
+        return new OpenHashMapContextData<>(PropertiesUtil.getProperties().getIntegerProperty(
+                PROPERTY_NAME_INITIAL_CAPACITY, DEFAULT_INITIAL_CAPACITY));
+    }
+
+    @Override
+    protected MutableContextData createMutableContextData(final ContextData original) {
+        return new OpenHashMapContextData<>(original);
+    }
+}


[02/50] logging-log4j2 git commit: LOG4J2-1010 improved ContextDataInjector documentation

Posted by rp...@apache.org.
LOG4J2-1010 improved ContextDataInjector documentation


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/07162bea
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/07162bea
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/07162bea

Branch: refs/heads/master
Commit: 07162bea686913a21f0b7688d1c8ad50f9b7b691
Parents: 947d9d6
Author: rpopma <rp...@apache.org>
Authored: Sun Aug 28 22:24:13 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Aug 28 22:24:13 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/core/impl/ContextDataInjector.java    | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/07162bea/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
index 5b74968..c1bd4b4 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
@@ -28,8 +28,13 @@ import org.apache.logging.log4j.core.config.Property;
  * </p><p>
  * In some asynchronous models, work may be delegated to several threads, while conceptually this work shares the same
  * context. In such models, storing context data in {@code ThreadLocal} variables is not convenient or desirable.
- * By specifying a custom {@code ContextDataInjectorFactory}, users can initialize log events with context data from
- * any arbitrary context.
+ * Users can configure the {@code ContextDataInjectorFactory} to provide custom {@code ContextDataInjector} objects,
+ * in order to initialize log events with context data from any arbitrary context.
+ * </p><p>
+ * When providing a custom {@code ContextDataInjector}, be aware that the {@code ContextDataFactory} may be invoked
+ * multiple times by the various components in Log4j that need access to context data.
+ * This includes the object(s) that populate log events, but also various lookups and filters that look at
+ * context data to determine whether an event should be logged.
  * </p>
  *
  * @see ContextDataInjectorFactory
@@ -43,7 +48,8 @@ public interface ContextDataInjector {
      * Returns a {@code MutableContextData} object initialized with the specified properties and the appropriate
      * context data. The returned value may be the specified parameter or a different object.
      *
-     * @param properties Properties from the log4j configuration to be added to the resulting ContextData
+     * @param properties Properties from the log4j configuration to be added to the resulting ContextData. May be
+     *          {@code null} or empty
      * @param reusable a {@code MutableContextData} instance that may be reused to avoid creating temporary objects
      * @return a {@code MutableContextData} instance initialized with the specified properties and the appropriate
      *          context data. The returned value may be the specified parameter or a different object.


[31/50] logging-log4j2 git commit: LOG4J2-1349 move ArrayContextData (and its test) from spi to util

Posted by rp...@apache.org.
LOG4J2-1349 move ArrayContextData (and its test) from spi to util


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/e6cf7c90
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/e6cf7c90
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/e6cf7c90

Branch: refs/heads/master
Commit: e6cf7c9098a097ee570242877fd058d582f22131
Parents: 112a222
Author: rpopma <rp...@apache.org>
Authored: Fri Sep 2 23:44:03 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Sep 2 23:44:03 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/spi/ArrayContextData.java     | 448 ---------------
 .../CopyOnWriteSortedArrayThreadContextMap.java |   1 +
 .../GarbageFreeSortedArrayThreadContextMap.java |   1 +
 .../logging/log4j/util/ArrayContextData.java    | 449 +++++++++++++++
 .../logging/log4j/spi/ArrayContextDataTest.java | 569 -------------------
 .../log4j/util/ArrayContextDataTest.java        | 566 ++++++++++++++++++
 .../log4j/core/impl/ContextDataFactory.java     |   2 +-
 .../ContextDataAttributeConverterTest.java      |   2 +-
 .../ContextDataJsonAttributeConverterTest.java  |   2 +-
 .../log4j/core/impl/Log4jLogEventTest.java      |   2 +-
 .../log4j/core/impl/MutableLogEventTest.java    |   2 +-
 .../jmh/ArrayContextDataVsHashMapBenchmark.java |   2 +-
 .../log4j/perf/jmh/ThreadContextBenchmark.java  |   2 +-
 13 files changed, 1024 insertions(+), 1024 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-api/src/main/java/org/apache/logging/log4j/spi/ArrayContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ArrayContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/ArrayContextData.java
deleted file mode 100644
index d934a3d..0000000
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/ArrayContextData.java
+++ /dev/null
@@ -1,448 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements. See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache license, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License. You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the license for the specific language governing permissions and
- * limitations under the license.
- */
-package org.apache.logging.log4j.spi;
-
-import java.io.IOException;
-import java.io.InvalidObjectException;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import java.util.Objects;
-
-import org.apache.logging.log4j.util.BiConsumer;
-import org.apache.logging.log4j.util.TriConsumer;
-
-/**
- * Array-based implementation of the {@code ContextData} interface. Keys are held in a sorted array.
- * <p>
- * This is not a generic collection, but makes some trade-offs to optimize for the Log4j ContextData use case:
- * </p>
- * <ul>
- *   <li>Garbage-free iteration over key-value pairs with {@code BiConsumer} and {@code TriConsumer}.</li>
- *   <li>Fast copy. If the ThreadContextMap is also an instance of {@code ArrayContextData}, the full thread context
- *     data can be transferred with two array copies and two field updates.</li>
- *   <li>Acceptable performance for small data sets. The current implementation stores keys in a sorted array, values
- *     are stored in a separate array at the same index.
- *     Worst-case performance of {@code get} and {@code containsKey} is O(log N),
- *     worst-case performance of {@code put} and {@code remove} is O(N log N).
- *     The expectation is that for the small values of {@code N} (less than 100) that are the vast majority of
- *     ThreadContext use cases, the constants dominate performance more than the asymptotic performance of the
- *     algorithms used.
- *     </li>
- *     <li>Compact representation.</li>
- * </ul>
- *
- * @since 2.7
- */
-public class ArrayContextData implements MutableContextData, ThreadContextMap {
-
-    /**
-     * The default initial capacity.
-     */
-    private static final int DEFAULT_INITIAL_CAPACITY = 4;
-    private static final long serialVersionUID = -5748905872274478116L;
-    private static final int HASHVAL = 31;
-
-    private static final TriConsumer<String, Object, MutableContextData> PUT_ALL = new TriConsumer<String, Object, MutableContextData>() {
-        @Override
-        public void accept(final String key, final Object value, final MutableContextData contextData) {
-            contextData.putValue(key, value);
-        }
-    };
-
-    /**
-     * An empty array instance to share when the table is not inflated.
-     */
-    private static final String[] EMPTY = {};
-
-    private transient String[] keys = EMPTY;
-    private transient Object[] values = EMPTY;
-
-    /**
-     * The number of key-value mappings contained in this map.
-     */
-    private transient int size;
-
-    /**
-     * The next size value at which to resize (capacity * load factor).
-     * @serial
-     */
-    // If table == EMPTY_TABLE then this is the initial capacity at which the
-    // table will be created when inflated.
-    private int threshold;
-
-    public ArrayContextData() {
-        this(DEFAULT_INITIAL_CAPACITY);
-    }
-
-    public ArrayContextData(final int initialCapacity) {
-        if (initialCapacity < 1) {
-            throw new IllegalArgumentException("Initial capacity must be at least one but was " + initialCapacity);
-        }
-        threshold = ceilingNextPowerOfTwo(initialCapacity);
-    }
-
-    public ArrayContextData(final ContextData other) {
-        if (other instanceof ArrayContextData) {
-            initFrom0((ArrayContextData) other);
-        } else if (other != null) {
-            resize(ceilingNextPowerOfTwo(other.size()));
-            other.forEach(PUT_ALL, this);
-        }
-    }
-
-    @Override
-    public void clear() {
-        Arrays.fill(keys, 0, size, null);
-        Arrays.fill(values, 0, size, null);
-        size = 0;
-    }
-
-    @Override
-    public boolean containsKey(final String key) {
-        return indexOfKey(key) >= 0;
-    }
-
-    @Override
-    public Map<String, String> asMap() {
-        final Map<String, String> result = new HashMap<>(size());
-        for (int i = 0; i < size(); i++) {
-            final Object value = getValueAt(i);
-            result.put(getKeyAt(i), value == null ? null : String.valueOf(value));
-        }
-        return result;
-    }
-
-    @Override
-    public Map<String, String> getCopy() {
-        return asMap();
-    }
-
-    @Override
-    public Map<String, String> getImmutableMapOrNull() {
-        return isEmpty() ? null : Collections.unmodifiableMap(asMap());
-    }
-
-    @Override
-    public String get(final String key) {
-        final Object result = getValue(key);
-        return result == null ? null : String.valueOf(result);
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <V> V getValue(final String key) {
-        final int index = indexOfKey(key);
-        if (index < 0) {
-            return null;
-        }
-        return (V) values[index];
-    }
-
-    @Override
-    public boolean isEmpty() {
-        return size == 0;
-    }
-
-    int indexOfKey(final String key) {
-        if (keys == EMPTY) {
-            return -1;
-        }
-        if (key == null) { // null key is located at the start of the array
-            return nullKeyIndex(); // insert at index zero
-        }
-        final int start = size > 0 && keys[0] == null ? 1 : 0;
-        return Arrays.binarySearch(keys, start, size, key);
-    }
-
-    private int nullKeyIndex() {
-        return size > 0 && keys[0] == null ? 0 : ~0;
-    }
-
-    @Override
-    public void put(final String key, final String value) {
-        putValue(key, value);
-    }
-
-    @Override
-    public void putValue(final String key, final Object value) {
-        if (keys == EMPTY) {
-            inflateTable(threshold);
-        }
-        final int index = indexOfKey(key);
-        if (index >= 0) {
-            keys[index] = key;
-            values[index] = value;
-        } else { // not found, so insert.
-            insertAt(~index, key, value);
-        }
-    }
-
-    private void insertAt(final int index, final String key, final Object value) {
-        ensureCapacity();
-        System.arraycopy(keys, index, keys, index + 1, size - index);
-        System.arraycopy(values, index, values, index + 1, size - index);
-        keys[index] = key;
-        values[index] = value;
-        size++;
-    }
-
-    @Override
-    public void putAll(final ContextData source) {
-        if (source instanceof ArrayContextData) {
-            initFrom0((ArrayContextData) source);
-        } else if (source != null) {
-            source.forEach(PUT_ALL, this);
-        }
-    }
-
-    public void initFrom(final ArrayContextData other) {
-        initFrom0(other);
-    }
-
-    private void initFrom0(final ArrayContextData other) {
-        if (keys.length < other.size) {
-            keys = new String[other.threshold];
-            values = new Object[other.threshold];
-        }
-        System.arraycopy(other.keys, 0, keys, 0, other.size);
-        System.arraycopy(other.values, 0, values, 0, other.size);
-
-        size = other.size;
-        threshold = other.threshold;
-    }
-
-    private void ensureCapacity() {
-        if (size >= threshold) {
-            resize(threshold * 2);
-        }
-    }
-
-    private void resize(final int newCapacity) {
-        final String[] oldKeys = keys;
-        final Object[] oldValues = values;
-
-        keys = new String[newCapacity];
-        values = new Object[newCapacity];
-
-        System.arraycopy(oldKeys, 0, keys, 0, size);
-        System.arraycopy(oldValues, 0, values, 0, size);
-
-        threshold = newCapacity;
-    }
-
-    /**
-     * Inflates the table.
-     */
-    private void inflateTable(int toSize) {
-        threshold = toSize;
-        keys = new String[toSize];
-        values = new Object[toSize];
-    }
-
-    @Override
-    public void remove(final String key) {
-        if (keys == EMPTY) {
-            return;
-        }
-        final int index = indexOfKey(key);
-        if (index >= 0) {
-            System.arraycopy(keys, index + 1, keys, index, size - index);
-            System.arraycopy(values, index + 1, values, index, size - index);
-            size--;
-        }
-    }
-
-    String getKeyAt(final int index) {
-        if (index < 0 || index >= size) {
-            return null;
-        }
-        return keys[index];
-    }
-
-    @SuppressWarnings("unchecked")
-    <V> V getValueAt(final int index) {
-        if (index < 0 || index >= size) {
-            return null;
-        }
-        return (V) values[index];
-    }
-
-    @Override
-    public int size() {
-        return size;
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <V> void forEach(BiConsumer<String, ? super V> action) {
-        for (int i = 0; i < size; i++) {
-            action.accept(keys[i], (V) values[i]);
-        }
-    }
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public <V, T> void forEach(TriConsumer<String, ? super V, T> action, T state) {
-        for (int i = 0; i < size; i++) {
-            action.accept(keys[i], (V) values[i], state);
-        }
-    }
-
-    @Override
-    public boolean equals(final Object obj) {
-        if (obj == this) {
-            return true;
-        }
-        if (!(obj instanceof ArrayContextData)) {
-            return false;
-        }
-        ArrayContextData other = (ArrayContextData) obj;
-        if (this.size() != other.size()) {
-            return false;
-        }
-        for (int i = 0; i < size(); i++) {
-            if (!Objects.equals(keys[i], other.keys[i])) {
-                return false;
-            }
-            if (!Objects.equals(values[i], other.values[i])) {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    @Override
-    public int hashCode() {
-        int result = 37;
-        result = HASHVAL * result + size;
-        result = HASHVAL * result + hashCode(keys, size);
-        result = HASHVAL * result + hashCode(values, size);
-        return result;
-    }
-
-    private static int hashCode(Object[] values, int length) {
-        int result = 1;
-        for (int i = 0; i < length; i++) {
-            result = HASHVAL * result + (values[i] == null ? 0 : values[i].hashCode());
-        }
-        return result;
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(256);
-        sb.append('{');
-        for (int i = 0; i < size; i++) {
-            if (i > 0) {
-                sb.append(", ");
-            }
-            sb.append(keys[i]).append('=');
-            sb.append(values[i] == this ? "(this map)" : values[i]);
-        }
-        sb.append('}');
-        return sb.toString();
-    }
-
-    /**
-     * Save the state of the {@code ArrayContextData} instance to a stream (i.e.,
-     * serialize it).
-     *
-     * @serialData The <i>capacity</i> of the ArrayContextData (the length of the
-     *             bucket array) is emitted (int), followed by the
-     *             <i>size</i> (an int, the number of key-value
-     *             mappings), followed by the key (Object) and value (Object)
-     *             for each key-value mapping.  The key-value mappings are
-     *             emitted in no particular order.
-     */
-    private void writeObject(java.io.ObjectOutputStream s) throws IOException {
-        // Write out the threshold, and any hidden stuff
-        s.defaultWriteObject();
-
-        // Write out number of buckets
-        if (keys == EMPTY) {
-            s.writeInt(ceilingNextPowerOfTwo(threshold));
-        } else {
-            s.writeInt(keys.length);
-        }
-
-        // Write out size (number of Mappings)
-        s.writeInt(size);
-
-        // Write out keys and values (alternating)
-        if (size > 0) {
-            for (int i = 0; i < size; i++) {
-                s.writeObject(keys[i]);
-                s.writeObject(values[i]);
-            }
-        }
-    }
-
-
-    /**
-     * Calculate the next power of 2, greater than or equal to x.
-     * <p>
-     * From Hacker's Delight, Chapter 3, Harry S. Warren Jr.
-     *
-     * @param x Value to round up
-     * @return The next power of 2 from x inclusive
-     */
-    private static int ceilingNextPowerOfTwo(final int x) {
-        final int BITS_PER_INT = 32;
-        return 1 << (BITS_PER_INT - Integer.numberOfLeadingZeros(x - 1));
-    }
-
-    /**
-     * Reconstitute the {@code ArrayContextData} instance from a stream (i.e.,
-     * deserialize it).
-     */
-    private void readObject(java.io.ObjectInputStream s)  throws IOException, ClassNotFoundException {
-        // Read in the threshold (ignored), and any hidden stuff
-        s.defaultReadObject();
-
-        // set other fields that need values
-        keys = EMPTY;
-        values = EMPTY;
-
-        // Read in number of buckets
-        int capacity = s.readInt();
-        if (capacity < 0) {
-            throw new InvalidObjectException("Illegal capacity: " + capacity);
-        }
-
-        // Read number of mappings
-        int mappings = s.readInt();
-        if (mappings < 0) {
-            throw new InvalidObjectException("Illegal mappings count: " + mappings);
-        }
-
-        // allocate the bucket array;
-        if (mappings > 0) {
-            inflateTable(capacity);
-        } else {
-            threshold = capacity;
-        }
-
-        // Read the keys and values, and put the mappings in the arrays
-        for (int i = 0; i < mappings; i++) {
-            keys[i] = (String) s.readObject();
-            values[i] = s.readObject();
-        }
-        size = mappings;
-    }
-}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
index 08bac8e..80c0e4d 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/CopyOnWriteSortedArrayThreadContextMap.java
@@ -20,6 +20,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.util.PropertiesUtil;
 
 /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
index 1fe2f65..04705dd 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/GarbageFreeSortedArrayThreadContextMap.java
@@ -20,6 +20,7 @@ import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
 
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.util.PropertiesUtil;
 
 /**

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
new file mode 100644
index 0000000..bdc9951
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/ArrayContextData.java
@@ -0,0 +1,449 @@
+/*
+ * 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.util;
+
+import java.io.IOException;
+import java.io.InvalidObjectException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Objects;
+
+import org.apache.logging.log4j.spi.ContextData;
+import org.apache.logging.log4j.spi.MutableContextData;
+import org.apache.logging.log4j.spi.ThreadContextMap;
+
+/**
+ * Array-based implementation of the {@code ContextData} interface. Keys are held in a sorted array.
+ * <p>
+ * This is not a generic collection, but makes some trade-offs to optimize for the Log4j ContextData use case:
+ * </p>
+ * <ul>
+ *   <li>Garbage-free iteration over key-value pairs with {@code BiConsumer} and {@code TriConsumer}.</li>
+ *   <li>Fast copy. If the ThreadContextMap is also an instance of {@code ArrayContextData}, the full thread context
+ *     data can be transferred with two array copies and two field updates.</li>
+ *   <li>Acceptable performance for small data sets. The current implementation stores keys in a sorted array, values
+ *     are stored in a separate array at the same index.
+ *     Worst-case performance of {@code get} and {@code containsKey} is O(log N),
+ *     worst-case performance of {@code put} and {@code remove} is O(N log N).
+ *     The expectation is that for the small values of {@code N} (less than 100) that are the vast majority of
+ *     ThreadContext use cases, the constants dominate performance more than the asymptotic performance of the
+ *     algorithms used.
+ *     </li>
+ *     <li>Compact representation.</li>
+ * </ul>
+ *
+ * @since 2.7
+ */
+public class ArrayContextData implements MutableContextData, ThreadContextMap {
+
+    /**
+     * The default initial capacity.
+     */
+    private static final int DEFAULT_INITIAL_CAPACITY = 4;
+    private static final long serialVersionUID = -5748905872274478116L;
+    private static final int HASHVAL = 31;
+
+    private static final TriConsumer<String, Object, MutableContextData> PUT_ALL = new TriConsumer<String, Object, MutableContextData>() {
+        @Override
+        public void accept(final String key, final Object value, final MutableContextData contextData) {
+            contextData.putValue(key, value);
+        }
+    };
+
+    /**
+     * An empty array instance to share when the table is not inflated.
+     */
+    private static final String[] EMPTY = {};
+
+    private transient String[] keys = EMPTY;
+    private transient Object[] values = EMPTY;
+
+    /**
+     * The number of key-value mappings contained in this map.
+     */
+    private transient int size;
+
+    /**
+     * The next size value at which to resize (capacity * load factor).
+     * @serial
+     */
+    // If table == EMPTY_TABLE then this is the initial capacity at which the
+    // table will be created when inflated.
+    private int threshold;
+
+    public ArrayContextData() {
+        this(DEFAULT_INITIAL_CAPACITY);
+    }
+
+    public ArrayContextData(final int initialCapacity) {
+        if (initialCapacity < 1) {
+            throw new IllegalArgumentException("Initial capacity must be at least one but was " + initialCapacity);
+        }
+        threshold = ceilingNextPowerOfTwo(initialCapacity);
+    }
+
+    public ArrayContextData(final ContextData other) {
+        if (other instanceof ArrayContextData) {
+            initFrom0((ArrayContextData) other);
+        } else if (other != null) {
+            resize(ceilingNextPowerOfTwo(other.size()));
+            other.forEach(PUT_ALL, this);
+        }
+    }
+
+    @Override
+    public void clear() {
+        Arrays.fill(keys, 0, size, null);
+        Arrays.fill(values, 0, size, null);
+        size = 0;
+    }
+
+    @Override
+    public boolean containsKey(final String key) {
+        return indexOfKey(key) >= 0;
+    }
+
+    @Override
+    public Map<String, String> asMap() {
+        final Map<String, String> result = new HashMap<>(size());
+        for (int i = 0; i < size(); i++) {
+            final Object value = getValueAt(i);
+            result.put(getKeyAt(i), value == null ? null : String.valueOf(value));
+        }
+        return result;
+    }
+
+    @Override
+    public Map<String, String> getCopy() {
+        return asMap();
+    }
+
+    @Override
+    public Map<String, String> getImmutableMapOrNull() {
+        return isEmpty() ? null : Collections.unmodifiableMap(asMap());
+    }
+
+    @Override
+    public String get(final String key) {
+        final Object result = getValue(key);
+        return result == null ? null : String.valueOf(result);
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <V> V getValue(final String key) {
+        final int index = indexOfKey(key);
+        if (index < 0) {
+            return null;
+        }
+        return (V) values[index];
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return size == 0;
+    }
+
+    int indexOfKey(final String key) {
+        if (keys == EMPTY) {
+            return -1;
+        }
+        if (key == null) { // null key is located at the start of the array
+            return nullKeyIndex(); // insert at index zero
+        }
+        final int start = size > 0 && keys[0] == null ? 1 : 0;
+        return Arrays.binarySearch(keys, start, size, key);
+    }
+
+    private int nullKeyIndex() {
+        return size > 0 && keys[0] == null ? 0 : ~0;
+    }
+
+    @Override
+    public void put(final String key, final String value) {
+        putValue(key, value);
+    }
+
+    @Override
+    public void putValue(final String key, final Object value) {
+        if (keys == EMPTY) {
+            inflateTable(threshold);
+        }
+        final int index = indexOfKey(key);
+        if (index >= 0) {
+            keys[index] = key;
+            values[index] = value;
+        } else { // not found, so insert.
+            insertAt(~index, key, value);
+        }
+    }
+
+    private void insertAt(final int index, final String key, final Object value) {
+        ensureCapacity();
+        System.arraycopy(keys, index, keys, index + 1, size - index);
+        System.arraycopy(values, index, values, index + 1, size - index);
+        keys[index] = key;
+        values[index] = value;
+        size++;
+    }
+
+    @Override
+    public void putAll(final ContextData source) {
+        if (source instanceof ArrayContextData) {
+            initFrom0((ArrayContextData) source);
+        } else if (source != null) {
+            source.forEach(PUT_ALL, this);
+        }
+    }
+
+    public void initFrom(final ArrayContextData other) {
+        initFrom0(other);
+    }
+
+    private void initFrom0(final ArrayContextData other) {
+        if (keys.length < other.size) {
+            keys = new String[other.threshold];
+            values = new Object[other.threshold];
+        }
+        System.arraycopy(other.keys, 0, keys, 0, other.size);
+        System.arraycopy(other.values, 0, values, 0, other.size);
+
+        size = other.size;
+        threshold = other.threshold;
+    }
+
+    private void ensureCapacity() {
+        if (size >= threshold) {
+            resize(threshold * 2);
+        }
+    }
+
+    private void resize(final int newCapacity) {
+        final String[] oldKeys = keys;
+        final Object[] oldValues = values;
+
+        keys = new String[newCapacity];
+        values = new Object[newCapacity];
+
+        System.arraycopy(oldKeys, 0, keys, 0, size);
+        System.arraycopy(oldValues, 0, values, 0, size);
+
+        threshold = newCapacity;
+    }
+
+    /**
+     * Inflates the table.
+     */
+    private void inflateTable(int toSize) {
+        threshold = toSize;
+        keys = new String[toSize];
+        values = new Object[toSize];
+    }
+
+    @Override
+    public void remove(final String key) {
+        if (keys == EMPTY) {
+            return;
+        }
+        final int index = indexOfKey(key);
+        if (index >= 0) {
+            System.arraycopy(keys, index + 1, keys, index, size - index);
+            System.arraycopy(values, index + 1, values, index, size - index);
+            size--;
+        }
+    }
+
+    String getKeyAt(final int index) {
+        if (index < 0 || index >= size) {
+            return null;
+        }
+        return keys[index];
+    }
+
+    @SuppressWarnings("unchecked")
+    <V> V getValueAt(final int index) {
+        if (index < 0 || index >= size) {
+            return null;
+        }
+        return (V) values[index];
+    }
+
+    @Override
+    public int size() {
+        return size;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <V> void forEach(BiConsumer<String, ? super V> action) {
+        for (int i = 0; i < size; i++) {
+            action.accept(keys[i], (V) values[i]);
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <V, T> void forEach(TriConsumer<String, ? super V, T> action, T state) {
+        for (int i = 0; i < size; i++) {
+            action.accept(keys[i], (V) values[i], state);
+        }
+    }
+
+    @Override
+    public boolean equals(final Object obj) {
+        if (obj == this) {
+            return true;
+        }
+        if (!(obj instanceof ArrayContextData)) {
+            return false;
+        }
+        ArrayContextData other = (ArrayContextData) obj;
+        if (this.size() != other.size()) {
+            return false;
+        }
+        for (int i = 0; i < size(); i++) {
+            if (!Objects.equals(keys[i], other.keys[i])) {
+                return false;
+            }
+            if (!Objects.equals(values[i], other.values[i])) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    @Override
+    public int hashCode() {
+        int result = 37;
+        result = HASHVAL * result + size;
+        result = HASHVAL * result + hashCode(keys, size);
+        result = HASHVAL * result + hashCode(values, size);
+        return result;
+    }
+
+    private static int hashCode(Object[] values, int length) {
+        int result = 1;
+        for (int i = 0; i < length; i++) {
+            result = HASHVAL * result + (values[i] == null ? 0 : values[i].hashCode());
+        }
+        return result;
+    }
+
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder(256);
+        sb.append('{');
+        for (int i = 0; i < size; i++) {
+            if (i > 0) {
+                sb.append(", ");
+            }
+            sb.append(keys[i]).append('=');
+            sb.append(values[i] == this ? "(this map)" : values[i]);
+        }
+        sb.append('}');
+        return sb.toString();
+    }
+
+    /**
+     * Save the state of the {@code ArrayContextData} instance to a stream (i.e.,
+     * serialize it).
+     *
+     * @serialData The <i>capacity</i> of the ArrayContextData (the length of the
+     *             bucket array) is emitted (int), followed by the
+     *             <i>size</i> (an int, the number of key-value
+     *             mappings), followed by the key (Object) and value (Object)
+     *             for each key-value mapping.  The key-value mappings are
+     *             emitted in no particular order.
+     */
+    private void writeObject(java.io.ObjectOutputStream s) throws IOException {
+        // Write out the threshold, and any hidden stuff
+        s.defaultWriteObject();
+
+        // Write out number of buckets
+        if (keys == EMPTY) {
+            s.writeInt(ceilingNextPowerOfTwo(threshold));
+        } else {
+            s.writeInt(keys.length);
+        }
+
+        // Write out size (number of Mappings)
+        s.writeInt(size);
+
+        // Write out keys and values (alternating)
+        if (size > 0) {
+            for (int i = 0; i < size; i++) {
+                s.writeObject(keys[i]);
+                s.writeObject(values[i]);
+            }
+        }
+    }
+
+
+    /**
+     * Calculate the next power of 2, greater than or equal to x.
+     * <p>
+     * From Hacker's Delight, Chapter 3, Harry S. Warren Jr.
+     *
+     * @param x Value to round up
+     * @return The next power of 2 from x inclusive
+     */
+    private static int ceilingNextPowerOfTwo(final int x) {
+        final int BITS_PER_INT = 32;
+        return 1 << (BITS_PER_INT - Integer.numberOfLeadingZeros(x - 1));
+    }
+
+    /**
+     * Reconstitute the {@code ArrayContextData} instance from a stream (i.e.,
+     * deserialize it).
+     */
+    private void readObject(java.io.ObjectInputStream s)  throws IOException, ClassNotFoundException {
+        // Read in the threshold (ignored), and any hidden stuff
+        s.defaultReadObject();
+
+        // set other fields that need values
+        keys = EMPTY;
+        values = EMPTY;
+
+        // Read in number of buckets
+        int capacity = s.readInt();
+        if (capacity < 0) {
+            throw new InvalidObjectException("Illegal capacity: " + capacity);
+        }
+
+        // Read number of mappings
+        int mappings = s.readInt();
+        if (mappings < 0) {
+            throw new InvalidObjectException("Illegal mappings count: " + mappings);
+        }
+
+        // allocate the bucket array;
+        if (mappings > 0) {
+            inflateTable(capacity);
+        } else {
+            threshold = capacity;
+        }
+
+        // Read the keys and values, and put the mappings in the arrays
+        for (int i = 0; i < mappings; i++) {
+            keys[i] = (String) s.readObject();
+            values[i] = s.readObject();
+        }
+        size = mappings;
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-api/src/test/java/org/apache/logging/log4j/spi/ArrayContextDataTest.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/spi/ArrayContextDataTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/spi/ArrayContextDataTest.java
deleted file mode 100644
index f85db8a..0000000
--- a/log4j-api/src/test/java/org/apache/logging/log4j/spi/ArrayContextDataTest.java
+++ /dev/null
@@ -1,569 +0,0 @@
-package org.apache.logging.log4j.spi;/*
- * 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.
- */
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
-import java.lang.reflect.Field;
-import java.util.HashMap;
-import java.util.Map;
-
-import org.apache.logging.log4j.spi.ArrayContextData;
-import org.apache.logging.log4j.util.BiConsumer;
-import org.apache.logging.log4j.util.TriConsumer;
-import org.junit.Test;
-
-import static org.junit.Assert.*;
-
-/**
- * Tests the ArrayContextData class.
- */
-public class ArrayContextDataTest {
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testConstructorDisallowsNegativeCapacity() throws Exception {
-        new ArrayContextData(-1);
-    }
-
-    @Test(expected = IllegalArgumentException.class)
-    public void testConstructorDisallowsZeroCapacity() throws Exception {
-        new ArrayContextData(0);
-    }
-
-    @Test
-    public void testConstructorIgnoresNull() throws Exception {
-        assertEquals(0, new ArrayContextData(null).size());
-    }
-
-    @Test
-    public void testToString() {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-        assertEquals("{3=3value, B=Bvalue, a=avalue}", original.toString());
-    }
-
-    @Test
-    public void testSerialization() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-
-        final byte[] binary = serialize(original);
-        final ArrayContextData copy = deserialize(binary);
-        assertEquals(original, copy);
-    }
-
-    private byte[] serialize(final ArrayContextData data) throws IOException {
-        final ByteArrayOutputStream arr = new ByteArrayOutputStream();
-        final ObjectOutputStream out = new ObjectOutputStream(arr);
-        out.writeObject(data);
-        return arr.toByteArray();
-    }
-
-    private ArrayContextData deserialize(final byte[] binary) throws IOException, ClassNotFoundException {
-        final ByteArrayInputStream inArr = new ByteArrayInputStream(binary);
-        final ObjectInputStream in = new ObjectInputStream(inArr);
-        final ArrayContextData result = (ArrayContextData) in.readObject();
-        return result;
-    }
-
-    @Test
-    public void testPutAll() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-
-        final ArrayContextData other = new ArrayContextData();
-        other.putAll(original);
-        assertEquals(original, other);
-
-        other.putValue("3", "otherValue");
-        assertNotEquals(original, other);
-
-        other.putValue("3", null);
-        assertNotEquals(original, other);
-
-        other.putValue("3", "3value");
-        assertEquals(original, other);
-    }
-
-    @Test
-    public void testEquals() {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-        assertEquals(original, original); // equal to itself
-
-        final ArrayContextData other = new ArrayContextData();
-        other.putValue("a", "avalue");
-        assertNotEquals(original, other);
-
-        other.putValue("B", "Bvalue");
-        assertNotEquals(original, other);
-
-        other.putValue("3", "3value");
-        assertEquals(original, other);
-
-        other.putValue("3", "otherValue");
-        assertNotEquals(original, other);
-
-        other.putValue("3", null);
-        assertNotEquals(original, other);
-
-        other.putValue("3", "3value");
-        assertEquals(original, other);
-    }
-
-    @Test
-    public void testAsMap() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-
-        final Map<String, Object> expected = new HashMap<>();
-        expected.put("a", "avalue");
-        expected.put("B", "Bvalue");
-        expected.put("3", "3value");
-
-        assertEquals(expected, original.asMap());
-    }
-
-    @Test
-    public void testGetCopyDelegatesToAsMap() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        assertEquals(original.getCopy(), original.asMap());
-
-        original.putValue("B", "Bvalue");
-        assertEquals(original.getCopy(), original.asMap());
-
-        original.putValue("3", "3value");
-        assertEquals(original.getCopy(), original.asMap());
-    }
-
-    @Test
-    public void testGetImmutableMapOrNull() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        assertEquals(original.getImmutableMapOrNull(), original.asMap());
-
-        original.putValue("B", "Bvalue");
-        assertEquals(original.getImmutableMapOrNull(), original.asMap());
-
-        original.putValue("3", "3value");
-        assertEquals(original.getImmutableMapOrNull(), original.asMap());
-
-        try {
-            original.getImmutableMapOrNull().put("abc", "xyz");
-            fail("Expected map to be immutable");
-        } catch (final UnsupportedOperationException ok) {
-            //ok
-        }
-    }
-
-    @Test
-    public void testPutInsertsInAlphabeticOrder() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.put("a", "avalue");
-        original.put("B", "Bvalue");
-        original.put("3", "3value");
-        original.put("c", "cvalue");
-        original.put("d", "dvalue");
-
-        assertEquals("avalue", original.getValue("a"));
-        assertEquals("avalue", original.getValueAt(2));
-
-        assertEquals("Bvalue", original.getValue("B"));
-        assertEquals("Bvalue", original.getValueAt(1));
-
-        assertEquals("3value", original.getValue("3"));
-        assertEquals("3value", original.getValueAt(0));
-
-        assertEquals("cvalue", original.getValue("c"));
-        assertEquals("cvalue", original.getValueAt(3));
-
-        assertEquals("dvalue", original.getValue("d"));
-        assertEquals("dvalue", original.getValueAt(4));
-    }
-
-    @Test
-    public void testPutValueInsertsInAlphabeticOrder() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-        original.putValue("c", "cvalue");
-        original.putValue("d", "dvalue");
-
-        assertEquals("avalue", original.getValue("a"));
-        assertEquals("avalue", original.getValueAt(2));
-
-        assertEquals("Bvalue", original.getValue("B"));
-        assertEquals("Bvalue", original.getValueAt(1));
-
-        assertEquals("3value", original.getValue("3"));
-        assertEquals("3value", original.getValueAt(0));
-
-        assertEquals("cvalue", original.getValue("c"));
-        assertEquals("cvalue", original.getValueAt(3));
-
-        assertEquals("dvalue", original.getValue("d"));
-        assertEquals("dvalue", original.getValueAt(4));
-    }
-
-    @Test
-    public void testNullKeysAllowed() {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-        original.putValue("c", "cvalue");
-        original.putValue("d", "dvalue");
-        assertEquals(5, original.size());
-        assertEquals("{3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
-
-        original.putValue(null, "nullvalue");
-        assertEquals(6, original.size());
-        assertEquals("{null=nullvalue, 3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
-
-        original.putValue(null, "otherNullvalue");
-        assertEquals("{null=otherNullvalue, 3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
-        assertEquals(6, original.size());
-
-        original.putValue(null, "nullvalue");
-        assertEquals(6, original.size());
-        assertEquals("{null=nullvalue, 3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
-
-        original.putValue(null, "abc");
-        assertEquals(6, original.size());
-        assertEquals("{null=abc, 3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
-    }
-
-    @Test
-    public void testNullKeysCopiedToAsMap() {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-        original.putValue("c", "cvalue");
-        original.putValue("d", "dvalue");
-        assertEquals(5, original.size());
-
-        HashMap<String, String> expected = new HashMap<>();
-        expected.put("a", "avalue");
-        expected.put("B", "Bvalue");
-        expected.put("3", "3value");
-        expected.put("c", "cvalue");
-        expected.put("d", "dvalue");
-        assertEquals("initial", expected, original.asMap());
-
-        original.putValue(null, "nullvalue");
-        expected.put(null, "nullvalue");
-        assertEquals(6, original.size());
-        assertEquals("with null key", expected, original.asMap());
-
-        original.putValue(null, "otherNullvalue");
-        expected.put(null, "otherNullvalue");
-        assertEquals(6, original.size());
-        assertEquals("with null key value2", expected, original.asMap());
-
-        original.putValue(null, "nullvalue");
-        expected.put(null, "nullvalue");
-        assertEquals(6, original.size());
-        assertEquals("with null key value1 again", expected, original.asMap());
-
-        original.putValue(null, "abc");
-        expected.put(null, "abc");
-        assertEquals(6, original.size());
-        assertEquals("with null key value3", expected, original.asMap());
-    }
-
-    @Test
-    public void testRemove() {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        assertEquals(1, original.size());
-        assertEquals("avalue", original.getValue("a"));
-
-        original.remove("a");
-        assertEquals(0, original.size());
-        assertNull("no a val", original.getValue("a"));
-
-        original.remove("B");
-        assertEquals(0, original.size());
-        assertNull("no B val", original.getValue("B"));
-    }
-
-    @Test
-    public void testNullValuesArePreserved() {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        assertEquals(1, original.size());
-        assertEquals("avalue", original.getValue("a"));
-
-        original.putValue("a", null);
-        assertEquals(1, original.size());
-        assertNull("no a val", original.getValue("a"));
-
-        original.putValue("B", null);
-        assertEquals(2, original.size());
-        assertNull("no B val", original.getValue("B"));
-    }
-
-    @Test
-    public void testGet() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.put("a", "avalue");
-        original.put("B", "Bvalue");
-        original.put("3", "3value");
-
-        assertEquals("avalue", original.get("a"));
-        assertEquals("Bvalue", original.get("B"));
-        assertEquals("3value", original.get("3"));
-
-        original.putValue("0", "0value");
-        assertEquals("0value", original.get("0"));
-        assertEquals("3value", original.get("3"));
-        assertEquals("Bvalue", original.get("B"));
-        assertEquals("avalue", original.get("a"));
-    }
-
-    @Test
-    public void testGetValue_GetValueAt() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-
-        assertEquals("avalue", original.getValue("a"));
-        assertEquals("avalue", original.getValueAt(2));
-
-        assertEquals("Bvalue", original.getValue("B"));
-        assertEquals("Bvalue", original.getValueAt(1));
-
-        assertEquals("3value", original.getValue("3"));
-        assertEquals("3value", original.getValueAt(0));
-
-        original.putValue("0", "0value");
-        assertEquals("0value", original.getValue("0"));
-        assertEquals("0value", original.getValueAt(0));
-        assertEquals("3value", original.getValue("3"));
-        assertEquals("3value", original.getValueAt(1));
-        assertEquals("Bvalue", original.getValue("B"));
-        assertEquals("Bvalue", original.getValueAt(2));
-        assertEquals("avalue", original.getValue("a"));
-        assertEquals("avalue", original.getValueAt(3));
-    }
-
-    @Test
-    public void testClear() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-        assertEquals(3, original.size());
-
-        original.clear();
-        assertEquals(0, original.size());
-
-        // ensure slots in the values array are nulled out
-        Field f = ArrayContextData.class.getDeclaredField("values");
-        f.setAccessible(true);
-        Object[] values = (Object[]) f.get(original);
-        for (int i = 0; i < values.length; i++) {
-            assertNull(values[i]);
-        }
-    }
-
-    @Test
-    public void testIndexOfKey() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        assertEquals(0, original.indexOfKey("a"));
-
-        original.putValue("B", "Bvalue");
-        assertEquals(1, original.indexOfKey("a"));
-        assertEquals(0, original.indexOfKey("B"));
-
-        original.putValue("3", "3value");
-        assertEquals(2, original.indexOfKey("a"));
-        assertEquals(1, original.indexOfKey("B"));
-        assertEquals(0, original.indexOfKey("3"));
-
-        original.putValue("A", "AAA");
-        assertEquals(3, original.indexOfKey("a"));
-        assertEquals(2, original.indexOfKey("B"));
-        assertEquals(1, original.indexOfKey("A"));
-        assertEquals(0, original.indexOfKey("3"));
-
-        original.putValue("C", "CCC");
-        assertEquals(4, original.indexOfKey("a"));
-        assertEquals(3, original.indexOfKey("C"));
-        assertEquals(2, original.indexOfKey("B"));
-        assertEquals(1, original.indexOfKey("A"));
-        assertEquals(0, original.indexOfKey("3"));
-
-        original.putValue("2", "222");
-        assertEquals(5, original.indexOfKey("a"));
-        assertEquals(4, original.indexOfKey("C"));
-        assertEquals(3, original.indexOfKey("B"));
-        assertEquals(2, original.indexOfKey("A"));
-        assertEquals(1, original.indexOfKey("3"));
-        assertEquals(0, original.indexOfKey("2"));
-    }
-
-    @Test
-    public void testContainsKey() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        assertFalse("a", original.containsKey("a"));
-        assertFalse("B", original.containsKey("B"));
-        assertFalse("3", original.containsKey("3"));
-        assertFalse("A", original.containsKey("A"));
-
-        original.putValue("a", "avalue");
-        assertTrue("a", original.containsKey("a"));
-        assertFalse("B", original.containsKey("B"));
-        assertFalse("3", original.containsKey("3"));
-        assertFalse("A", original.containsKey("A"));
-
-        original.putValue("B", "Bvalue");
-        assertTrue("a", original.containsKey("a"));
-        assertTrue("B", original.containsKey("B"));
-        assertFalse("3", original.containsKey("3"));
-        assertFalse("A", original.containsKey("A"));
-
-        original.putValue("3", "3value");
-        assertTrue("a", original.containsKey("a"));
-        assertTrue("B", original.containsKey("B"));
-        assertTrue("3", original.containsKey("3"));
-        assertFalse("A", original.containsKey("A"));
-
-        original.putValue("A", "AAA");
-        assertTrue("a", original.containsKey("a"));
-        assertTrue("B", original.containsKey("B"));
-        assertTrue("3", original.containsKey("3"));
-        assertTrue("A", original.containsKey("A"));
-    }
-
-    @Test
-    public void testGetValueAt() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        assertEquals("a", original.getKeyAt(0));
-        assertEquals("avalue", original.getValueAt(0));
-
-        original.putValue("B", "Bvalue");
-        assertEquals("B", original.getKeyAt(0));
-        assertEquals("Bvalue", original.getValueAt(0));
-        assertEquals("a", original.getKeyAt(1));
-        assertEquals("avalue", original.getValueAt(1));
-
-        original.putValue("3", "3value");
-        assertEquals("3", original.getKeyAt(0));
-        assertEquals("3value", original.getValueAt(0));
-        assertEquals("B", original.getKeyAt(1));
-        assertEquals("Bvalue", original.getValueAt(1));
-        assertEquals("a", original.getKeyAt(2));
-        assertEquals("avalue", original.getValueAt(2));
-    }
-
-    @Test
-    public void testSizeAndIsEmpty() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        assertEquals(0, original.size());
-        assertTrue("initial", original.isEmpty());
-
-        original.putValue("a", "avalue");
-        assertEquals(1, original.size());
-        assertFalse("size=" + original.size(), original.isEmpty());
-
-        original.putValue("B", "Bvalue");
-        assertEquals(2, original.size());
-        assertFalse("size=" + original.size(), original.isEmpty());
-
-        original.putValue("3", "3value");
-        assertEquals(3, original.size());
-        assertFalse("size=" + original.size(), original.isEmpty());
-
-        original.remove("B");
-        assertEquals(2, original.size());
-        assertFalse("size=" + original.size(), original.isEmpty());
-
-        original.remove("3");
-        assertEquals(1, original.size());
-        assertFalse("size=" + original.size(), original.isEmpty());
-
-        original.remove("a");
-        assertEquals(0, original.size());
-        assertTrue("size=" + original.size(), original.isEmpty());
-    }
-
-    @Test
-    public void testForEachBiConsumer() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-
-        original.forEach(new BiConsumer<String, String>() {
-            int count = 0;
-            @Override
-            public void accept(final String key, final String value) {
-                assertEquals("key", key, original.getKeyAt(count));
-                assertEquals("val", value, original.getValueAt(count));
-                count++;
-                assertTrue("count should not exceed size but was " + count, count <= original.size());
-            }
-        });
-    }
-
-    static class State {
-        ArrayContextData data;
-        int count;
-    }
-    static TriConsumer<String, String, State> COUNTER = new TriConsumer<String, String, State>() {
-        @Override
-        public void accept(final String key, final String value, final State state) {
-            assertEquals("key", key, state.data.getKeyAt(state.count));
-            assertEquals("val", value, state.data.getValueAt(state.count));
-            state.count++;
-            assertTrue("count should not exceed size but was " + state.count,
-                    state.count <= state.data.size());
-        }
-    };
-
-    @Test
-    public void testForEachTriConsumer() throws Exception {
-        final ArrayContextData original = new ArrayContextData();
-        original.putValue("a", "avalue");
-        original.putValue("B", "Bvalue");
-        original.putValue("3", "3value");
-
-        final State state = new State();
-        state.data = original;
-        original.forEach(COUNTER, state);
-        assertEquals(state.count, original.size());
-    }
-}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java b/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
new file mode 100644
index 0000000..e3ac0a4
--- /dev/null
+++ b/log4j-api/src/test/java/org/apache/logging/log4j/util/ArrayContextDataTest.java
@@ -0,0 +1,566 @@
+package org.apache.logging.log4j.util;/*
+ * 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.
+ */
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.lang.reflect.Field;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+/**
+ * Tests the ArrayContextData class.
+ */
+public class ArrayContextDataTest {
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConstructorDisallowsNegativeCapacity() throws Exception {
+        new ArrayContextData(-1);
+    }
+
+    @Test(expected = IllegalArgumentException.class)
+    public void testConstructorDisallowsZeroCapacity() throws Exception {
+        new ArrayContextData(0);
+    }
+
+    @Test
+    public void testConstructorIgnoresNull() throws Exception {
+        assertEquals(0, new ArrayContextData(null).size());
+    }
+
+    @Test
+    public void testToString() {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+        assertEquals("{3=3value, B=Bvalue, a=avalue}", original.toString());
+    }
+
+    @Test
+    public void testSerialization() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+
+        final byte[] binary = serialize(original);
+        final ArrayContextData copy = deserialize(binary);
+        assertEquals(original, copy);
+    }
+
+    private byte[] serialize(final ArrayContextData data) throws IOException {
+        final ByteArrayOutputStream arr = new ByteArrayOutputStream();
+        final ObjectOutputStream out = new ObjectOutputStream(arr);
+        out.writeObject(data);
+        return arr.toByteArray();
+    }
+
+    private ArrayContextData deserialize(final byte[] binary) throws IOException, ClassNotFoundException {
+        final ByteArrayInputStream inArr = new ByteArrayInputStream(binary);
+        final ObjectInputStream in = new ObjectInputStream(inArr);
+        final ArrayContextData result = (ArrayContextData) in.readObject();
+        return result;
+    }
+
+    @Test
+    public void testPutAll() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+
+        final ArrayContextData other = new ArrayContextData();
+        other.putAll(original);
+        assertEquals(original, other);
+
+        other.putValue("3", "otherValue");
+        assertNotEquals(original, other);
+
+        other.putValue("3", null);
+        assertNotEquals(original, other);
+
+        other.putValue("3", "3value");
+        assertEquals(original, other);
+    }
+
+    @Test
+    public void testEquals() {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+        assertEquals(original, original); // equal to itself
+
+        final ArrayContextData other = new ArrayContextData();
+        other.putValue("a", "avalue");
+        assertNotEquals(original, other);
+
+        other.putValue("B", "Bvalue");
+        assertNotEquals(original, other);
+
+        other.putValue("3", "3value");
+        assertEquals(original, other);
+
+        other.putValue("3", "otherValue");
+        assertNotEquals(original, other);
+
+        other.putValue("3", null);
+        assertNotEquals(original, other);
+
+        other.putValue("3", "3value");
+        assertEquals(original, other);
+    }
+
+    @Test
+    public void testAsMap() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+
+        final Map<String, Object> expected = new HashMap<>();
+        expected.put("a", "avalue");
+        expected.put("B", "Bvalue");
+        expected.put("3", "3value");
+
+        assertEquals(expected, original.asMap());
+    }
+
+    @Test
+    public void testGetCopyDelegatesToAsMap() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        assertEquals(original.getCopy(), original.asMap());
+
+        original.putValue("B", "Bvalue");
+        assertEquals(original.getCopy(), original.asMap());
+
+        original.putValue("3", "3value");
+        assertEquals(original.getCopy(), original.asMap());
+    }
+
+    @Test
+    public void testGetImmutableMapOrNull() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        assertEquals(original.getImmutableMapOrNull(), original.asMap());
+
+        original.putValue("B", "Bvalue");
+        assertEquals(original.getImmutableMapOrNull(), original.asMap());
+
+        original.putValue("3", "3value");
+        assertEquals(original.getImmutableMapOrNull(), original.asMap());
+
+        try {
+            original.getImmutableMapOrNull().put("abc", "xyz");
+            fail("Expected map to be immutable");
+        } catch (final UnsupportedOperationException ok) {
+            //ok
+        }
+    }
+
+    @Test
+    public void testPutInsertsInAlphabeticOrder() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "avalue");
+        original.put("B", "Bvalue");
+        original.put("3", "3value");
+        original.put("c", "cvalue");
+        original.put("d", "dvalue");
+
+        assertEquals("avalue", original.getValue("a"));
+        assertEquals("avalue", original.getValueAt(2));
+
+        assertEquals("Bvalue", original.getValue("B"));
+        assertEquals("Bvalue", original.getValueAt(1));
+
+        assertEquals("3value", original.getValue("3"));
+        assertEquals("3value", original.getValueAt(0));
+
+        assertEquals("cvalue", original.getValue("c"));
+        assertEquals("cvalue", original.getValueAt(3));
+
+        assertEquals("dvalue", original.getValue("d"));
+        assertEquals("dvalue", original.getValueAt(4));
+    }
+
+    @Test
+    public void testPutValueInsertsInAlphabeticOrder() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+        original.putValue("c", "cvalue");
+        original.putValue("d", "dvalue");
+
+        assertEquals("avalue", original.getValue("a"));
+        assertEquals("avalue", original.getValueAt(2));
+
+        assertEquals("Bvalue", original.getValue("B"));
+        assertEquals("Bvalue", original.getValueAt(1));
+
+        assertEquals("3value", original.getValue("3"));
+        assertEquals("3value", original.getValueAt(0));
+
+        assertEquals("cvalue", original.getValue("c"));
+        assertEquals("cvalue", original.getValueAt(3));
+
+        assertEquals("dvalue", original.getValue("d"));
+        assertEquals("dvalue", original.getValueAt(4));
+    }
+
+    @Test
+    public void testNullKeysAllowed() {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+        original.putValue("c", "cvalue");
+        original.putValue("d", "dvalue");
+        assertEquals(5, original.size());
+        assertEquals("{3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
+
+        original.putValue(null, "nullvalue");
+        assertEquals(6, original.size());
+        assertEquals("{null=nullvalue, 3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
+
+        original.putValue(null, "otherNullvalue");
+        assertEquals("{null=otherNullvalue, 3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
+        assertEquals(6, original.size());
+
+        original.putValue(null, "nullvalue");
+        assertEquals(6, original.size());
+        assertEquals("{null=nullvalue, 3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
+
+        original.putValue(null, "abc");
+        assertEquals(6, original.size());
+        assertEquals("{null=abc, 3=3value, B=Bvalue, a=avalue, c=cvalue, d=dvalue}", original.toString());
+    }
+
+    @Test
+    public void testNullKeysCopiedToAsMap() {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+        original.putValue("c", "cvalue");
+        original.putValue("d", "dvalue");
+        assertEquals(5, original.size());
+
+        HashMap<String, String> expected = new HashMap<>();
+        expected.put("a", "avalue");
+        expected.put("B", "Bvalue");
+        expected.put("3", "3value");
+        expected.put("c", "cvalue");
+        expected.put("d", "dvalue");
+        assertEquals("initial", expected, original.asMap());
+
+        original.putValue(null, "nullvalue");
+        expected.put(null, "nullvalue");
+        assertEquals(6, original.size());
+        assertEquals("with null key", expected, original.asMap());
+
+        original.putValue(null, "otherNullvalue");
+        expected.put(null, "otherNullvalue");
+        assertEquals(6, original.size());
+        assertEquals("with null key value2", expected, original.asMap());
+
+        original.putValue(null, "nullvalue");
+        expected.put(null, "nullvalue");
+        assertEquals(6, original.size());
+        assertEquals("with null key value1 again", expected, original.asMap());
+
+        original.putValue(null, "abc");
+        expected.put(null, "abc");
+        assertEquals(6, original.size());
+        assertEquals("with null key value3", expected, original.asMap());
+    }
+
+    @Test
+    public void testRemove() {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        assertEquals(1, original.size());
+        assertEquals("avalue", original.getValue("a"));
+
+        original.remove("a");
+        assertEquals(0, original.size());
+        assertNull("no a val", original.getValue("a"));
+
+        original.remove("B");
+        assertEquals(0, original.size());
+        assertNull("no B val", original.getValue("B"));
+    }
+
+    @Test
+    public void testNullValuesArePreserved() {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        assertEquals(1, original.size());
+        assertEquals("avalue", original.getValue("a"));
+
+        original.putValue("a", null);
+        assertEquals(1, original.size());
+        assertNull("no a val", original.getValue("a"));
+
+        original.putValue("B", null);
+        assertEquals(2, original.size());
+        assertNull("no B val", original.getValue("B"));
+    }
+
+    @Test
+    public void testGet() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.put("a", "avalue");
+        original.put("B", "Bvalue");
+        original.put("3", "3value");
+
+        assertEquals("avalue", original.get("a"));
+        assertEquals("Bvalue", original.get("B"));
+        assertEquals("3value", original.get("3"));
+
+        original.putValue("0", "0value");
+        assertEquals("0value", original.get("0"));
+        assertEquals("3value", original.get("3"));
+        assertEquals("Bvalue", original.get("B"));
+        assertEquals("avalue", original.get("a"));
+    }
+
+    @Test
+    public void testGetValue_GetValueAt() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+
+        assertEquals("avalue", original.getValue("a"));
+        assertEquals("avalue", original.getValueAt(2));
+
+        assertEquals("Bvalue", original.getValue("B"));
+        assertEquals("Bvalue", original.getValueAt(1));
+
+        assertEquals("3value", original.getValue("3"));
+        assertEquals("3value", original.getValueAt(0));
+
+        original.putValue("0", "0value");
+        assertEquals("0value", original.getValue("0"));
+        assertEquals("0value", original.getValueAt(0));
+        assertEquals("3value", original.getValue("3"));
+        assertEquals("3value", original.getValueAt(1));
+        assertEquals("Bvalue", original.getValue("B"));
+        assertEquals("Bvalue", original.getValueAt(2));
+        assertEquals("avalue", original.getValue("a"));
+        assertEquals("avalue", original.getValueAt(3));
+    }
+
+    @Test
+    public void testClear() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+        assertEquals(3, original.size());
+
+        original.clear();
+        assertEquals(0, original.size());
+
+        // ensure slots in the values array are nulled out
+        Field f = ArrayContextData.class.getDeclaredField("values");
+        f.setAccessible(true);
+        Object[] values = (Object[]) f.get(original);
+        for (int i = 0; i < values.length; i++) {
+            assertNull(values[i]);
+        }
+    }
+
+    @Test
+    public void testIndexOfKey() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        assertEquals(0, original.indexOfKey("a"));
+
+        original.putValue("B", "Bvalue");
+        assertEquals(1, original.indexOfKey("a"));
+        assertEquals(0, original.indexOfKey("B"));
+
+        original.putValue("3", "3value");
+        assertEquals(2, original.indexOfKey("a"));
+        assertEquals(1, original.indexOfKey("B"));
+        assertEquals(0, original.indexOfKey("3"));
+
+        original.putValue("A", "AAA");
+        assertEquals(3, original.indexOfKey("a"));
+        assertEquals(2, original.indexOfKey("B"));
+        assertEquals(1, original.indexOfKey("A"));
+        assertEquals(0, original.indexOfKey("3"));
+
+        original.putValue("C", "CCC");
+        assertEquals(4, original.indexOfKey("a"));
+        assertEquals(3, original.indexOfKey("C"));
+        assertEquals(2, original.indexOfKey("B"));
+        assertEquals(1, original.indexOfKey("A"));
+        assertEquals(0, original.indexOfKey("3"));
+
+        original.putValue("2", "222");
+        assertEquals(5, original.indexOfKey("a"));
+        assertEquals(4, original.indexOfKey("C"));
+        assertEquals(3, original.indexOfKey("B"));
+        assertEquals(2, original.indexOfKey("A"));
+        assertEquals(1, original.indexOfKey("3"));
+        assertEquals(0, original.indexOfKey("2"));
+    }
+
+    @Test
+    public void testContainsKey() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        assertFalse("a", original.containsKey("a"));
+        assertFalse("B", original.containsKey("B"));
+        assertFalse("3", original.containsKey("3"));
+        assertFalse("A", original.containsKey("A"));
+
+        original.putValue("a", "avalue");
+        assertTrue("a", original.containsKey("a"));
+        assertFalse("B", original.containsKey("B"));
+        assertFalse("3", original.containsKey("3"));
+        assertFalse("A", original.containsKey("A"));
+
+        original.putValue("B", "Bvalue");
+        assertTrue("a", original.containsKey("a"));
+        assertTrue("B", original.containsKey("B"));
+        assertFalse("3", original.containsKey("3"));
+        assertFalse("A", original.containsKey("A"));
+
+        original.putValue("3", "3value");
+        assertTrue("a", original.containsKey("a"));
+        assertTrue("B", original.containsKey("B"));
+        assertTrue("3", original.containsKey("3"));
+        assertFalse("A", original.containsKey("A"));
+
+        original.putValue("A", "AAA");
+        assertTrue("a", original.containsKey("a"));
+        assertTrue("B", original.containsKey("B"));
+        assertTrue("3", original.containsKey("3"));
+        assertTrue("A", original.containsKey("A"));
+    }
+
+    @Test
+    public void testGetValueAt() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        assertEquals("a", original.getKeyAt(0));
+        assertEquals("avalue", original.getValueAt(0));
+
+        original.putValue("B", "Bvalue");
+        assertEquals("B", original.getKeyAt(0));
+        assertEquals("Bvalue", original.getValueAt(0));
+        assertEquals("a", original.getKeyAt(1));
+        assertEquals("avalue", original.getValueAt(1));
+
+        original.putValue("3", "3value");
+        assertEquals("3", original.getKeyAt(0));
+        assertEquals("3value", original.getValueAt(0));
+        assertEquals("B", original.getKeyAt(1));
+        assertEquals("Bvalue", original.getValueAt(1));
+        assertEquals("a", original.getKeyAt(2));
+        assertEquals("avalue", original.getValueAt(2));
+    }
+
+    @Test
+    public void testSizeAndIsEmpty() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        assertEquals(0, original.size());
+        assertTrue("initial", original.isEmpty());
+
+        original.putValue("a", "avalue");
+        assertEquals(1, original.size());
+        assertFalse("size=" + original.size(), original.isEmpty());
+
+        original.putValue("B", "Bvalue");
+        assertEquals(2, original.size());
+        assertFalse("size=" + original.size(), original.isEmpty());
+
+        original.putValue("3", "3value");
+        assertEquals(3, original.size());
+        assertFalse("size=" + original.size(), original.isEmpty());
+
+        original.remove("B");
+        assertEquals(2, original.size());
+        assertFalse("size=" + original.size(), original.isEmpty());
+
+        original.remove("3");
+        assertEquals(1, original.size());
+        assertFalse("size=" + original.size(), original.isEmpty());
+
+        original.remove("a");
+        assertEquals(0, original.size());
+        assertTrue("size=" + original.size(), original.isEmpty());
+    }
+
+    @Test
+    public void testForEachBiConsumer() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+
+        original.forEach(new BiConsumer<String, String>() {
+            int count = 0;
+            @Override
+            public void accept(final String key, final String value) {
+                assertEquals("key", key, original.getKeyAt(count));
+                assertEquals("val", value, original.getValueAt(count));
+                count++;
+                assertTrue("count should not exceed size but was " + count, count <= original.size());
+            }
+        });
+    }
+
+    static class State {
+        ArrayContextData data;
+        int count;
+    }
+    static TriConsumer<String, String, State> COUNTER = new TriConsumer<String, String, State>() {
+        @Override
+        public void accept(final String key, final String value, final State state) {
+            assertEquals("key", key, state.data.getKeyAt(state.count));
+            assertEquals("val", value, state.data.getValueAt(state.count));
+            state.count++;
+            assertTrue("count should not exceed size but was " + state.count,
+                    state.count <= state.data.size());
+        }
+    };
+
+    @Test
+    public void testForEachTriConsumer() throws Exception {
+        final ArrayContextData original = new ArrayContextData();
+        original.putValue("a", "avalue");
+        original.putValue("B", "Bvalue");
+        original.putValue("3", "3value");
+
+        final State state = new State();
+        state.data = original;
+        original.forEach(COUNTER, state);
+        assertEquals(state.count, original.size());
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java
index 6661863..8f65b61 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataFactory.java
@@ -16,7 +16,7 @@
  */
 package org.apache.logging.log4j.core.impl;
 
-import org.apache.logging.log4j.spi.ArrayContextData;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.spi.MutableContextData;
 import org.apache.logging.log4j.util.PropertiesUtil;
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverterTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverterTest.java
index 00ee55f..32dc8e5 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverterTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataAttributeConverterTest.java
@@ -16,7 +16,7 @@
  */
 package org.apache.logging.log4j.core.appender.db.jpa.converter;
 
-import org.apache.logging.log4j.spi.ArrayContextData;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.spi.MutableContextData;
 import org.junit.After;
 import org.junit.Before;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverterTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverterTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverterTest.java
index 6930ed5..f486452 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverterTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/appender/db/jpa/converter/ContextDataJsonAttributeConverterTest.java
@@ -17,7 +17,7 @@
 package org.apache.logging.log4j.core.appender.db.jpa.converter;
 
 import org.apache.logging.log4j.spi.ContextData;
-import org.apache.logging.log4j.spi.ArrayContextData;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.spi.MutableContextData;
 import org.junit.After;
 import org.junit.Before;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
index 931fb15..b13bb8e 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
@@ -40,7 +40,7 @@ import org.apache.logging.log4j.core.util.DummyNanoClock;
 import org.apache.logging.log4j.message.Message;
 import org.apache.logging.log4j.message.ObjectMessage;
 import org.apache.logging.log4j.message.SimpleMessage;
-import org.apache.logging.log4j.spi.ArrayContextData;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.spi.MutableContextData;
 import org.apache.logging.log4j.util.Strings;
 import org.junit.AfterClass;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
index 0b2babf..70727a6 100644
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
@@ -29,7 +29,7 @@ import org.apache.logging.log4j.MarkerManager;
 import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.message.ParameterizedMessage;
 import org.apache.logging.log4j.message.SimpleMessage;
-import org.apache.logging.log4j.spi.ArrayContextData;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.spi.MutableContextData;
 import org.apache.logging.log4j.spi.MutableThreadContextStack;
 import org.junit.Test;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ArrayContextDataVsHashMapBenchmark.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ArrayContextDataVsHashMapBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ArrayContextDataVsHashMapBenchmark.java
index fae27de..24148e1 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ArrayContextDataVsHashMapBenchmark.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ArrayContextDataVsHashMapBenchmark.java
@@ -22,8 +22,8 @@ import java.util.Map;
 import java.util.Random;
 import java.util.concurrent.TimeUnit;
 
-import org.apache.logging.log4j.spi.ArrayContextData;
 import org.apache.logging.log4j.perf.nogc.OpenHashMapContextData;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.util.BiConsumer;
 import org.apache.logging.log4j.util.TriConsumer;
 import org.openjdk.jmh.annotations.Benchmark;

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/e6cf7c90/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
----------------------------------------------------------------------
diff --git a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
index cfa2eb7..6e07abb 100644
--- a/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
+++ b/log4j-perf/src/main/java/org/apache/logging/log4j/perf/jmh/ThreadContextBenchmark.java
@@ -30,7 +30,7 @@ import org.apache.logging.log4j.ThreadContextBenchmarkAccess;
 import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.core.impl.ContextDataInjector;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
-import org.apache.logging.log4j.spi.ArrayContextData;
+import org.apache.logging.log4j.util.ArrayContextData;
 import org.apache.logging.log4j.perf.nogc.CopyOnWriteOpenHashMapThreadContextMap;
 import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextMap;


[37/50] logging-log4j2 git commit: LOG4J2-1349 log event implementations should not try to modify shared copies of copy-on-write context data

Posted by rp...@apache.org.
LOG4J2-1349 log event implementations should not try to modify shared copies of copy-on-write context data


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/189f87d1
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/189f87d1
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/189f87d1

Branch: refs/heads/master
Commit: 189f87d138d9e7f7df05468c60a011f29298919e
Parents: 863cc12
Author: rpopma <rp...@apache.org>
Authored: Sun Sep 4 16:07:17 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Sep 4 16:07:17 2016 +0900

----------------------------------------------------------------------
 .../apache/logging/log4j/core/async/RingBufferLogEvent.java  | 8 +++++++-
 .../org/apache/logging/log4j/core/impl/Log4jLogEvent.java    | 7 ++++++-
 .../org/apache/logging/log4j/core/impl/MutableLogEvent.java  | 6 +++++-
 3 files changed, 18 insertions(+), 3 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/189f87d1/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
index d20be14..423578c 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/async/RingBufferLogEvent.java
@@ -381,9 +381,15 @@ public class RingBufferLogEvent implements LogEvent, ReusableMessage, CharSequen
         this.message = null;
         this.thrown = null;
         this.thrownProxy = null;
-        this.contextData.clear();
         this.contextStack = null;
         this.location = null;
+        if (contextData != null) {
+            if (contextData.isFrozen()) { // came from CopyOnWrite thread context
+                contextData = null;
+            } else {
+                contextData.clear();
+            }
+        }
 
         trimMessageText();
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/189f87d1/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index 8e152f3..19b7afd 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -132,8 +132,13 @@ public class Log4jLogEvent implements LogEvent {
                 if (other.getContextData() instanceof MutableContextData) {
                     this.contextData = (MutableContextData) other.getContextData();
                 } else {
-                    this.contextData.clear();
+                    if (this.contextData.isFrozen()) {
+                        this.contextData = ContextDataFactory.createContextData();
+                    } else {
+                        this.contextData.clear();
+                    }
                     this.contextData.putAll(other.getContextData());
+
                 }
                 this.thrownProxy = other.getThrownProxy();
                 this.source = other.getSource();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/189f87d1/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
index 97cb5d6..2a4f59b 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/MutableLogEvent.java
@@ -120,7 +120,11 @@ public class MutableLogEvent implements LogEvent, ReusableMessage {
         thrownProxy = null;
         source = null;
         if (contextData != null) {
-            contextData.clear();
+            if (contextData.isFrozen()) { // came from CopyOnWrite thread context
+                contextData = null;
+            } else {
+                contextData.clear();
+            }
         }
         contextStack = null;
 


[19/50] logging-log4j2 git commit: LOG4J2-1349 system properties disableThreadContextMap and disableThreadContext must work regardless of ThreadContextMap implementation

Posted by rp...@apache.org.
LOG4J2-1349 system properties disableThreadContextMap and disableThreadContext must work regardless of ThreadContextMap implementation


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/996d54b1
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/996d54b1
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/996d54b1

Branch: refs/heads/master
Commit: 996d54b18d8773074db0c0eb560d369cbcbda88a
Parents: 70807a5
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 22:53:37 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 22:53:37 2016 +0900

----------------------------------------------------------------------
 .../org/apache/logging/log4j/ThreadContext.java |  4 ++
 .../logging/log4j/spi/NoOpThreadContextMap.java | 65 ++++++++++++++++++++
 2 files changed, 69 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/996d54b1/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
index 0ca13ab..bc01bf8 100644
--- a/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/ThreadContext.java
@@ -31,6 +31,7 @@ import org.apache.logging.log4j.spi.CopyOnWriteSortedArrayThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextMap;
 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
 import org.apache.logging.log4j.spi.GarbageFreeSortedArrayThreadContextMap;
+import org.apache.logging.log4j.spi.NoOpThreadContextMap;
 import org.apache.logging.log4j.spi.Provider;
 import org.apache.logging.log4j.spi.ThreadContextMap;
 import org.apache.logging.log4j.spi.ThreadContextMap2;
@@ -259,6 +260,9 @@ public final class ThreadContext {
     }
 
     private static ThreadContextMap createThreadContextMap(final boolean doUseMap) {
+        if (!doUseMap) {
+            return new NoOpThreadContextMap();
+        }
         if (Constants.ENABLE_THREADLOCALS) {
             if (PropertiesUtil.getProperties().getBooleanProperty(GC_FREE_THREAD_CONTEXT_KEY)) {
                 return new GarbageFreeSortedArrayThreadContextMap();

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/996d54b1/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
new file mode 100644
index 0000000..a9f8a57
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/spi/NoOpThreadContextMap.java
@@ -0,0 +1,65 @@
+/*
+ * 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.spi;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * {@code ThreadContextMap} implementation used when either of system properties {@code disableThreadContextMap} or .
+ * {@code disableThreadContext} is {@code true}. This implementation does nothing.
+ *
+ * @since 2.7
+ */
+class NoOpThreadContextMap implements ThreadContextMap {
+    @Override
+    public void clear() {
+    }
+
+    @Override
+    public boolean containsKey(final String key) {
+        return false;
+    }
+
+    @Override
+    public String get(final String key) {
+        return null;
+    }
+
+    @Override
+    public Map<String, String> getCopy() {
+        return new HashMap<String, String>();
+    }
+
+    @Override
+    public Map<String, String> getImmutableMapOrNull() {
+        return null;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return true;
+    }
+
+    @Override
+    public void put(final String key, final String value) {
+    }
+
+    @Override
+    public void remove(final String key) {
+    }
+}


[12/50] logging-log4j2 git commit: Merge branch 'LOG4J2-1010&LOG4J2-1447-injectable-contextdata&better-datastructure' into LOG4J2-1349-gcfree-threadcontext

Posted by rp...@apache.org.
Merge branch 'LOG4J2-1010&LOG4J2-1447-injectable-contextdata&better-datastructure' into LOG4J2-1349-gcfree-threadcontext


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/463d4846
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/463d4846
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/463d4846

Branch: refs/heads/master
Commit: 463d484622c033e944a7cad1964f92fbb69c1aa9
Parents: 927251f 2a976a9
Author: rpopma <rp...@apache.org>
Authored: Wed Aug 31 00:11:55 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Wed Aug 31 00:11:55 2016 +0900

----------------------------------------------------------------------
 .../log4j/core/impl/ContextDataInjector.java    | 34 ++++++++++++++++++--
 1 file changed, 32 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/463d4846/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
----------------------------------------------------------------------
diff --cc log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
index e26616d,058ffe1..32b2caa
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ContextDataInjector.java
@@@ -35,13 -33,17 +35,17 @@@ import org.apache.logging.log4j.spi.Mut
   * in order to initialize log events with context data from any arbitrary context.
   * </p><p>
   * When providing a custom {@code ContextDataInjector}, be aware that the {@code ContextDataFactory} may be invoked
-  * multiple times by the various components in Log4j that need access to context data.
+  * multiple times and the various components in Log4j that need access to context data may each have their own instance
+  * of {@code ContextDataInjector}.
   * This includes the object(s) that populate log events, but also various lookups and filters that look at
   * context data to determine whether an event should be logged.
+  * </p><p>
+  * Implementors should take particular note of how the different methods in the interface have different thread-safety
+  * guarantees to enable optimal performance.
   * </p>
   *
 + * @see ContextData
   * @see ContextDataInjectorFactory
 - * @see org.apache.logging.log4j.core.ContextData
   * @see org.apache.logging.log4j.ThreadContext
   * @see ThreadContextDataInjector
   * @since 2.7


[30/50] logging-log4j2 git commit: LOG4J2-1349 obtain context data object through the factory, don't instantiate directly

Posted by rp...@apache.org.
LOG4J2-1349 obtain context data object through the factory, don't instantiate directly


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/112a2220
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/112a2220
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/112a2220

Branch: refs/heads/master
Commit: 112a22201a345f0b925e52d3f0a3caa1228565fe
Parents: fb7c8ea
Author: rpopma <rp...@apache.org>
Authored: Fri Sep 2 23:42:41 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Fri Sep 2 23:42:41 2016 +0900

----------------------------------------------------------------------
 .../java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java  | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/112a2220/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
index e45a405..8e152f3 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/Log4jLogEvent.java
@@ -26,7 +26,6 @@ import java.util.Objects;
 import org.apache.logging.log4j.Level;
 import org.apache.logging.log4j.Marker;
 import org.apache.logging.log4j.ThreadContext;
-import org.apache.logging.log4j.spi.ArrayContextData;
 import org.apache.logging.log4j.spi.ContextData;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.async.RingBufferLogEvent;
@@ -910,7 +909,9 @@ public class Log4jLogEvent implements LogEvent {
         }
 
         private static MutableContextData memento(final ContextData data) {
-            return new ArrayContextData(data); // TODO necessary to construct new instance?
+            MutableContextData result = ContextDataFactory.createContextData();
+            result.putAll(data);
+            return result;
         }
 
         /**


[07/50] logging-log4j2 git commit: LOG4J2-1349 implement the new ContextDataInjector::rawContextData() method introduced in LOG4J2-1010 in an efficient manner

Posted by rp...@apache.org.
LOG4J2-1349 implement the new ContextDataInjector::rawContextData() method introduced in LOG4J2-1010 in an efficient manner


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/1600bb2f
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/1600bb2f
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/1600bb2f

Branch: refs/heads/master
Commit: 1600bb2f705580a8a92f7ae8bb30ab7d7aed6d07
Parents: 7994789
Author: rpopma <rp...@apache.org>
Authored: Mon Aug 29 00:30:41 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Mon Aug 29 00:30:41 2016 +0900

----------------------------------------------------------------------
 .../log4j/core/impl/ThreadContextDataInjector.java    | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/1600bb2f/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
index 0e31a9a..65980f7 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ThreadContextDataInjector.java
@@ -25,6 +25,7 @@ import org.apache.logging.log4j.core.config.Property;
 import org.apache.logging.log4j.spi.ContextData;
 import org.apache.logging.log4j.spi.MutableContextData;
 import org.apache.logging.log4j.spi.MutableContextDataSupplier;
+import org.apache.logging.log4j.spi.ThreadContextMap;
 
 /**
  * {@code ThreadContextDataInjector} contains a number of strategies for copying key-value pairs from the various
@@ -71,7 +72,10 @@ public class ThreadContextDataInjector  {
 
         @Override
         public ContextData rawContextData() {
-            // TODO LOG4J2-1349: DefaultThreadContextMap itself implements the ContextData interface
+            final ThreadContextMap map = ThreadContextAccess.getThreadContextMap();
+            if (map instanceof ContextData) {
+                return (ContextData) map;
+            }
             final MutableContextData result = ContextDataFactory.createContextData();
             copyThreadContextMap(ThreadContext.getImmutableContext(), result);
             return result;
@@ -122,9 +126,7 @@ public class ThreadContextDataInjector  {
 
         @Override
         public ContextData rawContextData() {
-            // TODO LOG4J2-1349
-            //return ((AbstractGarbageFreeMutableThreadContext) ThreadContext.getThreadContextMap()).getContextData();
-            return null;
+            return ((MutableContextDataSupplier) ThreadContextAccess.getThreadContextMap()).getMutableContextData();
         }
     }
 
@@ -164,9 +166,7 @@ public class ThreadContextDataInjector  {
 
         @Override
         public ContextData rawContextData() {
-            // TODO LOG4J2-1349
-            //return ((AbstractCopyOnWriteMutableThreadContext) ThreadContext.getThreadContextMap()).getContextData();
-            return null;
+            return ((MutableContextDataSupplier) ThreadContextAccess.getThreadContextMap()).getMutableContextData();
         }
     }
 


[04/50] logging-log4j2 git commit: LOG4J2-1010 use the new ContextDataInjector::rawContextData() method to get fast access to the underlying context data in filters and lookups.

Posted by rp...@apache.org.
LOG4J2-1010 use the new ContextDataInjector::rawContextData() method to get fast access to the underlying context data in filters and lookups.


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/16eca7fc
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/16eca7fc
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/16eca7fc

Branch: refs/heads/master
Commit: 16eca7fce0d9874332e381f61b23fbfd2fd9d05e
Parents: d057eb2
Author: rpopma <rp...@apache.org>
Authored: Sun Aug 28 23:58:19 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Sun Aug 28 23:58:19 2016 +0900

----------------------------------------------------------------------
 .../logging/log4j/core/filter/DynamicThresholdFilter.java   | 9 +--------
 .../logging/log4j/core/filter/ThreadContextMapFilter.java   | 9 +--------
 .../apache/logging/log4j/core/lookup/ContextMapLookup.java  | 9 +--------
 3 files changed, 3 insertions(+), 24 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/16eca7fc/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
index d6146d7..e8bdf37 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/DynamicThresholdFilter.java
@@ -32,10 +32,8 @@ import org.apache.logging.log4j.core.config.plugins.Plugin;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
-import org.apache.logging.log4j.core.impl.ContextDataFactory;
 import org.apache.logging.log4j.core.impl.ContextDataInjector;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
-import org.apache.logging.log4j.core.impl.MutableContextData;
 import org.apache.logging.log4j.core.util.KeyValuePair;
 import org.apache.logging.log4j.message.Message;
 
@@ -158,12 +156,7 @@ public final class DynamicThresholdFilter extends AbstractFilter {
     }
 
     private ContextData currentContextData() {
-        return injector.injectContextData(null, reusableInstance());
-    }
-
-    private MutableContextData reusableInstance() {
-        // TODO if (Constants.ENABLE_THREADLOCALS) return thread-local instance
-        return ContextDataFactory.createContextData(); // creates temporary object
+        return injector.rawContextData();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/16eca7fc/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
index 35debf4..49b7044 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/filter/ThreadContextMapFilter.java
@@ -34,10 +34,8 @@ import org.apache.logging.log4j.core.config.plugins.PluginAliases;
 import org.apache.logging.log4j.core.config.plugins.PluginAttribute;
 import org.apache.logging.log4j.core.config.plugins.PluginElement;
 import org.apache.logging.log4j.core.config.plugins.PluginFactory;
-import org.apache.logging.log4j.core.impl.ContextDataFactory;
 import org.apache.logging.log4j.core.impl.ContextDataInjector;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
-import org.apache.logging.log4j.core.impl.MutableContextData;
 import org.apache.logging.log4j.core.util.KeyValuePair;
 import org.apache.logging.log4j.message.Message;
 
@@ -119,12 +117,7 @@ public class ThreadContextMapFilter extends MapFilter {
     }
 
     private ContextData currentContextData() {
-        return injector.injectContextData(null, reusableInstance());
-    }
-
-    private MutableContextData reusableInstance() {
-        // TODO if (Constants.ENABLE_THREADLOCALS) return thread-local instance
-        return ContextDataFactory.createContextData(); // creates temporary object
+        return injector.rawContextData();
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/16eca7fc/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
----------------------------------------------------------------------
diff --git a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
index 57818bc..bfbc5ea 100644
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/lookup/ContextMapLookup.java
@@ -20,10 +20,8 @@ import org.apache.logging.log4j.ThreadContext;
 import org.apache.logging.log4j.core.ContextData;
 import org.apache.logging.log4j.core.LogEvent;
 import org.apache.logging.log4j.core.config.plugins.Plugin;
-import org.apache.logging.log4j.core.impl.ContextDataFactory;
 import org.apache.logging.log4j.core.impl.ContextDataInjector;
 import org.apache.logging.log4j.core.impl.ContextDataInjectorFactory;
-import org.apache.logging.log4j.core.impl.MutableContextData;
 
 /**
  * Looks up keys from the context. By default this is the {@link ThreadContext}, but users may
@@ -46,12 +44,7 @@ public class ContextMapLookup implements StrLookup {
     }
 
     private ContextData currentContextData() {
-        return injector.injectContextData(null, reusableInstance());
-    }
-
-    private MutableContextData reusableInstance() {
-        // TODO if (Constants.ENABLE_THREADLOCALS) return thread-local instance
-        return ContextDataFactory.createContextData(); // creates temporary object
+        return injector.rawContextData();
     }
 
     /**


[43/50] logging-log4j2 git commit: Merge branch 'master' into LOG4J2-1349-gcfree-threadcontext

Posted by rp...@apache.org.
Merge branch 'master' into LOG4J2-1349-gcfree-threadcontext

Conflicts:
	log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java


Project: http://git-wip-us.apache.org/repos/asf/logging-log4j2/repo
Commit: http://git-wip-us.apache.org/repos/asf/logging-log4j2/commit/822f1063
Tree: http://git-wip-us.apache.org/repos/asf/logging-log4j2/tree/822f1063
Diff: http://git-wip-us.apache.org/repos/asf/logging-log4j2/diff/822f1063

Branch: refs/heads/master
Commit: 822f106382180fbf3c0d36fde71fe8ee5bdc04b8
Parents: 57eb251 53826ff
Author: rpopma <rp...@apache.org>
Authored: Thu Sep 8 22:45:22 2016 +0900
Committer: rpopma <rp...@apache.org>
Committed: Thu Sep 8 22:45:22 2016 +0900

----------------------------------------------------------------------
 .../config/Log4j1ConfigurationConverter.java    |    4 +-
 .../config/Log4j1ConfigurationFactory.java      |    2 +-
 .../log4j/config/Log4j1ConfigurationParser.java |   37 +-
 .../apache/log4j/layout/Log4j1XmlLayout.java    |   19 +-
 .../pattern/Log4j1NdcPatternConverter.java      |    2 +-
 .../log4j/layout/Log4j1XmlLayoutTest.java       |   18 +-
 .../pattern/Log4j1MdcPatternConverterTest.java  |   18 +-
 .../logging/log4j/message/LocalizedMessage.java |    2 +-
 .../log4j/message/ParameterizedMessage.java     |   13 +-
 .../log4j/spi/DefaultThreadContextMap.java      |    2 +-
 .../apache/logging/log4j/util/LoaderUtil.java   |   19 +
 .../apache/logging/log4j/ThreadContextTest.java |    1 -
 .../apache/logging/log4j/TraceLoggingTest.java  |   16 +-
 .../log4j/message/ParameterizedMessageTest.java |   24 +
 log4j-core/pom.xml                              |   12 +
 .../logging/log4j/core/AbstractLifeCycle.java   |    7 +-
 .../apache/logging/log4j/core/LifeCycle.java    |    2 +-
 .../logging/log4j/core/LoggerContext.java       |   60 +-
 .../log4j/core/appender/AbstractAppender.java   |    6 +-
 .../log4j/core/appender/AbstractManager.java    |  422 ++---
 .../appender/AbstractOutputStreamAppender.java  |  366 ++--
 .../core/appender/AbstractWriterAppender.java   |  248 +--
 .../log4j/core/appender/AsyncAppender.java      |  162 +-
 .../core/appender/ConfigurationFactoryData.java |    2 +-
 .../log4j/core/appender/ConsoleAppender.java    |    6 +-
 .../log4j/core/appender/FileAppender.java       |   10 +-
 .../log4j/core/appender/FileManager.java        |    6 +-
 .../core/appender/MemoryMappedFileAppender.java |    8 +-
 .../core/appender/MemoryMappedFileManager.java  |  716 ++++----
 .../core/appender/OutputStreamManager.java      |  685 +++----
 .../core/appender/RandomAccessFileAppender.java |    8 +-
 .../core/appender/RandomAccessFileManager.java  |  430 ++---
 .../core/appender/RollingFileAppender.java      |  744 ++++----
 .../RollingRandomAccessFileAppender.java        |    8 +-
 .../log4j/core/appender/SocketAppender.java     |   10 +-
 .../log4j/core/appender/WriterManager.java      |  300 +--
 .../appender/db/AbstractDatabaseAppender.java   |  280 +--
 .../appender/db/AbstractDatabaseManager.java    |  457 ++---
 .../db/jdbc/FactoryMethodConnectionSource.java  |    4 +-
 .../appender/db/jdbc/JdbcDatabaseManager.java   |  515 +++---
 .../log4j/core/appender/db/jpa/JpaAppender.java |    4 +-
 .../appender/db/jpa/JpaDatabaseManager.java     |  381 ++--
 .../converter/ThrowableAttributeConverter.java  |    4 +-
 .../log4j/core/appender/mom/JmsAppender.java    |  425 ++---
 .../log4j/core/appender/mom/JmsManager.java     |  347 ++--
 .../appender/mom/jeromq/JeroMqAppender.java     |  366 ++--
 .../core/appender/mom/jeromq/JeroMqManager.java |  442 ++---
 .../core/appender/mom/kafka/KafkaAppender.java  |  236 +--
 .../core/appender/mom/kafka/KafkaManager.java   |  172 +-
 .../core/appender/rewrite/RewriteAppender.java  |    5 -
 .../rolling/AbstractTriggeringPolicy.java       |   28 +
 .../rolling/CompositeTriggeringPolicy.java      |  169 +-
 .../appender/rolling/CronTriggeringPolicy.java  |   47 +-
 .../rolling/OnStartupTriggeringPolicy.java      |    5 +-
 .../core/appender/rolling/PatternProcessor.java |    2 +-
 .../appender/rolling/RollingFileManager.java    |  951 +++++-----
 .../rolling/RollingRandomAccessFileManager.java |  528 +++---
 .../rolling/SizeBasedTriggeringPolicy.java      |  207 ++-
 .../rolling/TimeBasedTriggeringPolicy.java      |    3 +-
 .../core/appender/rolling/TriggeringPolicy.java |    3 +-
 .../core/appender/routing/IdlePurgePolicy.java  |   13 +-
 .../core/appender/routing/RoutingAppender.java  |   10 +-
 .../core/async/ArrayBlockingQueueFactory.java   |   26 +
 .../log4j/core/async/AsyncLoggerConfig.java     |    8 +-
 .../core/async/AsyncLoggerConfigDisruptor.java  |   21 +-
 .../log4j/core/async/AsyncLoggerContext.java    |   10 +-
 .../log4j/core/async/AsyncLoggerDisruptor.java  |   30 +-
 .../log4j/core/async/BlockingQueueFactory.java  |   26 +
 .../core/async/DefaultAsyncQueueFullPolicy.java |   14 +-
 .../async/DisruptorBlockingQueueFactory.java    |   37 +
 .../core/async/JCToolsBlockingQueueFactory.java |  182 ++
 .../core/async/LinkedTransferQueueFactory.java  |   43 +
 .../core/config/AbstractConfiguration.java      |   21 +-
 .../core/config/ConfigurationScheduler.java     |   33 +-
 .../log4j/core/config/CronScheduledFuture.java  |    2 +-
 .../logging/log4j/core/config/LoggerConfig.java |    4 +-
 .../config/builder/impl/BuiltConfiguration.java |    2 +-
 .../impl/DefaultConfigurationBuilder.java       |   30 +-
 .../config/plugins/convert/TypeConverters.java  |    4 +-
 .../properties/PropertiesConfiguration.java     |    2 +-
 .../PropertiesConfigurationBuilder.java         |    3 +-
 .../PropertiesConfigurationFactory.java         |    2 +-
 .../log4j/core/filter/AbstractFilterable.java   |   24 +-
 .../log4j/core/filter/CompositeFilter.java      |    8 +-
 .../log4j/core/filter/LevelRangeFilter.java     |   15 +-
 .../log4j/core/impl/ExtendedClassInfo.java      |    2 +-
 .../core/impl/ExtendedStackTraceElement.java    |    4 +-
 .../core/impl/ReusableLogEventFactory.java      |    2 +-
 .../log4j/core/impl/ThrowableFormatOptions.java |  592 +++---
 .../logging/log4j/core/impl/ThrowableProxy.java | 1459 ++++++++-------
 .../log4j/core/net/DatagramSocketManager.java   |    2 +-
 .../logging/log4j/core/net/JndiManager.java     |  287 +--
 .../log4j/core/net/MulticastDnsAdvertiser.java  |    6 +-
 .../log4j/core/net/SslSocketManager.java        |    2 +-
 .../log4j/core/net/TcpSocketManager.java        |  652 +++----
 .../log4j/core/net/server/JmsServer.java        |  294 +--
 .../log4j/core/pattern/HtmlTextRenderer.java    |    6 +-
 .../log4j/core/pattern/JAnsiTextRenderer.java   |  664 +++----
 .../core/pattern/MessagePatternConverter.java   |   12 +-
 .../log4j/core/pattern/PlainTextRenderer.java   |    4 +-
 .../util/DefaultShutdownCallbackRegistry.java   |   13 +-
 .../log4j/core/util/ExecutorServices.java       |   81 +
 .../logging/log4j/core/util/JndiCloser.java     |  118 +-
 .../apache/logging/log4j/core/util/Loader.java  |   23 +-
 .../log4j/core/util/Log4jThreadFactory.java     |   36 +-
 .../log4j/core/util/OptionConverter.java        |    3 +-
 .../logging/log4j/core/util/TypeUtil.java       |    2 +-
 .../logging/log4j/core/util/WatchManager.java   |    6 +-
 .../core/util/datetime/FixedDateFormat.java     |    2 +-
 .../AsyncAppenderQueueFullPolicyTest.java       |    9 +-
 .../log4j/core/appender/AsyncAppenderTest.java  |   27 +-
 .../ConsoleAppenderJAnsiMessageMain.java        |  158 +-
 .../ConsoleAppenderJAnsiXExceptionMain.java     |  152 +-
 .../log4j/core/appender/FileAppenderTest.java   |   10 +-
 .../log4j/core/appender/HangingAppender.java    |    8 +-
 .../appender/JsonCompleteFileAppenderTest.java  |    2 +-
 .../core/appender/OutputStreamAppenderTest.java |    1 -
 .../log4j/core/appender/SocketAppenderTest.java |    6 +-
 .../appender/XmlCompleteFileAppenderTest.java   |    6 +-
 .../db/AbstractDatabaseAppenderTest.java        |    4 +-
 .../db/AbstractDatabaseManagerTest.java         |    2 +-
 .../rolling/OnStartupTriggeringPolicyTest.java  |    2 +-
 .../RollingAppenderCronOnceADayTest.java        |    6 +-
 .../rolling/RollingAppenderCronTest.java        |    4 +-
 .../rolling/RollingAppenderSizeTest.java        |    4 +-
 .../RollingAppenderUncompressedTest.java        |    2 +-
 .../routing/JsonRoutingAppender2Test.java       |    2 +-
 .../routing/JsonRoutingAppenderTest.java        |    2 +-
 .../routing/PropertiesRoutingAppenderTest.java  |    2 +-
 .../appender/routing/RoutingAppenderTest.java   |    2 +-
 .../routing/RoutingAppenderWithPurgingTest.java |    6 +-
 .../routing/RoutingDefaultAppenderTest.java     |    2 +-
 .../async/DefaultAsyncQueueFullPolicyTest.java  |    6 +-
 .../DiscardingAsyncQueueFullPolicyTest.java     |    8 +-
 .../core/async/RingBufferLogEventTest.java      |    2 +-
 .../core/async/perftest/AbstractRunQueue.java   |   91 +
 .../core/async/perftest/ResponseTimeTest.java   |    1 +
 .../core/async/perftest/RunConversant.java      |   31 +
 .../log4j/core/async/perftest/RunJCTools.java   |   32 +
 .../core/config/CompositeConfigurationTest.java |    4 +-
 .../core/config/CustomConfigurationTest.java    |    1 -
 .../builder/ConfigurationAssemblerTest.java     |    6 +-
 .../builder/ConfigurationBuilderTest.java       |    9 +-
 .../util/ResolverUtilCustomProtocolTest.java    |   34 +-
 .../config/plugins/util/ResolverUtilTest.java   |   30 +-
 .../log4j/core/filter/BurstFilterTest.java      |  283 ++-
 .../core/filter/DynamicThresholdFilterTest.java |    2 +-
 .../log4j/core/impl/Log4jLogEventTest.java      |    4 +-
 .../log4j/core/impl/MutableLogEventTest.java    |    2 +-
 .../core/impl/ReusableLogEventFactoryTest.java  |    8 +
 .../core/impl/ThrowableFormatOptionsTest.java   |   36 +-
 .../log4j/core/impl/ThrowableProxyTest.java     |   56 +
 .../core/layout/CsvParameterLayoutTest.java     |    4 +-
 .../log4j/core/layout/JsonLayoutTest.java       |    5 +-
 .../log4j/core/layout/Log4j2_1482_CoreTest.java |    2 +-
 .../log4j/core/layout/Log4j2_1482_Test.java     |   14 +-
 .../log4j/core/layout/Rfc5424LayoutTest.java    |    2 +-
 .../lookup/MainInputArgumentsMapLookup.java     |    2 +-
 .../core/lookup/ResourceBundleLookupTest.java   |    4 +-
 .../core/net/ssl/KeyStoreConfigurationTest.java |    2 +-
 .../net/ssl/TrustStoreConfigurationTest.java    |    2 +-
 .../pattern/MessagePatternConverterTest.java    |  210 +--
 .../log4j/core/pattern/PatternParserTest.java   |    2 +-
 .../logging/log4j/core/util/Profiler.java       |    5 +-
 .../apache/logging/log4j/junit/CleanFiles.java  |    2 +-
 .../logging/log4j/junit/CleanFolders.java       |    2 +-
 .../logging/log4j/junit/LoggerContextRule.java  |   18 +-
 .../junit/URLStreamHandlerFactoryRule.java      |    7 +-
 .../log4j/test/appender/BlockingAppender.java   |    9 +-
 .../log4j/test/appender/DeadlockAppender.java   |    9 +-
 .../log4j/test/appender/InMemoryAppender.java   |    2 +-
 .../log4j/test/appender/ListAppender.java       |    8 +-
 .../BlockingQueueFactory-ArrayBlockingQueue.xml |   40 +
 ...ckingQueueFactory-DisruptorBlockingQueue.xml |   40 +
 ...lockingQueueFactory-JCToolsBlockingQueue.xml |   40 +
 ...BlockingQueueFactory-LinkedTransferQueue.xml |   40 +
 .../test/resources/log4j-asynch-queue-full.xml  |    4 +-
 .../log4j/flume/appender/FlumeAppender.java     |   16 +-
 .../log4j/flume/appender/FlumeAvroManager.java  |    6 +-
 .../flume/appender/FlumeEmbeddedManager.java    |  554 +++---
 .../flume/appender/FlumePersistentManager.java  | 1703 +++++++++---------
 .../log4j/flume/appender/FlumeAppenderTest.java |    1 -
 .../flume/appender/FlumeEmbeddedAgentTest.java  |    4 +-
 .../appender/FlumeEmbeddedAppenderTest.java     |    4 +-
 .../appender/FlumePersistentAppenderTest.java   |    4 +-
 .../flume/appender/FlumePersistentPerf.java     |    4 +-
 .../nosql/appender/NoSqlDatabaseManager.java    |  440 ++---
 .../nosql/appender/couchdb/CouchDbProvider.java |    4 +-
 .../nosql/appender/mongodb/MongoDbProvider.java |    6 +-
 log4j-perf/pom.xml                              |    8 +
 .../perf/jmh/AsyncAppenderLog4j2Benchmark.java  |   37 +-
 .../AsyncAppenderLog4j2LocationBenchmark.java   |   23 +-
 .../perf5AsyncApndDsrptrNoLoc-noOpAppender.xml  |   32 +
 ...perf5AsyncApndDsrptrWithLoc-noOpAppender.xml |   32 +
 .../perf5AsyncApndMpscQNoLoc-noOpAppender.xml   |   32 +
 .../perf5AsyncApndMpscQWithLoc-noOpAppender.xml |   32 +
 .../perf5AsyncApndNoLoc-noOpAppender.xml        |    1 +
 .../perf5AsyncApndXferQNoLoc-noOpAppender.xml   |   32 +
 .../perf5AsyncApndXferQWithLoc-noOpAppender.xml |   32 +
 .../configuration/CustomConfiguration.java      |    4 +-
 .../logging/slf4j/Log4j2_1482_Slf4jTest.java    |    2 +-
 .../org/apache/logging/slf4j/MDCContextMap.java |    3 +-
 .../log4j/web/Log4jWebInitializerImpl.java      |  550 +++---
 pom.xml                                         |   14 +-
 src/changes/changes.xml                         |   24 +
 src/site/xdoc/manual/appenders.xml              |   84 +-
 206 files changed, 10749 insertions(+), 9297 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/822f1063/log4j-api/src/main/java/org/apache/logging/log4j/spi/DefaultThreadContextMap.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/822f1063/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
----------------------------------------------------------------------
diff --cc log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
index 62608a5,e6330bf..748148b
--- a/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
+++ b/log4j-core/src/main/java/org/apache/logging/log4j/core/impl/ReusableLogEventFactory.java
@@@ -75,8 -72,8 +75,8 @@@ public class ReusableLogEventFactory im
          result.setLevel(level == null ? Level.OFF : level);
          result.setMessage(message);
          result.setThrown(t);
 -        result.setContextMap(Log4jLogEvent.createMap(properties));
 +        result.setContextData(injector.injectContextData(properties, (MutableContextData) result.getContextData()));
-         result.setContextStack(ThreadContext.getDepth() == 0 ? null : ThreadContext.cloneStack());// mutable copy
+         result.setContextStack(ThreadContext.getDepth() == 0 ? ThreadContext.EMPTY_STACK : ThreadContext.cloneStack());// mutable copy
          result.setTimeMillis(message instanceof TimestampMessage
                  ? ((TimestampMessage) message).getTimestamp()
                  : CLOCK.currentTimeMillis());

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/822f1063/log4j-core/src/test/java/org/apache/logging/log4j/core/async/RingBufferLogEventTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/822f1063/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/Log4jLogEventTest.java
----------------------------------------------------------------------

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/822f1063/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
----------------------------------------------------------------------
diff --cc log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
index 70727a6,f6da5ef..a97dc6a
--- a/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
+++ b/log4j-core/src/test/java/org/apache/logging/log4j/core/impl/MutableLogEventTest.java
@@@ -217,9 -216,9 +217,9 @@@ public class MutableLogEventTest 
  
      @Test
      public void testJavaIoSerializableWithThrown() throws Exception {
-         final Error thrown = new InternalError("test error");
+         new InternalError("test error");
          final MutableLogEvent evt = new MutableLogEvent();
 -        evt.setContextMap(CONTEXTMAP);
 +        evt.setContextData(CONTEXT_DATA);
          evt.setContextStack(STACK);
          evt.setEndOfBatch(true);
          evt.setIncludeLocation(true);