Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

time based cache (See related posts)

A simple time based cache build around a map store.

import java.util.Map;
import java.util.WeakHashMap;

/**
 * Simple time-based cache.
 */
public class SimpleCache {
	private long maxAge;
	private Map store;

	/**
	 * Instanciate a cache with max age of 1 hour and a WeakHashMap as store.
	 * @see java.util.WeakHashMap
	 */
	public SimpleCache() {
		this.maxAge = 1000 * 60 * 60;
		this.store = new WeakHashMap();
	}
	
	/**
	 * @param maxAge maximum age of an entry in milliseconds
	 * @param store map to hold entries
	 */
	public SimpleCache(long maxAge, Map store) {
		this.maxAge = maxAge;
		this.store = store;
	}
	
	/**
	 * Cache an object.
	 * @param key unique identifier to retrieve object
	 * @param value object to cache
	 */
	public void put(Object key, Object value) {
		store.put(key, new Item(value));
	}
	
	/**
	 * Fetch an object.
	 * @param key unique identifier to retrieve object
	 * @return an object or null in case it isn't stored or it expired
	 */
	public Object get(Object key) {
		Item item = getItem(key);
		return item == null ? null : item.payload;
	}
	
	/**
	 * Fetch an object or store and return output of callback.
	 * @param key unique identifier to retrieve object
	 * @param block code executed when object not in cache
	 * @return an object
	 */
	public synchronized Object get(Object key, Callback block) {
		Item item = getItem(key);
		if (item == null) {
			Object value = block.execute();
			item = new Item(value);
			store.put(key, item);
		}
		return item.payload;
	}
	
	/**
	 * Remove an object from cache.
	 * @param key unique identifier to retrieve object
	 */
	public void remove(Object key) {
		store.remove(key);
	}
	
	/**
	 * Get an item, if it expired remove it from cache and return null.
	 * @param key unique identifier to retrieve object
	 * @return an item or null
	 */
	private Item getItem(Object key) {
		Item item = (Item) store.get(key);
		if (item == null) {
			return null;
		}
		if (System.currentTimeMillis() - item.birth > maxAge) {
			store.remove(key);
			return null;
		}
		return item;		
	}

	/**
	 * Value container.
	 */
	private static class Item {
		long birth;
		Object payload;
		Item(Object payload) {
			this.birth = System.currentTimeMillis();
			this.payload = payload;
		}
	}
	
	/**
	 * A visitor interface.
	 */
	public static interface Callback {
		Object execute();
	}
}


And a couple of junit tests:

import java.util.HashMap;

import junit.framework.TestCase;

public class SimpleCacheTest extends TestCase {
	public void testPutGet () {
		SimpleCache c = new SimpleCache(Long.MAX_VALUE, new HashMap());
		c.put("key1", "value1");
		assertEquals("value1", c.get("key1"));
		c.put("key1", "value1.0");
		assertEquals("value1.0", c.get("key1"));
		c.put("key2", "value2");
		assertEquals("value2", c.get("key2"));
		assertEquals("value1.0", c.get("key1"));
	}
	
	public void testMaxAge () throws InterruptedException {
		SimpleCache c = new SimpleCache(1000, new HashMap());
		c.put("key1", "value1");
		assertEquals("value1", c.get("key1"));
		Thread.sleep(1500);
		assertNull(c.get("key1"));
		
		c.put("key2", "value2");
		Thread.sleep(750);
		c.put("key3", "value3");
		Thread.sleep(750);
		assertNull(c.get("key2"));
		assertNotNull(c.get("key3"));
		Thread.sleep(750);
		assertNull(c.get("key3"));
	}
	
	public void testRemove () {
		SimpleCache c = new SimpleCache(Long.MAX_VALUE, new HashMap());
		c.remove("key");
		assertNull(c.get("key"));
		c.put("key", "value");
		assertNotNull(c.get("key"));
		c.remove("key");
		assertNull(c.get("key"));
	}
	
	public void testCallBack () {
		SimpleCache c = new SimpleCache(Long.MAX_VALUE, new HashMap());
		assertEquals("value1", c.get("key1", new SimpleCache.Callback() {
			public Object execute() {
				return "value1";
			}
		}));
		assertEquals("value1", c.get("key1"));
		
		// again with a new callback (value)
		c.get("key1", new SimpleCache.Callback() {
			public Object execute() {
				return "value2";
			}
		});
		assertEquals("value1", c.get("key1"));
	}
}

Comments on this post

llucifer posts on Oct 12, 2006 at 10:32
Consider instead of using System.currentTimeMillis() using a TimeStampProvider interface. For the unit test one can set the time manually instead of waiting.

You need to create an account or log in to post comments to this site.


Click here to browse all 4863 code snippets

Related Posts