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