Author: brentworden
Date: Fri Aug 24 05:08:36 2012
New Revision: 1376827

URL: http://svn.apache.org/viewvc?rev=1376827&view=rev
Log:
COLLECTIONS-241 added PassiveExpiringMap and tests

Added:
    
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/map/PassiveExpiringMap.java
   (with props)
    
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/map/TestPassiveExpiringMap.java

Added: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/map/PassiveExpiringMap.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/map/PassiveExpiringMap.java?rev=1376827&view=auto
==============================================================================
--- 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/map/PassiveExpiringMap.java
 (added)
+++ 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/map/PassiveExpiringMap.java
 Fri Aug 24 05:08:36 2012
@@ -0,0 +1,577 @@
+/*
+ * 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.commons.collections.map;
+
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.Serializable;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * Decorates a <code>Map</code> to evict expired entries once their expiration
+ * time has been reached.
+ * <p>
+ * When putting a key-value pair in the map this decorator uses a
+ * {@link ExpirationPolicy} to determine how long the entry should remain alive
+ * as defined by an expiration time value.
+ * </p>
+ * <p>
+ * When accessing the mapped value for a key, its expiration time is checked,
+ * and if it is a negative value or if it is greater than the current time, the
+ * mapped value is returned. Otherwise, the key is removed from the decorated
+ * map, and <code>null</code> is returned.
+ * </p>
+ * <p>
+ * When invoking methods that involve accessing the entire map contents (i.e
+ * {@link #containsKey(Object)}, {@link #entrySet()}, etc.) this decorator
+ * removes all expired entries prior to actually completing the invocation.
+ * </p>
+ * <p>
+ * <strong>Note that {@link PassiveExpiringMap} is not synchronized and is not
+ * thread-safe.</strong> If you wish to use this map from multiple threads
+ * concurrently, you must use appropriate synchronization. The simplest 
approach
+ * is to wrap this map using {@link 
java.util.Collections#synchronizedMap(Map)}.
+ * This class may throw exceptions when accessed by concurrent threads without
+ * synchronization.
+ * </p>
+ * 
+ * @param <K>
+ *            the type of the keys in the map
+ * 
+ * @param <V>
+ *            the type of the values in the map
+ * 
+ * @since 4.0
+ * @version $Id: $
+ */
+public class PassiveExpiringMap<K, V> extends AbstractMapDecorator<K, V>
+               implements Serializable {
+
+       /**
+        * A {@link ExpirationPolicy} that returns a expiration time that is a
+        * constant about of time in the future from the current time.
+        * 
+        * @param <K>
+        *            the type of the keys in the map
+        * @param <V>
+        *            the type of the values in the map
+        * 
+        * @since 4.0
+        * @version $Id: $
+        */
+       public static class ConstantTimeToLiveExpirationPolicy<K, V> implements
+                       ExpirationPolicy<K, V> {
+
+               /** Serialization version */
+               private static final long serialVersionUID = 1L;
+
+               /** the constant time-to-live value measured in milliseconds. */
+               private final long timeToLiveMillis;
+
+               /**
+                * Default constructor. Constructs a policy using a negative
+                * time-to-live value that results in entries never expiring.
+                */
+               public ConstantTimeToLiveExpirationPolicy() {
+                       this(-1L);
+               }
+
+               /**
+                * Construct a policy with the given time-to-live constant 
measured in
+                * milliseconds. A negative time-to-live value indicates 
entries never
+                * expire. A zero time-to-live value indicates entries expire 
(nearly)
+                * immediately.
+                * 
+                * @param timeToLiveMillis
+                *            the constant amount of time (in milliseconds) an 
entry is
+                *            available before it expires. A negative value 
results in
+                *            entries that NEVER expire. A zero value results 
in entries
+                *            that ALWAYS expire.
+                */
+               public ConstantTimeToLiveExpirationPolicy(long 
timeToLiveMillis) {
+                       super();
+                       this.timeToLiveMillis = timeToLiveMillis;
+               }
+
+               /**
+                * Construct a policy with the given time-to-live constant 
measured in
+                * the given time unit of measure.
+                * 
+                * @param timeToLive
+                *            the constant amount of time an entry is available 
before
+                *            it expires. A negative value results in entries 
that NEVER
+                *            expire. A zero value results in entries that 
ALWAYS
+                *            expire.
+                * @param timeUnit
+                *            the unit of time for the <code>timeToLive</code>
+                *            parameter, must not be null.
+                * @throws IllegalArgumentException
+                *             if the time unit is null.
+                */
+               public ConstantTimeToLiveExpirationPolicy(long timeToLive,
+                               TimeUnit timeUnit) {
+                       this(validateAndConvertToMillis(timeToLive, 
TimeUnit.MILLISECONDS));
+               }
+
+               /**
+                * Determine the expiration time for the given key-value entry.
+                * 
+                * @param key
+                *            the key for the entry (ignored).
+                * @param value
+                *            the value for the entry (ignored).
+                * @return if {@link #timeToLiveMillis} &ge; 0, an expiration 
time of
+                *         {@link #timeToLiveMillis} +
+                *         {@link System#currentTimeMillis()} is returned. 
Otherwise, -1
+                *         is returned indicating the entry never expires.
+                */
+               public long expirationTime(K key, V value) {
+                       if (timeToLiveMillis >= 0L) {
+                               // avoid numerical overflow
+                               long now = System.currentTimeMillis();
+                               if (now > Long.MAX_VALUE - timeToLiveMillis) {
+                                       // expiration would be greater than 
Long.MAX_VALUE
+                                       // never expire
+                                       return -1;
+                               }
+
+                               // timeToLiveMillis in the future
+                               return now + timeToLiveMillis;
+                       }
+                       
+                       // never expire
+                       return -1L;
+               }
+       }
+
+       /**
+        * A policy to determine the expiration time for key-value entries.
+        * 
+        * @param <K>
+        *            the key object type.
+        * @param <V>
+        *            the value object type
+        * 
+        * @since 4.0
+        * @version $Id: $
+        */
+       public static interface ExpirationPolicy<K, V> extends Serializable {
+               /**
+                * Determine the expiration time for the given key-value entry.
+                * 
+                * @param key
+                *            the key for the entry.
+                * @param value
+                *            the value for the entry.
+                * @return the expiration time value measured in milliseconds. A
+                *         negative return value indicates the entry never 
expires.
+                */
+               long expirationTime(K key, V value);
+       }
+
+       /** Serialization version */
+       private static final long serialVersionUID = 1L;
+
+       /**
+        * First validate the input parameters. If the parameters are valid, 
convert
+        * the given time measured in the given units to the same time measured 
in
+        * milliseconds. If the parameters are invalid, an
+        * {@link IllegalArgumentException} is thrown.
+        * 
+        * @param timeToLive
+        *            the constant amount of time an entry is available before 
it
+        *            expires. A negative value results in entries that NEVER
+        *            expire. A zero value results in entries that ALWAYS 
expire.
+        * @param timeUnit
+        *            the unit of time for the <code>timeToLive</code> 
parameter,
+        *            must not be null.
+        * @throws IllegalArgumentException
+        *             if the time unit is null.
+        */
+       private static long validateAndConvertToMillis(long timeToLive,
+                       TimeUnit timeUnit) {
+               if (timeUnit == null) {
+                       throw new IllegalArgumentException("Time unit must not 
be null");
+               }
+               return timeUnit.convert(timeToLive, TimeUnit.MILLISECONDS);
+       }
+
+       /** map used to manage expiration times for the actual map entries. */
+       private final Map<Object, Long> expirationMap = new HashMap<Object, 
Long>();
+
+       /** the policy used to determine time-to-live values for map entries. */
+       private final ExpirationPolicy<K, V> expiringPolicy;
+
+       /**
+        * Default constructor. Constructs a map decorator that results in 
entries
+        * NEVER expiring.
+        */
+       public PassiveExpiringMap() {
+               this(-1L);
+       }
+
+       /**
+        * Construct a map decorator using the given expiration policy to 
determine
+        * expiration times.
+        * 
+        * @param expiringPolicy
+        *            the policy used to determine expiration times of entries 
as
+        *            they are added.
+        */
+       public PassiveExpiringMap(ExpirationPolicy<K, V> expiringPolicy) {
+               this(expiringPolicy, new HashMap<K, V>());
+       }
+
+       /**
+        * Construct a map decorator that decorates the given map and uses the 
given
+        * expiration policy to determine expiration times. If there are any
+        * elements already in the map being decorated, they will NEVER expire
+        * unless they are replaced.
+        * 
+        * @param expiringPolicy
+        *            the policy used to determine expiration times of entries 
as
+        *            they are added.
+        * @param map
+        *            the map to decorate, must not be null.
+        * @throws IllegalArgumentException
+        *             if the map is null.
+        */
+       public PassiveExpiringMap(ExpirationPolicy<K, V> expiringPolicy,
+                       Map<K, V> map) {
+               super(map);
+               if (expiringPolicy == null) {
+                       throw new IllegalArgumentException("Policy must not be 
null.");
+               }
+               this.expiringPolicy = expiringPolicy;
+       }
+
+       /**
+        * Construct a map decorator that decorates the given map using the 
given
+        * time-to-live value measured in milliseconds to create and use a
+        * {@link ConstantTimeToLiveExpirationPolicy} expiration policy.
+        * 
+        * @param timeToLiveMillis
+        *            the constant amount of time (in milliseconds) an entry is
+        *            available before it expires. A negative value results in
+        *            entries that NEVER expire. A zero value results in entries
+        *            that ALWAYS expire.
+        */
+       public PassiveExpiringMap(long timeToLiveMillis) {
+               this(new ConstantTimeToLiveExpirationPolicy<K, 
V>(timeToLiveMillis),
+                               new HashMap<K, V>());
+       }
+
+       /**
+        * Construct a map decorator using the given time-to-live value 
measured in
+        * milliseconds to create and use a
+        * {@link ConstantTimeToLiveExpirationPolicy} expiration policy. If 
there
+        * are any elements already in the map being decorated, they will NEVER
+        * expire unless they are replaced.
+        * 
+        * @param timeToLiveMillis
+        *            the constant amount of time (in milliseconds) an entry is
+        *            available before it expires. A negative value results in
+        *            entries that NEVER expire. A zero value results in entries
+        *            that ALWAYS expire.
+        * @param map
+        *            the map to decorate, must not be null.
+        * @throws IllegalArgumentException
+        *             if the map is null.
+        */
+       public PassiveExpiringMap(long timeToLiveMillis, Map<K, V> map) {
+               this(new ConstantTimeToLiveExpirationPolicy<K, 
V>(timeToLiveMillis),
+                               map);
+       }
+
+       /**
+        * Construct a map decorator using the given time-to-live value 
measured in
+        * the given time units of measure to create and use a
+        * {@link ConstantTimeToLiveExpirationPolicy} expiration policy.
+        * 
+        * @param timeToLive
+        *            the constant amount of time an entry is available before 
it
+        *            expires. A negative value results in entries that NEVER
+        *            expire. A zero value results in entries that ALWAYS 
expire.
+        * @param timeUnit
+        *            the unit of time for the <code>timeToLive</code> 
parameter,
+        *            must not be null.
+        * @throws IllegalArgumentException
+        *             if the time unit is null.
+        */
+       public PassiveExpiringMap(long timeToLive, TimeUnit timeUnit) {
+               this(validateAndConvertToMillis(timeToLive, timeUnit));
+       }
+
+       /**
+        * Construct a map decorator that decorates the given map using the 
given
+        * time-to-live value measured in the given time units of measure to 
create
+        * {@link ConstantTimeToLiveExpirationPolicy} expiration policy. This 
policy
+        * is used to determine expiration times. If there are any elements 
already
+        * in the map being decorated, they will NEVER expire unless they are
+        * replaced.
+        * 
+        * @param timeToLive
+        *            the constant amount of time an entry is available before 
it
+        *            expires. A negative value results in entries that NEVER
+        *            expire. A zero value results in entries that ALWAYS 
expire.
+        * @param timeUnit
+        *            the unit of time for the <code>timeToLive</code> 
parameter,
+        *            must not be null.
+        * @throws IllegalArgumentException
+        *             if the time unit is null.
+        * @param map
+        *            the map to decorate, must not be null.
+        * @throws IllegalArgumentException
+        *             if the map is null.
+        */
+       public PassiveExpiringMap(long timeToLive, TimeUnit timeUnit, Map<K, V> 
map) {
+               this(validateAndConvertToMillis(timeToLive, timeUnit), map);
+       }
+
+       /**
+        * Constructs a map decorator that decorates the given map and results 
in
+        * entries NEVER expiring. If there are any elements already in the map
+        * being decorated, they also will NEVER expire.
+        * 
+        * @param map
+        *            the map to decorate, must not be null.
+        * @throws IllegalArgumentException
+        *             if the map is null.
+        */
+       public PassiveExpiringMap(Map<K, V> map) {
+               this(-1L, map);
+       }
+
+       /**
+        * Normal {@link Map#clear()} behavior with the addition of clearing all
+        * expiration entries as well.
+        */
+       @Override
+       public void clear() {
+               super.clear();
+               expirationMap.clear();
+       }
+
+       /**
+        * All expired entries are removed from the map prior to determining the
+        * contains result.
+        */
+       @Override
+       public boolean containsKey(Object key) {
+               removeIfExpired(key, now());
+               return super.containsKey(key);
+       }
+
+       /**
+        * All expired entries are removed from the map prior to determining the
+        * contains result.
+        */
+       @Override
+       public boolean containsValue(Object value) {
+               removeAllExpired(now());
+               return super.containsValue(value);
+       }
+
+       /**
+        * All expired entries are removed from the map prior to returning the 
entry
+        * set.
+        */
+       @Override
+       public Set<Entry<K, V>> entrySet() {
+               removeAllExpired(now());
+               return super.entrySet();
+       }
+
+       /**
+        * All expired entries are removed from the map prior to returning the 
entry
+        * value.
+        */
+       @Override
+       public V get(Object key) {
+               removeIfExpired(key, now());
+               return super.get(key);
+       }
+
+       /**
+        * All expired entries are removed from the map prior to determining if 
it
+        * is empty.
+        */
+       @Override
+       public boolean isEmpty() {
+               removeAllExpired(now());
+               return super.isEmpty();
+       }
+
+       /**
+        * Determines if the given expiration time is less than <code>now</code>
+        * 
+        * @param now
+        *            the time in milliseconds used to compare against the
+        *            expiration time.
+        * @param expirationTimeObject
+        *            the expiration time value retrieved from
+        *            {@link #expirationMap}, can be null.
+        * @return <code>true</code> if <code>expirationTimeObject</code> is 
&ge; 0
+        *         and <code>expirationTimeObject</code> &lt; <code>now</code>.
+        *         <code>false</code> otherwise.
+        */
+       private boolean isExpired(long now, Long expirationTimeObject) {
+               if (expirationTimeObject != null) {
+                       long expirationTime = expirationTimeObject.longValue();
+                       return (expirationTime >= 0 && now >= expirationTime);
+               }
+               return false;
+       }
+
+       /**
+        * All expired entries are removed from the map prior to returning the 
key
+        * set.
+        */
+       @Override
+       public Set<K> keySet() {
+               removeAllExpired(now());
+               return super.keySet();
+       }
+
+       /**
+        * The current time in milliseconds.
+        */
+       private long now() {
+               return System.currentTimeMillis();
+       }
+
+       @Override
+       public V put(K key, V value) {
+               return put(key, value, now());
+       }
+
+       /**
+        * Add the given key-value pair to this map as well as recording the 
entry's
+        * expiration time based on the current time in milliseconds,
+        * <code>now</code> and this map's {@link #expiringPolicy}.
+        */
+       private V put(K key, V value, long now) {
+               // record expiration time of new entry
+               long expirationTime = expiringPolicy.expirationTime(key, value);
+               expirationMap.put(key, Long.valueOf(expirationTime));
+
+               return super.put(key, value);
+       }
+
+       @Override
+       public void putAll(Map<? extends K, ? extends V> mapToCopy) {
+               for (Map.Entry<? extends K, ? extends V> entry : 
mapToCopy.entrySet()) {
+                       put(entry.getKey(), entry.getValue());
+               }
+       }
+
+       /**
+        * Normal {@link Map#remove(Object)} behavior with the addition of 
removing
+        * any expiration entry as well.
+        */
+       @Override
+       public V remove(Object key) {
+               expirationMap.remove(key);
+               return super.remove(key);
+       }
+
+       /**
+        * Removes all entries in the map whose expiration time is less than
+        * <code>now</code>. The exceptions are entries with negative expiration
+        * times; those entries are never removed.
+        * 
+        * @see #isExpired(long, Long)
+        */
+       private void removeAllExpired(long now) {
+               Iterator<Map.Entry<Object, Long>> iter = 
expirationMap.entrySet()
+                               .iterator();
+               while (iter.hasNext()) {
+                       Map.Entry<Object, Long> expirationEntry = iter.next();
+                       if (isExpired(now, expirationEntry.getValue())) {
+                               // remove entry from collection
+                               super.remove(expirationEntry.getKey());
+                               // remove entry from expiration map
+                               iter.remove();
+                       }
+               }
+       }
+
+       /**
+        * Removes the entry with the given key if the entry's expiration time 
is
+        * less than <code>now</code>. If the entry has a negative expiration 
time,
+        * the entry is never removed.
+        */
+       private void removeIfExpired(Object key, long now) {
+               Long expirationTimeObject = expirationMap.get(key);
+               if (isExpired(now, expirationTimeObject)) {
+                       remove(key);
+               }
+       }
+
+       /**
+        * All expired entries are removed from the map prior to returning the 
size.
+        */
+       @Override
+       public int size() {
+               removeAllExpired(now());
+               return super.size();
+       }
+
+       /**
+        * Read the map in using a custom routine.
+        * 
+        * @param in
+        *            the input stream
+        * @throws IOException
+        * @throws ClassNotFoundException
+        */
+       @SuppressWarnings("unchecked")
+       // (1) should only fail if input stream is incorrect
+       private void readObject(ObjectInputStream in) throws IOException,
+                       ClassNotFoundException {
+               in.defaultReadObject();
+               map = (Map<K, V>) in.readObject(); // (1)
+       }
+
+       /**
+        * Write the map out using a custom routine.
+        * 
+        * @param out
+        *            the output stream
+        * @throws IOException
+        */
+       private void writeObject(ObjectOutputStream out) throws IOException {
+               out.defaultWriteObject();
+               out.writeObject(map);
+       }
+
+       /**
+        * All expired entries are removed from the map prior to returning the 
value
+        * collection.
+        */
+       @Override
+       public Collection<V> values() {
+               removeAllExpired(now());
+               return super.values();
+       }
+}

Propchange: 
commons/proper/collections/trunk/src/main/java/org/apache/commons/collections/map/PassiveExpiringMap.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/map/TestPassiveExpiringMap.java
URL: 
http://svn.apache.org/viewvc/commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/map/TestPassiveExpiringMap.java?rev=1376827&view=auto
==============================================================================
--- 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/map/TestPassiveExpiringMap.java
 (added)
+++ 
commons/proper/collections/trunk/src/test/java/org/apache/commons/collections/map/TestPassiveExpiringMap.java
 Fri Aug 24 05:08:36 2012
@@ -0,0 +1,207 @@
+package org.apache.commons.collections.map;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import junit.framework.Test;
+
+import org.apache.commons.collections.BulkTest;
+import org.apache.commons.collections.map.PassiveExpiringMap.ExpirationPolicy;
+
+public class TestPassiveExpiringMap<K, V> extends AbstractTestMap<K, V> {
+
+       private static class TestExpirationPolicy implements
+                       ExpirationPolicy<Integer, String> {
+
+               private static final long serialVersionUID = 1L;
+
+               public long expirationTime(Integer key, String value) {
+                       // odd keys expire immediately, even keys never expire
+                       if (key == null) {
+                               return 0;
+                       }
+
+                       if (key.intValue() % 2 == 0) {
+                               return -1;
+                       }
+
+                       return 0;
+               }
+       }
+
+       public static Test suite() {
+               return BulkTest.makeSuite(TestPassiveExpiringMap.class);
+       }
+
+       public TestPassiveExpiringMap(String testName) {
+               super(testName);
+       }
+
+       // public void testCreate() throws Exception {
+       // writeExternalFormToDisk((java.io.Serializable) makeObject(),
+       // "PassiveExpiringMap.emptyCollection.version4.obj");
+       //
+       // writeExternalFormToDisk((java.io.Serializable) makeFullMap(),
+       // "PassiveExpiringMap.fullCollection.version4.obj");
+       // }
+
+       @Override
+       public String getCompatibilityVersion() {
+               return "4";
+       }
+
+       private Map<Integer, String> makeDecoratedTestMap() {
+               Map<Integer, String> m = new HashMap<Integer, String>();
+               m.put(Integer.valueOf(1), "one");
+               m.put(Integer.valueOf(2), "two");
+               m.put(Integer.valueOf(3), "three");
+               m.put(Integer.valueOf(4), "four");
+               m.put(Integer.valueOf(5), "five");
+               m.put(Integer.valueOf(6), "six");
+               return new PassiveExpiringMap<Integer, String>(
+                               new TestExpirationPolicy(), m);
+       }
+
+       @Override
+       public Map<K, V> makeObject() {
+               return new PassiveExpiringMap<K, V>();
+       }
+
+       private Map<Integer, String> makeTestMap() {
+               Map<Integer, String> m = new PassiveExpiringMap<Integer, 
String>(
+                               new TestExpirationPolicy());
+               m.put(Integer.valueOf(1), "one");
+               m.put(Integer.valueOf(2), "two");
+               m.put(Integer.valueOf(3), "three");
+               m.put(Integer.valueOf(4), "four");
+               m.put(Integer.valueOf(5), "five");
+               m.put(Integer.valueOf(6), "six");
+               return m;
+       }
+
+       public void testConstructors() {
+               try {
+                       Map<String, String> map = null;
+                       new PassiveExpiringMap<String, String>(map);
+                       fail("constructor - exception should have been 
thrown.");
+               } catch (IllegalArgumentException ex) {
+                       // success
+               }
+
+               try {
+                       ExpirationPolicy<String, String> policy = null;
+                       new PassiveExpiringMap<String, String>(policy);
+                       fail("constructor - exception should have been 
thrown.");
+               } catch (IllegalArgumentException ex) {
+                       // success
+               }
+
+               try {
+                       TimeUnit unit = null;
+                       new PassiveExpiringMap<String, String>(10L, unit);
+                       fail("constructor - exception should have been 
thrown.");
+               } catch (IllegalArgumentException ex) {
+                       // success
+               }
+       }
+
+       public void testContainsKey() {
+               Map<Integer, String> m = makeTestMap();
+               assertFalse(m.containsKey(Integer.valueOf(1)));
+               assertFalse(m.containsKey(Integer.valueOf(3)));
+               assertFalse(m.containsKey(Integer.valueOf(5)));
+               assertTrue(m.containsKey(Integer.valueOf(2)));
+               assertTrue(m.containsKey(Integer.valueOf(4)));
+               assertTrue(m.containsKey(Integer.valueOf(6)));
+       }
+
+       public void testContainsValue() {
+               Map<Integer, String> m = makeTestMap();
+               assertFalse(m.containsValue("one"));
+               assertFalse(m.containsValue("three"));
+               assertFalse(m.containsValue("five"));
+               assertTrue(m.containsValue("two"));
+               assertTrue(m.containsValue("four"));
+               assertTrue(m.containsValue("six"));
+       }
+
+       public void testDecoratedMap() {
+               // entries shouldn't expire
+               Map<Integer, String> m = makeDecoratedTestMap();
+               assertEquals(6, m.size());
+               assertEquals("one", m.get(Integer.valueOf(1)));
+
+               // removing a single item shouldn't affect any other items
+               assertEquals("two", m.get(Integer.valueOf(2)));
+               m.remove(Integer.valueOf(2));
+               assertEquals(5, m.size());
+               assertEquals("one", m.get(Integer.valueOf(1)));
+               assertNull(m.get(Integer.valueOf(2)));
+
+               // adding a single, even item shouldn't affect any other items
+               assertNull(m.get(Integer.valueOf(2)));
+               m.put(Integer.valueOf(2), "two");
+               assertEquals(6, m.size());
+               assertEquals("one", m.get(Integer.valueOf(1)));
+               assertEquals("two", m.get(Integer.valueOf(2)));
+
+               // adding a single, odd item (one that expires) shouldn't 
affect any
+               // other items
+               // put the entry expires immediately
+               m.put(Integer.valueOf(1), "one-one");
+               assertEquals(5, m.size());
+               assertNull(m.get(Integer.valueOf(1)));
+               assertEquals("two", m.get(Integer.valueOf(2)));
+       }
+
+       public void testEntrySet() {
+               Map<Integer, String> m = makeTestMap();
+               assertEquals(3, m.entrySet().size());
+       }
+
+       public void testGet() {
+               Map<Integer, String> m = makeTestMap();
+               assertNull(m.get(Integer.valueOf(1)));
+               assertEquals("two", m.get(Integer.valueOf(2)));
+               assertNull(m.get(Integer.valueOf(3)));
+               assertEquals("four", m.get(Integer.valueOf(4)));
+               assertNull(m.get(Integer.valueOf(5)));
+               assertEquals("six", m.get(Integer.valueOf(6)));
+       }
+
+       public void testIsEmpty() {
+               Map<Integer, String> m = makeTestMap();
+               assertFalse(m.isEmpty());
+
+               // remove just evens
+               m = makeTestMap();
+               m.remove(Integer.valueOf(2));
+               m.remove(Integer.valueOf(4));
+               m.remove(Integer.valueOf(6));
+               assertTrue(m.isEmpty());
+       }
+
+       public void testKeySet() {
+               Map<Integer, String> m = makeTestMap();
+               assertEquals(3, m.keySet().size());
+       }
+
+       public void testSize() {
+               Map<Integer, String> m = makeTestMap();
+               assertEquals(3, m.size());
+       }
+
+       public void testValues() {
+               Map<Integer, String> m = makeTestMap();
+               assertEquals(3, m.values().size());
+       }
+
+       public void testZeroTimeToLive() {
+               // item should not be available
+               PassiveExpiringMap<String, String> m = new 
PassiveExpiringMap<String, String>(
+                               0L);
+               m.put("a", "b");
+               assertNull(m.get("a"));
+       }
+}


Reply via email to