View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software 
12   * distributed under the License is distributed on an "AS IS" BASIS, 
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
14   * See the License for the specific language governing permissions and 
15   * limitations under the License.
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          // remove garbage collected elements
44          processQueue();
45  
46          // get an iterator of the superclass WeakHashSet
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                  // unwrap the element
56                  return getReferenceObject((WeakReference) i.next());
57              }
58  
59              public void remove() {
60                  // remove the element from the HashSet
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;	/* Hashcode of key, stored here since the key
131                                may be tossed by the GC */
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         /* A WeakElement is equal to another WeakElement iff they both refer to objects
152                that are, in turn, equal according to their own equals methods */
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