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