You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@logging.apache.org by mi...@apache.org on 2016/10/21 20:34:22 UTC

logging-log4j2 git commit: Immutable empty StringMap

Repository: logging-log4j2
Updated Branches:
  refs/heads/LOG4J2-1645 [created] a2a78643b


Immutable empty StringMap


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

Branch: refs/heads/LOG4J2-1645
Commit: a2a78643b44ce1a01bb47fa0e796672e860f1db5
Parents: 22369cc
Author: Mikael St�ldal <mi...@staldal.nu>
Authored: Fri Oct 21 22:34:04 2016 +0200
Committer: Mikael St�ldal <mi...@staldal.nu>
Committed: Fri Oct 21 22:34:04 2016 +0200

----------------------------------------------------------------------
 .../CopyOnWriteSortedArrayThreadContextMap.java |   8 +-
 .../log4j/util/EmptyFrozenStringMap.java        | 105 +++++++++++++++++++
 .../log4j/core/impl/ContextDataFactory.java     |  12 +++
 .../core/impl/ThreadContextDataInjector.java    |  10 +-
 .../org/apache/logging/slf4j/MDCContextMap.java |   8 +-
 src/changes/changes.xml                         |   3 +
 6 files changed, 127 insertions(+), 19 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a2a78643/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 ca2e22d..cd6d707 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.EmptyFrozenStringMap;
 import org.apache.logging.log4j.util.ReadOnlyStringMap;
 import org.apache.logging.log4j.util.SortedArrayStringMap;
 import org.apache.logging.log4j.util.StringMap;
@@ -52,11 +53,6 @@ class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap2, CopyO
      */
     protected static final String PROPERTY_NAME_INITIAL_CAPACITY = "log4j2.ThreadContext.initial.capacity";
 
-    private static final StringMap EMPTY_CONTEXT_DATA = new SortedArrayStringMap();
-    static {
-        EMPTY_CONTEXT_DATA.freeze();
-    }
-
     private final ThreadLocal<StringMap> localMap;
 
     public CopyOnWriteSortedArrayThreadContextMap() {
@@ -168,7 +164,7 @@ class CopyOnWriteSortedArrayThreadContextMap implements ThreadContextMap2, CopyO
     @Override
     public StringMap getReadOnlyContextData() {
         final StringMap map = localMap.get();
-        return map == null ? EMPTY_CONTEXT_DATA : map;
+        return map == null ? EmptyFrozenStringMap.INSTANCE : map;
     }
 
     @Override

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a2a78643/log4j-api/src/main/java/org/apache/logging/log4j/util/EmptyFrozenStringMap.java
----------------------------------------------------------------------
diff --git a/log4j-api/src/main/java/org/apache/logging/log4j/util/EmptyFrozenStringMap.java b/log4j-api/src/main/java/org/apache/logging/log4j/util/EmptyFrozenStringMap.java
new file mode 100644
index 0000000..b0a3ff8
--- /dev/null
+++ b/log4j-api/src/main/java/org/apache/logging/log4j/util/EmptyFrozenStringMap.java
@@ -0,0 +1,105 @@
+/*
+ * 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.util.Collections;
+import java.util.Map;
+
+/**
+ * <em>Consider this class private.</em>
+ * Empty pre-frozen implementation of the {@link StringMap} interface.
+ *
+ * @since 2.7.1
+ */
+public class EmptyFrozenStringMap implements StringMap {
+
+    /**
+     * Singleton instance.
+     */
+    public static final EmptyFrozenStringMap INSTANCE = new EmptyFrozenStringMap();
+
+    private static final String FROZEN = "Frozen collection cannot be modified";
+
+    /**
+     * Private default constructor to enforce singleton.
+     */
+    private EmptyFrozenStringMap() {
+    }
+
+    @Override
+    public Map<String, String> toMap() {
+        return Collections.emptyMap();
+    }
+
+    @Override
+    public boolean containsKey(String key) {
+        return false;
+    }
+
+    @Override
+    public <V> void forEach(BiConsumer<String, ? super V> action) {
+    }
+
+    @Override
+    public <V, S> void forEach(TriConsumer<String, ? super V, S> action, S state) {
+    }
+
+    @Override
+    public <V> V getValue(String key) {
+        return null;
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return true;
+    }
+
+    @Override
+    public int size() {
+        return 0;
+    }
+
+    @Override
+    public void clear() {
+    }
+
+    @Override
+    public void freeze() {
+    }
+
+    @Override
+    public boolean isFrozen() {
+        return true;
+    }
+
+    @Override
+    public void putAll(ReadOnlyStringMap source) {
+        if (source == this || source.isEmpty()) { // throw NPE if null
+            return; // this.putAll(this) does not modify this collection
+        }
+        throw new UnsupportedOperationException(FROZEN);
+    }
+
+    @Override
+    public void putValue(String key, Object value) {
+        throw new UnsupportedOperationException(FROZEN);
+    }
+
+    @Override
+    public void remove(String key) {
+    }
+}

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a2a78643/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 b417072..fc85932 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
@@ -20,6 +20,7 @@ import java.lang.reflect.Constructor;
 
 import org.apache.logging.log4j.core.ContextDataInjector;
 import org.apache.logging.log4j.core.LogEvent;
+import org.apache.logging.log4j.util.EmptyFrozenStringMap;
 import org.apache.logging.log4j.util.LoaderUtil;
 import org.apache.logging.log4j.util.PropertiesUtil;
 import org.apache.logging.log4j.util.SortedArrayStringMap;
@@ -92,4 +93,15 @@ public class ContextDataFactory {
             return new SortedArrayStringMap(initialCapacity);
         }
     }
