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