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