View Javadoc

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  
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       */
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       */
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       */
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      */
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      */
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      */
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 
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 }