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 _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 }