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 static org.junit.Assert.assertEquals;
013    import static org.junit.Assert.assertNotSame;
014    import static org.junit.Assert.assertSame;
015    
016    import java.util.HashMap;
017    import java.util.Map;
018    import java.lang.reflect.Type;
019    
020    import org.junit.Test;
021    import org.picocontainer.Characteristics;
022    import org.picocontainer.DefaultPicoContainer;
023    import org.picocontainer.MutablePicoContainer;
024    import org.picocontainer.PicoCompositionException;
025    import org.picocontainer.PicoContainer;
026    import org.picocontainer.adapters.AbstractAdapter;
027    import org.picocontainer.injectors.ConstructorInjection;
028    
029    /**
030     * This class can be used to test out various things asked on the mailing list.
031     * Or to answer questions.
032     *
033     * @author Aslak Hellesøy
034     */
035    @SuppressWarnings("serial")
036    public final class UserQuestionTestCase {
037    
038        // From Scott Farquahsr
039        public static final class CheeseAdapter extends AbstractAdapter {
040            private final Map bla;
041    
042            public CheeseAdapter(Object componentKey, Class componentImplementation, Map cheeseMap) throws PicoCompositionException {
043                super(componentKey, componentImplementation);
044                this.bla = cheeseMap;
045            }
046    
047            public Object getComponentInstance(PicoContainer pico, Type into) throws PicoCompositionException {
048                return bla.get("cheese");
049            }
050    
051            public void verify(PicoContainer pico) {
052            }
053    
054            public String getDescriptor() {
055                return null;
056            }
057        }
058    
059        public static interface Cheese {
060            String getName();
061        }
062    
063        public static class Gouda implements Cheese {
064            public String getName() {
065                return "Gouda";
066            }
067        }
068    
069        public static class Roquefort implements Cheese {
070            public String getName() {
071                return "Roquefort";
072            }
073        }
074    
075        public static class Omelette {
076            private final Cheese cheese;
077    
078            public Omelette(Cheese cheese) {
079                this.cheese = cheese;
080            }
081    
082            public Cheese getCheese() {
083                return cheese;
084            }
085        }
086    
087        @Test public void testOmeletteCanHaveDifferentCheeseWithAFunnyComponentAdapter() {
088            Map<String,Cheese> cheeseMap = new HashMap<String,Cheese>();
089    
090            MutablePicoContainer pico = new DefaultPicoContainer(new ConstructorInjection());
091            pico.addComponent(Omelette.class);
092            pico.addAdapter(new CheeseAdapter("scott", Gouda.class, cheeseMap));
093    
094            Cheese gouda = new Gouda();
095            cheeseMap.put("cheese", gouda);
096            Omelette goudaOmelette = pico.getComponent(Omelette.class);
097            assertSame(gouda, goudaOmelette.getCheese());
098    
099            Cheese roquefort = new Roquefort();
100            cheeseMap.put("cheese", roquefort);
101            Omelette roquefortOmelette = pico.getComponent(Omelette.class);
102            assertSame(roquefort, roquefortOmelette.getCheese());
103        }
104    
105        public static interface InterfaceX {
106            String getIt();
107        }
108    
109        public static class Enabled implements InterfaceX {
110            public String getIt() {
111                return "Enabled";
112            }
113        }
114    
115        public static class Disabled implements InterfaceX {
116            public String getIt() {
117                return "Disabled";
118            }
119        }
120    
121        public static class Something implements InterfaceX {
122            private final Disabled disabled;
123            private final Enabled enabled;
124            private final Map map;
125    
126            public Something(Disabled disabled, Enabled enabled, Map map) {
127                this.disabled = disabled;
128                this.enabled = enabled;
129                this.map = map;
130            }
131    
132            public String getIt() {
133                if (map.get("enabled") == null) {
134                    return disabled.getIt();
135                } else {
136                    return enabled.getIt();
137                }
138            }
139        }
140    
141        public static class NeedsInterfaceX {
142            private final InterfaceX interfaceX;
143    
144            public NeedsInterfaceX(InterfaceX interfaceX) {
145                this.interfaceX = interfaceX;
146            }
147    
148            public String getIt() {
149                return interfaceX.getIt();
150            }
151        }
152    
153        @Test public void testMoreWeirdness() {
154            MutablePicoContainer pico = new DefaultPicoContainer();
155            Map<String,String> map = new HashMap<String,String>();
156            pico.addComponent(map);
157            // See class level javadoc in DefaultPicoContainer - about precedence. 
158            pico.addComponent(InterfaceX.class, Something.class);
159            pico.addComponent(Disabled.class);
160            pico.addComponent(Enabled.class);
161            pico.addComponent(NeedsInterfaceX.class);
162    
163            NeedsInterfaceX needsInterfaceX = pico.getComponent(NeedsInterfaceX.class);
164            assertEquals("Disabled", needsInterfaceX.getIt());
165            map.put("enabled", "blah");
166            assertEquals("Enabled", needsInterfaceX.getIt());
167        }
168    
169        // From John Tal 23/03/2004
170        public static interface ABC {
171        }
172    
173        public static interface DEF {
174        }
175    
176        public static class ABCImpl implements ABC {
177            public ABCImpl(DEF def) {
178            }
179        }
180    
181        public static class DEFImpl implements DEF {
182            public DEFImpl() {
183            }
184        }
185    
186        @Test public void testJohnTalOne() {
187            MutablePicoContainer picoContainer = new DefaultPicoContainer();
188    
189            picoContainer.addComponent("ABC", ABCImpl.class);
190            picoContainer.addComponent("DEF", DEFImpl.class);
191    
192            assertEquals(ABCImpl.class, picoContainer.getComponent("ABC").getClass());
193        }
194    
195        public static interface Foo {
196        }
197    
198        public static interface Bar {
199        }
200    
201        public static class FooBar implements Foo, Bar {
202        }
203    
204        public static class NeedsFoo {
205            private final Foo foo;
206    
207            public NeedsFoo(Foo foo) {
208                this.foo = foo;
209            }
210    
211            public Foo getFoo() {
212                return foo;
213            }
214        }
215    
216        public static class NeedsBar {
217            private final Bar bar;
218    
219            public NeedsBar(Bar bar) {
220                this.bar = bar;
221            }
222    
223            public Bar getBar() {
224                return bar;
225            }
226        }
227    
228        @Test public void testShouldBeAbleShareSameReferenceForDifferentTypes() {
229            MutablePicoContainer pico = new DefaultPicoContainer();
230            pico.as(Characteristics.CACHE).addComponent(FooBar.class);
231            pico.addComponent(NeedsFoo.class);
232            pico.addComponent(NeedsBar.class);
233            NeedsFoo needsFoo = pico.getComponent(NeedsFoo.class);
234            NeedsBar needsBar = pico.getComponent(NeedsBar.class);
235            assertSame(needsFoo.getFoo(), needsBar.getBar());
236        }
237    
238        @Test public void testSeveralDifferentInstancesCanBeCreatedWithOnePreconfiguredContainer() {
239            // create a container that doesn't cache instances
240            MutablePicoContainer container = new DefaultPicoContainer(new ConstructorInjection());
241            container.addComponent(NeedsBar.class);
242    
243            Bar barOne = new FooBar();
244            container.addComponent(Bar.class, barOne);
245            NeedsBar needsBarOne = container.getComponent(NeedsBar.class);
246            assertSame(barOne, needsBarOne.getBar());
247    
248            // reuse the same container - just flip out the existing foo.
249            Bar barTwo = new FooBar();
250            container.removeComponent(Bar.class);
251            container.addComponent(Bar.class, barTwo);
252            NeedsBar needsBarTwo = container.getComponent(NeedsBar.class);
253            assertSame(barTwo, needsBarTwo.getBar());
254    
255            assertNotSame(needsBarOne, needsBarTwo);
256        }
257    }