1 package org.apache.fulcrum.yaafi.framework.tls;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.util.HashMap;
23 import java.util.Map;
24
25 /**
26 * Implementation of {@link org.apache.fulcrum.yaafi.framework.tls.ThreadLocalStorage}.
27 *
28 * The code was pasted from the Hivemnind container written by
29 * Howard Lewis Ship and Harish Krishnaswamy
30 *
31 * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
32 */
33
34 public class ThreadLocalStorageImpl implements ThreadLocalStorage
35 {
36 private static final String INITIALIZED_KEY =
37 "$org.apache.fulcrum.yaafi.framework.tls.ThreadLocalStorageImpl#initialized$";
38
39 private CleanableThreadLocal local = new CleanableThreadLocal();
40
41 private static class CleanableThreadLocal extends ThreadLocal<Object>
42 {
43 /**
44 * <p>
45 * Intializes the variable with a HashMap containing a single Boolean flag to denote the
46 * initialization of the variable.
47 */
48 protected Object initialValue()
49 {
50 // NOTE: This is a workaround to circumvent the ThreadLocal behavior.
51 // It would be easier if the implementation of ThreadLocal.get() checked for
52 // the existence of the thread local map, after initialValue() is evaluated,
53 // and used it instead of creating a new map always after initialization (possibly
54 // overwriting any variables created from within ThreadLocal.initialValue()).
55
56 Map<String, Boolean> map = new HashMap<String, Boolean>();
57 map.put(INITIALIZED_KEY, Boolean.TRUE);
58
59 return map;
60 }
61 }
62
63 /**
64 * Gets the thread local variable and registers the listener with ThreadEventNotifier
65 * if the thread local variable has been initialized. The registration cannot be done from
66 * within {@link CleanableThreadLocal#initialValue()} because the notifier's thread local
67 * variable will be overwritten and the listeners for the thread will be lost.
68 */
69 private Map<String, Object> getThreadLocalVariable()
70 {
71 Map<String, Object> map = (Map<String, Object>) local.get();
72 return map;
73 }
74
75 public Object get(String key)
76 {
77 Map<String, Object> map = getThreadLocalVariable();
78 return map.get(key);
79 }
80
81 public void put(String key, Object value)
82 {
83 Map<String, Object> map = getThreadLocalVariable();
84 map.put(key, value);
85 }
86
87 public boolean containsKey(String key)
88 {
89 Map<String, Object> map = getThreadLocalVariable();
90 return map.containsKey(key);
91 }
92
93 public void clear()
94 {
95 Map<?, ?> map = (Map<?, ?>) local.get();
96 if (map != null)
97 {
98 map.clear();
99 }
100 }
101 }