    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<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    }