// Copyright (c) 2006 Dustin Sallings <dustin@spy.net> package net.spy.cache; import java.lang.ref.Reference; import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import net.spy.SpyObject; /** * A simple time-based cache. */ public class SimpleCache extends SpyObject { private static SimpleCache instance=null; private final ConcurrentMap<String, Object> storage= new ConcurrentHashMap<String, Object>(); private final Timer timer=new Timer("SimpleCacheTimer", true); /** * Get an instance of SimpleCache. */ protected SimpleCache() { super(); } /** * Get the singleton SimpleCache instance. */ public static synchronized SimpleCache getInstance() { if(instance == null) { instance=new SimpleCache(); } return instance; } /** * Set the singleton SimpleCache instance. * This also cleanly shuts down the previous instance. */ public static synchronized void setInstance(SimpleCache to) { if(instance != null) { instance.timer.cancel(); } instance=to; } /** * Get an object from the cache. * If the stored object is a reference, it'll be dereferenced before * returned. * * @param key the cache key * @return the cached object */ public Object get(String key) { Object rv=storage.get(key); if(rv != null && rv instanceof Reference) { Reference<?> ref=(Reference<?>)rv; rv=ref.get(); if(rv == null) { storage.remove(key, ref); } } return rv; } /** * Store an object in the cache. * * @param key the cache key * @param timeout how long until it's deleted * @param value the value to cache */ public void store(String key, Object value, long timeout) { storage.put(key, value); if(timeout != Long.MAX_VALUE) { ClearTimer c=new ClearTimer(key, value); timer.schedule(c, timeout); } } /** * Remove an object from the cache. * * @param key the key of the object to remove * @return the previous object under this key (null if there wasn't one) */ public Object remove(String key) { return storage.remove(key); } /** * Conditionally remove an object from the cache. The object will only * be removed if the value is equal to the specified value. * * @param key the key * @param value the value * @return true if a value was removed */ public boolean remove(String key, Object value) { return storage.remove(key, value); } // timer that fires to clear stuff private static class ClearTimer extends TimerTask { private final String key; private final Object value; public ClearTimer(String k, Object v) { super(); key=k; value=v; } @Override public void run() { SimpleCache.getInstance().remove(key, value); } } }