1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.logging.log4j.spi;
18
19 import java.util.Collections;
20 import java.util.HashMap;
21 import java.util.Map;
22
23 import org.apache.logging.log4j.util.BiConsumer;
24 import org.apache.logging.log4j.util.ReadOnlyStringMap;
25 import org.apache.logging.log4j.util.PropertiesUtil;
26 import org.apache.logging.log4j.util.TriConsumer;
27
28
29
30
31
32
33
34 public class DefaultThreadContextMap implements ThreadContextMap, ReadOnlyStringMap {
35 private static final long serialVersionUID = 8218007901108944053L;
36
37
38
39
40
41 public static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
42
43 private final boolean useMap;
44 private final ThreadLocal<Map<String, String>> localMap;
45
46 private static boolean inheritableMap;
47
48 static {
49 init();
50 }
51
52
53
54 static ThreadLocal<Map<String, String>> createThreadLocalMap(final boolean isMapEnabled) {
55 if (inheritableMap) {
56 return new InheritableThreadLocal<Map<String, String>>() {
57 @Override
58 protected Map<String, String> childValue(final Map<String, String> parentValue) {
59 return parentValue != null && isMapEnabled
60 ? Collections.unmodifiableMap(new HashMap<>(parentValue))
61 : null;
62 }
63 };
64 }
65
66 return new ThreadLocal<>();
67 }
68
69 static void init() {
70 inheritableMap = PropertiesUtil.getProperties().getBooleanProperty(INHERITABLE_MAP);
71 }
72
73 public DefaultThreadContextMap() {
74 this(true);
75 }
76
77 public DefaultThreadContextMap(final boolean useMap) {
78 this.useMap = useMap;
79 this.localMap = createThreadLocalMap(useMap);
80 }
81
82 @Override
83 public void put(final String key, final String value) {
84 if (!useMap) {
85 return;
86 }
87 Map<String, String> map = localMap.get();
88 map = map == null ? new HashMap<String, String>(1) : new HashMap<>(map);
89 map.put(key, value);
90 localMap.set(Collections.unmodifiableMap(map));
91 }
92
93 public void putAll(final Map<String, String> m) {
94 if (!useMap) {
95 return;
96 }
97 Map<String, String> map = localMap.get();
98 map = map == null ? new HashMap<String, String>(m.size()) : new HashMap<>(map);
99 for (final Map.Entry<String, String> e : m.entrySet()) {
100 map.put(e.getKey(), e.getValue());
101 }
102 localMap.set(Collections.unmodifiableMap(map));
103 }
104
105 @Override
106 public String get(final String key) {
107 final Map<String, String> map = localMap.get();
108 return map == null ? null : map.get(key);
109 }
110
111 @Override
112 public void remove(final String key) {
113 final Map<String, String> map = localMap.get();
114 if (map != null) {
115 final Map<String, String> copy = new HashMap<>(map);
116 copy.remove(key);
117 localMap.set(Collections.unmodifiableMap(copy));
118 }
119 }
120
121 public void removeAll(final Iterable<String> keys) {
122 final Map<String, String> map = localMap.get();
123 if (map != null) {
124 final Map<String, String> copy = new HashMap<>(map);
125 for (final String key : keys) {
126 copy.remove(key);
127 }
128 localMap.set(Collections.unmodifiableMap(copy));
129 }
130 }
131
132 @Override
133 public void clear() {
134 localMap.remove();
135 }
136
137 @Override
138 public Map<String, String> toMap() {
139 return getCopy();
140 }
141
142 @Override
143 public boolean containsKey(final String key) {
144 final Map<String, String> map = localMap.get();
145 return map != null && map.containsKey(key);
146 }
147
148 @Override
149 public <V> void forEach(final BiConsumer<String, ? super V> action) {
150 final Map<String, String> map = localMap.get();
151 if (map == null) {
152 return;
153 }
154 for (final Map.Entry<String, String> entry : map.entrySet()) {
155
156 @SuppressWarnings("unchecked")
157 final
158 V value = (V) entry.getValue();
159 action.accept(entry.getKey(), value);
160 }
161 }
162
163 @Override
164 public <V, S> void forEach(final TriConsumer<String, ? super V, S> action, final S state) {
165 final Map<String, String> map = localMap.get();
166 if (map == null) {
167 return;
168 }
169 for (final Map.Entry<String, String> entry : map.entrySet()) {
170
171 @SuppressWarnings("unchecked")
172 final
173 V value = (V) entry.getValue();
174 action.accept(entry.getKey(), value, state);
175 }
176 }
177
178 @SuppressWarnings("unchecked")
179 @Override
180 public <V> V getValue(final String key) {
181 final Map<String, String> map = localMap.get();
182 return (V) (map == null ? null : map.get(key));
183 }
184
185 @Override
186 public Map<String, String> getCopy() {
187 final Map<String, String> map = localMap.get();
188 return map == null ? new HashMap<String, String>() : new HashMap<>(map);
189 }
190
191 @Override
192 public Map<String, String> getImmutableMapOrNull() {
193 return localMap.get();
194 }
195
196 @Override
197 public boolean isEmpty() {
198 final Map<String, String> map = localMap.get();
199 return map == null || map.size() == 0;
200 }
201
202 @Override
203 public int size() {
204 final Map<String, String> map = localMap.get();
205 return map == null ? 0 : map.size();
206 }
207
208 @Override
209 public String toString() {
210 final Map<String, String> map = localMap.get();
211 return map == null ? "{}" : map.toString();
212 }
213
214 @Override
215 public int hashCode() {
216 final int prime = 31;
217 int result = 1;
218 final Map<String, String> map = this.localMap.get();
219 result = prime * result + ((map == null) ? 0 : map.hashCode());
220 result = prime * result + Boolean.valueOf(this.useMap).hashCode();
221 return result;
222 }
223
224 @Override
225 public boolean equals(final Object obj) {
226 if (this == obj) {
227 return true;
228 }
229 if (obj == null) {
230 return false;
231 }
232 if (obj instanceof DefaultThreadContextMap) {
233 final DefaultThreadContextMap other = (DefaultThreadContextMap) obj;
234 if (this.useMap != other.useMap) {
235 return false;
236 }
237 }
238 if (!(obj instanceof ThreadContextMap)) {
239 return false;
240 }
241 final ThreadContextMap other = (ThreadContextMap) obj;
242 final Map<String, String> map = this.localMap.get();
243 final Map<String, String> otherMap = other.getImmutableMapOrNull();
244 if (map == null) {
245 if (otherMap != null) {
246 return false;
247 }
248 } else if (!map.equals(otherMap)) {
249 return false;
250 }
251 return true;
252 }
253 }