001    /*****************************************************************************
002     * Copyright (C) PicoContainer Organization. All rights reserved.            *
003     * ------------------------------------------------------------------------- *
004     * The software in this package is published under the terms of the BSD      *
005     * style license a copy of which has been included with this distribution in *
006     * the LICENSE.txt file.                                                     *
007     *                                                                           *
008     * Original code by                                                          *
009     *****************************************************************************/
010    package org.picocontainer.defaults;
011    
012    import java.util.ArrayList;
013    import java.util.List;
014    
015    import org.picocontainer.ComponentAdapter;
016    import org.picocontainer.MutablePicoContainer;
017    import org.picocontainer.Parameter;
018    import org.picocontainer.tck.AbstractComponentAdapterTestCase;
019    import org.picocontainer.testmodel.NullLifecycle;
020    import org.picocontainer.testmodel.PersonBean;
021    import org.picocontainer.testmodel.PurseBean;
022    import org.picocontainer.testmodel.SimpleTouchable;
023    import org.picocontainer.testmodel.Touchable;
024    
025    
026    public class SetterInjectionComponentAdapterTestCase
027            extends AbstractComponentAdapterTestCase {
028    
029        protected Class getComponentAdapterType() {
030            return SetterInjectionComponentAdapter.class;
031        }
032    
033        protected ComponentAdapterFactory createDefaultComponentAdapterFactory() {
034            return new CachingComponentAdapterFactory(new SetterInjectionComponentAdapterFactory());
035        }
036    
037        protected ComponentAdapter prepDEF_verifyWithoutDependencyWorks(MutablePicoContainer picoContainer) {
038            return new SetterInjectionComponentAdapter(PersonBean.class, PersonBean.class, new Parameter[]{new ConstantParameter(
039                    "Pico Container")});
040        }
041    
042        protected ComponentAdapter prepDEF_verifyDoesNotInstantiate(MutablePicoContainer picoContainer) {
043            picoContainer.registerComponentInstance("Pico Container");
044            return new SetterInjectionComponentAdapter(DeadBody.class, DeadBody.class, new Parameter[]{ComponentParameter.DEFAULT});
045        }
046    
047        protected ComponentAdapter prepDEF_visitable() {
048            return new SetterInjectionComponentAdapter(PersonBean.class, PersonBean.class, new Parameter[]{new ConstantParameter(
049                    "Pico Container")});
050        }
051    
052        protected ComponentAdapter prepSER_isSerializable(MutablePicoContainer picoContainer) {
053            picoContainer.registerComponentInstance("Pico Container");
054            return new SetterInjectionComponentAdapter(PersonBean.class, PersonBean.class, new Parameter[]{ComponentParameter.DEFAULT});
055        }
056    
057        protected ComponentAdapter prepSER_isXStreamSerializable(MutablePicoContainer picoContainer) {
058            return prepSER_isSerializable(picoContainer);
059        }
060    
061        protected ComponentAdapter prepDEF_isAbleToTakeParameters(MutablePicoContainer picoContainer) {
062            picoContainer.registerComponentInstance("Pico Container");
063            picoContainer.registerComponentImplementation(PersonBean.class);
064            return picoContainer.registerComponent(new SetterInjectionComponentAdapter(
065                    PurseBean.class, MoneyPurse.class, new Parameter[]{
066                            ComponentParameter.DEFAULT, new ConstantParameter(new Double(100.0))}));
067        }
068    
069        public static class MoneyPurse
070                extends PurseBean {
071            double money;
072    
073            public double getMoney() {
074                return money;
075            }
076    
077            public void setMoney(double money) {
078                this.money = money;
079            }
080        }
081    
082        protected ComponentAdapter prepVER_verificationFails(MutablePicoContainer picoContainer) {
083            picoContainer.registerComponentInstance("Pico Container");
084            picoContainer.registerComponentImplementation(PersonBean.class);
085            return picoContainer.registerComponent(new SetterInjectionComponentAdapter(
086                    PurseBean.class, MoneyPurse.class, new Parameter[]{ComponentParameter.DEFAULT}));
087        }
088    
089        protected ComponentAdapter prepINS_createsNewInstances(MutablePicoContainer picoContainer) {
090            picoContainer.registerComponentInstance("Pico Container");
091            return new SetterInjectionComponentAdapter(PersonBean.class, PersonBean.class, new Parameter[]{ComponentParameter.DEFAULT});
092        }
093    
094        public static class Ghost
095                extends PersonBean {
096            public Ghost() {
097                throw new VerifyError("test");
098            }
099        }
100    
101        protected ComponentAdapter prepINS_errorIsRethrown(MutablePicoContainer picoContainer) {
102            picoContainer.registerComponentInstance("Pico Container");
103            return new SetterInjectionComponentAdapter(Ghost.class, Ghost.class, new Parameter[]{ComponentParameter.DEFAULT});
104        }
105    
106        public static class DeadBody
107                extends PersonBean {
108            public DeadBody() throws Exception {
109                throw new RuntimeException("test");
110            }
111        }
112    
113        protected ComponentAdapter prepINS_runtimeExceptionIsRethrown(MutablePicoContainer picoContainer) {
114            picoContainer.registerComponentInstance("Pico Container");
115            return new SetterInjectionComponentAdapter(DeadBody.class, DeadBody.class, new Parameter[]{ComponentParameter.DEFAULT});
116        }
117    
118        public static class HidingPersion
119                extends PersonBean {
120            public HidingPersion() throws Exception {
121                throw new Exception("test");
122            }
123        }
124    
125        protected ComponentAdapter prepINS_normalExceptionIsRethrownInsidePicoInvocationTargetInitializationException(
126                MutablePicoContainer picoContainer) {
127            picoContainer.registerComponentInstance("Pico Container");
128            return new SetterInjectionComponentAdapter(
129                    HidingPersion.class, HidingPersion.class, new Parameter[]{ComponentParameter.DEFAULT});
130        }
131    
132        protected ComponentAdapter prepRES_dependenciesAreResolved(MutablePicoContainer picoContainer) {
133            picoContainer.registerComponentInstance("Pico Container");
134            picoContainer.registerComponentImplementation(PersonBean.class);
135            return new SetterInjectionComponentAdapter(PurseBean.class, PurseBean.class, new Parameter[]{ComponentParameter.DEFAULT});
136        }
137    
138        public static class WealthyPerson
139                extends PersonBean {
140            PurseBean purse;
141    
142            public PurseBean getPurse() {
143                return purse;
144            }
145    
146            public void setPurse(PurseBean purse) {
147                this.purse = purse;
148            }
149        }
150    
151        protected ComponentAdapter prepRES_failingVerificationWithCyclicDependencyException(MutablePicoContainer picoContainer) {
152            picoContainer.registerComponentInstance("Pico Container");
153            picoContainer.registerComponentImplementation(PersonBean.class, WealthyPerson.class);
154            return picoContainer.registerComponent(new SetterInjectionComponentAdapter(
155                    PurseBean.class, PurseBean.class, new Parameter[]{ComponentParameter.DEFAULT}));
156        }
157    
158        protected ComponentAdapter prepRES_failingInstantiationWithCyclicDependencyException(MutablePicoContainer picoContainer) {
159            picoContainer.registerComponentInstance("Pico Container");
160            picoContainer.registerComponentImplementation(PersonBean.class, WealthyPerson.class);
161            return picoContainer.registerComponent(new SetterInjectionComponentAdapter(
162                    PurseBean.class, PurseBean.class, new Parameter[]{ComponentParameter.DEFAULT}));
163        }
164    
165        public static class A {
166            private B b;
167            private String string;
168            private List list;
169    
170            public void setB(B b) {
171                this.b = b;
172            }
173    
174            public B getB() {
175                return b;
176            }
177    
178            public String getString() {
179                return string;
180            }
181    
182            public void setString(String string) {
183                this.string = string;
184            }
185    
186            public List getList() {
187                return list;
188            }
189    
190            public void setList(List list) {
191                this.list = list;
192            }
193        }
194    
195        public static class B {
196        }
197    
198        public void testAllUnsatisfiableDependenciesAreSignalled() {
199            SetterInjectionComponentAdapter aAdapter = new SetterInjectionComponentAdapter("a", A.class, null);
200            SetterInjectionComponentAdapter bAdapter = new SetterInjectionComponentAdapter("b", B.class, null);
201    
202            MutablePicoContainer pico = new DefaultPicoContainer();
203            pico.registerComponent(bAdapter);
204            pico.registerComponent(aAdapter);
205    
206            try {
207                aAdapter.getComponentInstance(pico);
208            } catch (UnsatisfiableDependenciesException e) {
209                assertTrue(e.getUnsatisfiableDependencies().contains(List.class));
210                assertTrue(e.getUnsatisfiableDependencies().contains(String.class));
211            }
212        }
213    
214        public static class C {
215            private B b;
216            private List l;
217            private final boolean asBean;
218    
219            public C() {
220                asBean = true;
221            }
222    
223            public C(B b) {
224                this.l = new ArrayList();
225                this.b = b;
226                asBean = false;
227            }
228    
229            public void setB(B b) {
230                this.b = b;
231            }
232    
233            public B getB() {
234                return b;
235            }
236    
237            public void setList(List l) {
238                this.l = l;
239            }
240    
241            public List getList() {
242                return l;
243            }
244    
245            public boolean instantiatedAsBean() {
246                return asBean;
247            }
248        }
249    
250        public void testHybridBeans() {
251            SetterInjectionComponentAdapter bAdapter = new SetterInjectionComponentAdapter("b", B.class, null);
252            SetterInjectionComponentAdapter cAdapter = new SetterInjectionComponentAdapter("c", C.class, null);
253            SetterInjectionComponentAdapter cNullAdapter = new SetterInjectionComponentAdapter("c0", C.class, null);
254    
255            MutablePicoContainer pico = new DefaultPicoContainer();
256            pico.registerComponent(bAdapter);
257            pico.registerComponent(cAdapter);
258            pico.registerComponent(cNullAdapter);
259            pico.registerComponentImplementation(ArrayList.class);
260    
261            C c = (C) cAdapter.getComponentInstance(pico);
262            assertTrue(c.instantiatedAsBean());
263            C c0 = (C) cNullAdapter.getComponentInstance(pico);
264            assertTrue(c0.instantiatedAsBean());
265        }
266    
267        public static class Yin {
268            private Yang yang;
269    
270            public void setYin(Yang yang) {
271                this.yang = yang;
272            }
273    
274            public Yang getYang() {
275                return yang;
276            }
277        }
278    
279        public static class Yang {
280            private Yin yin;
281    
282            public void setYang(Yin yin) {
283                this.yin = yin;
284            }
285    
286            public Yin getYin() {
287                return yin;
288            }
289        }
290    
291        // TODO PICO-188
292        // http://jira.codehaus.org/browse/PICO-188
293        public void FIXME_testShouldBeAbleToHandleMutualDependenciesWithSetterInjection() {
294            MutablePicoContainer pico = new DefaultPicoContainer(new CachingComponentAdapterFactory(
295                    new SetterInjectionComponentAdapterFactory()));
296    
297            pico.registerComponentImplementation(Yin.class);
298            pico.registerComponentImplementation(Yang.class);
299    
300            Yin yin = (Yin) pico.getComponentInstance(Yin.class);
301            Yang yang = (Yang) pico.getComponentInstance(Yang.class);
302    
303            assertSame(yin, yang.getYin());
304            assertSame(yang, yin.getYang());
305        }
306        
307        public void testCustomLifecycleCanBeInjected() throws NoSuchMethodException {
308            RecordingLifecycleStrategy strategy = new RecordingLifecycleStrategy(new StringBuffer());
309            SetterInjectionComponentAdapter sica = new SetterInjectionComponentAdapter(
310                    NullLifecycle.class, NullLifecycle.class, new Parameter[0], false, 
311                    new DelegatingComponentMonitor(), strategy);
312            Touchable touchable = new SimpleTouchable();
313            sica.start(touchable);
314            sica.stop(touchable);
315            sica.dispose(touchable);
316            assertEquals("<start<stop<dispose", strategy.recording());
317        }
318    
319    }