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 * Original code by *
009 *****************************************************************************/
010 package org.picocontainer.defaults;
011
012 import org.picocontainer.ComponentAdapter;
013 import org.picocontainer.MutablePicoContainer;
014 import org.picocontainer.PicoContainer;
015 import org.picocontainer.PicoCompositionException;
016 import org.picocontainer.DefaultPicoContainer;
017 import org.picocontainer.behaviors.CachingBehaviorFactory;
018 import org.picocontainer.injectors.AbstractInjector;
019 import org.picocontainer.injectors.ConstructorInjector;
020 import org.picocontainer.injectors.AdaptiveInjectionFactory;
021 import org.picocontainer.monitors.NullComponentMonitor;
022 import org.picocontainer.lifecycle.NullLifecycleStrategy;
023 import org.picocontainer.parameters.CollectionComponentParameter;
024 import org.picocontainer.parameters.ComponentParameter;
025 import org.picocontainer.adapters.InstanceAdapter;
026 import org.picocontainer.testmodel.SimpleTouchable;
027 import org.picocontainer.testmodel.Touchable;
028
029 import org.jmock.Mock;
030 import org.jmock.MockObjectTestCase;
031
032 import java.util.Arrays;
033 import java.util.Collection;
034 import java.util.Collections;
035 import java.util.HashSet;
036 import java.util.List;
037 import java.util.Map;
038 import java.util.Set;
039 import java.util.SortedMap;
040 import java.util.SortedSet;
041
042
043 /**
044 * @author Aslak Hellesøy
045 * @author Jörg Schaible
046 * @version $Revision: 3714 $
047 */
048 public class CollectionComponentParameterTestCase
049 extends MockObjectTestCase {
050
051 public void testShouldInstantiateArrayOfStrings() {
052 CollectionComponentParameter ccp = new CollectionComponentParameter();
053
054 Mock componentAdapterMock = mock(ComponentAdapter.class);
055 componentAdapterMock.expects(atLeastOnce()).method("getComponentKey").will(returnValue("x"));
056 Mock containerMock = mock(PicoContainer.class);
057 containerMock.expects(once()).method("getComponentAdapters").withNoArguments().will(returnValue(new HashSet()));
058 containerMock.expects(once()).method("getComponentAdapters").with(eq(String.class)).will(
059 returnValue(Arrays.asList(new InstanceAdapter("y", "Hello", new NullLifecycleStrategy(),
060 new NullComponentMonitor()), new InstanceAdapter("z", "World", new NullLifecycleStrategy(),
061 new NullComponentMonitor()))));
062 containerMock.expects(once()).method("getComponent").with(eq("z")).will(returnValue("World"));
063 containerMock.expects(once()).method("getComponent").with(eq("y")).will(returnValue("Hello"));
064 containerMock.expects(once()).method("getParent").withNoArguments().will(returnValue(null));
065
066 List expected = Arrays.asList("Hello", "World");
067 Collections.sort(expected);
068 List actual = Arrays.asList((Object[]) ccp.resolveInstance(
069 (PicoContainer) containerMock.proxy(), (ComponentAdapter) componentAdapterMock.proxy(), String[].class, null));
070 Collections.sort(actual);
071 assertEquals(expected, actual);
072 }
073
074 static public interface Fish {
075 }
076
077 static public class Cod
078 implements Fish {
079 public String toString() {
080 return "Cod";
081 }
082 }
083
084 static public class Shark
085 implements Fish {
086 public String toString() {
087 return "Shark";
088 }
089 }
090
091 static public class Bowl {
092 private final Cod[] cods;
093 private final Fish[] fishes;
094
095 public Bowl(Cod cods[], Fish fishes[]) {
096 this.cods = cods;
097 this.fishes = fishes;
098 }
099 }
100
101 private MutablePicoContainer getDefaultPicoContainer() {
102 MutablePicoContainer mpc = new DefaultPicoContainer(new CachingBehaviorFactory());
103 mpc.addComponent(Bowl.class);
104 mpc.addComponent(Cod.class);
105 mpc.addComponent(Shark.class);
106 return mpc;
107 }
108
109 public void testNativeArrays() {
110 MutablePicoContainer mpc = getDefaultPicoContainer();
111 Cod cod = mpc.getComponent(Cod.class);
112 Bowl bowl = mpc.getComponent(Bowl.class);
113 assertEquals(1, bowl.cods.length);
114 assertEquals(2, bowl.fishes.length);
115 assertSame(cod, bowl.cods[0]);
116 assertNotSame(bowl.fishes[0], bowl.fishes[1]);
117 }
118
119 public void testCollectionsAreGeneratedOnTheFly() {
120 MutablePicoContainer mpc = new DefaultPicoContainer();
121 mpc.addAdapter(new ConstructorInjector(Bowl.class, Bowl.class, null, new NullComponentMonitor(), new NullLifecycleStrategy()));
122 mpc.addComponent(Cod.class);
123 Bowl bowl = mpc.getComponent(Bowl.class);
124 assertEquals(1, bowl.cods.length);
125 mpc.addComponent("Nemo", new Cod());
126 bowl = mpc.getComponent(Bowl.class);
127 assertEquals(2, bowl.cods.length);
128 assertNotSame(bowl.cods[0], bowl.cods[1]);
129 }
130
131 static public class CollectedBowl {
132 private final Cod[] cods;
133 private final Fish[] fishes;
134
135 public CollectedBowl(Collection cods, Collection fishes) {
136 this.cods = (Cod[]) cods.toArray(new Cod[cods.size()]);
137 this.fishes = (Fish[]) fishes.toArray(new Fish[fishes.size()]);
138 }
139 }
140
141 public void testCollections() {
142 MutablePicoContainer mpc = new DefaultPicoContainer(new CachingBehaviorFactory());
143 mpc.addComponent(CollectedBowl.class, CollectedBowl.class,
144 new ComponentParameter(Cod.class, false), new ComponentParameter(Fish.class, false));
145 mpc.addComponent(Cod.class);
146 mpc.addComponent(Shark.class);
147 Cod cod = mpc.getComponent(Cod.class);
148 CollectedBowl bowl = mpc.getComponent(CollectedBowl.class);
149 assertEquals(1, bowl.cods.length);
150 assertEquals(2, bowl.fishes.length);
151 assertSame(cod, bowl.cods[0]);
152 assertNotSame(bowl.fishes[0], bowl.fishes[1]);
153 }
154
155 static public class MappedBowl {
156 private final Fish[] fishes;
157
158 public MappedBowl(Map map) {
159 Collection collection = map.values();
160 this.fishes = (Fish[]) collection.toArray(new Fish[collection.size()]);
161 }
162 }
163
164 public void testMaps() {
165 MutablePicoContainer mpc = new DefaultPicoContainer();
166 mpc.addComponent(MappedBowl.class, MappedBowl.class, new ComponentParameter(
167 Fish.class, false));
168 mpc.addComponent(Cod.class);
169 mpc.addComponent(Shark.class);
170 MappedBowl bowl = mpc.getComponent(MappedBowl.class);
171 assertEquals(2, bowl.fishes.length);
172 assertNotSame(bowl.fishes[0], bowl.fishes[1]);
173 }
174
175 public static class UngenericCollectionBowl {
176 public UngenericCollectionBowl(Collection fish) {
177 }
178 }
179
180 public void testShouldNotInstantiateCollectionForUngenericCollectionParameters() {
181 MutablePicoContainer pico = getDefaultPicoContainer();
182 pico.addComponent(UngenericCollectionBowl.class);
183 try {
184 pico.getComponent(UngenericCollectionBowl.class);
185 fail();
186 } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
187 // expected
188 }
189 }
190
191 public static class AnotherGenericCollectionBowl {
192 private final String[] strings;
193
194 public AnotherGenericCollectionBowl(String[] strings) {
195 this.strings = strings;
196 }
197
198 public String[] getStrings() {
199 return strings;
200 }
201 }
202
203 public void testShouldFailWhenThereAreNoComponentsToPutInTheArray() {
204 MutablePicoContainer pico = getDefaultPicoContainer();
205 pico.addComponent(AnotherGenericCollectionBowl.class);
206 try {
207 pico.getComponent(AnotherGenericCollectionBowl.class);
208 fail();
209 } catch (AbstractInjector.UnsatisfiableDependenciesException e) {
210 // expected
211 }
212 }
213
214 public void testAllowsEmptyArraysIfEspeciallySet() {
215 MutablePicoContainer pico = getDefaultPicoContainer();
216 pico.addComponent(
217 AnotherGenericCollectionBowl.class, AnotherGenericCollectionBowl.class,
218 ComponentParameter.ARRAY_ALLOW_EMPTY);
219 AnotherGenericCollectionBowl bowl = pico
220 .getComponent(AnotherGenericCollectionBowl.class);
221 assertNotNull(bowl);
222 assertEquals(0, bowl.strings.length);
223 }
224
225 public static class TouchableObserver
226 implements Touchable {
227 private final Touchable[] touchables;
228
229 public TouchableObserver(Touchable[] touchables) {
230 this.touchables = touchables;
231
232 }
233
234 public void touch() {
235 for (Touchable touchable : touchables) {
236 touchable.touch();
237 }
238 }
239 }
240
241 public void testWillOmitSelfFromCollection() {
242 MutablePicoContainer pico = getDefaultPicoContainer();
243 pico.addComponent(SimpleTouchable.class);
244 pico.addComponent(TouchableObserver.class);
245 Touchable observer = pico.getComponent(TouchableObserver.class);
246 assertNotNull(observer);
247 observer.touch();
248 SimpleTouchable touchable = pico.getComponent(SimpleTouchable.class);
249 assertTrue(touchable.wasTouched);
250 }
251
252 public void testWillRemoveComponentsWithMatchingKeyFromParent() {
253 MutablePicoContainer parent = new DefaultPicoContainer();
254 parent.addComponent("Tom", Cod.class);
255 parent.addComponent("Dick", Cod.class);
256 parent.addComponent("Harry", Cod.class);
257 MutablePicoContainer child = new DefaultPicoContainer(parent);
258 child.addComponent("Dick", Shark.class);
259 child.addComponent(Bowl.class);
260 Bowl bowl = child.getComponent(Bowl.class);
261 assertEquals(3, bowl.fishes.length);
262 assertEquals(2, bowl.cods.length);
263 }
264
265 public void testBowlWithoutTom() {
266 MutablePicoContainer mpc = new DefaultPicoContainer();
267 mpc.addComponent("Tom", Cod.class);
268 mpc.addComponent("Dick", Cod.class);
269 mpc.addComponent("Harry", Cod.class);
270 mpc.addComponent(Shark.class);
271 mpc.addComponent(CollectedBowl.class, CollectedBowl.class, new CollectionComponentParameter(Cod.class, false) {
272 protected boolean evaluate(ComponentAdapter adapter) {
273 return !"Tom".equals(adapter.getComponentKey());
274 }
275 },
276 new CollectionComponentParameter(Fish.class, false));
277 CollectedBowl bowl = mpc.getComponent(CollectedBowl.class);
278 Cod tom = (Cod) mpc.getComponent("Tom");
279 assertEquals(4, bowl.fishes.length);
280 assertEquals(2, bowl.cods.length);
281 assertFalse(Arrays.asList(bowl.cods).contains(tom));
282 }
283
284 public static class DependsOnAll {
285 public DependsOnAll(Set set, SortedSet sortedSet, Collection collection, List list, SortedMap sortedMap, Map map
286 // , ConcurrentMap concurrentMap, Queue queue, BlockingQueue blockingQueue
287 ) {
288 assertNotNull(set);
289 assertNotNull(sortedSet);
290 assertNotNull(collection);
291 assertNotNull(list);
292 assertNotNull(sortedMap);
293 assertNotNull(map);
294 // assertNotNull(concurrentMap);
295 // assertNotNull(queue);
296 // assertNotNull(blockingQueue);
297 }
298 }
299
300 public void testDifferentCollectiveTypesAreResolved() {
301 MutablePicoContainer pico = new DefaultPicoContainer();
302 CollectionComponentParameter parameter = new CollectionComponentParameter(Fish.class, true);
303 pico.addComponent(DependsOnAll.class, DependsOnAll.class,
304 parameter, parameter, parameter, parameter, parameter, parameter);
305 assertNotNull(pico.getComponent(DependsOnAll.class));
306 }
307
308 public void testVerify() {
309 MutablePicoContainer pico = new DefaultPicoContainer();
310 CollectionComponentParameter parameterNonEmpty = CollectionComponentParameter.ARRAY;
311 pico.addComponent(Shark.class);
312 parameterNonEmpty.verify(pico, null, Fish[].class, null);
313 try {
314 parameterNonEmpty.verify(pico, null, Cod[].class, null);
315 fail("(PicoCompositionException expected");
316 } catch (PicoCompositionException e) {
317 assertTrue(e.getMessage().indexOf(Cod.class.getName())>0);
318 }
319 CollectionComponentParameter parameterEmpty = CollectionComponentParameter.ARRAY_ALLOW_EMPTY;
320 parameterEmpty.verify(pico, null, Fish[].class, null);
321 parameterEmpty.verify(pico, null, Cod[].class, null);
322 }
323
324 // PICO-243 : this test will fail if executed on jdk1.3 without commons-collections
325 public void testOrderOfElementsOfAnArrayDependencyIsPreserved() {
326 MutablePicoContainer pico = new DefaultPicoContainer();
327 pico.addComponent("first", "first");
328 pico.addComponent("second", "second");
329 pico.addComponent("third", "third");
330 pico.addComponent("fourth", "fourth");
331 pico.addComponent("fifth", "fifth");
332 pico.addComponent(Truc.class);
333
334 final List strings = pico.getComponents(String.class);
335 assertEquals("first", strings.get(0));
336 assertEquals("second", strings.get(1));
337 assertEquals("third", strings.get(2));
338 assertEquals("fourth", strings.get(3));
339 assertEquals("fifth", strings.get(4));
340
341 pico.getComponent(Truc.class);
342 }
343
344 public static final class Truc {
345 public Truc(String[] s) {
346 assertEquals("first", s[0]);
347 assertEquals("second", s[1]);
348 assertEquals("third", s[2]);
349 assertEquals("fourth", s[3]);
350 assertEquals("fifth", s[4]);
351 }
352 }
353
354 }