001
014
015 package com.liferay.portal.kernel.util;
016
017 import com.liferay.portal.kernel.memory.EqualityWeakReference;
018 import com.liferay.portal.kernel.memory.FinalizeAction;
019 import com.liferay.portal.kernel.memory.FinalizeManager;
020
021 import java.io.Serializable;
022
023 import java.lang.ref.Reference;
024
025 import java.util.AbstractCollection;
026 import java.util.AbstractSet;
027 import java.util.ArrayList;
028 import java.util.Collection;
029 import java.util.Iterator;
030 import java.util.List;
031 import java.util.Map;
032 import java.util.Set;
033 import java.util.concurrent.ConcurrentHashMap;
034 import java.util.concurrent.ConcurrentMap;
035
036
039 public class WeakValueConcurrentHashMap<K, V>
040 implements ConcurrentMap<K, V>, Serializable {
041
042 public WeakValueConcurrentHashMap() {
043 _map = new ConcurrentHashMap<K, Reference<V>>();
044 }
045
046 public WeakValueConcurrentHashMap(int initialCapacity) {
047 _map = new ConcurrentHashMap<K, Reference<V>>(initialCapacity);
048 }
049
050 public WeakValueConcurrentHashMap(
051 int initialCapacity, float loadFactor, int concurrencyLevel) {
052
053 _map = new ConcurrentHashMap<K, Reference<V>>(
054 initialCapacity, loadFactor, concurrencyLevel);
055 }
056
057 public WeakValueConcurrentHashMap(Map<? extends K, ? extends V> map) {
058 _map = new ConcurrentHashMap<K, Reference<V>>();
059
060 putAll(map);
061 }
062
063 @Override
064 public void clear() {
065 _map.clear();
066 }
067
068 @Override
069 public boolean containsKey(Object key) {
070 return _map.containsKey(key);
071 }
072
073 @Override
074 public boolean containsValue(Object value) {
075 return _map.containsValue(new EqualityWeakReference<V>((V)value));
076 }
077
078 @Override
079 public Set<Entry<K, V>> entrySet() {
080 if (_entrySet == null) {
081 _entrySet = new UnwrapEntrySet();
082 }
083
084 return _entrySet;
085 }
086
087 @Override
088 public V get(Object key) {
089 Reference<V> valueReference = _map.get(key);
090
091 if (valueReference != null) {
092 return valueReference.get();
093 }
094
095 return null;
096 }
097
098 @Override
099 public boolean isEmpty() {
100 return _map.isEmpty();
101 }
102
103 @Override
104 public Set<K> keySet() {
105 return _map.keySet();
106 }
107
108 @Override
109 public V put(K key, V value) {
110 Reference<V> valueReference = wrapValue(key, value);
111
112 valueReference = _map.putIfAbsent(key, valueReference);
113
114 if (valueReference != null) {
115 return valueReference.get();
116 }
117
118 return null;
119 }
120
121 @Override
122 public final void putAll(Map<? extends K, ? extends V> map) {
123 for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
124 K key = entry.getKey();
125 V value = entry.getValue();
126
127 Reference<V> valueReference = wrapValue(key, value);
128
129 _map.put(key, valueReference);
130 }
131 }
132
133 @Override
134 public V putIfAbsent(K key, V value) {
135 Reference<V> valueReference = wrapValue(key, value);
136
137 valueReference = _map.putIfAbsent(key, valueReference);
138
139 if (valueReference != null) {
140 return valueReference.get();
141 }
142
143 return null;
144 }
145
146 @Override
147 public V remove(Object key) {
148 Reference<V> valueReference = _map.remove(key);
149
150 if (valueReference != null) {
151 return valueReference.get();
152 }
153
154 return null;
155 }
156
157 @Override
158 public boolean remove(Object key, Object value) {
159 Reference<V> valueReference = wrapValue(key, value);
160
161 return _map.remove(key, valueReference);
162 }
163
164 @Override
165 public V replace(K key, V value) {
166 Reference<V> valueReference = wrapValue(key, value);
167
168 valueReference = _map.replace(key, valueReference);
169
170 if (valueReference != null) {
171 return valueReference.get();
172 }
173
174 return null;
175 }
176
177 @Override
178 public boolean replace(K key, V oldValue, V newValue) {
179 Reference<V> oldValueReference = wrapValue(key, oldValue);
180 Reference<V> newValueReference = wrapValue(key, newValue);
181
182 return _map.replace(key, oldValueReference, newValueReference);
183 }
184
185 @Override
186 public int size() {
187 return _map.size();
188 }
189
190 @Override
191 public Collection<V> values() {
192 if (_values == null) {
193 _values = new UnwrapValues();
194 }
195
196 return _values;
197 }
198
199 protected Reference<V> wrapValue(Object key, Object value) {
200 return FinalizeManager.register(
201 (V)value, new RemoveEntryFinalizeAction((K)key));
202 }
203
204 private transient Set<Map.Entry<K, V>> _entrySet;
205 private final ConcurrentMap<K, Reference<V>> _map;
206 private transient Collection<V> _values;
207
208 private class RemoveEntryFinalizeAction implements FinalizeAction {
209
210 public RemoveEntryFinalizeAction(K key) {
211 _key = key;
212 }
213
214 @Override
215 public void doFinalize() {
216 remove(_key);
217 }
218
219 private final K _key;
220
221 }
222
223 private class UnwrapEntry implements Map.Entry<K, V> {
224
225 public UnwrapEntry(Entry<K, Reference<V>> entry) {
226 _entry = entry;
227 }
228
229 @Override
230 public K getKey() {
231 return _entry.getKey();
232 }
233
234 @Override
235 public V getValue() {
236 Reference<V> valueReference = _entry.getValue();
237
238 if (valueReference != null) {
239 return valueReference.get();
240 }
241
242 return null;
243 }
244
245 @Override
246 public V setValue(V value) {
247 return WeakValueConcurrentHashMap.this.put(_entry.getKey(), value);
248 }
249
250 private Map.Entry<K, Reference<V>> _entry;
251
252 }
253
254 private class UnwrapEntryIterator implements Iterator<Map.Entry<K, V>> {
255
256 public UnwrapEntryIterator() {
257 _iterator = _map.entrySet().iterator();
258 }
259
260 @Override
261 public boolean hasNext() {
262 return _iterator.hasNext();
263 }
264
265 @Override
266 public Entry<K, V> next() {
267 return new UnwrapEntry(_iterator.next());
268 }
269
270 @Override
271 public void remove() {
272 _iterator.remove();
273 }
274
275 private Iterator<Map.Entry<K, Reference<V>>> _iterator;
276
277 }
278
279 private class UnwrapEntrySet extends AbstractSet<Map.Entry<K, V>> {
280
281 @Override
282 public void clear() {
283 WeakValueConcurrentHashMap.this.clear();
284 }
285
286 @Override
287 public boolean contains(Object obj) {
288 if (!(obj instanceof Map.Entry<?, ?>)) {
289 return false;
290 }
291
292 Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
293
294 V value = WeakValueConcurrentHashMap.this.get(entry.getKey());
295
296 if ((value != null) && value.equals(entry.getValue())) {
297 return true;
298 }
299 else {
300 return false;
301 }
302 }
303
304 @Override
305 public Iterator<Map.Entry<K, V>> iterator() {
306 return new UnwrapEntryIterator();
307 }
308
309 @Override
310 public boolean remove(Object obj) {
311 if (!(obj instanceof Map.Entry<?, ?>)) {
312 return false;
313 }
314
315 Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
316
317 return WeakValueConcurrentHashMap.this.remove(
318 entry.getKey(), entry.getValue());
319 }
320
321 @Override
322 public int size() {
323 return WeakValueConcurrentHashMap.this.size();
324 }
325
326 @Override
327 public Object[] toArray() {
328 List<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(size());
329
330 Iterator<Map.Entry<K, V>> iterator = iterator();
331
332 while (iterator.hasNext()) {
333 list.add(iterator.next());
334 }
335
336 return list.toArray();
337 }
338
339 @Override
340 public <T> T[] toArray(T[] array) {
341 List<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(size());
342
343 Iterator<Map.Entry<K, V>> iterator = iterator();
344
345 while (iterator.hasNext()) {
346 list.add(iterator.next());
347 }
348
349 return list.toArray(array);
350 }
351
352 }
353
354 private class UnwrapValueIterator implements Iterator<V> {
355
356 public UnwrapValueIterator() {
357 _iterator = _map.values().iterator();
358 }
359
360 @Override
361 public boolean hasNext() {
362 return _iterator.hasNext();
363 }
364
365 @Override
366 public V next() {
367 Reference<V> valueReference = _iterator.next();
368
369 if (valueReference != null) {
370 return valueReference.get();
371 }
372
373 return null;
374 }
375
376 @Override
377 public void remove() {
378 _iterator.remove();
379 }
380
381 private Iterator<Reference<V>> _iterator;
382
383 }
384
385 private class UnwrapValues extends AbstractCollection<V> {
386
387 @Override
388 public void clear() {
389 WeakValueConcurrentHashMap.this.clear();
390 }
391
392 @Override
393 public boolean contains(Object obj) {
394 return WeakValueConcurrentHashMap.this.containsValue(obj);
395 }
396
397 @Override
398 public Iterator<V> iterator() {
399 return new UnwrapValueIterator();
400 }
401
402 @Override
403 public int size() {
404 return WeakValueConcurrentHashMap.this.size();
405 }
406
407 @Override
408 public Object[] toArray() {
409 List<V> list = new ArrayList<V>();
410
411 Iterator<V> iterator = iterator();
412
413 while (iterator.hasNext()) {
414 list.add(iterator.next());
415 }
416
417 return list.toArray();
418 }
419
420 @Override
421 public <T> T[] toArray(T[] a) {
422 List<V> list = new ArrayList<V>();
423
424 Iterator<V> iterator = iterator();
425
426 while (iterator.hasNext()) {
427 list.add(iterator.next());
428 }
429
430 return list.toArray(a);
431 }
432
433 }
434
435 }