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