1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.logging.log4j;
19
20 import org.apache.logging.log4j.message.ParameterizedMessage;
21
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.Collection;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.NoSuchElementException;
29
30
31
32
33
34
35
36
37 public final class ThreadContext {
38
39
40
41
42 public static final Map<String, String> EMPTY_MAP = new ImmutableMap();
43
44
45
46
47 public static final ContextStack EMPTY_STACK = new ImmutableStack();
48
49 private static final String DISABLE_MAP = "disableThreadContextMap";
50
51 private static final String DISABLE_STACK = "disableThreadContextStack";
52
53 private static final String DISABLE_ALL = "disableThreadContext";
54
55 private static boolean all = Boolean.getBoolean(DISABLE_ALL);
56
57 private static boolean useMap = !(Boolean.getBoolean(DISABLE_MAP) || all);
58
59 private static boolean useStack = !(Boolean.getBoolean(DISABLE_STACK) || all);
60
61 private static ThreadLocal<Map<String, String>> localMap =
62 new InheritableThreadLocal<Map<String, String>>() {
63 @Override
64 protected Map<String, String> childValue(Map<String, String> parentValue) {
65 return parentValue == null || !useMap ? null : new HashMap<String, String>(parentValue);
66 }
67 };
68
69 private static ThreadLocal<ContextStack> localStack = new ThreadLocal<ContextStack>();
70
71 private ThreadContext() {
72
73 }
74
75
76
77
78
79
80
81
82
83
84
85 public static void put(String key, String value) {
86 if (!useMap) {
87 return;
88 }
89 Map<String, String> map = localMap.get();
90 if (map == null) {
91 map = new HashMap<String, String>();
92 localMap.set(map);
93 }
94 map.put(key, value);
95 }
96
97
98
99
100
101
102
103
104 public static String get(String key) {
105 Map<String, String> map = localMap.get();
106 return map == null ? null : map.get(key);
107 }
108
109
110
111
112
113
114 public static void remove(String key) {
115 Map<String, String> map = localMap.get();
116 if (map != null) {
117 map.remove(key);
118 }
119 }
120
121
122
123
124 public static void clear() {
125 localMap.remove();
126 }
127
128
129
130
131
132
133 public static boolean containsKey(String key) {
134 Map<String, String> map = localMap.get();
135 return map == null ? false : map.containsKey(key);
136 }
137
138
139
140
141
142 public static Map<String, String> getContext() {
143 Map<String, String> map = localMap.get();
144 return map == null ? new HashMap<String, String>() : new HashMap<String, String>(map);
145 }
146
147
148
149
150
151 public static Map<String, String> getImmutableContext() {
152 Map<String, String> map = localMap.get();
153 return map == null ? new ImmutableMap() : new ImmutableMap(map);
154 }
155
156
157
158
159
160 public static boolean isEmpty() {
161 Map<String, String> map = localMap.get();
162 return map == null || map.size() == 0;
163 }
164
165
166
167
168 public static void clearStack() {
169 localStack.remove();
170 }
171
172
173
174
175
176 public static ContextStack cloneStack() {
177 ContextStack stack = localStack.get();
178 return stack == null ? new ThreadContextStack() : new ThreadContextStack(stack.asList());
179 }
180
181
182
183
184
185 public static ContextStack getImmutableStack() {
186 ContextStack stack = localStack.get();
187 return stack == null ? EMPTY_STACK : new ImmutableStack(stack.asList());
188 }
189
190
191
192
193
194 public static void setStack(Collection<String> stack) {
195 if (stack.size() == 0 || !useStack) {
196 return;
197 }
198 localStack.set(new ThreadContextStack(stack));
199 }
200
201
202
203
204
205
206
207 public static int getDepth() {
208 ContextStack stack = localStack.get();
209 return stack == null ? 0 : stack.getDepth();
210 }
211
212
213
214
215
216
217
218
219
220 public static String pop() {
221 ContextStack s = localStack.get();
222 if (s == null || s.getDepth() == 0) {
223 return "";
224 }
225 return s.pop();
226 }
227
228
229
230
231
232
233
234
235
236
237 public static String peek() {
238 ContextStack s = localStack.get();
239 if (s == null || s.getDepth() == 0) {
240 return "";
241 }
242 return s.peek();
243 }
244
245
246
247
248
249
250
251
252
253 public static void push(String message) {
254 if (!useStack) {
255 return;
256 }
257 ContextStack stack = localStack.get();
258 if (stack == null) {
259 stack = new ThreadContextStack();
260 localStack.set(stack);
261 }
262 stack.push(message);
263 }
264
265
266
267
268
269
270
271
272
273
274 public static void push(String message, Object... args) {
275 if (!useStack) {
276 return;
277 }
278 ContextStack stack = localStack.get();
279 if (stack == null) {
280 stack = new ThreadContextStack();
281 localStack.set(stack);
282 }
283 stack.push(ParameterizedMessage.format(message, args));
284 }
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304 public static void removeStack() {
305 localStack.remove();
306 }
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337 public static void trim(int depth) {
338 ContextStack stack = localStack.get();
339 if (stack != null) {
340 stack.trim(depth);
341 }
342 }
343
344
345
346
347 public interface ContextStack extends Serializable {
348
349
350
351
352 void clear();
353
354
355
356
357
358
359 String pop();
360
361
362
363
364
365 String peek();
366
367
368
369
370
371 void push(String message);
372
373
374
375
376
377 int getDepth();
378
379
380
381
382
383 List<String> asList();
384
385
386
387
388
389 void trim(int depth);
390
391
392
393
394
395 ContextStack copy();
396 }
397
398
399
400
401 private static class ThreadContextStack extends ArrayList<String> implements ContextStack {
402
403 private static final long serialVersionUID = 5050501L;
404
405 public ThreadContextStack() {
406 super();
407 }
408
409 public ThreadContextStack(Collection<String> collection) {
410 super(collection);
411 }
412
413 public String pop() {
414 int index = size() - 1;
415 if (index >= 0) {
416 String result = get(index);
417 remove(index);
418 return result;
419 }
420 throw new NoSuchElementException("The ThreadContext stack is empty");
421 }
422
423 public String peek() {
424 int index = size() - 1;
425 if (index >= 0) {
426 return get(index);
427 }
428 return null;
429 }
430
431 public void push(String message) {
432 add(message);
433 }
434
435 public int getDepth() {
436 return size();
437 }
438
439 public List<String> asList() {
440 return this;
441 }
442
443 public void trim(int depth) {
444 if (depth < 0) {
445 throw new IllegalArgumentException("Maximum stack depth cannot be negative");
446 }
447 while (size() > depth) {
448 remove(size() - 1);
449 }
450
451 }
452
453 public ContextStack copy() {
454 return new ThreadContextStack(this);
455 }
456 }
457
458
459
460
461 public static class ImmutableStack extends ThreadContextStack {
462
463 private static final long serialVersionUID = 5050502L;
464
465 public ImmutableStack() {
466 }
467
468 public ImmutableStack(Collection<String> collection) {
469 super(collection);
470 }
471
472 public ImmutableStack(ThreadContextStack stack) {
473 super(stack);
474 }
475
476 @Override
477 public void push(String message) {
478 throw new UnsupportedOperationException("Stack cannot be modified");
479 }
480
481 @Override
482 public void trim(int depth) {
483 throw new UnsupportedOperationException("Stack cannot be modified");
484 }
485 }
486
487
488
489
490 public static class ImmutableMap extends HashMap<String, String> {
491 private static final long serialVersionUID = 5050503L;
492
493 public ImmutableMap() {
494 super();
495 }
496
497 public ImmutableMap(Map<String, String> map) {
498 super(map);
499 }
500
501 @Override
502 public String put(String s, String s1) {
503 throw new UnsupportedOperationException("Map cannot be modified");
504 }
505
506 @Override
507 public void putAll(Map<? extends String, ? extends String> map) {
508 throw new UnsupportedOperationException("Map cannot be modified");
509 }
510
511 @Override
512 public String remove(Object o) {
513 throw new UnsupportedOperationException("Map cannot be modified");
514 }
515
516 @Override
517 public void clear() {
518 throw new UnsupportedOperationException("Map cannot be modified");
519 }
520 }
521 }