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 *****************************************************************************/
010package org.picocontainer.defaults;
011
012import static org.junit.Assert.assertEquals;
013import static org.junit.Assert.assertNotSame;
014import static org.junit.Assert.assertSame;
015
016import java.util.HashMap;
017import java.util.Map;
018import java.lang.reflect.Type;
019
020import org.junit.Test;
021import org.picocontainer.Characteristics;
022import org.picocontainer.DefaultPicoContainer;
023import org.picocontainer.MutablePicoContainer;
024import org.picocontainer.PicoCompositionException;
025import org.picocontainer.PicoContainer;
026import org.picocontainer.adapters.AbstractAdapter;
027import 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")
036public 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}