1
17 package org.apache.tomcat.util.collections;
18
19 import java.lang.ref.Reference;
20 import java.lang.ref.ReferenceQueue;
21 import java.lang.ref.WeakReference;
22 import java.util.AbstractMap;
23 import java.util.AbstractSet;
24 import java.util.Collection;
25 import java.util.Iterator;
26 import java.util.Map;
27 import java.util.Objects;
28 import java.util.Set;
29 import java.util.concurrent.ConcurrentHashMap;
30 import java.util.concurrent.ConcurrentMap;
31
32
41 public class ManagedConcurrentWeakHashMap<K, V> extends AbstractMap<K, V> implements
42 ConcurrentMap<K, V> {
43
44 private final ConcurrentMap<Key, V> map = new ConcurrentHashMap<>();
45 private final ReferenceQueue<Object> queue = new ReferenceQueue<>();
46
47
51 public void maintain() {
52 Key key;
53 while ((key = (Key) queue.poll()) != null) {
54 if (key.isDead()) {
55
56 continue;
57 }
58 key.ackDeath();
59 map.remove(key);
60 }
61 }
62
63 private static class Key extends WeakReference<Object> {
64 private final int hash;
65 private boolean dead;
66
67 public Key(Object key, ReferenceQueue<Object> queue) {
68 super(key, queue);
69 hash = key.hashCode();
70 }
71
72 @Override
73 public int hashCode() {
74 return hash;
75 }
76
77 @Override
78 public boolean equals(Object obj) {
79 if (this == obj) {
80 return true;
81 }
82 if (dead) {
83
84
85 return false;
86 }
87 if (!(obj instanceof Reference<?>)) {
88 return false;
89 }
90 Object oA = get();
91 Object oB = ((Reference<?>) obj).get();
92 if (oA == oB) {
93 return true;
94 }
95 if (oA == null || oB == null) {
96 return false;
97 }
98 return oA.equals(oB);
99 }
100
101 public void ackDeath() {
102 this.dead = true;
103 }
104
105 public boolean isDead() {
106 return dead;
107 }
108 }
109
110
114 private Key createStoreKey(Object key) {
115 return new Key(key, queue);
116 }
117
118
122 private Key createLookupKey(Object key) {
123 return new Key(key, null);
124 }
125
126 @Override
127 public int size() {
128 return map.size();
129 }
130
131 @Override
132 public boolean isEmpty() {
133 return map.isEmpty();
134 }
135
136 @Override
137 public boolean containsValue(Object value) {
138 if (value == null) {
139 return false;
140 }
141 return map.containsValue(value);
142 }
143
144 @Override
145 public boolean containsKey(Object key) {
146 if (key == null) {
147 return false;
148 }
149 return map.containsKey(createLookupKey(key));
150 }
151
152 @Override
153 public V get(Object key) {
154 if (key == null) {
155 return null;
156 }
157 return map.get(createLookupKey(key));
158 }
159
160 @Override
161 public V put(K key, V value) {
162 Objects.requireNonNull(value);
163 return map.put(createStoreKey(key), value);
164 }
165
166 @Override
167 public V remove(Object key) {
168 return map.remove(createLookupKey(key));
169 }
170
171 @Override
172 public void clear() {
173 map.clear();
174
175
176 maintain();
177 }
178
179 @Override
180 public V putIfAbsent(K key, V value) {
181 Objects.requireNonNull(value);
182 Key storeKey = createStoreKey(key);
183 V oldValue = map.putIfAbsent(storeKey, value);
184 if (oldValue != null) {
185 storeKey.ackDeath();
186 }
187 return oldValue;
188 }
189
190 @Override
191 public boolean remove(Object key, Object value) {
192 if (value == null) {
193 return false;
194 }
195 return map.remove(createLookupKey(key), value);
196 }
197
198 @Override
199 public boolean replace(K key, V oldValue, V newValue) {
200 Objects.requireNonNull(newValue);
201 return map.replace(createLookupKey(key), oldValue, newValue);
202 }
203
204 @Override
205 public V replace(K key, V value) {
206 Objects.requireNonNull(value);
207 return map.replace(createLookupKey(key), value);
208 }
209
210 @Override
211 public Collection<V> values() {
212 return map.values();
213 }
214
215 @Override
216 public Set<Map.Entry<K, V>> entrySet() {
217 return new AbstractSet<Map.Entry<K, V>>() {
218 @Override
219 public boolean isEmpty() {
220 return map.isEmpty();
221 }
222
223 @Override
224 public int size() {
225 return map.size();
226 }
227
228 @Override
229 public Iterator<Map.Entry<K, V>> iterator() {
230 return new Iterator<Map.Entry<K, V>>() {
231 private final Iterator<Map.Entry<Key, V>> it = map
232 .entrySet().iterator();
233
234 @Override
235 public boolean hasNext() {
236 return it.hasNext();
237 }
238
239 @Override
240 public Map.Entry<K, V> next() {
241 return new Map.Entry<K, V>() {
242 private final Map.Entry<Key, V> en = it.next();
243
244 @SuppressWarnings("unchecked")
245 @Override
246 public K getKey() {
247 return (K) en.getKey().get();
248 }
249
250 @Override
251 public V getValue() {
252 return en.getValue();
253 }
254
255 @Override
256 public V setValue(V value) {
257 Objects.requireNonNull(value);
258 return en.setValue(value);
259 }
260 };
261 }
262
263 @Override
264 public void remove() {
265 it.remove();
266 }
267 };
268 }
269 };
270 }
271 }
272