1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 package org.apache.jdo.util;
19
20 import java.lang.ref.ReferenceQueue;
21 import java.lang.ref.WeakReference;
22 import java.util.HashSet;
23 import java.util.Iterator;
24
25 /**
26 * A weak HashSet. An element stored in the WeakHashSet might be
27 * garbage collected, if there is no strong reference to this element.
28 */
29
30 public class WeakHashSet extends HashSet {
31 /**
32 * Helps to detect garbage collected values.
33 */
34 ReferenceQueue queue = new ReferenceQueue();
35
36 /**
37 * Returns an iterator over the elements in this set. The elements
38 * are returned in no particular order.
39 *
40 * @return an Iterator over the elements in this set.
41 */
42 public Iterator iterator() {
43
44 processQueue();
45
46
47 final Iterator i = super.iterator();
48
49 return new Iterator() {
50 public boolean hasNext() {
51 return i.hasNext();
52 }
53
54 public Object next() {
55
56 return getReferenceObject((WeakReference) i.next());
57 }
58
59 public void remove() {
60
61 i.remove();
62 }
63 };
64 }
65
66 /**
67 * Returns <code>true</code> if this set contains the specified element.
68 *
69 * @param o element whose presence in this set is to be tested.
70 * @return <code>true</code> if this set contains the specified element.
71 */
72 public boolean contains(Object o) {
73 return super.contains(WeakElement.create(o));
74 }
75
76 /**
77 * Adds the specified element to this set if it is not already
78 * present.
79 *
80 * @param o element to be added to this set.
81 * @return <code>true</code> if the set did not already contain the specified
82 * element.
83 */
84 public boolean add(Object o) {
85 processQueue();
86 return super.add(WeakElement.create(o, this.queue));
87 }
88
89 /**
90 * Removes the given element from this set if it is present.
91 *
92 * @param o object to be removed from this set, if present.
93 * @return <code>true</code> if the set contained the specified element.
94 */
95 public boolean remove(Object o) {
96 boolean ret = super.remove(WeakElement.create(o));
97 processQueue();
98 return ret;
99 }
100
101 /**
102 * A convenience method to return the object held by the
103 * weak reference or <code>null</code> if it does not exist.
104 */
105 private final Object getReferenceObject(WeakReference ref) {
106 return (ref == null) ? null : ref.get();
107 }
108
109 /**
110 * Removes all garbage collected values with their keys from the map.
111 * Since we don't know how much the ReferenceQueue.poll() operation
112 * costs, we should call it only in the add() method.
113 */
114 private final void processQueue() {
115 WeakElement wv = null;
116
117 while ((wv = (WeakElement) this.queue.poll()) != null) {
118 super.remove(wv);
119 }
120 }
121
122 /**
123 * A WeakHashSet stores objects of class WeakElement.
124 * A WeakElement wraps the element that should be stored in the WeakHashSet.
125 * WeakElement inherits from java.lang.ref.WeakReference.
126 * It redefines equals and hashCode which delegate to the corresponding methods
127 * of the wrapped element.
128 */
129 static private class WeakElement extends WeakReference {
130 private int hash;
131
132
133 private WeakElement(Object o) {
134 super(o);
135 hash = o.hashCode();
136 }
137
138 private WeakElement(Object o, ReferenceQueue q) {
139 super(o, q);
140 hash = o.hashCode();
141 }
142
143 private static WeakElement create(Object o) {
144 return (o == null) ? null : new WeakElement(o);
145 }
146
147 private static WeakElement create(Object o, ReferenceQueue q) {
148 return (o == null) ? null : new WeakElement(o, q);
149 }
150
151
152
153 public boolean equals(Object o) {
154 if (this == o)
155 return true;
156 if (!(o instanceof WeakElement))
157 return false;
158 Object t = this.get();
159 Object u = ((WeakElement) o).get();
160 if (t == u)
161 return true;
162 if ((t == null) || (u == null))
163 return false;
164 return t.equals(u);
165 }
166
167 public int hashCode() {
168 return hash;
169 }
170 }
171
172 }
173
174