+
+    /**
+     * An empty pre-frozen StringMap. The returned object may be shared.
+     * <p>
+     * Not affected by the system property {@code "log4j2.ContextData"}.
+     *
+     * @return an empty pre-frozen StringMap
+     */
+    public static StringMap emptyFrozenContextData() {
+        return EmptyFrozenStringMap.INSTANCE;
+    }
 }

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a2a78643/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 210c5da..192fe4d 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
@@ -43,7 +43,7 @@ import org.apache.logging.log4j.util.StringMap;
  * @see ContextDataInjectorFactory
  * @since 2.7
  */
-public class ThreadContextDataInjector  {
+public class ThreadContextDataInjector {
 
     /**
      * Default {@code ContextDataInjector} for the legacy {@code Map<String, String>}-based ThreadContext (which is
@@ -52,10 +52,6 @@ public class ThreadContextDataInjector  {
      * This injector always puts key-value pairs into the specified reusable StringMap.
      */
     public static class ForDefaultThreadContextMap implements ContextDataInjector {
-        private static final StringMap EMPTY_STRING_MAP = ContextDataFactory.createContextData();
-        static {
-            EMPTY_STRING_MAP.freeze();
-        }
 
         /**
          * Puts key-value pairs from both the specified list of properties as well as the thread context into the
@@ -77,7 +73,7 @@ public class ThreadContextDataInjector  {
             if (props == null || props.isEmpty()) {
                 // this will replace the LogEvent's context data with the returned instance.
                 // NOTE: must mark as frozen or downstream components may attempt to modify (UnsupportedOperationEx)
-                return copy.isEmpty() ? EMPTY_STRING_MAP : frozenStringMap(copy);
+                return copy.isEmpty() ? ContextDataFactory.emptyFrozenContextData() : frozenStringMap(copy);
             }
             // If the list of Properties is non-empty we need to combine the properties and the ThreadContext
             // data. Note that we cannot reuse the specified StringMap: some Loggers may have properties defined
@@ -106,7 +102,7 @@ public class ThreadContextDataInjector  {
             if (map instanceof ReadOnlyStringMap) {
                 return (ReadOnlyStringMap) map;
             }
-            return map.isEmpty() ? EMPTY_STRING_MAP : new JdkMapAdapterStringMap(map.getImmutableMapOrNull());
+            return map.isEmpty() ? ContextDataFactory.emptyFrozenContextData() : new JdkMapAdapterStringMap(map.getImmutableMapOrNull());
         }
     }
 

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a2a78643/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
----------------------------------------------------------------------
diff --git a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
index 6b0f3ae..cb3a349 100644
--- a/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
+++ b/log4j-to-slf4j/src/main/java/org/apache/logging/slf4j/MDCContextMap.java
@@ -19,6 +19,7 @@ package org.apache.logging.slf4j;
 import java.util.Map;
 import java.util.Map.Entry;
 
+import org.apache.logging.log4j.util.EmptyFrozenStringMap;
 import org.apache.logging.log4j.util.StringMap;
 import org.apache.logging.log4j.spi.ThreadContextMap2;
 import org.apache.logging.log4j.util.SortedArrayStringMap;
@@ -29,11 +30,6 @@ import org.slf4j.MDC;
  */
 public class MDCContextMap implements ThreadContextMap2 {
 
-    private static final StringMap EMPTY_CONTEXT_DATA = new SortedArrayStringMap();
-    static {
-        EMPTY_CONTEXT_DATA.freeze();
-    }
-
     @Override
     public void put(final String key, final String value) {
         MDC.put(key, value);
@@ -87,7 +83,7 @@ public class MDCContextMap implements ThreadContextMap2 {
     public StringMap getReadOnlyContextData() {
         final Map<String, String> copy = getCopy();
         if (copy.isEmpty()) {
-            return EMPTY_CONTEXT_DATA;
+            return EmptyFrozenStringMap.INSTANCE;
         }
         final StringMap result = new SortedArrayStringMap();
         for (Entry<String, String> entry : copy.entrySet()) {

http://git-wip-us.apache.org/repos/asf/logging-log4j2/blob/a2a78643/src/changes/changes.xml
----------------------------------------------------------------------
diff --git a/src/changes/changes.xml b/src/changes/changes.xml
index 2922511..412164a 100644
--- a/src/changes/changes.xml
+++ b/src/changes/changes.xml
@@ -24,6 +24,9 @@
   </properties>
   <body>
     <release version="2.7.1" date="2016-MM-DD" description="GA Release 2.7.1">
+      <action issue="LOG4J2-1645" dev="mikes" type="fix">
+        Immutable empty StringMap.
+      </action>
       <action issue="LOG4J2-1623" dev="mikes" type="fix">
         Configurable JVM shutdown hook timeout.
       </action>