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