View | Details | Raw Unified | Return to bug 50486
Collapse All | Expand All

(-)tests/src/java/org/apache/log4j/MDCTestCase.java (+85 lines)
Line 0 Link Here
1
package org.apache.log4j;
2
3
import junit.framework.TestCase;
4
5
import java.lang.ref.Reference;
6
import java.lang.reflect.Field;
7
8
/**
9
 * Test for MDC
10
 * 
11
 *  @author Maarten Bosteels
12
 */
13
public class MDCTestCase extends TestCase {
14
  
15
  public void setUp() {
16
    MDC.clear();
17
  }
18
19
  public void tearDown() {
20
    MDC.clear();
21
  }
22
23
  public void testPut() throws Exception {
24
    MDC.put("key", "some value");
25
    assertEquals("some value", MDC.get("key"));
26
    assertEquals(1, MDC.getContext().size());
27
  }
28
  
29
  public void testRemoveLastKey() throws Exception {
30
    MDC.put("key", "some value");
31
    MDC.remove("key");
32
    checkThreadLocalsForLeaks();
33
  }
34
35
  private void checkThreadLocalsForLeaks() throws Exception {
36
37
      // this code is heavily based on code in org.apache.catalina.loader.WebappClassLoader
38
39
      // Make the fields in the Thread class that store ThreadLocals accessible    
40
      Field threadLocalsField = Thread.class.getDeclaredField("threadLocals");
41
      threadLocalsField.setAccessible(true);
42
      Field inheritableThreadLocalsField = Thread.class.getDeclaredField("inheritableThreadLocals");
43
      inheritableThreadLocalsField.setAccessible(true);
44
      // Make the underlying array of ThreadLoad.ThreadLocalMap.Entry objects accessible
45
      Class tlmClass = Class.forName("java.lang.ThreadLocal$ThreadLocalMap");
46
      Field tableField = tlmClass.getDeclaredField("table");
47
      tableField.setAccessible(true);
48
49
      Thread thread = Thread.currentThread();
50
51
      Object threadLocalMap;
52
      threadLocalMap = threadLocalsField.get(thread);
53
      // Check the first map
54
      checkThreadLocalMapForLeaks(threadLocalMap, tableField);
55
      // Check the second map
56
      threadLocalMap = inheritableThreadLocalsField.get(thread);
57
      checkThreadLocalMapForLeaks(threadLocalMap, tableField);
58
59
  }
60
61
  private void checkThreadLocalMapForLeaks(Object map, Field internalTableField) throws IllegalAccessException,
62
      NoSuchFieldException {
63
    
64
    if (map != null) {
65
      Object[] table = (Object[]) internalTableField.get(map);
66
      if (table != null) {
67
        for (int j =0; j < table.length; j++) {
68
          if (table[j] != null) {
69
70
            // Check the key
71
            Object key = ((Reference) table[j]).get();
72
            String keyClassName = key.getClass().getName();
73
74
            if (key.getClass() == org.apache.log4j.helpers.ThreadLocalMap.class) {
75
              fail("Found a ThreadLocal with key of type [" + keyClassName + "]");
76
            }
77
78
          }
79
        }
80
      }
81
    }
82
  }
83
84
85
}
(-)src/main/java/org/apache/log4j/MDC.java (+4 lines)
Lines 170-175 Link Here
170
      Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
170
      Hashtable ht = (Hashtable) ((ThreadLocalMap)tlm).get();
171
      if(ht != null) {
171
      if(ht != null) {
172
        ht.remove(key);
172
        ht.remove(key);
173
        // clean up if this was the last key
174
        if (ht.isEmpty()) {
175
          clear0();
176
        }
173
      } 
177
      } 
174
    }
178
    }
175
  }
179
  }

Return to bug 50486