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