001    /**
002     * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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    /**
037     * @author Shuyang Zhou
038     */
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                    _map = new ConcurrentHashMap<K, Reference<V>>(
053                            initialCapacity, loadFactor, concurrencyLevel);
054            }
055    
056            public WeakValueConcurrentHashMap(Map<? extends K, ? extends V> map) {
057                    _map = new ConcurrentHashMap<K, Reference<V>>();
058    
059                    putAll(map);
060            }
061    
062            public void clear() {
063                    _map.clear();
064            }
065    
066            public boolean containsKey(Object key) {
067                    return _map.containsKey(key);
068            }
069    
070            public boolean containsValue(Object value) {
071                    return _map.containsValue(new EqualityWeakReference<V>((V)value));
072            }
073    
074            public Set<Entry<K, V>> entrySet() {
075                    if (_entrySet == null) {
076                            _entrySet = new UnwrapEntrySet();
077                    }
078    
079                    return _entrySet;
080            }
081    
082            public V get(Object key) {
083                    Reference<V> valueReference = _map.get(key);
084    
085                    if (valueReference != null) {
086                            return valueReference.get();
087                    }
088    
089                    return null;
090            }
091    
092            public boolean isEmpty() {
093                    return _map.isEmpty();
094            }
095    
096            public Set<K> keySet() {
097                    return _map.keySet();
098            }
099    
100            public V put(K key, V value) {
101                    Reference<V> valueReference = wrapValue(key, value);
102    
103                    valueReference = _map.putIfAbsent(key, valueReference);
104    
105                    if (valueReference != null) {
106                            return valueReference.get();
107                    }
108    
109                    return null;
110            }
111    
112            public final void putAll(Map<? extends K, ? extends V> map) {
113                    for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
114                            K key = entry.getKey();
115                            V value = entry.getValue();
116    
117                            Reference<V> valueReference = wrapValue(key, value);
118    
119                            _map.put(key, valueReference);
120                    }
121            }
122    
123            public V putIfAbsent(K key, V value) {
124                    Reference<V> valueReference = wrapValue(key, value);
125    
126                    valueReference = _map.putIfAbsent(key, valueReference);
127    
128                    if (valueReference != null) {
129                            return valueReference.get();
130                    }
131    
132                    return null;
133            }
134    
135            public V remove(Object key) {
136                    Reference<V> valueReference = _map.remove(key);
137    
138                    if (valueReference != null) {
139                            valueReference.get();
140                    }
141    
142                    return null;
143            }
144    
145            public boolean remove(Object key, Object value) {
146                    Reference<V> valueReference = wrapValue(key, value);
147    
148                    return _map.remove(key, valueReference);
149            }
150    
151            public V replace(K key, V value) {
152                    Reference<V> valueReference = wrapValue(key, value);
153    
154                    valueReference = _map.replace(key, valueReference);
155    
156                    if (valueReference != null) {
157                            return valueReference.get();
158                    }
159    
160                    return null;
161            }
162    
163            public boolean replace(K key, V oldValue, V newValue) {
164                    Reference<V> oldValueReference = wrapValue(key, oldValue);
165                    Reference<V> newValueReference = wrapValue(key, newValue);
166    
167                    return _map.replace(key, oldValueReference, newValueReference);
168            }
169    
170            public int size() {
171                    return _map.size();
172            }
173    
174            public Collection<V> values() {
175                    if (_values == null) {
176                            _values = new UnwrapValues();
177                    }
178                    return _values;
179            }
180    
181            protected Reference<V> wrapValue(Object key, Object value) {
182                    return FinalizeManager.register(
183                            (V)value, new RemoveEntryFinalizeAction((K) key));
184            }
185    
186            private transient Set<Map.Entry<K, V>> _entrySet;
187            private final ConcurrentMap<K, Reference<V>> _map;
188            private transient Collection<V> _values;
189    
190            private class RemoveEntryFinalizeAction implements FinalizeAction {
191    
192                    public RemoveEntryFinalizeAction(K key) {
193                            _key = key;
194                    }
195    
196                    public void doFinalize() {
197                            remove(_key);
198                    }
199    
200                    private final K _key;
201    
202            }
203    
204            private class UnwrapEntry implements Map.Entry<K, V> {
205    
206                    public UnwrapEntry(Entry<K, Reference<V>> entry) {
207                            _entry = entry;
208                    }
209    
210                    public K getKey() {
211                            return _entry.getKey();
212                    }
213    
214                    public V getValue() {
215                            Reference<V> valueReference = _entry.getValue();
216    
217                            if (valueReference != null) {
218                                    return valueReference.get();
219                            }
220    
221                            return null;
222                    }
223    
224                    public V setValue(V value) {
225                            return WeakValueConcurrentHashMap.this.put(_entry.getKey(), value);
226                    }
227    
228                    private Map.Entry<K, Reference<V>> _entry;
229    
230            }
231    
232            private class UnwrapEntryIterator implements Iterator<Map.Entry<K, V>> {
233    
234                    public UnwrapEntryIterator() {
235                            _iterator = _map.entrySet().iterator();
236                    }
237    
238                    public boolean hasNext() {
239                            return _iterator.hasNext();
240                    }
241    
242                    public Entry<K, V> next() {
243                            return new UnwrapEntry(_iterator.next());
244                    }
245    
246                    public void remove() {
247                            _iterator.remove();
248                    }
249    
250                    private Iterator<Map.Entry<K, Reference<V>>> _iterator;
251    
252            }
253    
254            private class UnwrapEntrySet extends AbstractSet<Map.Entry<K, V>> {
255    
256                    public void clear() {
257                            WeakValueConcurrentHashMap.this.clear();
258                    }
259    
260                    public boolean contains(Object obj) {
261                            if (!(obj instanceof Map.Entry<?, ?>)) {
262                                    return false;
263                            }
264    
265                            Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
266    
267                            V value = WeakValueConcurrentHashMap.this.get(entry.getKey());
268    
269                            if ((value != null) && value.equals(entry.getValue())) {
270                                    return true;
271                            }
272                            else {
273                                    return false;
274                            }
275                    }
276    
277                    public Iterator<Map.Entry<K, V>> iterator() {
278                            return new UnwrapEntryIterator();
279                    }
280    
281                    public boolean remove(Object obj) {
282                            if (!(obj instanceof Map.Entry<?, ?>)) {
283                                    return false;
284                            }
285    
286                            Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
287    
288                            return WeakValueConcurrentHashMap.this.remove(
289                                    entry.getKey(), entry.getValue());
290                    }
291    
292                    public int size() {
293                            return WeakValueConcurrentHashMap.this.size();
294                    }
295    
296                    public Object[] toArray() {
297                            List<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(size());
298    
299                            Iterator<Map.Entry<K, V>> iterator = iterator();
300    
301                            while (iterator.hasNext()) {
302                                    list.add(iterator.next());
303                            }
304    
305                            return list.toArray();
306                    }
307    
308                    public <T> T[] toArray(T[] array) {
309                            List<Map.Entry<K, V>> list = new ArrayList<Map.Entry<K, V>>(size());
310    
311                            Iterator<Map.Entry<K, V>> iterator = iterator();
312    
313                            while (iterator.hasNext()) {
314                                    list.add(iterator.next());
315                            }
316    
317                            return list.toArray(array);
318                    }
319    
320            }
321    
322            private class UnwrapValueIterator implements Iterator<V> {
323    
324                    public UnwrapValueIterator() {
325                            _iterator = _map.values().iterator();
326                    }
327    
328                    public boolean hasNext() {
329                            return _iterator.hasNext();
330                    }
331    
332                    public V next() {
333                            Reference<V> valueReference = _iterator.next();
334    
335                            if (valueReference != null) {
336                                    return valueReference.get();
337                            }
338    
339                            return null;
340                    }
341    
342                    public void remove() {
343                            _iterator.remove();
344                    }
345    
346                    private Iterator<Reference<V>> _iterator;
347    
348            }
349    
350            private class UnwrapValues extends AbstractCollection<V> {
351    
352                    public void clear() {
353                            WeakValueConcurrentHashMap.this.clear();
354                    }
355    
356                    public boolean contains(Object obj) {
357                            return WeakValueConcurrentHashMap.this.containsValue(obj);
358                    }
359    
360                    public Iterator<V> iterator() {
361                            return new UnwrapValueIterator();
362                    }
363    
364                    public int size() {
365                            return WeakValueConcurrentHashMap.this.size();
366                    }
367    
368                    public Object[] toArray() {
369                            List<V> list = new ArrayList<V>();
370    
371                            Iterator<V> iterator = iterator();
372    
373                            while (iterator.hasNext()) {
374                                    list.add(iterator.next());
375                            }
376    
377                            return list.toArray();
378                    }
379    
380                    public <T> T[] toArray(T[] a) {
381                            List<V> list = new ArrayList<V>();
382    
383                            Iterator<V> iterator = iterator();
384    
385                            while (iterator.hasNext()) {
386                                    list.add(iterator.next());
387                            }
388    
389                            return list.toArray(a);
390                    }
391    
392            }
393    
394    }