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.picocontainer.Characteristics.CDI;
013    import static org.picocontainer.Characteristics.SDI;
014    import org.picocontainer.behaviors.Caching;
015    import org.picocontainer.containers.EmptyPicoContainer;
016    import org.picocontainer.injectors.AbstractInjector;
017    import org.picocontainer.injectors.ConstructorInjection;
018    import org.picocontainer.injectors.ConstructorInjector;
019    import org.picocontainer.lifecycle.NullLifecycleStrategy;
020    import org.picocontainer.monitors.NullComponentMonitor;
021    import org.picocontainer.monitors.WriterComponentMonitor;
022    import org.picocontainer.tck.AbstractPicoContainerTestCase;
023    import org.picocontainer.testmodel.DecoratedTouchable;
024    import org.picocontainer.testmodel.DependsOnTouchable;
025    import org.picocontainer.testmodel.SimpleTouchable;
026    import org.picocontainer.testmodel.Touchable;
027    
028    import java.io.Serializable;
029    import java.io.StringWriter;
030    import java.lang.reflect.Member;
031    import java.util.ArrayList;
032    import java.util.Collection;
033    import java.util.HashMap;
034    import java.util.LinkedList;
035    import java.util.List;
036    import java.util.Properties;
037    import java.util.Map;
038    
039    /**
040     * @author Aslak Hellesøy
041     * @author Paul Hammant
042     * @author Ward Cunningham
043     * @author Mauro Talevi
044     */
045    public final class DefaultPicoContainerTestCase extends AbstractPicoContainerTestCase {
046        protected MutablePicoContainer createPicoContainer(PicoContainer parent) {
047            return new DefaultPicoContainer(parent);
048        }
049    
050        protected Properties[] getProperties() {
051            return new Properties[0];
052        }
053    
054        public void testInstantiationWithNullComponentFactory() {
055            try {
056                new DefaultPicoContainer((ComponentFactory)null, null);
057                fail("NPE expected");
058            } catch (NullPointerException e) {
059                // expected
060            }
061        }
062    
063        public void testUpDownDependenciesCannotBeFollowed() {
064            MutablePicoContainer parent = createPicoContainer(null);
065            MutablePicoContainer child = createPicoContainer(parent);
066    
067            // ComponentF -> ComponentA -> ComponentB+C
068            child.addComponent(ComponentF.class);
069            parent.addComponent(ComponentA.class);
070            child.addComponent(ComponentB.class);
071            child.addComponent(ComponentC.class);
072    
073            try {
074                child.getComponent(ComponentF.class);
075                fail("Thrown " + AbstractInjector.UnsatisfiableDependenciesException.class.getName() + " expected");
076            } catch (final AbstractInjector.UnsatisfiableDependenciesException e) {
077                assertEquals(ComponentB.class, e.getUnsatisfiedDependencyType());
078            }
079        }
080    
081    
082        public void testComponentsCanBeRemovedByInstance() {
083            MutablePicoContainer pico = createPicoContainer(null);
084            pico.addComponent(HashMap.class);
085            pico.addComponent(ArrayList.class);
086            List list = pico.getComponent(List.class);
087            pico.removeComponentByInstance(list);
088            assertEquals(1, pico.getComponentAdapters().size());
089            assertEquals(1, pico.getComponents().size());
090            assertEquals(HashMap.class, pico.getComponent(Serializable.class).getClass());
091        }
092    
093        public void testComponentInstancesListIsReturnedForNullType() {
094            MutablePicoContainer pico = createPicoContainer(null);
095            List componentInstances = pico.getComponents(null);
096            assertNotNull(componentInstances);
097            assertEquals(0, componentInstances.size());
098        }
099    
100        public void testComponentsWithCommonSupertypeWhichIsAConstructorArgumentCanBeLookedUpByConcreteType() {
101            MutablePicoContainer pico = createPicoContainer(null);
102            pico.addComponent(LinkedList.class, LinkedList.class, Parameter.ZERO);
103            pico.addComponent(ArrayList.class);
104            assertEquals(ArrayList.class, pico.getComponent((Class)ArrayList.class).getClass());
105        }
106    
107        /*
108         When pico tries to resolve DecoratedTouchable it find as dependency itself and SimpleTouchable.
109         Problem is basically the same as above. Pico should not consider self as solution.
110         
111         JS
112         fixed it ( PICO-222 )
113         KP
114         */
115        public void testUnambiguouSelfDependency() {
116            MutablePicoContainer pico = createPicoContainer(null);
117            pico.addComponent(SimpleTouchable.class);
118            pico.addComponent(DecoratedTouchable.class);
119            Touchable t = (Touchable)pico.getComponent((Object)DecoratedTouchable.class);
120            assertNotNull(t);
121        }
122    
123    
124        public void testPicoUsedInBuilderStyle() {
125            MutablePicoContainer pico = createPicoContainer(null);
126            Touchable t = pico.change(Characteristics.CACHE)
127                .addComponent(SimpleTouchable.class)
128                .addComponent(DecoratedTouchable.class)
129                .getComponent(DecoratedTouchable.class);
130            SimpleTouchable t2 = pico.getComponent(SimpleTouchable.class);
131            assertNotNull(t);
132            assertNotNull(t2);
133            t.touch();
134            assertTrue(t2.wasTouched);
135        }
136    
137        public static class Thingie {
138            public Thingie(List c) {
139                assertNotNull(c);
140            }
141        }
142    
143        public void testThangCanBeInstantiatedWithArrayList() {
144            MutablePicoContainer pico = new DefaultPicoContainer();
145            pico.addComponent(Thingie.class);
146            pico.addComponent(ArrayList.class);
147            assertNotNull(pico.getComponent(Thingie.class));
148        }
149    
150        public void testGetComponentAdaptersOfTypeNullReturnsEmptyList() {
151            DefaultPicoContainer pico = new DefaultPicoContainer();
152            List adapters = pico.getComponentAdapters(null);
153            assertNotNull(adapters);
154            assertEquals(0, adapters.size());
155        }
156    
157    
158        public static class Service {
159        }
160    
161        public static final class TransientComponent {
162            private final Service service;
163    
164            public TransientComponent(Service service) {
165                this.service = service;
166            }
167        }
168    
169        public void testDefaultPicoContainerReturnsNewInstanceForEachCallWhenUsingTransientComponentAdapter() {
170    
171    
172            DefaultPicoContainer picoContainer =
173                new DefaultPicoContainer(new Caching().wrap(new ConstructorInjection()));
174    
175            picoContainer.addComponent(Service.class);
176            picoContainer.as(Characteristics.NO_CACHE)
177                .addAdapter(new ConstructorInjector(TransientComponent.class,
178                                                    TransientComponent.class,
179                                                    null,
180                                                    new NullComponentMonitor(),
181                                                    new NullLifecycleStrategy()));
182            TransientComponent c1 = picoContainer.getComponent(TransientComponent.class);
183            TransientComponent c2 = picoContainer.getComponent(TransientComponent.class);
184            assertNotSame(c1, c2);
185            assertSame(c1.service, c2.service);
186        }
187    
188        public static class DependsOnCollection {
189            public DependsOnCollection(Collection c) {
190            }
191        }
192    
193        public void testShouldProvideInfoAboutDependingWhenAmbiguityHappens() {
194            MutablePicoContainer pico = this.createPicoContainer(null);
195            pico.addComponent(new ArrayList());
196            pico.addComponent(new LinkedList());
197            pico.addComponent(DependsOnCollection.class);
198            try {
199                pico.getComponent(DependsOnCollection.class);
200                fail();
201            } catch (AbstractInjector.AmbiguousComponentResolutionException expected) {
202                String doc = DependsOnCollection.class.getName();
203                assertEquals("class " + doc +
204                             " 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",
205                             expected.getMessage());
206            }
207        }
208    
209        public void testInstantiationWithMonitorAndParent() {
210            StringWriter writer = new StringWriter();
211            ComponentMonitor monitor = new WriterComponentMonitor(writer);
212            DefaultPicoContainer parent = new DefaultPicoContainer();
213            DefaultPicoContainer child = new DefaultPicoContainer(monitor, parent);
214            parent.addComponent("st", SimpleTouchable.class);
215            child.addComponent("dot", DependsOnTouchable.class);
216            DependsOnTouchable dot = (DependsOnTouchable)child.getComponent("dot");
217            assertNotNull(dot);
218            assertTrue("writer not empty", writer.toString().length() > 0);
219        }
220    
221        public void testStartCapturedByMonitor() {
222            final StringBuffer sb = new StringBuffer();
223            DefaultPicoContainer dpc = new DefaultPicoContainer(new NullComponentMonitor() {
224                public void invoking(PicoContainer container,
225                                     ComponentAdapter componentAdapter,
226                                     Member member,
227                                     Object instance)
228                {
229                    sb.append(member.toString());
230                }
231            });
232            dpc.as(Characteristics.CACHE).addComponent(DefaultPicoContainer.class);
233            dpc.start();
234            assertEquals("ComponentMonitor should have been notified that the component had been started",
235                         "public abstract void org.picocontainer.Startable.start()", sb.toString());
236        }
237    
238        public static class StartableClazz implements Startable {
239            private MutablePicoContainer _pico;
240    
241            public void start() {
242                List<SimpleTouchable> cps = _pico
243                    .getComponents(SimpleTouchable.class);
244                assertNotNull(cps);
245            }
246    
247            public void stop() {
248            }
249    
250        }
251    
252        public void testListComponentsOnStart() {
253    
254            // This is really discouraged.  Breaks basic principals of IoC - components should not refer
255            // to their containers
256            //
257            // Might be deleted in due coure, along with adaptersClone stuff in DPC
258    
259            DefaultPicoContainer dpc = new DefaultPicoContainer();
260            dpc.addComponent(SimpleTouchable.class);
261            StartableClazz cl = new StartableClazz();
262            cl._pico = dpc;
263            dpc.addComponent(cl);
264            dpc.start();
265        }
266    
267        public void testCanChangeMonitor() {
268            StringWriter writer1 = new StringWriter();
269            ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
270            DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
271            pico.addComponent("t1", SimpleTouchable.class);
272            pico.addComponent("t3", SimpleTouchable.class);
273            Touchable t1 = (Touchable)pico.getComponent("t1");
274            assertNotNull(t1);
275            final String s = writer1.toString();
276            assertTrue("writer not empty", s.length() > 0);
277            StringWriter writer2 = new StringWriter();
278            ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
279            pico.changeMonitor(monitor2);
280            pico.addComponent("t2", SimpleTouchable.class);
281            Touchable t2 = (Touchable)pico.getComponent("t2");
282            assertNotNull(t2);
283            final String s2 = writer2.toString();
284            assertTrue("writer not empty", s2.length() > 0);
285            assertTrue("writers of same length", writer1.toString().length() == writer2.toString().length());
286            Touchable t3 = (Touchable)pico.getComponent("t3");
287            assertNotNull(t3);
288            assertTrue("old writer was used", writer1.toString().length() < writer2.toString().length());
289        }
290    
291        public void testCanChangeMonitorOfChildContainers() {
292            StringWriter writer1 = new StringWriter();
293            ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
294            DefaultPicoContainer parent = new DefaultPicoContainer();
295            DefaultPicoContainer child = new DefaultPicoContainer(monitor1);
296            parent.addChildContainer(child);
297            child.addComponent("t1", SimpleTouchable.class);
298            child.addComponent("t3", SimpleTouchable.class);
299            Touchable t1 = (Touchable)child.getComponent("t1");
300            assertNotNull(t1);
301            assertTrue("writer not empty", writer1.toString().length() > 0);
302            StringWriter writer2 = new StringWriter();
303            ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
304            parent.changeMonitor(monitor2);
305            child.addComponent("t2", SimpleTouchable.class);
306            Touchable t2 = (Touchable)child.getComponent("t2");
307            assertNotNull(t2);
308            assertTrue("writer not empty", writer2.toString().length() > 0);
309            String s1 = writer1.toString();
310            String s2 = writer2.toString();
311            assertTrue("writers of same length", s1.length() == s2.length());
312            Touchable t3 = (Touchable)child.getComponent("t3");
313            assertNotNull(t3);
314            assertTrue("old writer was used", writer1.toString().length() < writer2.toString().length());
315        }
316    
317        public void testChangeMonitorIsIgnoredIfNotSupportingStrategy() {
318            StringWriter writer = new StringWriter();
319            ComponentMonitor monitor = new WriterComponentMonitor(writer);
320            DefaultPicoContainer parent =
321                new DefaultPicoContainer(new ComponentFactoryWithNoMonitor(new ComponentAdapterWithNoMonitor(new SimpleTouchable())));
322            parent.addChildContainer(new EmptyPicoContainer());
323            parent.addComponent("t1", SimpleTouchable.class);
324            parent.changeMonitor(monitor);
325            assertTrue("writer empty", writer.toString().length() == 0);
326        }
327    
328        public void testCanReturnCurrentMonitorFromComponentFactory() {
329            StringWriter writer1 = new StringWriter();
330            ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
331            DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
332            assertEquals(monitor1, pico.currentMonitor());
333            StringWriter writer2 = new StringWriter();
334            ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
335            pico.changeMonitor(monitor2);
336            assertEquals(monitor2, pico.currentMonitor());
337        }
338    
339        private static final class ComponentFactoryWithNoMonitor implements ComponentFactory {
340            private final ComponentAdapter adapter;
341    
342            public ComponentFactoryWithNoMonitor(ComponentAdapter adapter) {
343                this.adapter = adapter;
344            }
345    
346            public ComponentAdapter createComponentAdapter(ComponentMonitor componentMonitor,
347                                                           LifecycleStrategy lifecycleStrategy,
348                                                           Properties componentProperties,
349                                                           Object componentKey,
350                                                           Class componentImplementation,
351                                                           Parameter... parameters) throws PicoCompositionException
352            {
353                return adapter;
354            }
355        }
356    
357        private static final class ComponentAdapterWithNoMonitor implements ComponentAdapter {
358            private final Object instance;
359    
360            public ComponentAdapterWithNoMonitor(Object instance) {
361                this.instance = instance;
362            }
363    
364            public Object getComponentKey() {
365                return instance.getClass();
366            }
367    
368            public Class getComponentImplementation() {
369                return instance.getClass();
370            }
371    
372            public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
373                return instance;
374            }
375    
376            public void verify(PicoContainer container) throws PicoCompositionException {
377            }
378    
379            public void accept(PicoVisitor visitor) {
380            }
381    
382            public ComponentAdapter getDelegate() {
383                return null;
384            }
385    
386            public ComponentAdapter findAdapterOfType(Class componentAdapterType) {
387                return null;
388            }
389        }
390    
391        public void testMakeChildContainer() {
392            MutablePicoContainer parent = new DefaultPicoContainer();
393            parent.addComponent("t1", SimpleTouchable.class);
394            MutablePicoContainer child = parent.makeChildContainer();
395            Object t1 = child.getParent().getComponent("t1");
396            assertNotNull(t1);
397            assertTrue(t1 instanceof SimpleTouchable);
398        }
399    
400        public void testCanUseCustomLifecycleStrategyForClassRegistrations() {
401            DefaultPicoContainer dpc = new DefaultPicoContainer(new FailingLifecycleStrategy(), null);
402            dpc.as(Characteristics.CACHE).addComponent(Startable.class, MyStartable.class);
403            try {
404                dpc.start();
405                fail("should have barfed");
406            } catch (RuntimeException e) {
407                assertEquals("foo", e.getMessage());
408            }
409        }
410    
411        public void testCanUseCustomLifecycleStrategyForInstanceRegistrations() {
412            DefaultPicoContainer dpc = new DefaultPicoContainer(new FailingLifecycleStrategy(), null);
413            Startable myStartable = new MyStartable();
414            dpc.addComponent(Startable.class, myStartable);
415            try {
416                dpc.start();
417                fail("should have barfed");
418            } catch (RuntimeException e) {
419                assertEquals("foo", e.getMessage());
420            }
421        }
422    
423        public static class FailingLifecycleStrategy implements LifecycleStrategy {
424            public void start(Object component) {
425                throw new RuntimeException("foo");
426            }
427    
428            public void stop(Object component) {
429            }
430    
431            public void dispose(Object component) {
432            }
433    
434            public boolean hasLifecycle(Class type) {
435                return true;
436            }
437    
438        }
439    
440        public static class MyStartable implements Startable {
441            public MyStartable() {
442            }
443    
444            public void start() {
445            }
446    
447            public void stop() {
448            }
449        }
450    
451        public static interface A {
452    
453        }
454    
455        public static class SimpleA implements A {
456    
457        }
458    
459        public static class WrappingA implements A {
460            private final A wrapped;
461    
462            public WrappingA(A wrapped) {
463                this.wrapped = wrapped;
464            }
465        }
466    
467        public void testCanRegisterTwoComponentsImplementingSameInterfaceOneWithInterfaceAsKey() throws Exception {
468            MutablePicoContainer container = createPicoContainer(null);
469    
470            container.addComponent(SimpleA.class);
471            container.addComponent(A.class, WrappingA.class);
472    
473            container.start();
474    
475            assertEquals(WrappingA.class, container.getComponent(A.class).getClass());
476        }
477    
478        public void testCanRegisterTwoComponentsWithSameImplementionAndDifferentKey() throws Exception {
479            MutablePicoContainer container = createPicoContainer(null);
480    
481            container.addComponent(SimpleA.class);
482            container.addComponent("A", SimpleA.class);
483    
484            container.start();
485    
486            assertNotNull(container.getComponent("A"));
487            assertNotNull(container.getComponent(SimpleA.class));
488            assertNotSame(container.getComponent("A"), container.getComponent(SimpleA.class));
489        }
490    
491        public void testPicoCanDifferentiateBetweenNamedStringsThatWouldOtherwiseBeAmbiguous() {
492            MutablePicoContainer mpc = createPicoContainer(null);
493            mpc.addComponent("greeting", "1");
494            mpc.addComponent("message", "2");
495            mpc.addComponent(PicoCompositionException.class, PicoCompositionException.class);
496            assertEquals("2", mpc.getComponent(PicoCompositionException.class).getMessage());
497        }
498    
499        public void testPicoCanDifferentiateBetweenNamedObjectsThatWouldOtherwiseBeAmbiguous() {
500            MutablePicoContainer mpc = createPicoContainer(null);
501            Horse dobbin = new Horse();
502            Horse redRum = new Horse();
503            mpc.addComponent("dobbin", dobbin);
504            mpc.addComponent("horse", redRum);
505            mpc.addComponent(CdiTurtle.class);
506            assertEquals(redRum, mpc.getComponent(CdiTurtle.class).horse);
507        }
508    
509        public void testPicoCanDifferentiateBetweenNamedIntsThatWouldOtherwiseBeAmbiguous() {
510            MutablePicoContainer mpc = createPicoContainer(null);
511            mpc.addComponent("one", 1);
512            mpc.addComponent("two", 2);
513            mpc.addComponent(NeedsTwo.class);
514            assertEquals(2, mpc.getComponent(NeedsTwo.class).two);
515        }
516    
517        public static class NeedsTwo {
518            private final int two;
519    
520            public NeedsTwo(Integer two) {
521                this.two = two;
522            }
523        }
524    
525        public static class Horse {
526        }
527    
528        public static class CdiTurtle {
529            public final Horse horse;
530    
531            public CdiTurtle(Horse horse) {
532                this.horse = horse;
533            }
534        }
535    
536        public static class SdiDonkey {
537            public Horse horse;
538    
539            public void setHorse(Horse horse) {
540                this.horse = horse;
541            }
542        }
543    
544        public static class SdiRabbit {
545            public Horse horse;
546    
547            public void setHorse(Horse horse) {
548                this.horse = horse;
549            }
550        }
551    
552        public void testMixingOfSDIandCDI() {
553    
554            MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
555            container.addComponent(Horse.class);
556            container.change(SDI);
557            container.addComponent(SdiDonkey.class);
558            container.addComponent(SdiRabbit.class);
559            container.change(CDI);
560            container.addComponent(CdiTurtle.class);
561    
562            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
563            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
564            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
565    
566            assertions(donkey, rabbit, turtle);
567        }
568    
569        public void testMixingOfSDIandCDIDifferently() {
570    
571            MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
572            container.addComponent(Horse.class);
573            container.addComponent(CdiTurtle.class);
574            container.change(SDI);
575            container.addComponent(SdiDonkey.class);
576            container.addComponent(SdiRabbit.class);
577    
578            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
579            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
580            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
581    
582            assertions(donkey, rabbit, turtle);
583        }
584    
585        public void testMixingOfSDIandCDIInBuilderStyle() {
586    
587            MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
588            container.addComponent(Horse.class).change(SDI)
589                .addComponent(SdiDonkey.class).addComponent(SdiRabbit.class).change(CDI).addComponent(CdiTurtle.class);
590    
591            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
592            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
593            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
594    
595            assertions(donkey, rabbit, turtle);
596        }
597    
598        private void assertions(SdiDonkey donkey, SdiRabbit rabbit, CdiTurtle turtle) {
599            assertNotNull(rabbit);
600            assertNotNull(donkey);
601            assertNotNull(turtle);
602            assertNotNull(turtle.horse);
603            assertNotNull(donkey.horse);
604            assertNotNull(rabbit.horse);
605            assertSame(donkey.horse, turtle.horse);
606            assertSame(rabbit.horse, turtle.horse);
607        }
608    
609        public void testMixingOfSDIandCDIWithTemporaryCharacterizations() {
610    
611            MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
612            container.addComponent(Horse.class);
613            container.addComponent(CdiTurtle.class);
614            container.as(SDI).addComponent(SdiDonkey.class);
615            container.as(SDI).addComponent(SdiRabbit.class);
616    
617            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
618            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
619            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
620    
621            assertions(donkey, rabbit, turtle);
622        }
623    
624        public void testMixingOfSDIandCDIWithTemporaryCharacterizationsDifferently() {
625    
626            MutablePicoContainer container = createPicoContainer(null).change(Characteristics.CACHE);
627            container.as(SDI).addComponent(SdiDonkey.class);
628            container.as(SDI).addComponent(SdiRabbit.class);
629            container.addComponent(Horse.class);
630            container.addComponent(CdiTurtle.class);
631    
632            SdiDonkey donkey = container.getComponent(SdiDonkey.class);
633            SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
634            CdiTurtle turtle = container.getComponent(CdiTurtle.class);
635    
636            assertions(donkey, rabbit, turtle);
637        }
638    
639        public void testNoComponentIsMonitoredAndPotentiallyLateProvided() {
640            final String[] missingKey = new String[1];
641    
642            String foo = (String)new DefaultPicoContainer(new NullComponentMonitor() {
643                public Object noComponentFound(MutablePicoContainer container, Object componentKey) {
644                    missingKey[0] = (String)componentKey;
645                    return "foo";
646                }
647            }).getComponent("missingKey");
648    
649            assertNotNull(missingKey[0]);
650            assertEquals("missingKey", missingKey[0]);
651            assertEquals("foo", foo);
652    
653        }
654    
655        public void testThatComponentCannotBeRemovedFromStartedContainer() {
656            MutablePicoContainer container = createPicoContainer(null);
657            container.addComponent(Map.class, HashMap.class);
658            container.start();
659            try {
660                container.removeComponent(Map.class);
661                fail("should have barfed");
662            } catch (PicoCompositionException e) {
663            }
664        }
665    }