package jfun.yan.containers;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import jfun.yan.Component;
import jfun.yan.ComponentMap;
import jfun.yan.Registrar;
import jfun.yan.UnresolvedComponentException;
import jfun.yan.YanException;
import jfun.yan.factory.Factory;
/**
* An optimized container that's fast when it is used immutably.
* <p>
* The autowire by type is slow because it needs linear time.
* If the underlying container is not changing, we can optimize
* it by caching the result of each getComponentOfType(),
* getComponentsOfType() and containsType().
* thus each type is searched at most once.
* </p>
* <p>
* After getComponentOfType() is called, the same result will always
* be returned. Newly registered component or unregistered component
* will invalidate the cache and the subsequent lookup will perform
* the slow search again.
* </p>
* <p>
* This is typically not a problem anyway.
* </p>
* @author Ben Yu
* Nov 17, 2005 8:45:01 AM
*/
public class ImmutablePreferredContainer extends jfun.yan.containers.SimpleContainer {
private final HashMap typecache = new HashMap();
private final HashMap typescache = new HashMap();
private final HashMap boolcache = new HashMap();
public ImmutablePreferredContainer(Registrar reg) {
super(reg);
}
public synchronized <T> Component<T> getComponentOfType(Class<T> type) {
Component<T> c = (Component<T>)typecache.get(type);
if(c==null){
c = super.getComponentOfType(type);
if(c!=null){
typecache.put(type, c);
}
}
return c;
}
public synchronized boolean containsType(Class type) {
if(boolcache.containsKey(type))
return true;
if(typecache.containsKey(type))
return true;
if(typescache.containsKey(type)){
return true;
}
final boolean ret = super.containsType(type);
if(ret){
boolcache.put(type, Boolean.valueOf(true));
}
return ret;
}
public synchronized <T> List<Component<T>> getComponentsOfType(Class<T> type) {
List<Component<T>> ret = (List<Component<T>>)typescache.get(type);
if(ret==null){
final Component<T> c = (Component<T>)typecache.get(type);
if(c==null){
ret = super.getComponentsOfType(type);
}
else{
ret = new ArrayList<Component<T>>(1);
ret.add(c);
}
typescache.put(type, ret);
}
return ret;
}
private final HashMap type_factory_cache = new HashMap();
private final HashMap key_factory_cache = new HashMap();
public Factory getFactory(Object key, ComponentMap cmap) throws UnresolvedComponentException, YanException {
if(cmap == this){
return getFactory(key);
}
else return super.getFactory(key, cmap);
}
public synchronized Factory getFactory(Object key){
Factory result = (Factory)key_factory_cache.get(key);
if(result==null){
result = super.getFactory(key);
key_factory_cache.put(key, result);
}
return result;
}
public <T> Factory<T> getFactoryOfType(Class<T> type, ComponentMap cmap){
if(cmap==this){
return getFactoryOfType(type);
}
else return super.getFactoryOfType(type, cmap);
}
public synchronized <T> Factory<T> getFactoryOfType(Class<T> type){
Factory<T> result = (Factory<T>)type_factory_cache.get(type);
if(result==null){
result = super.getFactoryOfType(type);
type_factory_cache.put(type, result);
}
return result;
}
public Object getInstance(Object key, ComponentMap cmap) {
if(cmap==this){
return getInstance(key);
}
else return super.getInstance(key, cmap);
}
public Object getInstance(Object key) {
return getFactory(key).create();
}
public <T> T getInstanceOfType(Class<T> type, ComponentMap cmap) {
if(cmap==this){
return getInstanceOfType(type);
}
else return super.getInstanceOfType(type, cmap);
}
public <T> T getInstanceOfType(Class<T> type) {
return getFactoryOfType(type).create();
}
public void registerComponent(Object key, Component cc) {
clearCache();
super.registerComponent(key, cc);
}
public void unregisterComponent(Object key) {
clearCache();
super.unregisterComponent(key);
}
public void unregisterComponentsOfType(Class type) {
clearCache();
super.unregisterComponentsOfType(type);
}
private synchronized void clearCache(){
typecache.clear();
typescache.clear();
boolcache.clear();
key_factory_cache.clear();
type_factory_cache.clear();
}
}