    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 }