From 29ea67406068f608ff88c1c96c105727d8808948 Mon Sep 17 00:00:00 2001 From: Collin Smith Date: Sat, 25 Jul 2020 17:35:36 -0700 Subject: [PATCH] OrderedMap impl of ThreadContextMap -- deprecated but may be of use later --- .../riiablo/log/OrderedThreadContextMap.java | 235 ++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 core/src/com/riiablo/log/OrderedThreadContextMap.java diff --git a/core/src/com/riiablo/log/OrderedThreadContextMap.java b/core/src/com/riiablo/log/OrderedThreadContextMap.java new file mode 100644 index 00000000..9e5df78e --- /dev/null +++ b/core/src/com/riiablo/log/OrderedThreadContextMap.java @@ -0,0 +1,235 @@ +package com.riiablo.log; + +import java.util.Map; +import org.apache.commons.collections4.OrderedMap; +import org.apache.commons.collections4.map.LinkedMap; +import org.apache.commons.collections4.map.UnmodifiableOrderedMap; +import org.apache.logging.log4j.spi.ThreadContextMap; +import org.apache.logging.log4j.util.BiConsumer; +import org.apache.logging.log4j.util.PropertiesUtil; +import org.apache.logging.log4j.util.ReadOnlyStringMap; +import org.apache.logging.log4j.util.TriConsumer; + +@Deprecated +public class OrderedThreadContextMap implements ThreadContextMap, ReadOnlyStringMap { + /** + * 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 boolean useMap; + private final ThreadLocal> localMap; + + private static boolean inheritableMap; + + static { + init(); + } + + static OrderedMap unmodifiableOrderedMap(OrderedMap map) { + return UnmodifiableOrderedMap.unmodifiableOrderedMap(map); + } + + // LOG4J2-479: by default, use a plain ThreadLocal, only use InheritableThreadLocal if configured. + // (This method is package protected for JUnit tests.) + static ThreadLocal> createThreadLocalMap(final boolean isMapEnabled) { + if (inheritableMap) { + return new InheritableThreadLocal>() { + @Override + protected OrderedMap childValue(final OrderedMap parentValue) { + return parentValue != null && isMapEnabled + ? unmodifiableOrderedMap(new LinkedMap<>(parentValue)) + : null; + } + }; + } + // if not inheritable, return plain ThreadLocal with null as initial value + return new ThreadLocal<>(); + } + + static void init() { + inheritableMap = PropertiesUtil.getProperties().getBooleanProperty(INHERITABLE_MAP); + } + + public OrderedThreadContextMap() { + this(true); + } + + public OrderedThreadContextMap(final boolean useMap) { + this.useMap = useMap; + this.localMap = createThreadLocalMap(useMap); + } + + @Override + public void put(final String key, final String value) { + if (!useMap) { + return; + } + OrderedMap map = localMap.get(); + map = map == null ? new LinkedMap(1) : new LinkedMap<>(map); + map.put(key, value); + localMap.set(unmodifiableOrderedMap(map)); + } + + public void putAll(final Map m) { + if (!useMap) { + return; + } + OrderedMap map = localMap.get(); + map = map == null ? new LinkedMap(m.size()) : new LinkedMap<>(map); + for (final Map.Entry e : m.entrySet()) { + map.put(e.getKey(), e.getValue()); + } + localMap.set(unmodifiableOrderedMap(map)); + } + + @Override + public String get(final String key) { + final Map map = localMap.get(); + return map == null ? null : map.get(key); + } + + @Override + public void remove(final String key) { + final Map map = localMap.get(); + if (map != null) { + final OrderedMap copy = new LinkedMap<>(map); + copy.remove(key); + localMap.set(unmodifiableOrderedMap(copy)); + } + } + + public void removeAll(final Iterable keys) { + final Map map = localMap.get(); + if (map != null) { + final OrderedMap copy = new LinkedMap<>(map); + for (final String key : keys) { + copy.remove(key); + } + localMap.set(unmodifiableOrderedMap(copy)); + } + } + + @Override + public void clear() { + localMap.remove(); + } + + @Override + public Map toMap() { + return getCopy(); + } + + @Override + public boolean containsKey(final String key) { + final Map map = localMap.get(); + return map != null && map.containsKey(key); + } + + @Override + public void forEach(final BiConsumer action) { + final Map map = localMap.get(); + if (map == null) { + return; + } + for (final Map.Entry entry : map.entrySet()) { + //BiConsumer should be able to handle values of any type V. In our case the values are of type String. + @SuppressWarnings("unchecked") + final + V value = (V) entry.getValue(); + action.accept(entry.getKey(), value); + } + } + + @Override + public void forEach(final TriConsumer action, final S state) { + final Map map = localMap.get(); + if (map == null) { + return; + } + for (final Map.Entry entry : map.entrySet()) { + //TriConsumer should be able to handle values of any type V. In our case the values are of type String. + @SuppressWarnings("unchecked") + final + V value = (V) entry.getValue(); + action.accept(entry.getKey(), value, state); + } + } + + @SuppressWarnings("unchecked") + @Override + public V getValue(final String key) { + final Map map = localMap.get(); + return (V) (map == null ? null : map.get(key)); + } + + @Override + public Map getCopy() { + final Map map = localMap.get(); + return map == null ? new LinkedMap() : new LinkedMap<>(map); + } + + @Override + public Map getImmutableMapOrNull() { + return localMap.get(); + } + + @Override + public boolean isEmpty() { + final Map map = localMap.get(); + return map == null || map.size() == 0; + } + + @Override + public int size() { + final Map map = localMap.get(); + return map == null ? 0 : map.size(); + } + + @Override + public String toString() { + final Map map = localMap.get(); + return map == null ? "{}" : map.toString(); + } + + @Override + public int hashCode() { + final int prime = 31; + int result = 1; + final Map map = this.localMap.get(); + result = prime * result + ((map == null) ? 0 : map.hashCode()); + result = prime * result + Boolean.valueOf(this.useMap).hashCode(); + return result; + } + + @Override + public boolean equals(final Object obj) { + if (this == obj) { + return true; + } + if (obj == null) { + return false; + } + if (obj instanceof OrderedThreadContextMap) { + final OrderedThreadContextMap other = (OrderedThreadContextMap) obj; + if (this.useMap != other.useMap) { + return false; + } + } + if (!(obj instanceof ThreadContextMap)) { + return false; + } + final ThreadContextMap other = (ThreadContextMap) obj; + final Map map = this.localMap.get(); + final Map otherMap = other.getImmutableMapOrNull(); + if (map == null) { + if (otherMap != null) { + return false; + } + } else if (!map.equals(otherMap)) { + return false; + } + return true; + } +}