1 17 package org.apache.geronimo.kernel.basic; 18 19 import java.lang.ref.Reference ; 20 import java.lang.ref.WeakReference ; 21 import java.lang.ref.ReferenceQueue ; 22 import java.util.Collection ; 23 import java.util.Map ; 24 import java.util.Set ; 25 26 37 public class BasicProxyMap implements Map { 38 39 40 private static final int DEFAULT_CAPACITY = 16; 41 42 private static final float DEFAULT_LOAD_FACTOR = 0.75f; 43 44 private static final int MAXIMUM_CAPACITY = 1 << 30; 45 46 47 private float loadFactor; 48 49 private transient int size; 50 51 private transient ReferenceEntry[] data; 52 53 private transient int threshold; 54 55 58 private ReferenceQueue purgeQueue; 59 60 public BasicProxyMap() { 61 this.loadFactor = DEFAULT_LOAD_FACTOR; 62 this.data = new ReferenceEntry[DEFAULT_CAPACITY]; 63 this.threshold = calculateThreshold(DEFAULT_CAPACITY, loadFactor); 64 this.purgeQueue = new ReferenceQueue (); 65 } 66 67 72 public int size() { 73 purge(); 74 return size; 75 } 76 77 82 public boolean isEmpty() { 83 purge(); 84 return (size == 0); 85 } 86 87 93 public boolean containsKey(Object key) { 94 purge(); 95 ReferenceEntry entry = getEntry(key); 96 if (entry == null) { 97 return false; 98 } 99 return (entry.getValue() != null); 100 } 101 102 108 public boolean containsValue(Object value) { 109 purge(); 110 if (value == null || size == 0) { 111 return false; 112 } 113 ReferenceEntry [] table = data; 114 for (int i = 0; i < table.length; i++) { 115 ReferenceEntry entry = table[i]; 116 while (entry != null) { 117 if (value.equals(entry.getValue())) { 118 return true; 119 } 120 entry = entry.next; 121 } 122 } 123 return false; 124 } 125 126 132 public Object get(Object key) { 133 purge(); 134 ReferenceEntry entry = getEntry(key); 135 if (entry == null) { 136 return null; 137 } 138 return entry.getValue(); 139 } 140 141 142 150 public Object put(Object key, Object value) { 151 assert key != null: "key is null"; 152 assert value != null: "value is null"; 153 154 purge(); 155 156 int hashCode = hash(key); 157 int index = hashIndex(hashCode, data.length); 158 ReferenceEntry entry = data[index]; 159 while (entry != null) { 160 if (entry.hashCode == hashCode && key == entry.getKey()) { 161 return entry.setValue(value); 162 } 163 entry = entry.next; 164 } 165 166 createEntry(index, hashCode, key, value); 167 return null; 168 } 169 170 176 public Object remove(Object key) { 177 if (key == null) { 178 return null; 179 } 180 purge(); 181 int hashCode = hash(key); 182 int index = hashIndex(hashCode, data.length); 183 ReferenceEntry entry = data[index]; 184 ReferenceEntry previous = null; 185 while (entry != null) { 186 if (entry.hashCode == hashCode && (key == entry.getKey())) { 187 Object oldValue = entry.getValue(); 188 removeEntry(entry, index, previous); 189 return oldValue; 190 } 191 previous = entry; 192 entry = entry.next; 193 } 194 return null; 195 } 196 197 201 public void clear() { 202 ReferenceEntry[] data = this.data; 203 for (int i = data.length - 1; i >= 0; i--) { 204 data[i] = null; 205 } 206 size = 0; 207 while (purgeQueue.poll() != null) {} } 209 210 public Collection values() { 211 throw new UnsupportedOperationException (); 212 } 213 214 public void putAll(Map t) { 215 throw new UnsupportedOperationException (); 216 } 217 218 public Set entrySet() { 219 throw new UnsupportedOperationException (); 220 } 221 222 public Set keySet() { 223 throw new UnsupportedOperationException (); 224 } 225 226 228 233 private ReferenceEntry getEntry(Object key) { 234 if (key == null) { 235 return null; 236 } 237 int hashCode = hash(key); 238 ReferenceEntry entry = data[hashIndex(hashCode, data.length)]; 239 while (entry != null) { 240 if (entry.hashCode == hashCode && (key == entry.getKey())) { 241 return entry; 242 } 243 entry = entry.next; 244 } 245 return null; 246 } 247 248 257 private ReferenceEntry createEntry(int index, int hashCode, Object key, Object value) { 258 ReferenceEntry newEntry = new ReferenceEntry(this, data[index], hashCode, key, value); 259 data[index] = newEntry; 260 size++; 261 checkCapacity(); 262 return newEntry; 263 } 264 265 275 private void removeEntry(ReferenceEntry entry, int hashIndex, ReferenceEntry previous) { 276 if (previous == null) { 277 data[hashIndex] = entry.next; 278 } else { 279 previous.next = entry.next; 280 } 281 size--; 282 entry.next = null; 283 entry.clear(); 284 entry.value = null; 285 } 286 287 292 private void checkCapacity() { 293 if (size >= threshold) { 294 int newCapacity = data.length * 2; 295 if (newCapacity <= MAXIMUM_CAPACITY) { 296 ensureCapacity(newCapacity); 297 } 298 } 299 } 300 301 306 private void ensureCapacity(int newCapacity) { 307 int oldCapacity = data.length; 308 if (newCapacity <= oldCapacity) { 309 return; 310 } 311 312 ReferenceEntry oldEntries[] = data; 313 ReferenceEntry newEntries[] = new ReferenceEntry[newCapacity]; 314 315 for (int i = oldCapacity - 1; i >= 0; i--) { 316 ReferenceEntry entry = oldEntries[i]; 317 if (entry != null) { 318 oldEntries[i] = null; do { 320 ReferenceEntry next = entry.next; 321 int index = hashIndex(entry.hashCode, newCapacity); 322 entry.next = newEntries[index]; 323 newEntries[index] = entry; 324 entry = next; 325 } while (entry != null); 326 } 327 } 328 threshold = calculateThreshold(newCapacity, loadFactor); 329 data = newEntries; 330 } 331 332 340 private int calculateThreshold(int newCapacity, float factor) { 341 return (int) (newCapacity * factor); 342 } 343 344 352 private int hash(Object key) { 353 return System.identityHashCode(key); 354 } 355 356 364 private int hashIndex(int hashCode, int dataSize) { 365 return hashCode & (dataSize - 1); 366 } 367 368 371 379 private void purge() { 380 Reference entryRef = purgeQueue.poll(); 381 while (entryRef != null) { 382 purge(entryRef); 383 entryRef = purgeQueue.poll(); 384 } 385 } 386 387 392 private void purge(Reference purgedEntry) { 393 int hash = ((ReferenceEntry)purgedEntry).hashCode; 394 int index = hashIndex(hash, data.length); 395 ReferenceEntry previous = null; 396 ReferenceEntry currentEntry = data[index]; 397 while (currentEntry != null) { 398 if (currentEntry == purgedEntry) { 399 currentEntry.purged(); 400 if (previous == null) { 401 data[index] = currentEntry.next; 402 } else { 403 previous.next = currentEntry.next; 404 } 405 this.size--; 406 return; 407 } 408 previous = currentEntry; 409 currentEntry = currentEntry.next; 410 } 411 } 412 413 421 private static class ReferenceEntry extends WeakReference { 422 423 private ReferenceEntry next; 424 425 private int hashCode; 426 427 private Object value; 428 429 438 private ReferenceEntry(BasicProxyMap parent, ReferenceEntry next, int hashCode, Object key, Object value) { 439 super(key, parent.purgeQueue); 440 this.next = next; 441 this.hashCode = hashCode; 442 this.value = value; 443 } 444 445 451 private Object getKey() { 452 return this.get(); 453 } 454 455 461 private Object getValue() { 462 return value; 463 } 464 465 471 private Object setValue(Object obj) { 472 Object old = getValue(); 473 value = obj; 474 return old; 475 } 476 477 480 private void purged() { 481 this.clear(); 482 value = null; 483 } 484 } 485 } 486 | Popular Tags |