/*****************************************************************************
* Copyright (C) Codehaus.org. All rights reserved. *
* ------------------------------------------------------------------------- *
* The software in this package is published under the terms of the BSD *
* style license a copy of which has been included with this distribution in *
* the LICENSE.txt file. *
*****************************************************************************/
/*
* Created on Feb 28, 2005
*
* Author Ben Yu
* ZBS
*/
package jfun.yan.containers;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import jfun.util.Misc;
import jfun.yan.AmbiguousComponentResolutionException;
import jfun.yan.Component;
import jfun.yan.ComponentInstantiationException;
import jfun.yan.ComponentMap;
import jfun.yan.Components;
import jfun.yan.Container;
import jfun.yan.Creator;
import jfun.yan.CyclicDependencyException;
import jfun.yan.Dependency;
import jfun.yan.Registrar;
import jfun.yan.UnknownComponentTypeException;
import jfun.yan.UnresolvedComponentException;
import jfun.yan.UnsatisfiedComponentException;
import jfun.yan.YanException;
import jfun.yan.factory.Factory;
/**
* A simple implementation of interface {@link Container}.
* <p>
* It forwards all method call to the delegated {@link Registrar} object,
* which makes it handy for customizing a Registrar object by subclassing.
* </p>
* <p>
* Plus, SimpleContainer implements {@link Container} interface,
* which provides convenient API's.
* </p>
* <p>
* In this implementation,
* registerStaticMethod and registerConstructor use singleton pattern.
* Override these methods or the {@link #defaultTransform(Component)} method to
* disable the singleton or get a different transformation.
* </p>
* Codehaus.org.
*
* @author Ben Yu
*
*/
public class SimpleContainer implements Container, java.io.Serializable{
private final Registrar target;
/**
* Create a new SimpleContainer object.
* @param target the Registrar object.
*/
public SimpleContainer(final Registrar target) {
this.target = target;
}
public void registerComponent(Object key, Component cc) {
target.registerComponent(key, cc);
}
public void registerComponent(Component cc){
final Class ctype = cc.getType();
if(ctype==null){
throw new UnknownComponentTypeException(
"immature component cannot be registered");
}
registerComponent(ctype, cc);
}
public void unregisterComponent(Object key) {
target.unregisterComponent(key);
}
public void unregisterComponentsOfType(Class type) {
target.unregisterComponentsOfType(type);
}
public boolean containsKey(Object key) {
return target.containsKey(key);
}
public boolean containsType(Class type) {
return target.containsType(type);
}
public Component getComponent(Object key) {
return target.getComponent(key);
}
public <T> Component<T> getComponentOfType(Class<T> type) {
return target.getComponentOfType(type);
}
public <T> List<Component<T>> getComponentsOfType(Class<T> type) {
return target.getComponentsOfType(type);
}
public <T> T getInstanceOfType(final Class<T> type, ComponentMap cmap){
try{
final Component<T> cc = getComponentOfType(type);
if(cc==null){
throw new UnresolvedComponentException(type);
}
return cc.create(cmap.getDependencyOfType(type, cmap));
}
catch(YanException e){
e.push("getInstanceOfType <" + Misc.getTypeName(type)+">");
throw e;
}
}
public <T> List<T> getInstancesOfType(final Class<T> type, ComponentMap cmap){
try{
java.util.List<Component<T>> ccs = getComponentsOfType(type);
final java.util.List<T> ret = new java.util.ArrayList<T>();
for(final Component<T> cc : ccs){
final Class ctype = cc.getType();
if(ctype != null)
ret.add(cc.create(cmap.getDependencyOfType(ctype, cmap)));
}
return ret;
}
catch(YanException e){
e.push("getInstancesOfType <" + Misc.getTypeName(type) + ">");
throw e;
}
}
public <T> T getInstanceOfType(Class<T> type){
return getInstanceOfType(type, this);
}
public <T> List<T> getInstancesOfType(Class<T> type){
return getInstancesOfType(type, this);
}
public Dependency getDependencyOfType(Class type, ComponentMap cmap) {
return target.getDependencyOfType(type, cmap);
}
public Dependency getDependency(Object key, ComponentMap cmap){
return target.getDependency(key, cmap);
}
public Dependency getDependency(Object key){
return getDependency(key, this);
}
public Dependency getDependencyOfType(Class type){
return getDependencyOfType(type, this);
}
public void verify(ComponentMap cmap) {
target.verify(cmap);
}
public void verify(){
target.verify(this);
}
public Class verifyComponent(Component cc){
try{
/*final Class ctype = cc.getType();
if(ctype == null)
throw new IllegalArgumentException(
"dynamic-bound component cannot be verified");
*/
return cc.verify(getDependency(null));
}
catch(YanException e){
e.push("verifyComponent <" + cc + ">");
throw e;
}
}
public Class verifyKey(Object key){
try{
final Component c = getComponent(key);
if(c==null){
throw new UnresolvedComponentException(key);
}
return c.verify(getDependency(key));
}
catch(YanException e){
e.push("verifyKey <" + key +">");
throw e;
}
}
public Class verifyType(Class type){
try{
final Component c = getComponentOfType(type);
if(c==null)
throw new UnresolvedComponentException(type);
return c.verify(getDependencyOfType(type));
}
catch(YanException e){
e.push("verifyType <" + Misc.getTypeName(type) +">");
throw e;
}
}
public Class getComponentType(Object key) {
final Component cc = getComponent(key);
if(cc==null) return null;
return cc.getType();
}
public <T> T instantiateComponent(Creator<T> cc, ComponentMap cmap)
throws AmbiguousComponentResolutionException,
ComponentInstantiationException, CyclicDependencyException,
UnresolvedComponentException, UnsatisfiedComponentException, YanException {
try{
return cc.create(getDependency(null, cmap));
}
catch(YanException e){
e.push("instantiateComponent <" + cc + ">");
throw e;
}
}
public <T> T instantiateComponent(Object key, Creator<T> cc, ComponentMap cmap)
throws AmbiguousComponentResolutionException,
ComponentInstantiationException, CyclicDependencyException,
UnresolvedComponentException, UnsatisfiedComponentException, YanException {
try{
return cc.create(getDependency(key, cmap));
}
catch(YanException e){
e.push("instantiateComponent <" + key + ">");
throw e;
}
}
public <T> T instantiateComponent(Creator<T> cc)
throws AmbiguousComponentResolutionException,
ComponentInstantiationException, CyclicDependencyException,
UnresolvedComponentException, UnsatisfiedComponentException, YanException {
return instantiateComponent(cc, this);
}
public <T> T instantiateComponent(Object key, Creator<T> cc)
throws AmbiguousComponentResolutionException,
ComponentInstantiationException, CyclicDependencyException,
UnresolvedComponentException, UnsatisfiedComponentException, YanException {
return instantiateComponent(key, cc, this);
}
public Object getInstance(Object key, ComponentMap cmap) {
try{
final Component cc = getComponent(key);
if(cc==null){
throw new UnresolvedComponentException(key);
}
return cc.create(cmap.getDependency(key,cmap));
}
catch(YanException e){
e.push("getInstance <" + key + ">");
throw e;
}
}
public Object getInstance(Object key){
return getInstance(key, this);
}
public void registerValue(Object key, Object v){
registerComponent(key, Components.value(v));
}
public void registerValue(Object v){
//registerValue(v==null?Object.class:v.getClass(), v);
registerValue(v.getClass(), v);
}
/**
* The component is transformed by {@link #defaultTransform(Component)},
* which makes it singleton.
* Override {@link #defaultTransform(Component)} if a different default behavior
* is desired.
*/
public void registerConstructor(Class c){
registerConstructor(c, c);
}
/**
* Transforms a component by calling singleton().
* registerConstructor and registerStaticMethod
* call this function to transform the component
* before registering to the container.
* Override this function if singleton() is not desired
* or a different transformation is needed.
* @param comp the component.
* @return the transformed component.
*/
protected Component defaultTransform(Component comp){
return comp.singleton();
}
/**
* The component is transformed by {@link #defaultTransform(Component)},
* which makes it singleton.
* Override {@link #defaultTransform(Component)} if a different default behavior
* is desired.
*/
public void registerConstructor(Object key, Class c){
registerComponent(key, defaultTransform(Components.ctor(c)));
}
/**
* The component is transformed by {@link #defaultTransform(Component)},
* which makes it singleton.
* Override {@link #defaultTransform(Component)} if a different default behavior
* is desired.
*/
public void registerConstructor(Class c, Class[] param_types){
registerConstructor(c, c, param_types);
}
/**
* The component is transformed by {@link #defaultTransform(Component)},
* which makes it singleton.
* Override {@link #defaultTransform(Component)} if a different default behavior
* is desired.
*/
public void registerConstructor(Object key, Class c, Class[] param_types){
registerComponent(key,
defaultTransform(Components.ctor(c, param_types)));
}
/**
* The component is transformed by {@link #defaultTransform(Component)},
* which makes it singleton.
* Override {@link #defaultTransform(Component)} if a different default behavior
* is desired.
*/
public void registerStaticMethod(Class c, String name){
final Component comp = Components.static_method(c, name);
registerComponent(defaultTransform(comp));
}
/**
* The component is transformed by {@link #defaultTransform(Component)},
* which makes it singleton.
* Override {@link #defaultTransform(Component)} if a different default behavior
* is desired.
*/
public void registerStaticMethod(Object key, Class c, String name){
registerComponent(key,
defaultTransform(Components.static_method(c, name)));
}
/**
* The component is transformed by {@link #defaultTransform(Component)},
* which makes it singleton.
* Override {@link #defaultTransform(Component)} if a different default behavior
* is desired.
*/
public void registerStaticMethod(Class c, String name, Class[] param_types){
final Component comp = Components.static_method(c, name, param_types);
registerComponent(defaultTransform(comp));
}
/**
* The component is transformed by {@link #defaultTransform(Component)},
* which makes it singleton.
* Override {@link #defaultTransform(Component)} if a different default behavior
* is desired.
*/
public void registerStaticMethod(Object key, Class c, String name, Class[] param_types){
registerComponent(key,
defaultTransform(Components.static_method(c, name, param_types)));
}
public Container inherit(Registrar parent){
if(parent==this) return this;
return new SimpleContainer(new InheritedRegistrar(parent, this));
}
public boolean equals(Object other) {
if(other instanceof SimpleContainer){
final SimpleContainer cc2 = (SimpleContainer)other;
return target.equals(cc2.target);
}
else return target.equals(other);
}
public int hashCode() {
return target.hashCode();
}
public String toString() {
return target.toString();
}
public Set keys() {
return target.keys();
}
public java.util.Collection getComponents(){
return target.getComponents();
}
public void getInstances(Map store){
getInstances(store, this);
}
public java.util.List getInstances(){
return getInstances(this);
}
public void getInstances(Map store, ComponentMap cmap){
try{
for(Iterator it = keys().iterator(); it.hasNext();){
final Object ky = it.next();
final Component cc = getComponent(ky);
store.put(ky, cc.create(cmap.getDependency(ky, cmap)));
}
}
catch(YanException e){
e.push("getInstances");
throw e;
}
}
public java.util.List getInstances(ComponentMap cmap){
try{
final java.util.Set ks = keys();
final ArrayList ret = new ArrayList();
for(Iterator it = ks.iterator(); it.hasNext();){
final Object ky = it.next();
final Component cc = getComponent(ky);
ret.add(cc.create(cmap.getDependency(ky, cmap)));
}
return ret;
}
catch(YanException e){
e.push("getInstances");
throw e;
}
}
public Factory getFactory(Object key, ComponentMap cmap) throws UnresolvedComponentException, YanException {
return instantiateFactory(key, getComponent(key), cmap);
}
public Factory getFactory(Object key) throws UnresolvedComponentException, YanException {
return instantiateFactory(key, getComponent(key));
}
public <T> Factory<T> getFactoryOfType(Class<T> type, ComponentMap cmap) throws AmbiguousComponentResolutionException, UnresolvedComponentException, YanException {
return instantiateFactory(type, getComponentOfType(type), cmap);
}
public <T> Factory<T> getFactoryOfType(Class<T> type) throws AmbiguousComponentResolutionException, UnresolvedComponentException, YanException {
return instantiateFactory(type, getComponentOfType(type));
}
private <T> Factory<T> instantiateFactory(Object key, Component<T> cc, ComponentMap src){
return this.instantiateComponent(key, cc.factory(), src);
}
private <T> Factory<T> instantiateFactory(Object key, Component<T> cc){
return this.instantiateComponent(key, cc.factory());
}
/**
* Gets the Registrar object being delegated.
* @return the Container object.
*/
protected final Registrar getDelegateTarget(){
return target;
}
}