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    
013    import static org.junit.Assert.assertEquals;
014    import static org.junit.Assert.assertNotNull;
015    import static org.junit.Assert.fail;
016    
017    import java.io.File;
018    import java.net.MalformedURLException;
019    import java.net.URL;
020    import java.text.SimpleDateFormat;
021    import java.util.Date;
022    import java.util.HashMap;
023    import java.util.Map;
024    import java.util.Properties;
025    
026    import javax.swing.JLabel;
027    
028    import org.junit.Test;
029    import org.picocontainer.Characteristics;
030    import org.picocontainer.ComponentAdapter;
031    import org.picocontainer.ComponentFactory;
032    import org.picocontainer.DefaultPicoContainer;
033    import org.picocontainer.Parameter;
034    import org.picocontainer.PicoCompositionException;
035    import org.picocontainer.injectors.AdaptingInjection;
036    import org.picocontainer.lifecycle.NullLifecycleStrategy;
037    import org.picocontainer.monitors.NullComponentMonitor;
038    import org.picocontainer.tck.AbstractComponentFactoryTest;
039    import org.picocontainer.testmodel.SimpleTouchable;
040    import org.picocontainer.testmodel.Touchable;
041    
042    
043    /**
044     * @author Aslak Hellesøy
045     * @author Mirko Novakovic
046     */
047    public 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    }