// Copyright (c) 2005 Dustin Sallings <dustin@spy.net>
package net.spy.factory;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import net.spy.SpyObject;
/**
* An implementation of Storage that is backed by a HashMap.
*
* This implementation will find any public methods on the given objects
* containing a CacheKey annotation, or any fields with any visibility declared
* only within the classes of the given objects and use them as cache hints.
*/
public class MemStorageImpl<T> extends SpyObject implements Storage<T> {
private Collection<T> allObjects;
private final Map<String, Map<Object, T>> singleCache;
private final Map<String, Map<Object, List<T>>> multiCache;
/**
* Get an instance of HashCacheEntry.
*/
public MemStorageImpl(Collection<T> obs) {
super();
allObjects=Collections.unmodifiableCollection(obs);
singleCache=new HashMap<String, Map<Object, T>>();
multiCache=new HashMap<String, Map<Object,List<T>>>();
index();
}
private void storeEntry(CacheKey ck, Object key, T val) {
if(key != null) {
String name=ck.name();
switch(ck.type()) {
case SINGLE:
Map<Object, T> sm=singleCache.get(name);
if(sm == null) {
sm=new HashMap<Object, T>();
singleCache.put(name, sm);
}
sm.put(key, val);
break;
case MULTI:
Map<Object, List<T>> mm=multiCache.get(name);
if(mm == null) {
mm=new HashMap<Object, List<T>>();
multiCache.put(name, mm);
}
List<T> l=mm.get(key);
if(l == null) {
l=new ArrayList<T>();
mm.put(key, l);
}
l.add(val);
break;
}
}
}
private void index() {
for(T i : allObjects) {
try {
internalCacheInstance(i);
} catch(Exception e) {
throw new RuntimeException("Problem indexing at " + i, e);
}
}
}
/* (non-Javadoc)
* @see net.spy.factory.Storage#cacheInstance(T)
*/
public void cacheInstance(T i) throws Exception {
internalCacheInstance(i);
if(!allObjects.contains(i)) {
Collection<T> newAll=new ArrayList<T>(allObjects);
newAll.add(i);
allObjects=Collections.unmodifiableCollection(newAll);
}
}
private void internalCacheInstance(T i) throws Exception {
CacheKeyFinder ckf=CacheKeyFinder.getInstance();
Map<CacheKey,CacheKeyFinder.Accessor<?>> m=
ckf.getCacheKeys(i.getClass());
for(Map.Entry<CacheKey, CacheKeyFinder.Accessor<?>> me : m.entrySet()) {
storeEntry(me.getKey(), me.getValue().get(i), i);
}
}
/* (non-Javadoc)
* @see net.spy.factory.Storage#getAllObjects()
*/
public Collection<T> getAllObjects() {
return allObjects;
}
/* (non-Javadoc)
* @see net.spy.factory.Storage#getObject(java.lang.String, java.lang.Object)
*/
public T getObject(String cacheName, Object key) {
T rv=null;
Map<Object, T>ccache=singleCache.get(cacheName);
if(ccache != null) {
rv=ccache.get(key);
}
return rv;
}
/* (non-Javadoc)
* @see net.spy.factory.Storage#getObjects(java.lang.String, java.lang.Object)
*/
public Collection<T> getObjects(String cacheName, Object key) {
Collection<T> rv=null;
Map<Object, List<T>> m=multiCache.get(cacheName);
if(m != null) {
rv=m.get(key);
}
if(rv == null) {
rv=Collections.emptyList();
}
return rv;
}
}