/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.concurrent;
import java.io.Serializable;
import java.util.AbstractCollection;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentMap;
/**
* @author Shuyang Zhou
*/
public abstract class ConcurrentMapperHashMap<K, IK, V, IV>
extends AbstractMap<K, V> implements ConcurrentMap<K, V>, Serializable {
@Override
public void clear() {
innerConcurrentMap.clear();
}
@Override
public boolean containsKey(Object key) {
if (key == null) {
throw new NullPointerException("Key is null");
}
return innerConcurrentMap.containsKey(mapKeyForQuery((K)key));
}
@Override
public boolean containsValue(Object value) {
if (value == null) {
throw new NullPointerException("Value is null");
}
return innerConcurrentMap.containsValue(mapValueForQuery((V)value));
}
@Override
public Set<Entry<K, V>> entrySet() {
if (entrySet == null) {
entrySet = new UnwrapEntrySet();
}
return entrySet;
}
@Override
public V get(Object key) {
if (key == null) {
throw new NullPointerException("Key is null");
}
IV innerValue = innerConcurrentMap.get(mapKeyForQuery((K)key));
if (innerValue == null) {
return null;
}
return unmapValueForQuery(innerValue);
}
@Override
public boolean isEmpty() {
return innerConcurrentMap.isEmpty();
}
@Override
public Set<K> keySet() {
if (keySet == null) {
keySet = new UnwrapKeySet();
}
return keySet;
}
@Override
public V put(K key, V value) {
if (key == null) {
throw new NullPointerException("Key is null");
}
if (value == null) {
throw new NullPointerException("Value is null");
}
IK innerKey = mapKey(key);
IV oldInnerValue = innerConcurrentMap.put(
innerKey, mapValue(key, value));
if (oldInnerValue == null) {
return null;
}
unmapKey(innerKey);
return unmapValue(oldInnerValue);
}
@Override
public void putAll(Map<? extends K, ? extends V> map) {
for (Map.Entry<? extends K, ? extends V> entry : map.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
@Override
public V putIfAbsent(K key, V value) {
if (key == null) {
throw new NullPointerException("Key is null");
}
if (value == null) {
throw new NullPointerException("Value is null");
}
IK innerKey = mapKey(key);
IV innerValue = mapValue(key, value);
IV previousInnerValue = innerConcurrentMap.putIfAbsent(
innerKey, innerValue);
if (previousInnerValue == null) {
return null;
}
unmapKey(innerKey);
unmapValue(innerValue);
return unmapValueForQuery(previousInnerValue);
}
@Override
public V remove(Object key) {
if (key == null) {
throw new NullPointerException("Key is null");
}
IK innerKey = mapKeyForQuery((K)key);
IV innerValue = innerConcurrentMap.remove(innerKey);
if (innerValue == null) {
return null;
}
return unmapValue(innerValue);
}
@Override
public boolean remove(Object key, Object value) {
if (key == null) {
throw new NullPointerException("Key is null");
}
if (value == null) {
throw new NullPointerException("Value is null");
}
IK innerKey = mapKeyForQuery((K)key);
IV innerValue = mapValueForQuery((V)value);
IV previousInnerValue = innerConcurrentMap.get(innerKey);
if (!innerValue.equals(previousInnerValue) ||
!innerConcurrentMap.remove(innerKey, previousInnerValue)) {
return false;
}
unmapValue(previousInnerValue);
return true;
}
@Override
public V replace(K key, V value) {
if (key == null) {
throw new NullPointerException("Key is null");
}
if (value == null) {
throw new NullPointerException("Value is null");
}
IV newInnerValue = mapValue(key, value);
IV oldInnerValue = innerConcurrentMap.replace(
mapKeyForQuery(key), newInnerValue);
if (oldInnerValue == null) {
unmapValue(newInnerValue);
return null;
}
return unmapValue(oldInnerValue);
}
@Override
public boolean replace(K key, V oldValue, V newValue) {
if (key == null) {
throw new NullPointerException("Key is null");
}
if (oldValue == null) {
throw new NullPointerException("Old value is null");
}
if (newValue == null) {
throw new NullPointerException("New value is null");
}
IK innerKey = mapKeyForQuery(key);
IV newInnerValue = mapValue(key, newValue);
IV oldInnerValue = innerConcurrentMap.get(innerKey);
if ((oldInnerValue == null) ||
!oldValue.equals(unmapValueForQuery(oldInnerValue))) {
unmapValue(newInnerValue);
return false;
}
if (innerConcurrentMap.replace(
innerKey, oldInnerValue, newInnerValue)) {
unmapValue(oldInnerValue);
return true;
}
unmapValue(newInnerValue);
return false;
}
@Override
public int size() {
return innerConcurrentMap.size();
}
@Override
public Collection<V> values() {
if (values == null) {
values = new UnwrapValues();
}
return values;
}
protected ConcurrentMapperHashMap(
ConcurrentMap<IK, IV> innerConcurrentMap) {
this.innerConcurrentMap = innerConcurrentMap;
}
protected abstract IK mapKey(K key);
protected abstract IK mapKeyForQuery(K key);
protected abstract IV mapValue(K key, V value);
protected abstract IV mapValueForQuery(V value);
protected abstract K unmapKey(IK key);
protected abstract K unmapKeyForQuery(IK key);
protected abstract V unmapValue(IV value);
protected abstract V unmapValueForQuery(IV value);
protected transient Set<Map.Entry<K, V>> entrySet;
protected final ConcurrentMap<IK, IV> innerConcurrentMap;
protected transient Set<K> keySet;
protected transient Collection<V> values;
private static final long serialVersionUID = 1L;
private class UnwrapEntry implements Map.Entry<K, V> {
public UnwrapEntry(Entry<IK, IV> innerEntry) {
_innerEntry = innerEntry;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof Map.Entry)) {
return false;
}
Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
if (Objects.equals(getKey(), entry.getKey()) &&
Objects.equals(getValue(), entry.getValue())) {
return true;
}
return false;
}
@Override
public K getKey() {
return unmapKeyForQuery(_innerEntry.getKey());
}
@Override
public V getValue() {
return unmapValueForQuery(_innerEntry.getValue());
}
@Override
public int hashCode() {
return _innerEntry.hashCode();
}
@Override
public V setValue(V value) {
K key = getKey();
V v = unmapValueForQuery(
_innerEntry.setValue(mapValueForQuery(value)));
ConcurrentMapperHashMap.this.put(key, value);
return v;
}
private final Entry<IK, IV> _innerEntry;
}
private class UnwrapEntryIterator implements Iterator<Map.Entry<K, V>> {
public UnwrapEntryIterator() {
Set<Entry<IK, IV>> entrySet = innerConcurrentMap.entrySet();
_iterator = entrySet.iterator();
}
@Override
public boolean hasNext() {
return _iterator.hasNext();
}
@Override
public Entry<K, V> next() {
return new UnwrapEntry(_iterator.next());
}
@Override
public void remove() {
_iterator.remove();
}
private final Iterator<Map.Entry<IK, IV>> _iterator;
}
private class UnwrapEntrySet extends AbstractSet<Map.Entry<K, V>> {
@Override
public void clear() {
ConcurrentMapperHashMap.this.clear();
}
@Override
public boolean contains(Object obj) {
if (!(obj instanceof Map.Entry<?, ?>)) {
return false;
}
Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
V value = ConcurrentMapperHashMap.this.get(entry.getKey());
if ((value != null) && value.equals(entry.getValue())) {
return true;
}
else {
return false;
}
}
@Override
public boolean isEmpty() {
return ConcurrentMapperHashMap.this.isEmpty();
}
@Override
public Iterator<Map.Entry<K, V>> iterator() {
return new UnwrapEntryIterator();
}
@Override
public boolean remove(Object obj) {
if (!(obj instanceof Map.Entry<?, ?>)) {
return false;
}
Map.Entry<K, V> entry = (Map.Entry<K, V>)obj;
return ConcurrentMapperHashMap.this.remove(
entry.getKey(), entry.getValue());
}
@Override
public int size() {
return ConcurrentMapperHashMap.this.size();
}
}
private class UnwrapKeyIterator implements Iterator<K> {
public UnwrapKeyIterator() {
Set<IK> keySet = innerConcurrentMap.keySet();
_iterator = keySet.iterator();
}
@Override
public boolean hasNext() {
return _iterator.hasNext();
}
@Override
public K next() {
return unmapKeyForQuery(_iterator.next());
}
@Override
public void remove() {
_iterator.remove();
}
private final Iterator<IK> _iterator;
}
private class UnwrapKeySet extends AbstractSet<K> {
@Override
public void clear() {
ConcurrentMapperHashMap.this.clear();
}
@Override
public boolean contains(Object o) {
return ConcurrentMapperHashMap.this.containsKey(o);
}
@Override
public boolean isEmpty() {
return ConcurrentMapperHashMap.this.isEmpty();
}
@Override
public Iterator<K> iterator() {
return new UnwrapKeyIterator();
}
@Override
public boolean remove(Object o) {
if (ConcurrentMapperHashMap.this.remove(o) != null) {
return true;
}
return false;
}
@Override
public int size() {
return ConcurrentMapperHashMap.this.size();
}
}
private class UnwrapValueIterator implements Iterator<V> {
public UnwrapValueIterator() {
Collection<IV> values = innerConcurrentMap.values();
_iterator = values.iterator();
}
@Override
public boolean hasNext() {
return _iterator.hasNext();
}
@Override
public V next() {
return unmapValueForQuery(_iterator.next());
}
@Override
public void remove() {
_iterator.remove();
}
private final Iterator<IV> _iterator;
}
private class UnwrapValues extends AbstractCollection<V> {
@Override
public void clear() {
ConcurrentMapperHashMap.this.clear();
}
@Override
public boolean contains(Object obj) {
return ConcurrentMapperHashMap.this.containsValue(obj);
}
@Override
public boolean isEmpty() {
return ConcurrentMapperHashMap.this.isEmpty();
}
@Override
public Iterator<V> iterator() {
return new UnwrapValueIterator();
}
@Override
public int size() {
return ConcurrentMapperHashMap.this.size();
}
}
}