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 @Override
113 public void clear() {
114 localMap.remove();
115 }
116
117 @Override
118 public Map<String, String> toMap() {
119 return getCopy();
120 }
121
122 @Override
123 public boolean containsKey(final String key) {
124 final Map<String, String> map = localMap.get();
125 return map != null && map.containsKey(key);
126 }
127
128 @Override
129 public <V> void forEach(final BiConsumer<String, ? super V> action) {
130 final Map<String, String> map = localMap.get();
131 if (map == null) {
132 return;
133 }
134 for (final Map.Entry<String, String> entry : map.entrySet()) {
135 action.accept(entry.getKey(), (V) entry.getValue());
136 }
137 }
138
139 @Override
140 public <V, S> void forEach(final TriConsumer<String, ? super V, S> action, final S state) {
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(), state);
147 }
148 }
149
150 @SuppressWarnings("unchecked")
151 @Override
152 public <V> V getValue(final String key) {
153 final Map<String, String> map = localMap.get();
154 return (V) (map == null ? null : map.get(key));
155 }
156
157 @Override
158 public Map<String, String> getCopy() {
159 final Map<String, String> map = localMap.get();
160 return map == null ? new HashMap<String, String>() : new HashMap<>(map);
161 }
162
163 @Override
164 public Map<String, String> getImmutableMapOrNull() {
165 return localMap.get();
166 }
167
168 @Override
169 public boolean isEmpty() {
170 final Map<String, String> map = localMap.get();
171 return map == null || map.size() == 0;
172 }
173
174 @Override
175 public int size() {
176 final Map<String, String> map = localMap.get();
177 return map == null ? 0 : map.size();
178 }
179
180 @Override
181 public String toString() {
182 final Map<String, String> map = localMap.get();
183 return map == null ? "{}" : map.toString();
184 }
185
186 @Override
187 public int hashCode() {
188 final int prime = 31;
189 int result = 1;
190 final Map<String, String> map = this.localMap.get();
191 result = prime * result + ((map == null) ? 0 : map.hashCode());
192 result = prime * result + Boolean.valueOf(this.useMap).hashCode();
193 return result;
194 }
195
196 @Override
197 public boolean equals(final Object obj) {
198 if (this == obj) {
199 return true;
200 }
201 if (obj == null) {
202 return false;
203 }
204 if (obj instanceof DefaultThreadContextMap) {
205 final DefaultThreadContextMap other = (DefaultThreadContextMap) obj;
206 if (this.useMap != other.useMap) {
207 return false;
208 }
209 }
210 if (!(obj instanceof ThreadContextMap)) {
211 return false;
212 }
213 final ThreadContextMap other = (ThreadContextMap) obj;
214 final Map<String, String> map = this.localMap.get();
215 final Map<String, String> otherMap = other.getImmutableMapOrNull();
216 if (map == null) {
217 if (otherMap != null) {
218 return false;
219 }
220 } else if (!map.equals(otherMap)) {
221 return false;
222 }
223 return true;
224 }
225 }