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