Home | History | Annotate | Download | only in helpers
      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 }
    162