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øp;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 void invoking(PicoContainer container,
259 ComponentAdapter componentAdapter, Member member,
260 Object instance) {
261 sb.append(member.toString());
262 }
263 });
264 dpc.as(Characteristics.CACHE).addComponent(DefaultPicoContainer.class);
265 dpc.start();
266 assertEquals(
267 "ComponentMonitor should have been notified that the component had been started",
268 "public abstract void org.picocontainer.Startable.start()", sb
269 .toString());
270 }
271
272 public static class StartableClazz implements Startable {
273 private MutablePicoContainer _pico;
274
275 public void start() {
276 List<SimpleTouchable> cps = _pico
277 .getComponents(SimpleTouchable.class);
278 assertNotNull(cps);
279 }
280
281 public void stop() {
282 }
283
284 }
285
286 @Test public void testListComponentsOnStart() {
287
288 // This is really discouraged. Breaks basic principals of IoC -
289 // components should not refer
290 // to their containers
291 //
292 // Might be deleted in due coure, along with adaptersClone stuff in DPC
293
294 DefaultPicoContainer dpc = new DefaultPicoContainer();
295 dpc.addComponent(SimpleTouchable.class);
296 StartableClazz cl = new StartableClazz();
297 cl._pico = dpc;
298 dpc.addComponent(cl);
299 dpc.start();
300 }
301
302 @Test public void testCanChangeMonitor() {
303 StringWriter writer1 = new StringWriter();
304 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
305 DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
306 pico.addComponent("t1", SimpleTouchable.class);
307 pico.addComponent("t3", SimpleTouchable.class);
308 Touchable t1 = (Touchable) pico.getComponent("t1");
309 assertNotNull(t1);
310 final String s = writer1.toString();
311 assertTrue("writer not empty", s.length() > 0);
312 StringWriter writer2 = new StringWriter();
313 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
314 pico.changeMonitor(monitor2);
315 pico.addComponent("t2", SimpleTouchable.class);
316 Touchable t2 = (Touchable) pico.getComponent("t2");
317 assertNotNull(t2);
318 final String s2 = writer2.toString();
319 assertTrue("writer not empty", s2.length() > 0);
320 assertTrue("writers of same length",
321 writer1.toString().length() == writer2.toString().length());
322 Touchable t3 = (Touchable) pico.getComponent("t3");
323 assertNotNull(t3);
324 assertTrue("old writer was used", writer1.toString().length() < writer2
325 .toString().length());
326 }
327
328 @Test public void testCanChangeMonitorOfChildContainers() {
329 StringWriter writer1 = new StringWriter();
330 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
331 DefaultPicoContainer parent = new DefaultPicoContainer();
332 DefaultPicoContainer child = new DefaultPicoContainer(monitor1);
333 parent.addChildContainer(child);
334 child.addComponent("t1", SimpleTouchable.class);
335 child.addComponent("t3", SimpleTouchable.class);
336 Touchable t1 = (Touchable) child.getComponent("t1");
337 assertNotNull(t1);
338 assertTrue("writer not empty", writer1.toString().length() > 0);
339 StringWriter writer2 = new StringWriter();
340 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
341 parent.changeMonitor(monitor2);
342 child.addComponent("t2", SimpleTouchable.class);
343 Touchable t2 = (Touchable) child.getComponent("t2");
344 assertNotNull(t2);
345 assertTrue("writer not empty", writer2.toString().length() > 0);
346 String s1 = writer1.toString();
347 String s2 = writer2.toString();
348 assertTrue("writers of same length", s1.length() == s2.length());
349 Touchable t3 = (Touchable) child.getComponent("t3");
350 assertNotNull(t3);
351 assertTrue("old writer was used", writer1.toString().length() < writer2
352 .toString().length());
353 }
354
355 @Test public void testChangeMonitorIsIgnoredIfNotSupportingStrategy() {
356 StringWriter writer = new StringWriter();
357 ComponentMonitor monitor = new WriterComponentMonitor(writer);
358 DefaultPicoContainer parent = new DefaultPicoContainer(
359 new ComponentFactoryWithNoMonitor(
360 new ComponentAdapterWithNoMonitor(new SimpleTouchable())));
361 parent.addChildContainer(new EmptyPicoContainer());
362 parent.addComponent("t1", SimpleTouchable.class);
363 parent.changeMonitor(monitor);
364 assertTrue("writer empty", writer.toString().length() == 0);
365 }
366
367 @Test public void testCanReturnCurrentMonitorFromComponentFactory() {
368 StringWriter writer1 = new StringWriter();
369 ComponentMonitor monitor1 = new WriterComponentMonitor(writer1);
370 DefaultPicoContainer pico = new DefaultPicoContainer(monitor1);
371 assertEquals(monitor1, pico.currentMonitor());
372 StringWriter writer2 = new StringWriter();
373 ComponentMonitor monitor2 = new WriterComponentMonitor(writer2);
374 pico.changeMonitor(monitor2);
375 assertEquals(monitor2, pico.currentMonitor());
376 }
377
378 private static final class ComponentFactoryWithNoMonitor implements ComponentFactory {
379 private final ComponentAdapter adapter;
380
381 public ComponentFactoryWithNoMonitor(ComponentAdapter adapter) {
382 this.adapter = adapter;
383 }
384
385 public ComponentAdapter createComponentAdapter(
386 ComponentMonitor componentMonitor,
387 LifecycleStrategy lifecycleStrategy,
388 Properties componentProperties, Object componentKey,
389 Class componentImplementation, Parameter... parameters)
390 throws PicoCompositionException {
391 return adapter;
392 }
393
394 public void verify(PicoContainer container) {
395 }
396
397 public void accept(PicoVisitor visitor) {
398 visitor.visitComponentFactory(this);
399 }
400 }
401
402 private static final class ComponentAdapterWithNoMonitor implements
403 ComponentAdapter {
404 private final Object instance;
405
406 public ComponentAdapterWithNoMonitor(Object instance) {
407 this.instance = instance;
408 }
409
410 public Object getComponentKey() {
411 return instance.getClass();
412 }
413
414 public Class getComponentImplementation() {
415 return instance.getClass();
416 }
417
418 public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
419 return getComponentInstance(container, null);
420 }
421
422 public Object getComponentInstance(PicoContainer container, Type into)
423 throws PicoCompositionException {
424 return instance;
425 }
426
427 public void verify(PicoContainer container)
428 throws PicoCompositionException {
429 }
430
431 public void accept(PicoVisitor visitor) {
432 }
433
434 public ComponentAdapter getDelegate() {
435 return null;
436 }
437
438 public ComponentAdapter findAdapterOfType(Class componentAdapterType) {
439 return null;
440 }
441
442 public String getDescriptor() {
443 return null;
444 }
445
446 }
447
448 @Test public void testMakeChildContainer() {
449 MutablePicoContainer parent = new DefaultPicoContainer();
450 parent.addComponent("t1", SimpleTouchable.class);
451 MutablePicoContainer child = parent.makeChildContainer();
452 Object t1 = child.getParent().getComponent("t1");
453 assertNotNull(t1);
454 assertTrue(t1 instanceof SimpleTouchable);
455 }
456
457 @Test public void testMakeChildContainerPassesMonitorFromParentToChild() {
458 final StringBuilder sb = new StringBuilder();
459 ComponentMonitor cm = new NullComponentMonitor() {
460 public <T> void instantiated(PicoContainer container, ComponentAdapter<T> componentAdapter,
461 Constructor<T> constructor,
462 Object instantiated,
463 Object[] injected,
464 long duration) {
465 sb.append(instantiated.getClass().getName()).append(",");
466 }
467
468 };
469 MutablePicoContainer parent = new DefaultPicoContainer(cm);
470 MutablePicoContainer child = parent.makeChildContainer();
471 child.addComponent("t1", SimpleTouchable.class);
472 Object t1 = child.getComponent("t1");
473 assertNotNull(t1);
474 assertTrue(t1 instanceof SimpleTouchable);
475 assertEquals("org.picocontainer.testmodel.SimpleTouchable,", sb.toString());
476 }
477
478
479
480 @Test public void testCanUseCustomLifecycleStrategyForClassRegistrations() {
481 DefaultPicoContainer dpc = new DefaultPicoContainer(
482 new FailingLifecycleStrategy(), null);
483 dpc.as(Characteristics.CACHE).addComponent(Startable.class,
484 MyStartable.class);
485 try {
486 dpc.start();
487 fail("should have barfed");
488 } catch (RuntimeException e) {
489 assertEquals("foo", e.getMessage());
490 }
491 }
492
493 @Test public void testCanUseCustomLifecycleStrategyForInstanceRegistrations() {
494 DefaultPicoContainer dpc = new DefaultPicoContainer(
495 new FailingLifecycleStrategy(), null);
496 Startable myStartable = new MyStartable();
497 dpc.addComponent(Startable.class, myStartable);
498 try {
499 dpc.start();
500 fail("should have barfed");
501 } catch (RuntimeException e) {
502 assertEquals("foo", e.getMessage());
503 }
504 }
505
506 public static class FailingLifecycleStrategy implements LifecycleStrategy {
507 public void start(Object component) {
508 throw new RuntimeException("foo");
509 }
510
511 public void stop(Object component) {
512 }
513
514 public void dispose(Object component) {
515 }
516
517 public boolean hasLifecycle(Class type) {
518 return true;
519 }
520
521 }
522
523 public static class MyStartable implements Startable {
524 public MyStartable() {
525 }
526
527 public void start() {
528 }
529
530 public void stop() {
531 }
532 }
533
534 public static interface A {
535
536 }
537
538 public static class SimpleA implements A {
539
540 }
541
542 public static class WrappingA implements A {
543 private final A wrapped;
544
545 public WrappingA(A wrapped) {
546 this.wrapped = wrapped;
547 }
548 }
549
550 @Test public void testCanRegisterTwoComponentsImplementingSameInterfaceOneWithInterfaceAsKey()
551 throws Exception {
552 MutablePicoContainer container = createPicoContainer(null);
553
554 container.addComponent(SimpleA.class);
555 container.addComponent(A.class, WrappingA.class);
556
557 container.start();
558
559 assertEquals(WrappingA.class, container.getComponent(A.class)
560 .getClass());
561 }
562
563 @Test public void testCanRegisterTwoComponentsWithSameImplementionAndDifferentKey()
564 throws Exception {
565 MutablePicoContainer container = createPicoContainer(null);
566
567 container.addComponent(SimpleA.class);
568 container.addComponent("A", SimpleA.class);
569
570 container.start();
571
572 assertNotNull(container.getComponent("A"));
573 assertNotNull(container.getComponent(SimpleA.class));
574 assertNotSame(container.getComponent("A"), container
575 .getComponent(SimpleA.class));
576 }
577
578 @Test public void testPicoCanDifferentiateBetweenNamedStringsThatWouldOtherwiseBeAmbiguous() {
579 MutablePicoContainer mpc = createPicoContainer(null);
580 mpc.addComponent("greeting", "1");
581 mpc.addComponent("message", "2");
582 mpc.as(Characteristics.USE_NAMES).addComponent(
583 PicoCompositionException.class, PicoCompositionException.class);
584 assertEquals("2", mpc.getComponent(PicoCompositionException.class)
585 .getMessage());
586 }
587
588 @Test public void testPicoCanDifferentiateBetweenNamedObjectsThatWouldOtherwiseBeAmbiguous() {
589 MutablePicoContainer mpc = createPicoContainer(null);
590 Horse dobbin = new Horse();
591 Horse redRum = new Horse();
592 mpc.addComponent("dobbin", dobbin);
593 mpc.addComponent("horse", redRum);
594 mpc.as(Characteristics.USE_NAMES).addComponent(CdiTurtle.class);
595 assertEquals(redRum, mpc.getComponent(CdiTurtle.class).horse);
596 }
597
598 @Test public void testPicoCanDifferentiateBetweenNamedIntsThatWouldOtherwiseBeAmbiguous() {
599 MutablePicoContainer mpc = createPicoContainer(null);
600 mpc.addComponent("one", 1);
601 mpc.addComponent("two", 2);
602 mpc.as(Characteristics.USE_NAMES).addComponent(NeedsTwo.class);
603 assertEquals(2, mpc.getComponent(NeedsTwo.class).two);
604 }
605
606 public static class ListComponentsInStartClass implements Startable {
607 private MutablePicoContainer _pico;
608
609 public void start() {
610 List<SimpleTouchable> cps = _pico
611 .getComponents(SimpleTouchable.class);
612 assertNotNull(cps);
613 }
614
615 public void stop() {
616 }
617
618 }
619
620 /**
621 * JIRA: PICO-295 reported by Erik Putrycz
622 */
623 @Test public void testListComponentsInStart() {
624 DefaultPicoContainer dpc = new DefaultPicoContainer();
625 dpc.addComponent(SimpleTouchable.class);
626 ListComponentsInStartClass cl = new ListComponentsInStartClass();
627 cl._pico = dpc;
628 dpc.addComponent(cl);
629 dpc.start();
630 }
631
632 public static class NeedsTwo {
633 private final int two;
634
635 public NeedsTwo(Integer two) {
636 this.two = two;
637 }
638 }
639
640 public static class Horse {
641 }
642
643 public static class CdiTurtle {
644 public final Horse horse;
645
646 public CdiTurtle(Horse horse) {
647 this.horse = horse;
648 }
649 }
650
651 public static class SdiDonkey {
652 public Horse horse;
653
654 public void setHorse(Horse horse) {
655 this.horse = horse;
656 }
657 }
658
659 public static class SdiRabbit {
660 public Horse horse;
661
662 public void setHorse(Horse horse) {
663 this.horse = horse;
664 }
665 }
666
667 @Test public void testMixingOfSDIandCDI() {
668
669 MutablePicoContainer container = createPicoContainer(null).change(
670 Characteristics.CACHE);
671 container.addComponent(Horse.class);
672 container.change(SDI);
673 container.addComponent(SdiDonkey.class);
674 container.addComponent(SdiRabbit.class);
675 container.change(CDI);
676 container.addComponent(CdiTurtle.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 testMixingOfSDIandCDIDifferently() {
686
687 MutablePicoContainer container = createPicoContainer(null).change(
688 Characteristics.CACHE);
689 container.addComponent(Horse.class);
690 container.addComponent(CdiTurtle.class);
691 container.change(SDI);
692 container.addComponent(SdiDonkey.class);
693 container.addComponent(SdiRabbit.class);
694
695 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
696 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
697 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
698
699 assertions(donkey, rabbit, turtle);
700 }
701
702 @Test public void testMixingOfSDIandCDIInBuilderStyle() {
703
704 MutablePicoContainer container = createPicoContainer(null).change(
705 Characteristics.CACHE);
706 container.addComponent(Horse.class).change(SDI).addComponent(
707 SdiDonkey.class).addComponent(SdiRabbit.class).change(CDI)
708 .addComponent(CdiTurtle.class);
709
710 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
711 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
712 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
713
714 assertions(donkey, rabbit, turtle);
715 }
716
717 private void assertions(SdiDonkey donkey, SdiRabbit rabbit, CdiTurtle turtle) {
718 assertNotNull(rabbit);
719 assertNotNull(donkey);
720 assertNotNull(turtle);
721 assertNotNull(turtle.horse);
722 assertNotNull(donkey.horse);
723 assertNotNull(rabbit.horse);
724 assertSame(donkey.horse, turtle.horse);
725 assertSame(rabbit.horse, turtle.horse);
726 }
727
728 @Test public void testMixingOfSDIandCDIWithTemporaryCharacterizations() {
729
730 MutablePicoContainer container = createPicoContainer(null).change(
731 Characteristics.CACHE);
732 container.addComponent(Horse.class);
733 container.addComponent(CdiTurtle.class);
734 container.as(SDI).addComponent(SdiDonkey.class);
735 container.as(SDI).addComponent(SdiRabbit.class);
736
737 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
738 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
739 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
740
741 assertions(donkey, rabbit, turtle);
742 }
743
744 @Test public void testMixingOfSDIandCDIWithTemporaryCharacterizationsDifferently() {
745
746 MutablePicoContainer container = createPicoContainer(null).change(
747 Characteristics.CACHE);
748 container.as(SDI).addComponent(SdiDonkey.class);
749 container.as(SDI).addComponent(SdiRabbit.class);
750 container.addComponent(Horse.class);
751 container.addComponent(CdiTurtle.class);
752
753 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
754 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
755 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
756
757 assertions(donkey, rabbit, turtle);
758 }
759
760 @Test public void testChainingOfTemporaryCharacterizationsIsNotAllowed() {
761
762 MutablePicoContainer container = createPicoContainer(null);
763 try {
764 container.as(Characteristics.CACHE).as(SDI).addComponent(HashMap.class);
765 fail("shoulf barf");
766 } catch (PicoCompositionException e) {
767 assertTrue(e.getMessage().contains("as(FOO).as(BAR)"));
768 }
769 }
770
771 public static class NeedsString {
772 String string;
773
774 public NeedsString(String string) {
775 this.string = string;
776 }
777 }
778
779 @SuppressWarnings("serial")
780 @Test public void testNoComponentIsMonitoredAndPotentiallyLateProvided() {
781 final Class[] missingKey = new Class[1];
782
783 DefaultPicoContainer container = new DefaultPicoContainer(
784 new NullComponentMonitor() {
785 public Object noComponentFound(
786 MutablePicoContainer container, Object componentKey) {
787 missingKey[0] = (Class) componentKey;
788 return "foo";
789 }
790 });
791 container.addComponent(NeedsString.class);
792 NeedsString needsString = container.getComponent(NeedsString.class);
793
794 assertNotNull(missingKey[0]);
795 assertEquals(String.class, missingKey[0]);
796 assertNotNull(needsString);
797 assertEquals("foo", needsString.string);
798
799 }
800
801 @Test public void testThatComponentCannotBeRemovedFromStartedContainer() {
802 MutablePicoContainer container = createPicoContainer(null);
803 container.addComponent(Map.class, HashMap.class);
804 container.start();
805 try {
806 container.removeComponent(Map.class);
807 fail("should have barfed");
808 } catch (PicoCompositionException e) {
809 }
810 }
811
812 @Test public void testThatSimpleStringComponentIsAddedOnlyOnce() {
813 MutablePicoContainer container = createPicoContainer(null);
814 container.addComponent("foo bar");
815 assertEquals(1, container.getComponentAdapters().size());
816 }
817
818 public static class ConstantParameterTestClass {
819 public ConstantParameterTestClass(Class<String> type) {
820 assert type != null;
821 }
822 }
823
824
825 @Test
826 public void testConstantParameterReferenceClass() {
827 MutablePicoContainer container = createPicoContainer(null);
828 container.addComponent(ConstantParameterTestClass.class, ConstantParameterTestClass.class, new ConstantParameter(String.class));
829
830 assertNotNull(container.getComponent(ConstantParameterTestClass.class));
831
832 }
833
834
835 @Test public void canInterceptImplementationViaNewInjectionFactoryMethodOnMonitor() {
836 DefaultPicoContainer dpc = new DefaultPicoContainer(new MyNullComponentMonitor());
837 dpc.addComponent(Collection.class, HashSet.class);
838 dpc.addComponent(List.class, ArrayList.class);
839 assertNotNull(dpc.getComponent(List.class));
840 assertEquals("doppleganger", dpc.getComponent(List.class).get(0));
841 }
842
843 @SuppressWarnings({"serial", "unchecked"})
844 private static class MyNullComponentMonitor extends NullComponentMonitor {
845 public Injector newInjector(Injector injector) {
846 if (injector.getComponentKey() == List.class) {
847 return new AbstractInjector(List.class, ArrayList.class, Parameter.DEFAULT, MyNullComponentMonitor.this, null, false) {
848 public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
849 return getComponentInstance(container, null);
850 }
851
852 public Object getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
853 ArrayList list = new ArrayList();
854 list.add("doppleganger");
855 return list;
856 }
857 };
858 } else {
859 return injector;
860 }
861 }
862
863 public Behavior newBehavior(Behavior behavior) {
864 return behavior;
865 }
866 }
867
868
869 }