|
|||||||||||||||||||
Source file | Conditionals | Statements | Methods | TOTAL | |||||||||||||||
ThreadLocalStorageImpl.java | 75% | 100% | 100% | 96.4% |
|
1 | // Copyright 2004, 2005 The Apache Software Foundation | |
2 | // | |
3 | // Licensed under the Apache License, Version 2.0 (the "License"); | |
4 | // you may not use this file except in compliance with the License. | |
5 | // You may obtain a copy of the License at | |
6 | // | |
7 | // http://www.apache.org/licenses/LICENSE-2.0 | |
8 | // | |
9 | // Unless required by applicable law or agreed to in writing, software | |
10 | // distributed under the License is distributed on an "AS IS" BASIS, | |
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
12 | // See the License for the specific language governing permissions and | |
13 | // limitations under the License. | |
14 | ||
15 | package org.apache.hivemind.service.impl; | |
16 | ||
17 | import java.util.HashMap; | |
18 | import java.util.Map; | |
19 | ||
20 | import org.apache.hivemind.service.ThreadCleanupListener; | |
21 | import org.apache.hivemind.service.ThreadEventNotifier; | |
22 | import org.apache.hivemind.service.ThreadLocalStorage; | |
23 | ||
24 | /** | |
25 | * Implementation of {@link org.apache.hivemind.service.ThreadLocalStorage}. | |
26 | * | |
27 | * @author Howard Lewis Ship, Harish Krishnaswamy | |
28 | */ | |
29 | public class ThreadLocalStorageImpl implements ThreadLocalStorage, ThreadCleanupListener | |
30 | { | |
31 | private static final String INITIALIZED_KEY = | |
32 | "$org.apache.hivemind.service.impl.ThreadLocalStorageImpl#initialized$"; | |
33 | ||
34 | private CleanableThreadLocal _local = new CleanableThreadLocal(); | |
35 | private ThreadEventNotifier _notifier; | |
36 | ||
37 | private static class CleanableThreadLocal extends ThreadLocal | |
38 | { | |
39 | /** | |
40 | * <p> | |
41 | * Intializes the variable with a HashMap containing a single Boolean flag to denote the | |
42 | * initialization of the variable. The Boolean flag will be used to determine when to | |
43 | * register the listener with {@link ThreadEventNotifier}. | |
44 | * <p> | |
45 | * The registration cannot be done from here because it may get lost once the caller method ( | |
46 | * {@link ThreadLocal#get()}or {@link ThreadLocal#set(java.lang.Object)} completes, if | |
47 | * this was the first ThreadLocal variable access for the Thread. | |
48 | */ | |
49 | 87 | protected Object initialValue() |
50 | { | |
51 | // NOTE: This is a workaround to circumvent the ThreadLocal behavior. | |
52 | // It would be easier if the implementation of ThreadLocal.get() checked for | |
53 | // the existence of the thread local map, after initialValue() is evaluated, | |
54 | // and used it instead of creating a new map always after initialization (possibly | |
55 | // overwriting any variables created from within ThreadLocal.initialValue()). | |
56 | ||
57 | 87 | Map map = new HashMap(); |
58 | 87 | map.put(INITIALIZED_KEY, Boolean.TRUE); |
59 | ||
60 | 87 | return map; |
61 | } | |
62 | } | |
63 | ||
64 | /** | |
65 | * Gets the thread local variable and registers the listener with {@link ThreadEventNotifier} | |
66 | * if the thread local variable has been initialized. The registration cannot be done from | |
67 | * within {@link CleanableThreadLocal#initialValue()} because the notifier's thread local | |
68 | * variable will be overwritten and the listeners for the thread will be lost. | |
69 | */ | |
70 | 817 | private Map getThreadLocalVariable() |
71 | { | |
72 | 817 | Map map = (Map) _local.get(); |
73 | ||
74 | 817 | if (Boolean.TRUE.equals(map.get(INITIALIZED_KEY)) && _notifier != null) |
75 | { | |
76 | 83 | _notifier.addThreadCleanupListener(this); |
77 | ||
78 | 83 | map.remove(INITIALIZED_KEY); |
79 | } | |
80 | ||
81 | 817 | return map; |
82 | } | |
83 | ||
84 | 11 | public Object get(String key) |
85 | { | |
86 | 11 | Map map = getThreadLocalVariable(); |
87 | ||
88 | 11 | return map.get(key); |
89 | } | |
90 | ||
91 | 806 | public void put(String key, Object value) |
92 | { | |
93 | 806 | Map map = getThreadLocalVariable(); |
94 | ||
95 | 806 | map.put(key, value); |
96 | } | |
97 | ||
98 | 805 | public void clear() |
99 | { | |
100 | 805 | Map map = (Map) _local.get(); |
101 | ||
102 | 805 | if (map != null) |
103 | 805 | map.clear(); |
104 | } | |
105 | ||
106 | 6 | public void setNotifier(ThreadEventNotifier notifier) |
107 | { | |
108 | 6 | _notifier = notifier; |
109 | } | |
110 | ||
111 | /** | |
112 | * Invokes {@link #clear()}. | |
113 | */ | |
114 | 803 | public void threadDidCleanup() |
115 | { | |
116 | 803 | clear(); |
117 | } | |
118 | ||
119 | } |
|