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