1 23 24 package com.sun.jdo.spi.persistence.utility; 25 26 import java.lang.ref.ReferenceQueue ; 27 import java.lang.ref.WeakReference ; 28 29 import java.util.AbstractCollection ; 30 import java.util.AbstractSet ; 31 import java.util.Collection ; 32 import java.util.HashMap ; 33 import java.util.Iterator ; 34 import java.util.Map ; 35 import java.util.NoSuchElementException ; 36 import java.util.Set ; 37 38 50 51 public class WeakValueHashMap extends HashMap { 52 53 54 private ReferenceQueue queue = new ReferenceQueue (); 55 56 60 public int size() { 61 return entrySet().size(); 63 } 64 65 69 public boolean isEmpty() { 70 return size() == 0; 71 } 72 73 80 public boolean containsKey(Object key) { 81 processQueue(); 83 return super.containsKey(key); 84 } 85 86 92 public boolean containsValue(Object value) { 93 return super.containsValue(WeakValue.create(value)); 94 } 95 96 101 public Object get(Object key) { 102 return getReferenceObject((WeakReference ) super.get(key)); 107 } 108 109 117 public Object put(Object key, Object value) { 118 processQueue(); 128 129 WeakValue oldValue = 130 (WeakValue)super.put(key, WeakValue.create(key, value, queue)); 131 return getReferenceObject(oldValue); 132 } 133 134 141 public Object remove(Object key) { 142 return getReferenceObject((WeakReference ) super.remove(key)); 143 } 144 145 149 private final Object getReferenceObject(WeakReference ref) { 150 return (ref == null) ? null : ref.get(); 151 } 152 153 158 private void processQueue() { 159 WeakValue wv = null; 160 161 while ((wv = (WeakValue) this.queue.poll()) != null) { 162 super.remove(wv.key); 165 } 166 } 167 168 169 170 175 private static class WeakValue extends WeakReference { 176 180 private Object key; 181 182 private WeakValue(Object value) { 183 super(value); 184 } 185 186 190 private static WeakValue create(Object value) { 191 if (value == null) return null; 192 else return new WeakValue(value); 193 } 194 195 private WeakValue(Object key, Object value, ReferenceQueue queue) { 196 super(value, queue); 197 this.key = key; 198 } 199 200 203 private static WeakValue create(Object key, Object value, 204 ReferenceQueue queue) { 205 if (value == null) return null; 206 else return new WeakValue(key, value, queue); 207 } 208 209 214 public boolean equals(Object obj) { 215 if (this == obj) 216 return true; 217 218 if (!(obj instanceof WeakValue)) 219 return false; 220 221 Object ref1 = this.get(); 222 Object ref2 = ((WeakValue) obj).get(); 223 224 if (ref1 == ref2) 225 return true; 226 227 if ((ref1 == null) || (ref2 == null)) 228 return false; 229 230 return ref1.equals(ref2); 231 } 232 233 236 public int hashCode() { 237 Object ref = this.get(); 238 239 return (ref == null) ? 0 : ref.hashCode(); 240 } 241 } 242 243 247 private class Entry implements Map.Entry { 248 private Map.Entry ent; 249 private Object value; 252 253 Entry(Map.Entry ent, Object value) { 254 this.ent = ent; 255 this.value = value; 256 } 257 258 public Object getKey() { 259 return ent.getKey(); 260 } 261 262 public Object getValue() { 263 return value; 264 } 265 266 public Object setValue(Object value) { 267 Object oldValue = this.value; 270 this.value = value; 271 ent.setValue(WeakValue.create(getKey(), value, queue)); 272 return oldValue; 273 } 274 275 private boolean valEquals(Object o1, Object o2) { 276 return (o1 == null) ? (o2 == null) : o1.equals(o2); 277 } 278 279 public boolean equals(Object o) { 280 if (!(o instanceof Map.Entry )) return false; 281 Map.Entry e = (Map.Entry ) o; 282 return (valEquals(ent.getKey(), e.getKey()) 283 && valEquals(value, e.getValue())); 284 } 285 286 public int hashCode() { 287 Object k; 288 return ((((k = ent.getKey()) == null) ? 0 : k.hashCode()) 289 ^ ((value == null) ? 0 : value.hashCode())); 290 } 291 292 } 293 294 298 private class EntrySet extends AbstractSet { 299 300 public Iterator iterator() { 301 processQueue(); 303 304 return new Iterator () { 305 Iterator hashIterator = hashEntrySet.iterator(); 306 Entry next = null; 307 308 public boolean hasNext() { 309 if (hashIterator.hasNext()) { 310 Map.Entry ent = (Map.Entry ) hashIterator.next(); 313 WeakValue wv = (WeakValue) ent.getValue(); 314 Object v = (wv == null) ? null : wv.get(); 315 next = new Entry(ent, v); 316 return true; 317 } 318 return false; 319 } 320 321 public Object next() { 322 if ((next == null) && !hasNext()) 323 throw new NoSuchElementException (); 324 Entry e = next; 325 next = null; 326 return e; 327 } 328 329 public void remove() { 330 hashIterator.remove(); 331 } 332 333 }; 334 } 335 336 public boolean isEmpty() { 337 return !(iterator().hasNext()); 338 } 339 340 public int size() { 341 int j = 0; 342 for (Iterator i = iterator(); i.hasNext(); i.next()) j++; 343 return j; 344 } 345 346 public boolean remove(Object o) { 347 if (!(o instanceof Map.Entry )) return false; 348 Map.Entry e = (Map.Entry ) o; 349 Object ek = e.getKey(); 350 Object ev = e.getValue(); 351 Object hv = WeakValueHashMap.this.get(ek); 352 if (hv == null) { 353 if ((ev == null) && WeakValueHashMap.this.containsKey(ek)) { 356 WeakValueHashMap.this.remove(ek); 357 return true; 358 } else { 359 return false; 360 } 361 } else if (hv.equals(ev)) { 363 WeakValueHashMap.this.remove(ek); 364 return true; 365 } 366 367 return false; 368 } 369 370 public int hashCode() { 371 int h = 0; 372 for (Iterator i = hashEntrySet.iterator(); i.hasNext(); ) { 373 Map.Entry ent = (Map.Entry ) i.next(); 374 Object k; 375 WeakValue wv = (WeakValue) ent.getValue(); 376 if (wv == null) continue; 377 h += ((((k = ent.getKey()) == null) ? 0 : k.hashCode()) 378 ^ wv.hashCode()); 379 } 380 return h; 381 } 382 383 } 384 385 private Set hashEntrySet = null; 388 private Set entrySet = null; 390 391 395 public Set entrySet() { 396 if (entrySet == null) { 397 hashEntrySet = super.entrySet(); 398 entrySet = new EntrySet(); 399 } 400 return entrySet; 401 } 402 403 private transient Collection values = null; 405 406 412 public Collection values() { 413 if (values == null) { 416 values = new AbstractCollection () { 417 public Iterator iterator() { 418 return new Iterator () { 419 private Iterator i = entrySet().iterator(); 420 421 public boolean hasNext() { 422 return i.hasNext(); 423 } 424 425 public Object next() { 426 return ((Entry)i.next()).getValue(); 427 } 428 429 public void remove() { 430 i.remove(); 431 } 432 }; 433 } 434 435 public int size() { 436 return WeakValueHashMap.this.size(); 437 } 438 439 public boolean contains(Object v) { 440 return WeakValueHashMap.this.containsValue(v); 441 } 442 }; 443 } 444 return values; 445 } 446 447 } 448 | Popular Tags |