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