View Javadoc

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 static org.junit.Assert.assertEquals;
20  import static org.junit.Assert.assertFalse;
21  import static org.junit.Assert.assertNotNull;
22  import static org.junit.Assert.assertNull;
23  import static org.junit.Assert.assertSame;
24  import static org.junit.Assert.assertTrue;
25  import static org.junit.Assert.fail;
26  
27  import java.io.File;
28  import java.io.FileReader;
29  import java.io.FileWriter;
30  import java.io.IOException;
31  import java.io.Reader;
32  import java.io.Writer;
33  import java.net.URL;
34  import java.util.Collection;
35  import java.util.Iterator;
36  import java.util.List;
37  import java.util.Set;
38  
39  import org.apache.commons.configuration.beanutils.BeanHelper;
40  import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy;
41  import org.apache.commons.configuration.tree.DefaultConfigurationNode;
42  import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine;
43  import org.junit.After;
44  import org.junit.Before;
45  import org.junit.Test;
46  
47  /**
48   * Test class for VFSConfigurationBuilder.
49   *
50   * @author <a
51   * href="http://commons.apache.org/configuration/team-list.html">Commons
52   * Configuration team</a>
53   * @version $Id: TestVFSConfigurationBuilder.java 1308148 2012-04-01 16:27:41Z rgoers $
54   */
55  public class TestVFSConfigurationBuilder
56  {
57      /** Test configuration definition file. */
58      private static final File TEST_FILE = ConfigurationAssert
59              .getTestFile("testDigesterConfiguration.xml");
60  
61      private static final File ADDITIONAL_FILE = ConfigurationAssert
62              .getTestFile("testDigesterConfiguration2.xml");
63  
64      private static final File OPTIONAL_FILE = ConfigurationAssert
65              .getTestFile("testDigesterOptionalConfiguration.xml");
66  
67      private static final File OPTIONALEX_FILE = ConfigurationAssert
68              .getTestFile("testDigesterOptionalConfigurationEx.xml");
69  
70      private static final File MULTI_FILE = ConfigurationAssert
71              .getTestFile("testDigesterConfiguration3.xml");
72  
73      private static final File INIT_FILE = ConfigurationAssert
74              .getTestFile("testComplexInitialization.xml");
75  
76      private static final File CLASS_FILE = ConfigurationAssert
77              .getTestFile("testExtendedClass.xml");
78  
79      private static final File PROVIDER_FILE = ConfigurationAssert
80              .getTestFile("testConfigurationProvider.xml");
81  
82      private static final File EXTENDED_PROVIDER_FILE = ConfigurationAssert
83              .getTestFile("testExtendedXMLConfigurationProvider.xml");
84  
85      private static final File GLOBAL_LOOKUP_FILE = ConfigurationAssert
86              .getTestFile("testGlobalLookup.xml");
87  
88      private static final File SYSTEM_PROPS_FILE = ConfigurationAssert
89              .getTestFile("testSystemProperties.xml");
90  
91      private static final File VALIDATION_FILE = ConfigurationAssert
92              .getTestFile("testValidation.xml");
93  
94      private static final File VALIDATION2_FILE = ConfigurationAssert
95              .getTestFile("testValidation2.xml");
96  
97      private static final File MULTI_TENENT_FILE = ConfigurationAssert
98              .getTestFile("testMultiTenentConfigurationBuilder.xml");
99  
100     private static final File FILESYSTEM_FILE = ConfigurationAssert
101             .getTestFile("testFileSystem.xml");
102 
103     private static final File FILERELOAD_FILE = ConfigurationAssert
104             .getTestFile("testFileReloadConfigurationBuilder.xml");
105 
106     private static final File MULTI_RELOAD_FILE1 = ConfigurationAssert
107             .getTestFile("testVFSMultiTenentConfigurationBuilder1.xml");
108 
109     private static final File MULTI_RELOAD_FILE2 = ConfigurationAssert
110             .getTestFile("testVFSMultiTenentConfigurationBuilder2.xml");
111 
112     /** Constant for the name of an optional configuration.*/
113     private static final String OPTIONAL_NAME = "optionalConfig";
114 
115     /** Stores the object to be tested. */
116     DefaultConfigurationBuilder factory;
117 
118     @Before
119     public void setUp() throws Exception
120     {
121         System
122                 .setProperty("java.naming.factory.initial",
123                         "org.apache.commons.configuration.MockInitialContextFactory");
124         System.setProperty("test_file_xml", "test.xml");
125         System.setProperty("test_file_combine", "testcombine1.xml");
126         System.setProperty("basePath", "file://" + System.getProperty("user.dir") + "/target/test-classes");
127         FileSystem.setDefaultFileSystem(new VFSFileSystem());
128         factory = new DefaultConfigurationBuilder();
129         factory.clearErrorListeners();  // avoid exception messages
130     }
131 
132     @After
133     public void tearDown() throws Exception
134     {
135         FileSystem.resetDefaultFileSystem();
136     }
137 
138     /**
139      * Tests the isReservedNode() method of ConfigurationDeclaration.
140      */
141     @Test
142     public void testConfigurationDeclarationIsReserved()
143     {
144         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
145                 factory, factory);
146         DefaultConfigurationNode parent = new DefaultConfigurationNode();
147         DefaultConfigurationNode nd = new DefaultConfigurationNode("at");
148         parent.addAttribute(nd);
149         assertTrue("Attribute at not recognized", decl.isReservedNode(nd));
150         nd = new DefaultConfigurationNode("optional");
151         parent.addAttribute(nd);
152         assertTrue("Attribute optional not recognized", decl.isReservedNode(nd));
153         nd = new DefaultConfigurationNode("config-class");
154         parent.addAttribute(nd);
155         assertTrue("Inherited attribute not recognized", decl
156                 .isReservedNode(nd));
157         nd = new DefaultConfigurationNode("different");
158         parent.addAttribute(nd);
159         assertFalse("Wrong reserved attribute", decl.isReservedNode(nd));
160         nd = new DefaultConfigurationNode("at");
161         parent.addChild(nd);
162         assertFalse("Node type not evaluated", decl.isReservedNode(nd));
163     }
164 
165     /**
166      * Tests if the at attribute is correctly detected as reserved attribute.
167      */
168     @Test
169     public void testConfigurationDeclarationIsReservedAt()
170     {
171         checkOldReservedAttribute("at");
172     }
173 
174     /**
175      * Tests if the optional attribute is correctly detected as reserved
176      * attribute.
177      */
178     @Test
179     public void testConfigurationDeclarationIsReservedOptional()
180     {
181         checkOldReservedAttribute("optional");
182     }
183 
184     /**
185      * Tests if special reserved attributes are recognized by the
186      * isReservedNode() method. For compatibility reasons the attributes "at"
187      * and "optional" are also treated as reserved attributes, but only if there
188      * are no corresponding attributes with the "config-" prefix.
189      *
190      * @param name the attribute name
191      */
192     private void checkOldReservedAttribute(String name)
193     {
194         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
195                 factory, factory);
196         DefaultConfigurationNode parent = new DefaultConfigurationNode();
197         DefaultConfigurationNode nd = new DefaultConfigurationNode("config-"
198                 + name);
199         parent.addAttribute(nd);
200         assertTrue("config-" + name + " attribute not recognized", decl
201                 .isReservedNode(nd));
202         DefaultConfigurationNode nd2 = new DefaultConfigurationNode(name);
203         parent.addAttribute(nd2);
204         assertFalse(name + " is reserved though config- exists", decl
205                 .isReservedNode(nd2));
206         assertTrue("config- attribute not recognized when " + name + " exists",
207                 decl.isReservedNode(nd));
208     }
209 
210     /**
211      * Tests access to certain reserved attributes of a
212      * ConfigurationDeclaration.
213      */
214     @Test
215     public void testConfigurationDeclarationGetAttributes()
216     {
217         factory.addProperty("xml.fileName", "test.xml");
218         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
219                 factory, factory.configurationAt("xml"));
220         assertNull("Found an at attribute", decl.getAt());
221         assertFalse("Found an optional attribute", decl.isOptional());
222         factory.addProperty("xml[@config-at]", "test1");
223         assertEquals("Wrong value of at attribute", "test1", decl.getAt());
224         factory.addProperty("xml[@at]", "test2");
225         assertEquals("Wrong value of config-at attribute", "test1", decl.getAt());
226         factory.clearProperty("xml[@config-at]");
227         assertEquals("Old at attribute not detected", "test2", decl.getAt());
228         factory.addProperty("xml[@config-optional]", "true");
229         assertTrue("Wrong value of optional attribute", decl.isOptional());
230         factory.addProperty("xml[@optional]", "false");
231         assertTrue("Wrong value of config-optional attribute", decl.isOptional());
232         factory.clearProperty("xml[@config-optional]");
233         factory.setProperty("xml[@optional]", Boolean.TRUE);
234         assertTrue("Old optional attribute not detected", decl.isOptional());
235     }
236 
237     /**
238      * Tests whether an invalid value of an optional attribute is detected.
239      */
240     @Test(expected = ConfigurationRuntimeException.class)
241     public void testConfigurationDeclarationOptionalAttributeInvalid()
242     {
243         factory.addProperty("xml.fileName", "test.xml");
244         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
245                 factory, factory.configurationAt("xml"));
246         factory.setProperty("xml[@optional]", "invalid value");
247         decl.isOptional();
248     }
249 
250     /**
251      * Tests adding a new configuration provider.
252      */
253     @Test
254     public void testAddConfigurationProvider()
255     {
256         DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider();
257         assertNull("Provider already registered", factory
258                 .providerForTag("test"));
259         factory.addConfigurationProvider("test", provider);
260         assertSame("Provider not registered", provider, factory
261                 .providerForTag("test"));
262     }
263 
264     /**
265      * Tries to register a null configuration provider. This should cause an
266      * exception.
267      */
268     @Test(expected = IllegalArgumentException.class)
269     public void testAddConfigurationProviderNull()
270     {
271         factory.addConfigurationProvider("test", null);
272     }
273 
274     /**
275      * Tries to register a configuration provider for a null tag. This should
276      * cause an exception to be thrown.
277      */
278     @Test(expected = IllegalArgumentException.class)
279     public void testAddConfigurationProviderNullTag()
280     {
281         factory.addConfigurationProvider(null,
282                new DefaultConfigurationBuilder.ConfigurationProvider());
283     }
284 
285     /**
286      * Tests removing configuration providers.
287      */
288     @Test
289     public void testRemoveConfigurationProvider()
290     {
291         assertNull("Removing unknown provider", factory
292                 .removeConfigurationProvider("test"));
293         assertNull("Removing provider for null tag", factory
294                 .removeConfigurationProvider(null));
295         DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider();
296         factory.addConfigurationProvider("test", provider);
297         assertSame("Failed to remove provider", provider, factory
298                 .removeConfigurationProvider("test"));
299         assertNull("Provider still registered", factory.providerForTag("test"));
300     }
301 
302     /**
303      * Tests creating a configuration object from a configuration declaration.
304      */
305     @Test
306     public void testConfigurationBeanFactoryCreateBean()
307     {
308         factory.addConfigurationProvider("test",
309                 new DefaultConfigurationBuilder.ConfigurationProvider(
310                         PropertiesConfiguration.class));
311         factory.addProperty("test[@throwExceptionOnMissing]", "true");
312         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
313                 factory, factory.configurationAt("test"));
314         PropertiesConfiguration conf = (PropertiesConfiguration) BeanHelper
315                 .createBean(decl);
316         assertTrue("Property was not initialized", conf
317                 .isThrowExceptionOnMissing());
318     }
319 
320     /**
321      * Tests creating a configuration object from an unknown tag. This should
322      * cause an exception.
323      */
324     @Test(expected = ConfigurationRuntimeException.class)
325     public void testConfigurationBeanFactoryCreateUnknownTag()
326     {
327         factory.addProperty("test[@throwExceptionOnMissing]", "true");
328         DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration(
329                 factory, factory.configurationAt("test"));
330         BeanHelper.createBean(decl);
331     }
332 
333     /**
334      * Tests loading a simple configuration definition file.
335      */
336     @Test
337     public void testLoadConfiguration() throws ConfigurationException
338     {
339         factory.setFile(TEST_FILE);
340         checkConfiguration();
341     }
342 
343     /**
344      * Tests the file constructor.
345      */
346     @Test
347     public void testLoadConfigurationFromFile() throws ConfigurationException
348     {
349         factory = new DefaultConfigurationBuilder(TEST_FILE);
350         checkConfiguration();
351     }
352 
353     /**
354      * Tests the file name constructor.
355      */
356     @Test
357     public void testLoadConfigurationFromFileName()
358             throws ConfigurationException
359     {
360         factory = new DefaultConfigurationBuilder(TEST_FILE.getAbsolutePath());
361         checkConfiguration();
362     }
363 
364     /**
365      * Tests the URL constructor.
366      */
367     @Test
368     public void testLoadConfigurationFromURL() throws Exception
369     {
370         factory = new DefaultConfigurationBuilder(TEST_FILE.toURI().toURL());
371         checkConfiguration();
372     }
373 
374     /**
375      * Tests if the configuration was correctly created by the factory.
376      */
377     private void checkConfiguration() throws ConfigurationException
378     {
379         CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory
380                 .getConfiguration();
381 
382         assertEquals("Number of configurations", 3, compositeConfiguration
383                 .getNumberOfConfigurations());
384         assertEquals(PropertiesConfiguration.class, compositeConfiguration
385                 .getConfiguration(0).getClass());
386         assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration
387                 .getConfiguration(1).getClass());
388         assertEquals(XMLConfiguration.class, compositeConfiguration
389                 .getConfiguration(2).getClass());
390 
391         // check the first configuration
392         PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration
393                 .getConfiguration(0);
394         assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc
395                 .getFileName());
396 
397         // check some properties
398         checkProperties(compositeConfiguration);
399     }
400 
401     /**
402      * Checks if the passed in configuration contains the expected properties.
403      *
404      * @param compositeConfiguration the configuration to check
405      */
406     private void checkProperties(Configuration compositeConfiguration)
407     {
408         assertTrue("Make sure we have loaded our key", compositeConfiguration
409                 .getBoolean("test.boolean"));
410         assertEquals("I'm complex!", compositeConfiguration
411                 .getProperty("element2.subelement.subsubelement"));
412         assertEquals("property in the XMLPropertiesConfiguration", "value1",
413                 compositeConfiguration.getProperty("key1"));
414     }
415 
416     /**
417      * Tests loading a configuration definition file with an additional section.
418      */
419     @Test
420     public void testLoadAdditional() throws ConfigurationException
421     {
422         factory.setFile(ADDITIONAL_FILE);
423         CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory
424                 .getConfiguration();
425         assertEquals("Verify how many configs", 2, compositeConfiguration
426                 .getNumberOfConfigurations());
427 
428         // Test if union was constructed correctly
429         Object prop = compositeConfiguration.getProperty("tables.table.name");
430         assertTrue(prop instanceof Collection);
431         assertEquals(3, ((Collection<?>) prop).size());
432         assertEquals("users", compositeConfiguration
433                 .getProperty("tables.table(0).name"));
434         assertEquals("documents", compositeConfiguration
435                 .getProperty("tables.table(1).name"));
436         assertEquals("tasks", compositeConfiguration
437                 .getProperty("tables.table(2).name"));
438 
439         prop = compositeConfiguration
440                 .getProperty("tables.table.fields.field.name");
441         assertTrue(prop instanceof Collection);
442         assertEquals(17, ((Collection<?>) prop).size());
443 
444         assertEquals("smtp.mydomain.org", compositeConfiguration
445                 .getString("mail.host.smtp"));
446         assertEquals("pop3.mydomain.org", compositeConfiguration
447                 .getString("mail.host.pop"));
448 
449         // This was overridden
450         assertEquals("masterOfPost", compositeConfiguration
451                 .getString("mail.account.user"));
452         assertEquals("topsecret", compositeConfiguration
453                 .getString("mail.account.psswd"));
454 
455         // This was overridden, too, but not in additional section
456         assertEquals("enhanced factory", compositeConfiguration
457                 .getString("test.configuration"));
458     }
459 
460     /**
461      * Tests whether a default log error listener is registered at the builder
462      * instance.
463      */
464     @Test
465     public void testLogErrorListener()
466     {
467         assertEquals("No default error listener registered", 1,
468                 new DefaultConfigurationBuilder().getErrorListeners().size());
469     }
470 
471     /**
472      * Tests loading a definition file that contains optional configurations.
473      */
474     @Test
475     public void testLoadOptional() throws Exception
476     {
477         factory.setURL(OPTIONAL_FILE.toURI().toURL());
478         Configuration config = factory.getConfiguration();
479         assertTrue(config.getBoolean("test.boolean"));
480         assertEquals("value", config.getProperty("element"));
481     }
482 
483     /**
484      * Tests whether loading a failing optional configuration causes an error
485      * event.
486      */
487     @Test
488     public void testLoadOptionalErrorEvent() throws Exception
489     {
490         factory.clearErrorListeners();
491         ConfigurationErrorListenerImpl listener = new ConfigurationErrorListenerImpl();
492         factory.addErrorListener(listener);
493         prepareOptionalTest("configuration", false);
494         listener.verify(DefaultConfigurationBuilder.EVENT_ERR_LOAD_OPTIONAL,
495                 OPTIONAL_NAME, null);
496     }
497 
498     /**
499      * Tests loading a definition file with optional and non optional
500      * configuration sources. One non optional does not exist, so this should
501      * cause an exception.
502      */
503     @Test(expected = ConfigurationException.class)
504     public void testLoadOptionalWithException() throws ConfigurationException
505     {
506         factory.setFile(OPTIONALEX_FILE);
507         factory.getConfiguration();
508     }
509 
510     /**
511      * Tries to load a configuration file with an optional, non file-based
512      * configuration. The optional attribute should work for other configuration
513      * classes, too.
514      */
515     @Test
516     public void testLoadOptionalNonFileBased() throws ConfigurationException
517     {
518         CombinedConfiguration config = prepareOptionalTest("configuration", false);
519         assertTrue("Configuration not empty", config.isEmpty());
520         assertEquals("Wrong number of configurations", 0, config
521                 .getNumberOfConfigurations());
522     }
523 
524     /**
525      * Tests an optional, non existing configuration with the forceCreate
526      * attribute. This configuration should be added to the resulting
527      * configuration.
528      */
529     @Test
530     public void testLoadOptionalForceCreate() throws ConfigurationException
531     {
532         factory.setBasePath(TEST_FILE.getParent());
533         CombinedConfiguration config = prepareOptionalTest("xml", true);
534         assertEquals("Wrong number of configurations", 1, config
535                 .getNumberOfConfigurations());
536         FileConfiguration fc = (FileConfiguration) config
537                 .getConfiguration(OPTIONAL_NAME);
538         assertNotNull("Optional config not found", fc);
539         assertEquals("File name was not set", "nonExisting.xml", fc
540                 .getFileName());
541         assertNotNull("Base path was not set", fc.getBasePath());
542     }
543 
544     /**
545      * Tests loading an embedded optional configuration builder with the force
546      * create attribute.
547      */
548     @Test
549     public void testLoadOptionalBuilderForceCreate()
550             throws ConfigurationException
551     {
552         CombinedConfiguration config = prepareOptionalTest("configuration",
553                 true);
554         assertEquals("Wrong number of configurations", 1, config
555                 .getNumberOfConfigurations());
556         assertTrue(
557                 "Wrong optional configuration type",
558                 config.getConfiguration(OPTIONAL_NAME) instanceof CombinedConfiguration);
559     }
560 
561     /**
562      * Tests loading an optional configuration with the force create attribute
563      * set. The provider will always throw an exception. In this case the
564      * configuration will not be added to the resulting combined configuration.
565      */
566     @Test
567     public void testLoadOptionalForceCreateWithException()
568             throws ConfigurationException
569     {
570         factory.addConfigurationProvider("test",
571                 new DefaultConfigurationBuilder.ConfigurationBuilderProvider()
572                 {
573                     // Throw an exception here, too
574                     @Override
575                     public AbstractConfiguration getEmptyConfiguration(
576                             DefaultConfigurationBuilder.ConfigurationDeclaration decl) throws Exception
577                     {
578                         throw new Exception("Unable to create configuration!");
579                     }
580                 });
581         CombinedConfiguration config = prepareOptionalTest("test", true);
582         assertEquals("Optional configuration could be created", 0, config
583                 .getNumberOfConfigurations());
584     }
585 
586     /**
587      * Prepares a test for loading a configuration definition file with an
588      * optional configuration declaration.
589      *
590      * @param tag the tag name with the optional configuration
591      * @param force the forceCreate attribute
592      * @return the combined configuration obtained from the builder
593      * @throws org.apache.commons.configuration.ConfigurationException if an error occurs
594      */
595     private CombinedConfiguration prepareOptionalTest(String tag, boolean force)
596             throws ConfigurationException
597     {
598         String prefix = "override." + tag;
599         factory.addProperty(prefix + "[@fileName]", "nonExisting.xml");
600         factory.addProperty(prefix + "[@config-optional]", Boolean.TRUE);
601         factory.addProperty(prefix + "[@config-name]", OPTIONAL_NAME);
602         if (force)
603         {
604             factory.addProperty(prefix + "[@config-forceCreate]", Boolean.TRUE);
605         }
606         return factory.getConfiguration(false);
607     }
608 
609     /**
610      * Tests loading a definition file with multiple different sources.
611      */
612     @Test
613     public void testLoadDifferentSources() throws ConfigurationException
614     {
615         factory.setFile(MULTI_FILE);
616         Configuration config = factory.getConfiguration();
617         assertFalse(config.isEmpty());
618         assertTrue(config instanceof CombinedConfiguration);
619         CombinedConfiguration cc = (CombinedConfiguration) config;
620         assertEquals("Wrong number of configurations", 1, cc
621                 .getNumberOfConfigurations());
622 
623         assertNotNull(config
624                 .getProperty("tables.table(0).fields.field(2).name"));
625         assertNotNull(config.getProperty("element2.subelement.subsubelement"));
626         assertEquals("value", config.getProperty("element3"));
627         assertEquals("foo", config.getProperty("element3[@name]"));
628         assertNotNull(config.getProperty("mail.account.user"));
629 
630         // test JNDIConfiguration
631         assertNotNull(config.getProperty("test.onlyinjndi"));
632         assertTrue(config.getBoolean("test.onlyinjndi"));
633 
634         Configuration subset = config.subset("test");
635         assertNotNull(subset.getProperty("onlyinjndi"));
636         assertTrue(subset.getBoolean("onlyinjndi"));
637 
638         // test SystemConfiguration
639         assertNotNull(config.getProperty("java.version"));
640         assertEquals(System.getProperty("java.version"), config
641                 .getString("java.version"));
642     }
643 
644     /**
645      * Tests if the base path is correctly evaluated.
646      */
647     @Test
648     public void testSetConfigurationBasePath() throws ConfigurationException
649     {
650         factory.addProperty("properties[@fileName]", "test.properties");
651         File deepDir = new File(ConfigurationAssert.TEST_DIR, "config/deep");
652         factory.setConfigurationBasePath(deepDir.getAbsolutePath());
653 
654         Configuration config = factory.getConfiguration(false);
655         assertEquals("Wrong property value", "somevalue", config
656                 .getString("somekey"));
657     }
658 
659     /**
660      * Tests reading a configuration definition file that contains complex
661      * initialization of properties of the declared configuration sources.
662      */
663     @Test
664     public void testComplexInitialization() throws ConfigurationException
665     {
666         factory.setFile(INIT_FILE);
667         CombinedConfiguration cc = (CombinedConfiguration) factory
668                 .getConfiguration();
669 
670         assertEquals("System property not found", "test.xml",
671                 cc.getString("test_file_xml"));
672         PropertiesConfiguration c1 = (PropertiesConfiguration) cc
673                 .getConfiguration(1);
674         assertTrue(
675                 "Reloading strategy was not set",
676                 c1.getReloadingStrategy() instanceof FileChangedReloadingStrategy);
677         assertEquals("Refresh delay was not set", 10000,
678                 ((FileChangedReloadingStrategy) c1.getReloadingStrategy())
679                         .getRefreshDelay());
680 
681         Configuration xmlConf = cc.getConfiguration("xml");
682         assertEquals("Property not found", "I'm complex!", xmlConf
683                 .getString("element2/subelement/subsubelement"));
684         assertEquals("List index not found", "two", xmlConf
685                 .getString("list[0]/item[1]"));
686         assertEquals("Property in combiner file not found", "yellow", cc
687                 .getString("/gui/selcolor"));
688 
689         assertTrue("Delimiter flag was not set", cc
690                 .isDelimiterParsingDisabled());
691         assertTrue("Expression engine was not set",
692                 cc.getExpressionEngine() instanceof XPathExpressionEngine);
693     }
694 
695     /**
696      * Tests if the returned combined configuration has the expected structure.
697      */
698     @Test
699     public void testCombinedConfiguration() throws ConfigurationException
700     {
701         factory.setFile(INIT_FILE);
702         CombinedConfiguration cc = (CombinedConfiguration) factory
703                 .getConfiguration();
704         assertNotNull("Properties configuration not found", cc
705                 .getConfiguration("properties"));
706         assertNotNull("XML configuration not found", cc.getConfiguration("xml"));
707         assertEquals("Wrong number of contained configs", 4, cc
708                 .getNumberOfConfigurations());
709 
710         CombinedConfiguration cc2 = (CombinedConfiguration) cc
711                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME);
712         assertNotNull("No additional configuration found", cc2);
713         Set<String> names = cc2.getConfigurationNames();
714         assertEquals("Wrong number of contained additional configs", 2, names
715                 .size());
716         assertTrue("Config 1 not contained", names.contains("combiner1"));
717         assertTrue("Config 2 not contained", names.contains("combiner2"));
718     }
719 
720     /**
721      * Tests the structure of the returned combined configuration if there is no
722      * additional section.
723      */
724     @Test
725     public void testCombinedConfigurationNoAdditional()
726             throws ConfigurationException
727     {
728         factory.setFile(TEST_FILE);
729         CombinedConfiguration cc = factory.getConfiguration(true);
730         assertNull("Additional configuration was found", cc
731                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME));
732     }
733 
734     /**
735      * Tests whether the list node definition was correctly processed.
736      */
737     @Test
738     public void testCombinedConfigurationListNodes()
739             throws ConfigurationException
740     {
741         factory.setFile(INIT_FILE);
742         CombinedConfiguration cc = factory.getConfiguration(true);
743         Set<String> listNodes = cc.getNodeCombiner().getListNodes();
744         assertEquals("Wrong number of list nodes", 2, listNodes.size());
745         assertTrue("table node not a list node", listNodes.contains("table"));
746         assertTrue("list node not a list node", listNodes.contains("list"));
747 
748         CombinedConfiguration cca = (CombinedConfiguration) cc
749                 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME);
750         listNodes = cca.getNodeCombiner().getListNodes();
751         assertTrue("Found list nodes for additional combiner", listNodes
752                 .isEmpty());
753     }
754 
755     /**
756      * Tests whether a configuration builder can itself be declared in a
757      * configuration definition file.
758      */
759     @Test
760     public void testConfigurationBuilderProvider()
761             throws ConfigurationException
762     {
763         factory.addProperty("override.configuration[@fileName]", TEST_FILE
764                 .getAbsolutePath());
765         CombinedConfiguration cc = factory.getConfiguration(false);
766         assertEquals("Wrong number of configurations", 1, cc
767                 .getNumberOfConfigurations());
768         checkProperties(cc);
769     }
770 
771     /**
772      * Tests whether XML settings can be inherited.
773      */
774     @Test
775     public void testLoadXMLWithSettings() throws Exception
776     {
777         File confDir = new File("conf");
778         File targetDir = new File("target");
779         File testXMLValidationSource = new File(confDir,
780                 "testValidateInvalid.xml");
781         File testSavedXML = new File(targetDir, "testSave.xml");
782         File testSavedFactory = new File(targetDir, "testSaveFactory.xml");
783         URL dtdFile = getClass().getResource("/properties.dtd");
784         final String publicId = "http://commons.apache.org/test.dtd";
785 
786         XMLConfiguration config = new XMLConfiguration("testDtd.xml");
787         config.setPublicID(publicId);
788         config.save(testSavedXML);
789         factory.addProperty("xml[@fileName]", testSavedXML.getAbsolutePath());
790         factory.addProperty("xml(0)[@validating]", "true");
791         factory.addProperty("xml(-1)[@fileName]", testXMLValidationSource
792                 .getAbsolutePath());
793         factory.addProperty("xml(1)[@config-optional]", "true");
794         factory.addProperty("xml(1)[@validating]", "true");
795         factory.save(testSavedFactory);
796 
797         factory = new DefaultConfigurationBuilder();
798         factory.setFile(testSavedFactory);
799         factory.registerEntityId(publicId, dtdFile);
800         factory.clearErrorListeners();
801         Configuration c = factory.getConfiguration();
802         assertEquals("Wrong property value", "value1", c.getString("entry(0)"));
803         assertFalse("Invalid XML source was loaded", c
804                 .containsKey("table.name"));
805 
806         testSavedXML.delete();
807         testSavedFactory.delete();
808     }
809 
810     /**
811      * Tests loading a configuration definition file that defines a custom
812      * result class.
813      */
814     @Test
815     public void testExtendedClass() throws ConfigurationException
816     {
817         factory.setFile(CLASS_FILE);
818         CombinedConfiguration cc = factory.getConfiguration(true);
819         String prop = (String)cc.getProperty("test");
820         assertEquals("Expected 'Extended', actual '" + prop + "'", "Extended", prop);
821         assertTrue("Wrong result class: " + cc.getClass(),
822                 cc instanceof TestDefaultConfigurationBuilder.ExtendedCombinedConfiguration);
823     }
824 
825     /**
826      * Tests loading a configuration definition file that defines new providers.
827      */
828     @Test
829     public void testConfigurationProvider() throws ConfigurationException
830     {
831         factory.setFile(PROVIDER_FILE);
832         factory.getConfiguration(true);
833         DefaultConfigurationBuilder.ConfigurationProvider provider = factory
834                 .providerForTag("test");
835         assertNotNull("Provider 'test' not registered", provider);
836     }
837 
838     /**
839      * Tests loading a configuration definition file that defines new providers.
840      */
841     @Test
842     public void testExtendedXMLConfigurationProvider() throws ConfigurationException
843     {
844         factory.setFile(EXTENDED_PROVIDER_FILE);
845         CombinedConfiguration cc = factory.getConfiguration(true);
846         DefaultConfigurationBuilder.ConfigurationProvider provider = factory
847                 .providerForTag("test");
848         assertNotNull("Provider 'test' not registered", provider);
849         Configuration config = cc.getConfiguration("xml");
850         assertNotNull("Test configuration not present", config);
851         assertTrue("Configuration is not ExtendedXMLConfiguration, is " +
852                 config.getClass().getName(),
853                 config instanceof TestDefaultConfigurationBuilder.ExtendedXMLConfiguration);
854     }
855 
856     @Test
857     public void testGlobalLookup() throws Exception
858     {
859         factory.setFile(GLOBAL_LOOKUP_FILE);
860         CombinedConfiguration cc = factory.getConfiguration(true);
861         String value = cc.getInterpolator().lookup("test:test_key");
862         assertNotNull("The test key was not located", value);
863         assertEquals("Incorrect value retrieved","test.value",value);
864     }
865 
866     @Test
867     public void testSystemProperties() throws Exception
868     {
869         factory.setFile(SYSTEM_PROPS_FILE);
870         factory.getConfiguration(true);
871         String value = System.getProperty("key1");
872         assertNotNull("The test key was not located", value);
873         assertEquals("Incorrect value retrieved","value1",value);
874     }
875 
876     @Test
877     public void testValidation() throws Exception
878     {
879         factory.setFile(VALIDATION_FILE);
880         CombinedConfiguration cc = factory.getConfiguration(true);
881         String value = cc.getString("key1");
882         assertNotNull("The test key was not located", value);
883         assertEquals("Incorrect value retrieved","value1",value);
884     }
885 
886     @Test
887     public void testValidation2() throws Exception
888     {
889         factory.setFile(VALIDATION2_FILE);
890         CombinedConfiguration cc = factory.getConfiguration(true);
891         String value = cc.getString("key1");
892         assertNotNull("The test key was not located", value);
893         assertEquals("Incorrect value retrieved","value1",value);
894     }
895 
896     @Test
897     public void testMultiTenentConfiguration() throws Exception
898     {
899         factory.setFile(MULTI_TENENT_FILE);
900         System.getProperties().remove("Id");
901 
902         CombinedConfiguration config = factory.getConfiguration(true);
903         assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration);
904 
905         verify(null, config, 50);
906         verify("1001", config, 15);
907         verify("1002", config, 25);
908         verify("1003", config, 35);
909         verify("1004", config, 50);
910         verify("1005", config, 50);
911     }
912 
913     @Test
914     public void testMultiTenentConfiguration2() throws Exception
915     {
916         factory.setFile(MULTI_TENENT_FILE);
917         System.setProperty("Id", "1004");
918 
919         CombinedConfiguration config = factory.getConfiguration(true);
920         assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration);
921 
922         verify("1001", config, 15);
923         verify("1002", config, 25);
924         verify("1003", config, 35);
925         verify("1004", config, 50);
926         verify("1005", config, 50);
927     }
928 
929     @Test
930     public void testMultiTenentConfiguration3() throws Exception
931     {
932         factory.setFile(MULTI_TENENT_FILE);
933         System.setProperty("Id", "1005");
934 
935         CombinedConfiguration config = factory.getConfiguration(true);
936         assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration);
937 
938         verify("1001", config, 15);
939         verify("1002", config, 25);
940         verify("1003", config, 35);
941         verify("1004", config, 50);
942         verify("1005", config, 50);
943     }
944 
945     @Test
946     public void testSetFileSystem() throws Exception
947     {
948         factory.setFile(PROVIDER_FILE);
949         FileSystem fs = new VFSFileSystem();
950         factory.setFileSystem(fs);
951         FileSystem.resetDefaultFileSystem();
952         System.getProperties().remove("Id");
953 
954         CombinedConfiguration config = factory.getConfiguration(true);
955         List<AbstractConfiguration> list = config.getConfigurations();
956         assertTrue("Incorrect number of configurations - " + list.size(), list.size() == 4);
957         Iterator<AbstractConfiguration> iter = list.iterator();
958         while (iter.hasNext())
959         {
960             Configuration conf = iter.next();
961             if (conf instanceof FileSystemBased)
962             {
963                 assertTrue("Incorrect file system for Configuration " + conf,
964                         ((FileSystemBased)conf).getFileSystem() == fs);
965             }
966             else if (conf instanceof CombinedConfiguration)
967             {
968                 Iterator<AbstractConfiguration> it = ((CombinedConfiguration)conf).getConfigurations().iterator();
969                 while (it.hasNext())
970                 {
971                     conf = it.next();
972                     if (conf instanceof FileSystemBased)
973                     {
974                         assertTrue("Incorrect file system for Configuration " + conf,
975                             ((FileSystemBased)conf).getFileSystem() == fs);
976                     }
977                 }
978             }
979         }
980     }
981 
982     @Test
983     public void testConfiguredFileSystem() throws Exception
984     {
985         factory.setFile(FILESYSTEM_FILE);
986         FileSystem.resetDefaultFileSystem();
987         System.getProperties().remove("Id");
988 
989         CombinedConfiguration config = factory.getConfiguration(true);
990         FileSystem fs = factory.getFileSystem();
991         assertNotNull("No File System",fs);
992         assertTrue("Incorrect File System", fs instanceof VFSFileSystem);
993         List<AbstractConfiguration> list = config.getConfigurations();
994         assertTrue("Incorrect number of configurations - " + list.size(), list.size() == 4);
995         Iterator<AbstractConfiguration> iter = list.iterator();
996         while (iter.hasNext())
997         {
998             Configuration conf = iter.next();
999             if (conf instanceof FileSystemBased)
1000             {
1001                 assertTrue("Incorrect file system for Configuration " + conf,
1002                         ((FileSystemBased)conf).getFileSystem() == fs);
1003             }
1004             else if (conf instanceof CombinedConfiguration)
1005             {
1006                 Iterator<AbstractConfiguration> it = ((CombinedConfiguration)conf).getConfigurations().iterator();
1007                 while (it.hasNext())
1008                 {
1009                     conf = it.next();
1010                     if (conf instanceof FileSystemBased)
1011                     {
1012                         assertTrue("Incorrect file system for Configuration " + conf,
1013                             ((FileSystemBased)conf).getFileSystem() == fs);
1014                     }
1015                 }
1016             }
1017         }
1018     }
1019 
1020     @Test
1021     public void testFileReload1() throws Exception
1022     {
1023         // create a new configuration
1024         File input = new File("target/test-classes/testMultiConfiguration_1001.xml");
1025         File output = new File("target/test-classes/testwrite/testMultiConfiguration_1001.xml");
1026         output.delete();
1027         output.getParentFile().mkdir();
1028         copyFile(input, output);
1029         // Sleep to make sure the file timestamp is not in the same second as "now".
1030         Thread.sleep(1100);
1031 
1032         factory.setFile(FILERELOAD_FILE);
1033         FileSystem.resetDefaultFileSystem();
1034         System.getProperties().remove("Id");
1035 
1036         CombinedConfiguration config = factory.getConfiguration(true);
1037         assertNotNull(config);
1038         verify("1001", config, 15);
1039         Thread.sleep(1100);
1040         XMLConfiguration x = new XMLConfiguration(output);
1041         x.setProperty("rowsPerPage", "50");
1042         x.save();
1043         verify("1001", config, 50);
1044         output.delete();
1045     }
1046 
1047     @Test
1048     public void testFileReload2() throws Exception
1049     {
1050         // create a new configuration
1051         File input = new File("target/test-classes/testMultiConfiguration_1002.xml");
1052         File output = new File("target/test-classes/testwrite/testMultiConfiguration_1002.xml");
1053         output.delete();
1054 
1055         factory.setFile(FILERELOAD_FILE);
1056         FileSystem.resetDefaultFileSystem();
1057         System.getProperties().remove("Id");
1058 
1059         CombinedConfiguration config = factory.getConfiguration(true);
1060         assertNotNull(config);
1061 
1062         verify("1002", config, 50);
1063         // Sleep to make sure the file timestamp is not in the same second as "now".
1064         Thread.sleep(1100);
1065         output.getParentFile().mkdir();
1066         copyFile(input, output);
1067         verify("1002", config, 25);
1068         output.delete();
1069     }
1070 
1071     @Test
1072     public void testFileReload3() throws Exception
1073     {
1074         // create a new configuration
1075         File input = new File("target/test-classes/testMultiConfiguration_1001.xml");
1076         File output = new File("target/test-classes/testwrite/testMultiConfiguration_1001.xml");
1077         output.delete();
1078         output.getParentFile().mkdir();
1079 
1080         factory.setFile(FILERELOAD_FILE);
1081         FileSystem.resetDefaultFileSystem();
1082         System.getProperties().remove("Id");
1083 
1084         CombinedConfiguration config = factory.getConfiguration(true);
1085         assertNotNull(config);
1086         verify("1001", config, 50);
1087         copyFile(input, output);
1088         // Sleep to make sure the file timestamp is not in the same second as "now".
1089         Thread.sleep(1100);
1090         verify("1001", config, 15);
1091         XMLConfiguration x = new XMLConfiguration(output);
1092         x.setProperty("rowsPerPage", "25");
1093         x.save();
1094          // Sleep to make sure the file timestamp is not in the same second as "now".
1095         Thread.sleep(1100);
1096         verify("1001", config, 25);
1097         output.delete();
1098     }
1099 
1100     @Test
1101     public void testReloadDefault() throws Exception
1102     {
1103         // create a new configuration
1104         String defaultName = "target/test-classes/testMultiConfiguration_default.xml";
1105         File input = new File(defaultName);
1106 
1107         System.getProperties().remove("Id");
1108         factory.setFile(MULTI_RELOAD_FILE1);
1109         CombinedConfiguration config = factory.getConfiguration(true);
1110         assertNotNull(config);
1111         verify("3001", config, 15);
1112         verify("3002", config, 25);
1113         System.setProperty("Id", "3002");
1114         config.addProperty("/ TestProp", "Test");
1115         assertTrue("Property not added", "Test".equals(config.getString("TestProp")));
1116         System.getProperties().remove("Id");
1117         //Sleep so refreshDelay elapses
1118         Thread.sleep(600);
1119         long time = System.currentTimeMillis();
1120         long original = input.lastModified();
1121         input.setLastModified(time);
1122         File defaultFile = new File(defaultName);
1123         long newTime = defaultFile.lastModified();
1124         assertTrue("time mismatch", original != newTime);
1125         Thread.sleep(600);
1126         verify("3001", config, 15);
1127         verify("3002", config, 25);
1128         System.setProperty("Id", "3002");
1129         String test = config.getString("TestProp");
1130         assertNull("Property was not cleared by reload", test);
1131     }
1132 
1133     @Test
1134     public void testFileReloadSchemaValidationError() throws Exception
1135     {
1136         System.getProperties().remove("Id");
1137         factory.setFile(MULTI_RELOAD_FILE2);
1138         CombinedConfiguration config = factory.getConfiguration(true);
1139 
1140         // create a new configuration
1141         File input = new File("target/test-classes/testMultiConfiguration_3001.xml");
1142         File output = new File("target/test-classes/testwrite/testMultiConfiguration_3001.xml");
1143         output.delete();
1144         output.getParentFile().mkdir();
1145         copyFile(input, output);
1146 
1147         assertNotNull(config);
1148         verify("3001", config, 15);
1149         Thread.sleep(1100);
1150         XMLConfiguration x = new XMLConfiguration();
1151         x.setFile(output);
1152         x.setAttributeSplittingDisabled(true);
1153         x.setDelimiterParsingDisabled(true);
1154         x.load();
1155         x.setProperty("rowsPerPage", "test");
1156         //Insure orginal timestamp and new timestamp aren't the same second.
1157         Thread.sleep(1100);
1158         x.save();
1159         System.setProperty("Id", "3001");
1160         try
1161         {
1162             config.getInt("rowsPerPage");
1163             fail("No exception was thrown");
1164         }
1165         catch (Exception ex)
1166         {
1167 
1168         }
1169 
1170         output.delete();
1171     }
1172 
1173     private void copyFile(File input, File output) throws IOException
1174     {
1175         Reader reader = new FileReader(input);
1176         Writer writer = new FileWriter(output);
1177         char[] buffer = new char[4096];
1178         int n = 0;
1179         while (-1 != (n = reader.read(buffer)))
1180         {
1181             writer.write(buffer, 0, n);
1182         }
1183         reader.close();
1184         writer.close();
1185     }
1186 
1187     private void verify(String key, CombinedConfiguration config, int rows)
1188     {
1189         if (key == null)
1190         {
1191             System.getProperties().remove("Id");
1192         }
1193         else
1194         {
1195             System.setProperty("Id", key);
1196         }
1197         int actual = config.getInt("rowsPerPage");
1198         assertTrue("expected: " + rows + " actual: " + actual, actual == rows);
1199     }
1200 }