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