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 }