1/* 2 * Copyright (c) 2005, 2008, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26package com.sun.jmx.mbeanserver; 27 28import static com.sun.jmx.mbeanserver.Util.*; 29 30import java.lang.ref.Reference; 31import java.lang.ref.ReferenceQueue; 32import java.lang.ref.WeakReference; 33 34import java.util.Map; 35 36 37/** 38 * <p>A map where keys are compared using identity comparison (like 39 * IdentityHashMap) but where the presence of an object as a key in 40 * the map does not prevent it being garbage collected (like 41 * WeakHashMap). This class does not implement the Map interface 42 * because it is difficult to ensure correct semantics for iterators 43 * over the entrySet().</p> 44 * 45 * <p>Because we do not implement Map, we do not copy the questionable 46 * interface where you can call get(k) or remove(k) for any type of k, 47 * which of course can only have an effect if k is of type K.</p> 48 * 49 * <p>This map does not support null keys.</p> 50 */ 51/* 52 * The approach 53 * is to wrap each key in a WeakReference and use the wrapped value as 54 * a key in an ordinary HashMap. The WeakReference has to be a 55 * subclass IdentityWeakReference (IWR) where two IWRs are equal if 56 * they refer to the same object. This enables us to find the entry 57 * again. 58 */ 59class WeakIdentityHashMap<K, V> { 60 private WeakIdentityHashMap() {} 61 62 static <K, V> WeakIdentityHashMap<K, V> make() { 63 return new WeakIdentityHashMap<K, V>(); 64 } 65 66 V get(K key) { 67 expunge(); 68 WeakReference<K> keyref = makeReference(key); 69 return map.get(keyref); 70 } 71 72 public V put(K key, V value) { 73 expunge(); 74 if (key == null) 75 throw new IllegalArgumentException("Null key"); 76 WeakReference<K> keyref = makeReference(key, refQueue); 77 return map.put(keyref, value); 78 } 79 80 public V remove(K key) { 81 expunge(); 82 WeakReference<K> keyref = makeReference(key); 83 return map.remove(keyref); 84 } 85 86 private void expunge() { 87 Reference<? extends K> ref; 88 while ((ref = refQueue.poll()) != null) 89 map.remove(ref); 90 } 91 92 private WeakReference<K> makeReference(K referent) { 93 return new IdentityWeakReference<K>(referent); 94 } 95 96 private WeakReference<K> makeReference(K referent, ReferenceQueue<K> q) { 97 return new IdentityWeakReference<K>(referent, q); 98 } 99 100 /** 101 * WeakReference where equals and hashCode are based on the 102 * referent. More precisely, two objects are equal if they are 103 * identical or if they both have the same non-null referent. The 104 * hashCode is the value the original referent had. Even if the 105 * referent is cleared, the hashCode remains. Thus, objects of 106 * this class can be used as keys in hash-based maps and sets. 107 */ 108 private static class IdentityWeakReference<T> extends WeakReference<T> { 109 IdentityWeakReference(T o) { 110 this(o, null); 111 } 112 113 IdentityWeakReference(T o, ReferenceQueue<T> q) { 114 super(o, q); 115 this.hashCode = (o == null) ? 0 : System.identityHashCode(o); 116 } 117 118 public boolean equals(Object o) { 119 if (this == o) 120 return true; 121 if (!(o instanceof IdentityWeakReference<?>)) 122 return false; 123 IdentityWeakReference<?> wr = (IdentityWeakReference<?>) o; 124 Object got = get(); 125 return (got != null && got == wr.get()); 126 } 127 128 public int hashCode() { 129 return hashCode; 130 } 131 132 private final int hashCode; 133 } 134 135 private Map<WeakReference<K>, V> map = newMap(); 136 private ReferenceQueue<K> refQueue = new ReferenceQueue<K>(); 137} 138