View Javadoc

    1   /*
    2    * Licensed to the Apache Software Foundation (ASF) under one or more
    3    * contributor license agreements.  See the NOTICE file distributed with
    4    * this work for additional information regarding copyright ownership.
    5    * The ASF licenses this file to You under the Apache License, Version 2.0
    6    * (the "License"); you may not use this file except in compliance with
    7    * the License.  You may obtain a copy of the License at
    8    *
    9    *      http://www.apache.org/licenses/LICENSE-2.0
    10   *
    11   * Unless required by applicable law or agreed to in writing, software
    12   * distributed under the License is distributed on an "AS IS" BASIS,
    13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14   * See the License for the specific language governing permissions and
    15   * limitations under the License.
    16   */
    17
    18  package org.apache.log4j;
    19
    20  import java.lang.reflect.InvocationTargetException;
    21  import java.lang.reflect.Method;
    22  import java.util.Hashtable;
    23  import org.apache.log4j.helpers.Loader;
    24  import org.apache.log4j.helpers.ThreadLocalMap;
    25
    26  /**
    27     The MDC class is similar to the {@link NDC} class except that it is
    28     based on a map instead of a stack. It provides <em>mapped
    29     diagnostic contexts</em>. A <em>Mapped Diagnostic Context</em>, or
    30     MDC in short, is an instrument for distinguishing interleaved log
    31     output from different sources. Log output is typically interleaved
    32     when a server handles multiple clients near-simultaneously.
    33
    34     <p><b><em>The MDC is managed on a per thread basis</em></b>. A
    35     child thread automatically inherits a <em>copy</em> of the mapped
    36     diagnostic context of its parent.
    37
    38     <p>The MDC class requires JDK 1.2 or above. Under JDK 1.1 the MDC
    39     will always return empty values but otherwise will not affect or
    40     harm your application.
    41
    42     @since 1.2
    43
    44     @author Ceki G&uuml;lc&uuml;
    45  */
    46  public class MDC {
    47
    48    final static MDC mdc = new MDC();
    49
    50    static final int HT_SIZE = 7;
    51
    52    boolean java1;
    53
    54    Object tlm;
    55
    56    private Method removeMethod;
    57
    58    private
    59    MDC() {
    60      java1 = Loader.isJava1();
    61      if(!java1) {
    62        tlm = new ThreadLocalMap();
    63      }
    64
    65      try {
    66        removeMethod = ThreadLocal.class.getMethod("remove", null);
    67      } catch (NoSuchMethodException e) {
    68        // don't do anything - java prior 1.5
    69      }
    70    }
    71
    72    /**
    73       Put a context value (the <code>o</code> parameter) as identified
    74       with the <code>key</code> parameter into the current thread's
    75       context map.
    76
    77       <p>If the current thread does not have a context map it is
    78       created as a side effect.
    79
    80     */
    81    static
    82    public
    83    void put(String key, Object o) {
    84       if (mdc != null) {
    85           mdc.put0(key, o);
    86       }
    87    }
    88
    89    /**
    90       Get the context identified by the <code>key</code> parameter.
    91
    92       <p>This method has no side effects.
    93     */
    94    static
    95    public
    96    Object get(String key) {
    97      if (mdc != null) {
    98          return mdc.get0(key);
    99      }
    100     return null;
    101   }
    102
    103   /**
    104      Remove the the context identified by the <code>key</code>
    105      parameter.
    106
    107   */
    108   static
    109   public
    110   void remove(String key) {
    111     if (mdc != null) {
    112         mdc.remove0(key);
    113     }
    114   }
    115
    116
    117   /**
    118    * Get the current thread's MDC as a hashtable. This method is
    119    * intended to be used internally.
    120    * */
    121   public static Hashtable getContext() {
    122     if (mdc != null) {
    123         return mdc.getContext0();
    124     } else {
    125         return null;
    126     }
    127   }
    128
    129   /**
    130    *  Remove all values from the MDC.
    131    *  @since 1.2.16
    132   */
    133   public static void clear() {
    134     if (mdc != null) {
    135         mdc.clear0();
    136     }
    137   }
    138
    139
    140   private
    141   void put0(String key, Object o) {
    142     if(java1 || tlm == null) {
    143       return;
    144     } else {
    145       Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
    146       if(ht == null) {
    147         ht = new Hashtable(HT_SIZE);
    148         ((ThreadLocalMap)tlm).set(ht);
    149       }
    150       ht.put(key, o);
    151     }
    152   }
    153
    154   private
    155   Object get0(String key) {
    156     if(java1 || tlm == null) {
    157       return null;
    158     } else {
    159       Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
    160       if(ht != null && key != null) {
    161         return ht.get(key);
    162       } else {
    163         return null;
    164       }
    165     }
    166   }
    167
    168   private
    169   void remove0(String key) {
    170     if(!java1 && tlm != null) {
    171       Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
    172       if(ht != null) {
    173         ht.remove(key);
    174         // clean up if this was the last key
    175         if (ht.isEmpty()) {
    176           clear0();
    177         }
    178       }
    179     }
    180   }
    181
    182
    183   private
    184   Hashtable getContext0() {
    185      if(java1 || tlm == null) {
    186       return null;
    187     } else {
    188       return (Hashtable) ((ThreadLocalMap)tlm).get();
    189     }
    190   }
    191
    192   private
    193   void clear0() {
    194     if(!java1 && tlm != null) {
    195       Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
    196       if(ht != null) {
    197         ht.clear();
    198       }
    199       if(removeMethod != null) {
    200           // java 1.3/1.4 does not have remove - will suffer from a memory leak
    201           try {
    202             removeMethod.invoke(tlm, null);
    203           } catch (IllegalAccessException e) {
    204             // should not happen
    205           } catch (InvocationTargetException e) {
    206             // should not happen
    207           }
    208       }
    209     }
    210   }
    211
    212 }