    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&oslash;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    }