Author: doogie
Date: Fri Dec 11 18:43:55 2009
New Revision: 889761
URL: http://svn.apache.org/viewvc?rev=889761&view=rev
Log:
Support ConcurrentModificationException for iterators.
Modified:
ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/GenericMap.java
Modified:
ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/GenericMap.java
URL:
http://svn.apache.org/viewvc/ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/GenericMap.java?rev=889761&r1=889760&r2=889761&view=diff
==============================================================================
---
ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/GenericMap.java
(original)
+++
ofbiz/trunk/framework/base/src/org/ofbiz/base/util/collections/GenericMap.java
Fri Dec 11 18:43:55 2009
@@ -19,10 +19,12 @@
package org.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.ofbiz.base.util.Appender;
@@ -33,10 +35,28 @@
private static final AtomicReferenceFieldUpdater<GenericMap, Set>
keySetUpdater = AtomicReferenceFieldUpdater.newUpdater(GenericMap.class,
Set.class, "keySet");
private static final AtomicReferenceFieldUpdater<GenericMap, Set>
entrySetUpdater = AtomicReferenceFieldUpdater.newUpdater(GenericMap.class,
Set.class, "entrySet");
private static final AtomicReferenceFieldUpdater<GenericMap, Collection>
valuesUpdater = AtomicReferenceFieldUpdater.newUpdater(GenericMap.class,
Collection.class, "values");
+ private static final AtomicIntegerFieldUpdater<GenericMap> modCountUpdater
= 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);
@@ -91,6 +111,19 @@
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) {
@@ -99,7 +132,17 @@
}
public Iterator<Map.Entry<K, V>> iterator(boolean noteAccess) {
- return GenericMap.this.iterator(noteAccess);
+ return new GenericMapIterator<Map.Entry<K, V>>(noteAccess)
{
+ 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
+ // evictionPolicy.remove(evictionDeque, dest);
+ // if (diskStore != null) diskStore.remove(dest);
+ }
+
+ protected Map.Entry<K, V> convert(Map.Entry<K, V> src)
{
+ return src;
+ }
+ };
}
});
}
@@ -116,7 +159,7 @@
}
public Iterator<K> iterator(boolean noteAccess) {
- return new IteratorWrapper<K, Map.Entry<K,
V>>(GenericMap.this.iterator(noteAccess)) {
+ return new GenericMapIterator<K>(noteAccess) {
protected void noteRemoval(K dest, Map.Entry<K, V>
src) {
// No need to note the remove, the wrapped
iterator does that for us
// evictionPolicy.remove(evictionDeque, dest);
@@ -137,7 +180,7 @@
if (values == null) {
valuesUpdater.compareAndSet(this, null, new GenericMapValues<K, V,
GenericMap<K, V>>(this) {
public Iterator<V> iterator(boolean noteAccess) {
- return new IteratorWrapper<V, Map.Entry<K,
V>>(GenericMap.this.iterator(noteAccess)) {
+ return new GenericMapIterator<V>(noteAccess) {
protected void noteRemoval(V dest, Map.Entry<K, V>
src) {
// No need to note the remove, the wrapped
iterator does that for us
// evictionPolicy.remove(evictionDeque,
src.getKey());
@@ -154,11 +197,19 @@
return values;
}
- public void putAll(Map<? extends K, ? extends V> map) {
+ 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);