1 16 package org.apache.myfaces.util; 17 18 import java.util.*; 19 20 21 53 public abstract class BiLevelCacheMap implements Map 54 { 55 57 private static final int INITIAL_SIZE_L1 = 32; 58 59 60 protected Map _cacheL1; 61 62 63 private final Map _cacheL2; 64 private final int _mergeThreshold; 65 private int _missCount; 66 67 69 public BiLevelCacheMap(int mergeThreshold) 70 { 71 _cacheL1 = new HashMap(INITIAL_SIZE_L1); 72 _cacheL2 = new HashMap(HashMapUtils.calcCapacity(mergeThreshold)); 73 _mergeThreshold = mergeThreshold; 74 } 75 76 78 public boolean isEmpty() 79 { 80 synchronized (_cacheL2) { 81 return _cacheL1.isEmpty() && _cacheL2.isEmpty(); 82 } 83 } 84 85 public void clear() 86 { 87 synchronized (_cacheL2) { 88 _cacheL1 = new HashMap(); _cacheL2.clear(); 90 } 91 } 92 93 public boolean containsKey(Object key) 94 { 95 synchronized (_cacheL2) { 96 return _cacheL1.containsKey(key) || _cacheL2.containsKey(key); 97 } 98 } 99 100 public boolean containsValue(Object value) 101 { 102 synchronized (_cacheL2) { 103 return _cacheL1.containsValue(value) || _cacheL2.containsValue(value); 104 } 105 } 106 107 public Set entrySet() 108 { 109 synchronized (_cacheL2) 110 { 111 mergeIfL2NotEmpty(); 112 return Collections.unmodifiableSet(_cacheL1.entrySet()); 113 } 114 } 115 116 public Object get(Object key) 117 { 118 Map cacheL1 = _cacheL1; 119 Object retval = cacheL1.get(key); 120 if (retval != null) 121 { 122 return retval; 123 } 124 125 synchronized (_cacheL2) 126 { 127 if (cacheL1 != _cacheL1) 129 { 130 if ((retval = _cacheL1.get(key)) != null) 131 { 132 return retval; 134 } 135 } 136 137 if ((retval = _cacheL2.get(key)) == null) 138 { 139 retval = newInstance(key); 140 if (retval != null) 141 { 142 put(key, retval); 143 mergeIfNeeded(); 144 } 145 } 146 else 147 { 148 mergeIfNeeded(); 149 } 150 } 151 152 return retval; 153 } 154 155 public Set keySet() 156 { 157 synchronized (_cacheL2) 158 { 159 mergeIfL2NotEmpty(); 160 return Collections.unmodifiableSet(_cacheL1.keySet()); 161 } 162 } 163 164 169 public Object put(Object key, Object value) 170 { 171 synchronized (_cacheL2) 172 { 173 _cacheL2.put(key, value); 174 175 mergeIfNeeded(); 178 } 179 180 return value; 181 } 182 183 public void putAll(Map map) 184 { 185 synchronized (_cacheL2) 186 { 187 mergeIfL2NotEmpty(); 188 189 merge(map); 192 } 193 } 194 195 196 public Object remove(Object key) 197 { 198 synchronized (_cacheL2) 199 { 200 if (!_cacheL1.containsKey(key) && !_cacheL2.containsKey(key)) 201 { 202 return null; 204 } 205 206 Object retval; 207 Map newMap; 208 synchronized (_cacheL1) 209 { 210 newMap = HashMapUtils.merge(_cacheL1, _cacheL2); 213 retval = newMap.remove(key); 214 } 215 216 _cacheL1 = newMap; 217 _cacheL2.clear(); 218 _missCount = 0; 219 return retval; 220 } 221 } 222 223 public int size() 224 { 225 synchronized (_cacheL2) 228 { 229 mergeIfL2NotEmpty(); 230 return _cacheL1.size(); 231 } 232 } 233 234 public Collection values() 235 { 236 synchronized (_cacheL2) 237 { 238 mergeIfL2NotEmpty(); 239 return Collections.unmodifiableCollection(_cacheL1.values()); 240 } 241 } 242 243 private void mergeIfL2NotEmpty() 244 { 245 if (!_cacheL2.isEmpty()) 246 { 247 merge(_cacheL2); 248 } 249 } 250 251 private void mergeIfNeeded() 252 { 253 if (++_missCount >= _mergeThreshold) 254 { 255 merge(_cacheL2); 256 } 257 } 258 259 private void merge(Map map) 260 { 261 Map newMap; 262 synchronized (_cacheL1) 263 { 264 newMap = HashMapUtils.merge(_cacheL1, map); 268 } 269 _cacheL1 = newMap; 270 _cacheL2.clear(); 271 _missCount = 0; 272 } 273 274 289 protected abstract Object newInstance(Object key); 290 } 291 | Popular Tags |