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 *****************************************************************************/
010package org.picocontainer.behaviors;
011
012
013import static org.junit.Assert.assertEquals;
014import static org.junit.Assert.assertNotNull;
015import static org.junit.Assert.fail;
016
017import java.io.File;
018import java.net.MalformedURLException;
019import java.net.URL;
020import java.text.SimpleDateFormat;
021import java.util.Date;
022import java.util.HashMap;
023import java.util.Map;
024import java.util.Properties;
025
026import javax.swing.JLabel;
027
028import org.junit.Test;
029import org.picocontainer.Characteristics;
030import org.picocontainer.ComponentAdapter;
031import org.picocontainer.ComponentFactory;
032import org.picocontainer.DefaultPicoContainer;
033import org.picocontainer.Parameter;
034import org.picocontainer.PicoCompositionException;
035import org.picocontainer.injectors.AdaptingInjection;
036import org.picocontainer.lifecycle.NullLifecycleStrategy;
037import org.picocontainer.monitors.NullComponentMonitor;
038import org.picocontainer.tck.AbstractComponentFactoryTest;
039import org.picocontainer.testmodel.SimpleTouchable;
040import org.picocontainer.testmodel.Touchable;
041
042
043/**
044 * @author Aslak Hellesøy
045 * @author Mirko Novakovic
046 */
047public class PropertyApplyingTestCase extends AbstractComponentFactoryTest {
048
049    public static class Foo {
050        public String message;
051
052        public void setMessage(String message) {
053            this.message = message;
054        }
055    }
056
057    public static class Failing {
058        public void setMessage(String message) {
059            throw new ArrayIndexOutOfBoundsException();
060        }
061    }
062
063    /**
064     * Class that contains all types of Java primitives, to test if they are
065     * set correctly.
066     *
067     * @author Mirko Novakovic
068     */
069    public static class Primitives {
070        public byte byte_;
071        public short short_;
072        public int int_;
073        public long long_;
074        public float float_;
075        public double double_;
076        public boolean boolean_;
077        public char char_;
078        public File file_;
079        public URL url_;
080        public Class class_;
081        public String string_;
082
083        public void setClass_(Class class_) {
084            this.class_ = class_;
085        }
086
087        public void setString_(String string_) {
088            this.string_ = string_;
089        }
090
091        public void setBoolean_(boolean boolean_) {
092            this.boolean_ = boolean_;
093        }
094
095        public void setByte_(byte byte_) {
096            this.byte_ = byte_;
097        }
098
099        public void setChar_(char char_) {
100            this.char_ = char_;
101        }
102
103        public void setDouble_(double double_) {
104            this.double_ = double_;
105        }
106
107        public void setFloat_(float float_) {
108            this.float_ = float_;
109        }
110
111        public void setInt_(int int_) {
112            this.int_ = int_;
113        }
114
115        public void setLong_(long long_) {
116            this.long_ = long_;
117        }
118
119        public void setShort_(short short_) {
120            this.short_ = short_;
121        }
122
123        public void setFile_(File file_) {
124            this.file_ = file_;
125        }
126
127        public void setUrl_(URL url_) {
128            this.url_ = url_;
129        }
130    }
131
132    public static class A {
133        private B b;
134
135        public void setB(B b) {
136            this.b = b;
137        }
138    }
139
140    public static class B {
141    }
142
143    @Test public void testSetProperties() {
144        ComponentAdapter adapter = createAdapterCallingSetMessage(Foo.class);
145        Foo foo = (Foo)adapter.getComponentInstance(null, ComponentAdapter.NOTHING.class);
146        assertNotNull(foo);
147        assertEquals("hello", foo.message);
148    }
149
150    @Test public void testFailingSetter() {
151        ComponentAdapter adapter = createAdapterCallingSetMessage(Failing.class);
152        try {
153            adapter.getComponentInstance(null, ComponentAdapter.NOTHING.class);
154            fail();
155        } catch (PicoCompositionException e) {
156        }
157    }
158
159    protected ComponentFactory createComponentFactory() {
160        return new PropertyApplying().wrap(new AdaptingInjection());
161    }
162
163    @Test public void testPropertiesSetAfterAdapterCreationShouldBeTakenIntoAccount() {
164        PropertyApplying factory = (PropertyApplying)createComponentFactory();
165
166        PropertyApplicator adapter =
167            (PropertyApplicator)factory.createComponentAdapter(new NullComponentMonitor(),
168                                                                     new NullLifecycleStrategy(),
169                                                                     new Properties(Characteristics
170                                                                         .CDI),
171                                                                     "foo",
172                                                                     Foo.class,
173                                                                     (Parameter[])null);
174
175        Map properties = new HashMap();
176        properties.put("message", "hello");
177        adapter.setProperties(properties);
178
179        Foo foo = (Foo)adapter.getComponentInstance(null, ComponentAdapter.NOTHING.class);
180
181        assertEquals("hello", foo.message);
182    }
183
184    @Test public void testPropertySetAfterAdapterCreationShouldBeTakenIntoAccount() {
185        PropertyApplying factory = (PropertyApplying)createComponentFactory();
186
187        PropertyApplicator adapter =
188            (PropertyApplicator)factory.createComponentAdapter(new NullComponentMonitor(),
189                                                                     new NullLifecycleStrategy(),
190                                                                     new Properties(Characteristics
191                                                                         .CDI),
192                                                                     "foo",
193                                                                     Foo.class,
194                                                                     (Parameter[])null);
195        adapter.setProperty("message", "hello");
196
197        Foo foo = (Foo)adapter.getComponentInstance(null, ComponentAdapter.NOTHING.class);
198
199        assertEquals("hello", foo.message);
200    }
201
202
203    @Test public void testPropertiesTidiedUpAfterPicoUsage() {
204        DefaultPicoContainer pico = new DefaultPicoContainer(createComponentFactory());
205        pico.as(Characteristics.PROPERTY_APPLYING).addComponent("foo", Foo.class);
206        Foo foo = (Foo) pico.getComponent("foo");
207    }
208
209
210    @Test public void testDelegateIsAccessible() {
211        AbstractBehavior componentAdapter =
212            (AbstractBehavior)createComponentFactory().createComponentAdapter(new NullComponentMonitor(),
213                                                                              new NullLifecycleStrategy(),
214                                                                              new Properties(Characteristics
215                                                                                  .CDI),
216                                                                              Touchable.class,
217                                                                              SimpleTouchable.class,
218                                                                              (Parameter[])null);
219
220        assertNotNull(componentAdapter.getDelegate());
221    }
222
223    private ComponentAdapter createAdapterCallingSetMessage(Class impl) {
224        PropertyApplying factory = (PropertyApplying)createComponentFactory();
225
226        Map properties = new HashMap();
227        properties.put("message", "hello");
228
229        PropertyApplicator adapter =
230            (PropertyApplicator)factory.createComponentAdapter(new NullComponentMonitor(),
231                                                                     new NullLifecycleStrategy(),
232                                                                     new Properties(Characteristics
233                                                                         .CDI),
234                                                                     impl,
235                                                                     impl,
236                                                                     (Parameter[])null);
237        adapter.setProperties(properties);
238        return adapter;
239    }
240
241    @Test public void testAllJavaPrimitiveAttributesShouldBeSetByTheAdapter() throws MalformedURLException {
242        PropertyApplying factory = (PropertyApplying)createComponentFactory();
243        Map properties = new HashMap();
244        properties.put("byte_", "1");
245        properties.put("short_", "2");
246        properties.put("int_", "3");
247        properties.put("long_", "4");
248        properties.put("float_", "5.0");
249        properties.put("double_", "6.0");
250        properties.put("char_", "a");
251        properties.put("boolean_", "true");
252        properties.put("file_", "/foo/bar");
253        properties.put("url_", "http://www.picocontainer.org/");
254        properties.put("string_", "g string");
255        properties.put("class_", "javax.swing.JLabel");
256        PropertyApplicator adapter =
257            (PropertyApplicator)factory.createComponentAdapter(new NullComponentMonitor(),
258                                                                     new NullLifecycleStrategy(),
259                                                                     new Properties(Characteristics
260                                                                         .CDI),
261                                                                     Primitives.class,
262                                                                     Primitives.class,
263                                                                     (Parameter[])null);
264        adapter.setProperties(properties);
265        Primitives primitives = (Primitives)adapter.getComponentInstance(null, ComponentAdapter.NOTHING.class);
266
267        assertNotNull(primitives);
268        assertEquals(1, primitives.byte_);
269        assertEquals(2, primitives.short_);
270        assertEquals(3, primitives.int_);
271        assertEquals(4, primitives.long_);
272        assertEquals(5.0, primitives.float_, 0.1);
273        assertEquals(6.0, primitives.double_, 0.1);
274        assertEquals('a', primitives.char_);
275        assertEquals(true, primitives.boolean_);
276        assertEquals(new File("/foo/bar"), primitives.file_);
277        assertEquals(new URL("http://www.picocontainer.org/"), primitives.url_);
278        assertEquals("g string", primitives.string_);
279        assertEquals(JLabel.class, primitives.class_);
280    }
281
282    @Test public void testSetDependenComponentWillBeSetByTheAdapter() {
283        picoContainer.addComponent("b", B.class);
284        PropertyApplying factory = (PropertyApplying)createComponentFactory();
285        Map properties = new HashMap();
286
287        // the second b is the key of the B implementation
288        properties.put("b", "b");
289        PropertyApplicator adapter =
290            (PropertyApplicator)factory.createComponentAdapter(new NullComponentMonitor(),
291                                                                     new NullLifecycleStrategy(),
292                                                                     new Properties(Characteristics
293                                                                         .CDI),
294                                                                     A.class,
295                                                                     A.class,
296                                                                     (Parameter[])null);
297        adapter.setProperties(properties);
298        picoContainer.addAdapter(adapter);
299        A a = picoContainer.getComponent(A.class);
300
301        assertNotNull(a);
302        assertNotNull(a.b);
303    }
304
305    @Test public void testPropertySetAfterWrappedAdapterCreationShouldBeTakenIntoAccount() {
306        Caching factory = (Caching) new Caching().wrap(createComponentFactory());
307
308        ComponentAdapter<?> adapter =
309            factory.createComponentAdapter(new NullComponentMonitor(),
310                                                                     new NullLifecycleStrategy(),
311                                                                     new Properties(Characteristics
312                                                                         .CDI),
313                                                                     "foo",
314                                                                     Foo.class,
315                                                                     (Parameter[])null);
316
317
318        PropertyApplicator pa = adapter.findAdapterOfType(PropertyApplicator.class);
319
320        pa.setProperty("message", "hello");
321
322        Foo foo = (Foo)adapter.getComponentInstance(null, ComponentAdapter.NOTHING.class);
323
324        assertEquals("hello", foo.message);
325    }
326
327    @Test public void testSetBeanPropertiesWithValueObjects() {
328        PropertyApplying factory = (PropertyApplying)createComponentFactory();
329
330        Map properties = new HashMap();
331        properties.put("lenient", Boolean.FALSE);
332        properties.put("2DigitYearStart", new Date(0));
333
334        PropertyApplicator adapter =
335            (PropertyApplicator)factory.createComponentAdapter(new NullComponentMonitor(),
336                                                                     new NullLifecycleStrategy(),
337                                                                     new Properties(Characteristics
338                                                                         .CDI),
339                                                                     SimpleDateFormat.class,
340                                                                     SimpleDateFormat.class,
341                                                                     (Parameter[])null);
342        adapter.setProperties(properties);
343        picoContainer.addAdapter(adapter);
344
345
346        SimpleDateFormat dateFormat = picoContainer.getComponent(SimpleDateFormat.class);
347        assertNotNull(dateFormat);
348        assertEquals(false, dateFormat.isLenient());
349        assertEquals(new Date(0), dateFormat.get2DigitYearStart());
350    }
351
352
353    /** todo Is this test duplicated elsewhere?  --MR */
354    @Test public void testSetBeanPropertiesWithWrongNumberOfParametersThrowsPicoInitializationException() {
355        Object testBean = new Object() {
356            public void setMultiValues(String val1, String Val2) {
357                throw new IllegalStateException("Setter should never have been called");
358            }
359
360            public void setSomeString(String val1) {
361                throw new IllegalStateException("Setter should never have been called");
362            }
363        };
364
365        PropertyApplying factory = (PropertyApplying)createComponentFactory();
366
367
368        PropertyApplicator adapter =
369            (PropertyApplicator)factory.createComponentAdapter(new NullComponentMonitor(),
370                                                                     new NullLifecycleStrategy(),
371                                                                     new Properties(Characteristics
372                                                                         .CDI),
373                                                                     "TestBean",
374                                                                     testBean.getClass(),
375                                                                     (Parameter[])null);
376
377        Map properties = new HashMap();
378        properties.put("multiValues", "abcdefg");
379        adapter.setProperties(properties);
380
381        picoContainer.addAdapter(adapter);
382
383        try {
384            Object testResult = picoContainer.getComponent("TestBean");
385            fail(
386                "Getting a bad test result through PropertyApplicator should have thrown exception.  Instead got:" +
387                testResult);
388        } catch (PicoCompositionException ex) {
389            //A-ok
390        }
391
392    }
393
394
395    @Test public void testSetBeanPropertiesWithInvalidValueTypes() {
396        PropertyApplying factory = (PropertyApplying)createComponentFactory();
397
398
399        Map properties = new HashMap();
400
401        // Set two digit year to a boolean (should throw error)
402        properties.put("2DigitYearStart", Boolean.FALSE);
403        PropertyApplicator adapter =
404            (PropertyApplicator)factory.createComponentAdapter(new NullComponentMonitor(),
405                                                                     new NullLifecycleStrategy(),
406                                                                     new Properties(Characteristics
407                                                                         .CDI),
408                                                                     SimpleDateFormat.class,
409                                                                     SimpleDateFormat.class,
410                                                                     (Parameter[])null);
411        adapter.setProperties(properties);
412        picoContainer.addAdapter(adapter);
413
414
415        try {
416            SimpleDateFormat dateFormat = picoContainer.getComponent(SimpleDateFormat.class);
417            fail(
418                "Getting a bad test result through PropertyApplicator should have thrown exception.  Instead got:" +
419                dateFormat);
420        } catch (ClassCastException ex) {
421            //A-ok
422        }
423
424    }
425}