package org.ripple.power.ioc.injector.attribute;
import java.util.Collection;
import java.util.Iterator;
import java.util.Map;
import org.ripple.power.ioc.injector.Bind;
import org.ripple.power.ioc.injector.BindInterceptor;
import org.ripple.power.ioc.injector.BindMediator;
import org.ripple.power.ioc.injector.ClassBind;
import org.ripple.power.ioc.injector.ClassBindImpl;
import org.ripple.power.ioc.injector.ComponentFactory;
import org.ripple.power.ioc.injector.Container;
import org.ripple.power.ioc.injector.Injector;
import org.ripple.power.ioc.injector.Interceptor;
import org.ripple.power.ioc.injector.Start;
import org.ripple.power.utils.CollectionUtils;
public abstract class AbstractContainer implements Container {
private Map<Object, Object> injectors = CollectionUtils.createMap();
private Map<Object, Object> binds = CollectionUtils.createMap();
private Interceptor interceptor = this.createInterceptor();
private boolean started;
private ComponentFactory factory;
public AbstractContainer(ComponentFactory factory) {
this.factory = factory;
}
public void inject(Object key, Object target) {
Injector injector = this.getInjector(key);
if (injector != null && target != null) {
injector.inject(this, target);
}
}
private Injector getInjector(Object key) {
return (Injector) this.injectors.get(key);
}
public Container addInjector(Object key, Injector injector) {
this.injectors.put(key, injector);
return this;
}
private Object getKey(Object key) {
Object rightKey = key;
Collection<Object> keys = CollectionUtils.createList();
if (!binds.containsKey(key) && key instanceof Class) {
for (Iterator<Object> it = binds.keySet().iterator(); it.hasNext();) {
Object candidateKey = (Object) it.next();
if (candidateKey instanceof Class) {
keys.add(((Class<?>) key)
.isAssignableFrom((Class<?>) candidateKey) ? candidateKey
: key);
}
}
rightKey = CollectionUtils.first(keys);
}
return rightKey;
}
public Object getInstance(Object key) {
Object rightKey = getKey(key);
Object target = null;
this.interceptor.before(rightKey);
target = getInstanceFromBind(rightKey);
this.interceptor.after(rightKey);
inject(rightKey, target);
return target;
}
public void inject(Object target) {
for (Iterator<Object> it = this.injectors.keySet().iterator(); it
.hasNext();) {
Object key = it.next();
if (key instanceof Class) {
Class<?> classKey = (Class<?>) key;
if (classKey.isAssignableFrom(target.getClass())) {
Injector injector = getInjector(classKey);
injector.inject(this, target);
}
}
}
}
public Object getAttributeValue(Object key) {
Object rightKey = key;
Collection<Object> keys = CollectionUtils.createList();
if (binds.containsKey(key)) {
for (Iterator<Object> it = binds.keySet().iterator(); it.hasNext();) {
Object candidateKey = (Object) it.next();
keys.add(candidateKey);
}
rightKey = CollectionUtils.first(keys);
}
return rightKey;
}
public Container addBind(Object key, Bind dependency) {
this.binds.put(key, this.factory.createBindMediator(dependency, this));
return this;
}
private Interceptor createInterceptor() {
return new BindInterceptor();
}
private Object getInstanceFromBind(Object key) {
BindMediator result = getBindMediator(key);
if (result != null) {
return result.getInstance();
}
return result;
}
private BindMediator getBindMediator(Object key) {
return (BindMediator) this.binds.get(key);
}
public Bind getBind(Object key) {
BindMediator bindMediator = getBindMediator(key);
return bindMediator.getBind();
}
public Container addInstanceBind(Object key, Object instance) {
return this.addBind(key, this.factory.createInstanceBind(instance));
}
public AttributeInjectorBuilder addAttributeInjector(Object key) {
AttributeInjectorBuilder attributeInjector = this.factory
.createAttributeInjectorBuilder();
attributeInjector.setInjector(key, this);
return attributeInjector;
}
public ClassBind addClassBind(Object key, Class<?> classDependency) {
ClassBind dependency = new ClassBindImpl(classDependency);
this.addBind(key, dependency);
return dependency;
}
public void start() {
if (!this.started) {
for (Iterator<Object> it = binds.values().iterator(); it.hasNext();) {
Start startable = (Start) it.next();
startable.start();
}
this.started = true;
}
}
public void stop() {
if (this.started) {
for (Iterator<Object> it = binds.values().iterator(); it.hasNext();) {
Start startable = (Start) it.next();
startable.stop();
}
this.started = false;
}
}
}