KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > nutch > util > SoftHashMap


1 /* Copyright (c) 2003 The Nutch Organization. All rights reserved. */
2 /* Use subject to the conditions in http://www.nutch.org/LICENSE.txt. */
3
4 package net.nutch.util;
5
6 import java.lang.ref.SoftReference JavaDoc;
7 import java.util.AbstractMap JavaDoc;
8 import java.util.ArrayList JavaDoc;
9 import java.util.Collections JavaDoc;
10 import java.util.Collection JavaDoc;
11 import java.util.HashMap JavaDoc;
12 import java.util.Map JavaDoc;
13 import java.util.Set JavaDoc;
14
15 /**
16  * A Map which uses {@link SoftReference}s to keep track of values.
17  *
18  * <p>
19  *
20  * This class is suitable for use as a best-effort caching mechanism.
21  * Under the hood, it is simply a {@link HashMap}, which wraps it's
22  * values with SoftReference</code>s. Unlike <code>HashMap</code>,
23  * however, null values should not be used- they will be
24  * indistinguisable from values which have been garbage collected.
25  *
26  * <p>
27  *
28  * Values should implement {@link SoftHashMap.FinalizationNotifier}, so keys
29  * can be cleaned up as values are garbage collected. If values are added
30  * which do not support this interface, the associated keys will continue to be
31  * referenced by this data structure until explicitly removed.
32  *
33  * <p>
34  *
35  * Expiration policy is determined by the JVM's implementation of
36  * <code>SoftReference</code>.
37  */

38 public class SoftHashMap extends AbstractMap JavaDoc implements Map JavaDoc {
39   Map JavaDoc hashMap;
40   ArrayList JavaDoc keysToDelete;
41
42   /**
43    * An interface for Object which accept notification when an another
44    * Object is finalized.
45    */

46   public interface FinalizationListener {
47     /**
48      * This method will be called when a {@link
49      * SoftHashMap.FinalizationNotifier} this Object is registered with is
50      * being finalized. <em>Note</em> that this method is not passed a
51      * reference to the Object which is undergoing finalization, since creating
52      * a new reference to that object may block finalization.
53      */

54     public void finalizationOccurring();
55   }
56
57   /**
58    * An interface for a Objects which can notify an object when they are
59    * finalized. Upon finalization, Objects which implement this interface will
60    * call the <code>finalizationOccurring</code> method of all {@link
61    * SoftHashMap.FinalizationListener}s that have registered with it.
62    */

63   public interface FinalizationNotifier {
64     /**
65      * Registers a {@link SoftHashMap.FinalizationListener} for this object.
66      */

67     public void addFinalizationListener(FinalizationListener listener);
68   }
69
70   private class MyFinalizationListener implements FinalizationListener {
71     Object JavaDoc key;
72
73     MyFinalizationListener(Object JavaDoc key, FinalizationNotifier value) {
74       this.key= key;
75       value.addFinalizationListener(this);
76     }
77
78     public void finalizationOccurring() {
79       SoftHashMap.this.queueKeyForDeletion(key);
80     }
81
82   }
83
84   public SoftHashMap() {
85     hashMap= Collections.synchronizedMap(new HashMap JavaDoc());
86     keysToDelete= new ArrayList JavaDoc(128);
87   }
88
89   public void clear() {
90     hashMap.clear();
91   }
92
93   // queues a key for deletion- called by FinalizationListener which
94
// is listening for a value's expiration
95
protected void queueKeyForDeletion(Object JavaDoc key) {
96     synchronized (keysToDelete) {
97       purgeQueuedKeys();
98       keysToDelete.add(key);
99     }
100   }
101
102   // purges keys listed in keysToDelete from map
103
protected void purgeQueuedKeys() {
104     synchronized (keysToDelete) {
105       for (int i= keysToDelete.size() - 1; i >= 0 ; i--) {
106         remove(keysToDelete.get(i));
107       }
108       keysToDelete.clear();
109     }
110   }
111
112   /**
113    * Returns true if this map contains a mapping for the specified key.
114    *
115    * <em>Note</em> that this method can return true if the value has
116    * been garbage collected, but the key has not been cleared.
117    * Additionally, the finalizer may invalidate the result of this
118    * operation before a subsequent <code>get()</code> can be issued.
119    */

120   public boolean containsKey(Object JavaDoc key) {
121     return hashMap.containsKey(key);
122   }
123
124   /**
125    * Not Implemented
126    *
127    * <em>Note</em> that the finalizer may invalidate the result an
128    * implementation would return.
129    */

130   public boolean containsValue(Object JavaDoc value)
131     throws UnsupportedOperationException JavaDoc {
132     throw new UnsupportedOperationException JavaDoc("SoftHashMap.containsValue is "
133                                             + "not implemented");
134   }
135
136   /**
137    * Not Implemented
138    */

139   public Set JavaDoc entrySet() throws UnsupportedOperationException JavaDoc {
140     throw new
141       UnsupportedOperationException JavaDoc("SoftHashMap.entrySet() not implemented");
142   }
143
144   public Object JavaDoc get(Object JavaDoc key) {
145     SoftReference JavaDoc ref= (SoftReference JavaDoc) hashMap.get(key);
146     if (ref == null) {
147       return null;
148     }
149     return ref.get();
150   }
151
152   public boolean isEmpty() {
153     purgeQueuedKeys();
154     return hashMap.isEmpty();
155   }
156
157   public Set JavaDoc keySet() {
158     purgeQueuedKeys();
159     return hashMap.keySet();
160   }
161
162
163   /**
164    * Associates the specified value with the specified key in this
165    * map. If the map previously contained a mapping for this key, the
166    * old value is replaced.
167    *
168    * <p>
169    *
170    * <em>Note</em>: <code>value<code> must implemnt FinalizationNotifier
171    * for keys to be freed properly when values are garbage collected.
172    */

173   public Object JavaDoc put(Object JavaDoc key, Object JavaDoc value) {
174     purgeQueuedKeys();
175     SoftReference JavaDoc oldRef=
176       (SoftReference JavaDoc) hashMap.put(key, new SoftReference JavaDoc(value));
177
178     try {
179       new MyFinalizationListener(key, (FinalizationNotifier) value);
180     } catch (ClassCastException JavaDoc e) {
181       // fixme: throw an exception? warn?
182
}
183     
184     if (oldRef == null)
185       return null;
186     return oldRef.get();
187   }
188
189   public Object JavaDoc remove(Object JavaDoc key) {
190     SoftReference JavaDoc ref= (SoftReference JavaDoc) hashMap.remove(key);
191     if (ref == null)
192       return null;
193     return ref.get();
194   }
195
196   public int size() {
197     purgeQueuedKeys();
198     return hashMap.size();
199   }
200
201   /**
202    * Not Implemented
203    */

204   public Collection JavaDoc values() throws UnsupportedOperationException JavaDoc {
205     throw new
206       UnsupportedOperationException JavaDoc("SoftHashMap: values() not implemnted");
207   }
208
209 }
210
Popular Tags