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