/*
* Created on Mar 4, 2005
*
* Author Ben Yu
* ZBS
*/
package tests.jfun.yan;
import junit.framework.TestCase;
import junit.framework.TestSuite;
import java.beans.IntrospectionException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Collection;
import tests.jfun.models.BankAccount;
import tests.jfun.models.BankAccountDao;
import tests.jfun.models.DumbBankAccountDao;
import tests.jfun.models.DumbMyBeanDao;
import tests.jfun.models.InjectingDecorator;
import tests.jfun.models.Injector;
import tests.jfun.models.MyBean;
import tests.jfun.models.MyBeanDao;
import tests.jfun.models.Named;
import tests.jfun.models.Struct;
import tests.jfun.yan.tck.BaseContainerTestCase;
import tests.jfun.yan.testmodel.*;
import jfun.yan.*;
import jfun.yan.containers.DefaultContainer;
import jfun.yan.containers.ProxyContainer;
import jfun.yan.etc.InjectorHelper;
import jfun.yan.factory.GlobalScope;
import jfun.yan.factory.ThreadLocalScope;
import jfun.yan.lifecycle.DefaultLifecycleManager;
import jfun.yan.lifecycle.Lifecycle;
/**
* Zephyr Business Solution
*
* @author Ben Yu
*
*/
public class DefaultContainerTestCase
extends BaseNonSingletonContainerTestCase {
// to go to parent testcase ?
public static void main(String[] args){
try{
Utils.runTest(suite());
}
catch(YanException e){
e.printResolutionTrace(System.err);
throw e;
}
}
private static TestSuite suite(){
return new TestSuite(DefaultContainerTestCase.class);
}
public void testBasicInstantiationAndContainment()
{
Container pico =
createPicoContainerWithTouchableAndDependsOnTouchable();
assertTrue("Component should be instance of Touchable",
Touchable.class.isAssignableFrom(
pico.getComponentOfType(Touchable.class)
.getType()));
}
/*
public void testComponentsCanBeRemovedByInstance() {
MutablePicoContainer pico = createPicoContainer(null);
pico.registerComponentImplementation(HashMap.class);
pico.registerComponentImplementation(ArrayList.class);
List list = (List) pico.getComponentInstanceOfType(List.class);
pico.unregisterComponentByInstance(list);
assertEquals(1, pico.getComponentAdapters().size());
assertEquals(1, pico.getComponentInstances().size());
assertEquals(HashMap.class, pico.getComponentInstanceOfType(Serializable.class).getClass());
}
*/
/*
When pico tries to instantiate ArrayList, it will attempt to use the constructor that takes a
java.util.Collection. Since both the ArrayList and LinkedList are Collection, it will fail with
AmbiguousComponentResolutionException.
Pico should be smart enough to figure out that it shouldn't consider a component as a candidate parameter for
its own instantiation. This may be fixed by adding an additional parameter to ComponentParameter.resolveAdapter -
namely the ComponentAdapter instance that should be excluded.
AH
*/
/*
When pico tries to resolve DecoratedTouchable it find as dependency itself and SimpleTouchable.
Problem is basically the same as above. Pico should not consider self as solution.
JS
*/
public void TodotestUnambiguouSelfDependency() {
Container pico = new DefaultContainer();
pico.registerConstructor(SimpleTouchable.class);
pico.registerConstructor(DecoratedTouchable.class);
Touchable t = (Touchable) pico.getInstance(DecoratedTouchable.class);
assertNotNull(t);
}
public static class Thingie {
public Thingie(List c) {
assertNotNull(c);
}
}
public void testThangCanBeInstantiatedWithArrayList() {
Container pico = new DefaultContainer();
pico.registerConstructor(Thingie.class);
pico.registerConstructor(ArrayList.class, new Class[0]);
assertNotNull(pico.getInstance(Thingie.class));
}
public void getComponentsOfTypeReturnsModifiableList() {
Container pico = new DefaultContainer();
pico.registerConstructor(Thingie.class);
pico.getComponentsOfType(Thingie.class).add((Component)Components.value(null));
}
public static class Service {
}
public static class TransientComponent {
private Service service;
public TransientComponent(Service service) {
this.service = service;
}
}
public void testDefaultPicoContainerReturnsNewInstanceForEachCallWhenUsingTransientComponentAdapter() {
DefaultContainer picoContainer = new DefaultContainer();
picoContainer.registerConstructor(Service.class);
picoContainer.registerComponent(TransientComponent.class,
Components.ctor(TransientComponent.class));
TransientComponent c1 = (TransientComponent) picoContainer.getInstance(TransientComponent.class);
TransientComponent c2 = (TransientComponent) picoContainer.getInstance(TransientComponent.class);
assertNotSame(c1, c2);
assertSame(c1.service, c2.service);
}
public static class DependsOnCollection {
public DependsOnCollection(Collection c) {
}
}
public void testShouldProvideInfoAboutDependingWhenAmbiguityHappens() {
Container pico = new DefaultContainer();
pico.registerValue(new ArrayList());
pico.registerValue(new LinkedList());
pico.registerConstructor(DependsOnCollection.class);
try {
pico.getInstanceOfType(DependsOnCollection.class);
fail();
} catch (AmbiguousComponentResolutionException expected) {
}
}
protected Container getContainerImpl(){
return new DefaultContainer();
}
/*
public void testComponentFromContainerMemorizesInstance()
throws Exception{
final Container yan = createYanContainer();
yan.registerComponent(Components.bean(String.class));
assertEquals(yan.getInstance(String.class), "");
assertSize(1, yan);
assertEquals(yan.getInstance(String.class), "");
assertSize(2, yan);
final Component c1 = yan.getComponent(String.class);
assertEquals(c1.create(yan.getDependencyOfType(c1.getType())), "");
assertSize(3, yan);
final Component c2 = c1.guard().guard().proxy(CharSequence.class);
assertEquals(c2.create(yan.getDependencyOfType(c2.getType())), "");
assertSize(4, yan);
assertEquals(c2.create(yan.getDependencyOfType(c2.getType())), "");
assertSize(5, yan);
final Component c3 = c1.proxy(new Class[]{Comparable.class,
CharSequence.class}).subsume(Comparable.class).proxy()
.withProperty("prop1", Components.value(null))
.proxy(new Class[]{Comparable.class})
;
assertEquals(c3.create(yan.getDependencyOfType(c3.getType())), "");
assertSize(6, yan);
assertEquals(c3.create(yan.getDependencyOfType(c3.getType())), "");
assertSize(7, yan);
final Component c4 = c3.singleton();
assertEquals(c4.create(yan.getDependencyOfType(c4.getType())), "");
assertSize(8, yan);
assertEquals(c4.create(yan.getDependencyOfType(c4.getType())), "");
assertSize(8, yan);
assertEquals(c3.create(yan.getDependencyOfType(c3.getType())), "");
assertSize(9, yan);
}*/
public void testEachPersonGetsNewId()
throws Exception{
final Container yan = getContainerWithPerson();
final Person p1 = (Person)yan.getInstance(Person.class);
final Person p2 = (Person)yan.getInstance(Person.class);
assertEquals(1, p1.getId());
assertEquals(2, p2.getId());
}
public static class Account{
private PersonBean owner;
private PersonBean ceo;
private PersonBean cto;
public Account(PersonBean owner, PersonBean ceo, PersonBean cto) {
super();
this.owner = owner;
this.ceo = ceo;
this.cto = cto;
}
public PersonBean getCeo() {
return ceo;
}
public void setCeo(PersonBean ceo) {
this.ceo = ceo;
}
public PersonBean getCto() {
return cto;
}
public void setCto(PersonBean cto) {
this.cto = cto;
}
public PersonBean getOwner() {
return owner;
}
public void setOwner(PersonBean owner) {
this.owner = owner;
}
}
public void testUseTypeAndSingleton(){
final Container yan = createYanContainer();
yan.registerComponent("singletonPerson",
Components.useType(PersonBean.class).singleton());
yan.registerComponent(Components.ctor(PersonBean.class,
new Class[]{String.class}));
yan.registerValue("Ben");
yan.registerComponent(Components.ctor(Account.class)
.withArgument(0, Components.useKey("singletonPerson"))
.withArgument(1, Components.useKey("singletonPerson")));
final Account acc1 = (Account)yan.getInstanceOfType(Account.class);
assertSame(acc1.getOwner(), acc1.getCeo());
assertNotSame(acc1.getCeo(), acc1.getCto());
assertEquals("Ben", acc1.getOwner().getName());
}
public void testVerify1()
throws Throwable{
final Container yan = this.createYanContainer();
final DefaultLifecycleManager man = new DefaultLifecycleManager();
Component mybean = Components.bean(MyBean.class, new String[]{"1","short"});
mybean = man.newLifecycle()
.verifier("verify")
.manage(mybean);
yan.registerValue(new Short((short)1));
yan.registerValue(Boolean.valueOf(true));
yan.registerComponent("target", mybean);
MyBean bean = (MyBean)yan.getInstance("target");
assertTrue(bean.is1());
try{
man.verify();
}
catch(IllegalStateException e){
return;
}
fail("should have failed with illegal state");
}
public void testVerify2()
throws Throwable{
final Container yan = this.createYanContainer();
Component mybean = Components.bean(MyBean.class, new String[]{"1","short"})
.followedBy(new Binder(){
public Creator bind(Object obj){
return Components.method(obj, "verify");
}
});
yan.registerValue(new Short((short)1));
yan.registerValue(Boolean.valueOf(true));
yan.registerComponent("target", mybean);
try{
MyBean bean = (MyBean)yan.getInstance("target");
}
catch(ComponentInstantiationException e){
return;
}
fail("should have failed in verification");
}
public void testField()throws Throwable{
final Component c1 = Components.static_field(Struct.class, "default_instance");
final Component c2 = c1.field("name");
assertResult(c2, "default");
assertResult(c2.withArgument(0, Components.value("x")), "default");
assertResult(c2.singleton(), "default");
final Component c3 = Components.ctor(Struct.class)
.withArguments(new Component[]{Components.value(1), Components.value("hello"), Components.value(10)});
assertResult(c3.field("name"), "hello");
assertResult(c3.field("id"), new Integer(1));
assertResult(c3.field("age"), new Integer(10));
class Tmp{
Component customize(Component c){
return c.withArgument(1, Components.value("a"));
}
}
Tmp tmp = new Tmp();
assertResult(tmp.customize(c3.field("name")), "hello");
assertError(c3.cast(null).field("age1"), IllegalArgumentException.class, Struct.class.getName()+".age1 not found.");
final Component getname = Components.fun(
Functions.instance_field(Struct.class, "name"))
.withArgument(0, Components.static_field(Struct.class, "default_instance"));
assertResult(getname, "default");
}
public void testVerifyBind(){
final Component str = Components.value("abc");
final Container yan = createYanContainer();
assertEquals(int.class, yan.verifyComponent(str.method("length")));
assertEquals(Object.class, yan.verifyComponent(str.bind(new Binder(){
public Creator bind(Object obj){
return Components.value(obj.toString().length());
}
})));
}
public static Component getBeanInjector(Object obj)
throws IntrospectionException{
return Components.value(obj).bean().optionalProperties();
}
public void testInstantiatorAndFactory(){
Container yan = createYanContainer();
final Component injector = Components.method(this, "getBeanInjector");
yan.registerComponent("target",
injector.bind(Monad.instantiator())
.factory(Injector.class)
);
yan.registerValue("apple");
MyBean mbean = new MyBean();
Injector inj = (Injector)yan.getInstance("target");
inj.inject(mbean);
assertEquals("apple", mbean.getName());
}
public void testInjectorHelper(){
Container yan = createYanContainer();
final Binder injection = new Binder(){
public Creator bind(Object obj)
throws IntrospectionException{
return getBeanInjector(obj);
}
};
yan.registerComponent("target",
new InjectorHelper()
.getInjectorComponent(Injector.class, injection)
);
yan.registerValue("apple");
MyBean mbean = new MyBean();
Injector inj = (Injector)yan.getInstance("target");
inj.inject(mbean);
assertEquals("apple", mbean.getName());
}
public void testInjectingDaoDecorator(){
Container yan = createYanContainer();
yan.registerValue("apple");
final Binder injection = new Binder(){
public Creator bind(Object obj)
throws IntrospectionException{
return getBeanInjector(obj);
}
};
Component injector = new InjectorHelper()
.getInjectorComponent(Injector.class, injection);
Component dumb_dao = Components.ctor(DumbMyBeanDao.class);
Component dao = Components.static_method(InjectingDecorator.class,
"getInjectingDecorator", new Class[]{Object.class, Class.class, Injector.class})
.withArguments(new Component[]{dumb_dao, Components.value(MyBean.class), injector});
yan.registerComponent("dao", dao);
MyBeanDao mdao = (MyBeanDao)yan.getInstance("dao");
assertEquals(mdao, mdao);
Named mbean = mdao.getBeanById(1);
assertEquals("apple", mbean.getName());
}
public void testReturningInjectedProxy(){
Container yan = createYanContainer();
yan.registerValue("apple");
final Binder injection = new Binder(){
public Creator bind(Object obj)
throws IntrospectionException{
return getBeanInjector(obj);
}
};
Component dumb_dao = Components.ctor(DumbMyBeanDao.class);
final Component dao = new InjectorHelper().getProxyComponentReturningInjected(MyBeanDao.class,
dumb_dao, MyBean.class, injection);
yan.registerComponent("dao", dao);
MyBeanDao mdao = (MyBeanDao)yan.getInstance("dao");
assertEquals(mdao, mdao);
Named mbean = mdao.getBeanById(1);
assertEquals("apple", mbean.getName());
}
public void testNestedInjectionProxy(){
Container yan = createYanContainer();
yan.registerValue("apple");
yan.registerConstructor("BankAccount", BankAccount.class, null);
final Binder bean_injection = new Binder(){
public Creator bind(Object obj)
throws IntrospectionException{
return getBeanInjector(obj);
}
};
final Binder account_injection = new Binder(){
public Creator bind(Object obj)
throws IntrospectionException{
return Components.value(obj).bean()
//.optionalProperties()
;
}
};
Component dumb_dao = Components.ctor(DumbBankAccountDao.class);
InjectorHelper helper = new InjectorHelper();
Component dao = helper.getProxyComponentReturningInjected(BankAccountDao.class,
dumb_dao, MyBean.class, bean_injection);
dao = helper.getProxyComponentReturningInjected(BankAccountDao.class, dao,
BankAccount.class, account_injection);
yan.registerComponent("dao", dao);
yan.registerValue(new Integer(10));
yan.registerValue(new char[]{'a','b'});
BankAccountDao mdao = (BankAccountDao)yan.getInstance("dao");
assertEquals(mdao, mdao);
MyBean mbean = mdao.getMyBean(1);
assertEquals("apple", mbean.getName());
BankAccount account = mdao.getAccount("a");
assertEquals('a', account.getChar(0));
assertEquals('b', account.getChar(1));
assertEquals("apple", account.getId());
assertEquals(10, account.getBalance());
}
public static class A{
private B b;
private String name;
public B getB() {
return b;
}
public void setB(B b) {
this.b = b;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public static class B{
private A a;
private int id;
public A getA() {
return a;
}
public void setA(A a) {
this.a = a;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
public void testMutualRecursionOnSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class).singleton();
Component b = Components.bean(B.class).singleton();
verifyABMutualRecursionForSingleton(a, b);
}
public void testMutualRecursionOnSingletonThenBean()
throws IntrospectionException{
Component a = Components.ctor(A.class).singleton().bean();
Component b = Components.ctor(B.class).singleton().bean();
try{
verifyABMutualRecursionForSingleton(a, b);
fail("should have failed with cyclic dependency");
}
catch(CyclicDependencyException e){}
}
public void testManualMutualRecursionOnSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class)
.withProperty("b", Components.useKey("b")).singleton();
Component b = Components.bean(B.class)
.withProperty("a", Components.useKey("a")).singleton();
verifyABMutualRecursionForSingleton(a, b);
}
public void testManualMutualRecursionOnSemiSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class)
.singleton().withProperty("b", Components.useKey("b"));
Component b = Components.bean(B.class)
.singleton().withProperty("a", Components.useKey("a"));
verifyABMutualRecursionForSingleton(a, b);
}
public void testMutualRecursionOnThreadLocalSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class).singleton(new ThreadLocalScope());
Component b = Components.bean(B.class).singleton(new ThreadLocalScope());
verifyABMutualRecursionForSingleton(a, b);
}
public void testMutualRecursionOnScopedSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class).singleton(new GlobalScope());
Component b = Components.bean(B.class).singleton(new ThreadLocalScope());
verifyABMutualRecursionForSingleton(a, b);
}
public void testManualMutualRecursionOnScopedSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class)
.withProperty("b", Components.useKey("b")).singleton(new GlobalScope());
Component b = Components.bean(B.class)
.withProperty("a", Components.useKey("a")).singleton(new ThreadLocalScope());
verifyABMutualRecursionForSingleton(a, b);
}
public void testManualMutualRecursionOnScopedSemiSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class)
.singleton(new GlobalScope()).withProperty("b", Components.useKey("b"));
Component b = Components.bean(B.class)
.singleton(new ThreadLocalScope()).withProperty("a", Components.useKey("a"));
verifyABMutualRecursionForSingleton(a, b);
}
public void testMutualRecursionOnScopedSingletonSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class).singleton(new GlobalScope()).singleton();
Component b = Components.bean(B.class).singleton(new ThreadLocalScope()).singleton();
verifyABMutualRecursionForSingleton(a, b);
}
public void testMutualRecursionOnSingletonScopedSingletonBean()
throws IntrospectionException{
Component a = Components.bean(A.class).singleton().singleton(new GlobalScope());
Component b = Components.bean(B.class).singleton().singleton(new ThreadLocalScope()).singleton();
verifyABMutualRecursionForSingleton(a, b);
}
private void verifyABMutualRecursionForSingleton(Component ac, Component bc){
final Container yan = createYanContainer();
yan.registerValue("Tom");
yan.registerValue(new Integer(10));
yan.registerComponent("a", ac);
yan.registerComponent("b", bc);
A a = (A)yan.getInstance("a");
B b = (B)yan.getInstance("b");
assertEquals("Tom", a.getName());
assertEquals(10, b.getId());
assertSame(a.getB(), b);
assertSame(a, b.getA());
assertSame(a, yan.getInstance("a"));
assertSame(b, yan.getInstance("b"));
}
}