1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 package org.onemind.commons.java.lang.ref;
22
23 import java.util.*;
24 import java.lang.ref.*;
25 /***
26 * @author TiongHiang Lee (thlee@onemindsoft.org)
27 * @version $Id: SoftHashMap.java,v 1.1 2004/10/23 15:24:35 thlee Exp $ $Name: $
28 * Credits: Article by Heinz Kabutz at http://archive.devx.com/java/free/articles/Kabutz01/Kabutz01-1.asp
29 */
30 public class SoftHashMap extends AbstractMap
31 {
32
33 /*** We define our own subclass of SoftReference which contains
34 not only the value but also the key to make it easier to find
35 the entry in the HashMap after it's been garbage collected. */
36 private static class SoftValue extends SoftReference
37 {
38 private final Object key;
39
40 /*** Did you know that an outer class can access private data
41 members and methods of an inner class? I didn't know that!
42 I thought it was only the inner class who could access the
43 outer class's private information. An outer class can also
44 access private members of an inner class inside its inner
45 class. */
46 private SoftValue(Object k, Object key, ReferenceQueue q)
47 {
48 super(k, q);
49 this.key = key;
50 }
51 }
52
53 /*** The internal HashMap that will hold the SoftReference. */
54 private final Map hash = new HashMap();
55
56 /*** The number of "hard" references to hold internally. */
57 private final int HARD_REF_SIZE;
58
59 /*** The FIFO list of hard references, order of last access. */
60 private final LinkedList hardRefCache;
61
62 /*** Reference queue for cleared SoftReference objects. */
63 private final ReferenceQueue queue = new ReferenceQueue();
64
65 /***
66 * Constructor
67 */
68 public SoftHashMap()
69 {
70 this(0);
71 }
72
73 /***
74 * Constructor
75 * @param hardSize the hard reference size to maintain
76 */
77 public SoftHashMap(int hardSize)
78 {
79 HARD_REF_SIZE = hardSize;
80 if (HARD_REF_SIZE>0)
81 {
82 hardRefCache = new LinkedList();
83 } else
84 {
85 hardRefCache = null;
86 }
87 }
88
89 public Object get(Object key)
90 {
91 Object result = null;
92
93 SoftReference soft_ref = (SoftReference) hash.get(key);
94 if (soft_ref != null)
95 {
96
97
98
99 result = soft_ref.get();
100 if (result == null)
101 {
102
103
104 hash.remove(key);
105 } else
106 {
107 if (HARD_REF_SIZE>0)
108 {
109
110
111
112
113
114 hardRefCache.addFirst(result);
115 if (hardRefCache.size() > HARD_REF_SIZE)
116 {
117
118 hardRefCache.removeLast();
119 }
120 }
121 }
122 }
123 return result;
124 }
125
126 /***
127 * Go through the ReferenceQueue and remove garbage
128 * collected SoftValue objects from the HashMap
129 */
130 private void _cleanCollectedValues()
131 {
132 SoftValue sv;
133 while ((sv = (SoftValue) queue.poll()) != null)
134 {
135 hash.remove(sv.key);
136 }
137 }
138
139 /***
140 * Here we put the key, value pair into the HashMap using
141 * a SoftValue object.
142 */
143 public Object put(Object key, Object value)
144 {
145 _cleanCollectedValues();
146 return hash.put(key, new SoftValue(value, key, queue));
147 }
148
149 /***
150 * {@inheritDoc}
151 */
152 public Object remove(Object key)
153 {
154 _cleanCollectedValues();
155 return hash.remove(key);
156 }
157
158 /***
159 * {@inheritDoc}
160 */
161 public void clear()
162 {
163 if (HARD_REF_SIZE>0)
164 {
165 hardRefCache.clear();
166 }
167 _cleanCollectedValues();
168 hash.clear();
169 }
170
171 /***
172 * {@inheritDoc}
173 */
174 public int size()
175 {
176 _cleanCollectedValues();
177 return hash.size();
178 }
179
180 /***
181 * {@inheritDoc}
182 */
183 public Set entrySet()
184 {
185
186 throw new UnsupportedOperationException();
187 }
188 }