    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;
    18
    19  import java.io.File;
    20  import java.io.IOException;
    21  import java.util.Collection;
    22  import java.util.Set;
    23  import java.util.Map;
    24  import java.util.HashMap;
    25
    26  import junit.framework.TestCase;
    27
    28  import org.apache.commons.configuration.beanutils.BeanHelper;
    29  import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
    30  import org.apache.commons.configuration.tree.DefaultConfigurationNode;
    31  import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
    32  import org.apache.commons.lang.text.StrLookup;
    33
    34  /***
    35   * Test class for DefaultConfigurationBuilder.
    36   *
    37   * @author Oliver Heger
    38   * @version $Id: TestDefaultConfigurationBuilder.java 727834 2008-12-18 22:16:32Z rgoers $
    39   */
    40  public class TestDefaultConfigurationBuilder extends TestCase
    41  {
    42      /*** Test configuration definition file. */
    43      private static final File TEST_FILE = new File(
    44              "conf/testDigesterConfiguration.xml");
    45
    46      private static final File ADDITIONAL_FILE = new File(
    47              "conf/testDigesterConfiguration2.xml");
    48
    49      private static final File OPTIONAL_FILE = new File(
    50              "conf/testDigesterOptionalConfiguration.xml");
    51
    52      private static final File OPTIONALEX_FILE = new File(
    53              "conf/testDigesterOptionalConfigurationEx.xml");
    54
    55      private static final File MULTI_FILE = new File(
    56              "conf/testDigesterConfiguration3.xml");
    57
    58      private static final File INIT_FILE = new File(
    59              "conf/testComplexInitialization.xml");
    60
    61      private static final File CLASS_FILE = new File(
    62              "conf/testExtendedClass.xml");
    63
    64      private static final File PROVIDER_FILE = new File(
    65              "conf/testConfigurationProvider.xml");
    66
    67      private static final File EXTENDED_PROVIDER_FILE = new File(
    68              "conf/testExtendedXMLConfigurationProvider.xml");
    69
    70      private static final File GLOBAL_LOOKUP_FILE = new File(
    71              "conf/testGlobalLookup.xml");
    72
    73      private static final File SYSTEM_PROPS_FILE = new File(
    74              "conf/testSystemProperties.xml");
    75
    76      /*** Constant for the name of an optional configuration.*/
    77      private static final String OPTIONAL_NAME = "optionalConfig";
    78
    79      /*** Stores the object to be tested. */
    80      DefaultConfigurationBuilder factory;
    81
    82      protected void setUp() throws Exception
    83      {
    84          super.setUp();
    85          System
    86                  .setProperty("java.naming.factory.initial",
    87                          "org.apache.commons.configuration.MockInitialContextFactory");
    88          System.setProperty("test_file_xml", "test.xml");
    89          System.setProperty("test_file_combine", "testcombine1.xml");
    90          factory = new DefaultConfigurationBuilder();
    91          factory.clearErrorListeners();  // avoid exception messages
    92      }
    93
    94      /***
    95       * Tests the isReservedNode() method of ConfigurationDeclaration.
    96       */
    97      public void testConfigurationDeclarationIsReserved()
    98      {
    99          DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
    100                 factory, factory);
    101         DefaultConfigurationNode parent = new DefaultConfigurationNode();
    102         DefaultConfigurationNode nd = new DefaultConfigurationNode("at");
    103         parent.addAttribute(nd);
    104         assertTrue("Attribute at not recognized", decl.isReservedNode(nd));
    105         nd = new DefaultConfigurationNode("optional");
    106         parent.addAttribute(nd);
    107         assertTrue("Attribute optional not recognized", decl.isReservedNode(nd));
    108         nd = new DefaultConfigurationNode("config-class");
    109         parent.addAttribute(nd);
    110         assertTrue("Inherited attribute not recognized", decl
    111                 .isReservedNode(nd));
    112         nd = new DefaultConfigurationNode("different");
    113         parent.addAttribute(nd);
    114         assertFalse("Wrong reserved attribute", decl.isReservedNode(nd));
    115         nd = new DefaultConfigurationNode("at");
    116         parent.addChild(nd);
    117         assertFalse("Node type not evaluated", decl.isReservedNode(nd));
    118     }
    119
    120     /***
    121      * Tests if the at attribute is correctly detected as reserved attribute.
    122      */
    123     public void testConfigurationDeclarationIsReservedAt()
    124     {
    125         checkOldReservedAttribute("at");
    126     }
    127
    128     /***
    129      * Tests if the optional attribute is correctly detected as reserved
    130      * attribute.
    131      */
    132     public void testConfigurationDeclarationIsReservedOptional()
    133     {
    134         checkOldReservedAttribute("optional");
    135     }
    136
    137     /***
    138      * Tests if special reserved attributes are recognized by the
    139      * isReservedNode() method. For compatibility reasons the attributes "at"
    140      * and "optional" are also treated as reserved attributes, but only if there
    141      * are no corresponding attributes with the "config-" prefix.
    142      *
    143      * @param name the attribute name
    144      */
    145     private void checkOldReservedAttribute(String name)
    146     {
    147         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
    148                 factory, factory);
    149         DefaultConfigurationNode parent = new DefaultConfigurationNode();
    150         DefaultConfigurationNode nd = new DefaultConfigurationNode("config-"
    151                 + name);
    152         parent.addAttribute(nd);
    153         assertTrue("config-" + name + " attribute not recognized", decl
    154                 .isReservedNode(nd));
    155         DefaultConfigurationNode nd2 = new DefaultConfigurationNode(name);
    156         parent.addAttribute(nd2);
    157         assertFalse(name + " is reserved though config- exists", decl
    158                 .isReservedNode(nd2));
    159         assertTrue("config- attribute not recognized when " + name + " exists",
    160                 decl.isReservedNode(nd));
    161     }
    162
    163     /***
    164      * Tests access to certain reserved attributes of a
    165      * ConfigurationDeclaration.
    166      */
    167     public void testConfigurationDeclarationGetAttributes()
    168     {
    169         factory.addProperty("xml.fileName", "test.xml");
    170         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
    171                 factory, factory.configurationAt("xml"));
    172         assertNull("Found an at attribute", decl.getAt());
    173         assertFalse("Found an optional attribute", decl.isOptional());
    174         factory.addProperty("xml[@config-at]", "test1");
    175         assertEquals("Wrong value of at attribute", "test1", decl.getAt());
    176         factory.addProperty("xml[@at]", "test2");
    177         assertEquals("Wrong value of config-at attribute", "test1", decl.getAt());
    178         factory.clearProperty("xml[@config-at]");
    179         assertEquals("Old at attribute not detected", "test2", decl.getAt());
    180         factory.addProperty("xml[@config-optional]", "true");
    181         assertTrue("Wrong value of optional attribute", decl.isOptional());
    182         factory.addProperty("xml[@optional]", "false");
    183         assertTrue("Wrong value of config-optional attribute", decl.isOptional());
    184         factory.clearProperty("xml[@config-optional]");
    185         factory.setProperty("xml[@optional]", Boolean.TRUE);
    186         assertTrue("Old optional attribute not detected", decl.isOptional());
    187         factory.setProperty("xml[@optional]", "invalid value");
    188         try
    189         {
    190             decl.isOptional();
    191             fail("Invalid optional attribute was not detected!");
    192         }
    193         catch (ConfigurationRuntimeException crex)
    194         {
    195             // ok
    196         }
    197     }
    198
    199     /***
    200      * Tests adding a new configuration provider.
    201      */
    202     public void testAddConfigurationProvider()
    203     {
    204         DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider();
    205         assertNull("Provider already registered", factory
    206                 .providerForTag("test"));
    207         factory.addConfigurationProvider("test", provider);
    208         assertSame("Provider not registered", provider, factory
    209                 .providerForTag("test"));
    210     }
    211
    212     /***
    213      * Tries to register a null configuration provider. This should cause an
    214      * exception.
    215      */
    216     public void testAddConfigurationProviderNull()
    217     {
    218         try
    219         {
    220             factory.addConfigurationProvider("test", null);
    221             fail("Could register null provider");
    222         }
    223         catch (IllegalArgumentException iex)
    224         {
    225             // ok
    226         }
    227     }
    228
    229     /***
    230      * Tries to register a configuration provider for a null tag. This should
    231      * cause an exception to be thrown.
    232      */
    233     public void testAddConfigurationProviderNullTag()
    234     {
    235         try
    236         {
    237             factory.addConfigurationProvider(null,
    238                     new DefaultConfigurationBuilder.ConfigurationProvider());
    239             fail("Could register provider for null tag!");
    240         }
    241         catch (IllegalArgumentException iex)
    242         {
    243             // ok
    244         }
    245     }
    246
    247     /***
    248      * Tests removing configuration providers.
    249      */
    250     public void testRemoveConfigurationProvider()
    251     {
    252         assertNull("Removing unknown provider", factory
    253                 .removeConfigurationProvider("test"));
    254         assertNull("Removing provider for null tag", factory
    255                 .removeConfigurationProvider(null));
    256         DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider();
    257         factory.addConfigurationProvider("test", provider);
    258         assertSame("Failed to remove provider", provider, factory
    259                 .removeConfigurationProvider("test"));
    260         assertNull("Provider still registered", factory.providerForTag("test"));
    261     }
    262
    263     /***
    264      * Tests creating a configuration object from a configuration declaration.
    265      */
    266     public void testConfigurationBeanFactoryCreateBean()
    267     {
    268         factory.addConfigurationProvider("test",
    269                 new DefaultConfigurationBuilder.ConfigurationProvider(
    270                         PropertiesConfiguration.class));
    271         factory.addProperty("test[@throwExceptionOnMissing]", "true");
    272         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
    273                 factory, factory.configurationAt("test"));
    274         PropertiesConfiguration conf = (PropertiesConfiguration) BeanHelper
    275                 .createBean(decl);
    276         assertTrue("Property was not initialized", conf
    277                 .isThrowExceptionOnMissing());
    278     }
    279
    280     /***
    281      * Tests creating a configuration object from an unknown tag. This should
    282      * cause an exception.
    283      */
    284     public void testConfigurationBeanFactoryCreateUnknownTag()
    285     {
    286         factory.addProperty("test[@throwExceptionOnMissing]", "true");
    287         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
    288                 factory, factory.configurationAt("test"));
    289         try
    290         {
    291             BeanHelper.createBean(decl);
    292             fail("Could create configuration from unknown tag!");
    293         }
    294         catch (ConfigurationRuntimeException crex)
    295         {
    296             // ok
    297         }
    298     }
    299
    300     /***
    301      * Tests loading a simple configuration definition file.
    302      */
    303     public void testLoadConfiguration() throws ConfigurationException
    304     {
    305         factory.setFile(TEST_FILE);
    306         checkConfiguration();
    307     }
    308
    309     /***
    310      * Tests the file constructor.
    311      */
    312     public void testLoadConfigurationFromFile() throws ConfigurationException
    313     {
    314         factory = new DefaultConfigurationBuilder(TEST_FILE);
    315         checkConfiguration();
    316     }
    317
    318     /***
    319      * Tests the file name constructor.
    320      */
    321     public void testLoadConfigurationFromFileName()
    322             throws ConfigurationException
    323     {
    324         factory = new DefaultConfigurationBuilder(TEST_FILE.getAbsolutePath());
    325         checkConfiguration();
    326     }
    327
    328     /***
    329      * Tests the URL constructor.
    330      */
    331     public void testLoadConfigurationFromURL() throws Exception
    332     {
    333         factory = new DefaultConfigurationBuilder(TEST_FILE.toURL());
    334         checkConfiguration();
    335     }
    336
    337     /***
    338      * Tests if the configuration was correctly created by the factory.
    339      */
    340     private void checkConfiguration() throws ConfigurationException
    341     {
    342         CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory
    343                 .getConfiguration();
    344
    345         assertEquals("Number of configurations", 3, compositeConfiguration
    346                 .getNumberOfConfigurations());
    347         assertEquals(PropertiesConfiguration.class, compositeConfiguration
    348                 .getConfiguration(0).getClass());
    349         assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration
    350                 .getConfiguration(1).getClass());
    351         assertEquals(XMLConfiguration.class, compositeConfiguration
    352                 .getConfiguration(2).getClass());
    353
    354         // check the first configuration
    355         PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration
    356                 .getConfiguration(0);
    357         assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc
    358                 .getFileName());
    359
    360         // check some properties
    361         checkProperties(compositeConfiguration);
    362     }
    363
    364     /***
    365      * Checks if the passed in configuration contains the expected properties.
    366      *
    367      * @param compositeConfiguration the configuration to check
    368      */
    369     private void checkProperties(Configuration compositeConfiguration)
    370     {
    371         assertTrue("Make sure we have loaded our key", compositeConfiguration
    372                 .getBoolean("test.boolean"));
    373         assertEquals("I'm complex!", compositeConfiguration
    374                 .getProperty("element2.subelement.subsubelement"));
    375         assertEquals("property in the XMLPropertiesConfiguration", "value1",
    376                 compositeConfiguration.getProperty("key1"));
    377     }
    378
    379     /***
    380      * Tests loading a configuration definition file with an additional section.
    381      */
    382     public void testLoadAdditional() throws ConfigurationException
    383     {
    384         factory.setFile(ADDITIONAL_FILE);
    385         CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory
    386                 .getConfiguration();
    387         assertEquals("Verify how many configs", 2, compositeConfiguration
    388                 .getNumberOfConfigurations());
    389
    390         // Test if union was constructed correctly
    391         Object prop = compositeConfiguration.getProperty("tables.table.name");
    392         assertTrue(prop instanceof Collection);
    393         assertEquals(3, ((Collection) prop).size());
    394         assertEquals("users", compositeConfiguration
    395                 .getProperty("tables.table(0).name"));
    396         assertEquals("documents", compositeConfiguration
    397                 .getProperty("tables.table(1).name"));
    398         assertEquals("tasks", compositeConfiguration
    399                 .getProperty("tables.table(2).name"));
    400
    401         prop = compositeConfiguration
    402                 .getProperty("tables.table.fields.field.name");
    403         assertTrue(prop instanceof Collection);
    404         assertEquals(17, ((Collection) prop).size());
    405
    406         assertEquals("smtp.mydomain.org", compositeConfiguration
    407                 .getString("mail.host.smtp"));
    408         assertEquals("pop3.mydomain.org", compositeConfiguration
    409                 .getString("mail.host.pop"));
    410
    411         // This was overriden
    412         assertEquals("masterOfPost", compositeConfiguration
    413                 .getString("mail.account.user"));
    414         assertEquals("topsecret", compositeConfiguration
    415                 .getString("mail.account.psswd"));
    416
    417         // This was overriden, too, but not in additional section
    418         assertEquals("enhanced factory", compositeConfiguration
    419                 .getString("test.configuration"));
    420     }
    421
    422     /***
    423      * Tests whether a default log error listener is registered at the builder
    424      * instance.
    425      */
    426     public void testLogErrorListener()
    427     {
    428         assertEquals("No default error listener registered", 1,
    429                 new DefaultConfigurationBuilder().getErrorListeners().size());
    430     }
    431
    432     /***
    433      * Tests loading a definition file that contains optional configurations.
    434      */
    435     public void testLoadOptional() throws Exception
    436     {
    437         factory.setURL(OPTIONAL_FILE.toURL());
    438         Configuration config = factory.getConfiguration();
    439         assertTrue(config.getBoolean("test.boolean"));
    440         assertEquals("value", config.getProperty("element"));
    441     }
    442
    443     /***
    444      * Tests whether loading a failing optional configuration causes an error
    445      * event.
    446      */
    447     public void testLoadOptionalErrorEvent() throws Exception
    448     {
    449         factory.clearErrorListeners();
    450         ConfigurationErrorListenerImpl listener = new ConfigurationErrorListenerImpl();
    451         factory.addErrorListener(listener);
    452         prepareOptionalTest("configuration", false);
    453         listener.verify(DefaultConfigurationBuilder.EVENT_ERR_LOAD_OPTIONAL,
    454                 OPTIONAL_NAME, null);
    455     }
    456
    457     /***
    458      * Tests loading a definition file with optional and non optional
    459      * configuration sources. One non optional does not exist, so this should
    460      * cause an exception.
    461      */
    462     public void testLoadOptionalWithException()
    463     {
    464         factory.setFile(OPTIONALEX_FILE);
    465         try
    466         {
    467             factory.getConfiguration();
    468             fail("Non existing source did not cause an exception!");
    469         }
    470         catch (ConfigurationException cex)
    471         {
    472             // ok
    473         }
    474     }
    475
    476     /***
    477      * Tries to load a configuration file with an optional, non file-based
    478      * configuration. The optional attribute should work for other configuration
    479      * classes, too.
    480      */
    481     public void testLoadOptionalNonFileBased() throws ConfigurationException
    482     {
    483         CombinedConfiguration config = prepareOptionalTest("configuration", false);
    484         assertTrue("Configuration not empty", config.isEmpty());
    485         assertEquals("Wrong number of configurations", 0, config
    486                 .getNumberOfConfigurations());
    487     }
    488
    489     /***
    490      * Tests an optional, non existing configuration with the forceCreate
    491      * attribute. This configuration should be added to the resulting
    492      * configuration.
    493      */
    494     public void testLoadOptionalForceCreate() throws ConfigurationException
    495     {
    496         factory.setBasePath(TEST_FILE.getParent());
    497         CombinedConfiguration config = prepareOptionalTest("xml", true);
    498         assertEquals("Wrong number of configurations", 1, config
    499                 .getNumberOfConfigurations());
    500         FileConfiguration fc = (FileConfiguration) config
    501                 .getConfiguration(OPTIONAL_NAME);
    502         assertNotNull("Optional config not found", fc);
    503         assertEquals("File name was not set", "nonExisting.xml", fc
    504                 .getFileName());
    505         assertNotNull("Base path was not set", fc.getBasePath());
    506     }
    507
    508     /***
    509      * Tests loading an embedded optional configuration builder with the force
    510      * create attribute.
    511      */
    512     public void testLoadOptionalBuilderForceCreate()
    513             throws ConfigurationException
    514     {
    515         CombinedConfiguration config = prepareOptionalTest("configuration",
    516                 true);
    517         assertEquals("Wrong number of configurations", 1, config
    518                 .getNumberOfConfigurations());
    519         assertTrue(
    520                 "Wrong optional configuration type",
    521                 config.getConfiguration(OPTIONAL_NAME) instanceof CombinedConfiguration);
    522     }
    523
    524     /***
    525      * Tests loading an optional configuration with the force create attribute
    526      * set. The provider will always throw an exception. In this case the
    527      * configuration will not be added to the resulting combined configuration.
    528      */
    529     public void testLoadOptionalForceCreateWithException()
    530             throws ConfigurationException
    531     {
    532         factory.addConfigurationProvider("test",
    533                 new DefaultConfigurationBuilder.ConfigurationBuilderProvider()
    534                 {
    535                     // Throw an exception here, too
    536                     public AbstractConfiguration getEmptyConfiguration(
    537                             DefaultConfigurationBuilder.ConfigurationDeclaration decl) throws Exception
    538                     {
    539                         throw new Exception("Unable to create configuration!");
    540                     }
    541                 });
    542         CombinedConfiguration config = prepareOptionalTest("test", true);
    543         assertEquals("Optional configuration could be created", 0, config
    544                 .getNumberOfConfigurations());
    545     }
    546
    547     /***
    548      * Prepares a test for loading a configuration definition file with an
    549      * optional configuration declaration.
    550      *
    551      * @param tag the tag name with the optional configuration
    552      * @param force the forceCreate attribute
    553      * @return the combined configuration obtained from the builder
    554      * @throws ConfigurationException if an error occurs
    555      */
    556     private CombinedConfiguration prepareOptionalTest(String tag, boolean force)
    557             throws ConfigurationException
    558     {
    559         String prefix = "override." + tag;
    560         factory.addProperty(prefix + "[@fileName]", "nonExisting.xml");
    561         factory.addProperty(prefix + "[@config-optional]", Boolean.TRUE);
    562         factory.addProperty(prefix + "[@config-name]", OPTIONAL_NAME);
    563         if (force)
    564         {
    565             factory.addProperty(prefix + "[@config-forceCreate]", Boolean.TRUE);
    566         }
    567         return factory.getConfiguration(false);
    568     }
    569
    570     /***
    571      * Tests loading a definition file with multiple different sources.
    572      */
    573     public void testLoadDifferentSources() throws ConfigurationException
    574     {
    575         factory.setFile(MULTI_FILE);
    576         Configuration config = factory.getConfiguration();
    577         assertFalse(config.isEmpty());
    578         assertTrue(config instanceof CombinedConfiguration);
    579         CombinedConfiguration cc = (CombinedConfiguration) config;
    580         assertEquals("Wrong number of configurations", 1, cc
    581                 .getNumberOfConfigurations());
    582
    583         assertNotNull(config
    584                 .getProperty("tables.table(0).fields.field(2).name"));
    585         assertNotNull(config.getProperty("element2.subelement.subsubelement"));
    586         assertEquals("value", config.getProperty("element3"));
    587         assertEquals("foo", config.getProperty("element3[@name]"));
    588         assertNotNull(config.getProperty("mail.account.user"));
    589
    590         // test JNDIConfiguration
    591         assertNotNull(config.getProperty("test.onlyinjndi"));
    592         assertTrue(config.getBoolean("test.onlyinjndi"));
    593
    594         Configuration subset = config.subset("test");
    595         assertNotNull(subset.getProperty("onlyinjndi"));
    596         assertTrue(subset.getBoolean("onlyinjndi"));
    597
    598         // test SystemConfiguration
    599         assertNotNull(config.getProperty("java.version"));
    600         assertEquals(System.getProperty("java.version"), config
    601                 .getString("java.version"));
    602     }
    603
    604     /***
    605      * Tests if the base path is correctly evaluated.
    606      */
    607     public void testSetConfigurationBasePath() throws ConfigurationException
    608     {
    609         factory.addProperty("properties[@fileName]", "test.properties");
    610         File deepDir = new File("conf/config/deep");
    611         factory.setConfigurationBasePath(deepDir.getAbsolutePath());
    612
    613         Configuration config = factory.getConfiguration(false);
    614         assertEquals("Wrong property value", "somevalue", config
    615                 .getString("somekey"));
    616     }
    617
    618     /***
    619      * Tests reading a configuration definition file that contains complex
    620      * initialization of properties of the declared configuration sources.
    621      */
    622     public void testComplexInitialization() throws ConfigurationException
    623     {
    624         factory.setFile(INIT_FILE);
    625         CombinedConfiguration cc = (CombinedConfiguration) factory
    626                 .getConfiguration();
    627
    628         assertEquals("System property not found", "test.xml",
    629                 cc.getString("test_file_xml"));
    630         PropertiesConfiguration c1 = (PropertiesConfiguration) cc
    631                 .getConfiguration(1);
    632         assertTrue(
    633                 "Reloading strategy was not set",
    634                 c1.getReloadingStrategy() instanceof FileChangedReloadingStrategy);
    635         assertEquals("Refresh delay was not set", 10000,
    636                 ((FileChangedReloadingStrategy) c1.getReloadingStrategy())
    637                         .getRefreshDelay());
    638
    639         Configuration xmlConf = cc.getConfiguration("xml");
    640         assertEquals("Property not found", "I'm complex!", xmlConf
    641                 .getString("element2/subelement/subsubelement"));
    642         assertEquals("List index not found", "two", xmlConf
    643                 .getString("list[0]/item[1]"));
    644         assertEquals("Property in combiner file not found", "yellow", cc
    645                 .getString("/gui/selcolor"));
    646
    647         assertTrue("Delimiter flag was not set", cc
    648                 .isDelimiterParsingDisabled());
    649         assertTrue("Expression engine was not set",
    650                 cc.getExpressionEngine() instanceof XPathExpressionEngine);
    651     }
    652
    653     /***
    654      * Tests if the returned combined configuration has the expected structure.
    655      */
    656     public void testCombinedConfiguration() throws ConfigurationException
    657     {
    658         factory.setFile(INIT_FILE);
    659         CombinedConfiguration cc = (CombinedConfiguration) factory
    660                 .getConfiguration();
    661         assertNotNull("Properties configuration not found", cc
    662                 .getConfiguration("properties"));
    663         assertNotNull("XML configuration not found", cc.getConfiguration("xml"));
    664         assertEquals("Wrong number of contained configs", 4, cc
    665                 .getNumberOfConfigurations());
    666
    667         CombinedConfiguration cc2 = (CombinedConfiguration) cc
    668                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME);
    669         assertNotNull("No additional configuration found", cc2);
    670         Set names = cc2.getConfigurationNames();
    671         assertEquals("Wrong number of contained additional configs", 2, names
    672                 .size());
    673         assertTrue("Config 1 not contained", names.contains("combiner1"));
    674         assertTrue("Config 2 not contained", names.contains("combiner2"));
    675     }
    676
    677     /***
    678      * Tests the structure of the returned combined configuration if there is no
    679      * additional section.
    680      */
    681     public void testCombinedConfigurationNoAdditional()
    682             throws ConfigurationException
    683     {
    684         factory.setFile(TEST_FILE);
    685         CombinedConfiguration cc = factory.getConfiguration(true);
    686         assertNull("Additional configuration was found", cc
    687                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME));
    688     }
    689
    690     /***
    691      * Tests whether the list node definition was correctly processed.
    692      */
    693     public void testCombinedConfigurationListNodes()
    694             throws ConfigurationException
    695     {
    696         factory.setFile(INIT_FILE);
    697         CombinedConfiguration cc = factory.getConfiguration(true);
    698         Set listNodes = cc.getNodeCombiner().getListNodes();
    699         assertEquals("Wrong number of list nodes", 2, listNodes.size());
    700         assertTrue("table node not a list node", listNodes.contains("table"));
    701         assertTrue("list node not a list node", listNodes.contains("list"));
    702
    703         CombinedConfiguration cca = (CombinedConfiguration) cc
    704                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME);
    705         listNodes = cca.getNodeCombiner().getListNodes();
    706         assertTrue("Found list nodes for additional combiner", listNodes
    707                 .isEmpty());
    708     }
    709
    710     /***
    711      * Tests whether a configuration builder can itself be declared in a
    712      * configuration definition file.
    713      */
    714     public void testConfigurationBuilderProvider()
    715             throws ConfigurationException
    716     {
    717         factory.addProperty("override.configuration[@fileName]", TEST_FILE
    718                 .getAbsolutePath());
    719         CombinedConfiguration cc = factory.getConfiguration(false);
    720         assertEquals("Wrong number of configurations", 1, cc
    721                 .getNumberOfConfigurations());
    722         checkProperties(cc);
    723     }
    724
    725     /***
    726      * Tests whether XML settings can be inherited.
    727      */
    728     public void testLoadXMLWithSettings() throws ConfigurationException,
    729             IOException
    730     {
    731         File confDir = new File("conf");
    732         File targetDir = new File("target");
    733         File testXMLSource = new File(confDir, "testDtd.xml");
    734         File testXMLValidationSource = new File(confDir,
    735                 "testValidateInvalid.xml");
    736         File testSavedXML = new File(targetDir, "testSave.xml");
    737         File testSavedFactory = new File(targetDir, "testSaveFactory.xml");
    738         File dtdFile = new File(confDir, "properties.dtd");
    739         final String publicId = "http://commons.apache.org/test.dtd";
    740
    741         XMLConfiguration config = new XMLConfiguration(testXMLSource);
    742         config.setPublicID(publicId);
    743         config.save(testSavedXML);
    744         factory.addProperty("xml[@fileName]", testSavedXML.getAbsolutePath());
    745         factory.addProperty("xml(0)[@validating]", "true");
    746         factory.addProperty("xml(-1)[@fileName]", testXMLValidationSource
    747                 .getAbsolutePath());
    748         factory.addProperty("xml(1)[@config-optional]", "true");
    749         factory.addProperty("xml(1)[@validating]", "true");
    750         factory.save(testSavedFactory);
    751
    752         factory = new DefaultConfigurationBuilder();
    753         factory.setFile(testSavedFactory);
    754         factory.registerEntityId(publicId, dtdFile.toURL());
    755         factory.clearErrorListeners();
    756         Configuration c = factory.getConfiguration();
    757         assertEquals("Wrong property value", "value1", c.getString("entry(0)"));
    758         assertFalse("Invalid XML source was loaded", c
    759                 .containsKey("table.name"));
    760
    761         testSavedXML.delete();
    762         testSavedFactory.delete();
    763     }
    764
    765     /***
    766      * Tests loading a configuration definition file that defines a custom
    767      * result class.
    768      */
    769     public void testExtendedClass() throws ConfigurationException
    770     {
    771         factory.setFile(CLASS_FILE);
    772         CombinedConfiguration cc = factory.getConfiguration(true);
    773         assertEquals("Extended", cc.getProperty("test"));
    774         assertTrue("Wrong result class: " + cc.getClass(),
    775                 cc instanceof ExtendedCombinedConfiguration);
    776     }
    777
    778     /***
    779      * Tests loading a configuration definition file that defines new providers.
    780      */
    781     public void testConfigurationProvider() throws ConfigurationException
    782     {
    783         factory.setFile(PROVIDER_FILE);
    784         factory.getConfiguration(true);
    785         DefaultConfigurationBuilder.ConfigurationProvider provider = factory
    786                 .providerForTag("test");
    787         assertNotNull("Provider 'test' not registered", provider);
    788     }
    789
    790         /***
    791      * Tests loading a configuration definition file that defines new providers.
    792      */
    793     public void testExtendedXMLConfigurationProvider() throws ConfigurationException
    794     {
    795         factory.setFile(EXTENDED_PROVIDER_FILE);
    796         CombinedConfiguration cc = factory.getConfiguration(true);
    797         DefaultConfigurationBuilder.ConfigurationProvider provider = factory
    798                 .providerForTag("test");
    799         assertNotNull("Provider 'test' not registered", provider);
    800         Configuration config = cc.getConfiguration("xml");
    801         assertNotNull("Test configuration not present", config);
    802         assertTrue("Configuration is not ExtendedXMLConfiguration, is " +
    803                 config.getClass().getName(), config instanceof ExtendedXMLConfiguration);
    804     }
    805
    806     public void testGlobalLookup() throws Exception
    807     {
    808         factory.setFile(GLOBAL_LOOKUP_FILE);
    809         CombinedConfiguration cc = factory.getConfiguration(true);
    810         String value = cc.getInterpolator().lookup("test:test_key");
    811         assertNotNull("The test key was not located", value);
    812         assertEquals("Incorrect value retrieved","test.value",value);
    813     }
    814
    815     public void testSystemProperties() throws Exception
    816     {
    817         factory.setFile(SYSTEM_PROPS_FILE);
    818         CombinedConfiguration cc = factory.getConfiguration(true);
    819         String value = System.getProperty("key1");
    820         assertNotNull("The test key was not located", value);
    821         assertEquals("Incorrect value retrieved","value1",value);
    822     }
    823
    824
    825     /***
    826      * A specialized combined configuration implementation used for testing
    827      * custom result classes.
    828      */
    829     public static class ExtendedCombinedConfiguration extends
    830             CombinedConfiguration
    831     {
    832         /***
    833          * The serial version UID.
    834          */
    835         private static final long serialVersionUID = 4678031745085083392L;
    836
    837         public Object getProperty(String key)
    838         {
    839             if (key.equals("test"))
    840             {
    841                 return "Extended";
    842             }
    843             return super.getProperty(key);
    844         }
    845     }
    846
    847     public static class ExtendedXMLConfiguration extends XMLConfiguration
    848     {
    849         public ExtendedXMLConfiguration()
    850         {
    851         }
    852
    853     }
    854
    855     public static class TestLookup extends StrLookup
    856     {
    857         Map map = new HashMap();
    858
    859         public TestLookup()
    860         {
    861             map.put("test_file_xml", "test.xml");
    862             map.put("test_file_combine", "testcombine1.xml");
    863             map.put("test_key", "test.value");
    864         }
    865
    866         public String lookup(String key)
    867         {
    868             if (key == null)
    869             {
    870                 return null;
    871             }
    872             return (String)map.get(key);
    873
    874         }
    875     }
    876 }
    877