// Copyright (c) 2005 Dustin Sallings <dustin@spy.net>
package net.spy.factory;
import java.util.Collection;
import java.util.TimerTask;
import net.spy.SpyObject;
import net.spy.cache.SimpleCache;
/**
* Base implementation of a generic object instance cache for objects
* collections suitable of being stored completely in memory.
*/
public abstract class GenFactoryImpl<T> extends SpyObject
implements GenFactory<T> {
private final String cacheKey;
private final long cacheTime;
private long lastRefresh=0;
private TimerTask nextRefresh=null;
/**
* Get an instance of GenFactory.
* @param key the cache key to use
* @param time the refresh duration of the cache
*/
protected GenFactoryImpl(String key, long time) {
super();
if(key == null) {
throw new NullPointerException("Cache key must not be null.");
}
if(time < 1) {
throw new IllegalArgumentException("Invalid cache time: " + time);
}
cacheKey=key;
cacheTime=time;
}
/**
* Get the cache for this factory.
*
* If the cache does not exist, getNewCacheEntry() will be called to get an
* uninitialized CacheEntry instance, and getInstances() will be called to
* get a collection of instances to populate the cache.
*
* @return a CacheEntry
*/
protected Storage<T> getCache() {
SimpleCache sc=SimpleCache.getInstance();
@SuppressWarnings("unchecked")
Storage<T> rv=(Storage)sc.get(cacheKey);
if(rv == null) {
rv=setCache();
}
return(rv);
}
/**
* Get a new Storage over the given collection.
*/
protected Storage<T> getNewCacheEntry(Collection<T> c) {
return new MemStorageImpl<T>(c);
}
// Set the cache
private Storage<T> setCache() {
Storage<T> rv=getNewCacheEntry(getInstances());
lastRefresh=System.currentTimeMillis();
SimpleCache sc=SimpleCache.getInstance();
sc.store(cacheKey, rv, cacheTime);
return(rv);
}
/**
* Store or update an individual object in the cache.
*
* @param i the object to store
* @throws Exception if the cache cannot be updated with this instance
*/
protected void cacheInstance(T i) throws Exception {
getCache().cacheInstance(i);
}
/**
* Get the collection of all Instance objects to be cached.
*/
protected abstract Collection<T> getInstances();
/**
* This method is called whenever getObject(String,Object) would return
* null. The result of this object will be used instead. Alternatively,
* one may throw a RuntimeException indicating a failure.
*
* @param cacheName the name of the cache that was accessed
* @param key the key under that cache that was accessed
* @return null
*/
protected T handleNullLookup(String cacheName, Object key) {
return null;
}
/* (non-Javadoc)
* @see net.spy.factory.GenFactory#getObject(java.lang.String, java.lang.Object)
*/
public T getObject(String cacheName, Object key) {
Storage<T> ce=getCache();
T rv=ce.getObject(cacheName, key);
if(rv == null) {
rv=handleNullLookup(cacheName, key);
}
return(rv);
}
/* (non-Javadoc)
* @see net.spy.factory.GenFactory#getObject(int)
*/
public T getObject(int id) {
return getObject("id", id);
}
/* (non-Javadoc)
* @see net.spy.factory.GenFactory#getObjects(java.lang.String, java.lang.Object)
*/
public Collection<T> getObjects(String cacheName, Object key) {
Collection<T> rv=getCache().getObjects(cacheName, key);
assert rv != null;
return rv;
}
/* (non-Javadoc)
* @see net.spy.factory.GenFactory#getObjects()
*/
public Collection<T> getObjects() {
Storage<T> ce=getCache();
return(ce.getAllObjects());
}
/* (non-Javadoc)
* @see net.spy.factory.GenFactory#recache()
*/
public void recache() {
setCache();
}
/* (non-Javadoc)
* @see net.spy.factory.GenFactory#getLastRefresh()
*/
public long getLastRefresh() {
return lastRefresh;
}
/**
* Get the TimerTask scheduled to refresh this cache (if any).
*/
TimerTask getNextRefresh() {
return nextRefresh;
}
/**
* Set the TimerTask for the update
*/
void setNextRefresh(TimerTask next) {
nextRefresh = next;
}
}