blob: caa0331e8dfad6b83aec15406a5121594dda73fd [file] [log] [blame]
/*******n***********************************************************************
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*******************************************************************************/
package org.apache.ofbiz.base.util.collections;
import java.io.Serializable;
import java.util.ConcurrentModificationException;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import org.apache.ofbiz.base.lang.Appender;
import org.apache.ofbiz.base.util.UtilGenerics;
import org.apache.ofbiz.base.util.UtilObject;
@SuppressWarnings("serial")
public abstract class GenericMap<K, V> implements Appender<StringBuilder>, Map<K, V>, Serializable {
private static final AtomicReferenceFieldUpdater<GenericMap<?, ?>, Set<?>> keySetUpdater = UtilGenerics.cast(AtomicReferenceFieldUpdater.newUpdater(GenericMap.class, Set.class, "keySet"));
private static final AtomicReferenceFieldUpdater<GenericMap<?, ?>, Set<?>> entrySetUpdater = UtilGenerics.cast(AtomicReferenceFieldUpdater.newUpdater(GenericMap.class, Set.class, "entrySet"));
private static final AtomicReferenceFieldUpdater<GenericMap<?, ?>, Collection<?>> valuesUpdater = UtilGenerics.cast(AtomicReferenceFieldUpdater.newUpdater(GenericMap.class, Collection.class, "values"));
private static final AtomicIntegerFieldUpdater<GenericMap<?, ?>> modCountUpdater = UtilGenerics.cast(AtomicIntegerFieldUpdater.newUpdater(GenericMap.class, "modCount"));
private volatile Set<K> keySet;
private volatile Set<Map.Entry<K, V>> entrySet;
private volatile Collection<V> values;
private volatile int modCount;
public int getModCount() {
return modCount;
}
protected void incrementModCount() {
modCountUpdater.getAndIncrement(this);
}
public final void clear() {
if (isEmpty()) return;
incrementModCount();
clearInternal();
}
protected abstract void clearInternal();
public boolean containsValue(Object value) {
return values().contains(value);
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Map<?, ?>)) return false;
if (this == o) return true;
Map<?, ?> map = (Map<?, ?>) o;
if (size() != map.size()) return false;
if (o instanceof GenericMap<?, ?>) return equalsGenericMap((GenericMap<?, ?>) o);
return equalsMap(map);
}
protected boolean equalsGenericMap(GenericMap<?, ?> map) {
Iterator<Map.Entry<K, V>> it = iterator(false);
while (it.hasNext()) {
Map.Entry<K, V> entry = it.next();
K key = entry.getKey();
V value = entry.getValue();
if (value != null) {
if (!value.equals(map.get(key, false))) return false;
} else {
Object otherValue = map.get(key, false);
if (otherValue != null) return false;
if (!map.containsKey(key)) return false;
}
}
return true;
}
protected boolean equalsMap(Map<?, ?> map) {
Iterator<Map.Entry<K, V>> it = iterator(false);
while (it.hasNext()) {
Map.Entry<K, V> entry = it.next();
K key = entry.getKey();
V value = entry.getValue();
if (value != null) {
if (!value.equals(map.get(key))) return false;
} else {
Object otherValue = map.get(key);
if (otherValue != null) return false;
if (!map.containsKey(key)) return false;
}
}
return true;
}
public final V get(Object key) {
return get(key, true);
}
protected abstract V get(Object key, boolean noteAccess);
protected abstract class GenericMapIterator<DEST> extends IteratorWrapper<DEST, Map.Entry<K, V>> {
private final int currentModCount = getModCount();
protected GenericMapIterator(boolean noteAccess) {
super(iterator(noteAccess));
}
protected boolean isValid(Map.Entry<K, V> src) {
if (currentModCount != getModCount()) throw new ConcurrentModificationException();
return true;
}
}
public final Set<Map.Entry<K, V>> entrySet() {
if (entrySet == null) {
entrySetUpdater.compareAndSet(this, null, new GenericMapEntrySet<K, V, GenericMap<K, V>>(this) {
@Override
protected boolean contains(Object key, Object value) {
return UtilObject.equalsHelper(get(key, false), value);
}
@Override
public Iterator<Map.Entry<K, V>> iterator(boolean noteAccess) {
return new GenericMapIterator<Map.Entry<K, V>>(noteAccess) {
@Override
protected void noteRemoval(Map.Entry<K, V> dest, Map.Entry<K, V> src) {
// No need to note the remove, the wrapped iterator does that for us
}
@Override
protected Map.Entry<K, V> convert(Map.Entry<K, V> src) {
return src;
}
};
}
});
}
return entrySet;
}
protected abstract Iterator<Map.Entry<K, V>> iterator(boolean noteAccess);
public final Set<K> keySet() {
if (keySet == null) {
keySetUpdater.compareAndSet(this, null, new GenericMapKeySet<K, V, GenericMap<K, V>>(this) {
public boolean contains(Object key) {
return containsKey(key);
}
@Override
public Iterator<K> iterator(boolean noteAccess) {
return new GenericMapIterator<K>(noteAccess) {
@Override
protected void noteRemoval(K dest, Map.Entry<K, V> src) {
// No need to note the remove, the wrapped iterator does that for us
}
@Override
protected K convert(Map.Entry<K, V> src) {
return src.getKey();
}
};
}
});
}
return keySet;
}
public final Collection<V> values() {
if (values == null) {
valuesUpdater.compareAndSet(this, null, new GenericMapValues<K, V, GenericMap<K, V>>(this) {
@Override
public Iterator<V> iterator(boolean noteAccess) {
return new GenericMapIterator<V>(noteAccess) {
@Override
protected void noteRemoval(V dest, Map.Entry<K, V> src) {
// No need to note the remove, the wrapped iterator does that for us
}
@Override
protected V convert(Map.Entry<K, V> src) {
return src.getValue();
}
};
}
});
}
return values;
}
public final V remove(Object key) {
return removeInternal(key, true);
}
protected abstract V removeInternal(Object key, boolean incrementModCount);
public final void putAll(Map<? extends K, ? extends V> map) {
putAllInternal(map);
}
private <KE extends K, VE extends V> void putAllInternal(Map<KE, VE> map) {
if (map.isEmpty()) return;
incrementModCount();
Iterator<Map.Entry<KE, VE>> it;
if (map instanceof GenericMap<?, ?>) {
GenericMap<KE, VE> otherMap = UtilGenerics.cast(map);
it = otherMap.iterator(false);
} else {
it = map.entrySet().iterator();
}
putAllIterator(it);
}
protected abstract <KE extends K, VE extends V> void putAllIterator(Iterator<Map.Entry<KE, VE>> it);
@Override
public String toString() {
return appendTo(new StringBuilder()).toString();
}
public StringBuilder appendTo(StringBuilder sb) {
sb.append("{");
Iterator<Map.Entry<K, V>> it = iterator(false);
while (it.hasNext()) {
Map.Entry<K, V> entry = it.next();
sb.append(entry.getKey()).append("=").append(entry.getValue());
if (it.hasNext()) sb.append(",");
}
return sb.append("}");
}
}