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 contextMap = null;
215 final PropertiesUtil managerProps = PropertiesUtil.getProperties();
216 disableAll = managerProps.getBooleanProperty(DISABLE_ALL);
217 useStack = !(managerProps.getBooleanProperty(DISABLE_STACK) || disableAll);
218 useMap = !(managerProps.getBooleanProperty(DISABLE_MAP) || disableAll);
219
220 contextStack = new DefaultThreadContextStack(useStack);
221 if (!useMap) {
222 contextMap = new NoOpThreadContextMap();
223 } else {
224 contextMap = ThreadContextMapFactory.createThreadContextMap();
225 }
226 if (contextMap instanceof ReadOnlyThreadContextMap) {
227 readOnlyContextMap = (ReadOnlyThreadContextMap) contextMap;
228 }
229 }
230
231
232
233
234
235
236
237
238
239
240
241
242 public static void put(final String key, final String value) {
243 contextMap.put(key, value);
244 }
245
246
247
248
249
250
251
252
253
254
255 public static void putAll(final Map<String, String> m) {
256 if (contextMap instanceof ThreadContextMap2) {
257 ((ThreadContextMap2) contextMap).putAll(m);
258 } else if (contextMap instanceof DefaultThreadContextMap) {
259 ((DefaultThreadContextMap) contextMap).putAll(m);
260 } else {
261 for (final Map.Entry<String, String> entry: m.entrySet()) {
262 contextMap.put(entry.getKey(), entry.getValue());
263 }
264 }
265 }
266
267
268
269
270
271
272
273
274
275
276
277 public static String get(final String key) {
278 return contextMap.get(key);
279 }
280
281
282
283
284
285
286 public static void remove(final String key) {
287 contextMap.remove(key);
288 }
289
290
291
292
293
294
295
296
297 public static void removeAll(final Iterable<String> keys) {
298 if (contextMap instanceof CleanableThreadContextMap) {
299 ((CleanableThreadContextMap) contextMap).removeAll(keys);
300 } else if (contextMap instanceof DefaultThreadContextMap) {
301 ((DefaultThreadContextMap) contextMap).removeAll(keys);
302 } else {
303 for (final String key : keys) {
304 contextMap.remove(key);
305 }
306 }
307 }
308
309
310
311
312 public static void clearMap() {
313 contextMap.clear();
314 }
315
316
317
318
319 public static void clearAll() {
320 clearMap();
321 clearStack();
322 }
323
324
325
326
327
328
329
330 public static boolean containsKey(final String key) {
331 return contextMap.containsKey(key);
332 }
333
334
335
336
337
338
339 public static Map<String, String> getContext() {
340 return contextMap.getCopy();
341 }
342
343
344
345
346
347
348 public static Map<String, String> getImmutableContext() {
349 final Map<String, String> map = contextMap.getImmutableMapOrNull();
350 return map == null ? EMPTY_MAP : map;
351 }
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369 public static ReadOnlyThreadContextMap getThreadContextMap() {
370 return readOnlyContextMap;
371 }
372
373
374
375
376
377
378 public static boolean isEmpty() {
379 return contextMap.isEmpty();
380 }
381
382
383
384
385 public static void clearStack() {
386 contextStack.clear();
387 }
388
389
390
391
392
393
394 public static ContextStack cloneStack() {
395 return contextStack.copy();
396 }
397
398
399
400
401
402
403 public static ContextStack getImmutableStack() {
404 final ContextStack result = contextStack.getImmutableStackOrNull();
405 return result == null ? EMPTY_STACK : result;
406 }
407
408
409
410
411
412
413 public static void setStack(final Collection<String> stack) {
414 if (stack.isEmpty() || !useStack) {
415 return;
416 }
417 contextStack.clear();
418 contextStack.addAll(stack);
419 }
420
421
422
423
424
425
426
427
428 public static int getDepth() {
429 return contextStack.getDepth();
430 }
431
432
433
434
435
436
437
438
439
440
441
442 public static String pop() {
443 return contextStack.pop();
444 }
445
446
447
448
449
450
451
452
453
454
455
456 public static String peek() {
457 return contextStack.peek();
458 }
459
460
461
462
463
464
465
466
467
468
469 public static void push(final String message) {
470 contextStack.push(message);
471 }
472
473
474
475
476
477
478
479
480
481
482
483
484
485 public static void push(final String message, final Object... args) {
486 contextStack.push(ParameterizedMessage.format(message, args));
487 }
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505 public static void removeStack() {
506 contextStack.clear();
507 }
508
509
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 public static void trim(final int depth) {
542 contextStack.trim(depth);
543 }
544
545
546
547
548 public interface ContextStack extends Serializable, Collection<String> {
549
550
551
552
553
554
555
556 String pop();
557
558
559
560
561
562
563 String peek();
564
565
566
567
568
569
570 void push(String message);
571
572
573
574
575
576
577 int getDepth();
578
579
580
581
582
583
584 List<String> asList();
585
586
587
588
589
590
591 void trim(int depth);
592
593
594
595
596
597
598 ContextStack copy();
599
600
601
602
603
604
605
606 ContextStack getImmutableStackOrNull();
607 }
608 }