• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2004-2011 QOS.ch
3  * All rights reserved.
4  *
5  * Permission is hereby granted, free  of charge, to any person obtaining
6  * a  copy  of this  software  and  associated  documentation files  (the
7  * "Software"), to  deal in  the Software without  restriction, including
8  * without limitation  the rights to  use, copy, modify,  merge, publish,
9  * distribute,  sublicense, and/or sell  copies of  the Software,  and to
10  * permit persons to whom the Software  is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The  above  copyright  notice  and  this permission  notice  shall  be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE  SOFTWARE IS  PROVIDED  "AS  IS", WITHOUT  WARRANTY  OF ANY  KIND,
17  * EXPRESS OR  IMPLIED, INCLUDING  BUT NOT LIMITED  TO THE  WARRANTIES OF
18  * MERCHANTABILITY,    FITNESS    FOR    A   PARTICULAR    PURPOSE    AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21  * OF CONTRACT, TORT OR OTHERWISE,  ARISING FROM, OUT OF OR IN CONNECTION
22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23  *
24  */
25 package org.slf4j.helpers;
26 
27 import org.slf4j.spi.MDCAdapter;
28 
29 import java.util.*;
30 
31 /**
32  * Basic MDC implementation, which can be used with logging systems that lack
33  * out-of-the-box MDC support.
34  *
35  * This code was initially inspired by  logback's LogbackMDCAdapter. However,
36  * LogbackMDCAdapter has evolved and is now considerably more sophisticated.
37  *
38  * @author Ceki Gulcu
39  * @author Maarten Bosteels
40  * @author Lukasz Cwik
41  *
42  * @since 1.5.0
43  */
44 public class BasicMDCAdapter implements MDCAdapter {
45 
46     private final ThreadLocalMapOfStacks threadLocalMapOfDeques = new ThreadLocalMapOfStacks();
47 
48     private final InheritableThreadLocal<Map<String, String>> inheritableThreadLocalMap = new InheritableThreadLocal<Map<String, String>>() {
49         @Override
50         protected Map<String, String> childValue(Map<String, String> parentValue) {
51             if (parentValue == null) {
52                 return null;
53             }
54             return new HashMap<>(parentValue);
55         }
56     };
57 
58     /**
59      * Put a context value (the <code>val</code> parameter) as identified with
60      * the <code>key</code> parameter into the current thread's context map.
61      * Note that contrary to log4j, the <code>val</code> parameter can be null.
62      *
63      * <p>
64      * If the current thread does not have a context map it is created as a side
65      * effect of this call.
66      *
67      * @throws IllegalArgumentException
68      *                 in case the "key" parameter is null
69      */
put(String key, String val)70     public void put(String key, String val) {
71         if (key == null) {
72             throw new IllegalArgumentException("key cannot be null");
73         }
74         Map<String, String> map = inheritableThreadLocalMap.get();
75         if (map == null) {
76             map = new HashMap<>();
77             inheritableThreadLocalMap.set(map);
78         }
79         map.put(key, val);
80     }
81 
82     /**
83      * Get the context identified by the <code>key</code> parameter.
84      */
get(String key)85     public String get(String key) {
86         Map<String, String> map = inheritableThreadLocalMap.get();
87         if ((map != null) && (key != null)) {
88             return map.get(key);
89         } else {
90             return null;
91         }
92     }
93 
94     /**
95      * Remove the context identified by the <code>key</code> parameter.
96      */
remove(String key)97     public void remove(String key) {
98         Map<String, String> map = inheritableThreadLocalMap.get();
99         if (map != null) {
100             map.remove(key);
101         }
102     }
103 
104     /**
105      * Clear all entries in the MDC.
106      */
clear()107     public void clear() {
108         Map<String, String> map = inheritableThreadLocalMap.get();
109         if (map != null) {
110             map.clear();
111             inheritableThreadLocalMap.remove();
112         }
113     }
114 
115     /**
116      * Returns the keys in the MDC as a {@link Set} of {@link String}s The
117      * returned value can be null.
118      *
119      * @return the keys in the MDC
120      */
getKeys()121     public Set<String> getKeys() {
122         Map<String, String> map = inheritableThreadLocalMap.get();
123         if (map != null) {
124             return map.keySet();
125         } else {
126             return null;
127         }
128     }
129 
130     /**
131      * Return a copy of the current thread's context map.
132      * Returned value may be null.
133      *
134      */
getCopyOfContextMap()135     public Map<String, String> getCopyOfContextMap() {
136         Map<String, String> oldMap = inheritableThreadLocalMap.get();
137         if (oldMap != null) {
138             return new HashMap<>(oldMap);
139         } else {
140             return null;
141         }
142     }
143 
setContextMap(Map<String, String> contextMap)144     public void setContextMap(Map<String, String> contextMap) {
145         Map<String, String> copy = null;
146         if (contextMap != null) {
147             copy = new HashMap<>(contextMap);
148         }
149         inheritableThreadLocalMap.set(copy);
150     }
151 
152     @Override
pushByKey(String key, String value)153     public void pushByKey(String key, String value) {
154         threadLocalMapOfDeques.pushByKey(key, value);
155     }
156 
157     @Override
popByKey(String key)158     public String popByKey(String key) {
159         return threadLocalMapOfDeques.popByKey(key);
160      }
161 
162     @Override
getCopyOfDequeByKey(String key)163     public Deque<String> getCopyOfDequeByKey(String key) {
164         return threadLocalMapOfDeques.getCopyOfDequeByKey(key);
165     }
166     @Override
clearDequeByKey(String key)167     public void clearDequeByKey(String key) {
168         threadLocalMapOfDeques.clearDequeByKey(key);
169     }
170 }
171