1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package org.apache.myfaces.shared.util;
20
21 import java.util.Collection;
22 import java.util.Collections;
23 import java.util.HashMap;
24 import java.util.Map;
25 import java.util.Set;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40 public abstract class BiLevelCacheMap implements Map
41 {
42
43
44 private static final int INITIAL_SIZE_L1 = 32;
45
46
47 protected Map _cacheL1;
48
49
50 private final Map _cacheL2;
51 private final int _mergeThreshold;
52 private int _missCount;
53
54
55
56 public BiLevelCacheMap(int mergeThreshold)
57 {
58 _cacheL1 = new HashMap(INITIAL_SIZE_L1);
59 _cacheL2 = new HashMap(HashMapUtils.calcCapacity(mergeThreshold));
60 _mergeThreshold = mergeThreshold;
61 }
62
63
64
65 public boolean isEmpty()
66 {
67 synchronized (_cacheL2)
68 {
69 return _cacheL1.isEmpty() && _cacheL2.isEmpty();
70 }
71 }
72
73 public void clear()
74 {
75 synchronized (_cacheL2)
76 {
77 _cacheL1 = new HashMap();
78 _cacheL2.clear();
79 }
80 }
81
82 public boolean containsKey(Object key)
83 {
84 synchronized (_cacheL2)
85 {
86 return _cacheL1.containsKey(key) || _cacheL2.containsKey(key);
87 }
88 }
89
90 public boolean containsValue(Object value)
91 {
92 synchronized (_cacheL2)
93 {
94 return _cacheL1.containsValue(value) || _cacheL2.containsValue(value);
95 }
96 }
97
98 public Set entrySet()
99 {
100 synchronized (_cacheL2)
101 {
102 mergeIfL2NotEmpty();
103 return Collections.unmodifiableSet(_cacheL1.entrySet());
104 }
105 }
106
107 public Object get(Object key)
108 {
109 Map cacheL1 = _cacheL1;
110 Object retval = cacheL1.get(key);
111 if (retval != null)
112 {
113 return retval;
114 }
115
116 synchronized (_cacheL2)
117 {
118
119 if (cacheL1 != _cacheL1)
120 {
121 retval = _cacheL1.get(key);
122 if (retval != null)
123 {
124
125 return retval;
126 }
127 }
128
129 retval = _cacheL2.get(key);
130 if (retval == null)
131 {
132 retval = newInstance(key);
133 if (retval != null)
134 {
135 put(key, retval);
136 mergeIfNeeded();
137 }
138 }
139 else
140 {
141 mergeIfNeeded();
142 }
143 }
144
145 return retval;
146 }
147
148 public Set keySet()
149 {
150 synchronized (_cacheL2)
151 {
152 mergeIfL2NotEmpty();
153 return Collections.unmodifiableSet(_cacheL1.keySet());
154 }
155 }
156
157
158
159
160
161
162 public Object put(Object key, Object value)
163 {
164 synchronized (_cacheL2)
165 {
166 _cacheL2.put(key, value);
167
168
169
170 mergeIfNeeded();
171 }
172
173 return value;
174 }
175
176 public void putAll(Map map)
177 {
178 synchronized (_cacheL2)
179 {
180 mergeIfL2NotEmpty();
181
182
183
184 merge(map);
185 }
186 }
187
188
189 public Object remove(Object key)
190 {
191 synchronized (_cacheL2)
192 {
193 if (!_cacheL1.containsKey(key) && !_cacheL2.containsKey(key))
194 {
195
196 return null;
197 }
198
199 Object retval;
200 Map newMap;
201 synchronized (_cacheL1)
202 {
203
204
205 newMap = HashMapUtils.merge(_cacheL1, _cacheL2);
206 retval = newMap.remove(key);
207 }
208
209 _cacheL1 = newMap;
210 _cacheL2.clear();
211 _missCount = 0;
212 return retval;
213 }
214 }
215
216 public int size()
217 {
218
219
220 synchronized (_cacheL2)
221 {
222 mergeIfL2NotEmpty();
223 return _cacheL1.size();
224 }
225 }
226
227 public Collection values()
228 {
229 synchronized (_cacheL2)
230 {
231 mergeIfL2NotEmpty();
232 return Collections.unmodifiableCollection(_cacheL1.values());
233 }
234 }
235
236 private void mergeIfL2NotEmpty()
237 {
238 if (!_cacheL2.isEmpty())
239 {
240 merge(_cacheL2);
241 }
242 }
243
244 private void mergeIfNeeded()
245 {
246 if (++_missCount >= _mergeThreshold)
247 {
248 merge(_cacheL2);
249 }
250 }
251
252 private void merge(Map map)
253 {
254 Map newMap;
255 synchronized (_cacheL1)
256 {
257
258
259
260 newMap = HashMapUtils.merge(_cacheL1, map);
261 }
262 _cacheL1 = newMap;
263 _cacheL2.clear();
264 _missCount = 0;
265 }
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282 protected abstract Object newInstance(Object key);
283 }