diff --git a/src/java/org/apache/commons/collections/ReferenceMap.java b/src/java/org/apache/commons/collections/ReferenceMap.java index 2580ad164..97c1eec1c 100644 --- a/src/java/org/apache/commons/collections/ReferenceMap.java +++ b/src/java/org/apache/commons/collections/ReferenceMap.java @@ -1,5 +1,5 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/ReferenceMap.java,v 1.10 2003/05/06 11:19:26 rdonkin Exp $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/java/org/apache/commons/collections/ReferenceMap.java,v 1.11 2003/05/07 09:18:57 rdonkin Exp $ * ==================================================================== * * The Apache Software License, Version 1.1 @@ -116,7 +116,7 @@ import java.util.Set; * @see java.lang.ref.Reference * * @since Commons Collections 2.1 - * @version $Revision: 1.10 $ $Date: 2003/05/06 11:19:26 $ + * @version $Revision: 1.11 $ $Date: 2003/05/07 09:18:57 $ * * @author Paul Jack */ @@ -175,6 +175,11 @@ public class ReferenceMap extends AbstractMap { * @serial */ private float loadFactor; + + /** + * Should the value be automatically purged when the associated key has been collected? + */ + private boolean purgeValues = false; // -- Non-serialized instance variables @@ -237,6 +242,21 @@ public class ReferenceMap extends AbstractMap { this(HARD, SOFT); } + /** + * Constructs a new ReferenceMap that will + * use the specified types of references. + * + * @param keyType the type of reference to use for keys; + * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK} + * @param valueType the type of reference to use for values; + * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK} + * @param purgeValues should the value be automatically purged when the + * key is garbage collected + */ + public ReferenceMap(int keyType, int valueType, boolean purgeValues) { + this(keyType, valueType); + this.purgeValues = purgeValues; + } /** * Constructs a new ReferenceMap that will @@ -251,6 +271,29 @@ public class ReferenceMap extends AbstractMap { this(keyType, valueType, 16, 0.75f); } + /** + * Constructs a new ReferenceMap with the + * specified reference types, load factor and initial + * capacity. + * + * @param keyType the type of reference to use for keys; + * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK} + * @param valueType the type of reference to use for values; + * must be {@link #HARD}, {@link #SOFT}, {@link #WEAK} + * @param capacity the initial capacity for the map + * @param loadFactor the load factor for the map + * @param purgeValues should the value be automatically purged when the + * key is garbage collected + */ + public ReferenceMap( + int keyType, + int valueType, + int capacity, + float loadFactor, + boolean purgeValues) { + this(keyType, valueType, capacity, loadFactor); + this.purgeValues = purgeValues; + } /** * Constructs a new ReferenceMap with the @@ -778,7 +821,11 @@ public class ReferenceMap extends AbstractMap { r = r || ((valueType > HARD) && (value == ref)); if (r) { if (keyType > HARD) ((Reference)key).clear(); - if (valueType > HARD) ((Reference)value).clear(); + if (valueType > HARD) { + ((Reference)value).clear(); + } else if (purgeValues) { + value = null; + } } return r; } diff --git a/src/test/org/apache/commons/collections/TestReferenceMap.java b/src/test/org/apache/commons/collections/TestReferenceMap.java index c82119cb0..f194eea90 100644 --- a/src/test/org/apache/commons/collections/TestReferenceMap.java +++ b/src/test/org/apache/commons/collections/TestReferenceMap.java @@ -1,7 +1,7 @@ /* - * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/TestReferenceMap.java,v 1.7 2003/05/06 11:19:26 rdonkin Exp $ - * $Revision: 1.7 $ - * $Date: 2003/05/06 11:19:26 $ + * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//collections/src/test/org/apache/commons/collections/TestReferenceMap.java,v 1.8 2003/05/07 09:18:58 rdonkin Exp $ + * $Revision: 1.8 $ + * $Date: 2003/05/07 09:18:58 $ * * ==================================================================== * @@ -61,6 +61,8 @@ package org.apache.commons.collections; +import java.lang.ref.WeakReference; + import java.util.Map; import junit.framework.Test; @@ -70,7 +72,7 @@ import junit.framework.Test; * Tests for ReferenceMap. * * @author Paul Jack - * @version $Id: TestReferenceMap.java,v 1.7 2003/05/06 11:19:26 rdonkin Exp $ + * @version $Id: TestReferenceMap.java,v 1.8 2003/05/07 09:18:58 rdonkin Exp $ */ public class TestReferenceMap extends TestMap { @@ -186,5 +188,44 @@ public class TestReferenceMap extends TestMap { return "2.1"; } - + /** Tests whether purge values setting works */ + public void testPurgeValues() throws Exception { + // many thanks to Juozas Baliuka for suggesting this method + Object key = new Object(); + Object value = new Object(); + + WeakReference keyReference = new WeakReference(key); + WeakReference valueReference = new WeakReference(value); + + Map testMap = new ReferenceMap(ReferenceMap.WEAK, ReferenceMap.HARD, true); + testMap.put(key, value); + + assertEquals("In map", value, testMap.get(key)); + assertNotNull("Weak reference released early (1)", keyReference.get()); + assertNotNull("Weak reference released early (2)", valueReference.get()); + + // dereference strong references + key = null; + value = null; + + int iterations = 0; + int bytz = 2; + while(true) { + System.gc(); + if(iterations++ > 50){ + fail("Max iterations reached before resource released."); + } + testMap.isEmpty(); + if( + keyReference.get() == null && + valueReference.get() == null) { + break; + + } else { + // create garbage: + byte[] b = new byte[bytz]; + bytz = bytz * 2; + } + } + } }