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