View Javadoc
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 }