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.PropertiesUtil;
24
25
26
27
28
29
30
31 public class DefaultThreadContextMap implements ThreadContextMap {
32
33
34
35
36 public static final String INHERITABLE_MAP = "isThreadContextMapInheritable";
37
38 private final boolean useMap;
39 private final ThreadLocal<Map<String, String>> localMap;
40
41 public DefaultThreadContextMap(final boolean useMap) {
42 this.useMap = useMap;
43 this.localMap = createThreadLocalMap(useMap);
44 }
45
46
47
48 static ThreadLocal<Map<String, String>> createThreadLocalMap(final boolean isMapEnabled) {
49 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
50 final boolean inheritable = managerProps.getBooleanProperty(INHERITABLE_MAP);
51 if (inheritable) {
52 return new InheritableThreadLocal<Map<String, String>>() {
53 @Override
54 protected Map<String, String> childValue(final Map<String, String> parentValue) {
55 return parentValue != null && isMapEnabled
56 ? Collections.unmodifiableMap(new HashMap<String, String>(parentValue))
57 : null;
58 }
59 };
60 }
61
62 return new ThreadLocal<Map<String, String>>();
63 }
64
65
66
67
68
69
70
71
72
73
74
75 @Override
76 public void put(final String key, final String value) {
77 if (!useMap) {
78 return;
79 }
80 Map<String, String> map = localMap.get();
81 map = map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
82 map.put(key, value);
83 localMap.set(Collections.unmodifiableMap(map));
84 }
85
86
87
88
89
90
91
92
93 @Override
94 public String get(final String key) {
95 final Map<String, String> map = localMap.get();
96 return map == null ? null : map.get(key);
97 }
98
99
100
101
102
103
104 @Override
105 public void remove(final String key) {
106 final Map<String, String> map = localMap.get();
107 if (map != null) {
108 final Map<String, String> copy = new HashMap<String, String>(map);
109 copy.remove(key);
110 localMap.set(Collections.unmodifiableMap(copy));
111 }
112 }
113
114
115
116
117 @Override
118 public void clear() {
119 localMap.remove();
120 }
121
122
123
124
125
126
127 @Override
128 public boolean containsKey(final String key) {
129 final Map<String, String> map = localMap.get();
130 return map != null && map.containsKey(key);
131 }
132
133
134
135
136
137 @Override
138 public Map<String, String> getCopy() {
139 final Map<String, String> map = localMap.get();
140 return map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
141 }
142
143
144
145
146
147 @Override
148 public Map<String, String> getImmutableMapOrNull() {
149 return localMap.get();
150 }
151
152
153
154
155
156 @Override
157 public boolean isEmpty() {
158 final Map<String, String> map = localMap.get();
159 return map == null || map.size() == 0;
160 }
161
162 @Override
163 public String toString() {
164 final Map<String, String> map = localMap.get();
165 return map == null ? "{}" : map.toString();
166 }
167
168 @Override
169 public int hashCode() {
170 final int prime = 31;
171 int result = 1;
172 final Map<String, String> map = this.localMap.get();
173 result = prime * result + ((map == null) ? 0 : map.hashCode());
174 result = prime * result + (this.useMap ? 1231 : 1237);
175 return result;
176 }
177
178 @Override
179 public boolean equals(final Object obj) {
180 if (this == obj) {
181 return true;
182 }
183 if (obj == null) {
184 return false;
185 }
186 if (obj instanceof DefaultThreadContextMap) {
187 final DefaultThreadContextMap other = (DefaultThreadContextMap) obj;
188 if (this.useMap != other.useMap) {
189 return false;
190 }
191 }
192 if (!(obj instanceof ThreadContextMap)) {
193 return false;
194 }
195 final ThreadContextMap other = (ThreadContextMap) obj;
196 final Map<String, String> map = this.localMap.get();
197 final Map<String, String> otherMap = other.getImmutableMapOrNull();
198 if (map == null) {
199 if (otherMap != null) {
200 return false;
201 }
202 } else if (!map.equals(otherMap)) {
203 return false;
204 }
205 return true;
206 }
207 }