001 /*****************************************************************************
002 * Copyright (c) PicoContainer Organization. All rights reserved. *
003 * ------------------------------------------------------------------------- *
004 * The software in this package is published under the terms of the BSD *
005 * style license a copy of which has been included with this distribution in *
006 * the LICENSE.txt file. *
007 * *
008 * Idea by Rachel Davies, Original code by Aslak Hellesoy and Paul Hammant *
009 *****************************************************************************/
010 package org.picocontainer;
011
012 import static org.junit.Assert.assertEquals;
013 import static org.junit.Assert.assertNotNull;
014 import static org.junit.Assert.assertNotSame;
015 import static org.junit.Assert.assertSame;
016 import static org.junit.Assert.assertTrue;
017 import static org.junit.Assert.fail;
018 import static org.picocontainer.Characteristics.CDI;
019 import static org.picocontainer.Characteristics.SDI;
020
021 import java.io.Serializable;
022 import java.io.StringWriter;
023 import java.lang.reflect.Field;
024 import java.lang.reflect.Member;
025 import java.lang.reflect.Type;
026 import java.util.ArrayList;
027 import java.util.Collection;
028 import java.util.HashMap;
029 import java.util.HashSet;
030 import java.util.LinkedList;
031 import java.util.List;
032 import java.util.Map;
033 import java.util.Properties;
034
035 import org.junit.Test;
036 import org.picocontainer.annotations.Inject;
037 import org.picocontainer.behaviors.Caching;
038 import org.picocontainer.behaviors.Decorating;
039 import org.picocontainer.behaviors.FieldDecorating;
040 import org.picocontainer.containers.EmptyPicoContainer;
041 import org.picocontainer.injectors.AbstractInjector;
042 import org.picocontainer.injectors.ConstructorInjection;
043 import org.picocontainer.injectors.ConstructorInjector;
044 import org.picocontainer.injectors.FactoryInjector;
045 import org.picocontainer.injectors.MultiInjection;
046 import org.picocontainer.lifecycle.NullLifecycleStrategy;
047 import org.picocontainer.monitors.NullComponentMonitor;
048 import org.picocontainer.monitors.WriterComponentMonitor;
049 import org.picocontainer.tck.AbstractPicoContainerTest;
050 import org.picocontainer.testmodel.DecoratedTouchable;
051 import org.picocontainer.testmodel.DependsOnTouchable;
052 import org.picocontainer.testmodel.SimpleTouchable;
053 import org.picocontainer.testmodel.Touchable;
054
055 /**
056 * @author Aslak Hellesøp;y
057 * @author Paul Hammant
058 * @author Ward Cunningham
059 * @author Mauro Talevi
060 */
061 @SuppressWarnings("serial")
062 public final class DefaultPicoContainerTestCase extends AbstractPicoContainerTest {
063
064 protected MutablePicoContainer createPicoContainer(PicoContainer parent) {
065 return new DefaultPicoContainer(parent);
066 }
067
068 protected Properties[] getProperties() {
069 return new Properties[0];
070 }
071
072 @Test public void testInstantiationWithNullComponentFactory() {
073 try {
074 new DefaultPicoContainer((ComponentFactory) null, null);
075 fail("NPE expected");
076 } catch (NullPointerException e) {
077 // expected
078 }
079 }
080
081 @Test public void testUpDownDependenciesCannotBeFollowed() {
082 MutablePicoContainer parent = createPicoContainer(null);
083 MutablePicoContainer child = createPicoContainer(parent);
084
085 // ComponentF -> ComponentA -> ComponentB+C
086 child.addComponent(ComponentF.class);
087 parent.addComponent(ComponentA.class);
088 child.addComponent(ComponentB.class);
089 child.addComponent(ComponentC.class);
090
091 try {
092 child.getComponent(ComponentF.class);
093 fail("Thrown "
094 + AbstractInjector.UnsatisfiableDependenciesException.class
095 .getName() + " expected");
096 } catch (final AbstractInjector.UnsatisfiableDependenciesException e) {
097 assertEquals(ComponentB.class, e.getUnsatisfiedDependencyType());
098 }
099
100 }
101
102 @Test public void testComponentsCanBeRemovedByInstance() {
103 MutablePicoContainer pico = createPicoContainer(null);
104 pico.addComponent(HashMap.class);
105 pico.addComponent(ArrayList.class);
106 List list = pico.getComponent(List.class);
107 pico.removeComponentByInstance(list);
108 assertEquals(1, pico.getComponentAdapters().size());
109 assertEquals(1, pico.getComponents().size());
110 assertEquals(HashMap.class, pico.getComponent(Serializable.class)
111 .getClass());
112 }
113
114 @Test public void testComponentInstancesListIsReturnedForNullType() {
115 MutablePicoContainer pico = createPicoContainer(null);
116 List componentInstances = pico.getComponents(null);
117 assertNotNull(componentInstances);
118 assertEquals(0, componentInstances.size());
119 }
120
121 @Test public void testComponentsWithCommonSupertypeWhichIsAConstructorArgumentCanBeLookedUpByConcreteType() {
122 MutablePicoContainer pico = createPicoContainer(null);
123 pico.addComponent(LinkedList.class, LinkedList.class, Parameter.ZERO);
124 pico.addComponent(ArrayList.class);
125 assertEquals(ArrayList.class, pico
126 .getComponent((Class) ArrayList.class).getClass());
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(),
198 new NullLifecycleStrategy(), false));
199 TransientComponent c1 = picoContainer
200 .getComponent(TransientComponent.class);
201 TransientComponent c2 = picoContainer
202 .getComponent(TransientComponent.class);
203 assertNotSame(c1, c2);
204 assertSame(c1.service, c2.service);
205 }
206
207 public static class DependsOnCollection {
208 public DependsOnCollection(Collection c) {
209 }
210 }
211
212 @Test public void testShouldProvideInfoAboutDependingWhenAmbiguityHappens() {
213 MutablePicoContainer pico = this.createPicoContainer(null);
214 pico.addComponent(new ArrayList());
215 pico.addComponent(new LinkedList());
216 pico.addComponent(DependsOnCollection.class);
217 try {
218 pico.getComponent(DependsOnCollection.class);
219 fail();
220 } catch (AbstractInjector.AmbiguousComponentResolutionException expected) {
221 String doc = DependsOnCollection.class.getName();
222 assertEquals(
223 "class "
224 + doc
225 + " 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",
226 expected.getMessage());
227 }
228 }
229
230 @Test public void testInstantiationWithMonitorAndParent() {
231 StringWriter writer = new StringWriter();
232 ComponentMonitor monitor = new WriterComponentMonitor(writer);
233 DefaultPicoContainer parent = new DefaultPicoContainer();
234 DefaultPicoContainer child = new DefaultPicoContainer(monitor, parent);
235 parent.addComponent("st", SimpleTouchable.class);
236 child.addComponent("dot", DependsOnTouchable.class);
237 DependsOnTouchable dot = (DependsOnTouchable) child.getComponent("dot");
238 assertNotNull(dot);
239 assertTrue("writer not empty", writer.toString().length() > 0);
240
241 }
242
243 @Test
244 public void testRepresentationOfContainerTree() {
245 StringWriter writer = new StringWriter();
246 DefaultPicoContainer parent = new DefaultPicoContainer();
247 parent.setName("parent");
248 DefaultPicoContainer child = new DefaultPicoContainer(parent);
249 child.setName("child");
250 parent.addComponent("st", SimpleTouchable.class);
251 child.addComponent("dot", DependsOnTouchable.class);
252 assertEquals("child:1<I<parent:1<|", child.toString());
253 }
254
255 @SuppressWarnings("serial")
256 @Test public void testStartCapturedByMonitor() {
257 final StringBuffer sb = new StringBuffer();
258 DefaultPicoContainer dpc = new DefaultPicoContainer(
259 new NullComponentMonitor() {
260 public void invoking(PicoContainer container,
261 ComponentAdapter componentAdapter, Member member,
262 Object instance) {
263 sb.append(member.toString());
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 componentAdapterType) {
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 testCanUseCustomLifecycleStrategyForClassRegistrations() {
460 DefaultPicoContainer dpc = new DefaultPicoContainer(
461 new FailingLifecycleStrategy(), null);
462 dpc.as(Characteristics.CACHE).addComponent(Startable.class,
463 MyStartable.class);
464 try {
465 dpc.start();
466 fail("should have barfed");
467 } catch (RuntimeException e) {
468 assertEquals("foo", e.getMessage());
469 }
470 }
471
472 @Test public void testCanUseCustomLifecycleStrategyForInstanceRegistrations() {
473 DefaultPicoContainer dpc = new DefaultPicoContainer(
474 new FailingLifecycleStrategy(), null);
475 Startable myStartable = new MyStartable();
476 dpc.addComponent(Startable.class, myStartable);
477 try {
478 dpc.start();
479 fail("should have barfed");
480 } catch (RuntimeException e) {
481 assertEquals("foo", e.getMessage());
482 }
483 }
484
485 public static class FailingLifecycleStrategy implements LifecycleStrategy {
486 public void start(Object component) {
487 throw new RuntimeException("foo");
488 }
489
490 public void stop(Object component) {
491 }
492
493 public void dispose(Object component) {
494 }
495
496 public boolean hasLifecycle(Class type) {
497 return true;
498 }
499
500 }
501
502 public static class MyStartable implements Startable {
503 public MyStartable() {
504 }
505
506 public void start() {
507 }
508
509 public void stop() {
510 }
511 }
512
513 public static interface A {
514
515 }
516
517 public static class SimpleA implements A {
518
519 }
520
521 public static class WrappingA implements A {
522 private final A wrapped;
523
524 public WrappingA(A wrapped) {
525 this.wrapped = wrapped;
526 }
527 }
528
529 @Test public void testCanRegisterTwoComponentsImplementingSameInterfaceOneWithInterfaceAsKey()
530 throws Exception {
531 MutablePicoContainer container = createPicoContainer(null);
532
533 container.addComponent(SimpleA.class);
534 container.addComponent(A.class, WrappingA.class);
535
536 container.start();
537
538 assertEquals(WrappingA.class, container.getComponent(A.class)
539 .getClass());
540 }
541
542 @Test public void testCanRegisterTwoComponentsWithSameImplementionAndDifferentKey()
543 throws Exception {
544 MutablePicoContainer container = createPicoContainer(null);
545
546 container.addComponent(SimpleA.class);
547 container.addComponent("A", SimpleA.class);
548
549 container.start();
550
551 assertNotNull(container.getComponent("A"));
552 assertNotNull(container.getComponent(SimpleA.class));
553 assertNotSame(container.getComponent("A"), container
554 .getComponent(SimpleA.class));
555 }
556
557 @Test public void testPicoCanDifferentiateBetweenNamedStringsThatWouldOtherwiseBeAmbiguous() {
558 MutablePicoContainer mpc = createPicoContainer(null);
559 mpc.addComponent("greeting", "1");
560 mpc.addComponent("message", "2");
561 mpc.as(Characteristics.USE_NAMES).addComponent(
562 PicoCompositionException.class, PicoCompositionException.class);
563 assertEquals("2", mpc.getComponent(PicoCompositionException.class)
564 .getMessage());
565 }
566
567 @Test public void testPicoCanDifferentiateBetweenNamedObjectsThatWouldOtherwiseBeAmbiguous() {
568 MutablePicoContainer mpc = createPicoContainer(null);
569 Horse dobbin = new Horse();
570 Horse redRum = new Horse();
571 mpc.addComponent("dobbin", dobbin);
572 mpc.addComponent("horse", redRum);
573 mpc.as(Characteristics.USE_NAMES).addComponent(CdiTurtle.class);
574 assertEquals(redRum, mpc.getComponent(CdiTurtle.class).horse);
575 }
576
577 @Test public void testPicoCanDifferentiateBetweenNamedIntsThatWouldOtherwiseBeAmbiguous() {
578 MutablePicoContainer mpc = createPicoContainer(null);
579 mpc.addComponent("one", 1);
580 mpc.addComponent("two", 2);
581 mpc.as(Characteristics.USE_NAMES).addComponent(NeedsTwo.class);
582 assertEquals(2, mpc.getComponent(NeedsTwo.class).two);
583 }
584
585 public static class ListComponentsInStartClass implements Startable {
586 private MutablePicoContainer _pico;
587
588 public void start() {
589 List<SimpleTouchable> cps = _pico
590 .getComponents(SimpleTouchable.class);
591 assertNotNull(cps);
592 }
593
594 public void stop() {
595 }
596
597 }
598
599 /**
600 * JIRA: PICO-295 reported by Erik Putrycz
601 */
602 @Test public void testListComponentsInStart() {
603 DefaultPicoContainer dpc = new DefaultPicoContainer();
604 dpc.addComponent(SimpleTouchable.class);
605 ListComponentsInStartClass cl = new ListComponentsInStartClass();
606 cl._pico = dpc;
607 dpc.addComponent(cl);
608 dpc.start();
609 }
610
611 public static class NeedsTwo {
612 private final int two;
613
614 public NeedsTwo(Integer two) {
615 this.two = two;
616 }
617 }
618
619 public static class Horse {
620 }
621
622 public static class CdiTurtle {
623 public final Horse horse;
624
625 public CdiTurtle(Horse horse) {
626 this.horse = horse;
627 }
628 }
629
630 public static class SdiDonkey {
631 public Horse horse;
632
633 public void setHorse(Horse horse) {
634 this.horse = horse;
635 }
636 }
637
638 public static class SdiRabbit {
639 public Horse horse;
640
641 public void setHorse(Horse horse) {
642 this.horse = horse;
643 }
644 }
645
646 @Test public void testMixingOfSDIandCDI() {
647
648 MutablePicoContainer container = createPicoContainer(null).change(
649 Characteristics.CACHE);
650 container.addComponent(Horse.class);
651 container.change(SDI);
652 container.addComponent(SdiDonkey.class);
653 container.addComponent(SdiRabbit.class);
654 container.change(CDI);
655 container.addComponent(CdiTurtle.class);
656
657 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
658 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
659 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
660
661 assertions(donkey, rabbit, turtle);
662 }
663
664 @Test public void testMixingOfSDIandCDIDifferently() {
665
666 MutablePicoContainer container = createPicoContainer(null).change(
667 Characteristics.CACHE);
668 container.addComponent(Horse.class);
669 container.addComponent(CdiTurtle.class);
670 container.change(SDI);
671 container.addComponent(SdiDonkey.class);
672 container.addComponent(SdiRabbit.class);
673
674 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
675 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
676 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
677
678 assertions(donkey, rabbit, turtle);
679 }
680
681 @Test public void testMixingOfSDIandCDIInBuilderStyle() {
682
683 MutablePicoContainer container = createPicoContainer(null).change(
684 Characteristics.CACHE);
685 container.addComponent(Horse.class).change(SDI).addComponent(
686 SdiDonkey.class).addComponent(SdiRabbit.class).change(CDI)
687 .addComponent(CdiTurtle.class);
688
689 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
690 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
691 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
692
693 assertions(donkey, rabbit, turtle);
694 }
695
696 private void assertions(SdiDonkey donkey, SdiRabbit rabbit, CdiTurtle turtle) {
697 assertNotNull(rabbit);
698 assertNotNull(donkey);
699 assertNotNull(turtle);
700 assertNotNull(turtle.horse);
701 assertNotNull(donkey.horse);
702 assertNotNull(rabbit.horse);
703 assertSame(donkey.horse, turtle.horse);
704 assertSame(rabbit.horse, turtle.horse);
705 }
706
707 @Test public void testMixingOfSDIandCDIWithTemporaryCharacterizations() {
708
709 MutablePicoContainer container = createPicoContainer(null).change(
710 Characteristics.CACHE);
711 container.addComponent(Horse.class);
712 container.addComponent(CdiTurtle.class);
713 container.as(SDI).addComponent(SdiDonkey.class);
714 container.as(SDI).addComponent(SdiRabbit.class);
715
716 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
717 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
718 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
719
720 assertions(donkey, rabbit, turtle);
721 }
722
723 @Test public void testMixingOfSDIandCDIWithTemporaryCharacterizationsDifferently() {
724
725 MutablePicoContainer container = createPicoContainer(null).change(
726 Characteristics.CACHE);
727 container.as(SDI).addComponent(SdiDonkey.class);
728 container.as(SDI).addComponent(SdiRabbit.class);
729 container.addComponent(Horse.class);
730 container.addComponent(CdiTurtle.class);
731
732 SdiDonkey donkey = container.getComponent(SdiDonkey.class);
733 SdiRabbit rabbit = container.getComponent(SdiRabbit.class);
734 CdiTurtle turtle = container.getComponent(CdiTurtle.class);
735
736 assertions(donkey, rabbit, turtle);
737 }
738
739 @Test public void testChainingOfTemporaryCharacterizationsIsNotAllowed() {
740
741 MutablePicoContainer container = createPicoContainer(null);
742 try {
743 container.as(Characteristics.CACHE).as(SDI).addComponent(HashMap.class);
744 fail("shoulf barf");
745 } catch (PicoCompositionException e) {
746 assertTrue(e.getMessage().contains("as(FOO).as(BAR)"));
747 }
748 }
749
750 @SuppressWarnings("serial")
751 @Test public void testNoComponentIsMonitoredAndPotentiallyLateProvided() {
752 final String[] missingKey = new String[1];
753
754 String foo = (String) new DefaultPicoContainer(
755 new NullComponentMonitor() {
756 public Object noComponentFound(
757 MutablePicoContainer container, Object componentKey) {
758 missingKey[0] = (String) componentKey;
759 return "foo";
760 }
761 }).getComponent("missingKey");
762
763 assertNotNull(missingKey[0]);
764 assertEquals("missingKey", missingKey[0]);
765 assertEquals("foo", foo);
766
767 }
768
769 @Test public void testThatComponentCannotBeRemovedFromStartedContainer() {
770 MutablePicoContainer container = createPicoContainer(null);
771 container.addComponent(Map.class, HashMap.class);
772 container.start();
773 try {
774 container.removeComponent(Map.class);
775 fail("should have barfed");
776 } catch (PicoCompositionException e) {
777 }
778 }
779
780 @Test public void testThatSimpleStringComponentIsAddedOnlyOnce() {
781 MutablePicoContainer container = createPicoContainer(null);
782 container.addComponent("foo bar");
783 assertEquals(1, container.getComponentAdapters().size());
784 }
785
786 @Test public void canInterceptImplementationViaNewInjectionFactoryMethodOnMonitor() {
787 DefaultPicoContainer dpc = new DefaultPicoContainer(new MyNullComponentMonitor());
788 dpc.addComponent(Collection.class, HashSet.class);
789 dpc.addComponent(List.class, ArrayList.class);
790 assertNotNull(dpc.getComponent(List.class));
791 assertEquals("doppleganger", dpc.getComponent(List.class).get(0));
792 }
793
794 @SuppressWarnings("serial")
795 private static class MyNullComponentMonitor extends NullComponentMonitor {
796 public AbstractInjector newInjectionFactory(AbstractInjector abstractInjector) {
797 if (abstractInjector.getComponentKey() == List.class) {
798 return new AbstractInjector(List.class, ArrayList.class, Parameter.DEFAULT, MyNullComponentMonitor.this, null, false) {
799 public Object getComponentInstance(PicoContainer container) throws PicoCompositionException {
800 return getComponentInstance(container, null);
801 }
802
803 public Object getComponentInstance(PicoContainer container, Type into) throws PicoCompositionException {
804 ArrayList list = new ArrayList();
805 list.add("doppleganger");
806 return list;
807 }
808
809 public void decorateComponentInstance(PicoContainer container, Type into, Object instance) {
810 }
811 };
812 } else {
813 return abstractInjector;
814 }
815 }
816 }
817
818
819
820 }