    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  package org.apache.log4j;
    18
    19  import java.lang.ref.Reference;
    20  import java.lang.reflect.Field;
    21  import java.lang.reflect.Method;
    22  import junit.framework.TestCase;
    23
    24  /**
    25   * Test for MDC
    26   *
    27   *  @author Maarten Bosteels
    28   */
    29  public class MDCTestCase extends TestCase {
    30
    31    public void setUp() {
    32      MDC.clear();
    33    }
    34
    35    public void tearDown() {
    36      MDC.clear();
    37    }
    38
    39    public void testPut() throws Exception {
    40      MDC.put("key", "some value");
    41      assertEquals("some value", MDC.get("key"));
    42      assertEquals(1, MDC.getContext().size());
    43    }
    44
    45    public void testRemoveLastKey() throws Exception {
    46      MDC.put("key", "some value");
    47
    48      MDC.remove("key");
    49      checkThreadLocalsForLeaks();
    50    }
    51
    52    private void checkThreadLocalsForLeaks() throws Exception {
    53
    54        // this code is heavily based on code in org.apache.catalina.loader.WebappClassLoader
    55
    56        // Make the fields in the Thread class that store ThreadLocals accessible
    57        Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
    58        threadLocalsField.setAccessible(true);
    59        Field inheritableThreadLocalsField = Thread.class.getDeclaredField("inheritableThreadLocals");
    60        inheritableThreadLocalsField.setAccessible(true);
    61        // Make the underlying array of ThreadLoad.ThreadLocalMap.Entry objects accessible
    62        Class tlmClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
    63        Field tableField = tlmClass.getDeclaredField("table");
    64        tableField.setAccessible(true);
    65
    66        Thread thread = Thread.currentThread();
    67
    68        Object threadLocalMap;
    69        threadLocalMap = threadLocalsField.get(thread);
    70        // Check the first map
    71        checkThreadLocalMapForLeaks(threadLocalMap, tableField);
    72        // Check the second map
    73        threadLocalMap = inheritableThreadLocalsField.get(thread);
    74        checkThreadLocalMapForLeaks(threadLocalMap, tableField);
    75
    76    }
    77
    78    private void checkThreadLocalMapForLeaks(Object map, Field internalTableField)
    79            throws IllegalAccessException, NoSuchFieldException {
    80      if (map != null) {
    81        Object[] table = (Object[]) internalTableField.get(map);
    82        if (table != null) {
    83          for (int j =0; j < table.length; j++) {
    84            if (table[j] != null) {
    85
    86              // Check the key
    87              Object key = ((Reference) table[j]).get();
    88              String keyClassName = key.getClass().getName();
    89
    90              if (key.getClass() == org.apache.log4j.helpers.ThreadLocalMap.class) {
    91                fail("Found a ThreadLocal with key of type [" + keyClassName + "]");
    92              }
    93            }
    94          }
    95        }
    96      }
    97    }
    98  }