    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     * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant   *
    009     *****************************************************************************/
    010    package org.picocontainer;
    011
    012    import static org.junit.Assert.assertEquals;
    013    import static org.junit.Assert.assertNotNull;
    014    import static org.junit.Assert.assertNotSame;
    015    import static org.junit.Assert.assertSame;
    016    import static org.junit.Assert.assertTrue;
    017    import static org.junit.Assert.fail;
    018    import static org.picocontainer.Characteristics.CDI;
    019    import static org.picocontainer.Characteristics.SDI;
    020
    021    import java.io.Serializable;
    022    import java.io.StringWriter;
    023    import java.lang.StringBuilder;
    024    import java.lang.reflect.Member;
    025    import java.lang.reflect.Constructor;
    026    import java.lang.reflect.Type;
    027    import java.util.ArrayList;
    028    import java.util.Collection;
    029    import java.util.HashMap;
    030    import java.util.HashSet;
    031    import java.util.LinkedList;
    032    import java.util.List;
    033    import java.util.Map;
    034    import java.util.Properties;
    035
    036    import org.junit.Test;
    037    import org.picocontainer.behaviors.Caching;
    038    import org.picocontainer.containers.EmptyPicoContainer;
    039    import org.picocontainer.injectors.AbstractInjector;
    040    import org.picocontainer.injectors.ConstructorInjection;
    041    import org.picocontainer.injectors.ConstructorInjector;
    042    import org.picocontainer.lifecycle.NullLifecycleStrategy;
    043    import org.picocontainer.monitors.NullComponentMonitor;
    044    import org.picocontainer.monitors.WriterComponentMonitor;
    045    import org.picocontainer.parameters.ConstantParameter;
    046    import org.picocontainer.tck.AbstractPicoContainerTest;
    047    import org.picocontainer.testmodel.DecoratedTouchable;
    048    import org.picocontainer.testmodel.DependsOnTouchable;
    049    import org.picocontainer.testmodel.SimpleTouchable;
    050    import org.picocontainer.testmodel.Touchable;
    051
    052    /**
    053     * @author Aslak Helles&oslashp;y
    054     * @author Paul Hammant
    055     * @author Ward Cunningham
    056     * @author Mauro Talevi
    057     */
    058    @SuppressWarnings("serial")
    059    public final class DefaultPicoContainerTestCase extends AbstractPicoContainerTest {
    060
    061            protected MutablePicoContainer createPicoContainer(PicoContainer parent) {
    062                    return new DefaultPicoContainer(parent);
    063            }
    064
    065            protected Properties[] getProperties() {
    066                    return new Properties[0];
    067            }
    068
    069            @Test public void testInstantiationWithNullComponentFactory() {
    070                    try {
    071                            new DefaultPicoContainer((ComponentFactory) null, null);
    072                            fail("NPE expected");
    073                    } catch (NullPointerException e) {
    074                            // expected
    075                    }
    076            }
    077
    078            @Test public void testUpDownDependenciesCannotBeFollowed() {
    079                    MutablePicoContainer parent = createPicoContainer(null);
    080                    MutablePicoContainer child = createPicoContainer(parent);
    081
    082                    // ComponentF -> ComponentA -> ComponentB+C
    083                    child.addComponent(ComponentF.class);
    084                    parent.addComponent(ComponentA.class);
    085                    child.addComponent(ComponentB.class);
    086                    child.addComponent(ComponentC.class);
    087
    088                    try {
    089                            child.getComponent(ComponentF.class);
    090                            fail("Thrown "
    091                                            + AbstractInjector.UnsatisfiableDependenciesException.class
    092                                                            .getName() + " expected");
    093                    } catch (final AbstractInjector.UnsatisfiableDependenciesException e) {
    094                            assertEquals(ComponentB.class, e.getUnsatisfiedDependencyType());
    095                    }
    096
    097        }
    098
    099            @Test public void testComponentsCanBeRemovedByInstance() {
    100                    MutablePicoContainer pico = createPicoContainer(null);
    101                    pico.addComponent(HashMap.class);
    102                    pico.addComponent(ArrayList.class);
    103                    List list = pico.getComponent(List.class);
    104                    pico.removeComponentByInstance(list);
    105                    assertEquals(1, pico.getComponentAdapters().size());
    106                    assertEquals(1, pico.getComponents().size());
    107                    assertEquals(HashMap.class, pico.getComponent(Serializable.class)
    108                                    .getClass());
    109            }
    110
    111            @Test public void testComponentInstancesListIsReturnedForNullType() {
    112                    MutablePicoContainer pico = createPicoContainer(null);
    113                    List componentInstances = pico.getComponents(null);
    114                    assertNotNull(componentInstances);
    115                    assertEquals(0, componentInstances.size());
    116            }
    117
    118            @Test public void testComponentsWithCommonSupertypeWhichIsAConstructorArgumentCanBeLookedUpByConcreteType() {
    119                    MutablePicoContainer pico = createPicoContainer(null);
    120                    pico.addComponent(LinkedList.class, LinkedList.class, Parameter.ZERO);
    121                    pico.addComponent(ArrayList.class, ArrayList.class, Parameter.ZERO);
    122                    assertEquals(ArrayList.class, pico
    123                                    .getComponent((Class) ArrayList.class).getClass());
    124            }
    125
    126
    127            /*
    128             * When pico tries to resolve DecoratedTouchable it find as dependency
    129             * itself and SimpleTouchable. Problem is basically the same as above. Pico
    130             * should not consider self as solution.
    131             *
    132             * JS fixed it ( PICO-222 ) KP
    133             */
    134            @Test public void testUnambiguouSelfDependency() {
    135                    MutablePicoContainer pico = createPicoContainer(null);
    136                    pico.addComponent(SimpleTouchable.class);
    137                    pico.addComponent(DecoratedTouchable.class);
    138                    Touchable t = (Touchable) pico
    139                                    .getComponent((Object) DecoratedTouchable.class);
    140                    assertNotNull(t);
    141            }
    142
    143            @Test public void testPicoUsedInBuilderStyle() {
    144                    MutablePicoContainer pico = createPicoContainer(null);
    145                    Touchable t = pico.change(Characteristics.CACHE).addComponent(
    146                                    SimpleTouchable.class).addComponent(DecoratedTouchable.class)
    147                                    .getComponent(DecoratedTouchable.class);
    148                    SimpleTouchable t2 = pico.getComponent(SimpleTouchable.class);
    149                    assertNotNull(t);
    150                    assertNotNull(t2);
    151                    t.touch();
    152                    assertTrue(t2.wasTouched);
    153            }
    154
    155            public static class Thingie {
    156                    public Thingie(List c) {
    157                            assertNotNull(c);
    158                    }
    159            }
    160
    161            @Test public void testThangCanBeInstantiatedWithArrayList() {
    162                    MutablePicoContainer pico = new DefaultPicoContainer();
    163                    pico.addComponent(Thingie.class);
    164                    pico.addComponent(ArrayList.class);
    165                    assertNotNull(pico.getComponent(Thingie.class));
    166            }
    167
    168            @Test public void testGetComponentAdaptersOfTypeNullReturnsEmptyList() {
    169                    DefaultPicoContainer pico = new DefaultPicoContainer();
    170                    List adapters = pico.getComponentAdapters(null);
    171                    assertNotNull(adapters);
    172                    assertEquals(0, adapters.size());
    173            }
    174
    175            public static class Service {
    176            }
    177
    178            public static final class TransientComponent {
    179                    private final Service service;
    180
    181                    public TransientComponent(Service service) {
    182                            this.service = service;
    183                    }
    184            }
    185
    186            @Test public void testDefaultPicoContainerReturnsNewInstanceForEachCallWhenUsingTransientComponentAdapter() {
    187
    188                    DefaultPicoContainer picoContainer = new DefaultPicoContainer(
    189                                    new Caching().wrap(new ConstructorInjection()));
    190
    191                    picoContainer.addComponent(Service.class);
    192                    picoContainer.as(Characteristics.NO_CACHE).addAdapter(
    193                                    new ConstructorInjector(TransientComponent.class,
    194                                                    TransientComponent.class, null,
    195                                                    new NullComponentMonitor(),
    196                                                    new NullLifecycleStrategy(), false));
    197                    TransientComponent c1 = picoContainer
    198                                    .getComponent(TransientComponent.class);
    199                    TransientComponent c2 = picoContainer
    200                                    .getComponent(TransientComponent.class);
    201                    assertNotSame(c1, c2);
    202                    assertSame(c1.service, c2.service);
    203            }
    204
    205            public static class DependsOnCollection {
    206                    public DependsOnCollection(Collection c) {
    207                    }
    208            }
    209
    210            @Test public void testShouldProvideInfoAboutDependingWhenAmbiguityHappens() {
    211                    MutablePicoContainer pico = this.createPicoContainer(null);
    212                    pico.addComponent(new ArrayList());
    213                    pico.addComponent(new LinkedList());
    214                    pico.addComponent(DependsOnCollection.class);
    215                    try {
    216                            pico.getComponent(DependsOnCollection.class);
    217                            fail();
    218                    } catch (AbstractInjector.AmbiguousComponentResolutionException expected) {
    219                            String doc = DependsOnCollection.class.getName();
    220                            assertEquals(
    221                                            "class "
    222                                                            + doc
    223                                                            + " needs a 'java.util.Collection' injected, but there are too many choices to inject. These:[class java.util.ArrayList, class java.util.LinkedList], refer http://picocontainer.org/ambiguous-injectable-help.html",
    224                                            expected.getMessage());
    225                    }
    226            }
    227
    228            @Test public void testInstantiationWithMonitorAndParent() {
    229                    StringWriter writer = new StringWriter();
    230                    ComponentMonitor monitor = new WriterComponentMonitor(writer);
    231                    DefaultPicoContainer parent = new DefaultPicoContainer();
    232                    DefaultPicoContainer child = new DefaultPicoContainer(monitor, parent);
    233                    parent.addComponent("st", SimpleTouchable.class);
    234                    child.addComponent("dot", DependsOnTouchable.class);
    235                    DependsOnTouchable dot = (DependsOnTouchable) child.getComponent("dot");
    236                    assertNotNull(dot);
    237                    assertTrue("writer not empty", writer.toString().length() > 0);
    238
    239        }
    240
    241        @Test
    242        public void testRepresentationOfContainerTree() {
    243            StringWriter writer = new StringWriter();
    244            DefaultPicoContainer parent = new DefaultPicoContainer();
    245            parent.setName("parent");
    246            DefaultPicoContainer child = new DefaultPicoContainer(parent);
    247            child.setName("child");
    248            parent.addComponent("st", SimpleTouchable.class);
    249            child.addComponent("dot", DependsOnTouchable.class);
    250            assertEquals("child:1<I<parent:1<|", child.toString());
    251        }
    252
    253        @SuppressWarnings("serial")
    254            @Test public void testStartCapturedByMonitor() {
    255                    final StringBuffer sb = new StringBuffer();
    256                    DefaultPicoContainer dpc = new DefaultPicoContainer(
    257                                    new NullComponentMonitor() {
    258                                            public Object invoking(PicoContainer container,
    259                                               ComponentAdapter componentAdapter, Member member,
    260                                               Object instance, Object[] args) {
    261                                                    sb.append(member.toString());
    262                            return null;
    263                        }
    264                                    });
    265                    dpc.as(Characteristics.CACHE).addComponent(DefaultPicoContainer.class);
    266                    dpc.start();
    267                    assertEquals(
    268                                    "ComponentMonitor should have been notified that the component had been started",
    269                                    "public abstract void org.picocontainer.Startable.start()", sb
    270                                                    .toString());
    271            }
    272
    273            public static class StartableClazz implements Startable {
    274                    private MutablePicoContainer _pico;
    275
    276                    public void start() {
    277                            List<SimpleTouchable> cps = _pico
    278                                            .getComponents(SimpleTouchable.class);
    279                            assertNotNull(cps);
    280                    }
    281
    282                    public void stop() {
    283                    }
    284
    285            }
    286
    287            @Test public void testListComponentsOnStart() {
    288
    289                    // This is really discouraged. Breaks basic principals of IoC -
    290                    // components should not refer
    291                    // to their containers
    292                    //
    293                    // Might be deleted in due coure, along with adaptersClone stuff in DPC
    294
    295                    DefaultPicoContainer dpc = new DefaultPicoContainer();
    296                    dpc.addComponent(SimpleTouchable.class);
    297                    StartableClazz cl = new StartableClazz();
    298                    cl._pico = dpc;
    299                    dpc.addComponent(cl);
    300                    dpc.start();
    301            }
    302
    303            @Test public void testCanChangeMonitor() {
    304                    StringWriter writer1 = new StringWriter();
    305                    ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
    306                    DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
    307                    pico.addComponent("t1", SimpleTouchable.class);
    308                    pico.addComponent("t3", SimpleTouchable.class);
    309                    Touchable t1 = (Touchable) pico.getComponent("t1");
    310                    assertNotNull(t1);
    311                    final String s = writer1.toString();
    312                    assertTrue("writer not empty", s.length() > 0);
    313                    StringWriter writer2 = new StringWriter();
    314                    ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
    315                    pico.changeMonitor(monitor2);
    316                    pico.addComponent("t2", SimpleTouchable.class);
    317                    Touchable t2 = (Touchable) pico.getComponent("t2");
    318                    assertNotNull(t2);
    319                    final String s2 = writer2.toString();
    320                    assertTrue("writer not empty", s2.length() > 0);
    321                    assertTrue("writers of same length",
    322                                    writer1.toString().length() == writer2.toString().length());
    323                    Touchable t3 = (Touchable) pico.getComponent("t3");
    324                    assertNotNull(t3);
    325                    assertTrue("old writer was used", writer1.toString().length() < writer2
    326                                    .toString().length());
    327            }
    328
    329            @Test public void testCanChangeMonitorOfChildContainers() {
    330                    StringWriter writer1 = new StringWriter();
    331                    ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
    332                    DefaultPicoContainer parent = new DefaultPicoContainer();
    333                    DefaultPicoContainer child = new DefaultPicoContainer(monitor1);
    334                    parent.addChildContainer(child);
    335                    child.addComponent("t1", SimpleTouchable.class);
    336                    child.addComponent("t3", SimpleTouchable.class);
    337                    Touchable t1 = (Touchable) child.getComponent("t1");
    338                    assertNotNull(t1);
    339                    assertTrue("writer not empty", writer1.toString().length() > 0);
    340                    StringWriter writer2 = new StringWriter();
    341                    ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
    342                    parent.changeMonitor(monitor2);
    343                    child.addComponent("t2", SimpleTouchable.class);
    344                    Touchable t2 = (Touchable) child.getComponent("t2");
    345                    assertNotNull(t2);
    346                    assertTrue("writer not empty", writer2.toString().length() > 0);
    347                    String s1 = writer1.toString();
    348                    String s2 = writer2.toString();
    349                    assertTrue("writers of same length", s1.length() == s2.length());
    350                    Touchable t3 = (Touchable) child.getComponent("t3");
    351                    assertNotNull(t3);
    352                    assertTrue("old writer was used", writer1.toString().length() < writer2
    353                                    .toString().length());
    354            }
    355
    356            @Test public void testChangeMonitorIsIgnoredIfNotSupportingStrategy() {
    357                    StringWriter writer = new StringWriter();
    358                    ComponentMonitor monitor = new WriterComponentMonitor(writer);
    359                    DefaultPicoContainer parent = new DefaultPicoContainer(
    360                                    new ComponentFactoryWithNoMonitor(
    361                                                    new ComponentAdapterWithNoMonitor(new SimpleTouchable())));
    362                    parent.addChildContainer(new EmptyPicoContainer());
    363                    parent.addComponent("t1", SimpleTouchable.class);
    364                    parent.changeMonitor(monitor);
    365                    assertTrue("writer empty", writer.toString().length() == 0);
    366            }
    367
    368            @Test public void testCanReturnCurrentMonitorFromComponentFactory() {
    369                    StringWriter writer1 = new StringWriter();
    370                    ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
    371                    DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
    372                    assertEquals(monitor1, pico.currentMonitor());
    373                    StringWriter writer2 = new StringWriter();
    374                    ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
    375                    pico.changeMonitor(monitor2);
    376                    assertEquals(monitor2, pico.currentMonitor());
    377            }
    378
    379            private static final class ComponentFactoryWithNoMonitor implements ComponentFactory {
    380                    private final ComponentAdapter adapter;
    381
    382                    public ComponentFactoryWithNoMonitor(ComponentAdapter adapter) {
    383                            this.adapter = adapter;
    384                    }
    385
    386                    public ComponentAdapter createComponentAdapter(
    387                                    ComponentMonitor componentMonitor,
    388                                    LifecycleStrategy lifecycleStrategy,
    389                                    Properties componentProperties, Object componentKey,
    390                                    Class componentImplementation, Parameter... parameters)
    391                                    throws PicoCompositionException {
    392                            return adapter;
    393                    }
    394
    395            public void verify(PicoContainer container) {
    396            }
    397
    398            public void accept(PicoVisitor visitor) {
    399                visitor.visitComponentFactory(this);
    400            }
    401        }
    402
    403            private static final class ComponentAdapterWithNoMonitor implements
    404                            ComponentAdapter {
    405                    private final Object instance;
    406
    407                    public ComponentAdapterWithNoMonitor(Object instance) {
    408                            this.instance = instance;
    409                    }
    410
    411                    public Object getComponentKey() {
    412                            return instance.getClass();
    413                    }
    414
    415                    public Class getComponentImplementation() {
    416                            return instance.getClass();
    417                    }
    418
    419            public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
    420                return getComponentInstance(container, null);
    421            }
    422
    423            public Object getComponentInstance(PicoContainer container, Type into)
    424                                    throws PicoCompositionException {
    425                            return instance;
    426                    }
    427
    428                    public void verify(PicoContainer container)
    429                                    throws PicoCompositionException {
    430                    }
    431
    432                    public void accept(PicoVisitor visitor) {
    433            }
    434
    435                    public ComponentAdapter getDelegate() {
    436                            return null;
    437                    }
    438
    439                    public ComponentAdapter findAdapterOfType(Class adapterType) {
    440                            return null;
    441                    }
    442
    443                    public String getDescriptor() {
    444                            return null;
    445                    }
    446
    447            }
    448
    449            @Test public void testMakeChildContainer() {
    450                    MutablePicoContainer parent = new DefaultPicoContainer();
    451                    parent.addComponent("t1", SimpleTouchable.class);
    452                    MutablePicoContainer child = parent.makeChildContainer();
    453                    Object t1 = child.getParent().getComponent("t1");
    454                    assertNotNull(t1);
    455                    assertTrue(t1 instanceof SimpleTouchable);
    456            }
    457
    458        @Test public void testMakeChildContainerPassesMonitorFromParentToChild() {
    459            final StringBuilder sb = new StringBuilder();
    460            ComponentMonitor cm = new NullComponentMonitor() {
    461                public <T> void instantiated(PicoContainer container, ComponentAdapter<T> componentAdapter,
    462                                  Constructor<T> constructor,
    463                                  Object instantiated,
    464                                  Object[] injected,
    465                                  long duration) {
    466                    sb.append(instantiated.getClass().getName()).append(",");
    467                }
    468
    469            };
    470            MutablePicoContainer parent = new DefaultPicoContainer(cm);
    471            MutablePicoContainer child = parent.makeChildContainer();
    472            child.addComponent("t1", SimpleTouchable.class);
    473            Object t1 = child.getComponent("t1");
    474            assertNotNull(t1);
    475            assertTrue(t1 instanceof SimpleTouchable);
    476            assertEquals("org.picocontainer.testmodel.SimpleTouchable,", sb.toString());
    477        }
    478
    479
    480
    481            @Test public void testCanUseCustomLifecycleStrategyForClassRegistrations() {
    482                    DefaultPicoContainer dpc = new DefaultPicoContainer(
    483                                    new FailingLifecycleStrategy(), null);
    484                    dpc.as(Characteristics.CACHE).addComponent(Startable.class,
    485                                    MyStartable.class);
    486                    try {
    487                            dpc.start();
    488                            fail("should have barfed");
    489                    } catch (RuntimeException e) {
    490                            assertEquals("foo", e.getMessage());
    491                    }
    492            }
    493
    494            @Test public void testCanUseCustomLifecycleStrategyForInstanceRegistrations() {
    495                    DefaultPicoContainer dpc = new DefaultPicoContainer(
    496                                    new FailingLifecycleStrategy(), null);
    497                    Startable myStartable = new MyStartable();
    498                    dpc.addComponent(Startable.class, myStartable);
    499                    try {
    500                            dpc.start();
    501                            fail("should have barfed");
    502                    } catch (RuntimeException e) {
    503                            assertEquals("foo", e.getMessage());
    504                    }
    505            }
    506
    507            public static class FailingLifecycleStrategy implements LifecycleStrategy {
    508                    public void start(Object component) {
    509                            throw new RuntimeException("foo");
    510                    }
    511
    512                    public void stop(Object component) {
    513                    }
    514
    515                    public void dispose(Object component) {
    516                    }
    517
    518                    public boolean hasLifecycle(Class type) {
    519                            return true;
    520                    }
    521
    522            }
    523
    524            public static class MyStartable implements Startable {
    525                    public MyStartable() {
    526                    }
    527
    528                    public void start() {
    529                    }
    530
    531                    public void stop() {
    532                    }
    533            }
    534
    535            public static interface A {
    536
    537            }
    538
    539            public static class SimpleA implements A {
    540
    541            }
    542
    543            public static class WrappingA implements A {
    544                    private final A wrapped;
    545
    546                    public WrappingA(A wrapped) {
    547                            this.wrapped = wrapped;
    548                    }
    549            }
    550
    551            @Test public void testCanRegisterTwoComponentsImplementingSameInterfaceOneWithInterfaceAsKey()
    552                            throws Exception {
    553                    MutablePicoContainer container = createPicoContainer(null);
    554
    555                    container.addComponent(SimpleA.class);
    556                    container.addComponent(A.class, WrappingA.class);
    557
    558                    container.start();
    559
    560                    assertEquals(WrappingA.class, container.getComponent(A.class)
    561                                    .getClass());
    562            }
    563
    564            @Test public void testCanRegisterTwoComponentsWithSameImplementionAndDifferentKey()
    565                            throws Exception {
    566                    MutablePicoContainer container = createPicoContainer(null);
    567
    568                    container.addComponent(SimpleA.class);
    569                    container.addComponent("A", SimpleA.class);
    570
    571                    container.start();
    572
    573                    assertNotNull(container.getComponent("A"));
    574                    assertNotNull(container.getComponent(SimpleA.class));
    575                    assertNotSame(container.getComponent("A"), container
    576                                    .getComponent(SimpleA.class));
    577            }
    578
    579            @Test public void testPicoCanDifferentiateBetweenNamedStringsThatWouldOtherwiseBeAmbiguous() {
    580                    MutablePicoContainer mpc = createPicoContainer(null);
    581                    mpc.addComponent("greeting", "1");
    582                    mpc.addComponent("message", "2");
    583                    mpc.as(Characteristics.USE_NAMES).addComponent(
    584                                    PicoCompositionException.class, PicoCompositionException.class);
    585                    assertEquals("2", mpc.getComponent(PicoCompositionException.class)
    586                                    .getMessage());
    587            }
    588
    589            @Test public void testPicoCanDifferentiateBetweenNamedObjectsThatWouldOtherwiseBeAmbiguous() {
    590                    MutablePicoContainer mpc = createPicoContainer(null);
    591                    Horse dobbin = new Horse();
    592                    Horse redRum = new Horse();
    593                    mpc.addComponent("dobbin", dobbin);
    594                    mpc.addComponent("horse", redRum);
    595                    mpc.as(Characteristics.USE_NAMES).addComponent(CdiTurtle.class);
    596                    assertEquals(redRum, mpc.getComponent(CdiTurtle.class).horse);
    597            }
    598
    599            @Test public void testPicoCanDifferentiateBetweenNamedIntsThatWouldOtherwiseBeAmbiguous() {
    600                    MutablePicoContainer mpc = createPicoContainer(null);
    601                    mpc.addComponent("one", 1);
    602                    mpc.addComponent("two", 2);
    603                    mpc.as(Characteristics.USE_NAMES).addComponent(NeedsTwo.class);
    604                    assertEquals(2, mpc.getComponent(NeedsTwo.class).two);
    605            }
    606
    607            public static class ListComponentsInStartClass implements Startable {
    608                    private MutablePicoContainer _pico;
    609
    610                    public void start() {
    611                            List<SimpleTouchable> cps = _pico
    612                                            .getComponents(SimpleTouchable.class);
    613                            assertNotNull(cps);
    614                    }
    615
    616                    public void stop() {
    617                    }
    618
    619            }
    620
    621            /**
    622             * JIRA: PICO-295 reported by Erik Putrycz
    623             */
    624            @Test public void testListComponentsInStart() {
    625                    DefaultPicoContainer dpc = new DefaultPicoContainer();
    626                    dpc.addComponent(SimpleTouchable.class);
    627                    ListComponentsInStartClass cl = new ListComponentsInStartClass();
    628                    cl._pico = dpc;
    629                    dpc.addComponent(cl);
    630                    dpc.start();
    631            }
    632
    633            public static class NeedsTwo {
    634                    private final int two;
    635
    636                    public NeedsTwo(Integer two) {
    637                            this.two = two;
    638                    }
    639            }
    640
    641            public static class Horse {
    642            }
    643
    644            public static class CdiTurtle {
    645                    public final Horse horse;
    646
    647                    public CdiTurtle(Horse horse) {
    648                            this.horse = horse;
    649                    }
    650            }
    651
    652            public static class SdiDonkey {
    653                    public Horse horse;
    654
    655                    public void setHorse(Horse horse) {
    656                            this.horse = horse;
    657                    }
    658            }
    659
    660            public static class SdiRabbit {
    661                    public Horse horse;
    662
    663                    public void setHorse(Horse horse) {
    664                            this.horse = horse;
    665                    }
    666            }
    667
    668            @Test public void testMixingOfSDIandCDI() {
    669
    670                    MutablePicoContainer container = createPicoContainer(null).change(
    671                                    Characteristics.CACHE);
    672                    container.addComponent(Horse.class);
    673                    container.change(SDI);
    674                    container.addComponent(SdiDonkey.class);
    675                    container.addComponent(SdiRabbit.class);
    676                    container.change(CDI);
    677                    container.addComponent(CdiTurtle.class);
    678
    679                    SdiDonkey donkey = container.getComponent(SdiDonkey.class);
    680                    SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
    681                    CdiTurtle turtle = container.getComponent(CdiTurtle.class);
    682
    683                    assertions(donkey, rabbit, turtle);
    684            }
    685
    686            @Test public void testMixingOfSDIandCDIDifferently() {
    687
    688                    MutablePicoContainer container = createPicoContainer(null).change(
    689                                    Characteristics.CACHE);
    690                    container.addComponent(Horse.class);
    691                    container.addComponent(CdiTurtle.class);
    692                    container.change(SDI);
    693                    container.addComponent(SdiDonkey.class);
    694                    container.addComponent(SdiRabbit.class);
    695
    696                    SdiDonkey donkey = container.getComponent(SdiDonkey.class);
    697                    SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
    698                    CdiTurtle turtle = container.getComponent(CdiTurtle.class);
    699
    700                    assertions(donkey, rabbit, turtle);
    701            }
    702
    703            @Test public void testMixingOfSDIandCDIInBuilderStyle() {
    704
    705                    MutablePicoContainer container = createPicoContainer(null).change(
    706                                    Characteristics.CACHE);
    707                    container.addComponent(Horse.class).change(SDI).addComponent(
    708                                    SdiDonkey.class).addComponent(SdiRabbit.class).change(CDI)
    709                                    .addComponent(CdiTurtle.class);
    710
    711                    SdiDonkey donkey = container.getComponent(SdiDonkey.class);
    712                    SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
    713                    CdiTurtle turtle = container.getComponent(CdiTurtle.class);
    714
    715                    assertions(donkey, rabbit, turtle);
    716            }
    717
    718            private void assertions(SdiDonkey donkey, SdiRabbit rabbit, CdiTurtle turtle) {
    719                    assertNotNull(rabbit);
    720                    assertNotNull(donkey);
    721                    assertNotNull(turtle);
    722                    assertNotNull(turtle.horse);
    723                    assertNotNull(donkey.horse);
    724                    assertNotNull(rabbit.horse);
    725                    assertSame(donkey.horse, turtle.horse);
    726                    assertSame(rabbit.horse, turtle.horse);
    727            }
    728
    729            @Test public void testMixingOfSDIandCDIWithTemporaryCharacterizations() {
    730
    731                    MutablePicoContainer container = createPicoContainer(null).change(
    732                                    Characteristics.CACHE);
    733                    container.addComponent(Horse.class);
    734                    container.addComponent(CdiTurtle.class);
    735                    container.as(SDI).addComponent(SdiDonkey.class);
    736                    container.as(SDI).addComponent(SdiRabbit.class);
    737
    738                    SdiDonkey donkey = container.getComponent(SdiDonkey.class);
    739                    SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
    740                    CdiTurtle turtle = container.getComponent(CdiTurtle.class);
    741
    742                    assertions(donkey, rabbit, turtle);
    743            }
    744
    745            @Test public void testMixingOfSDIandCDIWithTemporaryCharacterizationsDifferently() {
    746
    747                    MutablePicoContainer container = createPicoContainer(null).change(
    748                                    Characteristics.CACHE);
    749                    container.as(SDI).addComponent(SdiDonkey.class);
    750                    container.as(SDI).addComponent(SdiRabbit.class);
    751                    container.addComponent(Horse.class);
    752                    container.addComponent(CdiTurtle.class);
    753
    754                    SdiDonkey donkey = container.getComponent(SdiDonkey.class);
    755                    SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
    756                    CdiTurtle turtle = container.getComponent(CdiTurtle.class);
    757
    758                    assertions(donkey, rabbit, turtle);
    759            }
    760
    761            @Test public void testChainingOfTemporaryCharacterizationsIsNotAllowed() {
    762
    763                    MutablePicoContainer container = createPicoContainer(null);
    764            try {
    765                container.as(Characteristics.CACHE).as(SDI).addComponent(HashMap.class);
    766                fail("shoulf barf");
    767            } catch (PicoCompositionException e) {
    768                assertTrue(e.getMessage().contains("as(FOO).as(BAR)"));
    769            }
    770        }
    771
    772        public static class NeedsString {
    773            String string;
    774
    775            public NeedsString(String string) {
    776                this.string = string;
    777            }
    778        }
    779
    780        @SuppressWarnings("serial")
    781            @Test public void testNoComponentIsMonitoredAndPotentiallyLateProvided() {
    782                    final Class[] missingKey = new Class[1];
    783
    784            DefaultPicoContainer container = new DefaultPicoContainer(
    785                    new NullComponentMonitor() {
    786                        public Object noComponentFound(
    787                                MutablePicoContainer container, Object componentKey) {
    788                            missingKey[0] = (Class) componentKey;
    789                            return "foo";
    790                        }
    791                    });
    792            container.addComponent(NeedsString.class);
    793            NeedsString needsString = container.getComponent(NeedsString.class);
    794
    795                    assertNotNull(missingKey[0]);
    796                    assertEquals(String.class, missingKey[0]);
    797                    assertNotNull(needsString);
    798                    assertEquals("foo", needsString.string);
    799
    800            }
    801
    802            @Test public void testThatComponentCannotBeRemovedFromStartedContainer() {
    803                    MutablePicoContainer container = createPicoContainer(null);
    804                    container.addComponent(Map.class, HashMap.class);
    805                    container.start();
    806                    try {
    807                            container.removeComponent(Map.class);
    808                            fail("should have barfed");
    809                    } catch (PicoCompositionException e) {
    810                    }
    811            }
    812
    813            @Test public void testThatSimpleStringComponentIsAddedOnlyOnce() {
    814                    MutablePicoContainer container = createPicoContainer(null);
    815                    container.addComponent("foo bar");
    816                    assertEquals(1, container.getComponentAdapters().size());
    817            }
    818
    819        public static class ConstantParameterTestClass {
    820            public ConstantParameterTestClass(Class<String> type) {
    821                    assert type != null;
    822            }
    823        }
    824
    825
    826        @Test
    827        public void testConstantParameterReferenceClass() {
    828            MutablePicoContainer container = createPicoContainer(null);
    829            container.addComponent(ConstantParameterTestClass.class, ConstantParameterTestClass.class, new ConstantParameter(String.class));
    830
    831            assertNotNull(container.getComponent(ConstantParameterTestClass.class));
    832
    833        }
    834
    835
    836        @Test public void canInterceptImplementationViaNewInjectionFactoryMethodOnMonitor() {
    837            DefaultPicoContainer dpc = new DefaultPicoContainer(new MyNullComponentMonitor());
    838            dpc.addComponent(Collection.class, HashSet.class);
    839            dpc.addComponent(List.class, ArrayList.class);
    840            assertNotNull(dpc.getComponent(List.class));
    841            assertEquals("doppleganger", dpc.getComponent(List.class).get(0));
    842        }
    843
    844        @SuppressWarnings({"serial", "unchecked"})
    845        private static class MyNullComponentMonitor extends NullComponentMonitor {
    846                    public Injector newInjector(Injector injector) {
    847                if (injector.getComponentKey() == List.class) {
    848                    return new AbstractInjector(List.class, ArrayList.class, Parameter.DEFAULT, MyNullComponentMonitor.this, null, false) {
    849                        public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
    850                            return getComponentInstance(container, null);
    851                        }
    852
    853                        public Object getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
    854                            ArrayList list = new ArrayList();
    855                            list.add("doppleganger");
    856                            return list;
    857                        }
    858                    };
    859                } else {
    860                    return injector;
    861                }
    862            }
    863
    864            public Behavior newBehavior(Behavior behavior) {
    865                return behavior;
    866            }
    867        }
    868
    869
    870    }