[Arakhnę-Dev] [27] Bug fix: avoid ConcurrentModificationException on WeakValueMap and SoftValueMap.

[ Thread Index | Date Index | More arakhne.org/dev Archives ]


Revision: 27
Author:   galland
Date:     2009-02-02 21:42:49 +0100 (Mon, 02 Feb 2009)

Log Message:
-----------
Bug fix: avoid ConcurrentModificationException on WeakValueMap and SoftValueMap.

Modified Paths:
--------------
    trunk/arakhneRefs/pom.xml
    trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/SoftValueMap.java
    trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/WeakValueMap.java
    trunk/pom.xml

Added Paths:
-----------
    trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/AbstractWeakSoftValueMap.java


Modified: trunk/arakhneRefs/pom.xml
===================================================================
--- trunk/arakhneRefs/pom.xml	2009-02-02 20:41:14 UTC (rev 26)
+++ trunk/arakhneRefs/pom.xml	2009-02-02 20:42:49 UTC (rev 27)
@@ -22,5 +22,13 @@
 	<scm>
 		<url>http://www.arakhne.org/websvn.php?project=afc&amp;subproject=arakhneRefs</url>
 	</scm>
+	
+	<dependencies>
+		<dependency>
+			<groupId>junit</groupId>
+			<artifactId>junit</artifactId>
+			<scope>test</scope>
+		</dependency>
+	</dependencies>
 
 </project>

