1   /* 
2    * Copyright (c) 2004-2008 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  package org.slf4j.helpers;
25  
26  import org.slf4j.spi.MDCAdapter;
27  
28  import java.util.HashMap;
29  import java.util.Map;
30  import java.util.Set;
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 is largely based on logback's <a
37   * href="http://svn.qos.ch/viewvc/logback/trunk/logback-classic/src/main/java/org/slf4j/impl/LogbackMDCAdapter.java">
38   * LogbackMDCAdapter</a>.
39   * 
40   * @author Ceki Gulcu
41   * @author Maarten Bosteels
42   * 
43   * @since 1.5.0
44   */
45  public class BasicMDCAdapter implements MDCAdapter {
46  
47    private InheritableThreadLocal inheritableThreadLocal = new InheritableThreadLocal();
48  
49    /**
50     * Put a context value (the <code>val</code> parameter) as identified with
51     * the <code>key</code> parameter into the current thread's context map.
52     * Note that contrary to log4j, the <code>val</code> parameter can be null.
53     * 
54     * <p>
55     * If the current thread does not have a context map it is created as a side
56     * effect of this call.
57     * 
58     * @throws IllegalArgumentException
59     *                 in case the "key" parameter is null
60     */
61    public void put(String key, String val) {
62      if (key == null) {
63        throw new IllegalArgumentException("key cannot be null");
64      }
65      HashMap map = (HashMap) inheritableThreadLocal.get();
66      if (map == null) {
67        map = new HashMap();
68        inheritableThreadLocal.set(map);
69      }
70      map.put(key, val);
71    }
72  
73    /**
74     * Get the context identified by the <code>key</code> parameter.
75     */
76    public String get(String key) {
77      HashMap hashMap = (HashMap) inheritableThreadLocal.get();
78      if ((hashMap != null) && (key != null)) {
79        return (String) hashMap.get(key);
80      } else {
81        return null;
82      }
83    }
84  
85    /**
86     * Remove the the context identified by the <code>key</code> parameter.
87     */
88    public void remove(String key) {
89      HashMap map = (HashMap) inheritableThreadLocal.get();
90      if (map != null) {
91        map.remove(key);
92      }
93    }
94  
95    /**
96     * Clear all entries in the MDC.
97     */
98    public void clear() {
99      HashMap hashMap = (HashMap) inheritableThreadLocal.get();
100     if (hashMap != null) {
101       hashMap.clear();
102       inheritableThreadLocal.remove();
103     }
104   }
105 
106   /**
107    * Returns the keys in the MDC as a {@link Set} of {@link String}s The
108    * returned value can be null.
109    * 
110    * @return the keys in the MDC
111    */
112   public Set getKeys() {
113     HashMap hashMap = (HashMap) inheritableThreadLocal.get();
114     if (hashMap != null) {
115       return hashMap.keySet();
116     } else {
117       return null;
118     }
119   }
120   /**
121    * Return a copy of the current thread's context map. 
122    * Returned value may be null.
123    * 
124    */
125   public Map getCopyOfContextMap() {
126     HashMap hashMap = (HashMap) inheritableThreadLocal.get();
127     if (hashMap != null) {
128       return new HashMap(hashMap);
129     } else {
130       return null;
131     }
132   }
133 
134   public void setContextMap(Map contextMap) {
135     HashMap hashMap = (HashMap) inheritableThreadLocal.get();
136     if (hashMap != null) {
137       hashMap.clear();
138       hashMap.putAll(contextMap);
139     } else {
140       hashMap = new HashMap(contextMap);
141       inheritableThreadLocal.set(hashMap);
142     }
143   }
144 
145 }