001/** 002 * Copyright (c) 2004-2011 QOS.ch 003 * All rights reserved. 004 * 005 * Permission is hereby granted, free of charge, to any person obtaining 006 * a copy of this software and associated documentation files (the 007 * "Software"), to deal in the Software without restriction, including 008 * without limitation the rights to use, copy, modify, merge, publish, 009 * distribute, sublicense, and/or sell copies of the Software, and to 010 * permit persons to whom the Software is furnished to do so, subject to 011 * the following conditions: 012 * 013 * The above copyright notice and this permission notice shall be 014 * included in all copies or substantial portions of the Software. 015 * 016 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 017 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 018 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 019 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 020 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 021 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 022 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 023 * 024 */ 025package org.slf4j.helpers; 026 027import org.slf4j.spi.MDCAdapter; 028 029import java.util.*; 030import java.util.Map; 031 032/** 033 * Basic MDC implementation, which can be used with logging systems that lack 034 * out-of-the-box MDC support. 035 * 036 * This code was initially inspired by logback's LogbackMDCAdapter. However, 037 * LogbackMDCAdapter has evolved and is now considerably more sophisticated. 038 * 039 * @author Ceki Gulcu 040 * @author Maarten Bosteels 041 * @author Lukasz Cwik 042 * 043 * @since 1.5.0 044 */ 045public class BasicMDCAdapter implements MDCAdapter { 046 047 private InheritableThreadLocal<Map<String, String>> inheritableThreadLocal = new InheritableThreadLocal<Map<String, String>>() { 048 @Override 049 protected Map<String, String> childValue(Map<String, String> parentValue) { 050 if (parentValue == null) { 051 return null; 052 } 053 return new HashMap<String, String>(parentValue); 054 } 055 }; 056 057 /** 058 * Put a context value (the <code>val</code> parameter) as identified with 059 * the <code>key</code> parameter into the current thread's context map. 060 * Note that contrary to log4j, the <code>val</code> parameter can be null. 061 * 062 * <p> 063 * If the current thread does not have a context map it is created as a side 064 * effect of this call. 065 * 066 * @throws IllegalArgumentException 067 * in case the "key" parameter is null 068 */ 069 public void put(String key, String val) { 070 if (key == null) { 071 throw new IllegalArgumentException("key cannot be null"); 072 } 073 Map<String, String> map = inheritableThreadLocal.get(); 074 if (map == null) { 075 map = new HashMap<String, String>(); 076 inheritableThreadLocal.set(map); 077 } 078 map.put(key, val); 079 } 080 081 /** 082 * Get the context identified by the <code>key</code> parameter. 083 */ 084 public String get(String key) { 085 Map<String, String> map = inheritableThreadLocal.get(); 086 if ((map != null) && (key != null)) { 087 return map.get(key); 088 } else { 089 return null; 090 } 091 } 092 093 /** 094 * Remove the the context identified by the <code>key</code> parameter. 095 */ 096 public void remove(String key) { 097 Map<String, String> map = inheritableThreadLocal.get(); 098 if (map != null) { 099 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}