1 7 package org.enhydra.xml.xmlc.deferredparsing; 8 9 import java.lang.ref.ReferenceQueue ; 10 import java.lang.ref.WeakReference ; 11 import java.util.AbstractCollection ; 12 import java.util.Collection ; 13 import java.util.HashMap ; 14 import java.util.Iterator ; 15 import java.util.Map ; 16 import java.util.Set ; 17 18 27 public class Cache implements Map { 28 29 33 protected static class MRUCache { 34 35 private static final class Entry { 36 public Object ref; 37 public Cache.MRUCache.Entry prev; 38 public Cache.MRUCache.Entry next; 39 } 40 41 42 43 private Entry[] cache; 44 45 46 private Entry freelist; 47 48 49 private Entry header; 50 51 56 MRUCache(int num) { 57 cache = new Entry[num]; 58 for (int i = 0; i < cache.length; ++i) 59 cache[i] = new Entry(); 60 61 header = new Entry(); 62 this.clear(); 63 } 64 65 70 int getCapacity() { 71 return cache.length; 72 } 73 74 80 synchronized Object add(Object obj) { 81 if (obj == null || obj == header.next.ref) 84 return obj; 85 86 Entry entry = null; 87 88 if ((entry = find(obj)) != null) { 89 extractEntry(entry); 90 } else if (freelist != null) { 91 entry = freelist; 92 freelist = entry.next; 93 } else { 94 entry = header.prev; 96 extractEntry(entry); 97 } 98 99 entry.ref = obj; 100 101 entry.next = header.next; 103 entry.prev = header; 104 entry.next.prev = entry; 105 header.next = entry; 106 107 return obj; 108 } 109 110 111 116 synchronized void remove(Object obj) { 117 Entry entry = null; 118 if (obj != null && (entry = find(obj)) != null) { 119 extractEntry(entry); 120 121 entry.ref = null; 122 entry.next = freelist; 123 freelist = entry; 124 } 125 } 126 127 130 synchronized void clear() { 131 header.next = header.prev = header; 132 133 for (int i = 0; i < (cache.length - 1); ++i) { 134 cache[i].next = cache[i + 1]; 135 cache[i].ref = null; 136 } 137 138 freelist = cache[0]; 139 cache[cache.length - 1].next = null; 140 cache[cache.length - 1].ref = null; 141 } 142 143 149 private Entry find(Object obj) { 150 for (Entry e = header.next; e != header; e = e.next) { 151 if (e.ref == obj) 152 return e; 153 } 154 return null; 155 } 156 157 158 163 private void extractEntry(Entry entry) { 164 entry.next.prev = entry.prev; 165 entry.prev.next = entry.next; 166 } 167 168 } 169 170 173 private class MapEntry extends WeakReference implements Map.Entry { 174 175 private Object key; 176 177 184 MapEntry(Object key, Object value, ReferenceQueue queue) { 185 super(value, queue); 186 this.key = key; 187 } 188 189 193 public Object getKey() { 194 return key; 195 } 196 197 201 public Object getValue() { 202 return this.get(); 203 } 204 205 209 public Object setValue(Object value) { 210 return Cache.this.put(key, value); 211 } 212 213 public boolean equals(Object o) { 214 return (o!=null) && 215 (o instanceof MapEntry) && 216 (key.equals(((MapEntry)o).getKey())); 217 } 218 219 public int hashCode() { 220 return key.hashCode(); 221 } 222 } 223 224 227 private class ValueIterator implements Iterator { 228 Iterator it; 229 230 public ValueIterator(Iterator it) { 231 this.it = it; 232 } 233 234 public boolean hasNext() { 235 return it.hasNext(); 236 } 237 238 public Object next() { 239 return mru.add(((MapEntry) it.next()).getValue()); 240 } 241 242 public void remove() { 243 it.remove(); 244 } 245 } 246 247 248 public static final int DEFAULT_NUM_MRU_ENTRIES = 64; 249 250 251 private ReferenceQueue queue = new ReferenceQueue (); 252 253 254 private HashMap map = new HashMap (); 255 256 257 private MRUCache mru; 258 259 264 public Cache () { 265 this(DEFAULT_NUM_MRU_ENTRIES); 266 } 267 268 274 public Cache (int numMRUEntries) { 275 mru = new MRUCache(numMRUEntries); 276 } 277 278 284 public Cache (Map other) { 285 this(); 286 putAll(other); 287 } 288 289 295 public Cache (int numMRUEntries, Map other) { 296 this(numMRUEntries); 297 putAll(other); 298 } 299 300 305 public int hashCode() { 306 return map.hashCode(); 307 } 308 309 315 public boolean equals(Object cache) { 316 return (cache instanceof Cache) && map.equals(((Cache)cache).map); 317 } 318 319 324 public int size() { 325 return map.size(); 326 } 327 328 332 public void clear() { 333 mru.clear(); 334 map.clear(); 335 } 336 337 347 public synchronized Object put(Object key, Object value) { 348 349 if (value == null) 352 return new UnsupportedOperationException ("Cache does not support null values"); 353 354 cleanup(); 357 358 MapEntry entry = (MapEntry) map.put(key, new MapEntry(key, value, queue)); 359 360 return (entry != null) ? entry.getValue() : null; 361 } 362 363 372 public synchronized Object get(Object key) { 373 Object value = null; 374 MapEntry entry = null; 375 376 cleanup(); 377 378 if ((entry = (MapEntry) map.get(key)) != null) 379 value = entry.getValue(); 380 381 return mru.add(value); 382 } 383 384 393 public Collection values() { 394 return new AbstractCollection () { 395 public int size() { 396 return Cache.this.size(); 397 } 398 399 public Iterator iterator() { 400 return getValueIterator(); 401 } 402 }; 403 } 404 405 411 public synchronized Object remove(Object key) { 412 cleanup(); 413 mru.remove(key); 414 MapEntry entry = (MapEntry) map.remove(key); 415 return (entry != null) ? entry.getValue() : null; 416 } 417 418 423 public Set keySet() { 424 cleanup(); 425 return map.keySet(); 426 } 427 428 440 public Set entrySet() { 441 cleanup(); 442 return map.entrySet(); 443 } 444 445 451 public boolean isEmpty() { 452 cleanup(); 453 return map.isEmpty(); 454 } 455 456 462 public boolean containsValue(Object obj) { 463 for (Iterator it = map.entrySet().iterator(); it.hasNext(); ) { 464 MapEntry entry = (MapEntry) it.next(); 465 Object value = entry.getValue(); 466 if (value != null && value.equals(obj)) 467 return true; 468 } 469 470 return false; 471 } 472 473 479 public boolean containsKey(Object key) { 480 return map.containsKey(key); 481 } 482 483 488 public void putAll(Map cache) { 489 for (Iterator it = cache.keySet().iterator(); it.hasNext(); ) { 490 Object key = it.next(); 491 put(key, cache.get(key)); 492 } 493 } 494 495 498 private synchronized void cleanup() { 499 MapEntry entry; 500 while ((entry = (MapEntry)queue.poll()) != null) { 501 map.remove(entry.getKey()); 502 } 503 } 504 505 private Iterator getValueIterator() { 506 cleanup(); 507 return new ValueIterator(map.entrySet().iterator()); 508 } 509 510 } | Popular Tags |