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 java.io.Serializable;
21 import java.util.AbstractCollection;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Iterator;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.NoSuchElementException;
28
29 import org.apache.logging.log4j.message.ParameterizedMessage;
30 import org.apache.logging.log4j.spi.DefaultThreadContextMap;
31 import org.apache.logging.log4j.spi.DefaultThreadContextStack;
32 import org.apache.logging.log4j.spi.NoOpThreadContextMap;
33 import org.apache.logging.log4j.spi.ReadOnlyThreadContextMap;
34 import org.apache.logging.log4j.spi.ThreadContextMap;
35 import org.apache.logging.log4j.spi.ThreadContextMap2;
36 import org.apache.logging.log4j.spi.CleanableThreadContextMap;
37 import org.apache.logging.log4j.spi.ThreadContextMapFactory;
38 import org.apache.logging.log4j.spi.ThreadContextStack;
39 import org.apache.logging.log4j.util.PropertiesUtil;
40
41
42
43
44
45
46
47
48
49 public final class ThreadContext {
50
51
52
53
54 private static class EmptyThreadContextStack extends AbstractCollection<String> implements ThreadContextStack {
55
56 private static final long serialVersionUID = 1L;
57
58 private static final Iterator<String> EMPTY_ITERATOR = new EmptyIterator<>();
59
60 @Override
61 public String pop() {
62 return null;
63 }
64
65 @Override
66 public String peek() {
67 return null;
68 }
69
70 @Override
71 public void push(final String message) {
72 throw new UnsupportedOperationException();
73 }
74
75 @Override
76 public int getDepth() {
77 return 0;
78 }
79
80 @Override
81 public List<String> asList() {
82 return Collections.emptyList();
83 }
84
85 @Override
86 public void trim(final int depth) {
87
88 }
89
90 @Override
91 public boolean equals(final Object o) {
92
93 return (o instanceof Collection) && ((Collection<?>) o).isEmpty();
94 }
95
96 @Override
97 public int hashCode() {
98
99 return 1;
100 }
101
102 @Override
103 public ContextStack copy() {
104 return this;
105 }
106
107 @Override
108 public <T> T[] toArray(final T[] a) {
109 throw new UnsupportedOperationException();
110 }
111
112 @Override
113 public boolean add(final String e) {
114 throw new UnsupportedOperationException();
115 }
116
117 @Override
118 public boolean containsAll(final Collection<?> c) {
119 return false;
120 }
121
122 @Override
123 public boolean addAll(final Collection<? extends String> c) {
124 throw new UnsupportedOperationException();
125 }
126
127 @Override
128 public boolean removeAll(final Collection<?> c) {
129 throw new UnsupportedOperationException();
130 }
131
132 @Override
133 public boolean retainAll(final Collection<?> c) {
134 throw new UnsupportedOperationException();
135 }
136
137 @Override
138 public Iterator<String> iterator() {
139 return EMPTY_ITERATOR;
140 }
141
142 @Override
143 public int size() {
144 return 0;
145 }
146
147 @Override
148 public ContextStack getImmutableStackOrNull() {
149 return this;
150 }
151 }
152
153
154
155
156
157
158 private static class EmptyIterator<E> implements Iterator<E> {
159
160 @Override
161 public boolean hasNext() {
162 return false;
163 }
164
165 @Override
166 public E next() {
167 throw new NoSuchElementException("This is an empty iterator!");
168 }
169
170 @Override
171 public void remove() {
172
173 }
174 }
175
176
177
178
179
180 @SuppressWarnings("PublicStaticCollectionField")
181
182 public static final Map<String, String> EMPTY_MAP = Collections.emptyMap();
183
184
185
186
187
188 @SuppressWarnings("PublicStaticCollectionField")
189 public static final ThreadContextStack EMPTY_STACK = new EmptyThreadContextStack();
190
191 private static final String DISABLE_MAP = "disableThreadContextMap";
192 private static final String DISABLE_STACK = "disableThreadContextStack";
193 private static final String DISABLE_ALL = "disableThreadContext";
194
195 private static boolean disableAll;
196 private static boolean useMap;
197 private static boolean useStack;
198 private static ThreadContextMap contextMap;
199 private static ThreadContextStack contextStack;
200 private static ReadOnlyThreadContextMap readOnlyContextMap;
201
202 static {
203 init();
204 }
205
206 private ThreadContext() {
207
208 }
209
210
211
212
213 static void init() {
214 ThreadContextMapFactory.init();
215 contextMap = null;
216 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
217 disableAll = managerProps.getBooleanProperty(DISABLE_ALL);
218 useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll);
219 useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
220
221 contextStack = new DefaultThreadContextStack(useStack);
222 if (!useMap) {
223 contextMap = new NoOpThreadContextMap();
224 } else {
225 contextMap = ThreadContextMapFactory.createThreadContextMap();
226 }
227 if (contextMap instanceof ReadOnlyThreadContextMap) {
228 readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap;
229 } else {
230 readOnlyContextMap = null;
231 }
232 }
233
234
235
236
237
238
239
240
241
242
243
244
245 public static void put(final String key, final String value) {
246 contextMap.put(key, value);
247 }
248
249
250
251
252
253
254
255
256
257
258 public static void putAll(final Map<String, String> m) {
259 if (contextMap instanceof ThreadContextMap2) {
260 ((ThreadContextMap2) contextMap).putAll(m);
261 } else if (contextMap instanceof DefaultThreadContextMap) {
262 ((DefaultThreadContextMap) contextMap).putAll(m);
263 } else {
264 for (final Map.Entry<String, String> entry: m.entrySet()) {
265 contextMap.put(entry.getKey(), entry.getValue());
266 }
267 }
268 }
269
270
271
272
273
274
275
276
277
278
279
280 public static String get(final String key) {
281 return contextMap.get(key);
282 }
283
284
285
286
287
288
289 public static void remove(final String key) {
290 contextMap.remove(key);
291 }
292
293
294
295
296
297
298
299
300 public static void removeAll(final Iterable<String> keys) {
301 if (contextMap instanceof CleanableThreadContextMap) {
302 ((CleanableThreadContextMap) contextMap).removeAll(keys);
303 } else if (contextMap instanceof DefaultThreadContextMap) {
304 ((DefaultThreadContextMap) contextMap).removeAll(keys);
305 } else {
306 for (final String key : keys) {
307 contextMap.remove(key);
308 }
309 }
310 }
311
312
313
314
315 public static void clearMap() {
316 contextMap.clear();
317 }
318
319
320
321
322 public static void clearAll() {
323 clearMap();
324 clearStack();
325 }
326
327
328
329
330
331
332
333 public static boolean containsKey(final String key) {
334 return contextMap.containsKey(key);
335 }
336
337
338
339
340
341
342 public static Map<String, String> getContext() {
343 return contextMap.getCopy();
344 }
345
346
347
348
349
350
351 public static Map<String, String> getImmutableContext() {
352 final Map<String, String> map = contextMap.getImmutableMapOrNull();
353 return map == null ? EMPTY_MAP : map;
354 }
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372 public static ReadOnlyThreadContextMap getThreadContextMap() {
373 return readOnlyContextMap;
374 }
375
376
377
378
379
380
381 public static boolean isEmpty() {
382 return contextMap.isEmpty();
383 }
384
385
386
387
388 public static void clearStack() {
389 contextStack.clear();
390 }
391
392
393
394
395
396
397 public static ContextStack cloneStack() {
398 return contextStack.copy();
399 }
400
401
402
403
404
405
406 public static ContextStack getImmutableStack() {
407 final ContextStack result = contextStack.getImmutableStackOrNull();
408 return result == null ? EMPTY_STACK : result;
409 }
410
411
412
413
414
415
416 public static void setStack(final Collection<String> stack) {
417 if (stack.isEmpty() || !useStack) {
418 return;
419 }
420 contextStack.clear();
421 contextStack.addAll(stack);
422 }
423
424
425
426
427
428
429
430
431 public static int getDepth() {
432 return contextStack.getDepth();
433 }
434
435
436
437
438
439
440
441
442
443
444
445 public static String pop() {
446 return contextStack.pop();
447 }
448
449
450
451
452
453
454
455
456
457
458
459 public static String peek() {
460 return contextStack.peek();
461 }
462
463
464
465
466
467
468
469
470
471
472 public static void push(final String message) {
473 contextStack.push(message);
474 }
475
476
477
478
479
480
481
482
483
484
485
486
487
488 public static void push(final String message, final Object... args) {
489 contextStack.push(ParameterizedMessage.format(message, args));
490 }
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508 public static void removeStack() {
509 contextStack.clear();
510 }
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544 public static void trim(final int depth) {
545 contextStack.trim(depth);
546 }
547
548
549
550
551 public interface ContextStack extends Serializable, Collection<String> {
552
553
554
555
556
557
558
559 String pop();
560
561
562
563
564
565
566 String peek();
567
568
569
570
571
572
573 void push(String message);
574
575
576
577
578
579
580 int getDepth();
581
582
583
584
585
586
587 List<String> asList();
588
589
590
591
592
593
594 void trim(int depth);
595
596
597
598
599
600
601 ContextStack copy();
602
603
604
605
606
607
608
609 ContextStack getImmutableStackOrNull();
610 }
611 }