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 import java.util.Map;
31 
32 /**
33  * Basic MDC implementation, which can be used with logging systems that lack
34  * out-of-the-box MDC support.
35  *
36  * This code was initially inspired by  logback's LogbackMDCAdapter. However,
37  * LogbackMDCAdapter has evolved and is now considerably more sophisticated.
38  *
39  * @author Ceki Gulcu
40  * @author Maarten Bosteels
41  *
42  * @since 1.5.0
43  */
44 public class BasicMDCAdapter implements MDCAdapter {
45 
46     private InheritableThreadLocal<Map<String, String>> inheritableThreadLocal = new InheritableThreadLocal<Map<String, String>>();
47 
isJDK14()48     static boolean isJDK14() {
49         try {
50             String javaVersion = System.getProperty("java.version");
51             return javaVersion.startsWith("1.4");
52         } catch (SecurityException se) {
53             // punt and assume JDK 1.5 or later
54             return false;
55         }
56     }
57 
58     static boolean IS_JDK14 = isJDK14();
59 
60     /**
61      * Put a context value (the <code>val</code> parameter) as identified with
62      * the <code>key</code> parameter into the current thread's context map.
63      * Note that contrary to log4j, the <code>val</code> parameter can be null.
64      *
65      * <p>
66      * If the current thread does not have a context map it is created as a side
67      * effect of this call.
68      *
69      * @throws IllegalArgumentException
70      *                 in case the "key" parameter is null
71      */
put(String key, String val)72     public void put(String key, String val) {
73         if (key == null) {
74             throw new IllegalArgumentException("key cannot be null");
75         }
76         Map<String, String> map = (Map<String, String>) inheritableThreadLocal.get();
77         if (map == null) {
78             map = Collections.<String, String> synchronizedMap(new HashMap<String, String>());
79             inheritableThreadLocal.set(map);
80         }
81         map.put(key, val);
82     }
83 
84     /**
85      * Get the context identified by the <code>key</code> parameter.
86      */
get(String key)87     public String get(String key) {
88         Map<String, String> Map = (Map<String, String>) inheritableThreadLocal.get();
89         if ((Map != null) && (key != null)) {
90             return (String) Map.get(key);
91         } else {
92             return null;
93         }
94     }
95 
96     /**
97      * Remove the the context identified by the <code>key</code> parameter.
98      */
remove(String key)99     public void remove(String key) {
100         Map<String, String> map = (Map<String, String>) inheritableThreadLocal.get();
101         if (map != null) {
102             map.remove(key);
103         }
104     }
105 
106     /**
107      * Clear all entries in the MDC.
108      */
clear()109     public void clear() {
110         Map<String, String> map = (Map<String, String>) inheritableThreadLocal.get();
111         if (map != null) {
112             map.clear();
113             // the InheritableThreadLocal.remove method was introduced in JDK 1.5
114             // Thus, invoking clear() on previous JDK 1.4 will fail
115             if (isJDK14()) {
116                 inheritableThreadLocal.set(null);
117             } else {
118                 inheritableThreadLocal.remove();
119             }
120         }
121     }
122 
123     /**
124      * Returns the keys in the MDC as a {@link Set} of {@link String}s The
125      * returned value can be null.
126      *
127      * @return the keys in the MDC
128      */
getKeys()129     public Set<String> getKeys() {
130         Map<String, String> map = (Map<String, String>) inheritableThreadLocal.get();
131         if (map != null) {
132             return map.keySet();
133         } else {
134             return null;
135         }
136     }
137 
138     /**
139      * Return a copy of the current thread's context map.
140      * Returned value may be null.
141      *
142      */
getCopyOfContextMap()143     public Map<String, String> getCopyOfContextMap() {
144         Map<String, String> oldMap = (Map<String, String>) inheritableThreadLocal.get();
145         if (oldMap != null) {
146             Map<String, String> newMap = Collections.<String, String> synchronizedMap(new HashMap<String, String>());
147             synchronized (oldMap) {
148                 newMap.putAll(oldMap);
149             }
150             return newMap;
151         } else {
152             return null;
153         }
154     }
155 
setContextMap(Map<String, String> contextMap)156     public void setContextMap(Map<String, String> contextMap) {
157         Map<String, String> map = Collections.<String, String> synchronizedMap(new HashMap<String, String>(contextMap));
158         inheritableThreadLocal.set(map);
159     }
160 
161 }
162