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 <[email protected]> Authored: Fri Oct 21 22:34:04 2016 +0200 Committer: Mikael Ståldal <[email protected]> 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>
