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