Time Based Cache
Join the DZone community and get the full member experience.
Join For FreeA 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"));
}
}
Cache (computing)
Opinions expressed by DZone contributors are their own.
Comments