package jfun.yan.xml;
import jfun.yan.Binder;
import jfun.yan.Component;
import jfun.yan.Components;
import jfun.yan.Creator;
import jfun.yan.LazyComponent;
abstract class Thunk implements Closure {
private Object obj = null;
private boolean entered = false;
private final Object key;
private final Location loc;
public Thunk(Object name, Location loc) {
this.loc = loc;
this.key = name;
}
public synchronized Object get() {
if(entered){
//reentry. do lazy.
return lazy();
}
if(obj==null){
entered = true;
try{
obj = evaluate();
}
finally{
entered = false;
}
}
return obj;
}
abstract Object evaluate();
private Component getLazyComponent(){
return Components.fromLazy(new LazyComponent(){
public Component eval(){
final Object c = get();
if(c instanceof Component){
return (Component)c;
}
else{
throw new ConfigurationException("Component expected, "
+ NutsUtils.getTypeName(c) + " encountered", loc);
}
}
public Class getType(){
return null;
}
}, key);
}
private Binder getLazyBinder(){
return new Binder(){
public Creator bind(Object v) throws Throwable {
final Object b = get();
if(b instanceof Binder){
return ((Binder)b).bind(v);
}
else{
throw new ConfigurationException("Binder expected, "
+ NutsUtils.getTypeName(b) + " encountered", loc);
}
}
};
}
private final Object lazy(){
final Class type = getType();
if(Component.class.isAssignableFrom(type)){
//do lazy Component.
return getLazyComponent();
}
else if(Binder.class.isAssignableFrom(type)){
return getLazyBinder();
}
else{
throw new ConfigurationException(
"recursive dependency for "+key, loc);
}
}
}