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   * @author Lukasz Cwik
42   * 
43   * @since 1.5.0
44   */
45  public class BasicMDCAdapter implements MDCAdapter {
46  
47      private InheritableThreadLocal<Map<String, String>> inheritableThreadLocal = new InheritableThreadLocal<Map<String, String>>() {
48          @Override
49          protected Map<String, String> childValue(Map<String, String> parentValue) {
50              if (parentValue == null) {
51                  return null;
52              }
53              return new HashMap<String, String>(parentValue);
54          }
55      };
56  
57      /**
58       * Put a context value (the <code>val</code> parameter) as identified with
59       * the <code>key</code> parameter into the current thread's context map.
60       * Note that contrary to log4j, the <code>val</code> parameter can be null.
61       *
62       * <p>
63       * If the current thread does not have a context map it is created as a side
64       * effect of this call.
65       *
66       * @throws IllegalArgumentException
67       *                 in case the "key" parameter is null
68       */
69      public void put(String key, String val) {
70          if (key == null) {
71              throw new IllegalArgumentException("key cannot be null");
72          }
73          Map<String, String> map = inheritableThreadLocal.get();
74          if (map == null) {
75              map = new HashMap<String, String>();
76              inheritableThreadLocal.set(map);
77          }
78          map.put(key, val);
79      }
80  
81      /**
82       * Get the context identified by the <code>key</code> parameter.
83       */
84      public String get(String key) {
85          Map<String, String> map = inheritableThreadLocal.get();
86          if ((map != null) && (key != null)) {
87              return map.get(key);
88          } else {
89              return null;
90          }
91      }
92  
93      /**
94       * Remove the the context identified by the <code>key</code> parameter.
95       */
96      public void remove(String key) {
97          Map<String, String> map = inheritableThreadLocal.get();
98          if (map != null) {
99              map.remove(key);
100         }
101     }
102 
103     /**
104      * Clear all entries in the MDC.
105      */
106     public void clear() {
107         Map<String, String> map = inheritableThreadLocal.get();
108         if (map != null) {
109             map.clear();
110             inheritableThreadLocal.remove();
111         }
112     }
113 
114     /**
115      * Returns the keys in the MDC as a {@link Set} of {@link String}s The
116      * returned value can be null.
117      *
118      * @return the keys in the MDC
119      */
120     public Set<String> getKeys() {
121         Map<String, String> map = inheritableThreadLocal.get();
122         if (map != null) {
123             return map.keySet();
124         } else {
125             return null;
126         }
127     }
128 
129     /**
130      * Return a copy of the current thread's context map.
131      * Returned value may be null.
132      *
133      */
134     public Map<String, String> getCopyOfContextMap() {
135         Map<String, String> oldMap = inheritableThreadLocal.get();
136         if (oldMap != null) {
137             return new HashMap<String, String>(oldMap);
138         } else {
139             return null;
140         }
141     }
142 
143     public void setContextMap(Map<String, String> contextMap) {
144         inheritableThreadLocal.set(new HashMap<String, String>(contextMap));
145     }
146 }