1 16 17 18 package org.apache.commons.logging.impl; 19 20 import java.lang.ref.ReferenceQueue ; 21 import java.lang.ref.WeakReference ; 22 import java.util.*; 23 24 110 public final class WeakHashtable extends Hashtable { 111 112 116 private static final int MAX_CHANGES_BEFORE_PURGE = 100; 117 118 122 private static final int PARTIAL_PURGE_COUNT = 10; 123 124 125 private ReferenceQueue queue = new ReferenceQueue (); 126 127 private int changeCount = 0; 128 129 133 public WeakHashtable() {} 134 135 136 139 public boolean containsKey(Object key) { 140 Referenced referenced = new Referenced(key); 142 return super.containsKey(referenced); 143 } 144 145 148 public Enumeration elements() { 149 purge(); 150 return super.elements(); 151 } 152 153 156 public Set entrySet() { 157 purge(); 158 Set referencedEntries = super.entrySet(); 159 Set unreferencedEntries = new HashSet(); 160 for (Iterator it=referencedEntries.iterator(); it.hasNext();) { 161 Map.Entry entry = (Map.Entry) it.next(); 162 Referenced referencedKey = (Referenced) entry.getKey(); 163 Object key = referencedKey.getValue(); 164 Object value = entry.getValue(); 165 if (key != null) { 166 Entry dereferencedEntry = new Entry(key, value); 167 unreferencedEntries.add(dereferencedEntry); 168 } 169 } 170 return unreferencedEntries; 171 } 172 173 176 public Object get(Object key) { 177 Referenced referenceKey = new Referenced(key); 179 return super.get(referenceKey); 180 } 181 182 185 public Enumeration keys() { 186 purge(); 187 final Enumeration enumer = super.keys(); 188 return new Enumeration() { 189 public boolean hasMoreElements() { 190 return enumer.hasMoreElements(); 191 } 192 public Object nextElement() { 193 Referenced nextReference = (Referenced) enumer.nextElement(); 194 return nextReference.getValue(); 195 } 196 }; 197 } 198 199 200 203 public Set keySet() { 204 purge(); 205 Set referencedKeys = super.keySet(); 206 Set unreferencedKeys = new HashSet(); 207 for (Iterator it=referencedKeys.iterator(); it.hasNext();) { 208 Referenced referenceKey = (Referenced) it.next(); 209 Object keyValue = referenceKey.getValue(); 210 if (keyValue != null) { 211 unreferencedKeys.add(keyValue); 212 } 213 } 214 return unreferencedKeys; 215 } 216 217 220 public Object put(Object key, Object value) { 221 if (key == null) { 223 throw new NullPointerException ("Null keys are not allowed"); 224 } 225 if (value == null) { 226 throw new NullPointerException ("Null values are not allowed"); 227 } 228 229 if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) { 232 purge(); 233 changeCount = 0; 234 } 235 else if ((changeCount % PARTIAL_PURGE_COUNT) == 0) { 237 purgeOne(); 238 } 239 240 Object result = null; 241 Referenced keyRef = new Referenced(key, queue); 242 return super.put(keyRef, value); 243 } 244 245 248 public void putAll(Map t) { 249 if (t != null) { 250 Set entrySet = t.entrySet(); 251 for (Iterator it=entrySet.iterator(); it.hasNext();) { 252 Map.Entry entry = (Map.Entry) it.next(); 253 put(entry.getKey(), entry.getValue()); 254 } 255 } 256 } 257 258 261 public Collection values() { 262 purge(); 263 return super.values(); 264 } 265 266 269 public Object remove(Object key) { 270 if (changeCount++ > MAX_CHANGES_BEFORE_PURGE) { 273 purge(); 274 changeCount = 0; 275 } 276 else if ((changeCount % PARTIAL_PURGE_COUNT) == 0) { 278 purgeOne(); 279 } 280 return super.remove(new Referenced(key)); 281 } 282 283 286 public boolean isEmpty() { 287 purge(); 288 return super.isEmpty(); 289 } 290 291 294 public int size() { 295 purge(); 296 return super.size(); 297 } 298 299 302 public String toString() { 303 purge(); 304 return super.toString(); 305 } 306 307 310 protected void rehash() { 311 purge(); 313 super.rehash(); 314 } 315 316 320 private void purge() { 321 synchronized (queue) { 322 WeakKey key; 323 while ((key = (WeakKey) queue.poll()) != null) { 324 super.remove(key.getReferenced()); 325 } 326 } 327 } 328 329 333 private void purgeOne() { 334 335 synchronized (queue) { 336 WeakKey key = (WeakKey) queue.poll(); 337 if (key != null) { 338 super.remove(key.getReferenced()); 339 } 340 } 341 } 342 343 344 private final static class Entry implements Map.Entry { 345 346 private final Object key; 347 private final Object value; 348 349 private Entry(Object key, Object value) { 350 this.key = key; 351 this.value = value; 352 } 353 354 public boolean equals(Object o) { 355 boolean result = false; 356 if (o != null && o instanceof Map.Entry) { 357 Map.Entry entry = (Map.Entry) o; 358 result = (getKey()==null ? 359 entry.getKey() == null : 360 getKey().equals(entry.getKey())) 361 && 362 (getValue()==null ? 363 entry.getValue() == null : 364 getValue().equals(entry.getValue())); 365 } 366 return result; 367 } 368 369 public int hashCode() { 370 371 return (getKey()==null ? 0 : getKey().hashCode()) ^ 372 (getValue()==null ? 0 : getValue().hashCode()); 373 } 374 375 public Object setValue(Object value) { 376 throw new UnsupportedOperationException ("Entry.setValue is not supported."); 377 } 378 379 public Object getValue() { 380 return value; 381 } 382 383 public Object getKey() { 384 return key; 385 } 386 } 387 388 389 390 private final static class Referenced { 391 392 private final WeakReference reference; 393 private final int hashCode; 394 395 399 private Referenced(Object referant) { 400 reference = new WeakReference (referant); 401 hashCode = referant.hashCode(); 404 } 405 406 410 private Referenced(Object key, ReferenceQueue queue) { 411 reference = new WeakKey(key, queue, this); 412 hashCode = key.hashCode(); 415 416 } 417 418 public int hashCode() { 419 return hashCode; 420 } 421 422 private Object getValue() { 423 return reference.get(); 424 } 425 426 public boolean equals(Object o) { 427 boolean result = false; 428 if (o instanceof Referenced) { 429 Referenced otherKey = (Referenced) o; 430 Object thisKeyValue = getValue(); 431 Object otherKeyValue = otherKey.getValue(); 432 if (thisKeyValue == null) { 433 result = (otherKeyValue == null); 434 435 if (result == true) { 442 result = (this.hashCode() == otherKey.hashCode()); 443 } 444 } 449 else 450 { 451 result = thisKeyValue.equals(otherKeyValue); 452 } 453 } 454 return result; 455 } 456 } 457 458 463 private final static class WeakKey extends WeakReference { 464 465 private final Referenced referenced; 466 467 private WeakKey(Object key, 468 ReferenceQueue queue, 469 Referenced referenced) { 470 super(key, queue); 471 this.referenced = referenced; 472 } 473 474 private Referenced getReferenced() { 475 return referenced; 476 } 477 } 478 } 479 | Popular Tags |