1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.commons.configuration.beanutils;
18  
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.Map;
22  
23  import org.apache.commons.configuration.ConfigurationRuntimeException;
24  
25  import junit.framework.TestCase;
26  
27  /***
28   * Test class for BeanHelper.
29   *
30   * @since 1.3
31   * @author Oliver Heger
32   * @version $Id: TestBeanHelper.java 570462 2007-08-28 15:56:49Z oheger $
33   */
34  public class TestBeanHelper extends TestCase
35  {
36      /*** Constant for the name of the test bean factory. */
37      private static final String TEST_FACTORY = "testFactory";
38  
39      /***
40       * Stores the default bean factory. Because this is a static field in
41       * BeanHelper it is temporarily stored and reset after the tests.
42       */
43      private BeanFactory tempDefaultBeanFactory;
44  
45      protected void setUp() throws Exception
46      {
47          super.setUp();
48          tempDefaultBeanFactory = BeanHelper.getDefaultBeanFactory();
49          deregisterFactories();
50      }
51  
52      protected void tearDown() throws Exception
53      {
54          deregisterFactories();
55  
56          // Reset old default bean factory
57          BeanHelper.setDefaultBeanFactory(tempDefaultBeanFactory);
58  
59          super.tearDown();
60      }
61  
62      /***
63       * Removes all bean factories that might have been registered during a test.
64       */
65      private void deregisterFactories()
66      {
67          for (Iterator it = BeanHelper.registeredFactoryNames().iterator(); it
68                  .hasNext();)
69          {
70              BeanHelper.deregisterBeanFactory((String) it.next());
71          }
72          assertTrue("Remaining registered bean factories", BeanHelper
73                  .registeredFactoryNames().isEmpty());
74      }
75  
76      /***
77       * Tests registering a new bean factory.
78       */
79      public void testRegisterBeanFactory()
80      {
81          assertTrue("List of registered factories is not empty", BeanHelper
82                  .registeredFactoryNames().isEmpty());
83          BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory());
84          assertEquals("Wrong number of registered factories", 1, BeanHelper
85                  .registeredFactoryNames().size());
86          assertTrue("Test factory is not contained", BeanHelper
87                  .registeredFactoryNames().contains(TEST_FACTORY));
88      }
89  
90      /***
91       * Tries to register a null factory. This should cause an exception.
92       */
93      public void testRegisterBeanFactoryNull()
94      {
95          try
96          {
97              BeanHelper.registerBeanFactory(TEST_FACTORY, null);
98              fail("Could register null factory!");
99          }
100         catch (IllegalArgumentException iex)
101         {
102             // ok
103         }
104     }
105 
106     /***
107      * Tries to register a bean factory with a null name. This should cause an
108      * exception.
109      */
110     public void testRegisterBeanFactoryNullName()
111     {
112         try
113         {
114             BeanHelper.registerBeanFactory(null, new TestBeanFactory());
115             fail("Could register factory with null name!");
116         }
117         catch (IllegalArgumentException iex)
118         {
119             // ok
120         }
121     }
122 
123     /***
124      * Tests to deregister a bean factory.
125      */
126     public void testDeregisterBeanFactory()
127     {
128         assertNull("deregistering non existing factory", BeanHelper
129                 .deregisterBeanFactory(TEST_FACTORY));
130         assertNull("deregistering null factory", BeanHelper
131                 .deregisterBeanFactory(null));
132         BeanFactory factory = new TestBeanFactory();
133         BeanHelper.registerBeanFactory(TEST_FACTORY, factory);
134         assertSame("Could not deregister factory", factory, BeanHelper
135                 .deregisterBeanFactory(TEST_FACTORY));
136         assertTrue("List of factories is not empty", BeanHelper
137                 .registeredFactoryNames().isEmpty());
138     }
139 
140     /***
141      * Tests whether the default bean factory is correctly initialized.
142      */
143     public void testGetDefaultBeanFactory()
144     {
145         assertSame("Incorrect default bean factory",
146                 DefaultBeanFactory.INSTANCE, tempDefaultBeanFactory);
147     }
148 
149     /***
150      * Tests setting the default bean factory to null. This should caus an
151      * exception.
152      */
153     public void testSetDefaultBeanFactoryNull()
154     {
155         try
156         {
157             BeanHelper.setDefaultBeanFactory(null);
158             fail("Could set default bean factory to null!");
159         }
160         catch (IllegalArgumentException iex)
161         {
162             // ok
163         }
164     }
165 
166     /***
167      * Tests initializing a bean.
168      */
169     public void testInitBean()
170     {
171         BeanHelper.setDefaultBeanFactory(new TestBeanFactory());
172         TestBeanDeclaration data = setUpBeanDeclaration();
173         TestBean bean = new TestBean();
174         BeanHelper.initBean(bean, data);
175         checkBean(bean);
176     }
177 
178     /***
179      * Tests initializing a bean when the bean declaration does not contain any
180      * data.
181      */
182     public void testInitBeanWithNoData()
183     {
184         TestBeanDeclaration data = new TestBeanDeclaration();
185         TestBean bean = new TestBean();
186         BeanHelper.initBean(bean, data);
187         assertNull("Wrong string property", bean.getStringValue());
188         assertEquals("Wrong int property", 0, bean.getIntValue());
189         assertNull("Buddy was set", bean.getBuddy());
190     }
191 
192     /***
193      * Tries to initialize a bean with a bean declaration that contains an
194      * invalid property value. This should cause an exception.
195      */
196     public void testInitBeanWithInvalidProperty()
197     {
198         TestBeanDeclaration data = setUpBeanDeclaration();
199         data.getBeanProperties().put("nonExistingProperty", Boolean.TRUE);
200         try
201         {
202             BeanHelper.initBean(new TestBean(), data);
203             fail("Could initialize non existing property!");
204         }
205         catch (ConfigurationRuntimeException cex)
206         {
207             // ok
208         }
209     }
210 
211     /***
212      * Tests creating a bean. All necessary information is stored in the bean
213      * declaration.
214      */
215     public void testCreateBean()
216     {
217         TestBeanFactory factory = new TestBeanFactory();
218         BeanHelper.registerBeanFactory(TEST_FACTORY, factory);
219         TestBeanDeclaration data = setUpBeanDeclaration();
220         data.setBeanFactoryName(TEST_FACTORY);
221         data.setBeanClassName(TestBean.class.getName());
222         checkBean((TestBean) BeanHelper.createBean(data, null));
223         assertNull("A parameter was passed", factory.parameter);
224     }
225 
226     /***
227      * Tests creating a bean when no bean declaration is provided. This should
228      * cause an exception.
229      */
230     public void testCreateBeanWithNullDeclaration()
231     {
232         try
233         {
234             BeanHelper.createBean(null);
235             fail("Could create bean with null declaration!");
236         }
237         catch (IllegalArgumentException iex)
238         {
239             // ok
240         }
241     }
242 
243     /***
244      * Tests creating a bean. The bean's class is specified as the default class
245      * argument.
246      */
247     public void testCreateBeanWithDefaultClass()
248     {
249         BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory());
250         TestBeanDeclaration data = setUpBeanDeclaration();
251         data.setBeanFactoryName(TEST_FACTORY);
252         checkBean((TestBean) BeanHelper.createBean(data, TestBean.class));
253     }
254 
255     /***
256      * Tests creating a bean when the bean's class is specified as the default
257      * class of the bean factory.
258      */
259     public void testCreateBeanWithFactoryDefaultClass()
260     {
261         TestBeanFactory factory = new TestBeanFactory();
262         factory.supportsDefaultClass = true;
263         BeanHelper.registerBeanFactory(TEST_FACTORY, factory);
264         TestBeanDeclaration data = setUpBeanDeclaration();
265         data.setBeanFactoryName(TEST_FACTORY);
266         checkBean((TestBean) BeanHelper.createBean(data, null));
267     }
268 
269     /***
270      * Tries to create a bean when no class is provided. This should cause an
271      * exception.
272      */
273     public void testCreateBeanWithNoClass()
274     {
275         BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory());
276         TestBeanDeclaration data = setUpBeanDeclaration();
277         data.setBeanFactoryName(TEST_FACTORY);
278         try
279         {
280             BeanHelper.createBean(data, null);
281             fail("Could create bean without class!");
282         }
283         catch (ConfigurationRuntimeException cex)
284         {
285             // ok
286         }
287     }
288 
289     /***
290      * Tries to create a bean with a non existing class. This should cause an
291      * exception.
292      */
293     public void testCreateBeanWithInvalidClass()
294     {
295         BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory());
296         TestBeanDeclaration data = setUpBeanDeclaration();
297         data.setBeanFactoryName(TEST_FACTORY);
298         data.setBeanClassName("non.existing.ClassName");
299         try
300         {
301             BeanHelper.createBean(data, null);
302             fail("Could create bean of an unexisting class!");
303         }
304         catch (ConfigurationRuntimeException cex)
305         {
306             // ok
307         }
308     }
309 
310     /***
311      * Tests creating a bean using the default bean factory.
312      */
313     public void testCreateBeanWithDefaultFactory()
314     {
315         BeanHelper.setDefaultBeanFactory(new TestBeanFactory());
316         TestBeanDeclaration data = setUpBeanDeclaration();
317         data.setBeanClassName(TestBean.class.getName());
318         checkBean((TestBean) BeanHelper.createBean(data, null));
319     }
320 
321     /***
322      * Tests creating a bean using a non registered factory.
323      */
324     public void testCreateBeanWithUnknownFactory()
325     {
326         TestBeanDeclaration data = setUpBeanDeclaration();
327         data.setBeanFactoryName(TEST_FACTORY);
328         data.setBeanClassName(TestBean.class.getName());
329         try
330         {
331             BeanHelper.createBean(data, null);
332             fail("Could create bean with non registered factory!");
333         }
334         catch (ConfigurationRuntimeException cex)
335         {
336             // ok
337         }
338     }
339 
340     /***
341      * Tests creating a bean when the factory throws an exception.
342      */
343     public void testCreateBeanWithException()
344     {
345         BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory());
346         TestBeanDeclaration data = setUpBeanDeclaration();
347         data.setBeanFactoryName(TEST_FACTORY);
348         data.setBeanClassName(getClass().getName());
349         try
350         {
351             BeanHelper.createBean(data, null);
352             fail("Could create bean of wrong class!");
353         }
354         catch (ConfigurationRuntimeException cex)
355         {
356             // ok
357         }
358     }
359 
360     /***
361      * Tests if a parameter is correctly passed to the bean factory.
362      */
363     public void testCreateBeanWithParameter()
364     {
365         Object param = new Integer(42);
366         TestBeanFactory factory = new TestBeanFactory();
367         BeanHelper.registerBeanFactory(TEST_FACTORY, factory);
368         TestBeanDeclaration data = setUpBeanDeclaration();
369         data.setBeanFactoryName(TEST_FACTORY);
370         data.setBeanClassName(TestBean.class.getName());
371         checkBean((TestBean) BeanHelper.createBean(data, null, param));
372         assertSame("Wrong parameter", param, factory.parameter);
373     }
374 
375     /***
376      * Returns an initialized bean declaration.
377      *
378      * @return the bean declaration
379      */
380     private TestBeanDeclaration setUpBeanDeclaration()
381     {
382         TestBeanDeclaration data = new TestBeanDeclaration();
383         Map properties = new HashMap();
384         properties.put("stringValue", "testString");
385         properties.put("intValue", "42");
386         data.setBeanProperties(properties);
387         TestBeanDeclaration buddyData = new TestBeanDeclaration();
388         Map properties2 = new HashMap();
389         properties2.put("stringValue", "Another test string");
390         properties2.put("intValue", new Integer(100));
391         buddyData.setBeanProperties(properties2);
392         buddyData.setBeanClassName(TestBean.class.getName());
393         if (BeanHelper.getDefaultBeanFactory() == null)
394         {
395             buddyData.setBeanFactoryName(TEST_FACTORY);
396         }
397         Map nested = new HashMap();
398         nested.put("buddy", buddyData);
399         data.setNestedBeanDeclarations(nested);
400         return data;
401     }
402 
403     /***
404      * Tests if the bean was correctly initialized from the data of the test
405      * bean declaration.
406      *
407      * @param bean the bean to be checked
408      */
409     private void checkBean(TestBean bean)
410     {
411         assertEquals("Wrong string property", "testString", bean
412                 .getStringValue());
413         assertEquals("Wrong int property", 42, bean.getIntValue());
414         TestBean buddy = bean.getBuddy();
415         assertNotNull("Buddy was not set", buddy);
416         assertEquals("Wrong string property in buddy", "Another test string",
417                 buddy.getStringValue());
418         assertEquals("Wrong int property in buddy", 100, buddy.getIntValue());
419     }
420 
421     /***
422      * A simple bean class used for testing creation operations.
423      */
424     public static class TestBean
425     {
426         private String stringValue;
427 
428         private int intValue;
429 
430         private TestBean buddy;
431 
432         public TestBean getBuddy()
433         {
434             return buddy;
435         }
436 
437         public void setBuddy(TestBean buddy)
438         {
439             this.buddy = buddy;
440         }
441 
442         public int getIntValue()
443         {
444             return intValue;
445         }
446 
447         public void setIntValue(int intValue)
448         {
449             this.intValue = intValue;
450         }
451 
452         public String getStringValue()
453         {
454             return stringValue;
455         }
456 
457         public void setStringValue(String stringValue)
458         {
459             this.stringValue = stringValue;
460         }
461     }
462 
463     /***
464      * An implementation of the BeanFactory interface used for testing. This
465      * implementation is really simple: If the TestBean class is provided, a new
466      * instance will be created. Otherwise an exception is thrown.
467      */
468     static class TestBeanFactory implements BeanFactory
469     {
470         Object parameter;
471 
472         boolean supportsDefaultClass;
473 
474         public Object createBean(Class beanClass, BeanDeclaration data, Object param)
475                 throws Exception
476         {
477             parameter = param;
478             if (TestBean.class.equals(beanClass))
479             {
480                 TestBean bean = new TestBean();
481                 BeanHelper.initBean(bean, data);
482                 return bean;
483             }
484             else
485             {
486                 throw new IllegalArgumentException("Unsupported class: "
487                         + beanClass);
488             }
489         }
490 
491         /***
492          * Returns the default class, but only if the supportsDefaultClass flag
493          * is set.
494          */
495         public Class getDefaultBeanClass()
496         {
497             return supportsDefaultClass ? TestBean.class : null;
498         }
499     }
500 
501     /***
502      * A test implementation of the BeanDeclaration interface. This
503      * implementation allows to set the values directly, which should be
504      * returned by the methods required by the BeanDeclaration interface.
505      */
506     static class TestBeanDeclaration implements BeanDeclaration
507     {
508         private String beanClassName;
509 
510         private String beanFactoryName;
511 
512         private Object beanFactoryParameter;
513 
514         private Map beanProperties;
515 
516         private Map nestedBeanDeclarations;
517 
518         public String getBeanClassName()
519         {
520             return beanClassName;
521         }
522 
523         public void setBeanClassName(String beanClassName)
524         {
525             this.beanClassName = beanClassName;
526         }
527 
528         public String getBeanFactoryName()
529         {
530             return beanFactoryName;
531         }
532 
533         public void setBeanFactoryName(String beanFactoryName)
534         {
535             this.beanFactoryName = beanFactoryName;
536         }
537 
538         public Object getBeanFactoryParameter()
539         {
540             return beanFactoryParameter;
541         }
542 
543         public void setBeanFactoryParameter(Object beanFactoryParameter)
544         {
545             this.beanFactoryParameter = beanFactoryParameter;
546         }
547 
548         public Map getBeanProperties()
549         {
550             return beanProperties;
551         }
552 
553         public void setBeanProperties(Map beanProperties)
554         {
555             this.beanProperties = beanProperties;
556         }
557 
558         public Map getNestedBeanDeclarations()
559         {
560             return nestedBeanDeclarations;
561         }
562 
563         public void setNestedBeanDeclarations(Map nestedBeanDeclarations)
564         {
565             this.nestedBeanDeclarations = nestedBeanDeclarations;
566         }
567     }
568 }