001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.configuration; 018 019 import static org.junit.Assert.assertEquals; 020 import static org.junit.Assert.assertFalse; 021 import static org.junit.Assert.assertNotNull; 022 import static org.junit.Assert.assertNull; 023 import static org.junit.Assert.assertSame; 024 import static org.junit.Assert.assertTrue; 025 026 import java.io.File; 027 import java.io.FileReader; 028 import java.io.IOException; 029 import java.io.OutputStreamWriter; 030 import java.io.Reader; 031 import java.io.Writer; 032 import java.util.Collection; 033 import java.util.HashMap; 034 import java.util.Map; 035 import java.util.Set; 036 037 import org.apache.commons.configuration.beanutils.BeanHelper; 038 import org.apache.commons.configuration.event.ConfigurationEvent; 039 import org.apache.commons.configuration.event.ConfigurationListener; 040 import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; 041 import org.apache.commons.configuration.tree.DefaultConfigurationNode; 042 import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; 043 import org.apache.commons.vfs2.FileName; 044 import org.apache.commons.vfs2.FileObject; 045 import org.apache.commons.vfs2.FileSystemManager; 046 import org.apache.commons.vfs2.FileSystemOptions; 047 import org.apache.commons.vfs2.VFS; 048 import org.junit.After; 049 import org.junit.Before; 050 import org.junit.Test; 051 052 /** 053 * Test class for DefaultConfigurationBuilder. 054 * 055 * @author <a 056 * href="http://commons.apache.org/configuration/team-list.html">Commons 057 * Configuration team</a> 058 * @version $Id: TestWebdavConfigurationBuilder.java 1225331 2011-12-28 20:55:49Z oheger $ 059 */ 060 public class TestWebdavConfigurationBuilder 061 implements FileOptionsProvider, ConfigurationListener 062 { 063 /** Test configuration definition file. */ 064 private static final String TEST_FILE = 065 "testDigesterConfiguration.xml"; 066 067 private static final String ADDITIONAL_FILE = 068 "testDigesterConfiguration2.xml"; 069 070 private static final String OPTIONAL_FILE = 071 "testDigesterOptionalConfiguration.xml"; 072 073 private static final String OPTIONALEX_FILE = 074 "testDigesterOptionalConfigurationEx.xml"; 075 076 private static final String MULTI_FILE = 077 "testDigesterConfiguration3.xml"; 078 079 private static final String INIT_FILE = 080 "testComplexInitialization.xml"; 081 082 private static final String CLASS_FILE = 083 "testExtendedClass.xml"; 084 085 private static final String PROVIDER_FILE = 086 "testConfigurationProvider.xml"; 087 088 private static final String EXTENDED_PROVIDER_FILE = 089 "testExtendedXMLConfigurationProvider.xml"; 090 091 private static final String GLOBAL_LOOKUP_FILE = 092 "testGlobalLookup.xml"; 093 094 private static final String SYSTEM_PROPS_FILE = 095 "testSystemProperties.xml"; 096 097 private static final String VALIDATION_FILE = 098 "testValidation.xml"; 099 100 private static final String MULTI_TENENT_FILE = 101 "testMultiTenentConfigurationBuilder.xml"; 102 103 private static final String FILERELOAD2_FILE = 104 "testFileReloadConfigurationBuilder2.xml"; 105 106 private static final String FILERELOAD_1001_FILE = 107 "testwrite/testMultiConfiguration_1001.xml"; 108 109 private static final String FILERELOAD_1002_FILE = 110 "testwrite/testMultiConfiguration_1002.xml"; 111 112 private static final String TEST_PROPERTIES = "test.properties.xml"; 113 114 private static final String TEST_SAVE = "testsave.xml"; 115 116 /** Constant for the name of an optional configuration.*/ 117 private static final String OPTIONAL_NAME = "optionalConfig"; 118 119 private Map<String, Object> options; 120 121 /** true when a file is changed */ 122 private boolean configChanged = false; 123 124 /** Stores the object to be tested. */ 125 DefaultConfigurationBuilder factory; 126 127 private String getBasePath() 128 { 129 String path = System.getProperty("test.webdav.base"); 130 assertNotNull("No base url provided", path); 131 return path; 132 } 133 134 @Before 135 public void setUp() throws Exception 136 { 137 System.setProperty("java.naming.factory.initial", 138 "org.apache.commons.configuration.MockInitialContextFactory"); 139 System.setProperty("test_file_xml", "test.xml"); 140 System.setProperty("test_file_combine", "testcombine1.xml"); 141 System.setProperty("basePath", getBasePath()); 142 FileSystem fs = new VFSFileSystem(); 143 fs.setFileOptionsProvider(this); 144 FileSystem.setDefaultFileSystem(fs); 145 factory = new DefaultConfigurationBuilder(); 146 factory.setBasePath(getBasePath()); 147 factory.clearErrorListeners(); // avoid exception messages 148 } 149 150 @After 151 public void tearDown() throws Exception 152 { 153 FileSystem.resetDefaultFileSystem(); 154 } 155 156 /** 157 * Tests the isReservedNode() method of ConfigurationDeclaration. 158 */ 159 @Test 160 public void testConfigurationDeclarationIsReserved() 161 { 162 DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( 163 factory, factory); 164 DefaultConfigurationNode parent = new DefaultConfigurationNode(); 165 DefaultConfigurationNode nd = new DefaultConfigurationNode("at"); 166 parent.addAttribute(nd); 167 assertTrue("Attribute at not recognized", decl.isReservedNode(nd)); 168 nd = new DefaultConfigurationNode("optional"); 169 parent.addAttribute(nd); 170 assertTrue("Attribute optional not recognized", decl.isReservedNode(nd)); 171 nd = new DefaultConfigurationNode("config-class"); 172 parent.addAttribute(nd); 173 assertTrue("Inherited attribute not recognized", decl 174 .isReservedNode(nd)); 175 nd = new DefaultConfigurationNode("different"); 176 parent.addAttribute(nd); 177 assertFalse("Wrong reserved attribute", decl.isReservedNode(nd)); 178 nd = new DefaultConfigurationNode("at"); 179 parent.addChild(nd); 180 assertFalse("Node type not evaluated", decl.isReservedNode(nd)); 181 } 182 183 /** 184 * Tests if the at attribute is correctly detected as reserved attribute. 185 */ 186 @Test 187 public void testConfigurationDeclarationIsReservedAt() 188 { 189 checkOldReservedAttribute("at"); 190 } 191 192 /** 193 * Tests if the optional attribute is correctly detected as reserved 194 * attribute. 195 */ 196 @Test 197 public void testConfigurationDeclarationIsReservedOptional() 198 { 199 checkOldReservedAttribute("optional"); 200 } 201 202 /** 203 * Tests if special reserved attributes are recognized by the 204 * isReservedNode() method. For compatibility reasons the attributes "at" 205 * and "optional" are also treated as reserved attributes, but only if there 206 * are no corresponding attributes with the "config-" prefix. 207 * 208 * @param name the attribute name 209 */ 210 private void checkOldReservedAttribute(String name) 211 { 212 DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( 213 factory, factory); 214 DefaultConfigurationNode parent = new DefaultConfigurationNode(); 215 DefaultConfigurationNode nd = new DefaultConfigurationNode("config-" 216 + name); 217 parent.addAttribute(nd); 218 assertTrue("config-" + name + " attribute not recognized", decl 219 .isReservedNode(nd)); 220 DefaultConfigurationNode nd2 = new DefaultConfigurationNode(name); 221 parent.addAttribute(nd2); 222 assertFalse(name + " is reserved though config- exists", decl 223 .isReservedNode(nd2)); 224 assertTrue("config- attribute not recognized when " + name + " exists", 225 decl.isReservedNode(nd)); 226 } 227 228 /** 229 * Tests access to certain reserved attributes of a 230 * ConfigurationDeclaration. 231 */ 232 @Test 233 public void testConfigurationDeclarationGetAttributes() 234 { 235 factory.addProperty("xml.fileName", "test.xml"); 236 DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( 237 factory, factory.configurationAt("xml")); 238 assertNull("Found an at attribute", decl.getAt()); 239 assertFalse("Found an optional attribute", decl.isOptional()); 240 factory.addProperty("xml[@config-at]", "test1"); 241 assertEquals("Wrong value of at attribute", "test1", decl.getAt()); 242 factory.addProperty("xml[@at]", "test2"); 243 assertEquals("Wrong value of config-at attribute", "test1", decl.getAt()); 244 factory.clearProperty("xml[@config-at]"); 245 assertEquals("Old at attribute not detected", "test2", decl.getAt()); 246 factory.addProperty("xml[@config-optional]", "true"); 247 assertTrue("Wrong value of optional attribute", decl.isOptional()); 248 factory.addProperty("xml[@optional]", "false"); 249 assertTrue("Wrong value of config-optional attribute", decl.isOptional()); 250 factory.clearProperty("xml[@config-optional]"); 251 factory.setProperty("xml[@optional]", Boolean.TRUE); 252 assertTrue("Old optional attribute not detected", decl.isOptional()); 253 } 254 255 /** 256 * Tests whether an invalid value of an optional attribute is detected. 257 */ 258 @Test(expected = ConfigurationRuntimeException.class) 259 public void testConfigurationDeclarationOptionalAttributeInvalid() 260 { 261 factory.addProperty("xml.fileName", "test.xml"); 262 DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( 263 factory, factory.configurationAt("xml")); 264 factory.setProperty("xml[@optional]", "invalid value"); 265 decl.isOptional(); 266 } 267 268 /** 269 * Tests adding a new configuration provider. 270 */ 271 @Test 272 public void testAddConfigurationProvider() 273 { 274 DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider(); 275 assertNull("Provider already registered", factory 276 .providerForTag("test")); 277 factory.addConfigurationProvider("test", provider); 278 assertSame("Provider not registered", provider, factory 279 .providerForTag("test")); 280 } 281 282 /** 283 * Tries to register a null configuration provider. This should cause an 284 * exception. 285 */ 286 @Test(expected = IllegalArgumentException.class) 287 public void testAddConfigurationProviderNull() 288 { 289 factory.addConfigurationProvider("test", null); 290 } 291 292 /** 293 * Tries to register a configuration provider for a null tag. This should 294 * cause an exception to be thrown. 295 */ 296 @Test(expected = IllegalArgumentException.class) 297 public void testAddConfigurationProviderNullTag() 298 { 299 factory.addConfigurationProvider(null, 300 new DefaultConfigurationBuilder.ConfigurationProvider()); 301 } 302 303 /** 304 * Tests removing configuration providers. 305 */ 306 @Test 307 public void testRemoveConfigurationProvider() 308 { 309 assertNull("Removing unknown provider", factory 310 .removeConfigurationProvider("test")); 311 assertNull("Removing provider for null tag", factory 312 .removeConfigurationProvider(null)); 313 DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider(); 314 factory.addConfigurationProvider("test", provider); 315 assertSame("Failed to remove provider", provider, factory 316 .removeConfigurationProvider("test")); 317 assertNull("Provider still registered", factory.providerForTag("test")); 318 } 319 320 /** 321 * Tests creating a configuration object from a configuration declaration. 322 */ 323 @Test 324 public void testConfigurationBeanFactoryCreateBean() 325 { 326 factory.addConfigurationProvider("test", 327 new DefaultConfigurationBuilder.ConfigurationProvider( 328 PropertiesConfiguration.class)); 329 factory.addProperty("test[@throwExceptionOnMissing]", "true"); 330 DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( 331 factory, factory.configurationAt("test")); 332 PropertiesConfiguration conf = (PropertiesConfiguration) BeanHelper 333 .createBean(decl); 334 assertTrue("Property was not initialized", conf 335 .isThrowExceptionOnMissing()); 336 } 337 338 /** 339 * Tests creating a configuration object from an unknown tag. This should 340 * cause an exception. 341 */ 342 @Test(expected = ConfigurationRuntimeException.class) 343 public void testConfigurationBeanFactoryCreateUnknownTag() 344 { 345 factory.addProperty("test[@throwExceptionOnMissing]", "true"); 346 DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( 347 factory, factory.configurationAt("test")); 348 BeanHelper.createBean(decl); 349 } 350 351 /** 352 * Tests loading a simple configuration definition file. 353 */ 354 @Test 355 public void testLoadConfiguration() throws ConfigurationException 356 { 357 factory.setFileName(TEST_FILE); 358 checkConfiguration(); 359 } 360 361 /** 362 * Tests the file constructor. 363 */ 364 @Test 365 public void testLoadConfigurationFromFile() throws ConfigurationException 366 { 367 factory = new DefaultConfigurationBuilder(getBasePath() + TEST_FILE); 368 checkConfiguration(); 369 } 370 371 /** 372 * This test doesn't test DefaultConfigurationBuilder. It tests saving a file 373 * using Webdav file options. 374 */ 375 @Test 376 public void testSaveConfiguration() throws ConfigurationException 377 { 378 options = new HashMap<String, Object>(); 379 options.put(FileOptionsProvider.VERSIONING, Boolean.TRUE); 380 options.put(FileOptionsProvider.CURRENT_USER, "TestUser"); 381 XMLConfiguration conf = new XMLConfiguration(); 382 conf.setFileName(getBasePath() + TEST_PROPERTIES); 383 conf.load(); 384 conf.save(getBasePath() + TEST_SAVE); 385 XMLConfiguration checkConfig = new XMLConfiguration(); 386 checkConfig.setFileName(getBasePath() + TEST_SAVE); 387 checkSavedConfig(conf, checkConfig); 388 options = null; 389 } 390 391 /** 392 * Tests if the configuration was correctly created by the factory. 393 */ 394 private void checkConfiguration() throws ConfigurationException 395 { 396 CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory 397 .getConfiguration(); 398 399 assertEquals("Number of configurations", 3, compositeConfiguration 400 .getNumberOfConfigurations()); 401 assertEquals(PropertiesConfiguration.class, compositeConfiguration 402 .getConfiguration(0).getClass()); 403 assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration 404 .getConfiguration(1).getClass()); 405 assertEquals(XMLConfiguration.class, compositeConfiguration 406 .getConfiguration(2).getClass()); 407 408 // check the first configuration 409 PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration 410 .getConfiguration(0); 411 assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc 412 .getFileName()); 413 414 // check some properties 415 checkProperties(compositeConfiguration); 416 } 417 418 /** 419 * Checks if the passed in configuration contains the expected properties. 420 * 421 * @param compositeConfiguration the configuration to check 422 */ 423 private void checkProperties(Configuration compositeConfiguration) 424 { 425 assertTrue("Make sure we have loaded our key", compositeConfiguration 426 .getBoolean("test.boolean")); 427 assertEquals("I'm complex!", compositeConfiguration 428 .getProperty("element2.subelement.subsubelement")); 429 assertEquals("property in the XMLPropertiesConfiguration", "value1", 430 compositeConfiguration.getProperty("key1")); 431 } 432 433 /** 434 * Tests loading a configuration definition file with an additional section. 435 */ 436 @Test 437 public void testLoadAdditional() throws ConfigurationException 438 { 439 factory.setFileName(ADDITIONAL_FILE); 440 CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory 441 .getConfiguration(); 442 assertEquals("Verify how many configs", 2, compositeConfiguration 443 .getNumberOfConfigurations()); 444 445 // Test if union was constructed correctly 446 Object prop = compositeConfiguration.getProperty("tables.table.name"); 447 assertTrue(prop instanceof Collection); 448 assertEquals(3, ((Collection<?>) prop).size()); 449 assertEquals("users", compositeConfiguration 450 .getProperty("tables.table(0).name")); 451 assertEquals("documents", compositeConfiguration 452 .getProperty("tables.table(1).name")); 453 assertEquals("tasks", compositeConfiguration 454 .getProperty("tables.table(2).name")); 455 456 prop = compositeConfiguration 457 .getProperty("tables.table.fields.field.name"); 458 assertTrue(prop instanceof Collection); 459 assertEquals(17, ((Collection<?>) prop).size()); 460 461 assertEquals("smtp.mydomain.org", compositeConfiguration 462 .getString("mail.host.smtp")); 463 assertEquals("pop3.mydomain.org", compositeConfiguration 464 .getString("mail.host.pop")); 465 466 // This was overridden 467 assertEquals("masterOfPost", compositeConfiguration 468 .getString("mail.account.user")); 469 assertEquals("topsecret", compositeConfiguration 470 .getString("mail.account.psswd")); 471 472 // This was overridden, too, but not in additional section 473 assertEquals("enhanced factory", compositeConfiguration 474 .getString("test.configuration")); 475 } 476 477 /** 478 * Tests whether a default log error listener is registered at the builder 479 * instance. 480 */ 481 @Test 482 public void testLogErrorListener() 483 { 484 assertEquals("No default error listener registered", 1, 485 new DefaultConfigurationBuilder().getErrorListeners().size()); 486 } 487 488 /** 489 * Tests loading a definition file that contains optional configurations. 490 */ 491 @Test 492 public void testLoadOptional() throws Exception 493 { 494 factory.setFileName(OPTIONAL_FILE); 495 Configuration config = factory.getConfiguration(); 496 assertTrue(config.getBoolean("test.boolean")); 497 assertEquals("value", config.getProperty("element")); 498 } 499 500 /** 501 * Tests whether loading a failing optional configuration causes an error 502 * event. 503 */ 504 @Test 505 public void testLoadOptionalErrorEvent() throws Exception 506 { 507 factory.clearErrorListeners(); 508 ConfigurationErrorListenerImpl listener = new ConfigurationErrorListenerImpl(); 509 factory.addErrorListener(listener); 510 prepareOptionalTest("configuration", false); 511 listener.verify(DefaultConfigurationBuilder.EVENT_ERR_LOAD_OPTIONAL, 512 OPTIONAL_NAME, null); 513 } 514 515 /** 516 * Tests loading a definition file with optional and non optional 517 * configuration sources. One non optional does not exist, so this should 518 * cause an exception. 519 */ 520 @Test(expected = ConfigurationException.class) 521 public void testLoadOptionalWithException() throws ConfigurationException 522 { 523 factory.setFileName(OPTIONALEX_FILE); 524 factory.getConfiguration(); 525 } 526 527 /** 528 * Tries to load a configuration file with an optional, non file-based 529 * configuration. The optional attribute should work for other configuration 530 * classes, too. 531 */ 532 @Test 533 public void testLoadOptionalNonFileBased() throws ConfigurationException 534 { 535 CombinedConfiguration config = prepareOptionalTest("configuration", false); 536 assertTrue("Configuration not empty", config.isEmpty()); 537 assertEquals("Wrong number of configurations", 0, config 538 .getNumberOfConfigurations()); 539 } 540 541 /** 542 * Tests loading an embedded optional configuration builder with the force 543 * create attribute. 544 */ 545 @Test 546 public void testLoadOptionalBuilderForceCreate() 547 throws ConfigurationException 548 { 549 CombinedConfiguration config = prepareOptionalTest("configuration", 550 true); 551 assertEquals("Wrong number of configurations", 1, config 552 .getNumberOfConfigurations()); 553 assertTrue( 554 "Wrong optional configuration type", 555 config.getConfiguration(OPTIONAL_NAME) instanceof CombinedConfiguration); 556 } 557 558 /** 559 * Tests loading an optional configuration with the force create attribute 560 * set. The provider will always throw an exception. In this case the 561 * configuration will not be added to the resulting combined configuration. 562 */ 563 @Test 564 public void testLoadOptionalForceCreateWithException() 565 throws ConfigurationException 566 { 567 factory.addConfigurationProvider("test", 568 new DefaultConfigurationBuilder.ConfigurationBuilderProvider() 569 { 570 // Throw an exception here, too 571 @Override 572 public AbstractConfiguration getEmptyConfiguration( 573 DefaultConfigurationBuilder.ConfigurationDeclaration decl) throws Exception 574 { 575 throw new Exception("Unable to create configuration!"); 576 } 577 }); 578 CombinedConfiguration config = prepareOptionalTest("test", true); 579 assertEquals("Optional configuration could be created", 0, config 580 .getNumberOfConfigurations()); 581 } 582 583 /** 584 * Prepares a test for loading a configuration definition file with an 585 * optional configuration declaration. 586 * 587 * @param tag the tag name with the optional configuration 588 * @param force the forceCreate attribute 589 * @return the combined configuration obtained from the builder 590 * @throws ConfigurationException if an error occurs 591 */ 592 private CombinedConfiguration prepareOptionalTest(String tag, boolean force) 593 throws ConfigurationException 594 { 595 String prefix = "override." + tag; 596 factory.addProperty(prefix + "[@fileName]", "nonExisting.xml"); 597 factory.addProperty(prefix + "[@config-optional]", Boolean.TRUE); 598 factory.addProperty(prefix + "[@config-name]", OPTIONAL_NAME); 599 if (force) 600 { 601 factory.addProperty(prefix + "[@config-forceCreate]", Boolean.TRUE); 602 } 603 return factory.getConfiguration(false); 604 } 605 606 /** 607 * Tests loading a definition file with multiple different sources. 608 */ 609 @Test 610 public void testLoadDifferentSources() throws ConfigurationException 611 { 612 factory.setFileName(MULTI_FILE); 613 Configuration config = factory.getConfiguration(); 614 assertFalse(config.isEmpty()); 615 assertTrue(config instanceof CombinedConfiguration); 616 CombinedConfiguration cc = (CombinedConfiguration) config; 617 assertEquals("Wrong number of configurations", 1, cc 618 .getNumberOfConfigurations()); 619 620 assertNotNull(config 621 .getProperty("tables.table(0).fields.field(2).name")); 622 assertNotNull(config.getProperty("element2.subelement.subsubelement")); 623 assertEquals("value", config.getProperty("element3")); 624 assertEquals("foo", config.getProperty("element3[@name]")); 625 assertNotNull(config.getProperty("mail.account.user")); 626 627 // test JNDIConfiguration 628 assertNotNull(config.getProperty("test.onlyinjndi")); 629 assertTrue(config.getBoolean("test.onlyinjndi")); 630 631 Configuration subset = config.subset("test"); 632 assertNotNull(subset.getProperty("onlyinjndi")); 633 assertTrue(subset.getBoolean("onlyinjndi")); 634 635 // test SystemConfiguration 636 assertNotNull(config.getProperty("java.version")); 637 assertEquals(System.getProperty("java.version"), config 638 .getString("java.version")); 639 } 640 641 /** 642 * Tests if the base path is correctly evaluated. 643 */ 644 @Test 645 public void testSetConfigurationBasePath() throws ConfigurationException 646 { 647 factory.addProperty("properties[@fileName]", "test.properties"); 648 File deepDir = new File("conf/config/deep"); 649 factory.setConfigurationBasePath(deepDir.getAbsolutePath()); 650 651 Configuration config = factory.getConfiguration(false); 652 assertEquals("Wrong property value", "somevalue", config 653 .getString("somekey")); 654 } 655 656 /** 657 * Tests reading a configuration definition file that contains complex 658 * initialization of properties of the declared configuration sources. 659 */ 660 @Test 661 public void testComplexInitialization() throws ConfigurationException 662 { 663 factory.setFileName(INIT_FILE); 664 CombinedConfiguration cc = (CombinedConfiguration) factory 665 .getConfiguration(); 666 667 assertEquals("System property not found", "test.xml", 668 cc.getString("test_file_xml")); 669 PropertiesConfiguration c1 = (PropertiesConfiguration) cc 670 .getConfiguration(1); 671 assertTrue( 672 "Reloading strategy was not set", 673 c1.getReloadingStrategy() instanceof FileChangedReloadingStrategy); 674 assertEquals("Refresh delay was not set", 10000, 675 ((FileChangedReloadingStrategy) c1.getReloadingStrategy()) 676 .getRefreshDelay()); 677 678 Configuration xmlConf = cc.getConfiguration("xml"); 679 assertEquals("Property not found", "I'm complex!", xmlConf 680 .getString("element2/subelement/subsubelement")); 681 assertEquals("List index not found", "two", xmlConf 682 .getString("list[0]/item[1]")); 683 assertEquals("Property in combiner file not found", "yellow", cc 684 .getString("/gui/selcolor")); 685 686 assertTrue("Delimiter flag was not set", cc 687 .isDelimiterParsingDisabled()); 688 assertTrue("Expression engine was not set", 689 cc.getExpressionEngine() instanceof XPathExpressionEngine); 690 } 691 692 /** 693 * Tests if the returned combined configuration has the expected structure. 694 */ 695 @Test 696 public void testCombinedConfiguration() throws ConfigurationException 697 { 698 factory.setFileName(INIT_FILE); 699 CombinedConfiguration cc = (CombinedConfiguration) factory 700 .getConfiguration(); 701 assertNotNull("Properties configuration not found", cc 702 .getConfiguration("properties")); 703 assertNotNull("XML configuration not found", cc.getConfiguration("xml")); 704 assertEquals("Wrong number of contained configs", 4, cc 705 .getNumberOfConfigurations()); 706 707 CombinedConfiguration cc2 = (CombinedConfiguration) cc 708 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); 709 assertNotNull("No additional configuration found", cc2); 710 Set<String> names = cc2.getConfigurationNames(); 711 assertEquals("Wrong number of contained additional configs", 2, names 712 .size()); 713 assertTrue("Config 1 not contained", names.contains("combiner1")); 714 assertTrue("Config 2 not contained", names.contains("combiner2")); 715 } 716 717 /** 718 * Tests the structure of the returned combined configuration if there is no 719 * additional section. 720 */ 721 @Test 722 public void testCombinedConfigurationNoAdditional() 723 throws ConfigurationException 724 { 725 factory.setFileName(TEST_FILE); 726 CombinedConfiguration cc = factory.getConfiguration(true); 727 assertNull("Additional configuration was found", cc 728 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME)); 729 } 730 731 /** 732 * Tests whether the list node definition was correctly processed. 733 */ 734 @Test 735 public void testCombinedConfigurationListNodes() 736 throws ConfigurationException 737 { 738 factory.setFileName(INIT_FILE); 739 CombinedConfiguration cc = factory.getConfiguration(true); 740 Set<String> listNodes = cc.getNodeCombiner().getListNodes(); 741 assertEquals("Wrong number of list nodes", 2, listNodes.size()); 742 assertTrue("table node not a list node", listNodes.contains("table")); 743 assertTrue("list node not a list node", listNodes.contains("list")); 744 745 CombinedConfiguration cca = (CombinedConfiguration) cc 746 .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); 747 listNodes = cca.getNodeCombiner().getListNodes(); 748 assertTrue("Found list nodes for additional combiner", listNodes 749 .isEmpty()); 750 } 751 752 /** 753 * Tests whether XML settings can be inherited. 754 */ 755 @Test 756 public void testLoadXMLWithSettings() throws ConfigurationException, 757 IOException 758 { 759 File confDir = new File("conf"); 760 File targetDir = new File("target"); 761 File testXMLSource = new File(confDir, "testDtd.xml"); 762 File testXMLValidationSource = new File(confDir, 763 "testValidateInvalid.xml"); 764 File testSavedXML = new File(targetDir, "testSave.xml"); 765 File testSavedFactory = new File(targetDir, "testSaveFactory.xml"); 766 File dtdFile = new File(confDir, "properties.dtd"); 767 final String publicId = "http://commons.apache.org/test.dtd"; 768 769 XMLConfiguration config = new XMLConfiguration(testXMLSource); 770 config.setPublicID(publicId); 771 config.save(testSavedXML); 772 factory.addProperty("xml[@fileName]", testSavedXML.getAbsolutePath()); 773 factory.addProperty("xml(0)[@validating]", "true"); 774 factory.addProperty("xml(-1)[@fileName]", testXMLValidationSource 775 .getAbsolutePath()); 776 factory.addProperty("xml(1)[@config-optional]", "true"); 777 factory.addProperty("xml(1)[@validating]", "true"); 778 factory.save(testSavedFactory); 779 780 factory = new DefaultConfigurationBuilder(); 781 factory.setFile(testSavedFactory); 782 factory.registerEntityId(publicId, dtdFile.toURI().toURL()); 783 factory.clearErrorListeners(); 784 Configuration c = factory.getConfiguration(); 785 assertEquals("Wrong property value", "value1", c.getString("entry(0)")); 786 assertFalse("Invalid XML source was loaded", c 787 .containsKey("table.name")); 788 789 testSavedXML.delete(); 790 testSavedFactory.delete(); 791 } 792 793 /** 794 * Tests loading a configuration definition file that defines a custom 795 * result class. 796 */ 797 @Test 798 public void testExtendedClass() throws ConfigurationException 799 { 800 factory.setFileName(CLASS_FILE); 801 CombinedConfiguration cc = factory.getConfiguration(true); 802 String prop = (String)cc.getProperty("test"); 803 assertEquals("Expected 'Extended', actual '" + prop + "'", "Extended", prop); 804 assertTrue("Wrong result class: " + cc.getClass(), 805 cc instanceof TestDefaultConfigurationBuilder.ExtendedCombinedConfiguration); 806 } 807 808 /** 809 * Tests loading a configuration definition file that defines new providers. 810 */ 811 @Test 812 public void testConfigurationProvider() throws ConfigurationException 813 { 814 factory.setFileName(PROVIDER_FILE); 815 factory.getConfiguration(true); 816 DefaultConfigurationBuilder.ConfigurationProvider provider = factory 817 .providerForTag("test"); 818 assertNotNull("Provider 'test' not registered", provider); 819 } 820 821 /** 822 * Tests loading a configuration definition file that defines new providers. 823 */ 824 @Test 825 public void testExtendedXMLConfigurationProvider() throws ConfigurationException 826 { 827 factory.setFileName(EXTENDED_PROVIDER_FILE); 828 CombinedConfiguration cc = factory.getConfiguration(true); 829 DefaultConfigurationBuilder.ConfigurationProvider provider = factory 830 .providerForTag("test"); 831 assertNotNull("Provider 'test' not registered", provider); 832 Configuration config = cc.getConfiguration("xml"); 833 assertNotNull("Test configuration not present", config); 834 assertTrue("Configuration is not ExtendedXMLConfiguration, is " + 835 config.getClass().getName(), 836 config instanceof TestDefaultConfigurationBuilder.ExtendedXMLConfiguration); 837 } 838 839 @Test 840 public void testGlobalLookup() throws Exception 841 { 842 factory.setFileName(GLOBAL_LOOKUP_FILE); 843 CombinedConfiguration cc = factory.getConfiguration(true); 844 String value = cc.getInterpolator().lookup("test:test_key"); 845 assertNotNull("The test key was not located", value); 846 assertEquals("Incorrect value retrieved","test.value",value); 847 } 848 849 @Test 850 public void testSystemProperties() throws Exception 851 { 852 factory.setFileName(SYSTEM_PROPS_FILE); 853 factory.getConfiguration(true); 854 String value = System.getProperty("key1"); 855 assertNotNull("The test key was not located", value); 856 assertEquals("Incorrect value retrieved","value1",value); 857 } 858 859 @Test 860 public void testValidation() throws Exception 861 { 862 factory.setFileName(VALIDATION_FILE); 863 factory.getConfiguration(true); 864 String value = System.getProperty("key1"); 865 assertNotNull("The test key was not located", value); 866 assertEquals("Incorrect value retrieved","value1",value); 867 } 868 869 @Test 870 public void testMultiTenentConfiguration() throws Exception 871 { 872 factory.setFileName(MULTI_TENENT_FILE); 873 System.getProperties().remove("Id"); 874 875 CombinedConfiguration config = factory.getConfiguration(true); 876 assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); 877 878 verify("1001", config, 15); 879 verify("1002", config, 25); 880 verify("1003", config, 35); 881 verify("1004", config, 50); 882 verify("1005", config, 50); 883 } 884 885 @Test 886 public void testMultiTenentConfiguration2() throws Exception 887 { 888 factory.setFileName(MULTI_TENENT_FILE); 889 System.setProperty("Id", "1004"); 890 891 CombinedConfiguration config = factory.getConfiguration(true); 892 assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); 893 894 verify("1001", config, 15); 895 verify("1002", config, 25); 896 verify("1003", config, 35); 897 verify("1004", config, 50); 898 verify("1005", config, 50); 899 } 900 901 @Test 902 public void testMultiTenentConfiguration3() throws Exception 903 { 904 factory.setFileName(MULTI_TENENT_FILE); 905 System.setProperty("Id", "1005"); 906 907 CombinedConfiguration config = factory.getConfiguration(true); 908 assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); 909 910 verify("1001", config, 15); 911 verify("1002", config, 25); 912 verify("1003", config, 35); 913 verify("1004", config, 50); 914 verify("1005", config, 50); 915 } 916 917 @Test 918 public void testFileChanged() throws Exception 919 { 920 // create a new configuration 921 File input = new File("target/test-classes/testMultiConfiguration_1001.xml"); 922 FileObject output = getFile(getBasePath() + FILERELOAD_1001_FILE); 923 output.delete(); 924 output.getParent().createFolder(); 925 copyFile(input, output); 926 927 factory.setFileName(getBasePath() + FILERELOAD2_FILE); 928 System.getProperties().remove("Id"); 929 930 CombinedConfiguration config = factory.getConfiguration(true); 931 assertNotNull(config); 932 config.addConfigurationListener(this); 933 verify("1001", config, 15); 934 935 // Allow time for FileMonitor to set up. 936 Thread.sleep(1000); 937 XMLConfiguration x = new XMLConfiguration(getBasePath() + FILERELOAD_1001_FILE); 938 x.setProperty("rowsPerPage", "50"); 939 x.save(); 940 // Let FileMonitor detect the change. 941 //Thread.sleep(2000); 942 waitForChange(); 943 verify("1001", config, 50); 944 output.delete(); 945 } 946 947 @Test 948 public void testFileChanged2() throws Exception 949 { 950 // create a new configuration 951 File input = new File("target/test-classes/testMultiConfiguration_1002.xml"); 952 FileObject output = getFile(getBasePath() + FILERELOAD_1002_FILE); 953 output.delete(); 954 955 factory.setFileName(getBasePath() + FILERELOAD2_FILE); 956 System.getProperties().remove("Id"); 957 958 CombinedConfiguration config = factory.getConfiguration(true); 959 assertNotNull(config); 960 config.addConfigurationListener(this); 961 962 verify("1002", config, 50); 963 Thread.sleep(1000); 964 965 output.getParent().createFolder(); 966 copyFile(input, output); 967 968 // Allow time for the monitor to notice the change. 969 //Thread.sleep(2000); 970 waitForChange(); 971 verify("1002", config, 25); 972 output.delete(); 973 } 974 975 private void verify(String key, CombinedConfiguration config, int rows) 976 { 977 System.setProperty("Id", key); 978 int actual = config.getInt("rowsPerPage"); 979 assertTrue("expected: " + rows + " actual: " + actual, actual == rows); 980 } 981 982 public Map<String, Object> getOptions() 983 { 984 return this.options; 985 } 986 987 /** 988 * Helper method for checking if a save operation was successful. Loads a 989 * saved configuration and then tests against a reference configuration. 990 * @param conf the original configuration 991 * @param newConfig the configuration to check 992 * @throws ConfigurationException if an error occurs 993 */ 994 private void checkSavedConfig(XMLConfiguration conf, FileConfiguration newConfig) 995 throws ConfigurationException 996 { 997 newConfig.load(); 998 ConfigurationAssert.assertEquals(conf, newConfig); 999 } 1000 1001 private FileObject getFile(String fileName) throws Exception 1002 { 1003 FileSystemManager manager = VFS.getManager(); 1004 FileName file = manager.resolveURI(fileName); 1005 FileName base = file.getParent(); 1006 FileName path = manager.resolveName(base, file.getBaseName()); 1007 FileSystemOptions opts = new FileSystemOptions(); 1008 return manager.resolveFile(path.getURI(), opts); 1009 } 1010 1011 private void copyFile(File input, FileObject output) throws IOException 1012 { 1013 Reader reader = new FileReader(input); 1014 Writer writer = new OutputStreamWriter(output.getContent().getOutputStream()); 1015 char[] buffer = new char[4096]; 1016 int n = 0; 1017 while (-1 != (n = reader.read(buffer))) 1018 { 1019 writer.write(buffer, 0, n); 1020 } 1021 reader.close(); 1022 writer.close(); 1023 } 1024 1025 private void waitForChange() 1026 { 1027 synchronized(this) 1028 { 1029 try 1030 { 1031 int count = 0; 1032 while (!configChanged && count++ <= 3) 1033 { 1034 this.wait(5000); 1035 } 1036 } 1037 catch (InterruptedException ie) 1038 { 1039 throw new IllegalStateException("wait timed out"); 1040 } 1041 finally 1042 { 1043 configChanged = false; 1044 } 1045 } 1046 } 1047 1048 public void configurationChanged(ConfigurationEvent event) 1049 { 1050 if (event.getType() == AbstractFileConfiguration.EVENT_CONFIG_CHANGED) 1051 { 1052 synchronized(this) 1053 { 1054 configChanged = true; 1055 this.notify(); 1056 } 1057 } 1058 } 1059 }