001    /**
002     * Copyright (c) 2000-present 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.concurrent;
016    
017    import com.liferay.portal.kernel.util.Validator;
018    
019    import java.io.Serializable;
020    
021    import java.util.AbstractCollection;
022    import java.util.AbstractMap;
023    import java.util.AbstractSet;
024    import java.util.Collection;
025    import java.util.Iterator;
026    import java.util.Map;
027    import java.util.Set;
028    import java.util.concurrent.ConcurrentMap;
029    
030    /**
031     * @author Shuyang Zhou
032     */
033    public abstract class ConcurrentMapperHashMap<K, IK, V, IV>
034            extends AbstractMap<K, V>
035            implements ConcurrentMap<K, V>, Serializable {
036    
037            @Override
038            public void clear() {
039                    innerConcurrentMap.clear();
040            }
041    
042            @Override
043            public boolean containsKey(Object key) {
044                    if (key == null) {
045                            throw new NullPointerException("Key is null");
046                    }
047    
048                    return innerConcurrentMap.containsKey(mapKeyForQuery((K)key));
049            }
050    
051            @Override
052            public boolean containsValue(Object value) {
053                    if (value == null) {
054                            throw new NullPointerException("Value is null");
055                    }
056    
057                    return innerConcurrentMap.containsValue(mapValueForQuery((V)value));
058            }
059    
060            @Override
061            public Set<Entry<K, V>> entrySet() {
062                    if (entrySet == null) {
063                            entrySet = new UnwrapEntrySet();
064                    }
065    
066                    return entrySet;
067            }
068    
069            @Override
070            public V get(Object key) {
071                    if (key == null) {
072                            throw new NullPointerException("Key is null");
073                    }
074    
075                    IV innerValue = innerConcurrentMap.get(mapKeyForQuery((K)key));
076    
077                    if (innerValue == null) {
078                            return null;
079                    }
080    
081                    return unmapValueForQuery(innerValue);
082            }
083    
084            @Override
085            public boolean isEmpty() {
086                    return innerConcurrentMap.isEmpty();
087            }
088    
089            @Override
090            public Set<K> keySet() {
091                    if (keySet == null) {
092                            keySet = new UnwrapKeySet();
093                    }
094    
095                    return keySet;
096            }
097    
098            @Override
099            public V put(K key, V value) {
100                    if (key == null) {
101                            throw new NullPointerException("Key is null");
102                    }
103    
104                    if (value == null) {
105                            throw new NullPointerException("Value is null");
106                    }
107    
108                    IK innerKey = mapKey(key);
109    
110                    IV oldInnerValue = innerConcurrentMap.put(
111                            innerKey, mapValue(key, value));
112    
113                    if (oldInnerValue == null) {
114                            return null;
115                    }
116    
117                    unmapKey(innerKey);
118    
119                    return unmapValue(oldInnerValue);
120            }
121    
122            @Override
123            public void putAll(Map<? extends K, ? extends V> map) {
124                    for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
125                            put(entry.getKey(), entry.getValue());
126                    }
127            }
128    
129            @Override
130            public V putIfAbsent(K key, V value) {
131                    if (key == null) {
132                            throw new NullPointerException("Key is null");
133                    }
134    
135                    if (value == null) {
136                            throw new NullPointerException("Value is null");
137                    }
138    
139                    IK innerKey = mapKey(key);
140                    IV innerValue = mapValue(key, value);
141    
142                    IV previousInnerValue = innerConcurrentMap.putIfAbsent(
143                            innerKey, innerValue);
144    
145                    if (previousInnerValue == null) {
146                            return null;
147                    }
148    
149                    unmapKey(innerKey);
150                    unmapValue(innerValue);
151    
152                    return unmapValueForQuery(previousInnerValue);
153            }
154    
155            @Override
156            public V remove(Object key) {
157                    if (key == null) {
158                            throw new NullPointerException("Key is null");
159                    }
160    
161                    IK innerKey = mapKeyForQuery((K)key);
162    
163                    IV innerValue = innerConcurrentMap.remove(innerKey);
164    
165                    if (innerValue == null) {
166                            return null;
167                    }
168    
169                    return unmapValue(innerValue);
170            }
171    
172            @Override
173            public boolean remove(Object key, Object value) {
174                    if (key == null) {
175                            throw new NullPointerException("Key is null");
176                    }
177    
178                    if (value == null) {
179                            throw new NullPointerException("Value is null");
180                    }
181    
182                    IK innerKey = mapKeyForQuery((K)key);
183                    IV innerValue = mapValueForQuery((V)value);
184    
185                    IV previousInnerValue = innerConcurrentMap.get(innerKey);
186    
187                    if (!innerValue.equals(previousInnerValue) ||
188                            !innerConcurrentMap.remove(innerKey, previousInnerValue)) {
189    
190                            return false;
191                    }
192    
193                    unmapValue(previousInnerValue);
194    
195                    return true;
196            }
197    
198            @Override
199            public V replace(K key, V value) {
200                    if (key == null) {
201                            throw new NullPointerException("Key is null");
202                    }
203    
204                    if (value == null) {
205                            throw new NullPointerException("Value is null");
206                    }
207    
208                    IV newInnerValue = mapValue(key, value);
209    
210                    IV oldInnerValue = innerConcurrentMap.replace(
211                            mapKeyForQuery(key), newInnerValue);
212    
213                    if (oldInnerValue == null) {
214                            unmapValue(newInnerValue);
215    
216                            return null;
217                    }
218    
219                    return unmapValue(oldInnerValue);
220            }
221    
222            @Override
223            public boolean replace(K key, V oldValue, V newValue) {
224                    if (key == null) {
225                            throw new NullPointerException("Key is null");
226                    }
227    
228                    if (oldValue == null) {
229                            throw new NullPointerException("Old value is null");
230                    }
231    
232                    if (newValue == null) {
233                            throw new NullPointerException("New value is null");
234                    }
235    
236                    IK innerKey = mapKeyForQuery(key);
237    
238                    IV newInnerValue = mapValue(key, newValue);
239    
240                    IV oldInnerValue = innerConcurrentMap.get(innerKey);
241    
242                    if ((oldInnerValue == null) ||
243                            !oldValue.equals(unmapValueForQuery(oldInnerValue))) {
244    
245                            unmapValue(newInnerValue);
246    
247                            return false;
248                    }
249    
250                    if (innerConcurrentMap.replace(
251                                    innerKey, oldInnerValue, newInnerValue)) {
252    
253                            unmapValue(oldInnerValue);
254    
255                            return true;
256                    }
257    
258                    unmapValue(newInnerValue);
259    
260                    return false;
261            }
262    
263            @Override
264            public int size() {
265                    return innerConcurrentMap.size();
266            }
267    
268            @Override
269            public Collection<V> values() {
270                    if (values == null) {
271                            values = new UnwrapValues();
272                    }
273    
274                    return values;
275            }
276    
277            protected ConcurrentMapperHashMap(
278                    ConcurrentMap<IK, IV> innerConcurrentMap) {
279    
280                    this.innerConcurrentMap = innerConcurrentMap;
281            }
282    
283            protected abstract IK mapKey(K key);
284    
285            protected abstract IK mapKeyForQuery(K key);
286    
287            protected abstract IV mapValue(K key, V value);
288    
289            protected abstract IV mapValueForQuery(V value);
290    
291            protected abstract K unmapKey(IK key);
292    
293            protected abstract K unmapKeyForQuery(IK key);
294    
295            protected abstract V unmapValue(IV value);
296    
297            protected abstract V unmapValueForQuery(IV value);
298    
299            protected transient Set<Map.Entry<K, V>> entrySet;
300            protected final ConcurrentMap<IK, IV> innerConcurrentMap;
301            protected transient Set<K> keySet;
302            protected transient Collection<V> values;
303    
304            private static final long serialVersionUID = 1L;
305    
306            private class UnwrapEntry implements Map.Entry<K, V> {
307    
308                    public UnwrapEntry(Entry<IK, IV> innerEntry) {
309                            _innerEntry = innerEntry;
310                    }
311    
312                    @Override
313                    public boolean equals(Object obj) {
314                            if (this == obj) {
315                                    return true;
316                            }
317    
318                            if (!(obj instanceof Map.Entry)) {
319                                    return false;
320                            }
321    
322                            Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
323    
324                            if (Validator.equals(getKey(), entry.getKey()) &&
325                                    Validator.equals(getValue(), entry.getValue())) {
326    
327                                    return true;
328                            }
329    
330                            return false;
331                    }
332    
333                    @Override
334                    public K getKey() {
335                            return unmapKeyForQuery(_innerEntry.getKey());
336                    }
337    
338                    @Override
339                    public V getValue() {
340                            return unmapValueForQuery(_innerEntry.getValue());
341                    }
342    
343                    @Override
344                    public int hashCode() {
345                            return _innerEntry.hashCode();
346                    }
347    
348                    @Override
349                    public V setValue(V value) {
350                            K key = getKey();
351    
352                            V v = unmapValueForQuery(
353                                    _innerEntry.setValue(mapValueForQuery(value)));
354    
355                            ConcurrentMapperHashMap.this.put(key, value);
356    
357                            return v;
358                    }
359    
360                    private final Entry<IK, IV> _innerEntry;
361    
362            }
363    
364            private class UnwrapEntryIterator implements Iterator<Map.Entry<K, V>> {
365    
366                    public UnwrapEntryIterator() {
367                            Set<Entry<IK, IV>> entrySet = innerConcurrentMap.entrySet();
368    
369                            _iterator = entrySet.iterator();
370                    }
371    
372                    @Override
373                    public boolean hasNext() {
374                            return _iterator.hasNext();
375                    }
376    
377                    @Override
378                    public Entry<K, V> next() {
379                            return new UnwrapEntry(_iterator.next());
380                    }
381    
382                    @Override
383                    public void remove() {
384                            _iterator.remove();
385                    }
386    
387                    private final Iterator<Map.Entry<IK, IV>> _iterator;
388    
389            }
390    
391            private class UnwrapEntrySet extends AbstractSet<Map.Entry<K, V>> {
392    
393                    @Override
394                    public void clear() {
395                            ConcurrentMapperHashMap.this.clear();
396                    }
397    
398                    @Override
399                    public boolean contains(Object obj) {
400                            if (!(obj instanceof Map.Entry<?, ?>)) {
401                                    return false;
402                            }
403    
404                            Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
405    
406                            V value = ConcurrentMapperHashMap.this.get(entry.getKey());
407    
408                            if ((value != null) && value.equals(entry.getValue())) {
409                                    return true;
410                            }
411                            else {
412                                    return false;
413                            }
414                    }
415    
416                    @Override
417                    public boolean isEmpty() {
418                            return ConcurrentMapperHashMap.this.isEmpty();
419                    }
420    
421                    @Override
422                    public Iterator<Map.Entry<K, V>> iterator() {
423                            return new UnwrapEntryIterator();
424                    }
425    
426                    @Override
427                    public boolean remove(Object obj) {
428                            if (!(obj instanceof Map.Entry<?, ?>)) {
429                                    return false;
430                            }
431    
432                            Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
433    
434                            return ConcurrentMapperHashMap.this.remove(
435                                    entry.getKey(), entry.getValue());
436                    }
437    
438                    @Override
439                    public int size() {
440                            return ConcurrentMapperHashMap.this.size();
441                    }
442    
443            }
444    
445            private class UnwrapKeyIterator implements Iterator<K> {
446    
447                    public UnwrapKeyIterator() {
448                            Set<IK> keySet = innerConcurrentMap.keySet();
449    
450                            _iterator = keySet.iterator();
451                    }
452    
453                    @Override
454                    public boolean hasNext() {
455                            return _iterator.hasNext();
456                    }
457    
458                    @Override
459                    public K next() {
460                            return unmapKeyForQuery(_iterator.next());
461                    }
462    
463                    @Override
464                    public void remove() {
465                            _iterator.remove();
466                    }
467    
468                    private final Iterator<IK> _iterator;
469    
470            }
471    
472            private class UnwrapKeySet extends AbstractSet<K> {
473    
474                    @Override
475                    public void clear() {
476                            ConcurrentMapperHashMap.this.clear();
477                    }
478    
479                    @Override
480                    public boolean contains(Object o) {
481                            return ConcurrentMapperHashMap.this.containsKey(o);
482                    }
483    
484                    @Override
485                    public boolean isEmpty() {
486                            return ConcurrentMapperHashMap.this.isEmpty();
487                    }
488    
489                    @Override
490                    public Iterator<K> iterator() {
491                            return new UnwrapKeyIterator();
492                    }
493    
494                    @Override
495                    public boolean remove(Object o) {
496                            if (ConcurrentMapperHashMap.this.remove(o) != null) {
497                                    return true;
498                            }
499    
500                            return false;
501                    }
502    
503                    @Override
504                    public int size() {
505                            return ConcurrentMapperHashMap.this.size();
506                    }
507    
508            }
509    
510            private class UnwrapValueIterator implements Iterator<V> {
511    
512                    public UnwrapValueIterator() {
513                            Collection<IV> values = innerConcurrentMap.values();
514    
515                            _iterator = values.iterator();
516                    }
517    
518                    @Override
519                    public boolean hasNext() {
520                            return _iterator.hasNext();
521                    }
522    
523                    @Override
524                    public V next() {
525                            return unmapValueForQuery(_iterator.next());
526                    }
527    
528                    @Override
529                    public void remove() {
530                            _iterator.remove();
531                    }
532    
533                    private final Iterator<IV> _iterator;
534    
535            }
536    
537            private class UnwrapValues extends AbstractCollection<V> {
538    
539                    @Override
540                    public void clear() {
541                            ConcurrentMapperHashMap.this.clear();
542                    }
543    
544                    @Override
545                    public boolean contains(Object obj) {
546                            return ConcurrentMapperHashMap.this.containsValue(obj);
547                    }
548    
549                    @Override
550                    public boolean isEmpty() {
551                            return ConcurrentMapperHashMap.this.isEmpty();
552                    }
553    
554                    @Override
555                    public Iterator<V> iterator() {
556                            return new UnwrapValueIterator();
557                    }
558    
559                    @Override
560                    public int size() {
561                            return ConcurrentMapperHashMap.this.size();
562                    }
563    
564            }
565    
566    }