Added: trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/AbstractWeakSoftValueMap.java
===================================================================
--- trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/AbstractWeakSoftValueMap.java	                        (rev 0)
+++ trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/AbstractWeakSoftValueMap.java	2009-02-02 20:42:49 UTC (rev 27)
@@ -0,0 +1,413 @@
+/* 
+ * $Id: WeakValueMap.java,v 1.1 2007-02-20 08:52:37 sgalland Exp $
+ * 
+ * Copyright (C) 2005-2007 St&eacute;phane GALLAND
+ * 
+ * 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.
+ * 
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ * This program is free software; you can redistribute it and/or modify
+ */
+
+package org.arakhne.util.ref;
+
+import java.lang.ref.Reference;
+import java.lang.ref.ReferenceQueue;
+import java.util.AbstractMap;
+import java.util.AbstractSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Set;
+
+/**
+ * A <tt>Map</tt> implementation with <em>weak/soft values</em>. An entry in a
+ * <tt>AbstractWeakSoftValueMap</tt> will automatically be removed when its value is no
+ * longer in ordinary use or null.
+ *
+ * @param <K> is the type of the keys.
+ * @param <V> is the type of the values.
+ * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
+ * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+ */
+public abstract class AbstractWeakSoftValueMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
+	
+	/** Defines the NULL object inside a WeakValueMap.
+	 * 
+	 * @see #maskNull(Object)
+	 */
+	protected static final Object NULL_VALUE = new Object();
+
+	/** Mask the null values given by the used of this map.
+	 * <p>
+	 * This method replaces the <code>null</code> value by
+	 * the internal representation {@link #NULL_VALUE}.
+	 *
+	 * @param <V> is the type of the value.
+	 * @param value is the value given by the user of this map.
+	 * @return the internal representation of the value.
+	 * @see #unmaskNull(Object)
+	 */
+	@SuppressWarnings("unchecked")
+	protected static <V> V maskNull(V value) {
+		return (value==null) ? (V)NULL_VALUE : value;
+	}
+
+	/** Unmask the null values given by the used of this map.
+	 * <p>
+	 * This method replaces the internal representation
+	 * {@link #NULL_VALUE} of null values by its user representation
+	 * <code>null</code>.
+	 * 
+	 * @param <V> is the type of the value.
+	 * @param value is the value given by the user of this map.
+	 * @return the internal representation of the value.
+	 * @see #maskNull(Object)
+	 */
+	protected static <V> V unmaskNull(V value) {
+		return (value==NULL_VALUE) ? null : value;
+	}
+
+	private boolean autoExpurge = false;
+	private final HashMap<K,WeakSoftValue<K,V>> map;
+	private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
+	private final EntrySet entrySet;
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and load factor.
+     *
+     * @param  initialCapacity the initial capacity
+     * @param  loadFactor      the load factor
+     * @throws IllegalArgumentException if the initial capacity is negative
+     *         or the load factor is nonpositive
+     */
+    public AbstractWeakSoftValueMap(int initialCapacity, float loadFactor) {
+        this.map = new HashMap<K,WeakSoftValue<K,V>>(initialCapacity, loadFactor);
+        this.entrySet = new EntrySet();
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the specified initial
+     * capacity and the default load factor (0.75).
+     *
+     * @param  initialCapacity the initial capacity.
+     * @throws IllegalArgumentException if the initial capacity is negative.
+     */
+    public AbstractWeakSoftValueMap(int initialCapacity) {
+        this.map = new HashMap<K,WeakSoftValue<K,V>>(initialCapacity);
+        this.entrySet = new EntrySet();
+    }
+
+    /**
+     * Constructs an empty <tt>HashMap</tt> with the default initial capacity
+     * (16) and the default load factor (0.75).
+     */
+    public AbstractWeakSoftValueMap() {
+        this.map = new HashMap<K,WeakSoftValue<K,V>>();
+        this.entrySet = new EntrySet();
+    }
+
+    /**
+     * Constructs a new <tt>HashMap</tt> with the same mappings as the
+     * specified <tt>Map</tt>.  The <tt>HashMap</tt> is created with
+     * default load factor (0.75) and an initial capacity sufficient to
+     * hold the mappings in the specified <tt>Map</tt>.
+     *
+     * @param   m the map whose mappings are to be placed in this map
+     * @throws  NullPointerException if the specified map is null
+     */
+    public AbstractWeakSoftValueMap(Map<? extends K, ? extends V> m) {
+        this.map = new HashMap<K,WeakSoftValue<K,V>>();
+        this.entrySet = new EntrySet();
+        putAll(m);
+    }	
+
+    /** Clean the references that was marked as released inside
+     * the queue.
+     */
+	protected final void expurgeNow() {
+		if (this.autoExpurge)
+			expurge();
+		else
+			expurgeQueuedReferences();
+	}
+	
+	/** Replies if this map expurge all the released references
+	 * even if they are not enqueued by the virtual machine
+	 * 
+	 * @return <code>true</code> is the values are deeply expurged when they
+	 * are released from the moemory, otherwise <code>false</code>
+	 */
+	public final boolean isDeeplyExpurge() {
+		return this.autoExpurge;
+	}
+	
+	/** Set if this map expurge all the released references
+	 * even if they are not enqueued by the virtual machine
+	 * 
+	 * @param deeplyExpurge must be <code>true</code> to
+	 * expurge all the released values, otherwise <code>false</code>
+	 * to expurge only the enqueued values.
+	 * @return the old value of this flag
+	 */
+	public final boolean setDeeplyExpurge(boolean deeplyExpurge) {
+		boolean old = this.autoExpurge;
+		this.autoExpurge = deeplyExpurge;
+		return old;
+	}
+	
+    /** Clean the references that was marked as released inside
+     * the queue.
+     */
+	public final void expurgeQueuedReferences() {
+		Reference<? extends V> o;
+		while((o = this.queue.poll()) != null) {
+			if (o instanceof WeakSoftValue) {
+				this.map.remove(((WeakSoftValue<?,?>)o).getKey());
+			}
+			o.clear();
+		}
+	}
+
+	/** Clean the references that was released.
+     */
+	public final void expurge() {
+		Reference<? extends V> o;
+		
+		Iterator<Entry<K,WeakSoftValue<K,V>>> iter = this.map.entrySet().iterator();
+		Entry<K,WeakSoftValue<K,V>> entry;
+		WeakSoftValue<K,V> value;
+		while (iter.hasNext()) {
+			entry = iter.next();
+			if (entry!=null) {
+				value = entry.getValue();
+				if ((value!=null)&&
+					((value.isEnqueued())||(value.get()==null))) {
+					value.enqueue();
+					value.clear();
+				}
+			}
+		}
+		entry = null;
+		value = null;
+
+		while((o = this.queue.poll()) != null) {
+			if (o instanceof WeakSoftValue) {
+				this.map.remove(((WeakSoftValue<?,?>)o).getKey());
+			}
+			o.clear();
+		}
+	}
+
+	/** Create a storage object that permits to put the specified
+	 * elements inside this map.
+	 * 
+	 * @param k is the key associated to the value
+	 * @param v is the value
+	 * @param queue is the reference queue to use
+	 * @return the new storage object
+	 */
+	protected abstract WeakSoftValue<K,V> makeValue(K k, V v, ReferenceQueue<V> queue);
+
+	/**
+     * {@inheritDoc}
+     */
+	@Override
+	public final V put(K key, V value) {
+		expurgeNow();
+		WeakSoftValue<K,V> ret = this.map.put(key, makeValue(key, value, this.queue));
+		if(ret == null) return null;
+		return ret.getValue();
+	}
+
+	/**
+	 * {@inheritDoc}
+	 */
+	@Override
+	public final Set<Entry<K,V>> entrySet() {
+		expurgeNow();
+		return this.entrySet;
+	}	
+		
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+	public final boolean equals(Object o) {
+    	expurgeNow();
+    	return super.equals(o);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+	public final int hashCode() {
+    	expurgeNow();
+    	return hashCode();
+    }
+
+    /**
+	 * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
+	 * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+	 */
+	private class RealEntry implements Entry<K,V> {
+
+		private final K key;
+		private V value;
+		
+		public RealEntry(K k, V v) {
+			this.key = k;
+			this.value = v;
+		}
+		
+		@Override
+		public K getKey() {
+			return this.key;
+		}
+
+		@Override
+		public V getValue() {
+			return this.value;
+		}
+
+		@Override
+		public V setValue(V value) {
+			V oldValue = this.value;
+			this.value = value;
+			if (value==null)
+				remove(this.key);
+			else
+				put(this.key, value);
+			return oldValue;
+		}
+		
+	}
+
+	/**
+	 * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
+	 * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+	 */
+	private class EntrySetIterator implements Iterator<Entry<K,V>> {
+		
+		private final Iterator<Entry<K,WeakSoftValue<K,V>>> iter;
+		private RealEntry next;
+		
+		public EntrySetIterator(Iterator<Entry<K,WeakSoftValue<K,V>>> iter) {
+			this.iter = iter;
+			expurgeNow();
+			this.next = searchNext();
+		}
+		
+		private RealEntry searchNext() {
+			Entry<K,WeakSoftValue<K,V>> entry;
+			WeakSoftValue<K,V> val;
+			V value;
+			while (this.iter.hasNext()) {
+				entry = this.iter.next();
+				if (entry==null) throw new NoSuchElementException();
+				val = entry.getValue();
+				if (val==null) throw new NoSuchElementException();
+				value = val.getValue();
+				if (value!=null) {
+					return new RealEntry(entry.getKey(), value);
+				}
+			}
+			return null;
+		}
+		
+		public boolean hasNext() { 
+			return (this.next!=null);
+		}
+		
+		public Entry<K,V> next() {
+			RealEntry entry = this.next;
+			if (entry==null) throw new NoSuchElementException();
+			this.next = searchNext();
+			return entry;
+		}
+		
+		public void remove() {
+			this.iter.remove();
+		}
+		
+	}
+
+	/**
+	 * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
+	 * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+	 */
+	private class EntrySet extends AbstractSet<Entry<K,V>> implements Set<Entry<K,V>> {
+		
+		/**
+		 *
+		 */
+		public EntrySet() {
+			//
+		}
+		
+		/**
+		 * {@inheritDoc}
+		 * 
+		 * @return {@inheritDoc}
+		 */
+		@SuppressWarnings("synthetic-access")
+		@Override
+		public Iterator<Entry<K, V>> iterator() {
+			return new EntrySetIterator(AbstractWeakSoftValueMap.this.map.entrySet().iterator());
+		}
+
+		/**
+		 * {@inheritDoc}
+		 * 
+		 * @return {@inheritDoc}
+		 */
+		@SuppressWarnings("synthetic-access")
+		@Override
+		public int size() {
+			expurgeNow();
+			return AbstractWeakSoftValueMap.this.map.size();
+		}
+		
+	}
+        
+	/**
+	 * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
+	 * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
+	 */
+	protected interface WeakSoftValue<K,V> extends Entry<K,V> {
+		
+		/**
+		 * @return if the value is enqueued into a reference queue.
+		 */
+		public boolean isEnqueued();
+		
+		/**
+		 * @return the weak/soft reference.
+		 */
+		public V get();
+
+		/**
+		 * @return if the value was enqueued
+		 */
+		public boolean enqueue();
+
+		/**
+		 */
+		public void clear();
+
+	}
+
+}

Modified: trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/SoftValueMap.java
===================================================================
--- trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/SoftValueMap.java	2009-02-02 20:41:14 UTC (rev 26)
+++ trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/SoftValueMap.java	2009-02-02 20:42:49 UTC (rev 27)
@@ -1,7 +1,7 @@
 /* 
- * $Id$
+ * $Id: SoftValueMap.java,v 1.1 2007-02-20 08:52:37 sgalland Exp $
  * 
- * Copyright (C) 2005-2008 St&eacute;phane GALLAND
+ * Copyright (C) 2005-2007 St&eacute;phane GALLAND
  * 
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -21,23 +21,16 @@
 
 package org.arakhne.util.ref;
 
-import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.Set;
 
 /**
- * A <tt>Map</tt> implementation with <em>soft-referenced values</em>. An entry in a
+ * A <tt>Map</tt> implementation with <em>soft values</em>. An entry in a
  * <tt>SoftValueMap</tt> will automatically be removed when its value is no
  * longer in ordinary use or null.
  * <p>
- * This class was inspirated from {@link WeakValueMap}.
+ * This class was inspirated from <code>WeakHashMap</code>
  * <p>
  * This class has a special flag which permits to control the
  * way how the released references are expurged: {@link #isDeeplyExpurge()},
@@ -66,48 +59,8 @@
  * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
  * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
  */
-public class SoftValueMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
-
-	/** Constant that represent a NULL value inside a SoftValueMap.
-	 * @see #maskNull(Object)
-	 */
-	protected static final Object NULL_VALUE = new Object();
-
-	/** Mask the null values given by the used of this map.
-	 * <p>
-	 * This method replaces the <code>null</code> value by
-	 * the internal representation {@link #NULL_VALUE}.
-	 *
-	 * @param <V> is the type of the value
-	 * @param value is the value given by the user of this map.
-	 * @return the internal representation of the value.
-	 * @see #unmaskNull(Object)
-	 */
-	@SuppressWarnings("unchecked")
-	protected static <V> V maskNull(V value) {
-		return (value==null) ? (V)NULL_VALUE : value;
-	}
-
-	/** Unmask the null values given by the used of this map.
-	 * <p>
-	 * This method replaces the internal representation
-	 * {@link #NULL_VALUE} of null values by its user representation
-	 * <code>null</code>.
-	 * 
-	 * @param <V> is the type of the value
-	 * @param value is the value given by the user of this map.
-	 * @return the internal representation of the value.
-	 * @see #maskNull(Object)
-	 */
-	protected static <V> V unmaskNull(V value) {
-		return (value==NULL_VALUE) ? null : value;
-	}
-
-	private boolean autoExpurge = false;
-	private final HashMap<K,Value<K,V>> map;
-	private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
-	private final EntrySet entrySet;
-
+public class SoftValueMap<K,V> extends AbstractWeakSoftValueMap<K,V> {
+	
     /**
      * Constructs an empty <tt>HashMap</tt> with the specified initial
      * capacity and load factor.
@@ -118,8 +71,7 @@
      *         or the load factor is nonpositive
      */
     public SoftValueMap(int initialCapacity, float loadFactor) {
-        this.map = new HashMap<K,Value<K,V>>(initialCapacity, loadFactor);
-        this.entrySet = new EntrySet();
+        super(initialCapacity, loadFactor);
     }
 
     /**
@@ -130,8 +82,7 @@
      * @throws IllegalArgumentException if the initial capacity is negative.
      */
     public SoftValueMap(int initialCapacity) {
-        this.map = new HashMap<K,Value<K,V>>(initialCapacity);
-        this.entrySet = new EntrySet();
+    	super(initialCapacity);
     }
 
     /**
@@ -139,8 +90,7 @@
      * (16) and the default load factor (0.75).
      */
     public SoftValueMap() {
-        this.map = new HashMap<K,Value<K,V>>();
-        this.entrySet = new EntrySet();
+    	super();
     }
 
     /**
@@ -153,89 +103,9 @@
      * @throws  NullPointerException if the specified map is null
      */
     public SoftValueMap(Map<? extends K, ? extends V> m) {
-        this.map = new HashMap<K,Value<K,V>>();
-        this.entrySet = new EntrySet();
-        putAll(m);
+        super(m);
     }	
 
-    /** Clean the references that was marked as released inside
-     * the queue.
-     */
-	protected void expurgeNow() {
-		if (this.autoExpurge)
-			expurge();
-		else
-			expurgeQueuedReferences();
-	}
-	
-	/** Replies if this map expurge all the released references
-	 * even if they are not enqueued by the virtual machine
-	 * 
-	 * @return <code>true</code> if this map deeply expurge its content,
-	 * otherwise <code>false</code>
-	 */
-	public boolean isDeeplyExpurge() {
-		return this.autoExpurge;
-	}
-	
-	/** Set if this map expurge all the released references
-	 * even if they are not enqueued by the virtual machine
-	 * 
-	 * @param deeplyExpurge must be <code>true</code> to
-	 * expurge all the released values, otherwise <code>false</code>
-	 * to expurge only the enqueued values.
-	 * @return the old value of this flag
-	 */
-	public boolean setDeeplyExpurge(boolean deeplyExpurge) {
-		boolean old = this.autoExpurge;
-		this.autoExpurge = deeplyExpurge;
-		return old;
-	}
-	
-    /** Clean the references that was marked as released inside
-     * the queue.
-     */
-	public void expurgeQueuedReferences() {
-		Reference<? extends V> o;
-		while((o = this.queue.poll()) != null) {
-			if (o instanceof Value) {
-				
-				this.map.remove(((Value<?,?>)o).getKey());
-			}
-			o.clear();
-		}
-	}
-
-	/** Clean the references that was released.
-     */
-	public void expurge() {
-		Reference<? extends V> o;
-		
-		Iterator<Entry<K,Value<K,V>>> iter = this.map.entrySet().iterator();
-		Entry<K,Value<K,V>> entry;
-		Value<K,V> value;
-		while (iter.hasNext()) {
-			entry = iter.next();
-			if (entry!=null) {
-				value = entry.getValue();
-				if ((value!=null)&&
-					((value.isEnqueued())||(value.get()==null))) {
-					value.enqueue();
-					value.clear();
-				}
-			}
-		}
-		entry = null;
-		value = null;
-
-		while((o = this.queue.poll()) != null) {
-			if (o instanceof Value) {
-				this.map.remove(((Value<?,?>)o).getKey());
-			}
-			o.clear();
-		}
-	}
-
 	/** Create a storage object that permits to put the specified
 	 * elements inside this map.
 	 * 
@@ -244,115 +114,23 @@
 	 * @param queue is the reference queue to use
 	 * @return the new storage object
 	 */
-	protected Value<K,V> makeValue(K k, V v, ReferenceQueue<V> queue) {
+	@Override
+	protected WeakSoftValue<K,V> makeValue(K k, V v, ReferenceQueue<V> queue) {
 		return new Value<K,V>(k, v, queue);
 	}
 
 	/**
-     * {@inheritDoc}
-     */
-	@Override
-	public V put(K key, V value) {
-		expurgeNow();
-		Value<K,V> ret = this.map.put(key, makeValue(key, value, this.queue));
-		if(ret == null) return null;
-		return ret.getValue();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Set<Entry<K,V>> entrySet() {
-		expurgeNow();
-		return this.entrySet;
-	}	
-		
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-	public boolean equals(Object o) {
-    	expurgeNow();
-    	return super.equals(o);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-	public int hashCode() {
-    	expurgeNow();
-    	return hashCode();
-    }
-
-    /**
 	 * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
 	 * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
 	 */
-	private class EntrySet extends AbstractSet<Entry<K,V>> implements Set<Entry<K,V>> {
+	private static class Value<K,V> extends SoftReference<V> implements WeakSoftValue<K,V> {
 		
-		private final Set<Entry<K,Value<K,V>>> baseSet;
-
-		/**
-		 * 
-		 */
-		@SuppressWarnings("synthetic-access")
-		public EntrySet() {
-			this.baseSet = SoftValueMap.this.map.entrySet();
-		}
-		
-		/**
-		 * {@inheritDoc}
-		 * 
-		 * @return {@inheritDoc}
-		 */
-		@Override
-		public Iterator<Entry<K, V>> iterator() {
-			final Iterator<Entry<K,Value<K,V>>> iter = this.baseSet.iterator();
-			return new Iterator<Entry<K,V>>() {
-				public boolean hasNext() { 
-					expurgeNow();
-					return iter.hasNext();
-				}
-				public Entry<K,V> next() {
-					Entry<K, Value<K,V>> entry = iter.next();
-					if (entry==null) throw new ConcurrentModificationException();
-					Value<K,V> value = entry.getValue();
-					if (value==null) throw new ConcurrentModificationException();
-					return value;
-				}
-				public void remove() {
-					iter.remove();
-				}
-			};
-		}
-
-		/**
-		 * {@inheritDoc}
-		 * 
-		 * @return {@inheritDoc}
-		 */
-		@Override
-		public int size() {
-			expurgeNow();
-			return this.baseSet.size();
-		}
-		
-	}
-
-	/**
-	 * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
-	 * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
-	 */
-	private static class Value<K,V> extends SoftReference<V> implements Entry<K,V> {
-		
 		private final K k;
 
 		/**
 		 * @param k is the key.
 		 * @param v is the value.
-		 * @param queue is the memory release listener.
+		 * @param queue is the memory-release listener.
 		 */
 		Value(K k, V v, ReferenceQueue<V> queue) {
 			super(maskNull(v), queue);
@@ -382,7 +160,7 @@
 			buffer.append('}');
 			return buffer.toString();
 		}
-
+		
 		/**
 		 * {@inheritDoc}
 		 * 
@@ -400,7 +178,7 @@
 		public V getValue() {
 			return unmaskNull(get());
 		}
-
+		
 		/**
 		 * {@inheritDoc}
 		 *

Modified: trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/WeakValueMap.java
===================================================================
--- trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/WeakValueMap.java	2009-02-02 20:41:14 UTC (rev 26)
+++ trunk/arakhneRefs/src/main/java/org/arakhne/util/ref/WeakValueMap.java	2009-02-02 20:42:49 UTC (rev 27)
@@ -21,16 +21,9 @@
 
 package org.arakhne.util.ref;
 
-import java.lang.ref.Reference;
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.WeakReference;
-import java.util.AbstractMap;
-import java.util.AbstractSet;
-import java.util.ConcurrentModificationException;
-import java.util.HashMap;
-import java.util.Iterator;
 import java.util.Map;
-import java.util.Set;
 import java.util.WeakHashMap;
 
 /**
@@ -67,49 +60,8 @@
  * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
  * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
  */
-public class WeakValueMap<K,V> extends AbstractMap<K,V> implements Map<K,V> {
+public class WeakValueMap<K,V> extends AbstractWeakSoftValueMap<K,V> {
 	
-	/** Defines the NULL object inside a WeakValueMap.
-	 * 
-	 * @see #maskNull(Object)
-	 */
-	protected static final Object NULL_VALUE = new Object();
-
-	/** Mask the null values given by the used of this map.
-	 * <p>
-	 * This method replaces the <code>null</code> value by
-	 * the internal representation {@link #NULL_VALUE}.
-	 *
-	 * @param <V> is the type of the value.
-	 * @param value is the value given by the user of this map.
-	 * @return the internal representation of the value.
-	 * @see #unmaskNull(Object)
-	 */
-	@SuppressWarnings("unchecked")
-	protected static <V> V maskNull(V value) {
-		return (value==null) ? (V)NULL_VALUE : value;
-	}
-
-	/** Unmask the null values given by the used of this map.
-	 * <p>
-	 * This method replaces the internal representation
-	 * {@link #NULL_VALUE} of null values by its user representation
-	 * <code>null</code>.
-	 * 
-	 * @param <V> is the type of the value.
-	 * @param value is the value given by the user of this map.
-	 * @return the internal representation of the value.
-	 * @see #maskNull(Object)
-	 */
-	protected static <V> V unmaskNull(V value) {
-		return (value==NULL_VALUE) ? null : value;
-	}
-
-	private boolean autoExpurge = false;
-	private final HashMap<K,Value<K,V>> map;
-	private final ReferenceQueue<V> queue = new ReferenceQueue<V>();
-	private final EntrySet entrySet;
-
     /**
      * Constructs an empty <tt>HashMap</tt> with the specified initial
      * capacity and load factor.
@@ -120,8 +72,7 @@
      *         or the load factor is nonpositive
      */
     public WeakValueMap(int initialCapacity, float loadFactor) {
-        this.map = new HashMap<K,Value<K,V>>(initialCapacity, loadFactor);
-        this.entrySet = new EntrySet();
+        super(initialCapacity, loadFactor);
     }
 
     /**
@@ -132,8 +83,7 @@
      * @throws IllegalArgumentException if the initial capacity is negative.
      */
     public WeakValueMap(int initialCapacity) {
-        this.map = new HashMap<K,Value<K,V>>(initialCapacity);
-        this.entrySet = new EntrySet();
+    	super(initialCapacity);
     }
 
     /**
@@ -141,8 +91,7 @@
      * (16) and the default load factor (0.75).
      */
     public WeakValueMap() {
-        this.map = new HashMap<K,Value<K,V>>();
-        this.entrySet = new EntrySet();
+    	super();
     }
 
     /**
@@ -155,88 +104,9 @@
      * @throws  NullPointerException if the specified map is null
      */
     public WeakValueMap(Map<? extends K, ? extends V> m) {
-        this.map = new HashMap<K,Value<K,V>>();
-        this.entrySet = new EntrySet();
-        putAll(m);
+        super(m);
     }	
 
-    /** Clean the references that was marked as released inside
-     * the queue.
-     */
-	protected void expurgeNow() {
-		if (this.autoExpurge)
-			expurge();
-		else
-			expurgeQueuedReferences();
-	}
-	
-	/** Replies if this map expurge all the released references
-	 * even if they are not enqueued by the virtual machine
-	 * 
-	 * @return <code>true</code> is the values are deeply expurged when they
-	 * are released from the moemory, otherwise <code>false</code>
-	 */
-	public boolean isDeeplyExpurge() {
-		return this.autoExpurge;
-	}
-	
-	/** Set if this map expurge all the released references
-	 * even if they are not enqueued by the virtual machine
-	 * 
-	 * @param deeplyExpurge must be <code>true</code> to
-	 * expurge all the released values, otherwise <code>false</code>
-	 * to expurge only the enqueued values.
-	 * @return the old value of this flag
-	 */
-	public boolean setDeeplyExpurge(boolean deeplyExpurge) {
-		boolean old = this.autoExpurge;
-		this.autoExpurge = deeplyExpurge;
-		return old;
-	}
-	
-    /** Clean the references that was marked as released inside
-     * the queue.
-     */
-	public void expurgeQueuedReferences() {
-		Reference<? extends V> o;
-		while((o = this.queue.poll()) != null) {
-			if (o instanceof Value) {
-				this.map.remove(((Value<?,?>)o).getKey());
-			}
-			o.clear();
-		}
-	}
-
-	/** Clean the references that was released.
-     */
-	public void expurge() {
-		Reference<? extends V> o;
-		
-		Iterator<Entry<K,Value<K,V>>> iter = this.map.entrySet().iterator();
-		Entry<K,Value<K,V>> entry;
-		Value<K,V> value;
-		while (iter.hasNext()) {
-			entry = iter.next();
-			if (entry!=null) {
-				value = entry.getValue();
-				if ((value!=null)&&
-					((value.isEnqueued())||(value.get()==null))) {
-					value.enqueue();
-					value.clear();
-				}
-			}
-		}
-		entry = null;
-		value = null;
-
-		while((o = this.queue.poll()) != null) {
-			if (o instanceof Value) {
-				this.map.remove(((Value<?,?>)o).getKey());
-			}
-			o.clear();
-		}
-	}
-
 	/** Create a storage object that permits to put the specified
 	 * elements inside this map.
 	 * 
@@ -245,109 +115,17 @@
 	 * @param queue is the reference queue to use
 	 * @return the new storage object
 	 */
-	protected Value<K,V> makeValue(K k, V v, ReferenceQueue<V> queue) {
+	@Override
+	protected WeakSoftValue<K,V> makeValue(K k, V v, ReferenceQueue<V> queue) {
 		return new Value<K,V>(k, v, queue);
 	}
 
 	/**
-     * {@inheritDoc}
-     */
-	@Override
-	public V put(K key, V value) {
-		expurgeNow();
-		Value<K,V> ret = this.map.put(key, makeValue(key, value, this.queue));
-		if(ret == null) return null;
-		return ret.getValue();
-	}
-
-	/**
-	 * {@inheritDoc}
-	 */
-	@Override
-	public Set<Entry<K,V>> entrySet() {
-		expurgeNow();
-		return this.entrySet;
-	}	
-		
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-	public boolean equals(Object o) {
-    	expurgeNow();
-    	return super.equals(o);
-    }
-
-    /**
-     * {@inheritDoc}
-     */
-    @Override
-	public int hashCode() {
-    	expurgeNow();
-    	return hashCode();
-    }
-
-    /**
 	 * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
 	 * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
 	 */
-	private class EntrySet extends AbstractSet<Entry<K,V>> implements Set<Entry<K,V>> {
+	private static class Value<K,V> extends WeakReference<V> implements WeakSoftValue<K,V> {
 		
-		private final Set<Entry<K,Value<K,V>>> baseSet;
-
-		/**
-		 *
-		 */
-		@SuppressWarnings("synthetic-access")
-		public EntrySet() {
-			this.baseSet = WeakValueMap.this.map.entrySet();
-		}
-		
-		/**
-		 * {@inheritDoc}
-		 * 
-		 * @return {@inheritDoc}
-		 */
-		@Override
-		public Iterator<Entry<K, V>> iterator() {
-			final Iterator<Entry<K,Value<K,V>>> iter = this.baseSet.iterator();
-			return new Iterator<Entry<K,V>>() {
-				public boolean hasNext() { 
-					expurgeNow();
-					return iter.hasNext();
-				}
-				public Entry<K,V> next() {
-					Entry<K, Value<K,V>> entry = iter.next();
-					if (entry==null) throw new ConcurrentModificationException();
-					Value<K,V> value = entry.getValue();
-					if (value==null) throw new ConcurrentModificationException();
-					return value;
-				}
-				public void remove() {
-					iter.remove();
-				}
-			};
-		}
-
-		/**
-		 * {@inheritDoc}
-		 * 
-		 * @return {@inheritDoc}
-		 */
-		@Override
-		public int size() {
-			expurgeNow();
-			return this.baseSet.size();
-		}
-		
-	}
-
-	/**
-	 * @author St&eacute;phane GALLAND &lt;galland@xxxxxxxxxxx&gt;
-	 * @version $Name:  $ $Revision: 1.1 $ $Date: 2007-02-20 08:52:37 $
-	 */
-	private static class Value<K,V> extends WeakReference<V> implements Entry<K,V> {
-		
 		private final K k;
 
 		/**

Modified: trunk/pom.xml
===================================================================
--- trunk/pom.xml	2009-02-02 20:41:14 UTC (rev 26)
+++ trunk/pom.xml	2009-02-02 20:42:49 UTC (rev 27)
@@ -18,7 +18,7 @@
 	<properties>
 		<version_myjdk>1.6</version_myjdk>
 		<version_arakhnelogger>1.1-SNAPSHOT</version_arakhnelogger>
-		<version_arakhnerefs>3.0-SNAPSHOT</version_arakhnerefs>
+		<version_arakhnerefs>4.0-SNAPSHOT</version_arakhnerefs>
 		<version_arakhnevmutils>2.1-SNAPSHOT</version_arakhnevmutils>
 	</properties>
 
@@ -34,6 +34,11 @@
 				<artifactId>maven-enforcer-plugin</artifactId>
 				<version>1.0-alpha-4</version>
 			</dependency>    
+			<dependency>
+				<groupId>junit</groupId>
+				<artifactId>junit</artifactId>
+				<version>[3.8,4.0)</version>
+			</dependency>    
 		</dependencies>
 	</dependencyManagement>
 
@@ -133,7 +138,6 @@
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-compiler-plugin</artifactId>
-				<version>2.0.2</version>
 				<configuration>
 					<source>${version_myjdk}</source>
 					<target>${version_myjdk}</target>
@@ -142,7 +146,6 @@
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-scm-plugin</artifactId>
-				<version>1.0</version>
 				<configuration>
 					<goals>install</goals>
 				</configuration>
@@ -150,12 +153,10 @@
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-site-plugin</artifactId>
-				<version>2.0-beta-7</version>
 			</plugin>		
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>
 				<artifactId>maven-deploy-plugin</artifactId>
-				<version>2.3</version>
 			</plugin>
 			<plugin>
 				<groupId>org.apache.maven.plugins</groupId>


Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/