1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.beanutils;
18
19 import java.util.Map;
20 import java.util.WeakHashMap;
21
22 /**
23 * A value that is provided per (thread) context classloader.
24 * Patterned after ThreadLocal.
25 * There is a separate value used when Thread.getContextClassLoader() is null.
26 * This mechanism provides isolation for web apps deployed in the same container.
27 * <strong>Note:</strong> A WeakHashMap bug in several 1.3 JVMs results in a memory leak
28 * for those JVMs.
29 *
30 * @see java.lang.Thread#getContextClassLoader
31 * @author Eric Pabst
32 */
33 public class ContextClassLoaderLocal {
34 private Map valueByClassLoader = new WeakHashMap();
35 private boolean globalValueInitialized = false;
36 private Object globalValue;
37
38 public ContextClassLoaderLocal() {
39 super();
40 }
41
42 /**
43 * Returns the initial value for this ContextClassLoaderLocal
44 * variable. This method will be called once per Context ClassLoader for
45 * each ContextClassLoaderLocal, the first time it is accessed
46 * with get or set. If the programmer desires ContextClassLoaderLocal variables
47 * to be initialized to some value other than null, ContextClassLoaderLocal must
48 * be subclassed, and this method overridden. Typically, an anonymous
49 * inner class will be used. Typical implementations of initialValue
50 * will call an appropriate constructor and return the newly constructed
51 * object.
52 *
53 * @return a new Object to be used as an initial value for this ContextClassLoaderLocal
54 */
55 protected Object initialValue() {
56 return null;
57 }
58
59 /**
60 * Gets the instance which provides the functionality for {@link BeanUtils}.
61 * This is a pseudo-singleton - an single instance is provided per (thread) context classloader.
62 * This mechanism provides isolation for web apps deployed in the same container.
63 * @return the object currently associated with the
64 */
65 public synchronized Object get() {
66
67
68
69
70
71 valueByClassLoader.isEmpty();
72 try {
73
74 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
75 if (contextClassLoader != null) {
76
77 Object value = valueByClassLoader.get(contextClassLoader);
78 if ((value == null)
79 && !valueByClassLoader.containsKey(contextClassLoader)) {
80 value = initialValue();
81 valueByClassLoader.put(contextClassLoader, value);
82 }
83 return value;
84
85 }
86
87 } catch (SecurityException e) {
88
89
90 if (!globalValueInitialized) {
91 globalValue = initialValue();
92 globalValueInitialized = true;
93 }
94 return globalValue;
95 }
96
97 /**
98 * Sets the value - a value is provided per (thread) context classloader.
99 * This mechanism provides isolation for web apps deployed in the same container.
100 *
101 * @param value the object to be associated with the entrant thread's context classloader
102 */
103 public synchronized void set(Object value) {
104
105
106
107
108 valueByClassLoader.isEmpty();
109 try {
110
111 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
112 if (contextClassLoader != null) {
113 valueByClassLoader.put(contextClassLoader, value);
114 return;
115 }
116
117 } catch (SecurityException e) {
118
119
120 globalValue = value;
121 globalValueInitialized = true;
122 }
123
124 /**
125 * Unsets the value associated with the current thread's context classloader
126 */
127 public synchronized void unset() {
128 try {
129
130 ClassLoader contextClassLoader = Thread.currentThread().getContextClassLoader();
131 unset(contextClassLoader);
132
133 } catch (SecurityException e) {
134 }
135
136 /**
137 * Unsets the value associated with the given classloader
138 */
139 public synchronized void unset(ClassLoader classLoader) {
140 valueByClassLoader.remove(classLoader);
141 }
142 }