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