1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * The contents of this file are subject to the terms of the Liferay Enterprise
5    * Subscription License ("License"). You may not use this file except in
6    * compliance with the License. You can obtain a copy of the License by
7    * contacting Liferay, Inc. See the License for the specific language governing
8    * permissions and limitations under the License, including but not limited to
9    * distribution rights of the Software.
10   *
11   *
12   *
13   */
14  
15  package com.liferay.portal.kernel.util;
16  
17  import com.liferay.portal.kernel.memory.EqualityWeakReference;
18  import com.liferay.portal.kernel.memory.FinalizeAction;
19  import com.liferay.portal.kernel.memory.FinalizeManager;
20  
21  import java.io.Serializable;
22  
23  import java.lang.ref.Reference;
24  
25  import java.util.AbstractCollection;
26  import java.util.AbstractSet;
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Iterator;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  import java.util.concurrent.ConcurrentHashMap;
34  import java.util.concurrent.ConcurrentMap;
35  
36  /**
37   * <a href="WeakValueConcurrentHashMap.java.html"><b><i>View Source</i></b></a>
38   *
39   * @author Shuyang Zhou
40   */
41  public class WeakValueConcurrentHashMap<K, V>
42      implements ConcurrentMap<K, V>, Serializable {
43  
44      public WeakValueConcurrentHashMap() {
45          _map = new ConcurrentHashMap<K, Reference<V>>();
46      }
47  
48      public WeakValueConcurrentHashMap(int initialCapacity) {
49          _map = new ConcurrentHashMap<K, Reference<V>>(initialCapacity);
50      }
51  
52      public WeakValueConcurrentHashMap(
53          int initialCapacity, float loadFactor, int concurrencyLevel) {
54          _map = new ConcurrentHashMap<K, Reference<V>>(
55              initialCapacity, loadFactor, concurrencyLevel);
56      }
57  
58      public WeakValueConcurrentHashMap(Map<? extends K, ? extends V> map) {
59          _map = new ConcurrentHashMap<K, Reference<V>>();
60  
61          putAll(map);
62      }
63  
64      public void clear() {
65          _map.clear();
66      }
67  
68      public boolean containsKey(Object key) {
69          return _map.containsKey(key);
70      }
71  
72      public boolean containsValue(Object value) {
73          return _map.containsValue(new EqualityWeakReference<V>((V)value));
74      }
75  
76      public Set<Entry<K, V>> entrySet() {
77          if (_entrySet == null) {
78              _entrySet = new UnwrapEntrySet();
79          }
80  
81          return _entrySet;
82      }
83  
84      public V get(Object key) {
85          Reference<V> valueReference = _map.get(key);
86  
87          if (valueReference != null) {
88              return valueReference.get();
89          }
90  
91          return null;
92      }
93  
94      public boolean isEmpty() {
95          return _map.isEmpty();
96      }
97  
98      public Set<K> keySet() {
99          return _map.keySet();
100     }
101 
102     public V put(K key, V value) {
103         Reference<V> valueReference = wrapValue(key, value);
104 
105         valueReference = _map.putIfAbsent(key, valueReference);
106 
107         if (valueReference != null) {
108             return valueReference.get();
109         }
110 
111         return null;
112     }
113 
114     public final void putAll(Map<? extends K, ? extends V> map) {
115         for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
116             K key = entry.getKey();
117             V value = entry.getValue();
118 
119             Reference<V> valueReference = wrapValue(key, value);
120 
121             _map.put(key, valueReference);
122         }
123     }
124 
125     public V putIfAbsent(K key, V value) {
126         Reference<V> valueReference = wrapValue(key, value);
127 
128         valueReference = _map.putIfAbsent(key, valueReference);
129 
130         if (valueReference != null) {
131             return valueReference.get();
132         }
133 
134         return null;
135     }
136 
137     public V remove(Object key) {
138         Reference<V> valueReference = _map.remove(key);
139 
140         if (valueReference != null) {
141             valueReference.get();
142         }
143 
144         return null;
145     }
146 
147     public boolean remove(Object key, Object value) {
148         Reference<V> valueReference = wrapValue(key, value);
149 
150         return _map.remove(key, valueReference);
151     }
152 
153     public V replace(K key, V value) {
154         Reference<V> valueReference = wrapValue(key, value);
155 
156         valueReference = _map.replace(key, valueReference);
157 
158         if (valueReference != null) {
159             return valueReference.get();
160         }
161 
162         return null;
163     }
164 
165     public boolean replace(K key, V oldValue, V newValue) {
166         Reference<V> oldValueReference = wrapValue(key, oldValue);
167         Reference<V> newValueReference = wrapValue(key, newValue);
168 
169         return _map.replace(key, oldValueReference, newValueReference);
170     }
171 
172     public int size() {
173         return _map.size();
174     }
175 
176     public Collection<V> values() {
177         if (_values == null) {
178             _values = new UnwrapValues();
179         }
180         return _values;
181     }
182 
183     protected Reference<V> wrapValue(Object key, Object value) {
184         return FinalizeManager.register(
185             (V)value, new RemoveEntryFinalizeAction((K) key));
186     }
187 
188     private transient Set<Map.Entry<K, V>> _entrySet;
189     private final ConcurrentMap<K, Reference<V>> _map;
190     private transient Collection<V> _values;
191 
192     private class RemoveEntryFinalizeAction implements FinalizeAction {
193 
194         public RemoveEntryFinalizeAction(K key) {
195             _key = key;
196         }
197 
198         public void doFinalize() {
199             remove(_key);
200         }
201 
202         private final K _key;
203 
204     }
205 
206     private class UnwrapEntry implements Map.Entry<K, V> {
207 
208         public UnwrapEntry(Entry<K, Reference<V>> entry) {
209             _entry = entry;
210         }
211 
212         public K getKey() {
213             return _entry.getKey();
214         }
215 
216         public V getValue() {
217             Reference<V> valueReference = _entry.getValue();
218 
219             if (valueReference != null) {
220                 return valueReference.get();
221             }
222 
223             return null;
224         }
225 
226         public V setValue(V value) {
227             return WeakValueConcurrentHashMap.this.put(_entry.getKey(), value);
228         }
229 
230         private Map.Entry<K, Reference<V>> _entry;
231 
232     }
233 
234     private class UnwrapEntryIterator implements Iterator<Map.Entry<K, V>> {
235 
236         public UnwrapEntryIterator() {
237             _iterator = _map.entrySet().iterator();
238         }
239 
240         public boolean hasNext() {
241             return _iterator.hasNext();
242         }
243 
244         public Entry<K, V> next() {
245             return new UnwrapEntry(_iterator.next());
246         }
247 
248         public void remove() {
249             _iterator.remove();
250         }
251 
252         private Iterator<Map.Entry<K, Reference<V>>> _iterator;
253 
254     }
255 
256     private class UnwrapEntrySet extends AbstractSet<Map.Entry<K, V>> {
257 
258         public void clear() {
259             WeakValueConcurrentHashMap.this.clear();
260         }
261 
262         public boolean contains(Object obj) {
263             if (!(obj instanceof Map.Entry<?, ?>)) {
264                 return false;
265             }
266 
267             Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
268 
269             V value = WeakValueConcurrentHashMap.this.get(entry.getKey());
270 
271             if ((value != null) && value.equals(entry.getValue())) {
272                 return true;
273             }
274             else {
275                 return false;
276             }
277         }
278 
279         public Iterator<Map.Entry<K, V>> iterator() {
280             return new UnwrapEntryIterator();
281         }
282 
283         public boolean remove(Object obj) {
284             if (!(obj instanceof Map.Entry<?, ?>)) {
285                 return false;
286             }
287 
288             Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
289 
290             return WeakValueConcurrentHashMap.this.remove(
291                 entry.getKey(), entry.getValue());
292         }
293 
294         public int size() {
295             return WeakValueConcurrentHashMap.this.size();
296         }
297 
298         public Object[] toArray() {
299             List<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(size());
300 
301             Iterator<Map.Entry<K, V>> iterator = iterator();
302 
303             while (iterator.hasNext()) {
304                 list.add(iterator.next());
305             }
306 
307             return list.toArray();
308         }
309 
310         public <T> T[] toArray(T[] array) {
311             List<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(size());
312 
313             Iterator<Map.Entry<K, V>> iterator = iterator();
314 
315             while (iterator.hasNext()) {
316                 list.add(iterator.next());
317             }
318 
319             return list.toArray(array);
320         }
321 
322     }
323 
324     private class UnwrapValueIterator implements Iterator<V> {
325 
326         public UnwrapValueIterator() {
327             _iterator = _map.values().iterator();
328         }
329 
330         public boolean hasNext() {
331             return _iterator.hasNext();
332         }
333 
334         public V next() {
335             Reference<V> valueReference = _iterator.next();
336 
337             if (valueReference != null) {
338                 return valueReference.get();
339             }
340 
341             return null;
342         }
343 
344         public void remove() {
345             _iterator.remove();
346         }
347 
348         private Iterator<Reference<V>> _iterator;
349 
350     }
351 
352     private class UnwrapValues extends AbstractCollection<V> {
353 
354         public void clear() {
355             WeakValueConcurrentHashMap.this.clear();
356         }
357 
358         public boolean contains(Object obj) {
359             return WeakValueConcurrentHashMap.this.containsValue(obj);
360         }
361 
362         public Iterator<V> iterator() {
363             return new UnwrapValueIterator();
364         }
365 
366         public int size() {
367             return WeakValueConcurrentHashMap.this.size();
368         }
369 
370         public Object[] toArray() {
371             List<V> list = new ArrayList<V>();
372 
373             Iterator<V> iterator = iterator();
374 
375             while (iterator.hasNext()) {
376                 list.add(iterator.next());
377             }
378 
379             return list.toArray();
380         }
381 
382         public <T> T[] toArray(T[] a) {
383             List<V> list = new ArrayList<V>();
384 
385             Iterator<V> iterator = iterator();
386 
387             while (iterator.hasNext()) {
388                 list.add(iterator.next());
389             }
390 
391             return list.toArray(a);
392         }
393 
394     }
395 
396 }