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