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