commons-configuration-1.10-src/LICENSE.txt100644 26136 12232154104 20067 0ustarhenningstaff 0 0 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. commons-configuration-1.10-src/NOTICE.txt100644 266 12232154104 17722 0ustarhenningstaff 0 0 Apache Commons Configuration Copyright 2001-2013 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). commons-configuration-1.10-src/pom.xml100644 50354 12232154104 17560 0ustarhenningstaff 0 0 org.apache.commons commons-parent 32 4.0.0 commons-configuration commons-configuration 1.10 Apache Commons Configuration 2001 Tools to assist in the reading of configuration/preferences files in various formats. http://commons.apache.org/configuration/ jira http://issues.apache.org/jira/browse/CONFIGURATION scm:svn:http://svn.apache.org/repos/asf/commons/proper/configuration/tags/CONFIGURATION_1_10RC2 scm:svn:https://svn.apache.org/repos/asf/commons/proper/configuration/tags/CONFIGURATION_1_10RC2 http://svn.apache.org/viewvc/commons/proper/configuration/tags/CONFIGURATION_1_10RC2 apache.website ${commons.deployment.protocol}://people.apache.org/www/commons.apache.org/${commons.componentid} Daniel Rall dlr dlr@finemaltcoding.com CollabNet, Inc. Java Developer Jason van Zyl jvanzyl jason@zenplex.com Zenplex Java Developer Martin Poeschl mpoeschl mpoeschl@marmot.at tucana.at Java Developer dIon Gillard dion dion@multitask.com.au Multitask Consulting Java Developer Henning P. Schmiedehausen henning henning@schmiedehausen.org -8 Java Developer Eric Pugh epugh epugh@upstate.com upstate.com Java Developer Brian E. Dunbar bdunbar bdunbar@dunbarconsulting.org dunbarconsulting.org Java Developer Emmanuel Bourg ebourg ebourg@apache.org Ariane Software +1 Java Developer Oliver Heger oheger oheger@apache.org Agfa HealthCare +1 Java Developer Jörg Schaible joehni joerg.schaible@gmx.de +1 Java Developer Ralph Goers rgoers rgoers@apache.org Intuit -8 Java Developer Konstantin Shaposhnikov ksh@scand.com scand.com Jamie M. Guillemette JMGuillemette@gmail.com TD Bank Jorge Ferrer jorge.ferrer@gmail.com Gabriele Garuglieri gabriele.garuglieri@infoblu.it Infoblu S.p.A Nicolas De Loof nicolas.deloof@gmail.com Cap Gemini commons-collections commons-collections 3.2.1 true commons-lang commons-lang 2.6 commons-logging commons-logging 1.1.1 logkit logkit avalon-framework avalon-framework commons-digester commons-digester 1.8.1 true commons-beanutils commons-beanutils 1.8.3 true commons-codec commons-codec 1.6 true org.apache.commons commons-jexl 2.1.1 true org.apache.commons commons-vfs2 2.0 true commons-jxpath commons-jxpath 1.3 true xerces xerces ant ant-optional xml-resolver xml-resolver 1.2 true javax.servlet servlet-api 2.4 provided xerces xercesImpl 2.6.2 test xml-apis xml-apis 1.0.b2 provided commons-dbcp commons-dbcp 1.2.2 test commons-pool commons-pool 1.4 test hsqldb hsqldb 1.7.2.2 test dbunit dbunit 2.1 test junit junit 4.11 test junit-addons junit-addons 1.4 test xerces xmlParserAPIs xerces xercesImpl mockobjects mockobjects-core 0.09 test mockobjects mockobjects-jdk1.4-j2ee1.3 0.09 test org.easymock easymock 3.2 test javax.mail mail 1.4 test log4j log4j 1.2.8 true org.slf4j slf4j-api 1.5.6 test org.slf4j slf4j-ext 1.5.6 test org.slf4j slf4j-log4j12 1.5.6 test configuration 1.10 RC1 CONFIGURATION 1.5 1.5 org.apache.commons.beanutils.*;resolution:=optional, org.apache.commons.digester.*;resolution:=optional, org.apache.commons.collections.*;resolution:=optional, org.apache.commons.codec.*;resolution:=optional, org.apache.commons.jxpath.*;resolution:=optional, org.apache.xml.resolver.*;resolution:=optional, javax.servlet.*;resolution:=optional, org.apache.commons.jexl2.*;resolution:=optional, org.apache.commons.vfs2.*;resolution:=optional, * src/test/resources src/main/resources *.dtd ${basedir} META-INF NOTICE.txt LICENSE.txt maven-assembly-plugin src/main/assembly/bin.xml src/main/assembly/src.xml gnu org.apache.maven.plugins maven-surefire-plugin once **/TestWebdavConfigurationBuilder.java true org.apache.commons.configuration.Logging org.apache.maven.plugins maven-source-plugin attach-sources install jar org.codehaus.mojo javacc-maven-plugin 2.6 javacc javacc org.apache.maven.plugins maven-scm-publish-plugin javadocs** org.eclipse.m2e lifecycle-mapping 1.0.0 org.apache.maven.plugins maven-antrun-plugin [0,) run org.codehaus.mojo javacc-maven-plugin [0,) javacc webdav false org.apache.jackrabbit jackrabbit-webdav 1.5.2 test org.apache.maven.plugins maven-surefire-plugin once true ${test.webdav.base} **/TestWebdavConfigurationBuilder.java org.apache.maven.plugins maven-changes-plugin true org.apache.maven.plugins maven-checkstyle-plugin 2.7 ${basedir}/conf/checkstyle.xml ${basedir}/conf/checkstyle-suppressions.xml false basedir=${basedir} checkstyle org.apache.rat apache-rat-plugin src/java/org/apache/commons/configuration/plist/*.java velocity.log org.codehaus.mojo findbugs-maven-plugin 2.3.1 Normal Default ${basedir}/conf/findbugs-exclude-filter.xml org.codehaus.mojo clirr-maven-plugin ${commons.clirr.version} org/apache/commons/configuration/plist/PropertyListParser* commons-configuration-1.10-src/RELEASE-NOTES.txt100644 10037 12232154104 20744 0ustarhenningstaff 0 0 $Id: RELEASE-NOTES.txt 1534410 2013-10-21 23:13:34Z henning $ Commons Configuration Package Version 1.10 Release Notes INTRODUCTION ============ This document contains the release notes for this version of the Commons Configuration component. It describes the changes since the previous version. The Commons Configuration software library provides a generic configuration interface which enables an application to read configuration data from a variety of sources. The 1.10 release contains a couple of minor bug fixes and improvements. There are no important new features. The idea is to release the current changes which have been applied to the 1.x branch, so that we can start with new development on an improved (and partly binary incompatible) 2.0 version. As there are small changes only, Commons Configuration 1.10 is fully binary compatible to the previous version. The minimum required Java version is 1.5. Please note that this release was compiled with the Java 1.6 compiler in 1.5 mode. There is a very small chance that this introduced incompatibilities with the Java 1.5 runtime. Java 1.5 was EOLed in October 2009. Following is a complete list of all changes in the new 1.10 release: BUG FIXES IN 1.10 ================= * [CONFIGURATION-500] Attributes in xml config should apply to all entries of a list XMLConfiguration now adds attributes of elements defining a list to all list nodes. * [CONFIGURATION-546] ClassCastException in BeanHelper constructing beans with a list of child beans. BeanHelper can now process BeanDefinitions initializing properties of collection types of their target beans. * [CONFIGURATION-555] XMLConfiguration doesn't seem to be preserving whitespace for the current node where xml:space="preserve" is set. Fixed a bug in the handling of the xml:space attribute in XMLConfiguration. The attribute is now also applied to the current element, not only to sub elements. * [CONFIGURATION-556] Regression with SystemProperties in 1.8 and 1.9 In 1.7 and before, any change to the system properties was immediately reflected in a SystemConfiguration object. This behaviour broke in 1.8 and 1.9. This has been fixed for 1.10. * [CONFIGURATION-557] Regression: MapConfiguration no longer accepts a Map In 1.7 and before, it was possible to pass an arbitrary Map into the constructor of MapConfiguration. With the generification in 1.8, this actually broke and it was no longer possible to pass in e.g. a Map because the signature now required a Map. Changing the constructor to accept a Map restores this. All of this is purely a compiler issue, the runtime itself does not see any of the generics due to the Java type erasure. * [CONFIGURATION-558] Configuration no longer accepts List as default for getList() Similar to CONFIGURATION-557, the getList(String, List) method was generified to be getList(String, List) but needs to be getList(String, List) so that code that used a more specific list (such as a List) still compiles against the new API. IMPROVEMENTS AND NEW FEATURES IN 1.10 ===================================== * [CONFIGURATION-525] PropertiesConfigurationLayout does not preserve comments at bottom of a file PropertiesConfiguration now keeps a comment at the bottom of a properties file. A new footer property was added for reading and writing this footer comment. * [CONFIGURATION-526] Support loading from and saving to DOM nodes XMLPropertiesConfiguration now supports loading from and saving to DOM nodes. * [CONFIGURATION-534] PropertyConfiguration's handling of includes depends on the existence of a base path The includesAllowed property of PropertyConfiguration is now independent from the existence of a base path. * [CONFIGURATION-550] Missing conversion to char Conversion to Character is now supported. OTHER CHANGES ============= commons-configuration-1.10-src/conf/ 40755 0 0 0 12232154102 14507 5ustar 0 0 commons-configuration-1.10-src/conf/checkstyle-suppressions.xml100644 2637 12232154102 24602 0ustarhenningstaff 0 0 commons-configuration-1.10-src/conf/checkstyle.xml100644 16426 12232154102 22050 0ustarhenningstaff 0 0 commons-configuration-1.10-src/conf/CommonsConfiguration.xsd100644 12074 12232154102 24046 0ustarhenningstaff 0 0 Commons Configuration v0.1 commons-configuration-1.10-src/conf/findbugs-exclude-filter.xml100644 2353 12232154102 24377 0ustarhenningstaff 0 0 commons-configuration-1.10-src/conf/HEADER.txt100644 1442 12232154102 20631 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ commons-configuration-1.10-src/conf/README100644 160 12232154102 17774 0ustarhenningstaff 0 0 DO NOT DELETE THESE FILES! They're used by the unit tests for testing various Configuration implementations. commons-configuration-1.10-src/src/ 40755 0 0 0 12232154103 14352 5ustar 0 0 commons-configuration-1.10-src/src/changes/ 40755 0 12232154103 20315 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/ 40755 0 12232154103 17631 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/assembly/ 40755 0 12232154102 21447 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/ 40755 0 12232154102 20551 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/ 40755 0 12232154102 21340 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/ 40755 0 12232154102 22561 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/ 40755 0 12232154102 24234 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ 40755 0 12232154103 27104 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/ 40755 0 12232154102 31071 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ 40755 0 12232154102 30224 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/ 40755 0 12232154102 30737 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/plist/ 40755 0 12232154102 30236 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/ 40755 0 12232154102 31047 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/ 40755 0 12232154102 30744 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ 40755 0 12232154102 30042 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/ 40755 0 12232154102 31166 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ 40755 0 12232154102 27660 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/javacc/ 40755 0 12232154103 21060 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/resources/ 40755 0 12232154103 21643 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/site/ 40755 0 12232154103 17651 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/site/resources/ 40755 0 12232154103 21663 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/site/resources/images/ 40755 0 12232154103 23130 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/site/xdoc/ 40755 0 12232154103 20606 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/site/xdoc/userguide/ 40755 0 12232154103 22602 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/ 40755 0 12232154103 17664 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/ 40755 0 12232154103 20605 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/ 40755 0 12232154103 21374 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/ 40755 0 12232154103 22615 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/ 40755 0 12232154103 24270 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/ 40755 0 12232154104 27140 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/ 40755 0 12232154104 31126 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/ 40755 0 12232154103 30260 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/ 40755 0 12232154103 30773 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/ 40755 0 12232154103 30272 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/ 40755 0 12232154103 31103 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/test/ 40755 0 12232154103 30116 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/ 40755 0 12232154104 30077 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/ 40755 0 12232154104 31223 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/ 40755 0 12232154103 27714 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/ 40755 0 12232154103 21676 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/01/ 40755 0 12232154103 22116 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/config/ 40755 0 12232154103 23143 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/config/deep/ 40755 0 12232154103 24060 5ustarhenningstaff 0 0 commons-configuration-1.10-src/src/changes/changes.xml100644 275776 12232154103 22634 0ustarhenningstaff 0 0 Changes Eric Pugh XMLConfiguration now adds attributes of elements defining a list to all list nodes. PropertiesConfiguration now keeps a comment at the bottom of a properties file. A new footer property was added for reading and writing this footer comment. XMLPropertiesConfiguration now supports loading from and saving to DOM nodes. The includesAllowed property of PropertyConfiguration is now independent from the existence of a base path. BeanHelper can now process BeanDefinitions initializing properties of collection types of their target beans. Conversion to Character is now supported. Fixed a bug in the handling of the xml:space attribute in XMLConfiguration. The attribute is now also applied to the current element, not only to sub elements. In 1.7 and before, any change to the system properties was immediately reflected in a SystemConfiguration object. This behaviour broke in 1.8 and 1.9. This has been fixed for 1.10. In 1.7 and before, it was possible to pass an arbitrary Map into the constructor of MapConfiguration. With the generification in 1.8, this actually broke and it was no longer possible to pass in e.g. a Map<String, String> because the signature now required a Map<String, Object>. Changing the constructor to accept a Map<String, ?> restores this. Similar to CONFIGURATION-557, the getList(String, List) method was generified to be getList(String, List<Object>) but needs to be getList(String, List<?>) so that code that used a more specific list (such as a List<String>) still compiles against the new API. Small changes in user guide documentation. Improvements of basic features and AbstractConfiguration documentation. XMLPropertyListConfiguration no longer swallows exception caused by invalid date properties. Now a warning message is logged. List properties can now be set correctly on a HierarchicalConfiguration if delimiter parsing is disabled. Made static DateFormat fields in XMLPropertyListConfiguration.PListNode final and added a note about proper synchronization. DataConfiguration.get() now also works with String properties and if no data type conversion is required. DatabaseConfiguration now always closes the result set. The Import-Package section in the OSGi manifest now uses the resolution:=optional directive for optional dependencies. Variable substitution in configuration sources declared in a definition file for DefaultConfigurationBuilder now works across multiple sources. PropertyListConfiguration now can deal with C-style comments in plist configuration files. Both block and single-line comments are supported. Fixed possible ClassCastExceptions in CompositeConfiguration related to special in-memory configurations. Class ConfigurationKey was deprecated in favor of DefaultConfigurationKey. Implemented delimiter parsing in HierarchicalINIConfiguration to be consistent with other Configuration implementations. Note that this can impact existing code. To switch back to the old behavior, call setDelimiterParsingDisabled(true) before loading the configuration. CompositeConfiguration now provides better support for child configurations that are used as in-memory configuration. Classes generated by JavaCC are now created dynamically during the build process. Commons Configuration now requires Java 5 or later. Binary literals are now supported (i.e Ob11010001). Updated the dependency to Commons Jexl to version 2.1.1. This version provides correct OSGi manifest headers. Improved documentation of AbstractFileConfiguration related to load() methods and their impact on the base path. The project now uses standard Maven directory layout. Reloading now also works for configuration sources declared in the additional section of a configuration definition file for DefaultConfigurationBuilder. ConfigurationFactory has been deprecated. The user guide was updated to no more mention this class. HierarchicalConfiguration now provides a specific implementation of the clear() method. This is more efficient and also solves some other problems related to clearing a SubnodeConfiguration. Improved Javadocs of getKeys(String) method for some configuration classes. HierarchicalINIConfiguration.getSection() now creates a section if it does not exist. The SubnodeConfiguration returned by this method is now always connected to the parent ini configuration. XPathExpressionEngine now provides better support for the setProperty() method. The parsing of ini files has been improved for property definitions containing multiple separator characters. DefaultConfigurationBuilder now supports including environment properties using the "env" tag. XMLConfiguration now handles attributes correctly whose value is an empty string. Transforming a CombinedConfiguration with ViewNodes to an XMLConfiguration could cause problems with attributes. This has been fixed. Child configuration builders created for a <configuration> element in a configuration definition file now inherit the configuration and error listeners from the original DefaultConfigurationBuilder. This makes it possible to suppress log output created for optional configurations. JNDIConfiguration.getKeys() no more logs an exception if the prefix does not exist. Child configuration builders created for a <configuration> element in a configuration definition file now inherit some of their properties from the builder object which processed the file. The optional dependency to Apache Ant has been changed to the new groupId org.apache.ant. The version was updated to the most recent version 1.8.2 (older versions should still work). HierarchicalINIConfiguration now recognizes comment characters in property definitions only if they are preceded by whitespace. Thus comment characters can now be part of the property value. This is for instance required for the definition of file paths which use the semicolon as path separator. Minor improvements of the support for indexed properties in ConfigurationDynaBean. The methods getList() and getStringArray() of AbstractConfiguration can now handle single-valued properties of primitive types. XMLConfiguration no longer escapes backslashs in the values of XML elements. HierarchicalINIConfiguration now works correctly with configurations that contain only properties in the global section. testFromClassPath() can fail when it should not because of inconsistent escaping of output from PropertiesConfiguration.getURL() and FileChangedReloadingStrategy.getFile().toURL(). A bug related to the interpretation of escape sequences for backslashes has been fixed. The user guide has also been improved in this area. Files with a plus character in their names are now handled correctly. SubsetConfiguration now produces correct events. DatabaseConfiguration can now be instructed to perform a commit after an update of the managed database table. This makes it usable in environments where the connections do not use auto-commit mode. Added a refresh() method to AbstractFileConfiguration and AbstractHierarchicalFileConfiguration. HierarchicalINIConfiguration now correctly saves sections whose name contains delimiter characters. PropertiesConfiguration.save() escaped slashes in properties values. This was caused by a bug in commons-lang 2.4. Updating to the new version commons-lang 2.5 fixed this problem. Fixed a potential IllegalStateException in HierarchicalINIConfiguration that can be thrown when the global section is requested concurrently. XMLPropertyListConfiguration no longer throws a ConfigurationException if the file to be loaded does not have an outer dict element. The default expression engine used by hierarchical configurations used to throw a NumberFormatException if invalid indices were used in property keys. This has been fixed. As a side effect brackets can now be used in property keys. When an empty XMLConfiguration was saved and reloaded the root element was assigned an empty text value. Because of this isEmpty() returned false for this configuration. This has been fixed. Default variable interpolation now supports the env: prefix for referencing environment variables. Schema violation exceptions are now propagated back to the caller. XMLConfiguration and CombinedConfiguraton are now synchronized to fix problems caused by reloading in a multithreaded environment. HierarchicalConfiguration.NodeVisitor is now passed the correct key to its visitAfterChildren() method. BaseConfiguration.clone() now also clones collections stored in the internal map. This causes list properties to be handled correctly. DefaultConfigurationBuilder now supports defining ini files in its configuration definition file. Attribute or element values will not be escaped when attribute or element splitting are disabled. When using Commons Lang 2.6 or higher as dependency nested interpolation in variable names is supported. Empty dictionaries in a PropertyList configuration are now preserved when the configuration is saved. DatabaseConfiguration now generates correct events for the clear() and clearProperty() methods. Add ExprLookup to allow expressions to be evaluated in configurations. When used, this requires that Apache Commons Jexl be added as a dependency to projects using Commons Configuration. MapConfiguration now provides a way of controlling the trimming behavior. Added MergeCombiner to allow elements in two configurations to be merged when the element and attributes in the first file match those in the second file. File system access has been abstracted to a FileSystem interface. Two implementations are provided, DefaultFileSystem that behaves in a backward compatible manner and VFSFileSystem which uses Commons VFS to retreive and store files. PropertiesConfigurationLayout now allows setting the line separator to be used when writing the properties file. PropertiesConfigurationLayout now also stores the property separators used for the single properties. It is also possible to change them for specific properties or set a global properties separator. In earlier versions the separator was hard-coded to " = ". PropertiesConfiguration now defines a nested interface IOFactory. Using this interface it is possible to inject custom PropertiesReader and PropertiesWriter implementations. SubnodeConfiguration now fires an event of type EVENT_SUBNODE_CHANGED if a structural change of the parent configuration was detected. If the SubnodeConfiguration is contained in a CombinedConfiguration, the CombinedConfiguration receives this event and can update itself. MultiFileHierarchicalConfiguration was not using basepath to construct the file url. It also threw an exception if the file pattern resolved to a non-existent file. This is now configurable. Align interpolation functionality of SubnodeConfiguration and SubsetConfiguration. SubsetConfiguration will now also interpolate keys of the parent configuration or use the local lookups of its parent. SubnodeConfiguration is in turn now able to lookup local keys as well. Align interpolation functionality of SubnodeConfiguration and SubsetConfiguration. Align interpolation functionality of SubnodeConfiguration and SubsetConfiguration. SubsetConfiguration did not use locally registered lookups of its interpolator. Fixed broken links to the API documentation in the user's guide. Improvements of the user's guide for hierarchical configurations. The message of the ConversionException thrown by AbstractConfiguration.getBigInteger() is now correct. Added getConfigurations and getConfigurationNameList. Allow configurations to be validated using XML Schemas. Allow configurations to be validated using XML Schemas. Some dependencies to other Commons components have been updated to the recent versions. Affected are Commons Lang, Commons Collections, Commons Logging, Commons BeanUtils, and Commons JXPath. The older versions should still work. Allow system properties to be set from a configuration file. Allow variable resolvers to be defined configured in DefaultConfigurationBuilder. Added MultiFileHierarchicalConfiguration, DynamicCombinedConfiguration and PatternSubtreeConfigurationWrapper. The visibility of DefaultConfigurationBuilder.XMLConfigurationProvider was changed from package local to public. This makes it easier to implement providers that create configuration classes derived from XMLConfiguration. AbstractHierarchicalFileConfiguration.getKeys() now also checks whether a reload is required. AbstractFileConfiguration.getKeys() now returns an iterator that points to a snapshot of the keys of the configuration. This prevents ConcurrentModificationExceptions during iteration when a reload is performed. ConfigurationUtils.convertToHierarchical() now creates multiple configuration nodes for properties with multiple values. This improves compatibility with queries. PropertiesConfiguration now per default uses the encoding "ISO-8859-1" for loading properties files. CombinedConfiguration could cause a deadlock when it was accessed while concurrently a reload of one of its child configuration happened. This was fixed by reducing synchronization where it is not strictly necessary. The "force reload check" mechanism of CombinedConfiguration now also works with sub configurations created by configurationAt(). When performing interpolation the methods getList() and getStringArray() of CompositeConfiguration did not take the order of child configurations into account. This could lead to wrong interpolated values when the key was contained in multiple child configuration. Interpolation is now always done in the correct order. PropertiesConfiguration now also performs interpolation when searching for include files. This means that the name of a file to include can be determined by another property. DefaultConfigurationBuilder now supports defining new configuration providers in the configuration definition file. When converting a flat configuration to a hierarchical one it is now possible to specify the expression engine to be used for this purpose. This may be necessary if the flat configuration contains keys with special characters interpreted by the expression engine. CombinedConfiguration defines the new setConversionExpressionEngine() method. The expression engine passed to this method will be used when converting flat child configurations to hierarchical ones. XMLConfiguration now allows disabling the attribute splitting mechanism introduced in the 1.5 release (as part of the fix for CONFIGURATION-268). This may be necessary for correctly processing attributes containing both the list delimiter and the attribute delimiter character. The new property "disableAttributeSplitting" was added for this purpose. Made handling of parent nodes more consistent when setRoot() or setRootNode() of HierarchicalConfiguration are involved. Properties written through a DataConfiguration to a wrapped PropertiesConfiguration got lost when the PropertiesConfiguration was saved. This has been fixed. XMLBeanDeclaration now defines a factory method createBeanDeclaration() for creating the declarations for complex nested properties. This method can be overridden by derived classes for injecting custom BeanDeclaration implementations. A bug in XMLConfiguration.addNodes() made it impossible to add attribute nodes using this method. This has been fixed. INIConfiguration misinterpreted variables in the global section with a dot in their name as section names. HierarchicalINIConfiguration fixes this problem. INIConfiguration does not support obtaining a subset for the global section. HierarchicalINIConfiguration provides the getSection() method that returns the content of the global section if null is passed in as section name. INIConfiguration does not return the global section in its getSections() method. HierarchicalINIConfiguration fixes this problem. HierarchicalINIConfiguration adds support for line continuation. INIConfiguration has been deprecated. Its functionality is now available through the new HierarchicalINIConfiguration class. With HierarchicalINIConfiguration a complete new Configuration implementation for parsing Windows INI files is available. This new class is a full replacement of INIConfiguration and addresses some of its shortcomings. Being derived from HierarchicalConfiguration it offers the enhanced functionality of hierarchical configurations. ConfigurationDynaBean now works properly with indexed properties stored internally in the underlying configuration as arrays. The iterator returned by HierarchicalConfiguration.getKeys(String prefix) now also contains the prefix if this key is contained in the configuration. XMLPropertyListConfiguration is no longer limited to 32 bits integers. When an XMLConfiguration is created using the copy constructor, the name of the root element is now preserved. Changing the text of the root element of an XMLConfiguration had no effect when the configuration was saved. This has been fixed. CombinedConfiguration used to send two EVENT_COMBINED_INVALIDATE events for each modified child configuration. Now this event is sent only once after the affected child configuration was updated. XMLConfiguration now supports the xml:space attribute. This attribute can be used to preserve whitespace in the content of XML elements. INIConfiguration now preserves whitespace in quoted values. If a change has been detected by FileChangedReloadingStrategy, the reloadingRequired() method will now return true until reloadingPerformed() has been called. Fixed a NullPointerException that could be thrown under certain circumstances when saving an XMLConfiguration that was created using the constructor that takes a HierarchicalConfiguration. Instantiating an XMLPropertyListConfiguration no longer fails if the DTD is missing from the classpath. It's now possible to read a configuration file containing a '#' in its name (requires Java 1.4 or above). Fixed the date format for XMLPropertyListConfiguration. Some of the dependencies in the m2 pom have been updated to be more consistent. The dependency to commons-logging was updated to the current version 1.1. Older versions of commons-logging will still work. A new method interpolatedConfiguration() was added to AbstractConfiguration. This method returns a configuration with the same type and content as the original configuration, however all variables have been resolved. Resolving of variables with the prefix const (constant fields) caused a ClassCastException under certain circumstances if non-String fields were involved. This has been fixed. The dependencies to commons-codec and commons-jxpath have been marked as optional. They are not required by the core classes. There is a new configuration implementation EnvironmentConfiguration, which provides access to (OS) environment variables. On Java >= 1.5 this class can be directly used; on earlier versions a dependency to ant is required. A bug in XMLConfiguration caused that attributes of the root element could not be changed. This has been fixed. A new method registerEntityId() was added to XMLConfiguration, which allows to register URLs for entities. A new default implementation of the EntityResolver interface handles these entities automatically. The subset() method of HierarchicalConfiguration now takes the value of the subset's root node into account if it is not ambigous. Nodes added to a XMLConfiguration using the addNodes() method could lose their value when the configuration was saved. This is now fixed. New copy() and append() methods have been added to AbstractConfiguration. They replace the methods with the same names in ConfigurationUtils, which do not handle all features of AbstractConfiguration properly (e.g. list delimiters in property values are incorrectly treated). To avoid such problems, the new methods should be used. The addNodes() method of hierarchical file-based configurations now correctly triggers an auto save. HierarchicalConfiguration.addNodes() now resets the reference property of all nodes to be added. This fixes a problem with XMLConfiguration, which now detects the added nodes as new and treats them correctly when the configuration is saved. DefaultConfigurationBuilder will now notify registered error listeners about optional configuration sources that could not be created. Before exceptions thrown by optional configurations were swallowed ConfigurationUtils.convertToHierarchical() now correctly deals with property values containing escaped list delimiters. This also affects CombinedConfiguration when sub configurations with such property values are contained. AbstractConfiguration.addProperty() now correctly deals with list and array properties if delimiter parsing is disabled. The default expression engine used by HierarchicalConfiguration instances is now lazily initialized. This avoids NullPointerExceptions in certain server environments after a redeploy. Cycles in the JNDI tree no longer cause a stack overflow in JNDIConfiguration. The base implementation of clear() in AbstractConfiguration now checks for a potential UnsupportedOperationException when iterating over the existing properties. Using file-based configurations in auto-save mode together with a reloading strategy could cause data loss. This has been fixed. A PropertiesConfiguration that was created from a non existing file lost its content when it was saved. This problem has been solved. A new getSource() method was added to CompositeConfiguration and CombinedConfiguration, which returns the child configuration, in which a given property is defined. PropertiesConfiguration now supports escaping the escape character for list delimiters. PropertiesConfiguration no longer escapes the list delimiter on saving if the list delimiter has been disabled. List properties and properties containing interpolated variables are now properly saved by INIConfiguration. When delimiter parsing was disabled for XMLConfiguration, saving and loading the configuration accidently added escape characters to properties containing the list delimiter character. This has been fixed. It is now also possible to escape the escape character itself. The return value of FileConfiguration.getFile() is now always consistent with the result of getURL(). INIConfiguration uses the platform's specific line separator instead of the Windows line separator. INIConfiguration flushes the output at the end of a save operation. For hierarchical file-based configurations the auto-save mechanism is now also triggered if a subnode configuration is changed. In such a case the new event type EVENT_SUBNODE_CHANGED will be sent to registered listeners. ConfigurationInterpolator now also invokes the default lookup object for variables with a prefix that could not be resolved by their associated lookup object. A SubnodeConfiguration per default does not see certain changes of its parent configuration (e.g. reloads). With a new boolean parameter of HierarchicalConfiguration's configurationAt() method a mode can be enabled, in which the subnode configuration checks for such changes and reconstructs itself if necessary. byte[] properties are properly saved as data fields in the plist configurations (PropertyListConfiguration and XMLPropertyListConfiguration). DataConfiguration now supports java.net.InetAddress, javax.mail.internet.InternetAddress, and Java 5 enumeration types. Properties are converted to these types using the new generic getters. The object getters in DataConfiguration with no default value (i.e getURL(key)) now throw a NoSuchElementException if the flag throwExceptionOnMissing is set. Generic get methods have been added to DataConfiguration (get(), getArray() and getList()) XMLConfiguration used to drop attributes when an element's value was a list. This has been fixed. File configurations can now be saved to FTP URLs, or any other URL protocol supporting data output. Fixed a potential issue in DatabaseConfiguration where an error on closing a statement would prevent the connection from being closed. Date objects are now supported in ASCII plist files. XMLPropertyListConfiguration no longer requires commons-digester and commons-beanutils to work. Fixed INIConfiguration to handle the quoted values and the lines containing a value and a comment. MapConfiguration and the web-based configurations now treat strings that contain an escaped list delimiter correctly: The escape character will be removed, so that for instance "foo\,bar" becomes "foo,bar". DatabaseConfiguration now handles list delimiters in property values correctly. After cloning a XMLConfiguration there was still a connection to the original configuration. So when the clone was modified and then saved the content of the original configuration was written. This has now been fixed. Class loading in BeanHelper is now done using ClassUtils of Commons Lang. With ManagedReloadingStrategy a new reloading strategy for file-based configurations was added that can be triggered through JMX. The dependencies to Commons Lang, Commons Collections, and Commons Digester are updated to use the recent available version. However older versions will still work. A pom for maven 2 was added. ConfigurationUtils.getFile() now always checks first whether the passed in file name is absolute. If it is, this file will be returned. This prevents that on Unix under certain circumstances absolute file names are interpreted as relative ones. The dependency to xml-apis was changed to the version 1.0.b2. The so far used version 2.0.2 is reported to be bogus. In addition to configuration event listeners now so-called configuration error listeners are supported. These listeners are notified about internal errors that had been logged and swallowed by privious versions. The new enableRuntimeExceptions() method of ConfigurationUtils registers a special error listener at the passed in configuration that generates a runtime exception when an error event is received. AbstractConfiguration now allows to set an instance specific logger using the setLogger() method. This gives clients more control over a configuration's logging behavior. SubsetConfiguration and CompositeConfiguration were updated to fully support an instance specific list delimiter. Concerning splitting of string properties that contain a list delimiter character, these classes now behave like a "normal" configuration. Variable interpolation features have been improved. A variable can now have the form ${prefix:variableName} where the prefix defines the type of the variable. The standard types sys for system properties and const for constants are supported. Variables without a prefix are treated as references to other configuration properties (which is compatible to earlier versions). Commons Configuration now depends on Commons Lang 2.2. Some features of Lang's new text package are used. The number of dependencies needed for DefaultConfigurationBuilder was reduced by letting some of the default configuration providers resolve their classes per reflection. File-based configurations with a reloading strategy did not work well together with CombinedConfiguration because the reloading strategy is only checked when its associated configuration is accessed (which does not happen when only the combined configuration is queried). As a workaround CombinedConfiguration now provides the boolean forceReloadCheck property. If this is set to true, all contained configurations will be triggered when a property is queried. This will cause a reload if necessary. Configuration declarations in the configuration definition file for DefaultConfigurationBuilder that are marked as optional now support a new attribute config-forceCreate. If this attribute is set to true and the initialization of the configuration fails, DefaultConfigurationBuilder tries to add an empty configuration of the correct type to the resulting combined configuration. Before this change optional configurations that caused errors were never added to the combined configuration. CompositeConfiguration.clearProperty() now generates the correct update events. The configuration returned by HierarchicalConfiguration.subset() performed variable interpolation only in the keys that belong to the subset. Now the parent configuration is searched, too, to resolve the value of the referenced property. This is consistent with the way SubnodeConfiguration works. DefaultConfigurationBuilder now internally uses the standard expression engine for hierarchical configurations. So the dependency to Commons JXPath is no more needed when this class is used. Note that this change has some impact on existing code that manually sets properties before the combined configuration is created; this code must now be adapted to the changed syntax of property keys. HierarchicalConfiguration and some of its sub classes now define a copy constructor. A new configuration class for windows ini files was added. For file-based configurations loaded by ConfigurationFactory the load() method was called before all of the properties specified by attributes of the XML element have been initialized. Now load() is called after property initialization. Interpolation of non string values did not work when SubsetConfiguration was involved. This has now been fixed. The compatibility of ConfigurationDynaBean with other configuration types than those that inherit from BaseConfiguration was improved. The getList() method of CompositeConfiguration does now fully support variable interpolation. So it is possible to refer to a variable in one (sub) configuration that is defined in another configuration. XPathExpressionEngine used to create wrong keys for attribute nodes. This caused some operations on XMLConfiguration to fail when such an expression engine was set (e.g. reloading). Now correct keys for attributes are constructed. Some of the methods of file-based hierarchical configurations (e.g. subset() or configurationAt()) did not take an eventually set reloading strategy into account. This is now fixed by overriding the internal fetchNodeList() method in AbstractHierarchicalFileConfiguration and letting it always check for a reload. AbstractFileConfiguration now overrides addProperty() and setProperty() instead of addPropertyDirect() to implement the auto save feature. This was necessary to properly integrate PropertiesConfigurationLayout. It has also the advantage that an auto save is triggered only once if multi-valued properties are involved (before a save operation was performed for each property value). The new PropertiesConfigurationLayout class broke the save() operation of PropertiesConfiguration when an instance was newly created and populated in memory. This is fixed now by ensuring that a layout object is immediately created and registered as event listener at the configuration. ConfigurationFactory now supports variables in its configuration definition files. These variables are resolved using system properties and have the typical ${} syntax. There were still some problems with resolving relative paths when configuration files are loaded from classpath. This fix addresses these issues. DataConfiguration.getDateArray() used to ignore the format argument. This was fixed. PropertiesConfiguration now defines its own clone() method to handle the associated PropertiesConfigurationLayout object correctly. The dependency to servletapi was updated from version 2.3 to version 2.4, but version 2.3 will still work. A new class PropertiesConfigurationLayout was introduced whose task is to preserve the structure (e.g. comments, blanc lines) of a file loaded by PropertiesConfiguration. Each PropertiesConfiguration object is now associated with such a layout object. A saved properties file will look very similar to its original. clone() methods have been added to BaseConfiguration, AbstractFileConfiguration, MapConfiguration, CompositeConfiguration, and CombinedConfiguration. So the most important Configuration implementations now support cloning. To ConfigurationUtils an utility method cloneConfiguration() was added that allows to conveniently clone a configuration. If a configuration file was to be loaded from classpath, the constructor of AbstractFileConfiguration dropped the file's path. The path is now taken into account. The getter methods for numeric data types in AbstractConfiguration now support conversions between different Number types, e.g. you can now call getLong(key) when key points to an Integer value. The new class DefaultConfigurationBuilder was added as an alternative to ConfigurationFactory. It provides some more features and creates a CombinedConfiguration object The new class CombinedConfiguration was added as a hierarchical alternative to CompositeConfiguration. Support for low-level configuration events was added to all classes derived from AbstractConfiguration. The major part of this is handled by the new super class EventSource of AbstractConfiguration. A new method convertToHierarchical() was added to ConfigurationUtils, which is able to convert an arbitrary configuration object into a hierarchical configuration. Loading of file-based configurations no longer throws a NullPointerException in setups where the thread context class loader is not set. The dependency to dom4j was removed; it was only used by two test classes, which have been re-written. XMLConfiguration used to drop the DOCTYPE declaration when saving the configuration. It is now able to extract the DTD's public and system ID and write them back (more complex DOCTYPE declarations are still not supported). With the new methods setSystemID() and setPublicID(), the DOCTYPE declaration can be configured. Added two new constructors in CompositeConfiguration accepting a collection of configurations as a parameter. (Basic) Support for declaring beans in configuration files was added. Some new classes in the beanutils package allow to create instances from these declarations. The implementation of the interpolation features have been extracted out off AbstractConfiguration and moved to PropertyConverter. The interpolateHelper() method of AbstractConfiguration is now deprectated and will not be called any more during interpolation. A new method configurationsAt() was added to HierarchicalConfiguration that provides a convenient way of iterating over complex list-like structures without the need of manually constructing configuration keys with indices. A new class SubnodeConfiguration was introduced that wraps a configuration node of a HierarchicalConfiguration. All operations performed on this configuration use this wrapped node as root. The new configurationAt() method of HierarchicalConfiguration returns such a SubnodeConfiguration for a specified sub node. With XPathExpressionEngine an expression engine for hierarchical configurations is now available that can evaluate XPATH expressions in property keys. This expression engine implementation is based on Commons JXPath, which is now declared as a new dependency (but at runtime it is only needed if the XPathExpressionEngine class is used). The code for interpreting property keys was refactored out off HierarchicalConfiguration. Instead this class now supports pluggable expression engines (using the setExpressionEngine() method). So it is possible to plug in different expression languages. A default expression engine is provided that understands the native expression language used by hierarchical configurations in older versions. During the process of this refactoring some methods of HierarchicalConfiguration have been deprecated; they will not be called any more when searching or adding properties. These are the following: createAddPath(), fetchAddNode(), findLastPathNode(), findPropertyNodes(). A larger refactoring was performed on the inner Node class of HierarchicalConfiguration: A ConfigurationNode interface was extracted for which a default implementation (DefaultConfigurationNode) is provided. HierarchicalConfiguration.Node now extends this default implementation. The new ConfigurationNode interface defines some more methods than the Node class did originally for conveniently dealing with sub nodes and attributes. HierarchicalConfiguration now uses the new type ConfigurationNode whereever possible. Some methods dealing with Node objects have been deprecated and replaced by versions operating on ConfigurationNode objects instead. All configuration classes derived from AbstractConfiguration now allow to set an instance specific list delimiter. This can be done through the new method setListDelimiter(). As before it is possible to define a default list delimiter, which will be used if no instance specific delimiter is set. This can be done using the new setDefaultListDelimiter() method (the methods get/setDelimiter() have been deprecated). With the new setDelimiterParsingDisabled() method parsing of lists can be disabled at all. Commons Configuration now declares a dependency to Xalan. As with Xerces this dependency is only needed for JDK 1.3. It was introduced in a process of making Configuration buildable on a JDK 1.3. Documentation about the build process was also added. The dependency to Commons Beanutils Collections was unnecessary and thus removed. Commons Configuration now depends on Commons Digester 1.6 instead of 1.5. (This was done only to pick up the latest available release of digester.) ConfigurationDynaBean now implements the java.util.Map interface (as was stated in the javadocs). This was done by deriving the class from ConfigurationMap. The reload() method in AbstractFileConfiguration was updated to prevent reentrant invocation, which may be caused by some methods when they are called during a reloading operation. AbstractHierarchicalFileConfiguration, a new base class for file based hierarchical configurations, was introduced. XMLConfiguration now extends this class. XMLConfiguration now prints the used encoding in the xml declaration of generated files. In earlier versions always the default encoding was written. PropertiesConfiguration now always uses the platform specific line separator when saving files. PropertiesConfiguration now translates properly the escaped unicode characters (like \u1234) used in the property keys. This complies with the specification of java.util.Properties. ConfigurationConverter.getProperties() now uses the delimiter of the specified configuration to convert the list properties into strings. The interpolation of variables (${foo}) is now performed in all property getters of AbstractConfiguration and DataConfiguration. As a side effect the Properties object returned by ConfigurationConverter.getProperties() contains only interpolated values. PropertiesConfiguration now uses the ISO-8859-1 encoding by default instead of the system encoding to comply with the specification of java.util.Properties. JNDIConfiguration no longer logs an error when attempting to get a property that doesn't exist in the configuration. Attempting to load a configuration from a directory instead of a file will now throw a ConfigurationException. If a multi-valued property was involved in an interpolation operation, AbstractConfiguration created a string representation of the list of all values. This was changed to only use the first value, which makes more sense in this context and is consistent with other getters for single valued properties. If an include file with a relative path cannot be found in the base path, PropertiesConfiguration now also tries to resolve it based on its own location. Fixed MapConfiguration to store the list of values added under a same key instead of the last value added. Fixed a bug in the handling of relative file names in ConfigurationFactory: In most cases relative file names were not resolved relative to the location of the configuration definition file as stated in the documentation. This behavior was now changed to always be in sync with the documentation. This may have an impact on existing code which uses workarounds for the erroneous resolving mechanism. Empty elements or elements whose content consists only of comments or whitespace are now taken into account by XMLConfiguration. They are added to the configuration; their value is an empty string. XMLConfiguration now sets a valid system id in the InputSource used for loading files. This enables XML parsers to correctly resolve relative files, e.g. DTDs. getKeys() in HierarchicalConfiguration now returns the keys in the same order the properties were inserted. Commons Configuration now depends on Commons Collections 3.1 instead of 3.0 New configurations implementing the "property list" format used in NeXT/OpenStep and its XML variant used in Mac OS X. (PropertyListConfiguration and XMLPropertyListConfiguration) Resolved some issues with XMLConfiguration and properties containing the delimiter character. These properties are now correctly treated, escaping the delimiter will work, too. Added support for XMLPropertiesConfiguration in ConfigurationFactory. A <properties> element will generate a XMLPropertiesConfiguration if the filename ends with ".xml". PropertiesConfiguration now supports escaped key/value separators in the keys (i.e foo\:key = bar). PropertiesConfiguration now supports all key/value separators supported by java.util.Properties ('=', ':' and white space characters). Commons Configuration now depends on Commons Lang 2.1 instead of 2.0 Comment lines for PropertiesConfiguration can start with the '!' char (compatibility with java.util.Properties). Because ConfigurationUtils.copy() does not fully support hierarchical configurations a clone() method was added to HierarchicalConfiguration that can be used instead. XMLConfiguration now provides some support for validating XML documents. With the setValidating() method DTD validation can be enabled. It is also possible to set a custom DocumentBuilder allowing a caller to perform enhanced configuration of the XML loading process. AbstractFileConfiguration now always sets a valid base path if the configuration file could be located. This allows PropertiesConfiguration to resolve include files even when loaded from class path. Updated XMLConfiguration to correctly deal with properties containing dots in their names. Such properties could not be accessed before. PropertiesConfiguration's handling of backslash characters at the end of line was incorrect when there was an even number of trailing backslashes. This is now fixed. Fixed a problem related to file based configurations that are loaded from a URL which is application/x-www-form-urlencoded: the save() method would store such files at a wrong location. Updated FileChangedReloadingStrategy to use the file based configuration's source URL to find the file to watch. Before that it was possible that the strategy checked the wrong file. For configuration files loaded from a jar FileChangedReloadingStrategy now checks the jar file itself for changes. Finally a bug was fixed which caused the strategy to check the watched file's last change date on every invocation of its reloadingRequired() method ignoring its refresh delay. Thanks to Jorge Ferrer. Fixed a bug in the collaboration between XMLConfiguration and its reloading strategy: The configuration did not check its reloading strategy, so no reload was performed. Disabled auto save mode during PropertiesConfiguration.load(). Prior it was possible that the properties file to be loaded was immideately overwritten. Under certain circumstances it was possible that a reloading strategy set for PropertiesConfiguration interferred with the save() method causing the configuration file to be erased. This has now been fixed. AbstractFileConfiguration now stores the URL of the config file in the load() methods. This URL is reused by the save() method to ensure that the same file is written. XMLPropertiesConfiguration no longer depends on Digester to parse the configuration file, it's now implemented with a pure SAX parser. Fixed a bug which causes XMLConfiguration.save to lose attribute values under some circumstances. The clear() method now also ensures that the associated DOM document is always cleared. XMLConfiguration now parse the configuration using the encoding declared in the XML header instead of the OS default encoding. XMLConfiguration now uses the delimiter set by setDelimiter(char). Fixed a ConcurrentModificationException thrown when calling clear() on a SubsetConfiguration applied to a BaseConfiguration. The resolveContainerStore() method in AbstractConfiguration now works properly with arrays of objects and arrays of primitives. This means it is possible to store an array of value in the configuration and retrieve the first element with the getString(), getInt()... methods. Updated documentation for FileConfiguration's load() methods. Fixed a problem in XMLConfiguration with the output of the save() method when multiple files were loaded. Fixed a bug in FileChangedReloadingStrategy preventing the detection of a file change in some cases. Changed getXXXArray() and getXXXList() in DataConfiguration to return an empty array/list for empty values. Fixed getLongArray(), getFloatArray() and getDoubleArray() in DataConfiguration, the values were cast into integers. ConfigurationFactory now always configures digester to use the context classloader. This avoids problems in application server environments, which use their own version of digester. Thanks to Mike Colbert for the patch! Added a new configuration, XMLPropertiesConfiguration, supporting the new XML format for java.util.Properties introduced in Java 1.5. A 1.5 runtime is not required to use this class. Added a comment header to PropertiesConfiguration. The header is not parsed when the file is loaded yet. Added the setEncoding(String) and the getEncoding() methods to the FileConfiguration interface to control the encoding of the configuration file. Access to the top level element of the XML document is now provided. For newly created configurations this element can be changed before the document is written. Merged the two XML related configuration classes into one new class XMLConfiguration. This new class should provide the best of its ancestors. Replaced the PropertyTokenizer inner class in AbstractConfiguration with the split method in PropertyConverter. Also moved the method building an iterator on the elements of a composite value in PropertyConverter as toIterator(). Some cleanup of the handling of the base path in file based configurations. The base path is now always taken into account. Calling getProperties on a JNDIConfiguration no longer throws an UnsupportedOperationException. Removed the getPropertyDirect method from AbstractConfiguration, concrete configurations now implement directly the getProperty method from the Configuration interface. Added implementation of a save() method for HierarchicalXMLConfiguration. Constructing a file based configuration with a File no longer throws an exception when the file doesn't exist. Saving a configuration now creates the path to the file if it doesn't exist. AbstractFileConfiguration.save(File) no longer fails silently when an error occurs, a ConfigurationException is thrown instead. ConfigurationUtils.locate() now checks if the URL based resources exist. This fixes a bug preventing configuration files from being found if the configuration descriptor is in a JAR file (reported by Grant Ingersoll). Fixed NPE that were caused in the constructors of file based configurations if an invalid file name was specified. Added support for optional configuration sources in definition files for ConfigurationFactory. A new optional attribute allows to specify whether a configuration source is mandatory or optional. JNDIConfiguration.getKeys() now returns an empty iterator instead of throwing a ConfigurationRuntimeException when a NamingException occurs. The NamingExceptions are now logged. DatabaseConfiguration.isEmpty() now returns true if an SQLException occurs. Added two methods copy(Configuration, Configuration) and append(Configuration, Configuration) in ConfigurationUtils to copy properties between configurations. Moved the constructors implementations from PropertiesConfiguration and XMLConfiguration to AbstractFileConfiguration. Remove deprecated getVector() implementations. File based configurations can now be automatically reloaded when the underlying file is modified. Added a clear() method to the Configuration interface to remove all properties. Added a SystemConfiguration wrapping the system properties. ConfigurationFactory recognizes the corresponding <system/> element. Added a MapConfiguration to turn any Map into a Configuration. The getConfiguration() methods in ConfigurationConverter now use MapConfiguration, as a result the Configuration returned is always synchronized with the underlying Properties or ExtendedProperties, changes made to the Configuration are available in the Properties, and reciprocally. The "autoSave" feature of XMLConfiguration has been generalized to all file based configurations. Numeric properties can now be specified in hexadecimal format, for example "number = 0xC5F0". Fixed HierarchicalConfiguration.getKeys(String), it returned an empty iterator if the prefix string contained indices. Added a DataConfiguration decorator providing getters for all useful types found in a configuration (URL, Locale, Date, Calendar, Color, lists and arrays) Added 5 new configurations to be used in a web environment: AppletConfiguration, ServletConfiguration, ServletContextConfiguration, ServletRequestConfiguration, ServletFilterConfiguration. The getStringArray() method in CompositeConfiguration now interpolates the strings. SubsetConfiguration now shares the "throwExceptionOnMissing" property with its parent. Removed "file:" at the beginning of the base path when calling setFile() on a FileConfiguration. This prevented auto saving an XMLConfiguration loaded from a File (issue reported by Mark Roth). All NamingEnumerations in JNDIConfiguraiton are now properly closed (Suggested by Eric Jung). Properties added to an XMLConfiguration are no longer duplicated in the resulting XML file. Unified the mechanisms for loading and saving file based configurations. PropertiesConfiguration, XMLConfiguration and HierarchicalXMLConfiguration now implement the same FileConfiguration interface. BasePathLoader, BasePathConfiguration, ClassPropertiesConfiguration and BasePropertiesConfiguration have been removed. Replaced the calls to Boolean.booleanValue(boolean) in AbstractConfiguration and ConfigurationDynaBean to be Java 1.3 compatible. Changing the prefix of a JNDIConfiguration will now reset the base context used. The context used by JNDIConfiguration can be specified in its constructor or through the setContext() method. The context can be accessed with the getContext() method which is now public. Make the behaviour on missing properties for the get methods that return objects configurable. A property throwExceptionOnMissing can be set and then the getters throw an NoSuchElementException. The old default behaviour of returning a null value has been restored. Allow configurations extending AbstractConfiguration to change the delimiter used from "," to something else. PropertiesConfiguration.save() method has issues with preserving the filename Test cases for HierarchicalConfigurationXMLReader stores comments as text nodes. Clarify for ConfigurationDynaBean that the get method should throw an illegalArgumentException if there is no property specified. Fixed a ClassCastException when adding a non String property to an XMLConfiguration. Fixed the handling of attribute properties by HierarchicalConfigurationConverter. Fixed a ClassCastException thrown on adding a non string property in a DatabaseConfiguration. Bring back the getVector() methods in the Configuration interface. These methods are needed for "drop-on" replacement of the various pre-1.0 commons-configuration snapshots and are already deprecated. These methods will be removed for 1.1. HierarchicalConfigurationXMLReader stores comments as text nodes. project.xml contains bad dependencies. clearXmlProperty doesn't remove list properties completely. new ConfigurationDynaBean. new ConfigurationMap and ConfigurationSet. Problem adding property XMLConfiguration. ConfigurationXMLDocument removed until post 1.0. DatabaseConfiguration doesn't support List properties. Fixed a bug related to XMLConfiguration. Can't add a new property as an attribute in XMLConfiguration. Fixed a bug related to XMLConfiguration. XMLConfiguration doesn't support attribute names with a dot. Fixed a bug related to XMLConfiguration. XMLConfiguration doesn't ignore comments. Fixed a bug related to XMLConfiguration. XMLConfiguration.save() doesn't escape reserved characters. Added save methods in XMLConfiguration similar to PropertiesConfiguration to save the configuration to another file. Removed the DOM4J implementations in favor of the DOM ones. DOMConfiguration has been renamed to XMLConfiguration, and HierarchicalDOMConfiguration to HierarchicalXMLConfiguration. The elements parsed by the ConfigurationFactory have been changed accordingly. Added a save() method to PropertiesConfiguration and save(Writer out), save(OutputStream out), save(OutputStream out, String encoding) to BasePropertiesConfiguration. List values are now properly stored as comma separated values in the Properties object returned by ConfigurationConverter.getProperties() Introduced a ConversionException thrown when the value of a property is not compatible the type requested. It replaces the ClassCastException and the NumberFormatException thrown previously. Tokens like ${ref} in a PropertyConfiguration are now properly saved. The getList() method of a CompositeConfiguration now returns the list composed of the elements in the first matching configuration and the additional elements found in the in memory configuration. SubsetConfiguration returns a List on getList(). AbstractConfiguration wouldn't properly deal with a List, only with a Container for getList()! Thanks to jschaible for the unit test. Direct support of XML via DOM. New classes DOMConfiguration and HierarchicalDOMConfiguration. Update build to not include test configuration files in resulting jar. Refactored JNDIConfiguration to use AbstractConfiguration. Fixed invalid subsets by refactoring out the subset logic into a SubsetConfiguration. Reapply the ConfigurationXMLDocument that went missing during migration out of sandbox. Apply ASL 2.0 license. Thanks to Jeff Painter for scripting the conversion! Changed CompositeConfiguration to extend from AbstractConfiuration. This means that the behavior of CompositeConfiguration is much similar to others like PropertiesConfiguration in handling of missing keys, interpolation, etc.. Previously CompositeConfiguration had quite a few differences. Removed "defaults" from BaseConfiguration. Defaults are now done via using a CompositeConfiguration, either directly or via a ConfigurationFactory. if you want to save changes made to a Configuration, then you use a CompositeConfiguration and get back the inMemoryConfiguration that has the delta of changes. Added a bit of documentation on this. Enhancement: Configuration Comparator. BaseConfiguration: containsKey ignores default properties. I have changed it so that now the defaults are paid attention to. The Configuration interface now supports BigDecimal and BigInteger numbers. ConfigurationException is now thrown by public methods instead of Exception or IOException or whatnot. For configuration based on properties files, allow characters like \n etc to be escaped and unescaped. New DatabaseConfiguration that uses a database to store the properties. It supports 2 table structures: one table per configuration (2 colums key/value), one table for multiple configurations (2 columns key/value + 1 column for the name of the configuration). ConfigurationFactory now supports the hierarchicalDom4j element in configuration definition file Change all Vector objects to List objects. ConfigurationFactory now supports two types of properties files, additional and override. Additional properties add each other together. Override override each other. This allows you to have a single property that is either aggregated from a number of sources, or have a property that is overridden according to a specific order of sources. AbstractConfiguration addProperty now delegates to an abstract addPropertyDirect implemented by BaseConfiguration. Changed getString() method to throw a NoSuchElementException instead of "" if the configuration property doesn't exist. Added AbstractConfiguration to make it easier to create subclasses by only having to implement the methods required. ClassPropertiesConfiguration Additions: Use the classloader of class that is provided by the constructor. Add a constructor that indicates whether to use relative or absolute. Change getPropertyStream to utilize the relative or absolute flag. Add a test case that checks that absolute paths work. JNDIConfiguration.getKeys() Addition: The JNDIConfiguration.getKeys() method was returning an unsupported operation error. However, this is an important method to have supported. CompositeConfiguration.getKeys() Fix The CompositeConfiguration.getKeys() method was returning an unordered list of configuration values. However, many apps expect the order that keys are returned to be the order they are added into the properties file. commons-configuration-1.10-src/src/main/assembly/bin.xml100644 2744 12232154102 23045 0ustarhenningstaff 0 0 bin tar.gz zip ${artifactId}-${commons.release.version} LICENSE* NOTICE* RELEASE-NOTES* pom.xml target *.jar target/site/apidocs apidocs commons-configuration-1.10-src/src/main/assembly/src.xml100644 2467 12232154102 23066 0ustarhenningstaff 0 0 src tar.gz zip ${artifactId}-${commons.release.version}-src LICENSE* NOTICE* RELEASE-NOTES* pom.xml conf src ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractConfiguration.100644 117775 12232154102 33556 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Properties; import org.apache.commons.configuration.event.ConfigurationErrorEvent; import org.apache.commons.configuration.event.ConfigurationErrorListener; import org.apache.commons.configuration.event.EventSource; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.ObjectUtils; import org.apache.commons.lang.text.StrLookup; import org.apache.commons.lang.text.StrSubstitutor; import org.apache.commons.logging.Log; import org.apache.commons.logging.impl.NoOpLog; /** *

Abstract configuration class. Provides basic functionality but does not * store any data.

*

If you want to write your own Configuration class then you should * implement only abstract methods from this class. A lot of functionality * needed by typical implementations of the {@code Configuration} * interface is already provided by this base class. Following is a list of * features implemented here: *

  • Data conversion support. The various data types required by the * {@code Configuration} interface are already handled by this base class. * A concrete sub class only needs to provide a generic {@code getProperty()} * method.
  • *
  • Support for variable interpolation. Property values containing special * variable tokens (like ${var}) will be replaced by their * corresponding values.
  • *
  • Support for string lists. The values of properties to be added to this * configuration are checked whether they contain a list delimiter character. If * this is the case and if list splitting is enabled, the string is split and * multiple values are added for this property. (With the * {@code setListDelimiter()} method the delimiter character can be * specified; per default a comma is used. The * {@code setDelimiterParsingDisabled()} method can be used to disable * list splitting completely.)
  • *
  • Allows to specify how missing properties are treated. Per default the * get methods returning an object will return null if the searched * property key is not found (and no default value is provided). With the * {@code setThrowExceptionOnMissing()} method this behavior can be * changed to throw an exception when a requested property cannot be found.
  • *
  • Basic event support. Whenever this configuration is modified registered * event listeners are notified. Refer to the various {@code EVENT_XXX} * constants to get an impression about which event types are supported.
  • *

* * @author Konstantin Shaposhnikov * @author Henning P. Schmiedehausen * @version $Id: AbstractConfiguration.java 1534064 2013-10-21 08:44:33Z henning $ */ public abstract class AbstractConfiguration extends EventSource implements Configuration { /** * Constant for the add property event type. * @since 1.3 */ public static final int EVENT_ADD_PROPERTY = 1; /** * Constant for the clear property event type. * @since 1.3 */ public static final int EVENT_CLEAR_PROPERTY = 2; /** * Constant for the set property event type. * @since 1.3 */ public static final int EVENT_SET_PROPERTY = 3; /** * Constant for the clear configuration event type. * @since 1.3 */ public static final int EVENT_CLEAR = 4; /** * Constant for the get property event type. This event type is used for * error events. * @since 1.4 */ public static final int EVENT_READ_PROPERTY = 5; /** start token */ protected static final String START_TOKEN = "${"; /** end token */ protected static final String END_TOKEN = "}"; /** * Constant for the disabled list delimiter. This character is passed to the * list parsing methods if delimiter parsing is disabled. So this character * should not occur in string property values. */ private static final char DISABLED_DELIMITER = '\0'; /** The default value for listDelimiter */ private static char defaultListDelimiter = ','; /** Delimiter used to convert single values to lists */ private char listDelimiter = defaultListDelimiter; /** * When set to true the given configuration delimiter will not be used * while parsing for this configuration. */ private boolean delimiterParsingDisabled; /** * Whether the configuration should throw NoSuchElementExceptions or simply * return null when a property does not exist. Defaults to return null. */ private boolean throwExceptionOnMissing; /** Stores a reference to the object that handles variable interpolation.*/ private StrSubstitutor substitutor; /** Stores the logger.*/ private Log log; /** * Creates a new instance of {@code AbstractConfiguration}. */ public AbstractConfiguration() { setLogger(null); } /** * For configurations extending AbstractConfiguration, allow them to change * the listDelimiter from the default comma (","). This value will be used * only when creating new configurations. Those already created will not be * affected by this change * * @param delimiter The new listDelimiter */ public static void setDefaultListDelimiter(char delimiter) { AbstractConfiguration.defaultListDelimiter = delimiter; } /** * Sets the default list delimiter. * * @param delimiter the delimiter character * @deprecated Use AbstractConfiguration.setDefaultListDelimiter(char) * instead */ @Deprecated public static void setDelimiter(char delimiter) { setDefaultListDelimiter(delimiter); } /** * Retrieve the current delimiter. By default this is a comma (","). * * @return The delimiter in use */ public static char getDefaultListDelimiter() { return AbstractConfiguration.defaultListDelimiter; } /** * Returns the default list delimiter. * * @return the default list delimiter * @deprecated Use AbstractConfiguration.getDefaultListDelimiter() instead */ @Deprecated public static char getDelimiter() { return getDefaultListDelimiter(); } /** * Change the list delimiter for this configuration. * * Note: this change will only be effective for new parsings. If you * want it to take effect for all loaded properties use the no arg constructor * and call this method before setting the source. * * @param listDelimiter The new listDelimiter */ public void setListDelimiter(char listDelimiter) { this.listDelimiter = listDelimiter; } /** * Retrieve the delimiter for this configuration. The default * is the value of defaultListDelimiter. * * @return The listDelimiter in use */ public char getListDelimiter() { return listDelimiter; } /** * Determine if this configuration is using delimiters when parsing * property values to convert them to lists of values. Defaults to false * @return true if delimiters are not being used */ public boolean isDelimiterParsingDisabled() { return delimiterParsingDisabled; } /** * Set whether this configuration should use delimiters when parsing * property values to convert them to lists of values. By default delimiter * parsing is enabled * * Note: this change will only be effective for new parsings. If you * want it to take effect for all loaded properties use the no arg constructor * and call this method before setting source. * @param delimiterParsingDisabled a flag whether delimiter parsing should * be disabled */ public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled) { this.delimiterParsingDisabled = delimiterParsingDisabled; } /** * Allows to set the {@code throwExceptionOnMissing} flag. This * flag controls the behavior of property getter methods that return * objects if the requested property is missing. If the flag is set to * false (which is the default value), these methods will return * null. If set to true, they will throw a * {@code NoSuchElementException} exception. Note that getter methods * for primitive data types are not affected by this flag. * * @param throwExceptionOnMissing The new value for the property */ public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing) { this.throwExceptionOnMissing = throwExceptionOnMissing; } /** * Returns true if missing values throw Exceptions. * * @return true if missing values throw Exceptions */ public boolean isThrowExceptionOnMissing() { return throwExceptionOnMissing; } /** * Returns the object that is responsible for variable interpolation. * * @return the object responsible for variable interpolation * @since 1.4 */ public synchronized StrSubstitutor getSubstitutor() { if (substitutor == null) { substitutor = new StrSubstitutor(createInterpolator()); } return substitutor; } /** * Returns the {@code ConfigurationInterpolator} object that manages * the lookup objects for resolving variables. Note: If this * object is manipulated (e.g. new lookup objects added), synchronization * has to be manually ensured. Because * {@code ConfigurationInterpolator} is not thread-safe concurrent * access to properties of this configuration instance (which causes the * interpolator to be invoked) may cause race conditions. * * @return the {@code ConfigurationInterpolator} associated with this * configuration * @since 1.4 */ public ConfigurationInterpolator getInterpolator() { return (ConfigurationInterpolator) getSubstitutor() .getVariableResolver(); } /** * Creates the interpolator object that is responsible for variable * interpolation. This method is invoked on first access of the * interpolation features. It creates a new instance of * {@code ConfigurationInterpolator} and sets the default lookup * object to an implementation that queries this configuration. * * @return the newly created interpolator object * @since 1.4 */ protected ConfigurationInterpolator createInterpolator() { ConfigurationInterpolator interpol = new ConfigurationInterpolator(); interpol.setDefaultLookup(new StrLookup() { @Override public String lookup(String var) { Object prop = resolveContainerStore(var); return (prop != null) ? prop.toString() : null; } }); return interpol; } /** * Returns the logger used by this configuration object. * * @return the logger * @since 1.4 */ public Log getLogger() { return log; } /** * Allows to set the logger to be used by this configuration object. This * method makes it possible for clients to exactly control logging behavior. * Per default a logger is set that will ignore all log messages. Derived * classes that want to enable logging should call this method during their * initialization with the logger to be used. * * @param log the new logger * @since 1.4 */ public void setLogger(Log log) { this.log = (log != null) ? log : new NoOpLog(); } /** * Adds a special * {@link org.apache.commons.configuration.event.ConfigurationErrorListener} * object to this configuration that will log all internal errors. This * method is intended to be used by certain derived classes, for which it is * known that they can fail on property access (e.g. * {@code DatabaseConfiguration}). * * @since 1.4 */ public void addErrorLogListener() { addErrorListener(new ConfigurationErrorListener() { public void configurationError(ConfigurationErrorEvent event) { getLogger().warn("Internal error", event.getCause()); } }); } public void addProperty(String key, Object value) { fireEvent(EVENT_ADD_PROPERTY, key, value, true); addPropertyValues(key, value, isDelimiterParsingDisabled() ? DISABLED_DELIMITER : getListDelimiter()); fireEvent(EVENT_ADD_PROPERTY, key, value, false); } /** * Adds a key/value pair to the Configuration. Override this method to * provide write access to underlying Configuration store. * * @param key key to use for mapping * @param value object to store */ protected abstract void addPropertyDirect(String key, Object value); /** * Adds the specified value for the given property. This method supports * single values and containers (e.g. collections or arrays) as well. In the * latter case, {@code addPropertyDirect()} will be called for each * element. * * @param key the property key * @param value the value object * @param delimiter the list delimiter character */ private void addPropertyValues(String key, Object value, char delimiter) { Iterator it = PropertyConverter.toIterator(value, delimiter); while (it.hasNext()) { addPropertyDirect(key, it.next()); } } /** * interpolate key names to handle ${key} stuff * * @param base string to interpolate * * @return returns the key name with the ${key} substituted */ protected String interpolate(String base) { Object result = interpolate((Object) base); return (result == null) ? null : result.toString(); } /** * Returns the interpolated value. Non String values are returned without change. * * @param value the value to interpolate * * @return returns the value with variables substituted */ protected Object interpolate(Object value) { return PropertyConverter.interpolate(value, this); } /** * Recursive handler for multple levels of interpolation. * * When called the first time, priorVariables should be null. * * @param base string with the ${key} variables * @param priorVariables serves two purposes: to allow checking for loops, * and creating a meaningful exception message should a loop occur. It's * 0'th element will be set to the value of base from the first call. All * subsequent interpolated variables are added afterward. * * @return the string with the interpolation taken care of * @deprecated Interpolation is now handled by * {@link PropertyConverter}; this method will no longer be * called */ @Deprecated protected String interpolateHelper(String base, List priorVariables) { return base; // just a dummy implementation } public Configuration subset(String prefix) { return new SubsetConfiguration(this, prefix, "."); } public void setProperty(String key, Object value) { fireEvent(EVENT_SET_PROPERTY, key, value, true); setDetailEvents(false); try { clearProperty(key); addProperty(key, value); } finally { setDetailEvents(true); } fireEvent(EVENT_SET_PROPERTY, key, value, false); } /** * Removes the specified property from this configuration. This * implementation performs some preparations and then delegates to * {@code clearPropertyDirect()}, which will do the real work. * * @param key the key to be removed */ public void clearProperty(String key) { fireEvent(EVENT_CLEAR_PROPERTY, key, null, true); clearPropertyDirect(key); fireEvent(EVENT_CLEAR_PROPERTY, key, null, false); } /** * Removes the specified property from this configuration. This method is * called by {@code clearProperty()} after it has done some * preparations. It should be overridden in sub classes. This base * implementation is just left empty. * * @param key the key to be removed */ protected void clearPropertyDirect(String key) { // override in sub classes } public void clear() { fireEvent(EVENT_CLEAR, null, null, true); setDetailEvents(false); boolean useIterator = true; try { Iterator it = getKeys(); while (it.hasNext()) { String key = it.next(); if (useIterator) { try { it.remove(); } catch (UnsupportedOperationException usoex) { useIterator = false; } } if (useIterator && containsKey(key)) { useIterator = false; } if (!useIterator) { // workaround for Iterators that do not remove the property // on calling remove() or do not support remove() at all clearProperty(key); } } } finally { setDetailEvents(true); } fireEvent(EVENT_CLEAR, null, null, false); } /** * {@inheritDoc} This implementation returns keys that either match the * prefix or start with the prefix followed by a dot ('.'). So the call * {@code getKeys("db");} will find the keys {@code db}, * {@code db.user}, or {@code db.password}, but not the key * {@code dbdriver}. */ public Iterator getKeys(String prefix) { return new PrefixedKeysIterator(getKeys(), prefix); } public Properties getProperties(String key) { return getProperties(key, null); } /** * Get a list of properties associated with the given configuration key. * * @param key The configuration key. * @param defaults Any default values for the returned * {@code Properties} object. Ignored if {@code null}. * * @return The associated properties if key is found. * * @throws ConversionException is thrown if the key maps to an object that * is not a String/List of Strings. * * @throws IllegalArgumentException if one of the tokens is malformed (does * not contain an equals sign). */ public Properties getProperties(String key, Properties defaults) { /* * Grab an array of the tokens for this key. */ String[] tokens = getStringArray(key); /* * Each token is of the form 'key=value'. */ Properties props = defaults == null ? new Properties() : new Properties(defaults); for (String token : tokens) { int equalSign = token.indexOf('='); if (equalSign > 0) { String pkey = token.substring(0, equalSign).trim(); String pvalue = token.substring(equalSign + 1).trim(); props.put(pkey, pvalue); } else if (tokens.length == 1 && "".equals(token)) { // Semantically equivalent to an empty Properties // object. break; } else { throw new IllegalArgumentException('\'' + token + "' does not contain an equals sign"); } } return props; } /** * {@inheritDoc} * @see PropertyConverter#toBoolean(Object) */ public boolean getBoolean(String key) { Boolean b = getBoolean(key, null); if (b != null) { return b.booleanValue(); } else { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } } /** * {@inheritDoc} * @see PropertyConverter#toBoolean(Object) */ public boolean getBoolean(String key, boolean defaultValue) { return getBoolean(key, BooleanUtils.toBooleanObject(defaultValue)).booleanValue(); } /** * Obtains the value of the specified key and tries to convert it into a * {@code Boolean} object. If the property has no value, the passed * in default value will be used. * * @param key the key of the property * @param defaultValue the default value * @return the value of this key converted to a {@code Boolean} * @throws ConversionException if the value cannot be converted to a * {@code Boolean} * @see PropertyConverter#toBoolean(Object) */ public Boolean getBoolean(String key, Boolean defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toBoolean(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a Boolean object", e); } } } public byte getByte(String key) { Byte b = getByte(key, null); if (b != null) { return b.byteValue(); } else { throw new NoSuchElementException('\'' + key + " doesn't map to an existing object"); } } public byte getByte(String key, byte defaultValue) { return getByte(key, new Byte(defaultValue)).byteValue(); } public Byte getByte(String key, Byte defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toByte(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a Byte object", e); } } } public double getDouble(String key) { Double d = getDouble(key, null); if (d != null) { return d.doubleValue(); } else { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } } public double getDouble(String key, double defaultValue) { return getDouble(key, new Double(defaultValue)).doubleValue(); } public Double getDouble(String key, Double defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toDouble(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a Double object", e); } } } public float getFloat(String key) { Float f = getFloat(key, null); if (f != null) { return f.floatValue(); } else { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } } public float getFloat(String key, float defaultValue) { return getFloat(key, new Float(defaultValue)).floatValue(); } public Float getFloat(String key, Float defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toFloat(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a Float object", e); } } } public int getInt(String key) { Integer i = getInteger(key, null); if (i != null) { return i.intValue(); } else { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } } public int getInt(String key, int defaultValue) { Integer i = getInteger(key, null); if (i == null) { return defaultValue; } return i.intValue(); } public Integer getInteger(String key, Integer defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toInteger(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to an Integer object", e); } } } public long getLong(String key) { Long l = getLong(key, null); if (l != null) { return l.longValue(); } else { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } } public long getLong(String key, long defaultValue) { return getLong(key, new Long(defaultValue)).longValue(); } public Long getLong(String key, Long defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toLong(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a Long object", e); } } } public short getShort(String key) { Short s = getShort(key, null); if (s != null) { return s.shortValue(); } else { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } } public short getShort(String key, short defaultValue) { return getShort(key, new Short(defaultValue)).shortValue(); } public Short getShort(String key, Short defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toShort(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a Short object", e); } } } /** * {@inheritDoc} * @see #setThrowExceptionOnMissing(boolean) */ public BigDecimal getBigDecimal(String key) { BigDecimal number = getBigDecimal(key, null); if (number != null) { return number; } else if (isThrowExceptionOnMissing()) { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } else { return null; } } public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toBigDecimal(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a BigDecimal object", e); } } } /** * {@inheritDoc} * @see #setThrowExceptionOnMissing(boolean) */ public BigInteger getBigInteger(String key) { BigInteger number = getBigInteger(key, null); if (number != null) { return number; } else if (isThrowExceptionOnMissing()) { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } else { return null; } } public BigInteger getBigInteger(String key, BigInteger defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toBigInteger(interpolate(value)); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a BigInteger object", e); } } } /** * {@inheritDoc} * @see #setThrowExceptionOnMissing(boolean) */ public String getString(String key) { String s = getString(key, null); if (s != null) { return s; } else if (isThrowExceptionOnMissing()) { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } else { return null; } } public String getString(String key, String defaultValue) { Object value = resolveContainerStore(key); if (value instanceof String) { return interpolate((String) value); } else if (value == null) { return interpolate(defaultValue); } else { throw new ConversionException('\'' + key + "' doesn't map to a String object"); } } /** * Get an array of strings associated with the given configuration key. * If the key doesn't map to an existing object, an empty array is returned. * If a property is added to a configuration, it is checked whether it * contains multiple values. This is obvious if the added object is a list * or an array. For strings it is checked whether the string contains the * list delimiter character that can be specified using the * {@code setListDelimiter()} method. If this is the case, the string * is split at these positions resulting in a property with multiple * values. * * @param key The configuration key. * @return The associated string array if key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a String/List of Strings. * @see #setListDelimiter(char) * @see #setDelimiterParsingDisabled(boolean) */ public String[] getStringArray(String key) { Object value = getProperty(key); String[] array; if (value instanceof String) { array = new String[1]; array[0] = interpolate((String) value); } else if (value instanceof List) { List list = (List) value; array = new String[list.size()]; for (int i = 0; i < array.length; i++) { array[i] = interpolate(ObjectUtils.toString(list.get(i), null)); } } else if (value == null) { array = new String[0]; } else if (isScalarValue(value)) { array = new String[1]; array[0] = value.toString(); } else { throw new ConversionException('\'' + key + "' doesn't map to a String/List object"); } return array; } /** * {@inheritDoc} * @see #getStringArray(String) */ public List getList(String key) { return getList(key, new ArrayList()); } public List getList(String key, List defaultValue) { Object value = getProperty(key); List list; if (value instanceof String) { list = new ArrayList(1); list.add(interpolate((String) value)); } else if (value instanceof List) { list = new ArrayList(); List l = (List) value; // add the interpolated elements in the new list for (Object elem : l) { list.add(interpolate(elem)); } } else if (value == null) { list = (List) defaultValue; } else if (value.getClass().isArray()) { return Arrays.asList((Object[]) value); } else if (isScalarValue(value)) { return Collections.singletonList((Object) value.toString()); } else { throw new ConversionException('\'' + key + "' doesn't map to a List object: " + value + ", a " + value.getClass().getName()); } return list; } /** * Returns an object from the store described by the key. If the value is a * Collection object, replace it with the first object in the collection. * * @param key The property key. * * @return value Value, transparently resolving a possible collection dependency. */ protected Object resolveContainerStore(String key) { Object value = getProperty(key); if (value != null) { if (value instanceof Collection) { Collection collection = (Collection) value; value = collection.isEmpty() ? null : collection.iterator().next(); } else if (value.getClass().isArray() && Array.getLength(value) > 0) { value = Array.get(value, 0); } } return value; } /** * Checks whether the specified object is a scalar value. This method is * called by {@code getList()} and {@code getStringArray()} if the * property requested is not a string, a list, or an array. If it returns * true, the calling method transforms the value to a string and * returns a list or an array with this single element. This implementation * returns true if the value is of a wrapper type for a primitive * type. * * @param value the value to be checked * @return a flag whether the value is a scalar * @since 1.7 */ protected boolean isScalarValue(Object value) { return ClassUtils.wrapperToPrimitive(value.getClass()) != null; } /** * Copies the content of the specified configuration into this * configuration. If the specified configuration contains a key that is also * present in this configuration, the value of this key will be replaced by * the new value. Note: This method won't work well when copying * hierarchical configurations because it is not able to copy information * about the properties' structure (i.e. the parent-child-relationships will * get lost). So when dealing with hierarchical configuration objects their * {@link HierarchicalConfiguration#clone() clone()} methods * should be used. * * @param c the configuration to copy (can be null, then this * operation will have no effect) * @since 1.5 */ public void copy(Configuration c) { if (c != null) { for (Iterator it = c.getKeys(); it.hasNext();) { String key = it.next(); Object value = c.getProperty(key); fireEvent(EVENT_SET_PROPERTY, key, value, true); setDetailEvents(false); try { clearProperty(key); addPropertyValues(key, value, DISABLED_DELIMITER); } finally { setDetailEvents(true); } fireEvent(EVENT_SET_PROPERTY, key, value, false); } } } /** * Appends the content of the specified configuration to this configuration. * The values of all properties contained in the specified configuration * will be appended to this configuration. So if a property is already * present in this configuration, its new value will be a union of the * values in both configurations. Note: This method won't work * well when appending hierarchical configurations because it is not able to * copy information about the properties' structure (i.e. the * parent-child-relationships will get lost). So when dealing with * hierarchical configuration objects their * {@link HierarchicalConfiguration#clone() clone()} methods * should be used. * * @param c the configuration to be appended (can be null, then this * operation will have no effect) * @since 1.5 */ public void append(Configuration c) { if (c != null) { for (Iterator it = c.getKeys(); it.hasNext();) { String key = it.next(); Object value = c.getProperty(key); fireEvent(EVENT_ADD_PROPERTY, key, value, true); addPropertyValues(key, value, DISABLED_DELIMITER); fireEvent(EVENT_ADD_PROPERTY, key, value, false); } } } /** * Returns a configuration with the same content as this configuration, but * with all variables replaced by their actual values. This method tries to * clone the configuration and then perform interpolation on all properties. * So property values of the form ${var} will be resolved as * far as possible (if a variable cannot be resolved, it remains unchanged). * This operation is useful if the content of a configuration is to be * exported or processed by an external component that does not support * variable interpolation. * * @return a configuration with all variables interpolated * @throws ConfigurationRuntimeException if this configuration cannot be * cloned * @since 1.5 */ public Configuration interpolatedConfiguration() { // first clone this configuration AbstractConfiguration c = (AbstractConfiguration) ConfigurationUtils .cloneConfiguration(this); // now perform interpolation c.setDelimiterParsingDisabled(true); for (Iterator it = getKeys(); it.hasNext();) { String key = it.next(); c.setProperty(key, getList(key)); } c.setDelimiterParsingDisabled(isDelimiterParsingDisabled()); return c; } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractFileConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractFileConfigurat100644 101575 12232154102 33561 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.net.URL; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import org.apache.commons.configuration.reloading.InvariantReloadingStrategy; import org.apache.commons.configuration.reloading.ReloadingStrategy; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.LogFactory; /** *

Partial implementation of the {@code FileConfiguration} interface. * Developers of file based configuration may want to extend this class, * the two methods left to implement are {@link FileConfiguration#load(Reader)} * and {@link FileConfiguration#save(Writer)}.

*

This base class already implements a couple of ways to specify the location * of the file this configuration is based on. The following possibilities * exist: *

  • URLs: With the method {@code setURL()} a full URL to the * configuration source can be specified. This is the most flexible way. Note * that the {@code save()} methods support only file: URLs.
  • *
  • Files: The {@code setFile()} method allows to specify the * configuration source as a file. This can be either a relative or an * absolute file. In the former case the file is resolved based on the current * directory.
  • *
  • As file paths in string form: With the {@code setPath()} method a * full path to a configuration file can be provided as a string.
  • *
  • Separated as base path and file name: This is the native form in which * the location is stored. The base path is a string defining either a local * directory or a URL. It can be set using the {@code setBasePath()} * method. The file name, non surprisingly, defines the name of the configuration * file.

*

The configuration source to be loaded can be specified using one of the * methods described above. Then the parameterless {@code load()} method can be * called. Alternatively, one of the {@code load()} methods can be used which is * passed the source directly. These methods typically do not change the * internally stored file; however, if the configuration is not yet associated * with a configuration source, the first call to one of the {@code load()} * methods sets the base path and the source URL. This fact has to be taken * into account when calling {@code load()} multiple times with different file * paths.

*

Note that the {@code load()} methods do not wipe out the configuration's * content before the new configuration file is loaded. Thus it is very easy to * construct a union configuration by simply loading multiple configuration * files, e.g.

*

 * config.load(configFile1);
 * config.load(configFile2);
 * 

*

After executing this code fragment, the resulting configuration will * contain both the properties of configFile1 and configFile2. On the other * hand, if the current configuration file is to be reloaded, {@code clear()} * should be called first. Otherwise the properties are doubled. This behavior * is analogous to the behavior of the {@code load(InputStream)} method * in {@code java.util.Properties}.

* * @author Emmanuel Bourg * @version $Id: AbstractFileConfiguration.java 1234118 2012-01-20 20:36:04Z oheger $ * @since 1.0-rc2 */ public abstract class AbstractFileConfiguration extends BaseConfiguration implements FileConfiguration, FileSystemBased { /** Constant for the configuration reload event.*/ public static final int EVENT_RELOAD = 20; /** Constant fro the configuration changed event. */ public static final int EVENT_CONFIG_CHANGED = 21; /** The root of the file scheme */ private static final String FILE_SCHEME = "file:"; /** Stores the file name.*/ protected String fileName; /** Stores the base path.*/ protected String basePath; /** The auto save flag.*/ protected boolean autoSave; /** Holds a reference to the reloading strategy.*/ protected ReloadingStrategy strategy; /** A lock object for protecting reload operations.*/ protected Object reloadLock = new Lock("AbstractFileConfiguration"); /** Stores the encoding of the configuration file.*/ private String encoding; /** Stores the URL from which the configuration file was loaded.*/ private URL sourceURL; /** A counter that prohibits reloading.*/ private int noReload; /** The FileSystem being used for this Configuration */ private FileSystem fileSystem = FileSystem.getDefaultFileSystem(); /** * Default constructor * * @since 1.1 */ public AbstractFileConfiguration() { initReloadingStrategy(); setLogger(LogFactory.getLog(getClass())); addErrorLogListener(); } /** * Creates and loads the configuration from the specified file. The passed * in string must be a valid file name, either absolute or relativ. * * @param fileName The name of the file to load. * * @throws ConfigurationException Error while loading the file * @since 1.1 */ public AbstractFileConfiguration(String fileName) throws ConfigurationException { this(); // store the file name setFileName(fileName); // load the file load(); } /** * Creates and loads the configuration from the specified file. * * @param file The file to load. * @throws ConfigurationException Error while loading the file * @since 1.1 */ public AbstractFileConfiguration(File file) throws ConfigurationException { this(); // set the file and update the url, the base path and the file name setFile(file); // load the file if (file.exists()) { load(); } } /** * Creates and loads the configuration from the specified URL. * * @param url The location of the file to load. * @throws ConfigurationException Error while loading the file * @since 1.1 */ public AbstractFileConfiguration(URL url) throws ConfigurationException { this(); // set the URL and update the base path and the file name setURL(url); // load the file load(); } public void setFileSystem(FileSystem fileSystem) { if (fileSystem == null) { throw new NullPointerException("A valid FileSystem must be specified"); } this.fileSystem = fileSystem; } public void resetFileSystem() { this.fileSystem = FileSystem.getDefaultFileSystem(); } public FileSystem getFileSystem() { return this.fileSystem; } public Object getReloadLock() { return reloadLock; } /** * Load the configuration from the underlying location. * * @throws ConfigurationException if loading of the configuration fails */ public void load() throws ConfigurationException { if (sourceURL != null) { load(sourceURL); } else { load(getFileName()); } } /** * Locate the specified file and load the configuration. If the configuration is * already associated with a source, the current source is not changed. * Otherwise (i.e. this is the first load operation), the source URL and * the base path are set now based on the source to be loaded. * * @param fileName the name of the file to be loaded * @throws ConfigurationException if an error occurs */ public void load(String fileName) throws ConfigurationException { try { URL url = ConfigurationUtils.locate(this.fileSystem, basePath, fileName); if (url == null) { throw new ConfigurationException("Cannot locate configuration source " + fileName); } load(url); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration file " + fileName, e); } } /** * Load the configuration from the specified file. If the configuration is * already associated with a source, the current source is not changed. * Otherwise (i.e. this is the first load operation), the source URL and * the base path are set now based on the source to be loaded. * * @param file the file to load * @throws ConfigurationException if an error occurs */ public void load(File file) throws ConfigurationException { try { load(ConfigurationUtils.toURL(file)); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration file " + file, e); } } /** * Load the configuration from the specified URL. If the configuration is * already associated with a source, the current source is not changed. * Otherwise (i.e. this is the first load operation), the source URL and * the base path are set now based on the source to be loaded. * * @param url the URL of the file to be loaded * @throws ConfigurationException if an error occurs */ public void load(URL url) throws ConfigurationException { if (sourceURL == null) { if (StringUtils.isEmpty(getBasePath())) { // ensure that we have a valid base path setBasePath(url.toString()); } sourceURL = url; } InputStream in = null; try { in = fileSystem.getInputStream(url); load(in); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration from the URL " + url, e); } finally { // close the input stream try { if (in != null) { in.close(); } } catch (IOException e) { getLogger().warn("Could not close input stream", e); } } } /** * Load the configuration from the specified stream, using the encoding * returned by {@link #getEncoding()}. * * @param in the input stream * * @throws ConfigurationException if an error occurs during the load operation */ public void load(InputStream in) throws ConfigurationException { load(in, getEncoding()); } /** * Load the configuration from the specified stream, using the specified * encoding. If the encoding is null the default encoding is used. * * @param in the input stream * @param encoding the encoding used. {@code null} to use the default encoding * * @throws ConfigurationException if an error occurs during the load operation */ public void load(InputStream in, String encoding) throws ConfigurationException { Reader reader = null; if (encoding != null) { try { reader = new InputStreamReader(in, encoding); } catch (UnsupportedEncodingException e) { throw new ConfigurationException( "The requested encoding is not supported, try the default encoding.", e); } } if (reader == null) { reader = new InputStreamReader(in); } load(reader); } /** * Save the configuration. Before this method can be called a valid file * name must have been set. * * @throws ConfigurationException if an error occurs or no file name has * been set yet */ public void save() throws ConfigurationException { if (getFileName() == null) { throw new ConfigurationException("No file name has been set!"); } if (sourceURL != null) { save(sourceURL); } else { save(fileName); } strategy.init(); } /** * Save the configuration to the specified file. This doesn't change the * source of the configuration, use setFileName() if you need it. * * @param fileName the file name * * @throws ConfigurationException if an error occurs during the save operation */ public void save(String fileName) throws ConfigurationException { try { URL url = this.fileSystem.getURL(basePath, fileName); if (url == null) { throw new ConfigurationException("Cannot locate configuration source " + fileName); } save(url); /*File file = ConfigurationUtils.getFile(basePath, fileName); if (file == null) { throw new ConfigurationException("Invalid file name for save: " + fileName); } save(file); */ } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to save the configuration to the file " + fileName, e); } } /** * Save the configuration to the specified URL. * This doesn't change the source of the configuration, use setURL() * if you need it. * * @param url the URL * * @throws ConfigurationException if an error occurs during the save operation */ public void save(URL url) throws ConfigurationException { OutputStream out = null; try { out = fileSystem.getOutputStream(url); save(out); if (out instanceof VerifiableOutputStream) { ((VerifiableOutputStream) out).verify(); } } catch (IOException e) { throw new ConfigurationException("Could not save to URL " + url, e); } finally { closeSilent(out); } } /** * Save the configuration to the specified file. The file is created * automatically if it doesn't exist. This doesn't change the source * of the configuration, use {@link #setFile} if you need it. * * @param file the target file * * @throws ConfigurationException if an error occurs during the save operation */ public void save(File file) throws ConfigurationException { OutputStream out = null; try { out = fileSystem.getOutputStream(file); save(out); } finally { closeSilent(out); } } /** * Save the configuration to the specified stream, using the encoding * returned by {@link #getEncoding()}. * * @param out the output stream * * @throws ConfigurationException if an error occurs during the save operation */ public void save(OutputStream out) throws ConfigurationException { save(out, getEncoding()); } /** * Save the configuration to the specified stream, using the specified * encoding. If the encoding is null the default encoding is used. * * @param out the output stream * @param encoding the encoding to use * @throws ConfigurationException if an error occurs during the save operation */ public void save(OutputStream out, String encoding) throws ConfigurationException { Writer writer = null; if (encoding != null) { try { writer = new OutputStreamWriter(out, encoding); } catch (UnsupportedEncodingException e) { throw new ConfigurationException( "The requested encoding is not supported, try the default encoding.", e); } } if (writer == null) { writer = new OutputStreamWriter(out); } save(writer); } /** * Return the name of the file. * * @return the file name */ public String getFileName() { return fileName; } /** * Set the name of the file. The passed in file name can contain a * relative path. * It must be used when referring files with relative paths from classpath. * Use {@link AbstractFileConfiguration#setPath(String) * setPath()} to set a full qualified file name. * * @param fileName the name of the file */ public void setFileName(String fileName) { if (fileName != null && fileName.startsWith(FILE_SCHEME) && !fileName.startsWith("file://")) { fileName = "file://" + fileName.substring(FILE_SCHEME.length()); } sourceURL = null; this.fileName = fileName; getLogger().debug("FileName set to " + fileName); } /** * Return the base path. * * @return the base path * @see FileConfiguration#getBasePath() */ public String getBasePath() { return basePath; } /** * Sets the base path. The base path is typically either a path to a * directory or a URL. Together with the value passed to the * {@code setFileName()} method it defines the location of the * configuration file to be loaded. The strategies for locating the file are * quite tolerant. For instance if the file name is already an absolute path * or a fully defined URL, the base path will be ignored. The base path can * also be a URL, in which case the file name is interpreted in this URL's * context. Because the base path is used by some of the derived classes for * resolving relative file names it should contain a meaningful value. If * other methods are used for determining the location of the configuration * file (e.g. {@code setFile()} or {@code setURL()}), the * base path is automatically set. * * @param basePath the base path. */ public void setBasePath(String basePath) { if (basePath != null && basePath.startsWith(FILE_SCHEME) && !basePath.startsWith("file://")) { basePath = "file://" + basePath.substring(FILE_SCHEME.length()); } sourceURL = null; this.basePath = basePath; getLogger().debug("Base path set to " + basePath); } /** * Return the file where the configuration is stored. If the base path is a * URL with a protocol different than "file", or the configuration * file is within a compressed archive, the return value * will not point to a valid file object. * * @return the file where the configuration is stored; this can be null */ public File getFile() { if (getFileName() == null && sourceURL == null) { return null; } else if (sourceURL != null) { return ConfigurationUtils.fileFromURL(sourceURL); } else { return ConfigurationUtils.getFile(getBasePath(), getFileName()); } } /** * Set the file where the configuration is stored. The passed in file is * made absolute if it is not yet. Then the file's path component becomes * the base path and its name component becomes the file name. * * @param file the file where the configuration is stored */ public void setFile(File file) { sourceURL = null; setFileName(file.getName()); setBasePath((file.getParentFile() != null) ? file.getParentFile() .getAbsolutePath() : null); } /** * Returns the full path to the file this configuration is based on. The * return value is a valid File path only if this configuration is based on * a file on the local disk. * If the configuration was loaded from a packed archive the returned value * is the string form of the URL from which the configuration was loaded. * * @return the full path to the configuration file */ public String getPath() { return fileSystem.getPath(getFile(), sourceURL, getBasePath(), getFileName()); } /** * Sets the location of this configuration as a full or relative path name. * The passed in path should represent a valid file name on the file system. * It must not be used to specify relative paths for files that exist * in classpath, either plain file system or compressed archive, * because this method expands any relative path to an absolute one which * may end in an invalid absolute path for classpath references. * * @param path the full path name of the configuration file */ public void setPath(String path) { setFile(new File(path)); } URL getSourceURL() { return sourceURL; } /** * Return the URL where the configuration is stored. * * @return the configuration's location as URL */ public URL getURL() { return (sourceURL != null) ? sourceURL : ConfigurationUtils.locate(this.fileSystem, getBasePath(), getFileName()); } /** * Set the location of this configuration as a URL. For loading this can be * an arbitrary URL with a supported protocol. If the configuration is to * be saved, too, a URL with the "file" protocol should be * provided. * * @param url the location of this configuration as URL */ public void setURL(URL url) { setBasePath(ConfigurationUtils.getBasePath(url)); setFileName(ConfigurationUtils.getFileName(url)); sourceURL = url; getLogger().debug("URL set to " + url); } public void setAutoSave(boolean autoSave) { this.autoSave = autoSave; } public boolean isAutoSave() { return autoSave; } /** * Save the configuration if the automatic persistence is enabled * and if a file is specified. */ protected void possiblySave() { if (autoSave && fileName != null) { try { save(); } catch (ConfigurationException e) { throw new ConfigurationRuntimeException("Failed to auto-save", e); } } } /** * Adds a new property to this configuration. This implementation checks if * the auto save mode is enabled and saves the configuration if necessary. * * @param key the key of the new property * @param value the value */ @Override public void addProperty(String key, Object value) { synchronized (reloadLock) { super.addProperty(key, value); possiblySave(); } } /** * Sets a new value for the specified property. This implementation checks * if the auto save mode is enabled and saves the configuration if * necessary. * * @param key the key of the affected property * @param value the value */ @Override public void setProperty(String key, Object value) { synchronized (reloadLock) { super.setProperty(key, value); possiblySave(); } } @Override public void clearProperty(String key) { synchronized (reloadLock) { super.clearProperty(key); possiblySave(); } } public ReloadingStrategy getReloadingStrategy() { return strategy; } public void setReloadingStrategy(ReloadingStrategy strategy) { this.strategy = strategy; strategy.setConfiguration(this); strategy.init(); } /** * Performs a reload operation if necessary. This method is called on each * access of this configuration. It asks the associated reloading strategy * whether a reload should be performed. If this is the case, the * configuration is cleared and loaded again from its source. If this * operation causes an exception, the registered error listeners will be * notified. The error event passed to the listeners is of type * {@code EVENT_RELOAD} and contains the exception that caused the * event. */ public void reload() { reload(false); } public boolean reload(boolean checkReload) { synchronized (reloadLock) { if (noReload == 0) { try { enterNoReload(); // avoid reentrant calls if (strategy.reloadingRequired()) { if (getLogger().isInfoEnabled()) { getLogger().info("Reloading configuration. URL is " + getURL()); } refresh(); // notify the strategy strategy.reloadingPerformed(); } } catch (Exception e) { fireError(EVENT_RELOAD, null, null, e); // todo rollback the changes if the file can't be reloaded if (checkReload) { return false; } } finally { exitNoReload(); } } } return true; } /** * Reloads the associated configuration file. This method first clears the * content of this configuration, then the associated configuration file is * loaded again. Updates on this configuration which have not yet been saved * are lost. Calling this method is like invoking {@code reload()} * without checking the reloading strategy. * * @throws ConfigurationException if an error occurs * @since 1.7 */ public void refresh() throws ConfigurationException { fireEvent(EVENT_RELOAD, null, getURL(), true); setDetailEvents(false); boolean autoSaveBak = this.isAutoSave(); // save the current state this.setAutoSave(false); // deactivate autoSave to prevent information loss try { clear(); load(); } finally { this.setAutoSave(autoSaveBak); // set autoSave to previous value setDetailEvents(true); } fireEvent(EVENT_RELOAD, null, getURL(), false); } /** * Send notification that the configuration has changed. */ public void configurationChanged() { fireEvent(EVENT_CONFIG_CHANGED, null, getURL(), true); } /** * Enters the "No reloading mode". As long as this mode is active * no reloading will be performed. This is necessary for some * implementations of {@code save()} in derived classes, which may * cause a reload while accessing the properties to save. This may cause the * whole configuration to be erased. To avoid this, this method can be * called first. After a call to this method there always must be a * corresponding call of {@link #exitNoReload()} later! (If * necessary, {@code finally} blocks must be used to ensure this. */ protected void enterNoReload() { synchronized (reloadLock) { noReload++; } } /** * Leaves the "No reloading mode". * * @see #enterNoReload() */ protected void exitNoReload() { synchronized (reloadLock) { if (noReload > 0) // paranoia check { noReload--; } } } /** * Sends an event to all registered listeners. This implementation ensures * that no reloads are performed while the listeners are invoked. So * infinite loops can be avoided that can be caused by event listeners * accessing the configuration's properties when they are invoked. * * @param type the event type * @param propName the name of the property * @param propValue the value of the property * @param before the before update flag */ @Override protected void fireEvent(int type, String propName, Object propValue, boolean before) { enterNoReload(); try { super.fireEvent(type, propName, propValue, before); } finally { exitNoReload(); } } @Override public Object getProperty(String key) { synchronized (reloadLock) { reload(); return super.getProperty(key); } } @Override public boolean isEmpty() { reload(); synchronized (reloadLock) { return super.isEmpty(); } } @Override public boolean containsKey(String key) { reload(); synchronized (reloadLock) { return super.containsKey(key); } } /** * Returns an {@code Iterator} with the keys contained in this * configuration. This implementation performs a reload if necessary before * obtaining the keys. The {@code Iterator} returned by this method * points to a snapshot taken when this method was called. Later changes at * the set of keys (including those caused by a reload) won't be visible. * This is because a reload can happen at any time during iteration, and it * is impossible to determine how this reload affects the current iteration. * When using the iterator a client has to be aware that changes of the * configuration are possible at any time. For instance, if after a reload * operation some keys are no longer present, the iterator will still return * those keys because they were found when it was created. * * @return an {@code Iterator} with the keys of this configuration */ @Override public Iterator getKeys() { reload(); List keyList = new LinkedList(); enterNoReload(); try { for (Iterator it = super.getKeys(); it.hasNext();) { keyList.add(it.next()); } return keyList.iterator(); } finally { exitNoReload(); } } public String getEncoding() { return encoding; } public void setEncoding(String encoding) { this.encoding = encoding; } /** * Creates a copy of this configuration. The new configuration object will * contain the same properties as the original, but it will lose any * connection to a source file (if one exists); this includes setting the * source URL, base path, and file name to null. This is done to * avoid race conditions if both the original and the copy are modified and * then saved. * * @return the copy * @since 1.3 */ @Override public Object clone() { AbstractFileConfiguration copy = (AbstractFileConfiguration) super.clone(); copy.setBasePath(null); copy.setFileName(null); copy.initReloadingStrategy(); return copy; } /** * Helper method for initializing the reloading strategy. */ private void initReloadingStrategy() { setReloadingStrategy(new InvariantReloadingStrategy()); } /** * A helper method for closing an output stream. Occurring exceptions will * be ignored. * * @param out the output stream to be closed (may be null) * @since 1.5 */ protected void closeSilent(OutputStream out) { try { if (out != null) { out.close(); } } catch (IOException e) { getLogger().warn("Could not close output stream", e); } } } ././@LongLink100644 0 0 171 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractHierarchicalFi100644 35415 12232154103 33475 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.Collection; import java.util.Iterator; import java.util.List; import org.apache.commons.configuration.event.ConfigurationErrorEvent; import org.apache.commons.configuration.event.ConfigurationErrorListener; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.reloading.Reloadable; import org.apache.commons.configuration.reloading.ReloadingStrategy; import org.apache.commons.configuration.tree.ConfigurationNode; /** *

Base class for implementing file based hierarchical configurations.

*

This class serves an analogous purpose as the * {@link AbstractFileConfiguration} class for non hierarchical * configurations. It behaves in exactly the same way, so please refer to the * documentation of {@code AbstractFileConfiguration} for further details.

* * @since 1.2 * * @author Emmanuel Bourg * @version $Id: AbstractHierarchicalFileConfiguration.java 1206575 2011-11-26 20:07:52Z oheger $ */ public abstract class AbstractHierarchicalFileConfiguration extends HierarchicalConfiguration implements FileConfiguration, ConfigurationListener, ConfigurationErrorListener, FileSystemBased, Reloadable { /** Stores the delegate used for implementing functionality related to the * {@code FileConfiguration} interface. */ private FileConfigurationDelegate delegate; /** * Creates a new instance of {@code AbstractHierarchicalFileConfiguration}. */ protected AbstractHierarchicalFileConfiguration() { initialize(); } /** * Creates a new instance of * {@code AbstractHierarchicalFileConfiguration} and copies the * content of the specified configuration into this object. * * @param c the configuration to copy * @since 1.4 */ protected AbstractHierarchicalFileConfiguration(HierarchicalConfiguration c) { super(c); initialize(); } /** * Creates and loads the configuration from the specified file. * * @param fileName The name of the plist file to load. * @throws ConfigurationException Error while loading the file */ public AbstractHierarchicalFileConfiguration(String fileName) throws ConfigurationException { this(); // store the file name delegate.setFileName(fileName); // load the file load(); } /** * Creates and loads the configuration from the specified file. * * @param file The configuration file to load. * @throws ConfigurationException Error while loading the file */ public AbstractHierarchicalFileConfiguration(File file) throws ConfigurationException { this(); // set the file and update the url, the base path and the file name setFile(file); // load the file if (file.exists()) { load(); } } /** * Creates and loads the configuration from the specified URL. * * @param url The location of the configuration file to load. * @throws ConfigurationException Error while loading the file */ public AbstractHierarchicalFileConfiguration(URL url) throws ConfigurationException { this(); // set the URL and update the base path and the file name setURL(url); // load the file load(); } /** * Initializes this instance, mainly the internally used delegate object. */ private void initialize() { delegate = createDelegate(); initDelegate(delegate); } @Override protected void addPropertyDirect(String key, Object obj) { synchronized (delegate.getReloadLock()) { super.addPropertyDirect(key, obj); delegate.possiblySave(); } } @Override public void clearProperty(String key) { synchronized (delegate.getReloadLock()) { super.clearProperty(key); delegate.possiblySave(); } } @Override public void clearTree(String key) { synchronized (delegate.getReloadLock()) { super.clearTree(key); delegate.possiblySave(); } } @Override public void setProperty(String key, Object value) { synchronized (delegate.getReloadLock()) { super.setProperty(key, value); delegate.possiblySave(); } } public void load() throws ConfigurationException { delegate.load(); } public void load(String fileName) throws ConfigurationException { delegate.load(fileName); } public void load(File file) throws ConfigurationException { delegate.load(file); } public void load(URL url) throws ConfigurationException { delegate.load(url); } public void load(InputStream in) throws ConfigurationException { delegate.load(in); } public void load(InputStream in, String encoding) throws ConfigurationException { delegate.load(in, encoding); } public void save() throws ConfigurationException { delegate.save(); } public void save(String fileName) throws ConfigurationException { delegate.save(fileName); } public void save(File file) throws ConfigurationException { delegate.save(file); } public void save(URL url) throws ConfigurationException { delegate.save(url); } public void save(OutputStream out) throws ConfigurationException { delegate.save(out); } public void save(OutputStream out, String encoding) throws ConfigurationException { delegate.save(out, encoding); } public String getFileName() { return delegate.getFileName(); } public void setFileName(String fileName) { delegate.setFileName(fileName); } public String getBasePath() { return delegate.getBasePath(); } public void setBasePath(String basePath) { delegate.setBasePath(basePath); } public File getFile() { return delegate.getFile(); } public void setFile(File file) { delegate.setFile(file); } public URL getURL() { return delegate.getURL(); } public void setURL(URL url) { delegate.setURL(url); } public void setAutoSave(boolean autoSave) { delegate.setAutoSave(autoSave); } public boolean isAutoSave() { return delegate.isAutoSave(); } public ReloadingStrategy getReloadingStrategy() { return delegate.getReloadingStrategy(); } public void setReloadingStrategy(ReloadingStrategy strategy) { delegate.setReloadingStrategy(strategy); } public void reload() { reload(false); } private boolean reload(boolean checkReload) { synchronized (delegate.getReloadLock()) { setDetailEvents(false); try { return delegate.reload(checkReload); } finally { setDetailEvents(true); } } } /** * Reloads the associated configuration file. This method first clears the * content of this configuration, then the associated configuration file is * loaded again. Updates on this configuration which have not yet been saved * are lost. Calling this method is like invoking {@code reload()} * without checking the reloading strategy. * * @throws ConfigurationException if an error occurs * @since 1.7 */ public void refresh() throws ConfigurationException { delegate.refresh(); } public String getEncoding() { return delegate.getEncoding(); } public void setEncoding(String encoding) { delegate.setEncoding(encoding); } @Override public Object getReloadLock() { return delegate.getReloadLock(); } @Override public boolean containsKey(String key) { reload(); synchronized (delegate.getReloadLock()) { return super.containsKey(key); } } @Override public Iterator getKeys() { reload(); synchronized (delegate.getReloadLock()) { return super.getKeys(); } } @Override public Iterator getKeys(String prefix) { reload(); synchronized (delegate.getReloadLock()) { return super.getKeys(prefix); } } @Override public Object getProperty(String key) { if (reload(true)) { // Avoid reloading again and getting the same error. synchronized (delegate.getReloadLock()) { return super.getProperty(key); } } return null; } @Override public boolean isEmpty() { reload(); synchronized (delegate.getReloadLock()) { return super.isEmpty(); } } /** * Directly adds sub nodes to this configuration. This implementation checks * whether auto save is necessary after executing the operation. * * @param key the key where the nodes are to be added * @param nodes a collection with the nodes to be added * @since 1.5 */ @Override public void addNodes(String key, Collection nodes) { synchronized (delegate.getReloadLock()) { super.addNodes(key, nodes); delegate.possiblySave(); } } /** * Fetches a list of nodes, which are selected by the specified key. This * implementation will perform a reload if necessary. * * @param key the key * @return a list with the selected nodes */ @Override protected List fetchNodeList(String key) { reload(); synchronized (delegate.getReloadLock()) { return super.fetchNodeList(key); } } /** * Reacts on changes of an associated subnode configuration. If the auto * save mechanism is active, the configuration must be saved. * * @param event the event describing the change * @since 1.5 */ @Override protected void subnodeConfigurationChanged(ConfigurationEvent event) { delegate.possiblySave(); super.subnodeConfigurationChanged(event); } /** * Creates the file configuration delegate, i.e. the object that implements * functionality required by the {@code FileConfiguration} interface. * This base implementation will return an instance of the * {@code FileConfigurationDelegate} class. Derived classes may * override it to create a different delegate object. * * @return the file configuration delegate */ protected FileConfigurationDelegate createDelegate() { return new FileConfigurationDelegate(); } /** * Helper method for initializing the file configuration delegate. * * @param del the delegate */ private void initDelegate(FileConfigurationDelegate del) { del.addConfigurationListener(this); del.addErrorListener(this); del.setLogger(getLogger()); } /** * Reacts on configuration change events triggered by the delegate. These * events are passed to the registered configuration listeners. * * @param event the triggered event * @since 1.3 */ public void configurationChanged(ConfigurationEvent event) { // deliver reload events to registered listeners setDetailEvents(true); try { fireEvent(event.getType(), event.getPropertyName(), event .getPropertyValue(), event.isBeforeUpdate()); } finally { setDetailEvents(false); } } public void configurationError(ConfigurationErrorEvent event) { fireError(event.getType(), event.getPropertyName(), event.getPropertyValue(), event.getCause()); } /** * Returns the file configuration delegate. * * @return the delegate */ protected FileConfigurationDelegate getDelegate() { return delegate; } /** * Allows to set the file configuration delegate. * @param delegate the new delegate */ protected void setDelegate(FileConfigurationDelegate delegate) { this.delegate = delegate; } /** * Set the FileSystem to be used for this Configuration. * @param fileSystem The FileSystem to use. */ public void setFileSystem(FileSystem fileSystem) { delegate.setFileSystem(fileSystem); } /** * Reset the FileSystem to the default; */ public void resetFileSystem() { delegate.resetFileSystem(); } /** * Retrieve the FileSystem being used. * @return The FileSystem. */ public FileSystem getFileSystem() { return delegate.getFileSystem(); } /** * A special implementation of the {@code FileConfiguration} interface that is * used internally to implement the {@code FileConfiguration} methods * for hierarchical configurations. */ protected class FileConfigurationDelegate extends AbstractFileConfiguration { public void load(Reader in) throws ConfigurationException { AbstractHierarchicalFileConfiguration.this.load(in); } public void save(Writer out) throws ConfigurationException { AbstractHierarchicalFileConfiguration.this.save(out); } @Override public void clear() { AbstractHierarchicalFileConfiguration.this.clear(); } } } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/BaseConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/BaseConfiguration.java100644 14616 12232154103 33476 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; /** * Basic configuration class. Stores the configuration data but does not * provide any load or save functions. If you want to load your Configuration * from a file use PropertiesConfiguration or XmlConfiguration. * * This class extends normal Java properties by adding the possibility * to use the same key many times concatenating the value strings * instead of overwriting them. * * @author Stefano Mazzocchi * @author Jon S. Stevens * @author Dave Bryson * @author Geir Magnusson Jr. * @author Leon Messerschmidt * @author Kent Johnson * @author Daniel Rall * @author Ilkka Priha * @author Jason van Zyl * @author Martin Poeschl * @author Henning P. Schmiedehausen * @author Konstantin Shaposhnikov * @version $Id: BaseConfiguration.java 1231721 2012-01-15 18:32:07Z oheger $ */ public class BaseConfiguration extends AbstractConfiguration implements Cloneable { /** stores the configuration key-value pairs */ private Map store = new LinkedHashMap(); /** * Adds a key/value pair to the map. This routine does no magic morphing. * It ensures the keylist is maintained * * @param key key to use for mapping * @param value object to store */ @Override protected void addPropertyDirect(String key, Object value) { Object previousValue = getProperty(key); if (previousValue == null) { store.put(key, value); } else if (previousValue instanceof List) { // safe to case because we have created the lists ourselves @SuppressWarnings("unchecked") List valueList = (List) previousValue; // the value is added to the existing list valueList.add(value); } else { // the previous value is replaced by a list containing the previous value and the new value List list = new ArrayList(); list.add(previousValue); list.add(value); store.put(key, list); } } /** * Read property from underlying map. * * @param key key to use for mapping * * @return object associated with the given configuration key. */ public Object getProperty(String key) { return store.get(key); } /** * Check if the configuration is empty * * @return {@code true} if Configuration is empty, * {@code false} otherwise. */ public boolean isEmpty() { return store.isEmpty(); } /** * check if the configuration contains the key * * @param key the configuration key * * @return {@code true} if Configuration contain given key, * {@code false} otherwise. */ public boolean containsKey(String key) { return store.containsKey(key); } /** * Clear a property in the configuration. * * @param key the key to remove along with corresponding value. */ @Override protected void clearPropertyDirect(String key) { if (containsKey(key)) { store.remove(key); } } @Override public void clear() { fireEvent(EVENT_CLEAR, null, null, true); store.clear(); fireEvent(EVENT_CLEAR, null, null, false); } /** * Get the list of the keys contained in the configuration * repository. * * @return An Iterator. */ public Iterator getKeys() { return store.keySet().iterator(); } /** * Creates a copy of this object. This implementation will create a deep * clone, i.e. the map that stores the properties is cloned, too. So changes * performed at the copy won't affect the original and vice versa. * * @return the copy * @since 1.3 */ @Override public Object clone() { try { BaseConfiguration copy = (BaseConfiguration) super.clone(); // This is safe because the type of the map is known @SuppressWarnings("unchecked") Map clonedStore = (Map) ConfigurationUtils.clone(store); copy.store = clonedStore; // Handle collections in the map; they have to be cloned, too for (Map.Entry e : store.entrySet()) { if (e.getValue() instanceof Collection) { // This is safe because the collections were created by ourselves @SuppressWarnings("unchecked") Collection strList = (Collection) e.getValue(); copy.store.put(e.getKey(), new ArrayList(strList)); } } return copy; } catch (CloneNotSupportedException cex) { // should not happen throw new ConfigurationRuntimeException(cex); } } } ././@LongLink100644 0 0 156 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/BaseConfigurationXMLReader.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/BaseConfigurationXMLRe100644 7673 12232154103 33413 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; /** *

A specialized SAX2 XML parser that processes configuration objects.

* *

This class mimics to be a SAX compliant XML parser. It is able to iterate * over the keys in a configuration object and to generate corresponding SAX * events. By registering a {@code ContentHandler} at an instance * it is possible to perform XML processing on a configuration object.

* * @author Commons * Configuration team * @version $Id: BaseConfigurationXMLReader.java 1206765 2011-11-27 16:46:11Z oheger $ */ public class BaseConfigurationXMLReader extends ConfigurationXMLReader { /** Stores the actual configuration.*/ private Configuration config; /** * Creates a new instance of {@code BaseConfigurationXMLReader}. */ public BaseConfigurationXMLReader() { super(); } /** * Creates a new instance of {@code BaseConfigurationXMLReader} and * sets the configuration object to be parsed. * * @param conf the configuration to be parsed */ public BaseConfigurationXMLReader(Configuration conf) { this(); setConfiguration(conf); } /** * Returns the actual configuration to be processed. * * @return the actual configuration */ public Configuration getConfiguration() { return config; } /** * Sets the configuration to be processed. * * @param conf the configuration */ public void setConfiguration(Configuration conf) { config = conf; } /** * Returns the configuration to be processed. * * @return the actual configuration */ @Override public Configuration getParsedConfiguration() { return getConfiguration(); } /** * The main SAX event generation method. This element uses an internal * {@code HierarchicalConfigurationConverter} object to iterate over * all keys in the actual configuration and to generate corresponding SAX * events. */ @Override protected void processKeys() { fireElementStart(getRootName(), null); new SAXConverter().process(getConfiguration()); fireElementEnd(getRootName()); } /** * An internally used helper class to iterate over all configuration keys * ant to generate corresponding SAX events. * */ class SAXConverter extends HierarchicalConfigurationConverter { /** * Callback for the start of an element. * * @param name the element name * @param value the element value */ @Override protected void elementStart(String name, Object value) { fireElementStart(name, null); if (value != null) { fireCharacters(value.toString()); } } /** * Callback for the end of an element. * * @param name the element name */ @Override protected void elementEnd(String name) { fireElementEnd(name); } } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanDeclaration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanDeclarat100644 10311 12232154102 33432 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import java.util.Map; /** *

* Definition of an interface for declaring a bean in a configuration file. *

*

* Commons Configurations allows to define beans (i.e. simple Java objects) in * configuration files, which can be created at runtime. This is especially * useful if you program against interfaces and want to define the concrete * implementation class is a configuration file. *

*

* This interface defines methods for retrieving all information about a bean * that should be created from a configuration file, e.g. the bean's properties * or the factory to use for creating the instance. With different * implementations different "layouts" of bean declarations can be * supported. For instance if an XML configuration file is used, all features of * XML (e.g. attributes, nested elements) can be used to define the bean. In a * properties file the declaration format is more limited. The purpose of this * interface is to abstract from the concrete declaration format. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: BeanDeclaration.java 1208756 2011-11-30 20:37:32Z oheger $ */ public interface BeanDeclaration { /** * Returns the name of the {@code BeanFactory} that should be used * for creating the bean instance. This can be null, then a default * factory will be used. * * @return the name of the bean factory */ String getBeanFactoryName(); /** * Here an arbitrary object can be returned that will be passed to the bean * factory. Its meaning is not further specified. The purpose of this * additional parameter is to support a further configuration of the bean * factory that can be placed directly at the bean declaration. * * @return a parameter for the bean factory */ Object getBeanFactoryParameter(); /** * Returns the name of the bean class, from which an instance is to be * created. This value must be defined unless a default class is provided * for the bean creation operation. * * @return the name of the bean class */ String getBeanClassName(); /** * Returns a map with properties that should be initialized on the newly * created bean. The map's keys are the names of the properties; the * corresponding values are the properties' values. The return value can be * null if no properties should be set. * * @return a map with properties to be initialized */ Map getBeanProperties(); /** * Returns a map with declarations for beans that should be set as * properties of the newly created bean. This allows for complex * initialization scenarios: a bean for a bean that contains complex * properties (e.g. other beans) can have nested declarations for defining * these complex properties. The returned map's key are the names of the * properties to initialize. The values are either {@code BeanDeclaration} * implementations or collections thereof. They will be treated like this * declaration (in a* recursive manner), and the resulting beans are * assigned to the corresponding properties. * * @return a map with nested bean declarations */ Map getNestedBeanDeclarations(); } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanFactory.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanFactory.100644 6636 12232154102 33377 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; /** *

* Definition of an interface for bean factories. *

*

* Beans defined in configuration files are not directly created, but by so * called bean factories. This additional level of indirection * provides for high flexibility in the creation process. For instance one * implementation of this interface could be very simple and create a new * instance of the specified class for each invocation. A different * implementation could cache already created beans and ensure that always the * same bean of the given class will be returned - this would be an easy mean * for creating singleton objects. *

*

* The interface itself is quite simple. There is a single method for creating a * bean of a given class. All necessary parameters are obtained from an also * passed in {@link BeanDeclaration} object. It is also possible * (but optional) for a bean factory to declare the default class of the bean it * creates. Then it is not necessary to specify a bean class in the bean * declaration. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: BeanFactory.java 1208757 2011-11-30 20:38:15Z oheger $ */ public interface BeanFactory { /** * Returns a bean instance for the given class. The bean will be initialized * from the specified bean declaration object. It is up to a concrete * implementation how the bean will be created and initialized. * * @param beanClass the class for the bean * @param data the bean declaration object containing all data about the * bean to be created * @param param an additional parameter that may be passed by calling code; * it is up to a concrete implementation how this parameter is evaluated * @return the new bean instance (should not be null) * @throws Exception if an error occurs (the helper classes for creating * beans will catch this unspecific exception and wrap it in a configuration * exception) */ Object createBean(Class beanClass, BeanDeclaration data, Object param) throws Exception; /** * Returns the default bean class of this bean factory. If an implementation * here returns a non null value, bean declarations using this * factory do not need to provide the name of the bean class. In such a case * an instance of the default class will be created. * * @return the default class of this factory or null if there is * none */ Class getDefaultBeanClass(); } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.j100644 43722 12232154102 33376 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import java.beans.PropertyDescriptor; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.TreeSet; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.beanutils.PropertyUtils; import org.apache.commons.configuration.ConfigurationRuntimeException; import org.apache.commons.lang.ClassUtils; /** *

* A helper class for creating bean instances that are defined in configuration * files. *

*

* This class provides static utility methods related to bean creation * operations. These methods simplify such operations because a client need not * deal with all involved interfaces. Usually, if a bean declaration has already * been obtained, a single method call is necessary to create a new bean * instance. *

*

* This class also supports the registration of custom bean factories. * Implementations of the {@link BeanFactory} interface can be * registered under a symbolic name using the {@code registerBeanFactory()} * method. In the configuration file the name of the bean factory can be * specified in the bean declaration. Then this factory will be used to create * the bean. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: BeanHelper.java 1534393 2013-10-21 22:02:27Z henning $ */ public final class BeanHelper { /** Stores a map with the registered bean factories. */ private static final Map BEAN_FACTORIES = Collections .synchronizedMap(new HashMap()); /** * Stores the default bean factory, which will be used if no other factory * is provided. */ private static BeanFactory defaultBeanFactory = DefaultBeanFactory.INSTANCE; /** * Private constructor, so no instances can be created. */ private BeanHelper() { } /** * Register a bean factory under a symbolic name. This factory object can * then be specified in bean declarations with the effect that this factory * will be used to obtain an instance for the corresponding bean * declaration. * * @param name the name of the factory * @param factory the factory to be registered */ public static void registerBeanFactory(String name, BeanFactory factory) { if (name == null) { throw new IllegalArgumentException( "Name for bean factory must not be null!"); } if (factory == null) { throw new IllegalArgumentException("Bean factory must not be null!"); } BEAN_FACTORIES.put(name, factory); } /** * Deregisters the bean factory with the given name. After that this factory * cannot be used any longer. * * @param name the name of the factory to be deregistered * @return the factory that was registered under this name; null if * there was no such factory */ public static BeanFactory deregisterBeanFactory(String name) { return BEAN_FACTORIES.remove(name); } /** * Returns a set with the names of all currently registered bean factories. * * @return a set with the names of the registered bean factories */ public static Set registeredFactoryNames() { return BEAN_FACTORIES.keySet(); } /** * Returns the default bean factory. * * @return the default bean factory */ public static BeanFactory getDefaultBeanFactory() { return defaultBeanFactory; } /** * Sets the default bean factory. This factory will be used for all create * operations, for which no special factory is provided in the bean * declaration. * * @param factory the default bean factory (must not be null) */ public static void setDefaultBeanFactory(BeanFactory factory) { if (factory == null) { throw new IllegalArgumentException( "Default bean factory must not be null!"); } defaultBeanFactory = factory; } /** * Initializes the passed in bean. This method will obtain all the bean's * properties that are defined in the passed in bean declaration. These * properties will be set on the bean. If necessary, further beans will be * created recursively. * * @param bean the bean to be initialized * @param data the bean declaration * @throws ConfigurationRuntimeException if a property cannot be set */ public static void initBean(Object bean, BeanDeclaration data) throws ConfigurationRuntimeException { initBeanProperties(bean, data); Map nestedBeans = data.getNestedBeanDeclarations(); if (nestedBeans != null) { if (bean instanceof Collection) { // This is safe because the collection stores the values of the // nested beans. @SuppressWarnings("unchecked") Collection coll = (Collection) bean; if (nestedBeans.size() == 1) { Map.Entry e = nestedBeans.entrySet().iterator().next(); String propName = e.getKey(); Class defaultClass = getDefaultClass(bean, propName); if (e.getValue() instanceof List) { // This is safe, provided that the bean declaration is implemented // correctly. @SuppressWarnings("unchecked") List decls = (List) e.getValue(); for (BeanDeclaration decl : decls) { coll.add(createBean(decl, defaultClass)); } } else { BeanDeclaration decl = (BeanDeclaration) e.getValue(); coll.add(createBean(decl, defaultClass)); } } } else { for (Map.Entry e : nestedBeans.entrySet()) { String propName = e.getKey(); Class defaultClass = getDefaultClass(bean, propName); Object prop = e.getValue(); if (prop instanceof Collection) { Collection beanCollection = createPropertyCollection(propName, defaultClass); for (Object elemDef : (Collection) prop) { beanCollection .add(createBean((BeanDeclaration) elemDef)); } initProperty(bean, propName, beanCollection); } else { initProperty(bean, propName, createBean( (BeanDeclaration) e.getValue(), defaultClass)); } } } } } /** * Initializes the beans properties. * * @param bean the bean to be initialized * @param data the bean declaration * @throws ConfigurationRuntimeException if a property cannot be set */ public static void initBeanProperties(Object bean, BeanDeclaration data) throws ConfigurationRuntimeException { Map properties = data.getBeanProperties(); if (properties != null) { for (Map.Entry e : properties.entrySet()) { String propName = e.getKey(); initProperty(bean, propName, e.getValue()); } } } /** * Return the Class of the property if it can be determined. * @param bean The bean containing the property. * @param propName The name of the property. * @return The class associated with the property or null. */ private static Class getDefaultClass(Object bean, String propName) { try { PropertyDescriptor desc = PropertyUtils.getPropertyDescriptor(bean, propName); if (desc == null) { return null; } return desc.getPropertyType(); } catch (Exception ex) { return null; } } /** * Sets a property on the given bean using Common Beanutils. * * @param bean the bean * @param propName the name of the property * @param value the property's value * @throws ConfigurationRuntimeException if the property is not writeable or * an error occurred */ private static void initProperty(Object bean, String propName, Object value) throws ConfigurationRuntimeException { if (!PropertyUtils.isWriteable(bean, propName)) { throw new ConfigurationRuntimeException("Property " + propName + " cannot be set on " + bean.getClass().getName()); } try { BeanUtils.setProperty(bean, propName, value); } catch (IllegalAccessException iaex) { throw new ConfigurationRuntimeException(iaex); } catch (InvocationTargetException itex) { throw new ConfigurationRuntimeException(itex); } } /** * Creates a concrete collection instance to populate a property of type * collection. This method tries to guess an appropriate collection type. * Mostly the type of the property will be one of the collection interfaces * rather than a concrete class; so we have to create a concrete equivalent. * * @param propName the name of the collection property * @param propertyClass the type of the property * @return the newly created collection */ private static Collection createPropertyCollection(String propName, Class propertyClass) { Collection beanCollection = null; if (List.class.isAssignableFrom(propertyClass)) { beanCollection = new ArrayList(); } else if (Set.class.isAssignableFrom(propertyClass)) { beanCollection = new TreeSet(); } else { throw new UnsupportedOperationException( "Unable to handle collection of type : " + propertyClass.getName() + " for property " + propName); } return beanCollection; } /** * Set a property on the bean only if the property exists * * @param bean the bean * @param propName the name of the property * @param value the property's value * @throws ConfigurationRuntimeException if the property is not writeable or * an error occurred */ public static void setProperty(Object bean, String propName, Object value) { if (PropertyUtils.isWriteable(bean, propName)) { initProperty(bean, propName, value); } } /** * The main method for creating and initializing beans from a configuration. * This method will return an initialized instance of the bean class * specified in the passed in bean declaration. If this declaration does not * contain the class of the bean, the passed in default class will be used. * From the bean declaration the factory to be used for creating the bean is * queried. The declaration may here return null, then a default * factory is used. This factory is then invoked to perform the create * operation. * * @param data the bean declaration * @param defaultClass the default class to use * @param param an additional parameter that will be passed to the bean * factory; some factories may support parameters and behave different * depending on the value passed in here * @return the new bean * @throws ConfigurationRuntimeException if an error occurs */ public static Object createBean(BeanDeclaration data, Class defaultClass, Object param) throws ConfigurationRuntimeException { if (data == null) { throw new IllegalArgumentException( "Bean declaration must not be null!"); } BeanFactory factory = fetchBeanFactory(data); try { return factory.createBean(fetchBeanClass(data, defaultClass, factory), data, param); } catch (Exception ex) { throw new ConfigurationRuntimeException(ex); } } /** * Returns a bean instance for the specified declaration. This method is a * short cut for {@code createBean(data, null, null);}. * * @param data the bean declaration * @param defaultClass the class to be used when in the declaration no class * is specified * @return the new bean * @throws ConfigurationRuntimeException if an error occurs */ public static Object createBean(BeanDeclaration data, Class defaultClass) throws ConfigurationRuntimeException { return createBean(data, defaultClass, null); } /** * Returns a bean instance for the specified declaration. This method is a * short cut for {@code createBean(data, null);}. * * @param data the bean declaration * @return the new bean * @throws ConfigurationRuntimeException if an error occurs */ public static Object createBean(BeanDeclaration data) throws ConfigurationRuntimeException { return createBean(data, null); } /** * Returns a {@code java.lang.Class} object for the specified name. * Because class loading can be tricky in some environments the code for * retrieving a class by its name was extracted into this helper method. So * if changes are necessary, they can be made at a single place. * * @param name the name of the class to be loaded * @param callingClass the calling class * @return the class object for the specified name * @throws ClassNotFoundException if the class cannot be loaded */ static Class loadClass(String name, Class callingClass) throws ClassNotFoundException { return ClassUtils.getClass(name); } /** * Determines the class of the bean to be created. If the bean declaration * contains a class name, this class is used. Otherwise it is checked * whether a default class is provided. If this is not the case, the * factory's default class is used. If this class is undefined, too, an * exception is thrown. * * @param data the bean declaration * @param defaultClass the default class * @param factory the bean factory to use * @return the class of the bean to be created * @throws ConfigurationRuntimeException if the class cannot be determined */ private static Class fetchBeanClass(BeanDeclaration data, Class defaultClass, BeanFactory factory) throws ConfigurationRuntimeException { String clsName = data.getBeanClassName(); if (clsName != null) { try { return loadClass(clsName, factory.getClass()); } catch (ClassNotFoundException cex) { throw new ConfigurationRuntimeException(cex); } } if (defaultClass != null) { return defaultClass; } Class clazz = factory.getDefaultBeanClass(); if (clazz == null) { throw new ConfigurationRuntimeException( "Bean class is not specified!"); } return clazz; } /** * Obtains the bean factory to use for creating the specified bean. This * method will check whether a factory is specified in the bean declaration. * If this is not the case, the default bean factory will be used. * * @param data the bean declaration * @return the bean factory to use * @throws ConfigurationRuntimeException if the factory cannot be determined */ private static BeanFactory fetchBeanFactory(BeanDeclaration data) throws ConfigurationRuntimeException { String factoryName = data.getBeanFactoryName(); if (factoryName != null) { BeanFactory factory = BEAN_FACTORIES.get(factoryName); if (factory == null) { throw new ConfigurationRuntimeException( "Unknown bean factory: " + factoryName); } else { return factory; } } else { return getDefaultBeanFactory(); } } } ././@LongLink100644 0 0 163 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/ConfigurationDynaBean.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/Configuratio100644 17730 12232154102 33572 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import java.lang.reflect.Array; import java.util.Collection; import java.util.List; import org.apache.commons.beanutils.DynaBean; import org.apache.commons.beanutils.DynaClass; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationMap; import org.apache.commons.configuration.SubsetConfiguration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * The ConfigurationDynaBean dynamically reads and writes * configurations properties from a wrapped configuration-collection * {@link org.apache.commons.configuration.Configuration} instance. It also * implements a {@link java.util.Map} interface so that it can be used in * JSP 2.0 Expression Language expressions. * *

The {@code ConfigurationDynaBean} maps nested and mapped properties * to the appropriate {@code Configuration} subset using the * {@link org.apache.commons.configuration.Configuration#subset} * method. Similarly, indexed properties reference lists of configuration * properties using the * {@link org.apache.commons.configuration.Configuration#getList(String)} * method. Setting an indexed property is supported, too.

* *

Note: Some of the methods expect that a dot (".") is used as * property delimiter for the wrapped configuration. This is true for most of * the default configurations. Hierarchical configurations, for which a specific * expression engine is set, may cause problems.

* * @author Ricardo Gladwell * @version $Id: ConfigurationDynaBean.java 1366932 2012-07-29 20:06:31Z oheger $ * @since 1.0-rc1 */ public class ConfigurationDynaBean extends ConfigurationMap implements DynaBean { /** Constant for the property delimiter.*/ private static final String PROPERTY_DELIMITER = "."; /** The logger.*/ private static final Log LOG = LogFactory.getLog(ConfigurationDynaBean.class); /** * Creates a new instance of {@code ConfigurationDynaBean} and sets * the configuration this bean is associated with. * * @param configuration the configuration */ public ConfigurationDynaBean(Configuration configuration) { super(configuration); if (LOG.isTraceEnabled()) { LOG.trace("ConfigurationDynaBean(" + configuration + ")"); } } public void set(String name, Object value) { if (LOG.isTraceEnabled()) { LOG.trace("set(" + name + "," + value + ")"); } if (value == null) { throw new NullPointerException("Error trying to set property to null."); } if (value instanceof Collection) { Collection collection = (Collection) value; for (Object v : collection) { getConfiguration().addProperty(name, v); } } else if (value.getClass().isArray()) { int length = Array.getLength(value); for (int i = 0; i < length; i++) { getConfiguration().addProperty(name, Array.get(value, i)); } } else { getConfiguration().setProperty(name, value); } } public Object get(String name) { if (LOG.isTraceEnabled()) { LOG.trace("get(" + name + ")"); } // get configuration property Object result = getConfiguration().getProperty(name); if (result == null) { // otherwise attempt to create bean from configuration subset Configuration subset = new SubsetConfiguration(getConfiguration(), name, PROPERTY_DELIMITER); if (!subset.isEmpty()) { result = new ConfigurationDynaBean(subset); } } if (LOG.isDebugEnabled()) { LOG.debug(name + "=[" + result + "]"); } if (result == null) { throw new IllegalArgumentException("Property '" + name + "' does not exist."); } return result; } public boolean contains(String name, String key) { Configuration subset = getConfiguration().subset(name); if (subset == null) { throw new IllegalArgumentException("Mapped property '" + name + "' does not exist."); } return subset.containsKey(key); } public Object get(String name, int index) { if (!checkIndexedProperty(name)) { throw new IllegalArgumentException("Property '" + name + "' is not indexed."); } List list = getConfiguration().getList(name); return list.get(index); } public Object get(String name, String key) { Configuration subset = getConfiguration().subset(name); if (subset == null) { throw new IllegalArgumentException("Mapped property '" + name + "' does not exist."); } return subset.getProperty(key); } public DynaClass getDynaClass() { return new ConfigurationDynaClass(getConfiguration()); } public void remove(String name, String key) { Configuration subset = new SubsetConfiguration(getConfiguration(), name, PROPERTY_DELIMITER); subset.setProperty(key, null); } public void set(String name, int index, Object value) { if (!checkIndexedProperty(name) && index > 0) { throw new IllegalArgumentException("Property '" + name + "' is not indexed."); } Object property = getConfiguration().getProperty(name); if (property instanceof List) { // This is safe because multiple values of a configuration property // are always stored as lists of type Object. @SuppressWarnings("unchecked") List list = (List) property; list.set(index, value); getConfiguration().setProperty(name, list); } else if (property.getClass().isArray()) { Array.set(property, index, value); } else if (index == 0) { getConfiguration().setProperty(name, value); } } public void set(String name, String key, Object value) { getConfiguration().setProperty(name + "." + key, value); } /** * Tests whether the given name references an indexed property. This * implementation tests for properties of type list or array. If the * property does not exist, an exception is thrown. * * @param name the name of the property to check * @return a flag whether this is an indexed property * @throws IllegalArgumentException if the property does not exist */ private boolean checkIndexedProperty(String name) { Object property = getConfiguration().getProperty(name); if (property == null) { throw new IllegalArgumentException("Property '" + name + "' does not exist."); } return (property instanceof List) || property.getClass().isArray(); } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/ConfigurationDynaClass.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/Configuratio100644 11242 12232154102 33562 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.beanutils.DynaBean; import org.apache.commons.beanutils.DynaClass; import org.apache.commons.beanutils.DynaProperty; import org.apache.commons.configuration.Configuration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * The ConfigurationDynaClass dynamically determines properties for * a {@code ConfigurationDynaBean} from a wrapped configuration-collection * {@link org.apache.commons.configuration.Configuration} instance. * * @author Ricardo Gladwell * @version $Id: ConfigurationDynaClass.java 1366932 2012-07-29 20:06:31Z oheger $ * @since 1.0-rc1 */ public class ConfigurationDynaClass implements DynaClass { /** The logger.*/ private static final Log LOG = LogFactory.getLog(ConfigurationDynaClass.class); /** Stores the associated configuration.*/ private final Configuration configuration; /** * Construct an instance of a {@code ConfigurationDynaClass} * wrapping the specified {@code Configuration} instance. * @param configuration {@code Configuration} instance. */ public ConfigurationDynaClass(Configuration configuration) { super(); if (LOG.isTraceEnabled()) { LOG.trace("ConfigurationDynaClass(" + configuration + ")"); } this.configuration = configuration; } public DynaProperty getDynaProperty(String name) { if (LOG.isTraceEnabled()) { LOG.trace("getDynaProperty(" + name + ")"); } if (name == null) { throw new IllegalArgumentException("Property name must not be null!"); } Object value = configuration.getProperty(name); if (value == null) { return null; } else { Class type = value.getClass(); if (type == Byte.class) { type = Byte.TYPE; } if (type == Character.class) { type = Character.TYPE; } else if (type == Boolean.class) { type = Boolean.TYPE; } else if (type == Double.class) { type = Double.TYPE; } else if (type == Float.class) { type = Float.TYPE; } else if (type == Integer.class) { type = Integer.TYPE; } else if (type == Long.class) { type = Long.TYPE; } else if (type == Short.class) { type = Short.TYPE; } return new DynaProperty(name, type); } } public DynaProperty[] getDynaProperties() { if (LOG.isTraceEnabled()) { LOG.trace("getDynaProperties()"); } Iterator keys = configuration.getKeys(); List properties = new ArrayList(); while (keys.hasNext()) { String key = keys.next(); DynaProperty property = getDynaProperty(key); properties.add(property); } DynaProperty[] propertyArray = new DynaProperty[properties.size()]; properties.toArray(propertyArray); if (LOG.isDebugEnabled()) { LOG.debug("Found " + properties.size() + " properties."); } return propertyArray; } public String getName() { return ConfigurationDynaBean.class.getName(); } public DynaBean newInstance() throws IllegalAccessException, InstantiationException { return new ConfigurationDynaBean(configuration); } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanFactory.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanF100644 7750 12232154102 33402 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; /** *

* The default implementation of the {@code BeanFactory} interface. *

*

* This class creates beans of arbitrary types using reflection. Each time the * {@code createBean()} method is invoked, a new bean instance is * created. A default bean class is not supported. *

*

* An instance of this factory class will be set as the default bean factory for * the {@link BeanHelper} class. This means that if not bean * factory is specified in a {@link BeanDeclaration}, this * default instance will be used. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: DefaultBeanFactory.java 1208758 2011-11-30 20:38:59Z oheger $ */ public class DefaultBeanFactory implements BeanFactory { /** Stores the default instance of this class. */ public static final DefaultBeanFactory INSTANCE = new DefaultBeanFactory(); /** * Creates a new bean instance. This implementation delegates to the * protected methods {@code createBeanInstance()} and * {@code initBeanInstance()} for creating and initializing the bean. * This makes it easier for derived classes that need to change specific * functionality of the base class. * * @param beanClass the class of the bean, from which an instance is to be * created * @param data the bean declaration object * @param parameter an additional parameter (ignored by this implementation) * @return the new bean instance * @throws Exception if an error occurs */ public Object createBean(Class beanClass, BeanDeclaration data, Object parameter) throws Exception { Object result = createBeanInstance(beanClass, data); initBeanInstance(result, data); return result; } /** * Returns the default bean class used by this factory. This is always * null for this implementation. * * @return the default bean class */ public Class getDefaultBeanClass() { return null; } /** * Creates the bean instance. This method is called by * {@code createBean()}. It uses reflection to create a new instance * of the specified class. * * @param beanClass the class of the bean to be created * @param data the bean declaration * @return the new bean instance * @throws Exception if an error occurs */ protected Object createBeanInstance(Class beanClass, BeanDeclaration data) throws Exception { return beanClass.newInstance(); } /** * Initializes the newly created bean instance. This method is called by * {@code createBean()}. It calls the * {@link BeanHelper#initBean(Object, BeanDeclaration) initBean()} * of {@link BeanHelper} for performing the initialization. * * @param bean the newly created bean instance * @param data the bean declaration object * @throws Exception if an error occurs */ protected void initBeanInstance(Object bean, BeanDeclaration data) throws Exception { BeanHelper.initBean(bean, data); } } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/package.htmlcommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/package.html100644 2433 12232154102 33451 0ustarhenningstaff 0 0

In this package a Configuration implementation can be found that implements the DynaBean interface. It allows to access or modify a configuration using the classes from the Commons Beanutils package. There are also classes for declaring beans in configuration files, from which then instances can be created.

$Id: package.html 439648 2006-09-02 20:42:10Z oheger $

././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/XMLBeanDeclaration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/XMLBeanDecla100644 37233 12232154102 33320 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.configuration.ConfigurationRuntimeException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.PropertyConverter; import org.apache.commons.configuration.SubnodeConfiguration; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; /** *

* An implementation of the {@code BeanDeclaration} interface that is * suitable for XML configuration files. *

*

* This class defines the standard layout of a bean declaration in an XML * configuration file. Such a declaration must look like the following example * fragment: *

*

* *

 *   ...
 *   <personBean config-class="my.model.PersonBean"
 *       lastName="Doe" firstName="John">
 *       <address config-class="my.model.AddressBean"
 *           street="21st street 11" zip="1234"
 *           city="TestCity"/>
 *   </personBean>
 * 
* *

*

* The bean declaration can be contained in an arbitrary element. Here it is the * {@code personBean} element. In the attributes of this element * there can occur some reserved attributes, which have the following meaning: *

*
{@code config-class}
*
Here the full qualified name of the bean's class can be specified. An * instance of this class will be created. If this attribute is not specified, * the bean class must be provided in another way, e.g. as the * {@code defaultClass} passed to the {@code BeanHelper} class.
*
{@code config-factory}
*
This attribute can contain the name of the * {@link BeanFactory} that should be used for creating the bean. * If it is defined, a factory with this name must have been registered at the * {@code BeanHelper} class. If this attribute is missing, the default * bean factory will be used.
*
{@code config-factoryParam}
*
With this attribute a parameter can be specified that will be passed to * the bean factory. This may be useful for custom bean factories.
*
*

*

* All further attributes starting with the {@code config-} prefix are * considered as meta data and will be ignored. All other attributes are treated * as properties of the bean to be created, i.e. corresponding setter methods of * the bean will be invoked with the values specified here. *

*

* If the bean to be created has also some complex properties (which are itself * beans), their values cannot be initialized from attributes. For this purpose * nested elements can be used. The example listing shows how an address bean * can be initialized. This is done in a nested element whose name must match * the name of a property of the enclosing bean declaration. The format of this * nested element is exactly the same as for the bean declaration itself, i.e. * it can have attributes defining meta data or bean properties and even further * nested elements for complex bean properties. *

*

* A {@code XMLBeanDeclaration} object is usually created from a * {@code HierarchicalConfiguration}. From this it will derive a * {@code SubnodeConfiguration}, which is used to access the needed * properties. This subnode configuration can be obtained using the * {@link #getConfiguration()} method. All of its properties can * be accessed in the usual way. To ensure that the property keys used by this * class are understood by the configuration, the default expression engine will * be set. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: XMLBeanDeclaration.java 1301959 2012-03-17 16:43:18Z oheger $ */ public class XMLBeanDeclaration implements BeanDeclaration { /** Constant for the prefix of reserved attributes. */ public static final String RESERVED_PREFIX = "config-"; /** Constant for the prefix for reserved attributes.*/ public static final String ATTR_PREFIX = "[@" + RESERVED_PREFIX; /** Constant for the bean class attribute. */ public static final String ATTR_BEAN_CLASS = ATTR_PREFIX + "class]"; /** Constant for the bean factory attribute. */ public static final String ATTR_BEAN_FACTORY = ATTR_PREFIX + "factory]"; /** Constant for the bean factory parameter attribute. */ public static final String ATTR_FACTORY_PARAM = ATTR_PREFIX + "factoryParam]"; /** Stores the associated configuration. */ private final SubnodeConfiguration configuration; /** Stores the configuration node that contains the bean declaration. */ private final ConfigurationNode node; /** * Creates a new instance of {@code XMLBeanDeclaration} and * initializes it from the given configuration. The passed in key points to * the bean declaration. * * @param config the configuration * @param key the key to the bean declaration (this key must point to * exactly one bean declaration or a {@code IllegalArgumentException} * exception will be thrown) */ public XMLBeanDeclaration(HierarchicalConfiguration config, String key) { this(config, key, false); } /** * Creates a new instance of {@code XMLBeanDeclaration} and * initializes it from the given configuration. The passed in key points to * the bean declaration. If the key does not exist and the boolean argument * is true, the declaration is initialized with an empty * configuration. It is possible to create objects from such an empty * declaration if a default class is provided. If the key on the other hand * has multiple values or is undefined and the boolean argument is false, * a {@code IllegalArgumentException} exception will be thrown. * * @param config the configuration * @param key the key to the bean declaration * @param optional a flag whether this declaration is optional; if set to * true, no exception will be thrown if the passed in key is * undefined */ public XMLBeanDeclaration(HierarchicalConfiguration config, String key, boolean optional) { if (config == null) { throw new IllegalArgumentException( "Configuration must not be null!"); } SubnodeConfiguration tmpconfiguration = null; ConfigurationNode tmpnode = null; try { tmpconfiguration = config.configurationAt(key); tmpnode = tmpconfiguration.getRootNode(); } catch (IllegalArgumentException iex) { // If we reach this block, the key does not have exactly one value if (!optional || config.getMaxIndex(key) > 0) { throw iex; } tmpconfiguration = config.configurationAt(null); tmpnode = new DefaultConfigurationNode(); } this.node = tmpnode; this.configuration = tmpconfiguration; initSubnodeConfiguration(getConfiguration()); } /** * Creates a new instance of {@code XMLBeanDeclaration} and * initializes it from the given configuration. The configuration's root * node must contain the bean declaration. * * @param config the configuration with the bean declaration */ public XMLBeanDeclaration(HierarchicalConfiguration config) { this(config, (String) null); } /** * Creates a new instance of {@code XMLBeanDeclaration} and * initializes it with the configuration node that contains the bean * declaration. * * @param config the configuration * @param node the node with the bean declaration. */ public XMLBeanDeclaration(SubnodeConfiguration config, ConfigurationNode node) { if (config == null) { throw new IllegalArgumentException( "Configuration must not be null!"); } if (node == null) { throw new IllegalArgumentException("Node must not be null!"); } this.node = node; configuration = config; initSubnodeConfiguration(config); } /** * Returns the configuration object this bean declaration is based on. * * @return the associated configuration */ public SubnodeConfiguration getConfiguration() { return configuration; } /** * Returns the node that contains the bean declaration. * * @return the configuration node this bean declaration is based on */ public ConfigurationNode getNode() { return node; } /** * Returns the name of the bean factory. This information is fetched from * the {@code config-factory} attribute. * * @return the name of the bean factory */ public String getBeanFactoryName() { return getConfiguration().getString(ATTR_BEAN_FACTORY); } /** * Returns a parameter for the bean factory. This information is fetched * from the {@code config-factoryParam} attribute. * * @return the parameter for the bean factory */ public Object getBeanFactoryParameter() { return getConfiguration().getProperty(ATTR_FACTORY_PARAM); } /** * Returns the name of the class of the bean to be created. This information * is obtained from the {@code config-class} attribute. * * @return the name of the bean's class */ public String getBeanClassName() { return getConfiguration().getString(ATTR_BEAN_CLASS); } /** * Returns a map with the bean's (simple) properties. The properties are * collected from all attribute nodes, which are not reserved. * * @return a map with the bean's properties */ public Map getBeanProperties() { Map props = new HashMap(); for (ConfigurationNode attr : getNode().getAttributes()) { if (!isReservedNode(attr)) { props.put(attr.getName(), interpolate(attr .getValue())); } } return props; } /** * Returns a map with bean declarations for the complex properties of the * bean to be created. These declarations are obtained from the child nodes * of this declaration's root node. * * @return a map with bean declarations for complex properties */ public Map getNestedBeanDeclarations() { Map nested = new HashMap(); for (ConfigurationNode child : getNode().getChildren()) { if (!isReservedNode(child)) { if (nested.containsKey(child.getName())) { Object obj = nested.get(child.getName()); List list; if (obj instanceof List) { // Safe because we created the lists ourselves. @SuppressWarnings("unchecked") List tmpList = (List) obj; list = tmpList; } else { list = new ArrayList(); list.add((BeanDeclaration) obj); nested.put(child.getName(), list); } list.add(createBeanDeclaration(child)); } else { nested.put(child.getName(), createBeanDeclaration(child)); } } } return nested; } /** * Performs interpolation for the specified value. This implementation will * interpolate against the current subnode configuration's parent. If sub * classes need a different interpolation mechanism, they should override * this method. * * @param value the value that is to be interpolated * @return the interpolated value */ protected Object interpolate(Object value) { return PropertyConverter.interpolate(value, getConfiguration() .getParent()); } /** * Checks if the specified node is reserved and thus should be ignored. This * method is called when the maps for the bean's properties and complex * properties are collected. It checks whether the given node is an * attribute node and if its name starts with the reserved prefix. * * @param nd the node to be checked * @return a flag whether this node is reserved (and does not point to a * property) */ protected boolean isReservedNode(ConfigurationNode nd) { return nd.isAttribute() && (nd.getName() == null || nd.getName().startsWith( RESERVED_PREFIX)); } /** * Creates a new {@code BeanDeclaration} for a child node of the * current configuration node. This method is called by * {@code getNestedBeanDeclarations()} for all complex sub properties * detected by this method. Derived classes can hook in if they need a * specific initialization. This base implementation creates a * {@code XMLBeanDeclaration} that is properly initialized from the * passed in node. * * @param node the child node, for which a {@code BeanDeclaration} is * to be created * @return the {@code BeanDeclaration} for this child node * @since 1.6 */ protected BeanDeclaration createBeanDeclaration(ConfigurationNode node) { List list = getConfiguration().configurationsAt(node.getName()); if (list.size() == 1) { return new XMLBeanDeclaration((SubnodeConfiguration) list.get(0), node); } else { Iterator iter = list.iterator(); while (iter.hasNext()) { SubnodeConfiguration config = (SubnodeConfiguration) iter.next(); if (config.getRootNode().equals(node)) { return new XMLBeanDeclaration(config, node); } } throw new ConfigurationRuntimeException("Unable to match node for " + node.getName()); } } /** * Initializes the internally managed subnode configuration. This method * will set some default values for some properties. * * @param conf the configuration to initialize */ private void initSubnodeConfiguration(SubnodeConfiguration conf) { conf.setThrowExceptionOnMissing(false); conf.setExpressionEngine(null); } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/CombinedConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/CombinedConfiguration.100644 102135 12232154103 33514 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.ByteArrayOutputStream; import java.io.PrintStream; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationKey; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.configuration.tree.DefaultExpressionEngine; import org.apache.commons.configuration.tree.ExpressionEngine; import org.apache.commons.configuration.tree.NodeCombiner; import org.apache.commons.configuration.tree.TreeUtils; import org.apache.commons.configuration.tree.UnionCombiner; import org.apache.commons.configuration.tree.ViewNode; /** *

* A hierarchical composite configuration class. *

*

* This class maintains a list of configuration objects, which can be added * using the divers {@code addConfiguration()} methods. After that the * configurations can be accessed either by name (if one was provided when the * configuration was added) or by index. For the whole set of managed * configurations a logical node structure is constructed. For this purpose a * {@link org.apache.commons.configuration.tree.NodeCombiner NodeCombiner} * object can be set. This makes it possible to specify different algorithms for * the combination process. *

*

* The big advantage of this class is that it creates a truly hierarchical * structure of all the properties stored in the contained configurations - even * if some of them are no hierarchical configurations per se. So all enhanced * features provided by a hierarchical configuration (e.g. choosing an * expression engine) are applicable. *

*

* The class works by registering itself as an event listener at all added * configurations. So it gets notified whenever one of these configurations is * changed and can invalidate its internal node structure. The next time a * property is accessed the node structure will be re-constructed using the * current state of the managed configurations. Note that, depending on the used * {@code NodeCombiner}, this may be a complex operation. *

*

* Because of the way a {@code CombinedConfiguration} is working it has * more or less view character: it provides a logic view on the configurations * it contains. In this constellation not all methods defined for hierarchical * configurations - especially methods that update the stored properties - can * be implemented in a consistent manner. Using such methods (like * {@code addProperty()}, or {@code clearProperty()} on a * {@code CombinedConfiguration} is not strictly forbidden, however, * depending on the current {@link NodeCombiner} and the involved * properties, the results may be different than expected. Some examples may * illustrate this: *

*

*

    *
  • Imagine a {@code CombinedConfiguration} cc containing * two child configurations with the following content: *
    *
    user.properties
    *
    * *
     * gui.background = blue
     * gui.position = (10, 10, 400, 200)
     * 
    * *
    *
    default.properties
    *
    * *
     * gui.background = black
     * gui.foreground = white
     * home.dir = /data
     * 
    * *
    *
    * As a {@code NodeCombiner} a * {@link org.apache.commons.configuration.tree.OverrideCombiner OverrideCombiner} * is used. This combiner will ensure that defined user settings take precedence * over the default values. If the resulting {@code CombinedConfiguration} * is queried for the background color, {@code blue} will be returned * because this value is defined in {@code user.properties}. Now * consider what happens if the key {@code gui.background} is removed * from the {@code CombinedConfiguration}: * *
    cc.clearProperty("gui.background");
    * * Will a {@code cc.containsKey("gui.background")} now return false? * No, it won't! The {@code clearProperty()} operation is executed on the * node set of the combined configuration, which was constructed from the nodes * of the two child configurations. It causes the value of the * background node to be cleared, which is also part of the first * child configuration. This modification of one of its child configurations * causes the {@code CombinedConfiguration} to be re-constructed. This * time the {@code OverrideCombiner} cannot find a * {@code gui.background} property in the first child configuration, but * it finds one in the second, and adds it to the resulting combined * configuration. So the property is still present (with a different value now).
  • *
  • {@code addProperty()} can also be problematic: Most node * combiners use special view nodes for linking parts of the original * configurations' data together. If new properties are added to such a special * node, they do not belong to any of the managed configurations and thus hang * in the air. Using the same configurations as in the last example, the * statement * *
     * addProperty("database.user", "scott");
     * 
    * * would cause such a hanging property. If now one of the child configurations * is changed and the {@code CombinedConfiguration} is re-constructed, * this property will disappear! (Add operations are not problematic if they * result in a child configuration being updated. For instance an * {@code addProperty("home.url", "localhost");} will alter the second * child configuration - because the prefix home is here already * present; when the {@code CombinedConfiguration} is re-constructed, * this change is taken into account.)
  • *
* Because of such problems it is recommended to perform updates only on the * managed child configurations. *

*

* Whenever the node structure of a {@code CombinedConfiguration} becomes * invalid (either because one of the contained configurations was modified or * because the {@code invalidate()} method was directly called) an event * is generated. So this can be detected by interested event listeners. This * also makes it possible to add a combined configuration into another one. *

*

* Implementation note: Adding and removing configurations to and from a * combined configuration is not thread-safe. If a combined configuration is * manipulated by multiple threads, the developer has to take care about * properly synchronization. *

* * @author Commons * Configuration team * @since 1.3 * @version $Id: CombinedConfiguration.java 1234985 2012-01-23 21:09:09Z oheger $ */ public class CombinedConfiguration extends HierarchicalReloadableConfiguration implements ConfigurationListener, Cloneable { /** * Constant for the invalidate event that is fired when the internal node * structure becomes invalid. */ public static final int EVENT_COMBINED_INVALIDATE = 40; /** * The serial version ID. */ private static final long serialVersionUID = 8338574525528692307L; /** Constant for the expression engine for parsing the at path. */ private static final DefaultExpressionEngine AT_ENGINE = new DefaultExpressionEngine(); /** Constant for the default node combiner. */ private static final NodeCombiner DEFAULT_COMBINER = new UnionCombiner(); /** Constant for the name of the property used for the reload check.*/ private static final String PROP_RELOAD_CHECK = "CombinedConfigurationReloadCheck"; /** Stores the combiner. */ private NodeCombiner nodeCombiner; /** Stores the combined root node. */ private volatile ConfigurationNode combinedRoot; /** Stores a list with the contained configurations. */ private List configurations; /** Stores a map with the named configurations. */ private Map namedConfigurations; /** The default behavior is to ignore exceptions that occur during reload */ private boolean ignoreReloadExceptions = true; /** Set to true when the backing file has changed */ private boolean reloadRequired; /** * An expression engine used for converting child configurations to * hierarchical ones. */ private ExpressionEngine conversionExpressionEngine; /** A flag whether an enhanced reload check is to be performed.*/ private boolean forceReloadCheck; /** * Creates a new instance of {@code CombinedConfiguration} and * initializes the combiner to be used. * * @param comb the node combiner (can be null, then a union combiner * is used as default) */ public CombinedConfiguration(NodeCombiner comb) { setNodeCombiner((comb != null) ? comb : DEFAULT_COMBINER); clear(); } public CombinedConfiguration(NodeCombiner comb, Lock lock) { super(lock); setNodeCombiner((comb != null) ? comb : DEFAULT_COMBINER); clear(); } public CombinedConfiguration(Lock lock) { this(null, lock); } /** * Creates a new instance of {@code CombinedConfiguration} that uses * a union combiner. * * @see org.apache.commons.configuration.tree.UnionCombiner */ public CombinedConfiguration() { this(null, null); } /** * Returns the node combiner that is used for creating the combined node * structure. * * @return the node combiner */ public NodeCombiner getNodeCombiner() { return nodeCombiner; } /** * Sets the node combiner. This object will be used when the combined node * structure is to be constructed. It must not be null, otherwise an * {@code IllegalArgumentException} exception is thrown. Changing the * node combiner causes an invalidation of this combined configuration, so * that the new combiner immediately takes effect. * * @param nodeCombiner the node combiner */ public void setNodeCombiner(NodeCombiner nodeCombiner) { if (nodeCombiner == null) { throw new IllegalArgumentException( "Node combiner must not be null!"); } this.nodeCombiner = nodeCombiner; invalidate(); } /** * Returns a flag whether an enhanced reload check must be performed. * * @return the force reload check flag * @since 1.4 */ public boolean isForceReloadCheck() { return forceReloadCheck; } /** * Sets the force reload check flag. If this flag is set, each property * access on this configuration will cause a reload check on the contained * configurations. This is a workaround for a problem with some reload * implementations that only check if a reload is required when they are * triggered. Per default this mode is disabled. If the force reload check * flag is set to true, accessing properties will be less * efficient, but reloads on contained configurations will be detected. * * @param forceReloadCheck the value of the flag * @since 1.4 */ public void setForceReloadCheck(boolean forceReloadCheck) { this.forceReloadCheck = forceReloadCheck; } /** * Returns the {@code ExpressionEngine} for converting flat child * configurations to hierarchical ones. * * @return the conversion expression engine * @since 1.6 */ public ExpressionEngine getConversionExpressionEngine() { return conversionExpressionEngine; } /** * Sets the {@code ExpressionEngine} for converting flat child * configurations to hierarchical ones. When constructing the root node for * this combined configuration the properties of all child configurations * must be combined to a single hierarchical node structure. In this * process, non hierarchical configurations are converted to hierarchical * ones first. This can be problematic if a child configuration contains * keys that are no compatible with the default expression engine used by * hierarchical configurations. Therefore it is possible to specify a * specific expression engine to be used for this purpose. * * @param conversionExpressionEngine the conversion expression engine * @see ConfigurationUtils#convertToHierarchical(Configuration, ExpressionEngine) * @since 1.6 */ public void setConversionExpressionEngine( ExpressionEngine conversionExpressionEngine) { this.conversionExpressionEngine = conversionExpressionEngine; } /** * Retrieves the value of the ignoreReloadExceptions flag. * @return true if exceptions are ignored, false otherwise. */ public boolean isIgnoreReloadExceptions() { return ignoreReloadExceptions; } /** * If set to true then exceptions that occur during reloading will be * ignored. If false then the exceptions will be allowed to be thrown * back to the caller. * @param ignoreReloadExceptions true if exceptions should be ignored. */ public void setIgnoreReloadExceptions(boolean ignoreReloadExceptions) { this.ignoreReloadExceptions = ignoreReloadExceptions; } /** * Adds a new configuration to this combined configuration. It is possible * (but not mandatory) to give the new configuration a name. This name must * be unique, otherwise a {@code ConfigurationRuntimeException} will * be thrown. With the optional {@code at} argument you can specify * where in the resulting node structure the content of the added * configuration should appear. This is a string that uses dots as property * delimiters (independent on the current expression engine). For instance * if you pass in the string {@code "database.tables"}, * all properties of the added configuration will occur in this branch. * * @param config the configuration to add (must not be null) * @param name the name of this configuration (can be null) * @param at the position of this configuration in the combined tree (can be * null) */ public void addConfiguration(AbstractConfiguration config, String name, String at) { if (config == null) { throw new IllegalArgumentException( "Added configuration must not be null!"); } if (name != null && namedConfigurations.containsKey(name)) { throw new ConfigurationRuntimeException( "A configuration with the name '" + name + "' already exists in this combined configuration!"); } ConfigData cd = new ConfigData(config, name, at); if (getLogger().isDebugEnabled()) { getLogger().debug("Adding configuration " + config + " with name " + name); } configurations.add(cd); if (name != null) { namedConfigurations.put(name, config); } config.addConfigurationListener(this); invalidate(); } /** * Adds a new configuration to this combined configuration with an optional * name. The new configuration's properties will be added under the root of * the combined node structure. * * @param config the configuration to add (must not be null) * @param name the name of this configuration (can be null) */ public void addConfiguration(AbstractConfiguration config, String name) { addConfiguration(config, name, null); } /** * Adds a new configuration to this combined configuration. The new * configuration is not given a name. Its properties will be added under the * root of the combined node structure. * * @param config the configuration to add (must not be null) */ public void addConfiguration(AbstractConfiguration config) { addConfiguration(config, null, null); } /** * Returns the number of configurations that are contained in this combined * configuration. * * @return the number of contained configurations */ public int getNumberOfConfigurations() { return configurations.size(); } /** * Returns the configuration at the specified index. The contained * configurations are numbered in the order they were added to this combined * configuration. The index of the first configuration is 0. * * @param index the index * @return the configuration at this index */ public Configuration getConfiguration(int index) { ConfigData cd = configurations.get(index); return cd.getConfiguration(); } /** * Returns the configuration with the given name. This can be null * if no such configuration exists. * * @param name the name of the configuration * @return the configuration with this name */ public Configuration getConfiguration(String name) { return namedConfigurations.get(name); } /** * Returns a List of all the configurations that have been added. * @return A List of all the configurations. * @since 1.7 */ public List getConfigurations() { List list = new ArrayList(configurations.size()); for (ConfigData cd : configurations) { list.add(cd.getConfiguration()); } return list; } /** * Returns a List of the names of all the configurations that have been * added in the order they were added. A NULL value will be present in * the list for each configuration that was added without a name. * @return A List of all the configuration names. * @since 1.7 */ public List getConfigurationNameList() { List list = new ArrayList(configurations.size()); for (ConfigData cd : configurations) { list.add(cd.getName()); } return list; } /** * Removes the specified configuration from this combined configuration. * * @param config the configuration to be removed * @return a flag whether this configuration was found and could be removed */ public boolean removeConfiguration(Configuration config) { for (int index = 0; index < getNumberOfConfigurations(); index++) { if (configurations.get(index).getConfiguration() == config) { removeConfigurationAt(index); return true; } } return false; } /** * Removes the configuration at the specified index. * * @param index the index * @return the removed configuration */ public Configuration removeConfigurationAt(int index) { ConfigData cd = configurations.remove(index); if (cd.getName() != null) { namedConfigurations.remove(cd.getName()); } cd.getConfiguration().removeConfigurationListener(this); invalidate(); return cd.getConfiguration(); } /** * Removes the configuration with the specified name. * * @param name the name of the configuration to be removed * @return the removed configuration (null if this configuration * was not found) */ public Configuration removeConfiguration(String name) { Configuration conf = getConfiguration(name); if (conf != null) { removeConfiguration(conf); } return conf; } /** * Returns a set with the names of all configurations contained in this * combined configuration. Of course here are only these configurations * listed, for which a name was specified when they were added. * * @return a set with the names of the contained configurations (never * null) */ public Set getConfigurationNames() { return namedConfigurations.keySet(); } /** * Invalidates this combined configuration. This means that the next time a * property is accessed the combined node structure must be re-constructed. * Invalidation of a combined configuration also means that an event of type * {@code EVENT_COMBINED_INVALIDATE} is fired. Note that while other * events most times appear twice (once before and once after an update), * this event is only fired once (after update). */ public void invalidate() { reloadRequired = true; fireEvent(EVENT_COMBINED_INVALIDATE, null, null, false); } /** * Event listener call back for configuration update events. This method is * called whenever one of the contained configurations was modified. It * invalidates this combined configuration. * * @param event the update event */ public void configurationChanged(ConfigurationEvent event) { if (event.getType() == AbstractFileConfiguration.EVENT_CONFIG_CHANGED) { fireEvent(event.getType(), event.getPropertyName(), event.getPropertyValue(), event.isBeforeUpdate()); } else if (!event.isBeforeUpdate()) { invalidate(); } } /** * Returns the configuration root node of this combined configuration. This * method will construct a combined node structure using the current node * combiner if necessary. * * @return the combined root node */ @Override public ConfigurationNode getRootNode() { synchronized (getReloadLock()) { if (reloadRequired || combinedRoot == null) { combinedRoot = constructCombinedNode(); reloadRequired = false; } return combinedRoot; } } /** * Clears this configuration. All contained configurations will be removed. */ @Override public void clear() { fireEvent(EVENT_CLEAR, null, null, true); configurations = new ArrayList(); namedConfigurations = new HashMap(); fireEvent(EVENT_CLEAR, null, null, false); invalidate(); } /** * Returns a copy of this object. This implementation performs a deep clone, * i.e. all contained configurations will be cloned, too. For this to work, * all contained configurations must be cloneable. Registered event * listeners won't be cloned. The clone will use the same node combiner than * the original. * * @return the copied object */ @Override public Object clone() { CombinedConfiguration copy = (CombinedConfiguration) super.clone(); copy.clear(); for (ConfigData cd : configurations) { copy.addConfiguration((AbstractConfiguration) ConfigurationUtils .cloneConfiguration(cd.getConfiguration()), cd.getName(), cd.getAt()); } copy.setRootNode(new DefaultConfigurationNode()); return copy; } /** * Returns the configuration source, in which the specified key is defined. * This method will determine the configuration node that is identified by * the given key. The following constellations are possible: *
    *
  • If no node object is found for this key, null is returned.
  • *
  • If the key maps to multiple nodes belonging to different * configuration sources, a {@code IllegalArgumentException} is * thrown (in this case no unique source can be determined).
  • *
  • If exactly one node is found for the key, the (child) configuration * object, to which the node belongs is determined and returned.
  • *
  • For keys that have been added directly to this combined * configuration and that do not belong to the namespaces defined by * existing child configurations this configuration will be returned.
  • *
* * @param key the key of a configuration property * @return the configuration, to which this property belongs or null * if the key cannot be resolved * @throws IllegalArgumentException if the key maps to multiple properties * and the source cannot be determined, or if the key is null * @since 1.5 */ public Configuration getSource(String key) { if (key == null) { throw new IllegalArgumentException("Key must not be null!"); } List nodes = fetchNodeList(key); if (nodes.isEmpty()) { return null; } Iterator it = nodes.iterator(); Configuration source = findSourceConfiguration(it.next()); while (it.hasNext()) { Configuration src = findSourceConfiguration(it.next()); if (src != source) { throw new IllegalArgumentException("The key " + key + " is defined by multiple sources!"); } } return source; } /** * Evaluates the passed in property key and returns a list with the matching * configuration nodes. This implementation also evaluates the * force reload check flag. If it is set, * {@code performReloadCheck()} is invoked. * * @param key the property key * @return a list with the matching configuration nodes */ @Override protected List fetchNodeList(String key) { if (isForceReloadCheck()) { performReloadCheck(); } return super.fetchNodeList(key); } /** * Triggers the contained configurations to perform a reload check if * necessary. This method is called when a property of this combined * configuration is accessed and the {@code forceReloadCheck} property * is set to true. * * @see #setForceReloadCheck(boolean) * @since 1.6 */ protected void performReloadCheck() { for (ConfigData cd : configurations) { try { // simply retrieve a property; this is enough for // triggering a reload cd.getConfiguration().getProperty(PROP_RELOAD_CHECK); } catch (Exception ex) { if (!ignoreReloadExceptions) { throw new ConfigurationRuntimeException(ex); } } } } /** * Creates the root node of this combined configuration. * * @return the combined root node */ private ConfigurationNode constructCombinedNode() { if (getNumberOfConfigurations() < 1) { if (getLogger().isDebugEnabled()) { getLogger().debug("No configurations defined for " + this); } return new ViewNode(); } else { Iterator it = configurations.iterator(); ConfigurationNode node = it.next().getTransformedRoot(); while (it.hasNext()) { node = getNodeCombiner().combine(node, it.next().getTransformedRoot()); } if (getLogger().isDebugEnabled()) { ByteArrayOutputStream os = new ByteArrayOutputStream(); PrintStream stream = new PrintStream(os); TreeUtils.printTree(stream, node); getLogger().debug(os.toString()); } return node; } } /** * Determines the configuration that owns the specified node. * * @param node the node * @return the owning configuration */ private Configuration findSourceConfiguration(ConfigurationNode node) { synchronized (getReloadLock()) { ConfigurationNode root = null; ConfigurationNode current = node; // find the root node in this hierarchy while (current != null) { root = current; current = current.getParentNode(); } // Check with the root nodes of the child configurations for (ConfigData cd : configurations) { if (root == cd.getRootNode()) { return cd.getConfiguration(); } } } return this; } /** * An internal helper class for storing information about contained * configurations. */ class ConfigData { /** Stores a reference to the configuration. */ private AbstractConfiguration configuration; /** Stores the name under which the configuration is stored. */ private String name; /** Stores the at information as path of nodes. */ private Collection atPath; /** Stores the at string.*/ private String at; /** Stores the root node for this child configuration.*/ private ConfigurationNode rootNode; /** * Creates a new instance of {@code ConfigData} and initializes * it. * * @param config the configuration * @param n the name * @param at the at position */ public ConfigData(AbstractConfiguration config, String n, String at) { configuration = config; name = n; atPath = parseAt(at); this.at = at; } /** * Returns the stored configuration. * * @return the configuration */ public AbstractConfiguration getConfiguration() { return configuration; } /** * Returns the configuration's name. * * @return the name */ public String getName() { return name; } /** * Returns the at position of this configuration. * * @return the at position */ public String getAt() { return at; } /** * Returns the root node for this child configuration. * * @return the root node of this child configuration * @since 1.5 */ public ConfigurationNode getRootNode() { return rootNode; } /** * Returns the transformed root node of the stored configuration. The * term "transformed" means that an eventually defined at path * has been applied. * * @return the transformed root node */ public ConfigurationNode getTransformedRoot() { ViewNode result = new ViewNode(); ViewNode atParent = result; if (atPath != null) { // Build the complete path for (String p : atPath) { ViewNode node = new ViewNode(); node.setName(p); atParent.addChild(node); atParent = node; } } // Copy data of the root node to the new path ConfigurationNode root = ConfigurationUtils .convertToHierarchical(getConfiguration(), getConversionExpressionEngine()).getRootNode(); atParent.appendChildren(root); atParent.appendAttributes(root); rootNode = root; return result; } /** * Splits the at path into its components. * * @param at the at string * @return a collection with the names of the single components */ private Collection parseAt(String at) { if (at == null) { return null; } Collection result = new ArrayList(); DefaultConfigurationKey.KeyIterator it = new DefaultConfigurationKey( AT_ENGINE, at).iterator(); while (it.hasNext()) { result.add(it.nextKey()); } return result; } } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/CompositeConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/CompositeConfiguration100644 45165 12232154103 33651 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.ListIterator; import java.util.Set; /** *

{@code CompositeConfiguration} allows you to add multiple {@code Configuration} * objects to an aggregated configuration. If you add Configuration1, and then Configuration2, * any properties shared will mean that the value defined by Configuration1 * will be returned. If Configuration1 doesn't have the property, then * Configuration2 will be checked. You can add multiple different types or the * same type of properties file.

*

When querying properties the order in which child configurations have been * added is relevant. To deal with property updates, a so-called in-memory * configuration is used. Per default, such a configuration is created * automatically. All property writes target this special configuration. There * are constructors which allow you to provide a specific in-memory configuration. * If used that way, the in-memory configuration is always the last one in the * list of child configurations. This means that for query operations all other * configurations take precedence.

*

Alternatively it is possible to mark a child configuration as in-memory * configuration when it is added. In this case the treatment of the in-memory * configuration is slightly different: it remains in the list of child * configurations at the position it was added, i.e. its priority for property * queries can be defined by adding the child configurations in the correct * order.

* * @author Eric Pugh * @author Henning P. Schmiedehausen * @version $Id: CompositeConfiguration.java 1534064 2013-10-21 08:44:33Z henning $ */ public class CompositeConfiguration extends AbstractConfiguration implements Cloneable { /** List holding all the configuration */ private List configList = new LinkedList(); /** * Configuration that holds in memory stuff. Inserted as first so any * setProperty() override anything else added. */ private Configuration inMemoryConfiguration; /** * Stores a flag whether the current in-memory configuration is also a * child configuration. */ private boolean inMemoryConfigIsChild; /** * Creates an empty CompositeConfiguration object which can then * be added some other Configuration files */ public CompositeConfiguration() { clear(); } /** * Creates a CompositeConfiguration object with a specified in-memory * configuration. This configuration will store any changes made to the * {@code CompositeConfiguration}. Note: Use this constructor if you want to * set a special type of in-memory configuration. If you have a * configuration which should act as both a child configuration and as * in-memory configuration, use * {@link #addConfiguration(Configuration, boolean)} with a value of * true instead. * * @param inMemoryConfiguration the in memory configuration to use */ public CompositeConfiguration(Configuration inMemoryConfiguration) { configList.clear(); this.inMemoryConfiguration = inMemoryConfiguration; configList.add(inMemoryConfiguration); } /** * Create a CompositeConfiguration with an empty in memory configuration * and adds the collection of configurations specified. * * @param configurations the collection of configurations to add */ public CompositeConfiguration(Collection configurations) { this(new BaseConfiguration(), configurations); } /** * Creates a CompositeConfiguration with a specified in-memory * configuration, and then adds the given collection of configurations. * * @param inMemoryConfiguration the in memory configuration to use * @param configurations the collection of configurations to add * @see #CompositeConfiguration(Configuration) */ public CompositeConfiguration(Configuration inMemoryConfiguration, Collection configurations) { this(inMemoryConfiguration); if (configurations != null) { for (Configuration c : configurations) { addConfiguration(c); } } } /** * Add a configuration. * * @param config the configuration to add */ public void addConfiguration(Configuration config) { addConfiguration(config, false); } /** * Adds a child configuration and optionally makes it the in-memory * configuration. This means that all future property write operations * are executed on this configuration. Note that the current in-memory * configuration is replaced by the new one. If it was created automatically * or passed to the constructor, it is removed from the list of child * configurations! Otherwise, it stays in the list of child configurations * at its current position, but it passes its role as in-memory * configuration to the new one. * * @param config the configuration to be added * @param asInMemory true if this configuration becomes the new * in-memory configuration, false otherwise * @since 1.8 */ public void addConfiguration(Configuration config, boolean asInMemory) { if (!configList.contains(config)) { if (asInMemory) { replaceInMemoryConfiguration(config); inMemoryConfigIsChild = true; } if (!inMemoryConfigIsChild) { // As the inMemoryConfiguration contains all manually added // keys, we must make sure that it is always last. "Normal", non // composed configurations add their keys at the end of the // configuration and we want to mimic this behavior. configList.add(configList.indexOf(inMemoryConfiguration), config); } else { // However, if the in-memory configuration is a regular child, // only the order in which child configurations are added is // relevant configList.add(config); } if (config instanceof AbstractConfiguration) { ((AbstractConfiguration) config) .setThrowExceptionOnMissing(isThrowExceptionOnMissing()); } } } /** * Remove a configuration. The in memory configuration cannot be removed. * * @param config The configuration to remove */ public void removeConfiguration(Configuration config) { // Make sure that you can't remove the inMemoryConfiguration from // the CompositeConfiguration object if (!config.equals(inMemoryConfiguration)) { configList.remove(config); } } /** * Return the number of configurations. * * @return the number of configuration */ public int getNumberOfConfigurations() { return configList.size(); } /** * Removes all child configurations and reinitializes the in-memory * configuration. Attention: A new in-memory * configuration is created; the old one is lost. */ @Override public void clear() { configList.clear(); // recreate the in memory configuration inMemoryConfiguration = new BaseConfiguration(); ((BaseConfiguration) inMemoryConfiguration).setThrowExceptionOnMissing(isThrowExceptionOnMissing()); ((BaseConfiguration) inMemoryConfiguration).setListDelimiter(getListDelimiter()); ((BaseConfiguration) inMemoryConfiguration).setDelimiterParsingDisabled(isDelimiterParsingDisabled()); configList.add(inMemoryConfiguration); inMemoryConfigIsChild = false; } /** * Add this property to the inmemory Configuration. * * @param key The Key to add the property to. * @param token The Value to add. */ @Override protected void addPropertyDirect(String key, Object token) { inMemoryConfiguration.addProperty(key, token); } /** * Read property from underlying composite * * @param key key to use for mapping * * @return object associated with the given configuration key. */ public Object getProperty(String key) { Configuration firstMatchingConfiguration = null; for (Configuration config : configList) { if (config.containsKey(key)) { firstMatchingConfiguration = config; break; } } if (firstMatchingConfiguration != null) { return firstMatchingConfiguration.getProperty(key); } else { return null; } } public Iterator getKeys() { Set keys = new LinkedHashSet(); for (Configuration config : configList) { for (Iterator it = config.getKeys(); it.hasNext();) { keys.add(it.next()); } } return keys.iterator(); } @Override public Iterator getKeys(String key) { Set keys = new LinkedHashSet(); for (Configuration config : configList) { for (Iterator it = config.getKeys(key); it.hasNext();) { keys.add(it.next()); } } return keys.iterator(); } public boolean isEmpty() { for (Configuration config : configList) { if (!config.isEmpty()) { return false; } } return true; } @Override protected void clearPropertyDirect(String key) { for (Configuration config : configList) { config.clearProperty(key); } } public boolean containsKey(String key) { for (Configuration config : configList) { if (config.containsKey(key)) { return true; } } return false; } @Override public List getList(String key, List defaultValue) { List list = new ArrayList(); // add all elements from the first configuration containing the requested key Iterator it = configList.iterator(); while (it.hasNext() && list.isEmpty()) { Configuration config = it.next(); if (config != inMemoryConfiguration && config.containsKey(key)) { appendListProperty(list, config, key); } } // add all elements from the in memory configuration appendListProperty(list, inMemoryConfiguration, key); if (list.isEmpty()) { return (List) defaultValue; } ListIterator lit = list.listIterator(); while (lit.hasNext()) { lit.set(interpolate(lit.next())); } return list; } @Override public String[] getStringArray(String key) { List list = getList(key); // transform property values into strings String[] tokens = new String[list.size()]; for (int i = 0; i < tokens.length; i++) { tokens[i] = String.valueOf(list.get(i)); } return tokens; } /** * Return the configuration at the specified index. * * @param index The index of the configuration to retrieve * @return the configuration at this index */ public Configuration getConfiguration(int index) { return configList.get(index); } /** * Returns the "in memory configuration". In this configuration * changes are stored. * * @return the in memory configuration */ public Configuration getInMemoryConfiguration() { return inMemoryConfiguration; } /** * Returns a copy of this object. This implementation will create a deep * clone, i.e. all configurations contained in this composite will also be * cloned. This only works if all contained configurations support cloning; * otherwise a runtime exception will be thrown. Registered event handlers * won't get cloned. * * @return the copy * @since 1.3 */ @Override public Object clone() { try { CompositeConfiguration copy = (CompositeConfiguration) super .clone(); copy.clearConfigurationListeners(); copy.configList = new LinkedList(); copy.inMemoryConfiguration = ConfigurationUtils .cloneConfiguration(getInMemoryConfiguration()); copy.configList.add(copy.inMemoryConfiguration); for (Configuration config : configList) { if (config != getInMemoryConfiguration()) { copy.addConfiguration(ConfigurationUtils .cloneConfiguration(config)); } } return copy; } catch (CloneNotSupportedException cnex) { // cannot happen throw new ConfigurationRuntimeException(cnex); } } /** * Sets a flag whether added values for string properties should be checked * for the list delimiter. This implementation ensures that the in memory * configuration is correctly initialized. * * @param delimiterParsingDisabled the new value of the flag * @since 1.4 */ @Override public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled) { if (inMemoryConfiguration instanceof AbstractConfiguration) { ((AbstractConfiguration) inMemoryConfiguration) .setDelimiterParsingDisabled(delimiterParsingDisabled); } super.setDelimiterParsingDisabled(delimiterParsingDisabled); } /** * Sets the character that is used as list delimiter. This implementation * ensures that the in memory configuration is correctly initialized. * * @param listDelimiter the new list delimiter character * @since 1.4 */ @Override public void setListDelimiter(char listDelimiter) { if (inMemoryConfiguration instanceof AbstractConfiguration) { ((AbstractConfiguration) inMemoryConfiguration) .setListDelimiter(listDelimiter); } super.setListDelimiter(listDelimiter); } /** * Returns the configuration source, in which the specified key is defined. * This method will iterate over all existing child configurations and check * whether they contain the specified key. The following constellations are * possible: *
    *
  • If exactly one child configuration contains the key, this * configuration is returned as the source configuration. This may be the * in memory configuration (this has to be explicitly checked by * the calling application).
  • *
  • If none of the child configurations contain the key, null is * returned.
  • *
  • If the key is contained in multiple child configurations or if the * key is null, a {@code IllegalArgumentException} is thrown. * In this case the source configuration cannot be determined.
  • *
* * @param key the key to be checked * @return the source configuration of this key * @throws IllegalArgumentException if the source configuration cannot be * determined * @since 1.5 */ public Configuration getSource(String key) { if (key == null) { throw new IllegalArgumentException("Key must not be null!"); } Configuration source = null; for (Configuration conf : configList) { if (conf.containsKey(key)) { if (source != null) { throw new IllegalArgumentException("The key " + key + " is defined by multiple sources!"); } source = conf; } } return source; } /** * Replaces the current in-memory configuration by the given one. * * @param config the new in-memory configuration */ private void replaceInMemoryConfiguration(Configuration config) { if (!inMemoryConfigIsChild) { // remove current in-memory configuration configList.remove(inMemoryConfiguration); } inMemoryConfiguration = config; } /** * Adds the value of a property to the given list. This method is used by * {@code getList()} for gathering property values from the child * configurations. * * @param dest the list for collecting the data * @param config the configuration to query * @param key the key of the property */ private static void appendListProperty(List dest, Configuration config, String key) { Object value = config.getProperty(key); if (value != null) { if (value instanceof Collection) { Collection col = (Collection) value; dest.addAll(col); } else { dest.add(value); } } } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/Configuration.java100644 52536 12232154102 32705 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Iterator; import java.util.List; import java.util.Properties; /** *

The main Configuration interface.

*

This interface allows accessing and manipulating a configuration object. * The major part of the methods defined in this interface deals with accessing * properties of various data types. There is a generic {@code getProperty()} * method, which returns the value of the queried property in its raw data * type. Other getter methods try to convert this raw data type into a specific * data type. If this fails, a {@code ConversionException} will be thrown.

*

For most of the property getter methods an overloaded version exists that * allows to specify a default value, which will be returned if the queried * property cannot be found in the configuration. The behavior of the methods * that do not take a default value in case of a missing property is not defined * by this interface and depends on a concrete implementation. E.g. the * {@link AbstractConfiguration} class, which is the base class * of most configuration implementations provided by this package, per default * returns null if a property is not found, but provides the * {@link AbstractConfiguration#setThrowExceptionOnMissing(boolean) * setThrowExceptionOnMissing()} * method, with which it can be configured to throw a {@code NoSuchElementException} * exception in that case. (Note that getter methods for primitive types in * {@code AbstractConfiguration} always throw an exception for missing * properties because there is no way of overloading the return value.)

*

With the {@code addProperty()} and {@code setProperty()} methods * new properties can be added to a configuration or the values of properties * can be changed. With {@code clearProperty()} a property can be removed. * Other methods allow to iterate over the contained properties or to create * a subset configuration.

* * @author Commons Configuration team * @version $Id: Configuration.java 1534064 2013-10-21 08:44:33Z henning $ */ public interface Configuration { /** * Return a decorator Configuration containing every key from the current * Configuration that starts with the specified prefix. The prefix is * removed from the keys in the subset. For example, if the configuration * contains the following properties: * *
     *    prefix.number = 1
     *    prefix.string = Apache
     *    prefixed.foo = bar
     *    prefix = Jakarta
* * the Configuration returned by {@code subset("prefix")} will contain * the properties: * *
     *    number = 1
     *    string = Apache
     *    = Jakarta
* * (The key for the value "Jakarta" is an empty string) *

* Since the subset is a decorator and not a modified copy of the initial * Configuration, any change made to the subset is available to the * Configuration, and reciprocally. * * @param prefix The prefix used to select the properties. * @return a subset configuration * * @see SubsetConfiguration */ Configuration subset(String prefix); /** * Check if the configuration is empty. * * @return {@code true} if the configuration contains no property, * {@code false} otherwise. */ boolean isEmpty(); /** * Check if the configuration contains the specified key. * * @param key the key whose presence in this configuration is to be tested * * @return {@code true} if the configuration contains a value for this * key, {@code false} otherwise */ boolean containsKey(String key); /** * Add a property to the configuration. If it already exists then the value * stated here will be added to the configuration entry. For example, if * the property: * *

resource.loader = file
* * is already present in the configuration and you call * *
addProperty("resource.loader", "classpath")
* * Then you will end up with a List like the following: * *
["file", "classpath"]
* * @param key The key to add the property to. * @param value The value to add. */ void addProperty(String key, Object value); /** * Set a property, this will replace any previously set values. Set values * is implicitly a call to clearProperty(key), addProperty(key, value). * * @param key The key of the property to change * @param value The new value */ void setProperty(String key, Object value); /** * Remove a property from the configuration. * * @param key the key to remove along with corresponding value. */ void clearProperty(String key); /** * Remove all properties from the configuration. */ void clear(); /** * Gets a property from the configuration. This is the most basic get * method for retrieving values of properties. In a typical implementation * of the {@code Configuration} interface the other get methods (that * return specific data types) will internally make use of this method. On * this level variable substitution is not yet performed. The returned * object is an internal representation of the property value for the passed * in key. It is owned by the {@code Configuration} object. So a caller * should not modify this object. It cannot be guaranteed that this object * will stay constant over time (i.e. further update operations on the * configuration may change its internal state). * * @param key property to retrieve * @return the value to which this configuration maps the specified key, or * null if the configuration contains no mapping for this key. */ Object getProperty(String key); /** * Get the list of the keys contained in the configuration that match the * specified prefix. For instance, if the configuration contains the * following keys:
* {@code db.user, db.pwd, db.url, window.xpos, window.ypos},
* an invocation of {@code getKeys("db");}
* will return the keys below:
* {@code db.user, db.pwd, db.url}.
* Note that the prefix itself is included in the result set if there is a * matching key. The exact behavior - how the prefix is actually * interpreted - depends on a concrete implementation. * * @param prefix The prefix to test against. * @return An Iterator of keys that match the prefix. * @see #getKeys() */ Iterator getKeys(String prefix); /** * Get the list of the keys contained in the configuration. The returned * iterator can be used to obtain all defined keys. Note that the exact * behavior of the iterator's {@code remove()} method is specific to * a concrete implementation. It may remove the corresponding * property from the configuration, but this is not guaranteed. In any case * it is no replacement for calling * {@link #clearProperty(String)} for this property. So it is * highly recommended to avoid using the iterator's {@code remove()} * method. * * @return An Iterator. */ Iterator getKeys(); /** * Get a list of properties associated with the given configuration key. * This method expects the given key to have an arbitrary number of String * values, each of which is of the form {code key=value}. These * strings are split at the equals sign, and the key parts will become * keys of the returned {@code Properties} object, the value parts * become values. * * @param key The configuration key. * @return The associated properties if key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a String/List. * * @throws IllegalArgumentException if one of the tokens is * malformed (does not contain an equals sign). */ Properties getProperties(String key); /** * Get a boolean associated with the given configuration key. * * @param key The configuration key. * @return The associated boolean. * * @throws ConversionException is thrown if the key maps to an * object that is not a Boolean. */ boolean getBoolean(String key); /** * Get a boolean associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated boolean. * * @throws ConversionException is thrown if the key maps to an * object that is not a Boolean. */ boolean getBoolean(String key, boolean defaultValue); /** * Get a {@link Boolean} associated with the given configuration key. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated boolean if key is found and has valid * format, default value otherwise. * * @throws ConversionException is thrown if the key maps to an * object that is not a Boolean. */ Boolean getBoolean(String key, Boolean defaultValue); /** * Get a byte associated with the given configuration key. * * @param key The configuration key. * @return The associated byte. * * @throws ConversionException is thrown if the key maps to an * object that is not a Byte. */ byte getByte(String key); /** * Get a byte associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated byte. * * @throws ConversionException is thrown if the key maps to an * object that is not a Byte. */ byte getByte(String key, byte defaultValue); /** * Get a {@link Byte} associated with the given configuration key. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated byte if key is found and has valid format, default * value otherwise. * * @throws ConversionException is thrown if the key maps to an object that * is not a Byte. */ Byte getByte(String key, Byte defaultValue); /** * Get a double associated with the given configuration key. * * @param key The configuration key. * @return The associated double. * * @throws ConversionException is thrown if the key maps to an * object that is not a Double. */ double getDouble(String key); /** * Get a double associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated double. * * @throws ConversionException is thrown if the key maps to an * object that is not a Double. */ double getDouble(String key, double defaultValue); /** * Get a {@link Double} associated with the given configuration key. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated double if key is found and has valid * format, default value otherwise. * * @throws ConversionException is thrown if the key maps to an * object that is not a Double. */ Double getDouble(String key, Double defaultValue); /** * Get a float associated with the given configuration key. * * @param key The configuration key. * @return The associated float. * @throws ConversionException is thrown if the key maps to an * object that is not a Float. */ float getFloat(String key); /** * Get a float associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated float. * * @throws ConversionException is thrown if the key maps to an * object that is not a Float. */ float getFloat(String key, float defaultValue); /** * Get a {@link Float} associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated float if key is found and has valid * format, default value otherwise. * * @throws ConversionException is thrown if the key maps to an * object that is not a Float. */ Float getFloat(String key, Float defaultValue); /** * Get a int associated with the given configuration key. * * @param key The configuration key. * @return The associated int. * * @throws ConversionException is thrown if the key maps to an * object that is not a Integer. */ int getInt(String key); /** * Get a int associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated int. * * @throws ConversionException is thrown if the key maps to an * object that is not a Integer. */ int getInt(String key, int defaultValue); /** * Get an {@link Integer} associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated int if key is found and has valid format, default * value otherwise. * * @throws ConversionException is thrown if the key maps to an object that * is not a Integer. */ Integer getInteger(String key, Integer defaultValue); /** * Get a long associated with the given configuration key. * * @param key The configuration key. * @return The associated long. * * @throws ConversionException is thrown if the key maps to an * object that is not a Long. */ long getLong(String key); /** * Get a long associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated long. * * @throws ConversionException is thrown if the key maps to an * object that is not a Long. */ long getLong(String key, long defaultValue); /** * Get a {@link Long} associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated long if key is found and has valid * format, default value otherwise. * * @throws ConversionException is thrown if the key maps to an * object that is not a Long. */ Long getLong(String key, Long defaultValue); /** * Get a short associated with the given configuration key. * * @param key The configuration key. * @return The associated short. * * @throws ConversionException is thrown if the key maps to an * object that is not a Short. */ short getShort(String key); /** * Get a short associated with the given configuration key. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated short. * * @throws ConversionException is thrown if the key maps to an * object that is not a Short. */ short getShort(String key, short defaultValue); /** * Get a {@link Short} associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated short if key is found and has valid * format, default value otherwise. * * @throws ConversionException is thrown if the key maps to an * object that is not a Short. */ Short getShort(String key, Short defaultValue); /** * Get a {@link BigDecimal} associated with the given configuration key. * * @param key The configuration key. * @return The associated BigDecimal if key is found and has valid format */ BigDecimal getBigDecimal(String key); /** * Get a {@link BigDecimal} associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * * @return The associated BigDecimal if key is found and has valid * format, default value otherwise. */ BigDecimal getBigDecimal(String key, BigDecimal defaultValue); /** * Get a {@link BigInteger} associated with the given configuration key. * * @param key The configuration key. * * @return The associated BigInteger if key is found and has valid format */ BigInteger getBigInteger(String key); /** * Get a {@link BigInteger} associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * * @return The associated BigInteger if key is found and has valid * format, default value otherwise. */ BigInteger getBigInteger(String key, BigInteger defaultValue); /** * Get a string associated with the given configuration key. * * @param key The configuration key. * @return The associated string. * * @throws ConversionException is thrown if the key maps to an object that * is not a String. */ String getString(String key); /** * Get a string associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated string if key is found and has valid * format, default value otherwise. * * @throws ConversionException is thrown if the key maps to an object that * is not a String. */ String getString(String key, String defaultValue); /** * Get an array of strings associated with the given configuration key. * If the key doesn't map to an existing object an empty array is returned * * @param key The configuration key. * @return The associated string array if key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a String/List of Strings. */ String[] getStringArray(String key); /** * Get a List of strings associated with the given configuration key. * If the key doesn't map to an existing object an empty List is returned. * * @param key The configuration key. * @return The associated List. * * @throws ConversionException is thrown if the key maps to an * object that is not a List. */ List getList(String key); /** * Get a List of strings associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of strings. * * @throws ConversionException is thrown if the key maps to an * object that is not a List. */ List getList(String key, List defaultValue); } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationBuilder.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationBuilder.j100644 3523 12232154103 33475 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; /** *

* Definition of an interface for objects that can create a configuration. *

*

* This interface defines an abstract way of creating a * {@code Configuration} object. It does not assume any specific way of * how this is done; this is completely in the responsibility of an * implementation class. There is just a single method that returns the * configuration constructed by this builder. *

* * @author Commons Configuration team * @version $Id: ConfigurationBuilder.java 1208781 2011-11-30 21:11:02Z oheger $ */ public interface ConfigurationBuilder { /** * Returns the configuration provided by this builder. An implementation has * to perform all necessary steps for creating and initializing a * {@code Configuration} object. * * @return the configuration * @throws ConfigurationException if an error occurs */ Configuration getConfiguration() throws ConfigurationException; } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationComparator.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationComparato100644 2632 12232154102 33603 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; /** * Comparator for configurations interface. * * @since 1.0 * * @author Herve Quiroz * @version $Id: ConfigurationComparator.java 1208783 2011-11-30 21:12:45Z oheger $ */ public interface ConfigurationComparator { /** * Compare two configuration objects. * * @param a the first configuration * @param b the second configuration * @return true if the two configurations are identical according to * the implemented rules */ boolean compare(Configuration a, Configuration b); } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationConverter.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationConverter100644 10342 12232154102 33642 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.collections.ExtendedProperties; import org.apache.commons.lang.StringUtils; /** * Configuration converter. Helper class to convert between Configuration, * ExtendedProperties and standard Properties. * * @author Martin Poeschl * @version $Id: ConfigurationConverter.java 1208788 2011-11-30 21:15:37Z oheger $ */ public final class ConfigurationConverter { /** * Private constructor prevents instances from being created. */ private ConfigurationConverter() { // to prevent instanciation... } /** * Convert a ExtendedProperties class into a Configuration class. * * @param eprops ExtendedProperties object to convert * @return Configuration created from the ExtendedProperties */ public static Configuration getConfiguration(ExtendedProperties eprops) { return new MapConfiguration(eprops); } /** * Convert a standard Properties class into a configuration class. * * @param props properties object to convert * @return Configuration configuration created from the Properties */ public static Configuration getConfiguration(Properties props) { return new MapConfiguration(props); } /** * Convert a Configuration class into a ExtendedProperties class. * * @param config Configuration object to convert * @return ExtendedProperties created from the Configuration */ public static ExtendedProperties getExtendedProperties(Configuration config) { ExtendedProperties props = new ExtendedProperties(); for (Iterator keys = config.getKeys(); keys.hasNext();) { String key = keys.next(); Object property = config.getProperty(key); // turn lists into vectors if (property instanceof List) { property = new ArrayList((List) property); } props.setProperty(key, property); } return props; } /** * Convert a Configuration class into a Properties class. List properties * are joined into a string using the delimiter of the configuration if it * extends AbstractConfiguration, and a comma otherwise. * * @param config Configuration object to convert * @return Properties created from the Configuration */ public static Properties getProperties(Configuration config) { Properties props = new Properties(); char delimiter = (config instanceof AbstractConfiguration) ? ((AbstractConfiguration) config).getListDelimiter() : ','; for (Iterator keys = config.getKeys(); keys.hasNext();) { String key = keys.next(); List list = config.getList(key); // turn the list into a string props.setProperty(key, StringUtils.join(list.iterator(), delimiter)); } return props; } /** * Convert a Configuration class into a Map class. * * @param config Configuration object to convert * @return Map created from the Configuration */ public static Map getMap(Configuration config) { return new ConfigurationMap(config); } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationException.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationException100644 4516 12232154102 33617 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import org.apache.commons.lang.exception.NestableException; /** * Any exception that occurs while initializing a Configuration * object. * * @author Eric Pugh * @version $Id: ConfigurationException.java 1208784 2011-11-30 21:13:18Z oheger $ */ public class ConfigurationException extends NestableException { /** * The serial version ID. */ private static final long serialVersionUID = -1316746661346991484L; /** * Constructs a new {@code ConfigurationException} without specified * detail message. */ public ConfigurationException() { super(); } /** * Constructs a new {@code ConfigurationException} with specified * detail message. * * @param message the error message */ public ConfigurationException(String message) { super(message); } /** * Constructs a new {@code ConfigurationException} with specified * nested {@code Throwable}. * * @param cause the exception or error that caused this exception to be thrown */ public ConfigurationException(Throwable cause) { super(cause); } /** * Constructs a new {@code ConfigurationException} with specified * detail message and nested {@code Throwable}. * * @param message the error message * @param cause the exception or error that caused this exception to be thrown */ public ConfigurationException(String message, Throwable cause) { super(message, cause); } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationFactory.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationFactory.j100644 72003 12232154102 33534 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.Collection; import java.util.LinkedList; import java.util.Map; import org.apache.commons.configuration.plist.PropertyListConfiguration; import org.apache.commons.configuration.plist.XMLPropertyListConfiguration; import org.apache.commons.digester.AbstractObjectCreationFactory; import org.apache.commons.digester.CallMethodRule; import org.apache.commons.digester.Digester; import org.apache.commons.digester.ObjectCreationFactory; import org.apache.commons.digester.Substitutor; import org.apache.commons.digester.substitution.MultiVariableExpander; import org.apache.commons.digester.substitution.VariableSubstitutor; import org.apache.commons.digester.xmlrules.DigesterLoader; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.Attributes; import org.xml.sax.SAXException; /** *

* Factory class to create a CompositeConfiguration from a .xml file using * Digester. By default it can handle the Configurations from commons- * configuration. If you need to add your own, then you can pass in your own * digester rules to use. It is also namespace aware, by providing a * digesterRuleNamespaceURI. *

*

* Note: Almost all of the features provided by this class and many * more are also available for the {@link DefaultConfigurationBuilder} * class. {@code DefaultConfigurationBuilder} also has a more robust * merge algorithm for constructing combined configurations. So it is * recommended to use this class instead of {@code ConfigurationFactory}. *

* * @author Eric Pugh * @author Henning P. Schmiedehausen * @version $Id: ConfigurationFactory.java 1209685 2011-12-02 20:47:44Z oheger $ * @deprecated Use {@link DefaultConfigurationBuilder} instead; this class * provides the same features as ConfigurationFactory plus some more; it can * also process the same configuration definition files. */ @Deprecated public class ConfigurationFactory { /** Constant for the root element in the info file.*/ private static final String SEC_ROOT = "configuration/"; /** Constant for the override section.*/ private static final String SEC_OVERRIDE = SEC_ROOT + "override/"; /** Constant for the additional section.*/ private static final String SEC_ADDITIONAL = SEC_ROOT + "additional/"; /** Constant for the optional attribute.*/ private static final String ATTR_OPTIONAL = "optional"; /** Constant for the fileName attribute.*/ private static final String ATTR_FILENAME = "fileName"; /** Constant for the load method.*/ private static final String METH_LOAD = "load"; /** Constant for the default base path (points to actual directory).*/ private static final String DEF_BASE_PATH = "."; /** static logger */ private static Log log = LogFactory.getLog(ConfigurationFactory.class); /** The XML file with the details about the configuration to load */ private String configurationFileName; /** The URL to the XML file with the details about the configuration to load. */ private URL configurationURL; /** * The implicit base path for included files. This path is determined by * the configuration to load and used unless no other base path was * explicitly specified. */ private String implicitBasePath; /** The basePath to prefix file paths for file based property files. */ private String basePath; /** URL for xml digester rules file */ private URL digesterRules; /** The digester namespace to parse */ private String digesterRuleNamespaceURI; /** * Constructor */ public ConfigurationFactory() { setBasePath(DEF_BASE_PATH); } /** * Constructor with ConfigurationFile Name passed * * @param configurationFileName The path to the configuration file */ public ConfigurationFactory(String configurationFileName) { setConfigurationFileName(configurationFileName); } /** * Return the configuration provided by this factory. It loads the * configuration file which is a XML description of the actual * configurations to load. It can contain various different types of * configuration, e.g. Properties, XML and JNDI. * * @return A Configuration object * @throws ConfigurationException A generic exception that we had trouble during the * loading of the configuration data. */ public Configuration getConfiguration() throws ConfigurationException { Digester digester; InputStream input = null; ConfigurationBuilder builder = new ConfigurationBuilder(); URL url = getConfigurationURL(); try { if (url == null) { url = ConfigurationUtils.locate(implicitBasePath, getConfigurationFileName()); } input = url.openStream(); } catch (Exception e) { log.error("Exception caught opening stream to URL", e); throw new ConfigurationException("Exception caught opening stream to URL", e); } if (getDigesterRules() == null) { digester = new Digester(); configureNamespace(digester); initDefaultDigesterRules(digester); } else { digester = DigesterLoader.createDigester(getDigesterRules()); // This might already be too late. As far as I can see, the namespace // awareness must be configured before the digester rules are loaded. configureNamespace(digester); } // Configure digester to always enable the context class loader digester.setUseContextClassLoader(true); // Add a substitutor to resolve system properties enableDigesterSubstitutor(digester); // Put the composite builder object below all of the other objects. digester.push(builder); // Parse the input stream to configure our mappings try { digester.parse(input); input.close(); } catch (SAXException saxe) { log.error("SAX Exception caught", saxe); throw new ConfigurationException("SAX Exception caught", saxe); } catch (IOException ioe) { log.error("IO Exception caught", ioe); throw new ConfigurationException("IO Exception caught", ioe); } return builder.getConfiguration(); } /** * Returns the configurationFile. * * @return The name of the configuration file. Can be null. */ public String getConfigurationFileName() { return configurationFileName; } /** * Sets the configurationFile. * * @param configurationFileName The name of the configurationFile to use. */ public void setConfigurationFileName(String configurationFileName) { File file = new File(configurationFileName).getAbsoluteFile(); this.configurationFileName = file.getName(); implicitBasePath = file.getParent(); } /** * Returns the URL of the configuration file to be loaded. * * @return the URL of the configuration to load */ public URL getConfigurationURL() { return configurationURL; } /** * Sets the URL of the configuration to load. This configuration can be * either specified by a file name or by a URL. * * @param url the URL of the configuration to load */ public void setConfigurationURL(URL url) { configurationURL = url; implicitBasePath = url.toString(); } /** * Returns the digesterRules. * * @return URL */ public URL getDigesterRules() { return digesterRules; } /** * Sets the digesterRules. * * @param digesterRules The digesterRules to set */ public void setDigesterRules(URL digesterRules) { this.digesterRules = digesterRules; } /** * Adds a substitutor to interpolate system properties * * @param digester The digester to which we add the substitutor */ protected void enableDigesterSubstitutor(Digester digester) { // This is ugly, but it is safe because the Properties object returned // by System.getProperties() (which is actually a Map) // contains only String keys. @SuppressWarnings("unchecked") Map systemProperties = (Map) (Object) System.getProperties(); MultiVariableExpander expander = new MultiVariableExpander(); expander.addSource("$", systemProperties); // allow expansion in both xml attributes and element text Substitutor substitutor = new VariableSubstitutor(expander); digester.setSubstitutor(substitutor); } /** * Initializes the parsing rules for the default digester * * This allows the Configuration Factory to understand the default types: * Properties, XML and JNDI. Two special sections are introduced: * <override> and <additional>. * * @param digester The digester to configure */ protected void initDefaultDigesterRules(Digester digester) { initDigesterSectionRules(digester, SEC_ROOT, false); initDigesterSectionRules(digester, SEC_OVERRIDE, false); initDigesterSectionRules(digester, SEC_ADDITIONAL, true); } /** * Sets up digester rules for a specified section of the configuration * info file. * * @param digester the current digester instance * @param matchString specifies the section * @param additional a flag if rules for the additional section are to be * added */ protected void initDigesterSectionRules(Digester digester, String matchString, boolean additional) { setupDigesterInstance( digester, matchString + "properties", new PropertiesConfigurationFactory(), METH_LOAD, additional); setupDigesterInstance( digester, matchString + "plist", new PropertyListConfigurationFactory(), METH_LOAD, additional); setupDigesterInstance( digester, matchString + "xml", new FileConfigurationFactory(XMLConfiguration.class), METH_LOAD, additional); setupDigesterInstance( digester, matchString + "hierarchicalXml", new FileConfigurationFactory(XMLConfiguration.class), METH_LOAD, additional); setupDigesterInstance( digester, matchString + "jndi", new JNDIConfigurationFactory(), null, additional); setupDigesterInstance( digester, matchString + "system", new SystemConfigurationFactory(), null, additional); } /** * Sets up digester rules for a configuration to be loaded. * * @param digester the current digester * @param matchString the pattern to match with this rule * @param factory an ObjectCreationFactory instance to use for creating new * objects * @param method the name of a method to be called or null for none * @param additional a flag if rules for the additional section are to be * added */ protected void setupDigesterInstance( Digester digester, String matchString, ObjectCreationFactory factory, String method, boolean additional) { if (additional) { setupUnionRules(digester, matchString); } digester.addFactoryCreate(matchString, factory); digester.addSetProperties(matchString); if (method != null) { digester.addRule(matchString, new CallOptionalMethodRule(method)); } digester.addSetNext(matchString, "addConfiguration", Configuration.class.getName()); } /** * Sets up rules for configurations in the additional section. * * @param digester the current digester * @param matchString the pattern to match with this rule */ protected void setupUnionRules(Digester digester, String matchString) { digester.addObjectCreate(matchString, AdditionalConfigurationData.class); digester.addSetProperties(matchString); digester.addSetNext(matchString, "addAdditionalConfig", AdditionalConfigurationData.class.getName()); } /** * Returns the digesterRuleNamespaceURI. * * @return A String with the digesterRuleNamespaceURI. */ public String getDigesterRuleNamespaceURI() { return digesterRuleNamespaceURI; } /** * Sets the digesterRuleNamespaceURI. * * @param digesterRuleNamespaceURI The new digesterRuleNamespaceURI to use */ public void setDigesterRuleNamespaceURI(String digesterRuleNamespaceURI) { this.digesterRuleNamespaceURI = digesterRuleNamespaceURI; } /** * Configure the current digester to be namespace aware and to have * a Configuration object to which all of the other configurations * should be added * * @param digester The Digester to configure */ private void configureNamespace(Digester digester) { if (getDigesterRuleNamespaceURI() != null) { digester.setNamespaceAware(true); digester.setRuleNamespaceURI(getDigesterRuleNamespaceURI()); } else { digester.setNamespaceAware(false); } digester.setValidating(false); } /** * Returns the Base path from which this Configuration Factory operates. * This is never null. If you set the BasePath to null, then a base path * according to the configuration to load is returned. * * @return The base Path of this configuration factory. */ public String getBasePath() { String path = StringUtils.isEmpty(basePath) || DEF_BASE_PATH.equals(basePath) ? implicitBasePath : basePath; return StringUtils.isEmpty(path) ? DEF_BASE_PATH : path; } /** * Sets the basePath for all file references from this Configuration Factory. * Normally a base path need not to be set because it is determined by * the location of the configuration file to load. All relative pathes in * this file are resolved relative to this file. Setting a base path makes * sense if such relative pathes should be otherwise resolved, e.g. if * the configuration file is loaded from the class path and all sub * configurations it refers to are stored in a special config directory. * * @param basePath The new basePath to set. */ public void setBasePath(String basePath) { this.basePath = basePath; } /** * A base class for digester factory classes. This base class maintains * a default class for the objects to be created. * There will be sub classes for specific configuration implementations. */ public class DigesterConfigurationFactory extends AbstractObjectCreationFactory { /** Actual class to use. */ private Class clazz; /** * Creates a new instance of {@code DigesterConfigurationFactory}. * * @param clazz the class which we should instantiate */ public DigesterConfigurationFactory(Class clazz) { this.clazz = clazz; } /** * Creates an instance of the specified class. * * @param attribs the attributes (ignored) * @return the new object * @throws Exception if object creation fails */ @Override public Object createObject(Attributes attribs) throws Exception { return clazz.newInstance(); } } /** * A tiny inner class that allows the Configuration Factory to * let the digester construct FileConfiguration objects * that already have the correct base Path set. * */ public class FileConfigurationFactory extends DigesterConfigurationFactory { /** * C'tor * * @param clazz The class which we should instantiate. */ public FileConfigurationFactory(Class clazz) { super(clazz); } /** * Gets called by the digester. * * @param attributes the actual attributes * @return the new object * @throws Exception Couldn't instantiate the requested object. */ @Override public Object createObject(Attributes attributes) throws Exception { FileConfiguration conf = createConfiguration(attributes); conf.setBasePath(getBasePath()); return conf; } /** * Creates the object, a {@code FileConfiguration}. * * @param attributes the actual attributes * @return the file configuration * @throws Exception if the object could not be created */ protected FileConfiguration createConfiguration(Attributes attributes) throws Exception { return (FileConfiguration) super.createObject(attributes); } } /** * A factory that returns an XMLPropertiesConfiguration for .xml files * and a PropertiesConfiguration for the others. * * @since 1.2 */ public class PropertiesConfigurationFactory extends FileConfigurationFactory { /** * Creates a new instance of {@code PropertiesConfigurationFactory}. */ public PropertiesConfigurationFactory() { super(null); } /** * Creates the new configuration object. Based on the file name * provided in the attributes either a {@code PropertiesConfiguration} * or a {@code XMLPropertiesConfiguration} object will be * returned. * * @param attributes the attributes * @return the new configuration object * @throws Exception if an error occurs */ @Override protected FileConfiguration createConfiguration(Attributes attributes) throws Exception { String filename = attributes.getValue(ATTR_FILENAME); if (filename != null && filename.toLowerCase().trim().endsWith(".xml")) { return new XMLPropertiesConfiguration(); } else { return new PropertiesConfiguration(); } } } /** * A factory that returns an XMLPropertyListConfiguration for .xml files * and a PropertyListConfiguration for the others. * * @since 1.2 */ public class PropertyListConfigurationFactory extends FileConfigurationFactory { /** * Creates a new instance of PropertyListConfigurationFactory. */ public PropertyListConfigurationFactory() { super(null); } /** * Creates the new configuration object. Based on the file name * provided in the attributes either a {@code XMLPropertyListConfiguration} * or a {@code PropertyListConfiguration} object will be * returned. * * @param attributes the attributes * @return the new configuration object * @throws Exception if an error occurs */ @Override protected FileConfiguration createConfiguration(Attributes attributes) throws Exception { String filename = attributes.getValue(ATTR_FILENAME); if (filename != null && filename.toLowerCase().trim().endsWith(".xml")) { return new XMLPropertyListConfiguration(); } else { return new PropertyListConfiguration(); } } } /** * A tiny inner class that allows the Configuration Factory to * let the digester construct JNDIConfiguration objects. */ private class JNDIConfigurationFactory extends DigesterConfigurationFactory { /** * Creates a new instance of {@code JNDIConfigurationFactory}. */ public JNDIConfigurationFactory() { super(JNDIConfiguration.class); } } /** * A tiny inner class that allows the Configuration Factory to * let the digester construct SystemConfiguration objects. */ private class SystemConfigurationFactory extends DigesterConfigurationFactory { /** * Creates a new instance of {@code SystemConfigurationFactory}. */ public SystemConfigurationFactory() { super(SystemConfiguration.class); } } /** * A simple data class that holds all information about a configuration * from the <additional> section. */ public static class AdditionalConfigurationData { /** Stores the configuration object.*/ private Configuration configuration; /** Stores the location of this configuration in the global tree.*/ private String at; /** * Returns the value of the {@code at} attribute. * * @return the at attribute */ public String getAt() { return at; } /** * Sets the value of the {@code at} attribute. * * @param string the attribute value */ public void setAt(String string) { at = string; } /** * Returns the configuration object. * * @return the configuration */ public Configuration getConfiguration() { return configuration; } /** * Sets the configuration object. Note: Normally this method should be * named {@code setConfiguration()}, but the name * {@code addConfiguration()} is required by some of the digester * rules. * * @param config the configuration to set */ public void addConfiguration(Configuration config) { configuration = config; } } /** * An internally used helper class for constructing the composite * configuration object. */ public static class ConfigurationBuilder { /** Stores the composite configuration.*/ private CompositeConfiguration config; /** Stores a collection with the configs from the additional section.*/ private Collection additionalConfigs; /** * Creates a new instance of {@code ConfigurationBuilder}. */ public ConfigurationBuilder() { config = new CompositeConfiguration(); additionalConfigs = new LinkedList(); } /** * Adds a new configuration to this object. This method is called by * Digester. * * @param conf the configuration to be added */ public void addConfiguration(Configuration conf) { config.addConfiguration(conf); } /** * Adds information about an additional configuration. This method is * called by Digester. * * @param data the data about the additional configuration */ public void addAdditionalConfig(AdditionalConfigurationData data) { additionalConfigs.add(data); } /** * Returns the final composite configuration. * * @return the final configuration object */ public CompositeConfiguration getConfiguration() { if (!additionalConfigs.isEmpty()) { Configuration unionConfig = createAdditionalConfiguration(additionalConfigs); if (unionConfig != null) { addConfiguration(unionConfig); } additionalConfigs.clear(); } return config; } /** * Creates a configuration object with the union of all properties * defined in the <additional> section. This * implementation returns a {@code HierarchicalConfiguration} * object. * * @param configs a collection with * {@code AdditionalConfigurationData} objects * @return the union configuration (can be null) */ protected Configuration createAdditionalConfiguration(Collection configs) { HierarchicalConfiguration result = new HierarchicalConfiguration(); for (AdditionalConfigurationData cdata : configs) { result.addNodes(cdata.getAt(), createRootNode(cdata).getChildren()); } return result.isEmpty() ? null : result; } /** * Creates a configuration root node for the specified configuration. * * @param cdata the configuration data object * @return a root node for this configuration */ private HierarchicalConfiguration.Node createRootNode(AdditionalConfigurationData cdata) { if (cdata.getConfiguration() instanceof HierarchicalConfiguration) { // we can directly use this configuration's root node return ((HierarchicalConfiguration) cdata.getConfiguration()).getRoot(); } else { // transform configuration to a hierarchical root node HierarchicalConfiguration hc = new HierarchicalConfiguration(); ConfigurationUtils.copy(cdata.getConfiguration(), hc); return hc.getRoot(); } } } /** * A special implementation of Digester's {@code CallMethodRule} that * is internally used for calling a file configuration's {@code load()} * method. This class differs from its ancestor that it catches all occurring * exceptions when the specified method is called. It then checks whether * for the corresponding configuration the optional attribute is set. If * this is the case, the exception will simply be ignored. * * @since 1.4 */ private static class CallOptionalMethodRule extends CallMethodRule { /** A flag whether the optional attribute is set for this node. */ private boolean optional; /** * Creates a new instance of {@code CallOptionalMethodRule} and * sets the name of the method to invoke. * * @param methodName the name of the method */ public CallOptionalMethodRule(String methodName) { super(methodName); } /** * Checks if the optional attribute is set. * * @param attrs the attributes * @throws Exception if an error occurs */ @Override public void begin(Attributes attrs) throws Exception { optional = attrs.getValue(ATTR_OPTIONAL) != null && PropertyConverter.toBoolean( attrs.getValue(ATTR_OPTIONAL)).booleanValue(); super.begin(attrs); } /** * Calls the method. If the optional attribute was set, occurring * exceptions will be ignored. * * @throws Exception if an error occurs */ @Override public void end() throws Exception { try { super.end(); } catch (Exception ex) { if (optional) { log.warn("Could not create optional configuration!", ex); } else { throw ex; } } } } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationKey.java100644 50112 12232154103 33343 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.Serializable; import java.util.Iterator; import java.util.NoSuchElementException; /** *

A simple class that supports creation of and iteration on complex * configuration keys.

* *

For key creation the class works similar to a StringBuilder: There are * several {@code appendXXXX()} methods with which single parts * of a key can be constructed. All these methods return a reference to the * actual object so they can be written in a chain. When using this methods * the exact syntax for keys need not be known.

* *

This class also defines a specialized iterator for configuration keys. * With such an iterator a key can be tokenized into its single parts. For * each part it can be checked whether it has an associated index.

* * @author Commons * Configuration team * @version $Id: ConfigurationKey.java 1231749 2012-01-15 20:48:56Z oheger $ * @deprecated Use {@link org.apache.commons.configuration.tree.DefaultConfigurationKey} * instead. It is associated with a {@code DefaultExpressionEngine} and thus * can produce correct keys even if key separators have been changed. */ @Deprecated public class ConfigurationKey implements Serializable { /** Constant for a property delimiter.*/ public static final char PROPERTY_DELIMITER = '.'; /** Constant for an escaped delimiter. */ public static final String ESCAPED_DELIMITER = String.valueOf(PROPERTY_DELIMITER) + String.valueOf(PROPERTY_DELIMITER); /** Constant for an attribute start marker.*/ private static final String ATTRIBUTE_START = "[@"; /** Constant for an attribute end marker.*/ private static final String ATTRIBUTE_END = "]"; /** Constant for an index start marker.*/ private static final char INDEX_START = '('; /** Constant for an index end marker.*/ private static final char INDEX_END = ')'; /** Constant for the initial StringBuilder size.*/ private static final int INITIAL_SIZE = 32; /** * The serial version ID. */ private static final long serialVersionUID = -4299732083605277656L; /** Holds a buffer with the so far created key.*/ private StringBuilder keyBuffer; /** * Creates a new, empty instance of {@code ConfigurationKey}. */ public ConfigurationKey() { keyBuffer = new StringBuilder(INITIAL_SIZE); } /** * Creates a new instance of {@code ConfigurationKey} and * initializes it with the given key. * * @param key the key as a string */ public ConfigurationKey(String key) { keyBuffer = new StringBuilder(key); removeTrailingDelimiter(); } /** * Appends the name of a property to this key. If necessary, a * property delimiter will be added. * * @param property the name of the property to be added * @return a reference to this object */ public ConfigurationKey append(String property) { if (keyBuffer.length() > 0 && !hasDelimiter() && !isAttributeKey(property)) { keyBuffer.append(PROPERTY_DELIMITER); } keyBuffer.append(property); removeTrailingDelimiter(); return this; } /** * Appends an index to this configuration key. * * @param index the index to be appended * @return a reference to this object */ public ConfigurationKey appendIndex(int index) { keyBuffer.append(INDEX_START).append(index); keyBuffer.append(INDEX_END); return this; } /** * Appends an attribute to this configuration key. * * @param attr the name of the attribute to be appended * @return a reference to this object */ public ConfigurationKey appendAttribute(String attr) { keyBuffer.append(constructAttributeKey(attr)); return this; } /** * Checks if this key is an attribute key. * * @return a flag if this key is an attribute key */ public boolean isAttributeKey() { return isAttributeKey(keyBuffer.toString()); } /** * Checks if the passed in key is an attribute key. Such attribute keys * start and end with certain marker strings. In some cases they must be * treated slightly different. * * @param key the key (part) to be checked * @return a flag if this key is an attribute key */ public static boolean isAttributeKey(String key) { return key != null && key.startsWith(ATTRIBUTE_START) && key.endsWith(ATTRIBUTE_END); } /** * Decorates the given key so that it represents an attribute. Adds * special start and end markers. * * @param key the key to be decorated * @return the decorated attribute key */ public static String constructAttributeKey(String key) { StringBuilder buf = new StringBuilder(); buf.append(ATTRIBUTE_START).append(key).append(ATTRIBUTE_END); return buf.toString(); } /** * Extracts the name of the attribute from the given attribute key. * This method removes the attribute markers - if any - from the * specified key. * * @param key the attribute key * @return the name of the corresponding attribute */ public static String attributeName(String key) { return isAttributeKey(key) ? removeAttributeMarkers(key) : key; } /** * Helper method for removing attribute markers from a key. * * @param key the key * @return the key with removed attribute markers */ static String removeAttributeMarkers(String key) { return key.substring(ATTRIBUTE_START.length(), key.length() - ATTRIBUTE_END.length()); } /** * Helper method that checks if the actual buffer ends with a property * delimiter. * * @return a flag if there is a trailing delimiter */ private boolean hasDelimiter() { int count = 0; for (int idx = keyBuffer.length() - 1; idx >= 0 && keyBuffer.charAt(idx) == PROPERTY_DELIMITER; idx--) { count++; } return count % 2 != 0; } /** * Removes a trailing delimiter if there is any. */ private void removeTrailingDelimiter() { while (hasDelimiter()) { keyBuffer.deleteCharAt(keyBuffer.length() - 1); } } /** * Returns a string representation of this object. This is the * configuration key as a plain string. * * @return a string for this object */ @Override public String toString() { return keyBuffer.toString(); } /** * Returns an iterator for iterating over the single components of * this configuration key. * * @return an iterator for this key */ public KeyIterator iterator() { return new KeyIterator(); } /** * Returns the actual length of this configuration key. * * @return the length of this key */ public int length() { return keyBuffer.length(); } /** * Sets the new length of this configuration key. With this method it is * possible to truncate the key, e.g. to return to a state prior calling * some {@code append()} methods. The semantic is the same as * the {@code setLength()} method of {@code StringBuilder}. * * @param len the new length of the key */ public void setLength(int len) { keyBuffer.setLength(len); } /** * Checks if two {@code ConfigurationKey} objects are equal. The * method can be called with strings or other objects, too. * * @param c the object to compare * @return a flag if both objects are equal */ @Override public boolean equals(Object c) { if (c == null) { return false; } return keyBuffer.toString().equals(c.toString()); } /** * Returns the hash code for this object. * * @return the hash code */ @Override public int hashCode() { return String.valueOf(keyBuffer).hashCode(); } /** * Returns a configuration key object that is initialized with the part * of the key that is common to this key and the passed in key. * * @param other the other key * @return a key object with the common key part */ public ConfigurationKey commonKey(ConfigurationKey other) { if (other == null) { throw new IllegalArgumentException("Other key must no be null!"); } ConfigurationKey result = new ConfigurationKey(); KeyIterator it1 = iterator(); KeyIterator it2 = other.iterator(); while (it1.hasNext() && it2.hasNext() && partsEqual(it1, it2)) { if (it1.isAttribute()) { result.appendAttribute(it1.currentKey()); } else { result.append(it1.currentKey()); if (it1.hasIndex) { result.appendIndex(it1.getIndex()); } } } return result; } /** * Returns the "difference key" to a given key. This value * is the part of the passed in key that differs from this key. There is * the following relation: * {@code other = key.commonKey(other) + key.differenceKey(other)} * for an arbitrary configuration key {@code key}. * * @param other the key for which the difference is to be calculated * @return the difference key */ public ConfigurationKey differenceKey(ConfigurationKey other) { ConfigurationKey common = commonKey(other); ConfigurationKey result = new ConfigurationKey(); if (common.length() < other.length()) { String k = other.toString().substring(common.length()); // skip trailing delimiters int i = 0; while (i < k.length() && k.charAt(i) == PROPERTY_DELIMITER) { i++; } if (i < k.length()) { result.append(k.substring(i)); } } return result; } /** * Helper method for comparing two key parts. * * @param it1 the iterator with the first part * @param it2 the iterator with the second part * @return a flag if both parts are equal */ private static boolean partsEqual(KeyIterator it1, KeyIterator it2) { return it1.nextKey().equals(it2.nextKey()) && it1.getIndex() == it2.getIndex() && it1.isAttribute() == it2.isAttribute(); } /** * A specialized iterator class for tokenizing a configuration key. * This class implements the normal iterator interface. In addition it * provides some specific methods for configuration keys. */ public class KeyIterator implements Iterator, Cloneable { /** Stores the current key name.*/ private String current; /** Stores the start index of the actual token.*/ private int startIndex; /** Stores the end index of the actual token.*/ private int endIndex; /** Stores the index of the actual property if there is one.*/ private int indexValue; /** Stores a flag if the actual property has an index.*/ private boolean hasIndex; /** Stores a flag if the actual property is an attribute.*/ private boolean attribute; /** * Helper method for determining the next indices. * * @return the next key part */ private String findNextIndices() { startIndex = endIndex; // skip empty names while (startIndex < keyBuffer.length() && keyBuffer.charAt(startIndex) == PROPERTY_DELIMITER) { startIndex++; } // Key ends with a delimiter? if (startIndex >= keyBuffer.length()) { endIndex = keyBuffer.length(); startIndex = endIndex - 1; return keyBuffer.substring(startIndex, endIndex); } else { return nextKeyPart(); } } /** * Helper method for extracting the next key part. Takes escaping of * delimiter characters into account. * * @return the next key part */ private String nextKeyPart() { StringBuilder key = new StringBuilder(INITIAL_SIZE); int idx = startIndex; int endIdx = keyBuffer.toString().indexOf(ATTRIBUTE_START, startIndex); if (endIdx < 0 || endIdx == startIndex) { endIdx = keyBuffer.length(); } boolean found = false; while (!found && idx < endIdx) { char c = keyBuffer.charAt(idx); if (c == PROPERTY_DELIMITER) { // a duplicated delimiter means escaping if (idx == endIdx - 1 || keyBuffer.charAt(idx + 1) != PROPERTY_DELIMITER) { found = true; } else { idx++; } } if (!found) { key.append(c); idx++; } } endIndex = idx; return key.toString(); } /** * Returns the next key part of this configuration key. This is a short * form of {@code nextKey(false)}. * * @return the next key part */ public String nextKey() { return nextKey(false); } /** * Returns the next key part of this configuration key. The boolean * parameter indicates wheter a decorated key should be returned. This * affects only attribute keys: if the parameter is false, the * attribute markers are stripped from the key; if it is true, * they remain. * * @param decorated a flag if the decorated key is to be returned * @return the next key part */ public String nextKey(boolean decorated) { if (!hasNext()) { throw new NoSuchElementException("No more key parts!"); } hasIndex = false; indexValue = -1; String key = findNextIndices(); current = key; hasIndex = checkIndex(key); attribute = checkAttribute(current); return currentKey(decorated); } /** * Helper method for checking if the passed key is an attribute. * If this is the case, the internal fields will be set. * * @param key the key to be checked * @return a flag if the key is an attribute */ private boolean checkAttribute(String key) { if (isAttributeKey(key)) { current = removeAttributeMarkers(key); return true; } else { return false; } } /** * Helper method for checking if the passed key contains an index. * If this is the case, internal fields will be set. * * @param key the key to be checked * @return a flag if an index is defined */ private boolean checkIndex(String key) { boolean result = false; int idx = key.lastIndexOf(INDEX_START); if (idx > 0) { int endidx = key.indexOf(INDEX_END, idx); if (endidx > idx + 1) { indexValue = Integer.parseInt(key.substring(idx + 1, endidx)); current = key.substring(0, idx); result = true; } } return result; } /** * Checks if there is a next element. * * @return a flag if there is a next element */ public boolean hasNext() { return endIndex < keyBuffer.length(); } /** * Returns the next object in the iteration. * * @return the next object */ public Object next() { return nextKey(); } /** * Removes the current object in the iteration. This method is not * supported by this iterator type, so an exception is thrown. */ public void remove() { throw new UnsupportedOperationException("Remove not supported!"); } /** * Returns the current key of the iteration (without skipping to the * next element). This is the same key the previous {@code next()} * call had returned. (Short form of {@code currentKey(false)}. * * @return the current key */ public String currentKey() { return currentKey(false); } /** * Returns the current key of the iteration (without skipping to the * next element). The boolean parameter indicates wheter a decorated * key should be returned. This affects only attribute keys: if the * parameter is false, the attribute markers are stripped from * the key; if it is true, they remain. * * @param decorated a flag if the decorated key is to be returned * @return the current key */ public String currentKey(boolean decorated) { return (decorated && isAttribute()) ? constructAttributeKey(current) : current; } /** * Returns a flag if the current key is an attribute. This method can * be called after {@code next()}. * * @return a flag if the current key is an attribute */ public boolean isAttribute() { return attribute; } /** * Returns the index value of the current key. If the current key does * not have an index, return value is -1. This method can be called * after {@code next()}. * * @return the index value of the current key */ public int getIndex() { return indexValue; } /** * Returns a flag if the current key has an associated index. * This method can be called after {@code next()}. * * @return a flag if the current key has an index */ public boolean hasIndex() { return hasIndex; } /** * Creates a clone of this object. * * @return a clone of this object */ @Override public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException cex) { // should not happen return null; } } } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationMap.java100644 13610 12232154102 33331 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.AbstractMap; import java.util.AbstractSet; import java.util.Iterator; import java.util.Map; import java.util.Set; /** *

The {@code ConfigurationMap} wraps a * configuration-collection * {@link org.apache.commons.configuration.Configuration} * instance to provide a {@code Map} interface.

* *

Note: This implementation is incomplete.

* * @author Ricardo Gladwell * @version $Id: ConfigurationMap.java 1301959 2012-03-17 16:43:18Z oheger $ * @since 1.0 */ public class ConfigurationMap extends AbstractMap { /** * The {@code Configuration} wrapped by this class. */ private final Configuration configuration; /** * Creates a new instance of a {@code ConfigurationMap} * that wraps the specified {@code Configuration} * instance. * @param configuration {@code Configuration} * instance. */ public ConfigurationMap(Configuration configuration) { this.configuration = configuration; } /** * Returns the wrapped {@code Configuration} object. * * @return the wrapped configuration * @since 1.2 */ public Configuration getConfiguration() { return configuration; } /** * Returns a set with the entries contained in this configuration-based map. * * @return a set with the contained entries * @see java.util.Map#entrySet() */ @Override public Set> entrySet() { return new ConfigurationSet(configuration); } /** * Stores the value for the specified key. The value is stored in the * underlying configuration. * * @param key the key (will be converted to a string) * @param value the value * @return the old value of this key or null if it is new * @see java.util.Map#put(java.lang.Object, java.lang.Object) */ @Override public Object put(Object key, Object value) { String strKey = String.valueOf(key); Object old = configuration.getProperty(strKey); configuration.setProperty(strKey, value); return old; } /** * Returns the value of the specified key. The key is converted to a string * and then passed to the underlying configuration. * * @param key the key * @return the value of this key * @see java.util.Map#get(java.lang.Object) */ @Override public Object get(Object key) { return configuration.getProperty(String.valueOf(key)); } /** * Set of entries in the map. */ static class ConfigurationSet extends AbstractSet> { /** The configuration mapped to this entry set. */ private final Configuration configuration; /** * A Map entry in the ConfigurationMap. */ private final class Entry implements Map.Entry { /** The key of the map entry. */ private Object key; private Entry(Object key) { this.key = key; } public Object getKey() { return key; } public Object getValue() { return configuration.getProperty((String) key); } public Object setValue(Object value) { Object old = getValue(); configuration.setProperty((String) key, value); return old; } } /** * Iterator over the entries in the ConfigurationMap. */ private final class ConfigurationSetIterator implements Iterator> { /** An iterator over the keys in the configuration. */ private final Iterator keys; private ConfigurationSetIterator() { keys = configuration.getKeys(); } public boolean hasNext() { return keys.hasNext(); } public Map.Entry next() { return new Entry(keys.next()); } public void remove() { keys.remove(); } } ConfigurationSet(Configuration configuration) { this.configuration = configuration; } /** * @see java.util.Collection#size() */ @Override public int size() { // Ouch. Now _that_ one is expensive... int count = 0; for (Iterator iterator = configuration.getKeys(); iterator.hasNext();) { iterator.next(); count++; } return count; } /** * @see java.util.Collection#iterator() */ @Override public Iterator> iterator() { return new ConfigurationSetIterator(); } } } ././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationRuntimeException.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationRuntimeEx100644 4633 12232154103 33602 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import org.apache.commons.lang.exception.NestableRuntimeException; /** * A configuration related runtime exception. * * @since 1.0 * * @author Emmanuel Bourg * @version $Id: ConfigurationRuntimeException.java 1208785 2011-11-30 21:13:50Z oheger $ */ public class ConfigurationRuntimeException extends NestableRuntimeException { /** * The serial version ID. */ private static final long serialVersionUID = -7838702245512140996L; /** * Constructs a new {@code ConfigurationRuntimeException} without * specified detail message. */ public ConfigurationRuntimeException() { super(); } /** * Constructs a new {@code ConfigurationRuntimeException} with * specified detail message. * * @param message the error message */ public ConfigurationRuntimeException(String message) { super(message); } /** * Constructs a new {@code ConfigurationRuntimeException} with * specified nested {@code Throwable}. * * @param cause the exception or error that caused this exception to be thrown */ public ConfigurationRuntimeException(Throwable cause) { super(cause); } /** * Constructs a new {@code ConfigurationRuntimeException} with * specified detail message and nested {@code Throwable}. * * @param message the error message * @param cause the exception or error that caused this exception to be thrown */ public ConfigurationRuntimeException(String message, Throwable cause) { super(message, cause); } } ././@LongLink100644 0 0 146 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationUtils.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationUtils.jav100644 61702 12232154103 33561 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.PrintStream; import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; import org.apache.commons.configuration.event.ConfigurationErrorEvent; import org.apache.commons.configuration.event.ConfigurationErrorListener; import org.apache.commons.configuration.event.EventSource; import org.apache.commons.configuration.reloading.Reloadable; import org.apache.commons.configuration.tree.ExpressionEngine; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Miscellaneous utility methods for configurations. * * @see ConfigurationConverter Utility methods to convert configurations. * * @author Herve Quiroz * @author Emmanuel Bourg * @version $Id: ConfigurationUtils.java 1208795 2011-11-30 21:18:17Z oheger $ */ public final class ConfigurationUtils { /** Constant for the file URL protocol.*/ static final String PROTOCOL_FILE = "file"; /** Constant for the resource path separator.*/ static final String RESOURCE_PATH_SEPARATOR = "/"; /** Constant for the file URL protocol */ private static final String FILE_SCHEME = "file:"; /** Constant for the name of the clone() method.*/ private static final String METHOD_CLONE = "clone"; /** Constant for parsing numbers in hex format. */ private static final int HEX = 16; /** The logger.*/ private static final Log LOG = LogFactory.getLog(ConfigurationUtils.class); /** * Private constructor. Prevents instances from being created. */ private ConfigurationUtils() { // to prevent instantiation... } /** * Dump the configuration key/value mappings to some ouput stream. * * @param configuration the configuration * @param out the output stream to dump the configuration to */ public static void dump(Configuration configuration, PrintStream out) { dump(configuration, new PrintWriter(out)); } /** * Dump the configuration key/value mappings to some writer. * * @param configuration the configuration * @param out the writer to dump the configuration to */ public static void dump(Configuration configuration, PrintWriter out) { for (Iterator keys = configuration.getKeys(); keys.hasNext();) { String key = keys.next(); Object value = configuration.getProperty(key); out.print(key); out.print("="); out.print(value); if (keys.hasNext()) { out.println(); } } out.flush(); } /** * Get a string representation of the key/value mappings of a * configuration. * * @param configuration the configuration * @return a string representation of the configuration */ public static String toString(Configuration configuration) { StringWriter writer = new StringWriter(); dump(configuration, new PrintWriter(writer)); return writer.toString(); } /** *

Copy all properties from the source configuration to the target * configuration. Properties in the target configuration are replaced with * the properties with the same key in the source configuration.

*

Note: This method is not able to handle some specifics of * configurations derived from {@code AbstractConfiguration} (e.g. * list delimiters). For a full support of all of these features the * {@code copy()} method of {@code AbstractConfiguration} should * be used. In a future release this method might become deprecated.

* * @param source the source configuration * @param target the target configuration * @since 1.1 */ public static void copy(Configuration source, Configuration target) { for (Iterator keys = source.getKeys(); keys.hasNext();) { String key = keys.next(); target.setProperty(key, source.getProperty(key)); } } /** *

Append all properties from the source configuration to the target * configuration. Properties in the source configuration are appended to * the properties with the same key in the target configuration.

*

Note: This method is not able to handle some specifics of * configurations derived from {@code AbstractConfiguration} (e.g. * list delimiters). For a full support of all of these features the * {@code copy()} method of {@code AbstractConfiguration} should * be used. In a future release this method might become deprecated.

* * @param source the source configuration * @param target the target configuration * @since 1.1 */ public static void append(Configuration source, Configuration target) { for (Iterator keys = source.getKeys(); keys.hasNext();) { String key = keys.next(); target.addProperty(key, source.getProperty(key)); } } /** * Converts the passed in configuration to a hierarchical one. If the * configuration is already hierarchical, it is directly returned. Otherwise * all properties are copied into a new hierarchical configuration. * * @param conf the configuration to convert * @return the new hierarchical configuration (the result is null if * and only if the passed in configuration is null) * @since 1.3 */ public static HierarchicalConfiguration convertToHierarchical( Configuration conf) { return convertToHierarchical(conf, null); } /** * Converts the passed in {@code Configuration} object to a * hierarchical one using the specified {@code ExpressionEngine}. This * conversion works by adding the keys found in the configuration to a newly * created hierarchical configuration. When adding new keys to a * hierarchical configuration the keys are interpreted by its * {@code ExpressionEngine}. If they contain special characters (e.g. * brackets) that are treated in a special way by the default expression * engine, it may be necessary using a specific engine that can deal with * such characters. Otherwise null can be passed in for the * {@code ExpressionEngine}; then the default expression engine is * used. If the passed in configuration is already hierarchical, it is * directly returned. (However, the {@code ExpressionEngine} is set if * it is not null.) Otherwise all properties are copied into a new * hierarchical configuration. * * @param conf the configuration to convert * @param engine the {@code ExpressionEngine} for the hierarchical * configuration or null for the default * @return the new hierarchical configuration (the result is null if * and only if the passed in configuration is null) * @since 1.6 */ public static HierarchicalConfiguration convertToHierarchical( Configuration conf, ExpressionEngine engine) { if (conf == null) { return null; } if (conf instanceof HierarchicalConfiguration) { HierarchicalConfiguration hc; if (conf instanceof Reloadable) { Object lock = ((Reloadable) conf).getReloadLock(); synchronized (lock) { hc = new HierarchicalConfiguration((HierarchicalConfiguration) conf); } } else { hc = (HierarchicalConfiguration) conf; } if (engine != null) { hc.setExpressionEngine(engine); } return hc; } else { HierarchicalConfiguration hc = new HierarchicalConfiguration(); if (engine != null) { hc.setExpressionEngine(engine); } // Workaround for problem with copy() boolean delimiterParsingStatus = hc.isDelimiterParsingDisabled(); hc.setDelimiterParsingDisabled(true); hc.append(conf); hc.setDelimiterParsingDisabled(delimiterParsingStatus); return hc; } } /** * Clones the given configuration object if this is possible. If the passed * in configuration object implements the {@code Cloneable} * interface, its {@code clone()} method will be invoked. Otherwise * an exception will be thrown. * * @param config the configuration object to be cloned (can be null) * @return the cloned configuration (null if the argument was * null, too) * @throws ConfigurationRuntimeException if cloning is not supported for * this object * @since 1.3 */ public static Configuration cloneConfiguration(Configuration config) throws ConfigurationRuntimeException { if (config == null) { return null; } else { try { return (Configuration) clone(config); } catch (CloneNotSupportedException cnex) { throw new ConfigurationRuntimeException(cnex); } } } /** * An internally used helper method for cloning objects. This implementation * is not very sophisticated nor efficient. Maybe it can be replaced by an * implementation from Commons Lang later. The method checks whether the * passed in object implements the {@code Cloneable} interface. If * this is the case, the {@code clone()} method is invoked by * reflection. Errors that occur during the cloning process are re-thrown as * runtime exceptions. * * @param obj the object to be cloned * @return the cloned object * @throws CloneNotSupportedException if the object cannot be cloned */ static Object clone(Object obj) throws CloneNotSupportedException { if (obj instanceof Cloneable) { try { Method m = obj.getClass().getMethod(METHOD_CLONE); return m.invoke(obj); } catch (NoSuchMethodException nmex) { throw new CloneNotSupportedException( "No clone() method found for class" + obj.getClass().getName()); } catch (IllegalAccessException iaex) { throw new ConfigurationRuntimeException(iaex); } catch (InvocationTargetException itex) { throw new ConfigurationRuntimeException(itex); } } else { throw new CloneNotSupportedException(obj.getClass().getName() + " does not implement Cloneable"); } } /** * Constructs a URL from a base path and a file name. The file name can * be absolute, relative or a full URL. If necessary the base path URL is * applied. * * @param basePath the base path URL (can be null) * @param file the file name * @return the resulting URL * @throws MalformedURLException if URLs are invalid */ public static URL getURL(String basePath, String file) throws MalformedURLException { return FileSystem.getDefaultFileSystem().getURL(basePath, file); } /** * Helper method for constructing a file object from a base path and a * file name. This method is called if the base path passed to * {@code getURL()} does not seem to be a valid URL. * * @param basePath the base path * @param fileName the file name * @return the resulting file */ static File constructFile(String basePath, String fileName) { File file; File absolute = null; if (fileName != null) { absolute = new File(fileName); } if (StringUtils.isEmpty(basePath) || (absolute != null && absolute.isAbsolute())) { file = new File(fileName); } else { StringBuilder fName = new StringBuilder(); fName.append(basePath); // My best friend. Paranoia. if (!basePath.endsWith(File.separator)) { fName.append(File.separator); } // // We have a relative path, and we have // two possible forms here. If we have the // "./" form then just strip that off first // before continuing. // if (fileName.startsWith("." + File.separator)) { fName.append(fileName.substring(2)); } else { fName.append(fileName); } file = new File(fName.toString()); } return file; } /** * Return the location of the specified resource by searching the user home * directory, the current classpath and the system classpath. * * @param name the name of the resource * * @return the location of the resource */ public static URL locate(String name) { return locate(null, name); } /** * Return the location of the specified resource by searching the user home * directory, the current classpath and the system classpath. * * @param base the base path of the resource * @param name the name of the resource * * @return the location of the resource */ public static URL locate(String base, String name) { return locate(FileSystem.getDefaultFileSystem(), base, name); } /** * Return the location of the specified resource by searching the user home * directory, the current classpath and the system classpath. * * @param fileSystem the FileSystem to use. * @param base the base path of the resource * @param name the name of the resource * * @return the location of the resource */ public static URL locate(FileSystem fileSystem, String base, String name) { if (LOG.isDebugEnabled()) { StringBuilder buf = new StringBuilder(); buf.append("ConfigurationUtils.locate(): base is ").append(base); buf.append(", name is ").append(name); LOG.debug(buf.toString()); } if (name == null) { // undefined, always return null return null; } // attempt to create an URL directly URL url = fileSystem.locateFromURL(base, name); // attempt to load from an absolute path if (url == null) { File file = new File(name); if (file.isAbsolute() && file.exists()) // already absolute? { try { url = toURL(file); LOG.debug("Loading configuration from the absolute path " + name); } catch (MalformedURLException e) { LOG.warn("Could not obtain URL from file", e); } } } // attempt to load from the base directory if (url == null) { try { File file = constructFile(base, name); if (file != null && file.exists()) { url = toURL(file); } if (url != null) { LOG.debug("Loading configuration from the path " + file); } } catch (MalformedURLException e) { LOG.warn("Could not obtain URL from file", e); } } // attempt to load from the user home directory if (url == null) { try { File file = constructFile(System.getProperty("user.home"), name); if (file != null && file.exists()) { url = toURL(file); } if (url != null) { LOG.debug("Loading configuration from the home path " + file); } } catch (MalformedURLException e) { LOG.warn("Could not obtain URL from file", e); } } // attempt to load from classpath if (url == null) { url = locateFromClasspath(name); } return url; } /** * Tries to find a resource with the given name in the classpath. * @param resourceName the name of the resource * @return the URL to the found resource or null if the resource * cannot be found */ static URL locateFromClasspath(String resourceName) { URL url = null; // attempt to load from the context classpath ClassLoader loader = Thread.currentThread().getContextClassLoader(); if (loader != null) { url = loader.getResource(resourceName); if (url != null) { LOG.debug("Loading configuration from the context classpath (" + resourceName + ")"); } } // attempt to load from the system classpath if (url == null) { url = ClassLoader.getSystemResource(resourceName); if (url != null) { LOG.debug("Loading configuration from the system classpath (" + resourceName + ")"); } } return url; } /** * Return the path without the file name, for example http://xyz.net/foo/bar.xml * results in http://xyz.net/foo/ * * @param url the URL from which to extract the path * @return the path component of the passed in URL */ static String getBasePath(URL url) { if (url == null) { return null; } String s = url.toString(); if (s.startsWith(FILE_SCHEME) && !s.startsWith("file://")) { s = "file://" + s.substring(FILE_SCHEME.length()); } if (s.endsWith("/") || StringUtils.isEmpty(url.getPath())) { return s; } else { return s.substring(0, s.lastIndexOf("/") + 1); } } /** * Extract the file name from the specified URL. * * @param url the URL from which to extract the file name * @return the extracted file name */ static String getFileName(URL url) { if (url == null) { return null; } String path = url.getPath(); if (path.endsWith("/") || StringUtils.isEmpty(path)) { return null; } else { return path.substring(path.lastIndexOf("/") + 1); } } /** * Tries to convert the specified base path and file name into a file object. * This method is called e.g. by the save() methods of file based * configurations. The parameter strings can be relative files, absolute * files and URLs as well. This implementation checks first whether the passed in * file name is absolute. If this is the case, it is returned. Otherwise * further checks are performed whether the base path and file name can be * combined to a valid URL or a valid file name. Note: The test * if the passed in file name is absolute is performed using * {@code java.io.File.isAbsolute()}. If the file name starts with a * slash, this method will return true on Unix, but false on * Windows. So to ensure correct behavior for relative file names on all * platforms you should never let relative paths start with a slash. E.g. * in a configuration definition file do not use something like that: *
     * <properties fileName="/subdir/my.properties"/>
     * 
* Under Windows this path would be resolved relative to the configuration * definition file. Under Unix this would be treated as an absolute path * name. * * @param basePath the base path * @param fileName the file name * @return the file object (null if no file can be obtained) */ public static File getFile(String basePath, String fileName) { // Check if the file name is absolute File f = new File(fileName); if (f.isAbsolute()) { return f; } // Check if URLs are involved URL url; try { url = new URL(new URL(basePath), fileName); } catch (MalformedURLException mex1) { try { url = new URL(fileName); } catch (MalformedURLException mex2) { url = null; } } if (url != null) { return fileFromURL(url); } return constructFile(basePath, fileName); } /** * Tries to convert the specified URL to a file object. If this fails, * null is returned. Note: This code has been copied from the * {@code FileUtils} class from Commons IO. * * @param url the URL * @return the resulting file object */ public static File fileFromURL(URL url) { if (url == null || !url.getProtocol().equals(PROTOCOL_FILE)) { return null; } else { String filename = url.getFile().replace('/', File.separatorChar); int pos = 0; while ((pos = filename.indexOf('%', pos)) >= 0) { if (pos + 2 < filename.length()) { String hexStr = filename.substring(pos + 1, pos + 3); char ch = (char) Integer.parseInt(hexStr, HEX); filename = filename.substring(0, pos) + ch + filename.substring(pos + 3); } } return new File(filename); } } /** * Convert the specified file into an URL. This method is equivalent * to file.toURI().toURL(). It was used to work around a bug in the JDK * preventing the transformation of a file into an URL if the file name * contains a '#' character. See the issue CONFIGURATION-300 for * more details. Now that we switched to JDK 1.4 we can directly use * file.toURI().toURL(). * * @param file the file to be converted into an URL */ static URL toURL(File file) throws MalformedURLException { return file.toURI().toURL(); } /** * Enables runtime exceptions for the specified configuration object. This * method can be used for configuration implementations that may face errors * on normal property access, e.g. {@code DatabaseConfiguration} or * {@code JNDIConfiguration}. Per default such errors are simply * logged and then ignored. This implementation will register a special * {@link ConfigurationErrorListener} that throws a runtime * exception (namely a {@code ConfigurationRuntimeException}) on * each received error event. * * @param src the configuration, for which runtime exceptions are to be * enabled; this configuration must be derived from * {@link EventSource} */ public static void enableRuntimeExceptions(Configuration src) { if (!(src instanceof EventSource)) { throw new IllegalArgumentException( "Configuration must be derived from EventSource!"); } ((EventSource) src).addErrorListener(new ConfigurationErrorListener() { public void configurationError(ConfigurationErrorEvent event) { // Throw a runtime exception throw new ConfigurationRuntimeException(event.getCause()); } }); } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationXMLReader.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationXMLReader100644 23655 12232154103 33472 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.IOException; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.DTDHandler; import org.xml.sax.EntityResolver; import org.xml.sax.ErrorHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.XMLReader; import org.xml.sax.helpers.AttributesImpl; /** *

A base class for "faked" {@code XMLReader} classes * that transform a configuration object in a set of SAX parsing events.

*

This class provides dummy implementations for most of the methods * defined in the {@code XMLReader} interface that are not used for this * special purpose. There will be concrete sub classes that process specific * configuration classes.

* * @author Commons * Configuration team * @version $Id: ConfigurationXMLReader.java 1208805 2011-11-30 21:33:33Z oheger $ */ public abstract class ConfigurationXMLReader implements XMLReader { /** Constant for the namespace URI.*/ protected static final String NS_URI = ""; /** Constant for the default name of the root element.*/ private static final String DEFAULT_ROOT_NAME = "config"; /** An empty attributes object.*/ private static final Attributes EMPTY_ATTRS = new AttributesImpl(); /** Stores the content handler.*/ private ContentHandler contentHandler; /** Stores an exception that occurred during parsing.*/ private SAXException exception; /** Stores the name for the root element.*/ private String rootName; /** * Creates a new instance of {@code ConfigurationXMLReader}. */ protected ConfigurationXMLReader() { super(); setRootName(DEFAULT_ROOT_NAME); } /** * Parses the acutal configuration object. The passed system ID will be * ignored. * * @param systemId the system ID (ignored) * @throws IOException if no configuration was specified * @throws SAXException if an error occurs during parsing */ public void parse(String systemId) throws IOException, SAXException { parseConfiguration(); } /** * Parses the actual configuration object. The passed input source will be * ignored. * * @param input the input source (ignored) * @throws IOException if no configuration was specified * @throws SAXException if an error occurs during parsing */ public void parse(InputSource input) throws IOException, SAXException { parseConfiguration(); } /** * Dummy implementation of the interface method. * * @param name the name of the feature * @return always false (no features are supported) */ public boolean getFeature(String name) { return false; } /** * Dummy implementation of the interface method. * * @param name the name of the feature to be set * @param value the value of the feature */ public void setFeature(String name, boolean value) { } /** * Returns the actually set content handler. * * @return the content handler */ public ContentHandler getContentHandler() { return contentHandler; } /** * Sets the content handler. The object specified here will receive SAX * events during parsing. * * @param handler the content handler */ public void setContentHandler(ContentHandler handler) { contentHandler = handler; } /** * Returns the DTD handler. This class does not support DTD handlers, * so this method always returns null. * * @return the DTD handler */ public DTDHandler getDTDHandler() { return null; } /** * Sets the DTD handler. The passed value is ignored. * * @param handler the handler to be set */ public void setDTDHandler(DTDHandler handler) { } /** * Returns the entity resolver. This class does not support an entity * resolver, so this method always returns null. * * @return the entity resolver */ public EntityResolver getEntityResolver() { return null; } /** * Sets the entity resolver. The passed value is ignored. * * @param resolver the entity resolver */ public void setEntityResolver(EntityResolver resolver) { } /** * Returns the error handler. This class does not support an error handler, * so this method always returns null. * * @return the error handler */ public ErrorHandler getErrorHandler() { return null; } /** * Sets the error handler. The passed value is ignored. * * @param handler the error handler */ public void setErrorHandler(ErrorHandler handler) { } /** * Dummy implementation of the interface method. No properties are * supported, so this method always returns null. * * @param name the name of the requested property * @return the property value */ public Object getProperty(String name) { return null; } /** * Dummy implementation of the interface method. No properties are * supported, so a call of this method just has no effect. * * @param name the property name * @param value the property value */ public void setProperty(String name, Object value) { } /** * Returns the name to be used for the root element. * * @return the name for the root element */ public String getRootName() { return rootName; } /** * Sets the name for the root element. * * @param string the name for the root element. */ public void setRootName(String string) { rootName = string; } /** * Fires a SAX element start event. * * @param name the name of the actual element * @param attribs the attributes of this element (can be null) */ protected void fireElementStart(String name, Attributes attribs) { if (getException() == null) { try { Attributes at = (attribs == null) ? EMPTY_ATTRS : attribs; getContentHandler().startElement(NS_URI, name, name, at); } catch (SAXException ex) { exception = ex; } } } /** * Fires a SAX element end event. * * @param name the name of the affected element */ protected void fireElementEnd(String name) { if (getException() == null) { try { getContentHandler().endElement(NS_URI, name, name); } catch (SAXException ex) { exception = ex; } } } /** * Fires a SAX characters event. * * @param text the text */ protected void fireCharacters(String text) { if (getException() == null) { try { char[] ch = text.toCharArray(); getContentHandler().characters(ch, 0, ch.length); } catch (SAXException ex) { exception = ex; } } } /** * Returns a reference to an exception that occurred during parsing. * * @return a SAXExcpetion or null if none occurred */ public SAXException getException() { return exception; } /** * Parses the configuration object and generates SAX events. This is the * main processing method. * * @throws IOException if no configuration has been specified * @throws SAXException if an error occurs during parsing */ protected void parseConfiguration() throws IOException, SAXException { if (getParsedConfiguration() == null) { throw new IOException("No configuration specified!"); } if (getContentHandler() != null) { exception = null; getContentHandler().startDocument(); processKeys(); if (getException() != null) { throw getException(); } getContentHandler().endDocument(); } } /** * Returns a reference to the configuration that is parsed by this object. * * @return the parsed configuration */ public abstract Configuration getParsedConfiguration(); /** * Processes all keys stored in the actual configuration. This method is * called by {@code parseConfiguration()} to start the main parsing * process. {@code parseConfiguration()} calls the content handler's * {@code startDocument()} and {@code endElement()} methods * and cares for exception handling. The remaining actions are left to this * method that must be implemented in a concrete sub class. * * @throws IOException if an IO error occurs * @throws SAXException if a SAX error occurs */ protected abstract void processKeys() throws IOException, SAXException; } ././@LongLink100644 0 0 147 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConversionException.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConversionException.ja100644 4430 12232154102 33521 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; /** * Exception thrown when a property is incompatible with the type requested. * * @since 1.0 * * @author Emmanuel Bourg * @version $Id: ConversionException.java 1208806 2011-11-30 21:34:11Z oheger $ */ public class ConversionException extends ConfigurationRuntimeException { /** * The serial version UID. */ private static final long serialVersionUID = -5167943099293540392L; /** * Constructs a new {@code ConversionException} without specified * detail message. */ public ConversionException() { super(); } /** * Constructs a new {@code ConversionException} with specified * detail message. * * @param message the error message */ public ConversionException(String message) { super(message); } /** * Constructs a new {@code ConversionException} with specified * nested {@code Throwable}. * * @param cause the exception or error that caused this exception to be thrown */ public ConversionException(Throwable cause) { super(cause); } /** * Constructs a new {@code ConversionException} with specified * detail message and nested {@code Throwable}. * * @param message the error message * @param cause the exception or error that caused this exception to be thrown */ public ConversionException(String message, Throwable cause) { super(message, cause); } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DatabaseConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DatabaseConfiguration.100644 53343 12232154102 33465 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.sql.DataSource; import org.apache.commons.logging.LogFactory; /** * Configuration stored in a database. The properties are retrieved from a * table containing at least one column for the keys, and one column for the * values. It's possible to store several configurations in the same table by * adding a column containing the name of the configuration. The name of the * table and the columns is specified in the constructor. * *

Example 1 - One configuration per table

* *
 * CREATE TABLE myconfig (
 *     `key`   VARCHAR NOT NULL PRIMARY KEY,
 *     `value` VARCHAR
 * );
 *
 * INSERT INTO myconfig (key, value) VALUES ('foo', 'bar');
 *
 *
 * Configuration config = new DatabaseConfiguration(datasource, "myconfig", "key", "value");
 * String value = config.getString("foo");
 * 
* *

Example 2 - Multiple configurations per table

* *
 * CREATE TABLE myconfigs (
 *     `name`  VARCHAR NOT NULL,
 *     `key`   VARCHAR NOT NULL,
 *     `value` VARCHAR,
 *     CONSTRAINT sys_pk_myconfigs PRIMARY KEY (`name`, `key`)
 * );
 *
 * INSERT INTO myconfigs (name, key, value) VALUES ('config1', 'key1', 'value1');
 * INSERT INTO myconfigs (name, key, value) VALUES ('config2', 'key2', 'value2');
 *
 *
 * Configuration config1 = new DatabaseConfiguration(datasource, "myconfigs", "name", "key", "value", "config1");
 * String value1 = conf.getString("key1");
 *
 * Configuration config2 = new DatabaseConfiguration(datasource, "myconfigs", "name", "key", "value", "config2");
 * String value2 = conf.getString("key2");
 * 
* The configuration can be instructed to perform commits after database updates. * This is achieved by setting the {@code commits} parameter of the * constructors to true. If commits should not be performed (which is the * default behavior), it should be ensured that the connections returned by the * {@code DataSource} are in auto-commit mode. * *

Note: Like JDBC itself, protection against SQL injection is left to the user.

* @since 1.0 * * @author Emmanuel Bourg * @version $Id: DatabaseConfiguration.java 1344442 2012-05-30 20:17:35Z oheger $ */ public class DatabaseConfiguration extends AbstractConfiguration { /** The datasource to connect to the database. */ private final DataSource datasource; /** The name of the table containing the configurations. */ private final String table; /** The column containing the name of the configuration. */ private final String nameColumn; /** The column containing the keys. */ private final String keyColumn; /** The column containing the values. */ private final String valueColumn; /** The name of the configuration. */ private final String name; /** A flag whether commits should be performed by this configuration. */ private final boolean doCommits; /** * Build a configuration from a table containing multiple configurations. * No commits are performed by the new configuration instance. * * @param datasource the datasource to connect to the database * @param table the name of the table containing the configurations * @param nameColumn the column containing the name of the configuration * @param keyColumn the column containing the keys of the configuration * @param valueColumn the column containing the values of the configuration * @param name the name of the configuration */ public DatabaseConfiguration(DataSource datasource, String table, String nameColumn, String keyColumn, String valueColumn, String name) { this(datasource, table, nameColumn, keyColumn, valueColumn, name, false); } /** * Creates a new instance of {@code DatabaseConfiguration} that operates on * a database table containing multiple configurations. * * @param datasource the {@code DataSource} to connect to the database * @param table the name of the table containing the configurations * @param nameColumn the column containing the name of the configuration * @param keyColumn the column containing the keys of the configuration * @param valueColumn the column containing the values of the configuration * @param name the name of the configuration * @param commits a flag whether the configuration should perform a commit * after a database update */ public DatabaseConfiguration(DataSource datasource, String table, String nameColumn, String keyColumn, String valueColumn, String name, boolean commits) { this.datasource = datasource; this.table = table; this.nameColumn = nameColumn; this.keyColumn = keyColumn; this.valueColumn = valueColumn; this.name = name; doCommits = commits; setLogger(LogFactory.getLog(getClass())); addErrorLogListener(); // log errors per default } /** * Build a configuration from a table. * * @param datasource the datasource to connect to the database * @param table the name of the table containing the configurations * @param keyColumn the column containing the keys of the configuration * @param valueColumn the column containing the values of the configuration */ public DatabaseConfiguration(DataSource datasource, String table, String keyColumn, String valueColumn) { this(datasource, table, null, keyColumn, valueColumn, null); } /** * Creates a new instance of {@code DatabaseConfiguration} that * operates on a database table containing a single configuration only. * * @param datasource the {@code DataSource} to connect to the database * @param table the name of the table containing the configurations * @param keyColumn the column containing the keys of the configuration * @param valueColumn the column containing the values of the configuration * @param commits a flag whether the configuration should perform a commit * after a database update */ public DatabaseConfiguration(DataSource datasource, String table, String keyColumn, String valueColumn, boolean commits) { this(datasource, table, null, keyColumn, valueColumn, null, commits); } /** * Returns a flag whether this configuration performs commits after database * updates. * * @return a flag whether commits are performed */ public boolean isDoCommits() { return doCommits; } /** * Returns the value of the specified property. If this causes a database * error, an error event will be generated of type * {@code EVENT_READ_PROPERTY} with the causing exception. The * event's {@code propertyName} is set to the passed in property key, * the {@code propertyValue} is undefined. * * @param key the key of the desired property * @return the value of this property */ public Object getProperty(String key) { Object result = null; // build the query StringBuilder query = new StringBuilder("SELECT * FROM "); query.append(table).append(" WHERE "); query.append(keyColumn).append("=?"); if (nameColumn != null) { query.append(" AND " + nameColumn + "=?"); } Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); // bind the parameters pstmt = conn.prepareStatement(query.toString()); pstmt.setString(1, key); if (nameColumn != null) { pstmt.setString(2, name); } rs = pstmt.executeQuery(); List results = new ArrayList(); while (rs.next()) { Object value = rs.getObject(valueColumn); if (isDelimiterParsingDisabled()) { results.add(value); } else { // Split value if it contains the list delimiter Iterator it = PropertyConverter.toIterator(value, getListDelimiter()); while (it.hasNext()) { results.add(it.next()); } } } if (!results.isEmpty()) { result = (results.size() > 1) ? results : results.get(0); } } catch (SQLException e) { fireError(EVENT_READ_PROPERTY, key, null, e); } finally { close(conn, pstmt, rs); } return result; } /** * Adds a property to this configuration. If this causes a database error, * an error event will be generated of type {@code EVENT_ADD_PROPERTY} * with the causing exception. The event's {@code propertyName} is * set to the passed in property key, the {@code propertyValue} * points to the passed in value. * * @param key the property key * @param obj the value of the property to add */ @Override protected void addPropertyDirect(String key, Object obj) { // build the query StringBuilder query = new StringBuilder("INSERT INTO " + table); if (nameColumn != null) { query.append(" (" + nameColumn + ", " + keyColumn + ", " + valueColumn + ") VALUES (?, ?, ?)"); } else { query.append(" (" + keyColumn + ", " + valueColumn + ") VALUES (?, ?)"); } Connection conn = null; PreparedStatement pstmt = null; try { conn = getConnection(); // bind the parameters pstmt = conn.prepareStatement(query.toString()); int index = 1; if (nameColumn != null) { pstmt.setString(index++, name); } pstmt.setString(index++, key); pstmt.setString(index++, String.valueOf(obj)); pstmt.executeUpdate(); commitIfRequired(conn); } catch (SQLException e) { fireError(EVENT_ADD_PROPERTY, key, obj, e); } finally { // clean up close(conn, pstmt, null); } } /** * Adds a property to this configuration. This implementation will * temporarily disable list delimiter parsing, so that even if the value * contains the list delimiter, only a single record will be written into * the managed table. The implementation of {@code getProperty()} * will take care about delimiters. So list delimiters are fully supported * by {@code DatabaseConfiguration}, but internally treated a bit * differently. * * @param key the key of the new property * @param value the value to be added */ @Override public void addProperty(String key, Object value) { boolean parsingFlag = isDelimiterParsingDisabled(); try { if (value instanceof String) { // temporarily disable delimiter parsing setDelimiterParsingDisabled(true); } super.addProperty(key, value); } finally { setDelimiterParsingDisabled(parsingFlag); } } /** * Checks if this configuration is empty. If this causes a database error, * an error event will be generated of type {@code EVENT_READ_PROPERTY} * with the causing exception. Both the event's {@code propertyName} * and {@code propertyValue} will be undefined. * * @return a flag whether this configuration is empty. */ public boolean isEmpty() { boolean empty = true; // build the query StringBuilder query = new StringBuilder("SELECT count(*) FROM " + table); if (nameColumn != null) { query.append(" WHERE " + nameColumn + "=?"); } Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); // bind the parameters pstmt = conn.prepareStatement(query.toString()); if (nameColumn != null) { pstmt.setString(1, name); } rs = pstmt.executeQuery(); if (rs.next()) { empty = rs.getInt(1) == 0; } } catch (SQLException e) { fireError(EVENT_READ_PROPERTY, null, null, e); } finally { // clean up close(conn, pstmt, rs); } return empty; } /** * Checks whether this configuration contains the specified key. If this * causes a database error, an error event will be generated of type * {@code EVENT_READ_PROPERTY} with the causing exception. The * event's {@code propertyName} will be set to the passed in key, the * {@code propertyValue} will be undefined. * * @param key the key to be checked * @return a flag whether this key is defined */ public boolean containsKey(String key) { boolean found = false; // build the query StringBuilder query = new StringBuilder("SELECT * FROM " + table + " WHERE " + keyColumn + "=?"); if (nameColumn != null) { query.append(" AND " + nameColumn + "=?"); } Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); // bind the parameters pstmt = conn.prepareStatement(query.toString()); pstmt.setString(1, key); if (nameColumn != null) { pstmt.setString(2, name); } rs = pstmt.executeQuery(); found = rs.next(); } catch (SQLException e) { fireError(EVENT_READ_PROPERTY, key, null, e); } finally { // clean up close(conn, pstmt, rs); } return found; } /** * Removes the specified value from this configuration. If this causes a * database error, an error event will be generated of type * {@code EVENT_CLEAR_PROPERTY} with the causing exception. The * event's {@code propertyName} will be set to the passed in key, the * {@code propertyValue} will be undefined. * * @param key the key of the property to be removed */ @Override protected void clearPropertyDirect(String key) { // build the query StringBuilder query = new StringBuilder("DELETE FROM " + table + " WHERE " + keyColumn + "=?"); if (nameColumn != null) { query.append(" AND " + nameColumn + "=?"); } Connection conn = null; PreparedStatement pstmt = null; try { conn = getConnection(); // bind the parameters pstmt = conn.prepareStatement(query.toString()); pstmt.setString(1, key); if (nameColumn != null) { pstmt.setString(2, name); } pstmt.executeUpdate(); commitIfRequired(conn); } catch (SQLException e) { fireError(EVENT_CLEAR_PROPERTY, key, null, e); } finally { // clean up close(conn, pstmt, null); } } /** * Removes all entries from this configuration. If this causes a database * error, an error event will be generated of type * {@code EVENT_CLEAR} with the causing exception. Both the * event's {@code propertyName} and the {@code propertyValue} * will be undefined. */ @Override public void clear() { fireEvent(EVENT_CLEAR, null, null, true); // build the query StringBuilder query = new StringBuilder("DELETE FROM " + table); if (nameColumn != null) { query.append(" WHERE " + nameColumn + "=?"); } Connection conn = null; PreparedStatement pstmt = null; try { conn = getConnection(); // bind the parameters pstmt = conn.prepareStatement(query.toString()); if (nameColumn != null) { pstmt.setString(1, name); } pstmt.executeUpdate(); commitIfRequired(conn); } catch (SQLException e) { fireError(EVENT_CLEAR, null, null, e); } finally { // clean up close(conn, pstmt, null); } fireEvent(EVENT_CLEAR, null, null, false); } /** * Returns an iterator with the names of all properties contained in this * configuration. If this causes a database * error, an error event will be generated of type * {@code EVENT_READ_PROPERTY} with the causing exception. Both the * event's {@code propertyName} and the {@code propertyValue} * will be undefined. * @return an iterator with the contained keys (an empty iterator in case * of an error) */ public Iterator getKeys() { Collection keys = new ArrayList(); // build the query StringBuilder query = new StringBuilder("SELECT DISTINCT " + keyColumn + " FROM " + table); if (nameColumn != null) { query.append(" WHERE " + nameColumn + "=?"); } Connection conn = null; PreparedStatement pstmt = null; ResultSet rs = null; try { conn = getConnection(); // bind the parameters pstmt = conn.prepareStatement(query.toString()); if (nameColumn != null) { pstmt.setString(1, name); } rs = pstmt.executeQuery(); while (rs.next()) { keys.add(rs.getString(1)); } } catch (SQLException e) { fireError(EVENT_READ_PROPERTY, null, null, e); } finally { // clean up close(conn, pstmt, rs); } return keys.iterator(); } /** * Returns the used {@code DataSource} object. * * @return the data source * @since 1.4 */ public DataSource getDatasource() { return datasource; } /** * Returns a {@code Connection} object. This method is called when * ever the database is to be accessed. This implementation returns a * connection from the current {@code DataSource}. * * @return the {@code Connection} object to be used * @throws SQLException if an error occurs * @since 1.4 * @deprecated Use a custom data source to change the connection used by the * class. To be removed in Commons Configuration 2.0 */ @Deprecated protected Connection getConnection() throws SQLException { return getDatasource().getConnection(); } /** * Close the specified database objects. * Avoid closing if null and hide any SQLExceptions that occur. * * @param conn The database connection to close * @param stmt The statement to close * @param rs the result set to close */ private void close(Connection conn, Statement stmt, ResultSet rs) { try { if (rs != null) { rs.close(); } } catch (SQLException e) { getLogger().error("An error occurred on closing the result set", e); } try { if (stmt != null) { stmt.close(); } } catch (SQLException e) { getLogger().error("An error occured on closing the statement", e); } try { if (conn != null) { conn.close(); } } catch (SQLException e) { getLogger().error("An error occured on closing the connection", e); } } /** * Performs a commit if needed. This method is called after updates of the * managed database table. If the configuration should perform commits, it * does so now. * * @param conn the active connection * @throws SQLException if an error occurs */ private void commitIfRequired(Connection conn) throws SQLException { if (isDoCommits()) { conn.commit(); } } } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DataConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DataConfiguration.java100644 211653 12232154102 33514 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.awt.Color; import java.io.Serializable; import java.lang.reflect.Array; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.StringUtils; /** * Decorator providing additional getters for any Configuration. This extended * Configuration supports more types: *
    *
  • {@link java.net.URL}
  • *
  • {@link java.util.Locale}
  • *
  • {@link java.util.Date}
  • *
  • {@link java.util.Calendar}
  • *
  • {@link java.awt.Color}
  • *
  • {@link java.net.InetAddress}
  • *
  • {@link javax.mail.internet.InternetAddress} (requires Javamail in the classpath)
  • *
  • {@link java.lang.Enum} (Java 5 enumeration types)
  • *
* * Lists and arrays are available for all types. * *

Example

* * Configuration file config.properties: *
 * title.color = #0000FF
 * remote.host = 192.168.0.53
 * default.locales = fr,en,de
 * email.contact = ebourg@apache.org, oheger@apache.org
 * 
* * Usage: * *
 * DataConfiguration config = new DataConfiguration(new PropertiesConfiguration("config.properties"));
 *
 * // retrieve a property using a specialized getter
 * Color color = config.getColor("title.color");
 *
 * // retrieve a property using a generic getter
 * InetAddress host = (InetAddress) config.get(InetAddress.class, "remote.host");
 * Locale[] locales = (Locale[]) config.getArray(Locale.class, "default.locales");
 * List contacts = config.getList(InternetAddress.class, "email.contact");
 * 
* *

Dates

* * Date objects are expected to be formatted with the pattern yyyy-MM-dd HH:mm:ss. * This default format can be changed by specifying another format in the * getters, or by putting a date format in the configuration under the key * org.apache.commons.configuration.format.date. * * @author Emmanuel Bourg * @version $Id: DataConfiguration.java 1234985 2012-01-23 21:09:09Z oheger $ * @since 1.1 */ public class DataConfiguration extends AbstractConfiguration implements Serializable { /** The key of the property storing the user defined date format. */ public static final String DATE_FORMAT_KEY = "org.apache.commons.configuration.format.date"; /** The default format for dates. */ public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; /** * The serial version UID. */ private static final long serialVersionUID = -69011336405718640L; /** Stores the wrapped configuration.*/ protected Configuration configuration; /** * Creates a new instance of {@code DataConfiguration} and sets the * wrapped configuration. * * @param configuration the wrapped configuration */ public DataConfiguration(Configuration configuration) { this.configuration = configuration; } /** * Return the configuration decorated by this DataConfiguration. * * @return the wrapped configuration */ public Configuration getConfiguration() { return configuration; } public Object getProperty(String key) { return configuration.getProperty(key); } @Override protected void addPropertyDirect(String key, Object obj) { if (configuration instanceof AbstractConfiguration) { ((AbstractConfiguration) configuration).addPropertyDirect(key, obj); } else { configuration.addProperty(key, obj); } } @Override public void addProperty(String key, Object value) { getConfiguration().addProperty(key, value); } public boolean isEmpty() { return configuration.isEmpty(); } public boolean containsKey(String key) { return configuration.containsKey(key); } @Override public void clearProperty(String key) { configuration.clearProperty(key); } @Override public void setProperty(String key, Object value) { configuration.setProperty(key, value); } public Iterator getKeys() { return configuration.getKeys(); } /** * Get an object of the specified type associated with the given * configuration key. If the key doesn't map to an existing object, the * method returns null unless {@link #isThrowExceptionOnMissing()} is set * to true. * * @param the target type of the value * @param cls the target class of the value * @param key the key of the value * * @return the value of the requested type for the key * * @throws NoSuchElementException if the key doesn't map to an existing * object and throwExceptionOnMissing=true * @throws ConversionException if the value is not compatible with the requested type * * @since 1.5 */ public T get(Class cls, String key) { T value = get(cls, key, null); if (value != null) { return value; } else if (isThrowExceptionOnMissing()) { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } else { return null; } } /** * Get an object of the specified type associated with the given * configuration key. If the key doesn't map to an existing object, the * default value is returned. * * @param the target type of the value * @param cls the target class of the value * @param key the key of the value * @param defaultValue the default value * * @return the value of the requested type for the key * * @throws ConversionException if the value is not compatible with the requested type * * @since 1.5 */ public T get(Class cls, String key, T defaultValue) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } if (Date.class.equals(cls) || Calendar.class.equals(cls)) { return convert(cls, key, interpolate(value), new String[] {getDefaultDateFormat()}); } else { return convert(cls, key, interpolate(value), null); } } /** * Get a list of typed objects associated with the given configuration key. * If the key doesn't map to an existing object, an empty list is returned. * * @param the type expected for the elements of the list * @param cls the class expected for the elements of the list * @param key The configuration key. * @return The associated list if the key is found. * * @throws ConversionException is thrown if the key maps to an object that * is not compatible with a list of the specified class. * * @since 1.5 */ public List getList(Class cls, String key) { return getList(cls, key, new ArrayList()); } /** * Get a list of typed objects associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param the type expected for the elements of the list * @param cls the class expected for the elements of the list * @param key the configuration key. * @param defaultValue the default value. * @return The associated List. * * @throws ConversionException is thrown if the key maps to an object that * is not compatible with a list of the specified class. * * @since 1.5 */ public List getList(Class cls, String key, List defaultValue) { Object value = getProperty(key); Class valueClass = value != null ? value.getClass() : null; List list; if (value == null || (value instanceof String && StringUtils.isEmpty((String) value))) { // the value is null or is an empty string list = defaultValue; } else { list = new ArrayList(); Object[] params = null; if (cls.equals(Date.class) || cls.equals(Calendar.class)) { params = new Object[] {getDefaultDateFormat()}; } if (valueClass.isArray()) { // get the class of the objects contained in the array Class arrayType = valueClass.getComponentType(); int length = Array.getLength(value); if (arrayType.equals(cls) || (arrayType.isPrimitive() && cls.equals(ClassUtils.primitiveToWrapper(arrayType)))) { // the value is an array of the specified type, or an array // of the primitive type derived from the specified type for (int i = 0; i < length; i++) { list.add(cls.cast(Array.get(value, i))); } } else { // attempt to convert the elements of the array for (int i = 0; i < length; i++) { list.add(convert(cls, key, interpolate(Array.get(value, i)), params)); } } } else if (value instanceof Collection) { Collection values = (Collection) value; for (Object o : values) { list.add(convert(cls, key, interpolate(o), params)); } } else { // attempt to convert a single value list.add(convert(cls, key, interpolate(value), params)); } } return list; } /** * Get an array of typed objects associated with the given configuration key. * If the key doesn't map to an existing object, an empty list is returned. * * @param cls the type expected for the elements of the array * @param key The configuration key. * @return The associated array if the key is found, and the value compatible with the type specified. * * @throws ConversionException is thrown if the key maps to an object that * is not compatible with a list of the specified class. * * @since 1.5 */ public Object getArray(Class cls, String key) { return getArray(cls, key, Array.newInstance(cls, 0)); } /** * Get an array of typed objects associated with the given configuration key. * If the key doesn't map to an existing object, the default value is returned. * * @param cls the type expected for the elements of the array * @param key the configuration key. * @param defaultValue the default value * @return The associated array if the key is found, and the value compatible with the type specified. * * @throws ConversionException is thrown if the key maps to an object that * is not compatible with an array of the specified class. * @throws IllegalArgumentException if the default value is not an array of the specified type * * @since 1.5 */ public Object getArray(Class cls, String key, Object defaultValue) { // check the type of the default value if (defaultValue != null && (!defaultValue.getClass().isArray() || !cls .isAssignableFrom(defaultValue.getClass() .getComponentType()))) { throw new IllegalArgumentException( "The type of the default value (" + defaultValue.getClass() + ")" + " is not an array of the specified class (" + cls + ")"); } if (cls.isPrimitive()) { return getPrimitiveArray(cls, key, defaultValue); } List list = getList(cls, key); if (list.isEmpty()) { return defaultValue; } else { return list.toArray((Object[]) Array.newInstance(cls, list.size())); } } /** * Get an array of primitive values associated with the given configuration key. * If the key doesn't map to an existing object, the default value is returned. * * @param cls the primitive type expected for the elements of the array * @param key the configuration key. * @param defaultValue the default value * @return The associated array if the key is found, and the value compatible with the type specified. * * @throws ConversionException is thrown if the key maps to an object that * is not compatible with an array of the specified class. * * @since 1.5 */ private Object getPrimitiveArray(Class cls, String key, Object defaultValue) { Object value = getProperty(key); Class valueClass = value != null ? value.getClass() : null; Object array; if (value == null || (value instanceof String && StringUtils.isEmpty((String) value))) { // the value is null or is an empty string array = defaultValue; } else { if (valueClass.isArray()) { // get the class of the objects contained in the array Class arrayType = valueClass.getComponentType(); int length = Array.getLength(value); if (arrayType.equals(cls)) { // the value is an array of the same primitive type array = value; } else if (arrayType.equals(ClassUtils.primitiveToWrapper(cls))) { // the value is an array of the wrapper type derived from the specified primitive type array = Array.newInstance(cls, length); for (int i = 0; i < length; i++) { Array.set(array, i, Array.get(value, i)); } } else { throw new ConversionException('\'' + key + "' (" + arrayType + ")" + " doesn't map to a compatible array of " + cls); } } else if (value instanceof Collection) { Collection values = (Collection) value; array = Array.newInstance(cls, values.size()); int i = 0; for (Object o : values) { // This is safe because PropertyConverter can handle // conversion to wrapper classes correctly. @SuppressWarnings("unchecked") Object convertedValue = convert(ClassUtils.primitiveToWrapper(cls), key, interpolate(o), null); Array.set(array, i++, convertedValue); } } else { // attempt to convert a single value // This is safe because PropertyConverter can handle // conversion to wrapper classes correctly. @SuppressWarnings("unchecked") Object convertedValue = convert(ClassUtils.primitiveToWrapper(cls), key, interpolate(value), null); // create an array of one element array = Array.newInstance(cls, 1); Array.set(array, 0, convertedValue); } } return array; } /** * Get a list of Boolean objects associated with the given * configuration key. If the key doesn't map to an existing object * an empty list is returned. * * @param key The configuration key. * @return The associated Boolean list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of booleans. */ public List getBooleanList(String key) { return getBooleanList(key, new ArrayList()); } /** * Get a list of Boolean objects associated with the given * configuration key. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Booleans. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of booleans. */ public List getBooleanList(String key, List defaultValue) { return getList(Boolean.class, key, defaultValue); } /** * Get an array of boolean primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated boolean array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of booleans. */ public boolean[] getBooleanArray(String key) { return (boolean[]) getArray(Boolean.TYPE, key); } /** * Get an array of boolean primitives associated with the given * configuration key. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated boolean array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of booleans. */ public boolean[] getBooleanArray(String key, boolean[] defaultValue) { return (boolean[]) getArray(Boolean.TYPE, key, defaultValue); } /** * Get a list of Byte objects associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated Byte list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of bytes. */ public List getByteList(String key) { return getByteList(key, new ArrayList()); } /** * Get a list of Byte objects associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Bytes. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of bytes. */ public List getByteList(String key, List defaultValue) { return getList(Byte.class, key, defaultValue); } /** * Get an array of byte primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated byte array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of bytes. */ public byte[] getByteArray(String key) { return getByteArray(key, new byte[0]); } /** * Get an array of byte primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated byte array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of bytes. */ public byte[] getByteArray(String key, byte[] defaultValue) { return (byte[]) getArray(Byte.TYPE, key, defaultValue); } /** * Get a list of Short objects associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated Short list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of shorts. */ public List getShortList(String key) { return getShortList(key, new ArrayList()); } /** * Get a list of Short objects associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Shorts. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of shorts. */ public List getShortList(String key, List defaultValue) { return getList(Short.class, key, defaultValue); } /** * Get an array of short primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated short array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of shorts. */ public short[] getShortArray(String key) { return getShortArray(key, new short[0]); } /** * Get an array of short primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated short array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of shorts. */ public short[] getShortArray(String key, short[] defaultValue) { return (short[]) getArray(Short.TYPE, key, defaultValue); } /** * Get a list of Integer objects associated with the given * configuration key. If the key doesn't map to an existing object * an empty list is returned. * * @param key The configuration key. * @return The associated Integer list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of integers. */ public List getIntegerList(String key) { return getIntegerList(key, new ArrayList()); } /** * Get a list of Integer objects associated with the given * configuration key. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Integers. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of integers. */ public List getIntegerList(String key, List defaultValue) { return getList(Integer.class, key, defaultValue); } /** * Get an array of int primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated int array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of integers. */ public int[] getIntArray(String key) { return getIntArray(key, new int[0]); } /** * Get an array of int primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated int array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of integers. */ public int[] getIntArray(String key, int[] defaultValue) { return (int[]) getArray(Integer.TYPE, key, defaultValue); } /** * Get a list of Long objects associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated Long list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of longs. */ public List getLongList(String key) { return getLongList(key, new ArrayList()); } /** * Get a list of Long objects associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Longs. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of longs. */ public List getLongList(String key, List defaultValue) { return getList(Long.class, key, defaultValue); } /** * Get an array of long primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated long array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of longs. */ public long[] getLongArray(String key) { return getLongArray(key, new long[0]); } /** * Get an array of long primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated long array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of longs. */ public long[] getLongArray(String key, long[] defaultValue) { return (long[]) getArray(Long.TYPE, key, defaultValue); } /** * Get a list of Float objects associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated Float list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of floats. */ public List getFloatList(String key) { return getFloatList(key, new ArrayList()); } /** * Get a list of Float objects associated with the given * configuration key. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Floats. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of floats. */ public List getFloatList(String key, List defaultValue) { return getList(Float.class, key, defaultValue); } /** * Get an array of float primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated float array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of floats. */ public float[] getFloatArray(String key) { return getFloatArray(key, new float[0]); } /** * Get an array of float primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated float array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of floats. */ public float[] getFloatArray(String key, float[] defaultValue) { return (float[]) getArray(Float.TYPE, key, defaultValue); } /** * Get a list of Double objects associated with the given * configuration key. If the key doesn't map to an existing object * an empty list is returned. * * @param key The configuration key. * @return The associated Double list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of doubles. */ public List getDoubleList(String key) { return getDoubleList(key, new ArrayList()); } /** * Get a list of Double objects associated with the given * configuration key. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Doubles. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of doubles. */ public List getDoubleList(String key, List defaultValue) { return getList(Double.class, key, defaultValue); } /** * Get an array of double primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated double array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of doubles. */ public double[] getDoubleArray(String key) { return getDoubleArray(key, new double[0]); } /** * Get an array of double primitives associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated double array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of doubles. */ public double[] getDoubleArray(String key, double[] defaultValue) { return (double[]) getArray(Double.TYPE, key, defaultValue); } /** * Get a list of BigIntegers associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated BigInteger list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of BigIntegers. */ public List getBigIntegerList(String key) { return getBigIntegerList(key, new ArrayList()); } /** * Get a list of BigIntegers associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of BigIntegers. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of BigIntegers. */ public List getBigIntegerList(String key, List defaultValue) { return getList(BigInteger.class, key, defaultValue); } /** * Get an array of BigIntegers associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated BigInteger array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of BigIntegers. */ public BigInteger[] getBigIntegerArray(String key) { return getBigIntegerArray(key, new BigInteger[0]); } /** * Get an array of BigIntegers associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated BigInteger array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of BigIntegers. */ public BigInteger[] getBigIntegerArray(String key, BigInteger[] defaultValue) { return (BigInteger[]) getArray(BigInteger.class, key, defaultValue); } /** * Get a list of BigDecimals associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated BigDecimal list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of BigDecimals. */ public List getBigDecimalList(String key) { return getBigDecimalList(key, new ArrayList()); } /** * Get a list of BigDecimals associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of BigDecimals. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of BigDecimals. */ public List getBigDecimalList(String key, List defaultValue) { return getList(BigDecimal.class, key, defaultValue); } /** * Get an array of BigDecimals associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated BigDecimal array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of BigDecimals. */ public BigDecimal[] getBigDecimalArray(String key) { return getBigDecimalArray(key, new BigDecimal[0]); } /** * Get an array of BigDecimals associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated BigDecimal array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of BigDecimals. */ public BigDecimal[] getBigDecimalArray(String key, BigDecimal[] defaultValue) { return (BigDecimal[]) getArray(BigDecimal.class, key, defaultValue); } /** * Get an URL associated with the given configuration key. * * @param key The configuration key. * @return The associated URL. * * @throws ConversionException is thrown if the key maps to an * object that is not an URL. */ public URL getURL(String key) { return get(URL.class, key); } /** * Get an URL associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated URL. * * @throws ConversionException is thrown if the key maps to an * object that is not an URL. */ public URL getURL(String key, URL defaultValue) { return get(URL.class, key, defaultValue); } /** * Get a list of URLs associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated URL list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of URLs. */ public List getURLList(String key) { return getURLList(key, new ArrayList()); } /** * Get a list of URLs associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of URLs. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of URLs. */ public List getURLList(String key, List defaultValue) { return getList(URL.class, key, defaultValue); } /** * Get an array of URLs associated with the given configuration key. * If the key doesn't map to an existing object an empty array is returned. * * @param key The configuration key. * @return The associated URL array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of URLs. */ public URL[] getURLArray(String key) { return getURLArray(key, new URL[0]); } /** * Get an array of URLs associated with the given configuration key. * If the key doesn't map to an existing object an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated URL array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of URLs. */ public URL[] getURLArray(String key, URL[] defaultValue) { return (URL[]) getArray(URL.class, key, defaultValue); } /** * Get a Date associated with the given configuration key. If the property * is a String, it will be parsed with the format defined by the user in * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the * {@link #DEFAULT_DATE_FORMAT} pattern. * * @param key The configuration key. * @return The associated Date. * * @throws ConversionException is thrown if the key maps to an * object that is not a Date. */ public Date getDate(String key) { return get(Date.class, key); } /** * Get a Date associated with the given configuration key. If the property * is a String, it will be parsed with the specified format pattern. * * @param key The configuration key. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Date * * @throws ConversionException is thrown if the key maps to an * object that is not a Date. */ public Date getDate(String key, String format) { Date value = getDate(key, null, format); if (value != null) { return value; } else if (isThrowExceptionOnMissing()) { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } else { return null; } } /** * Get a Date associated with the given configuration key. If the property * is a String, it will be parsed with the format defined by the user in * the {@link #DATE_FORMAT_KEY} property, or if it's not defined with the * {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map to an * existing object, the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated Date. * * @throws ConversionException is thrown if the key maps to an * object that is not a Date. */ public Date getDate(String key, Date defaultValue) { return getDate(key, defaultValue, getDefaultDateFormat()); } /** * Get a Date associated with the given configuration key. If the property * is a String, it will be parsed with the specified format pattern. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Date. * * @throws ConversionException is thrown if the key maps to an * object that is not a Date. */ public Date getDate(String key, Date defaultValue, String format) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toDate(interpolate(value), format); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a Date", e); } } } public List getDateList(String key) { return getDateList(key, new ArrayList()); } /** * Get a list of Dates associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * specified format pattern. If the key doesn't map to an existing object * an empty list is returned. * * @param key The configuration key. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Date list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Dates. */ public List getDateList(String key, String format) { return getDateList(key, new ArrayList(), format); } /** * Get a list of Dates associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * format defined by the user in the {@link #DATE_FORMAT_KEY} property, * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated Date list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Dates. */ public List getDateList(String key, List defaultValue) { return getDateList(key, defaultValue, getDefaultDateFormat()); } /** * Get a list of Dates associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * specified format pattern. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Date list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Dates. */ public List getDateList(String key, List defaultValue, String format) { Object value = getProperty(key); List list; if (value == null || (value instanceof String && StringUtils.isEmpty((String) value))) { list = defaultValue; } else if (value.getClass().isArray()) { list = new ArrayList(); int length = Array.getLength(value); for (int i = 0; i < length; i++) { list.add(convert(Date.class, key, interpolate(Array.get(value, i)), new String[] {format})); } } else if (value instanceof Collection) { Collection values = (Collection) value; list = new ArrayList(); for (Object o : values) { list.add(convert(Date.class, key, interpolate(o), new String[] {format})); } } else { // attempt to convert a single value list = new ArrayList(); list.add(convert(Date.class, key, interpolate(value), new String[] {format})); } return list; } /** * Get an array of Dates associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * format defined by the user in the {@link #DATE_FORMAT_KEY} property, * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern. * If the key doesn't map to an existing object an empty array is returned. * * @param key The configuration key. * @return The associated Date array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Dates. */ public Date[] getDateArray(String key) { return getDateArray(key, new Date[0]); } /** * Get an array of Dates associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * specified format pattern. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Date array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Dates. */ public Date[] getDateArray(String key, String format) { return getDateArray(key, new Date[0], format); } /** * Get an array of Dates associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * format defined by the user in the {@link #DATE_FORMAT_KEY} property, * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern. * If the key doesn't map to an existing object an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated Date array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Dates. */ public Date[] getDateArray(String key, Date[] defaultValue) { return getDateArray(key, defaultValue, getDefaultDateFormat()); } /** * Get an array of Dates associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * specified format pattern. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Date array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Dates. */ public Date[] getDateArray(String key, Date[] defaultValue, String format) { List list = getDateList(key, format); if (list.isEmpty()) { return defaultValue; } else { return list.toArray(new Date[list.size()]); } } /** * Get a Calendar associated with the given configuration key. If the * property is a String, it will be parsed with the format defined by the * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined * with the {@link #DEFAULT_DATE_FORMAT} pattern. * * @param key The configuration key. * @return The associated Calendar. * * @throws ConversionException is thrown if the key maps to an * object that is not a Calendar. */ public Calendar getCalendar(String key) { return get(Calendar.class, key); } /** * Get a Calendar associated with the given configuration key. If the * property is a String, it will be parsed with the specified format * pattern. * * @param key The configuration key. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Calendar * * @throws ConversionException is thrown if the key maps to an * object that is not a Calendar. */ public Calendar getCalendar(String key, String format) { Calendar value = getCalendar(key, null, format); if (value != null) { return value; } else if (isThrowExceptionOnMissing()) { throw new NoSuchElementException('\'' + key + "' doesn't map to an existing object"); } else { return null; } } /** * Get a Calendar associated with the given configuration key. If the * property is a String, it will be parsed with the format defined by the * user in the {@link #DATE_FORMAT_KEY} property, or if it's not defined * with the {@link #DEFAULT_DATE_FORMAT} pattern. If the key doesn't map * to an existing object, the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated Calendar. * * @throws ConversionException is thrown if the key maps to an * object that is not a Calendar. */ public Calendar getCalendar(String key, Calendar defaultValue) { return getCalendar(key, defaultValue, getDefaultDateFormat()); } /** * Get a Calendar associated with the given configuration key. If the * property is a String, it will be parsed with the specified format * pattern. If the key doesn't map to an existing object, the default * value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Calendar. * * @throws ConversionException is thrown if the key maps to an * object that is not a Calendar. */ public Calendar getCalendar(String key, Calendar defaultValue, String format) { Object value = resolveContainerStore(key); if (value == null) { return defaultValue; } else { try { return PropertyConverter.toCalendar(interpolate(value), format); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a Calendar", e); } } } /** * Get a list of Calendars associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * format defined by the user in the {@link #DATE_FORMAT_KEY} property, * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated Calendar list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Calendars. */ public List getCalendarList(String key) { return getCalendarList(key, new ArrayList()); } /** * Get a list of Calendars associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * specified format pattern. If the key doesn't map to an existing object * an empty list is returned. * * @param key The configuration key. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Calendar list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Calendars. */ public List getCalendarList(String key, String format) { return getCalendarList(key, new ArrayList(), format); } /** * Get a list of Calendars associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * format defined by the user in the {@link #DATE_FORMAT_KEY} property, * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated Calendar list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Calendars. */ public List getCalendarList(String key, List defaultValue) { return getCalendarList(key, defaultValue, getDefaultDateFormat()); } /** * Get a list of Calendars associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * specified format pattern. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Calendar list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Calendars. */ public List getCalendarList(String key, List defaultValue, String format) { Object value = getProperty(key); List list; if (value == null || (value instanceof String && StringUtils.isEmpty((String) value))) { list = defaultValue; } else if (value.getClass().isArray()) { list = new ArrayList(); int length = Array.getLength(value); for (int i = 0; i < length; i++) { list.add(convert(Calendar.class, key, interpolate(Array.get(value, i)), new String[] {format})); } } else if (value instanceof Collection) { Collection values = (Collection) value; list = new ArrayList(); for (Object o : values) { list.add(convert(Calendar.class, key, interpolate(o), new String[] {format})); } } else { // attempt to convert a single value list = new ArrayList(); list.add(convert(Calendar.class, key, interpolate(value), new String[] {format})); } return list; } /** * Get an array of Calendars associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * format defined by the user in the {@link #DATE_FORMAT_KEY} property, * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern. * If the key doesn't map to an existing object an empty array is returned. * * @param key The configuration key. * @return The associated Calendar array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Calendars. */ public Calendar[] getCalendarArray(String key) { return getCalendarArray(key, new Calendar[0]); } /** * Get an array of Calendars associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * specified format pattern. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Calendar array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Calendars. */ public Calendar[] getCalendarArray(String key, String format) { return getCalendarArray(key, new Calendar[0], format); } /** * Get an array of Calendars associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * format defined by the user in the {@link #DATE_FORMAT_KEY} property, * or if it's not defined with the {@link #DEFAULT_DATE_FORMAT} pattern. * If the key doesn't map to an existing object an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated Calendar array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Calendars. */ public Calendar[] getCalendarArray(String key, Calendar[] defaultValue) { return getCalendarArray(key, defaultValue, getDefaultDateFormat()); } /** * Get an array of Calendars associated with the given configuration key. * If the property is a list of Strings, they will be parsed with the * specified format pattern. If the key doesn't map to an existing object, * the default value is returned. * * @param key The configuration key. * @param defaultValue The default value. * @param format The non-localized {@link java.text.DateFormat} pattern. * @return The associated Calendar array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Calendars. */ public Calendar[] getCalendarArray(String key, Calendar[] defaultValue, String format) { List list = getCalendarList(key, format); if (list.isEmpty()) { return defaultValue; } else { return list.toArray(new Calendar[list.size()]); } } /** * Returns the date format specified by the user in the DATE_FORMAT_KEY * property, or the default format otherwise. * * @return the default date format */ private String getDefaultDateFormat() { return getString(DATE_FORMAT_KEY, DEFAULT_DATE_FORMAT); } /** * Get a Locale associated with the given configuration key. * * @param key The configuration key. * @return The associated Locale. * * @throws ConversionException is thrown if the key maps to an * object that is not a Locale. */ public Locale getLocale(String key) { return get(Locale.class, key); } /** * Get a Locale associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated Locale. * * @throws ConversionException is thrown if the key maps to an * object that is not a Locale. */ public Locale getLocale(String key, Locale defaultValue) { return get(Locale.class, key, defaultValue); } /** * Get a list of Locales associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated Locale list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Locales. */ public List getLocaleList(String key) { return getLocaleList(key, new ArrayList()); } /** * Get a list of Locales associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Locales. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Locales. */ public List getLocaleList(String key, List defaultValue) { return getList(Locale.class, key, defaultValue); } /** * Get an array of Locales associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated Locale array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Locales. */ public Locale[] getLocaleArray(String key) { return getLocaleArray(key, new Locale[0]); } /** * Get an array of Locales associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated Locale array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Locales. */ public Locale[] getLocaleArray(String key, Locale[] defaultValue) { return (Locale[]) getArray(Locale.class, key, defaultValue); } /** * Get a Color associated with the given configuration key. * * @param key The configuration key. * @return The associated Color. * * @throws ConversionException is thrown if the key maps to an * object that is not a Color. */ public Color getColor(String key) { return get(Color.class, key); } /** * Get a Color associated with the given configuration key. * If the key doesn't map to an existing object, the default value * is returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated Color. * * @throws ConversionException is thrown if the key maps to an * object that is not a Color. */ public Color getColor(String key, Color defaultValue) { return get(Color.class, key, defaultValue); } /** * Get a list of Colors associated with the given configuration key. * If the key doesn't map to an existing object an empty list is returned. * * @param key The configuration key. * @return The associated Color list if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Colors. */ public List getColorList(String key) { return getColorList(key, new ArrayList()); } /** * Get a list of Colors associated with the given configuration key. * If the key doesn't map to an existing object, the default value is * returned. * * @param key The configuration key. * @param defaultValue The default value. * @return The associated List of Colors. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Colors. */ public List getColorList(String key, List defaultValue) { return getList(Color.class, key, defaultValue); } /** * Get an array of Colors associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @return The associated Color array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Colors. */ public Color[] getColorArray(String key) { return getColorArray(key, new Color[0]); } /** * Get an array of Colors associated with the given * configuration key. If the key doesn't map to an existing object * an empty array is returned. * * @param key The configuration key. * @param defaultValue the default value, which will be returned if the property is not found * @return The associated Color array if the key is found. * * @throws ConversionException is thrown if the key maps to an * object that is not a list of Colors. */ public Color[] getColorArray(String key, Color[] defaultValue) { return (Color[]) getArray(Color.class, key, defaultValue); } /** * Helper method for performing a type conversion using the * {@code PropertyConverter} class. * * @param the target type of the conversion * @param cls the target class of the conversion * @param key the configuration key * @param value the value to be converted * @param params additional parameters * @throws ConversionException if the value is not compatible with the * requested type */ private static T convert(Class cls, String key, Object value, Object[] params) { try { Object result = PropertyConverter.to(cls, value, params); // Will not throw a ClassCastException because PropertyConverter // would have thrown a ConversionException if conversion had failed. return cls.cast(result); } catch (ConversionException e) { throw new ConversionException('\'' + key + "' doesn't map to a " + cls, e); } } } ././@LongLink100644 0 0 157 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DefaultConfigurationBuilder.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DefaultConfigurationBu100644 206136 12232154102 33576 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.net.URL; import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.configuration.beanutils.BeanDeclaration; import org.apache.commons.configuration.beanutils.BeanFactory; import org.apache.commons.configuration.beanutils.BeanHelper; import org.apache.commons.configuration.beanutils.DefaultBeanFactory; import org.apache.commons.configuration.beanutils.XMLBeanDeclaration; import org.apache.commons.configuration.event.ConfigurationErrorListener; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; import org.apache.commons.configuration.resolver.CatalogResolver; import org.apache.commons.configuration.resolver.EntityRegistry; import org.apache.commons.configuration.resolver.EntityResolverSupport; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultExpressionEngine; import org.apache.commons.configuration.tree.OverrideCombiner; import org.apache.commons.configuration.tree.UnionCombiner; import org.apache.commons.lang.text.StrLookup; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.EntityResolver; /** *

* A factory class that creates a composite configuration from an XML based * configuration definition file. *

*

* This class provides an easy and flexible means for loading multiple * configuration sources and combining the results into a single configuration * object. The sources to be loaded are defined in an XML document that can * contain certain tags representing the different supported configuration * classes. If such a tag is found, the corresponding {@code Configuration} * class is instantiated and initialized using the classes of the * {@code beanutils} package (namely * {@link org.apache.commons.configuration.beanutils.XMLBeanDeclaration XMLBeanDeclaration} * will be used to extract the configuration's initialization parameters, which * allows for complex initialization scenarios). *

*

* It is also possible to add custom tags to the configuration definition file. * For this purpose register your own {@code ConfigurationProvider} * implementation for your tag using the {@code addConfigurationProvider()} * method. This provider will then be called when the corresponding custom tag * is detected. For the default configuration classes providers are already * registered. *

*

* The configuration definition file has the following basic structure: *

*

* *

 * <configuration systemProperties="properties file name">
 *   <header>
 *     <!-- Optional meta information about the composite configuration -->
 *   </header>
 *   <override>
 *     <!-- Declarations for override configurations -->
 *   </override>
 *   <additional>
 *     <!-- Declarations for union configurations -->
 *   </additional>
 * </configuration>
 * 
* *

*

* The name of the root element (here {@code configuration}) is * arbitrary. The optional systemProperties attribute identifies the path to * a property file containing properties that should be added to the system * properties. If specified on the root element, the system properties are * set before the rest of the configuration is processed. *

*

* There are two sections (both of them are optional) for declaring * override and additional configurations. Configurations * in the former section are evaluated in the order of their declaration, and * properties of configurations declared earlier hide those of configurations * declared later. Configurations in the latter section are combined to a union * configuration, i.e. all of their properties are added to a large hierarchical * configuration. Configuration declarations that occur as direct children of * the root element are treated as override declarations. *

*

* Each configuration declaration consists of a tag whose name is associated * with a {@code ConfigurationProvider}. This can be one of the * predefined tags like {@code properties}, or {@code xml}, or * a custom tag, for which a configuration provider was registered. Attributes * and sub elements with specific initialization parameters can be added. There * are some reserved attributes with a special meaning that can be used in every * configuration declaration: *

*

* * * * * * * * * * * * * * * * * *
AttributeMeaning
{@code config-name}Allows to specify a name for this configuration. This name can be used * to obtain a reference to the configuration from the resulting combined * configuration (see below).
{@code config-at}With this attribute an optional prefix can be specified for the * properties of the corresponding configuration.
{@code config-optional}Declares a configuration as optional. This means that errors that occur * when creating the configuration are ignored. (However * {@link org.apache.commons.configuration.event.ConfigurationErrorListener}s * registered at the builder instance will get notified about this error: they * receive an event of type {@code EVENT_ERR_LOAD_OPTIONAL}. The key * property of this event contains the name of the optional configuration source * that caused this problem.)
*

*

* The optional header section can contain some meta data about the * created configuration itself. For instance, it is possible to set further * properties of the {@code NodeCombiner} objects used for constructing * the resulting configuration. *

*

* The default configuration object returned by this builder is an instance of the * {@link CombinedConfiguration} class. The return value of the * {@code getConfiguration()} method can be casted to this type, and the * {@code getConfiguration(boolean)} method directly declares * {@code CombinedConfiguration} as return type. This allows for * convenient access to the configuration objects maintained by the combined * configuration (e.g. for updates of single configuration objects). It has also * the advantage that the properties stored in all declared configuration * objects are collected and transformed into a single hierarchical structure, * which can be accessed using different expression engines. The actual CombinedConfiguration * implementation can be overridden by specifying the class in the config-class * attribute of the result element. *

*

* A custom EntityResolver can be used for all XMLConfigurations by adding *

 * <entity-resolver config-class="EntityResolver fully qualified class name">
 * 
* The CatalogResolver can be used for all XMLConfiguration by adding *
 * <entity-resolver catalogFiles="comma separated list of catalog files">
 * 
*

*

* Additional ConfigurationProviders can be added by configuring them in the header * section. *

 * <providers>
 *   <provider config-tag="tag name" config-class="provider fully qualified class name"/>
 * </providers>
 * 
*

*

* Additional variable resolvers can be added by configuring them in the header * section. *

 * <lookups>
 *   <lookup config-prefix="prefix" config-class="StrLookup fully qualified class name"/>
 * </lookups>
 * 
*

*

* All declared override configurations are directly added to the resulting * combined configuration. If they are given names (using the * {@code config-name} attribute), they can directly be accessed using * the {@code getConfiguration(String)} method of * {@code CombinedConfiguration}. The additional configurations are * altogether added to another combined configuration, which uses a union * combiner. Then this union configuration is added to the resulting combined * configuration under the name defined by the {@code ADDITIONAL_NAME} * constant. *

*

* Implementation note: This class is not thread-safe. Especially the * {@code getConfiguration()} methods should be called by a single thread * only. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: DefaultConfigurationBuilder.java 1366930 2012-07-29 20:05:36Z oheger $ */ public class DefaultConfigurationBuilder extends XMLConfiguration implements ConfigurationBuilder { /** * Constant for the name of the additional configuration. If the * configuration definition file contains an {@code additional} * section, a special union configuration is created and added under this * name to the resulting combined configuration. */ public static final String ADDITIONAL_NAME = DefaultConfigurationBuilder.class .getName() + "/ADDITIONAL_CONFIG"; /** * Constant for the type of error events caused by optional configurations * that cannot be loaded. */ public static final int EVENT_ERR_LOAD_OPTIONAL = 51; /** Constant for the name of the configuration bean factory. */ static final String CONFIG_BEAN_FACTORY_NAME = DefaultConfigurationBuilder.class .getName() + ".CONFIG_BEAN_FACTORY_NAME"; /** Constant for the reserved name attribute. */ static final String ATTR_NAME = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START + XMLBeanDeclaration.RESERVED_PREFIX + "name" + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END; /** Constant for the name of the at attribute. */ static final String ATTR_ATNAME = "at"; /** Constant for the reserved at attribute. */ static final String ATTR_AT_RES = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START + XMLBeanDeclaration.RESERVED_PREFIX + ATTR_ATNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END; /** Constant for the at attribute without the reserved prefix. */ static final String ATTR_AT = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START + ATTR_ATNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END; /** Constant for the name of the optional attribute. */ static final String ATTR_OPTIONALNAME = "optional"; /** Constant for the reserved optional attribute. */ static final String ATTR_OPTIONAL_RES = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START + XMLBeanDeclaration.RESERVED_PREFIX + ATTR_OPTIONALNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END; /** Constant for the optional attribute without the reserved prefix. */ static final String ATTR_OPTIONAL = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START + ATTR_OPTIONALNAME + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END; /** Constant for the file name attribute. */ static final String ATTR_FILENAME = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START + "fileName" + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END; /** Constant for the forceCreate attribute. */ static final String ATTR_FORCECREATE = DefaultExpressionEngine.DEFAULT_ATTRIBUTE_START + XMLBeanDeclaration.RESERVED_PREFIX + "forceCreate" + DefaultExpressionEngine.DEFAULT_ATTRIBUTE_END; /** * Constant for the tag attribute for providers. */ static final String KEY_SYSTEM_PROPS = "[@systemProperties]"; /** Constant for the name of the header section. */ static final String SEC_HEADER = "header"; /** Constant for an expression that selects the union configurations. */ static final String KEY_UNION = "additional"; /** An array with the names of top level configuration sections.*/ static final String[] CONFIG_SECTIONS = { "additional", "override", SEC_HEADER }; /** * Constant for an expression that selects override configurations in the * override section. */ static final String KEY_OVERRIDE = "override"; /** * Constant for the key that points to the list nodes definition of the * override combiner. */ static final String KEY_OVERRIDE_LIST = SEC_HEADER + ".combiner.override.list-nodes.node"; /** * Constant for the key that points to the list nodes definition of the * additional combiner. */ static final String KEY_ADDITIONAL_LIST = SEC_HEADER + ".combiner.additional.list-nodes.node"; /** * Constant for the key for defining providers in the configuration file. */ static final String KEY_CONFIGURATION_PROVIDERS = SEC_HEADER + ".providers.provider"; /** * Constant for the tag attribute for providers. */ static final String KEY_PROVIDER_KEY = XMLBeanDeclaration.ATTR_PREFIX + "tag]"; /** * Constant for the key for defining variable resolvers */ static final String KEY_CONFIGURATION_LOOKUPS = SEC_HEADER + ".lookups.lookup"; /** * Constant for the key for defining entity resolvers */ static final String KEY_ENTITY_RESOLVER = SEC_HEADER + ".entity-resolver"; /** * Constant for the prefix attribute for lookups. */ static final String KEY_LOOKUP_KEY = XMLBeanDeclaration.ATTR_PREFIX + "prefix]"; /** * Constance for the FileSystem. */ static final String FILE_SYSTEM = SEC_HEADER + ".fileSystem"; /** * Constant for the key of the result declaration. This key can point to a * bean declaration, which defines properties of the resulting combined * configuration. */ static final String KEY_RESULT = SEC_HEADER + ".result"; /** Constant for the key of the combiner in the result declaration.*/ static final String KEY_COMBINER = KEY_RESULT + ".nodeCombiner"; /** Constant for the XML file extension. */ static final String EXT_XML = ".xml"; /** Constant for the provider for properties files. */ private static final ConfigurationProvider PROPERTIES_PROVIDER = new FileExtensionConfigurationProvider( XMLPropertiesConfiguration.class, PropertiesConfiguration.class, EXT_XML); /** Constant for the provider for XML files. */ private static final ConfigurationProvider XML_PROVIDER = new XMLConfigurationProvider(); /** Constant for the provider for JNDI sources. */ private static final ConfigurationProvider JNDI_PROVIDER = new ConfigurationProvider( JNDIConfiguration.class); /** Constant for the provider for system properties. */ private static final ConfigurationProvider SYSTEM_PROVIDER = new ConfigurationProvider( SystemConfiguration.class); /** Constant for the provider for ini files. */ private static final ConfigurationProvider INI_PROVIDER = new FileConfigurationProvider(HierarchicalINIConfiguration.class); /** Constant for the provider for environment properties. */ private static final ConfigurationProvider ENV_PROVIDER = new ConfigurationProvider(EnvironmentConfiguration.class); /** Constant for the provider for plist files. */ private static final ConfigurationProvider PLIST_PROVIDER = new FileExtensionConfigurationProvider( "org.apache.commons.configuration.plist.XMLPropertyListConfiguration", "org.apache.commons.configuration.plist.PropertyListConfiguration", EXT_XML); /** Constant for the provider for configuration definition files.*/ private static final ConfigurationProvider BUILDER_PROVIDER = new ConfigurationBuilderProvider(); /** An array with the names of the default tags. */ private static final String[] DEFAULT_TAGS = { "properties", "xml", "hierarchicalXml", "jndi", "system", "plist", "configuration", "ini", "env" }; /** An array with the providers for the default tags. */ private static final ConfigurationProvider[] DEFAULT_PROVIDERS = { PROPERTIES_PROVIDER, XML_PROVIDER, XML_PROVIDER, JNDI_PROVIDER, SYSTEM_PROVIDER, PLIST_PROVIDER, BUILDER_PROVIDER, INI_PROVIDER, ENV_PROVIDER }; /** * The serial version UID. */ private static final long serialVersionUID = -3113777854714492123L; /** * A specialized {@code StrLookup} object which operates on the combined * configuration constructed by this builder. This object is used as * default lookup for {@code ConfigurationInterpolator} objects assigned to * newly created configuration objects. */ private final StrLookup combinedConfigLookup = new StrLookup() { @Override public String lookup(String key) { if (constructedConfiguration != null) { Object value = constructedConfiguration.resolveContainerStore(key); return (value != null) ? value.toString() : null; } return null; } }; /** Stores the configuration that is currently constructed.*/ private CombinedConfiguration constructedConfiguration; /** Stores a map with the registered configuration providers. */ private final Map providers; /** Stores the base path to the configuration sources to load. */ private String configurationBasePath; /** * Creates a new instance of {@code DefaultConfigurationBuilder}. A * configuration definition file is not yet loaded. Use the diverse setter * methods provided by file based configurations to specify the * configuration definition file. */ public DefaultConfigurationBuilder() { super(); providers = new HashMap(); registerDefaultProviders(); registerBeanFactory(); setLogger(LogFactory.getLog(getClass())); addErrorLogListener(); // log errors per default } /** * Creates a new instance of {@code DefaultConfigurationBuilder} and * sets the specified configuration definition file. * * @param file the configuration definition file */ public DefaultConfigurationBuilder(File file) { this(); setFile(file); } /** * Creates a new instance of {@code DefaultConfigurationBuilder} and * sets the specified configuration definition file. * * @param fileName the name of the configuration definition file * @throws ConfigurationException if an error occurs when the file is loaded */ public DefaultConfigurationBuilder(String fileName) throws ConfigurationException { this(); setFileName(fileName); } /** * Creates a new instance of {@code DefaultConfigurationBuilder} and * sets the specified configuration definition file. * * @param url the URL to the configuration definition file * @throws ConfigurationException if an error occurs when the file is loaded */ public DefaultConfigurationBuilder(URL url) throws ConfigurationException { this(); setURL(url); } /** * Returns the base path for the configuration sources to load. This path is * used to resolve relative paths in the configuration definition file. * * @return the base path for configuration sources */ public String getConfigurationBasePath() { return (configurationBasePath != null) ? configurationBasePath : getBasePath(); } /** * Sets the base path for the configuration sources to load. Normally a base * path need not to be set because it is determined by the location of the * configuration definition file to load. All relative paths in this file * are resolved relative to this file. Setting a base path makes sense if * such relative paths should be otherwise resolved, e.g. if the * configuration file is loaded from the class path and all sub * configurations it refers to are stored in a special config directory. * * @param configurationBasePath the new base path to set */ public void setConfigurationBasePath(String configurationBasePath) { this.configurationBasePath = configurationBasePath; } /** * Adds a configuration provider for the specified tag. Whenever this tag is * encountered in the configuration definition file this provider will be * called to create the configuration object. * * @param tagName the name of the tag in the configuration definition file * @param provider the provider for this tag */ public void addConfigurationProvider(String tagName, ConfigurationProvider provider) { if (tagName == null) { throw new IllegalArgumentException("Tag name must not be null!"); } if (provider == null) { throw new IllegalArgumentException("Provider must not be null!"); } providers.put(tagName, provider); } /** * Removes the configuration provider for the specified tag name. * * @param tagName the tag name * @return the removed configuration provider or null if none was * registered for that tag */ public ConfigurationProvider removeConfigurationProvider(String tagName) { return providers.remove(tagName); } /** * Returns the configuration provider for the given tag. * * @param tagName the name of the tag * @return the provider that was registered for this tag or null if * there is none */ public ConfigurationProvider providerForTag(String tagName) { return providers.get(tagName); } /** * Returns the configuration provided by this builder. Loads and parses the * configuration definition file and creates instances for the declared * configurations. * * @return the configuration * @throws ConfigurationException if an error occurs */ public Configuration getConfiguration() throws ConfigurationException { return getConfiguration(true); } /** * Returns the configuration provided by this builder. If the boolean * parameter is true, the configuration definition file will be * loaded. It will then be parsed, and instances for the declared * configurations will be created. * * @param load a flag whether the configuration definition file should be * loaded; a value of false would make sense if the file has already * been created or its content was manipulated using some of the property * accessor methods * @return the configuration * @throws ConfigurationException if an error occurs */ public CombinedConfiguration getConfiguration(boolean load) throws ConfigurationException { if (load) { load(); } initFileSystem(); initSystemProperties(); configureEntityResolver(); registerConfiguredProviders(); registerConfiguredLookups(); CombinedConfiguration result = createResultConfiguration(); constructedConfiguration = result; List overrides = fetchTopLevelOverrideConfigs(); overrides.addAll(fetchChildConfigs(KEY_OVERRIDE)); initCombinedConfiguration(result, overrides, KEY_OVERRIDE_LIST); List additionals = fetchChildConfigs(KEY_UNION); if (!additionals.isEmpty()) { CombinedConfiguration addConfig = createAdditionalsConfiguration(result); result.addConfiguration(addConfig, ADDITIONAL_NAME); initCombinedConfiguration(addConfig, additionals, KEY_ADDITIONAL_LIST); } return result; } /** * Creates the resulting combined configuration. This method is called by * {@code getConfiguration()}. It checks whether the * {@code header} section of the configuration definition file * contains a {@code result} element. If this is the case, it will be * used to initialize the properties of the newly created configuration * object. * * @return the resulting configuration object * @throws ConfigurationException if an error occurs */ protected CombinedConfiguration createResultConfiguration() throws ConfigurationException { XMLBeanDeclaration decl = new XMLBeanDeclaration(this, KEY_RESULT, true); CombinedConfiguration result = (CombinedConfiguration) BeanHelper .createBean(decl, CombinedConfiguration.class); if (getMaxIndex(KEY_COMBINER) < 0) { // No combiner defined => set default result.setNodeCombiner(new OverrideCombiner()); } return result; } /** * Creates the {@code CombinedConfiguration} for the configuration * sources in the <additional> section. This method is * called when the builder constructs the final configuration. It creates a * new {@code CombinedConfiguration} and initializes some properties * from the result configuration. * * @param resultConfig the result configuration (this is the configuration * that will be returned by the builder) * @return the {@code CombinedConfiguration} for the additional * configuration sources * @since 1.7 */ protected CombinedConfiguration createAdditionalsConfiguration( CombinedConfiguration resultConfig) { CombinedConfiguration addConfig = new CombinedConfiguration(new UnionCombiner()); addConfig.setDelimiterParsingDisabled(resultConfig .isDelimiterParsingDisabled()); addConfig.setForceReloadCheck(resultConfig.isForceReloadCheck()); addConfig.setIgnoreReloadExceptions(resultConfig .isIgnoreReloadExceptions()); return addConfig; } /** * Initializes a combined configuration for the configurations of a specific * section. This method is called for the override and for the additional * section (if it exists). * * @param config the configuration to be initialized * @param containedConfigs the list with the declarations of the contained * configurations * @param keyListNodes a list with the declaration of list nodes * @throws ConfigurationException if an error occurs */ protected void initCombinedConfiguration(CombinedConfiguration config, List containedConfigs, String keyListNodes) throws ConfigurationException { List listNodes = getList(keyListNodes); for (Object listNode : listNodes) { config.getNodeCombiner().addListNode((String) listNode); } for (HierarchicalConfiguration conf : containedConfigs) { ConfigurationDeclaration decl = new ConfigurationDeclaration(this, conf); if (getLogger().isDebugEnabled()) { getLogger().debug("Creating configuration " + decl.getBeanClassName() + " with name " + decl.getConfiguration().getString(ATTR_NAME)); } AbstractConfiguration newConf = createConfigurationAt(decl); if (newConf != null) { config.addConfiguration(newConf, decl.getConfiguration() .getString(ATTR_NAME), decl.getAt()); } } } /** * Registers the default configuration providers supported by this class. * This method will be called during initialization. It registers * configuration providers for the tags that are supported by default. */ protected void registerDefaultProviders() { for (int i = 0; i < DEFAULT_TAGS.length; i++) { addConfigurationProvider(DEFAULT_TAGS[i], DEFAULT_PROVIDERS[i]); } } /** * Registers providers defined in the configuration. * * @throws ConfigurationException if an error occurs */ protected void registerConfiguredProviders() throws ConfigurationException { List nodes = configurationsAt(KEY_CONFIGURATION_PROVIDERS); for (HierarchicalConfiguration config : nodes) { XMLBeanDeclaration decl = new XMLBeanDeclaration(config); String key = config.getString(KEY_PROVIDER_KEY); addConfigurationProvider(key, (ConfigurationProvider) BeanHelper .createBean(decl)); } } /** * Registers StrLookups defined in the configuration. * * @throws ConfigurationException if an error occurs */ protected void registerConfiguredLookups() throws ConfigurationException { List nodes = configurationsAt(KEY_CONFIGURATION_LOOKUPS); for (HierarchicalConfiguration config : nodes) { XMLBeanDeclaration decl = new XMLBeanDeclaration(config); String key = config.getString(KEY_LOOKUP_KEY); StrLookup lookup = (StrLookup) BeanHelper.createBean(decl); BeanHelper.setProperty(lookup, "configuration", this); ConfigurationInterpolator.registerGlobalLookup(key, lookup); this.getInterpolator().registerLookup(key, lookup); } } protected void initFileSystem() throws ConfigurationException { if (getMaxIndex(FILE_SYSTEM) == 0) { HierarchicalConfiguration config = configurationAt(FILE_SYSTEM); XMLBeanDeclaration decl = new XMLBeanDeclaration(config); setFileSystem((FileSystem) BeanHelper.createBean(decl)); } } /** * If a property file is configured add the properties to the System properties. * @throws ConfigurationException if an error occurs. */ protected void initSystemProperties() throws ConfigurationException { String fileName = getString(KEY_SYSTEM_PROPS); if (fileName != null) { try { SystemConfiguration.setSystemProperties(getConfigurationBasePath(), fileName); } catch (Exception ex) { throw new ConfigurationException("Error setting system properties from " + fileName, ex); } } } protected void configureEntityResolver() throws ConfigurationException { if (getMaxIndex(KEY_ENTITY_RESOLVER) == 0) { XMLBeanDeclaration decl = new XMLBeanDeclaration(this, KEY_ENTITY_RESOLVER, true); EntityResolver resolver = (EntityResolver) BeanHelper.createBean(decl, CatalogResolver.class); BeanHelper.setProperty(resolver, "fileSystem", getFileSystem()); BeanHelper.setProperty(resolver, "baseDir", getBasePath()); BeanHelper.setProperty(resolver, "substitutor", getSubstitutor()); setEntityResolver(resolver); } } /** * Performs interpolation. This method will not only take this configuration * instance into account (which is the one that loaded the configuration * definition file), but also the so far constructed combined configuration. * So variables can be used that point to properties that are defined in * configuration sources loaded by this builder. * * @param value the value to be interpolated * @return the interpolated value */ @Override protected Object interpolate(Object value) { Object result = super.interpolate(value); if (constructedConfiguration != null) { result = constructedConfiguration.interpolate(result); } return result; } /** * Creates a configuration object from the specified configuration * declaration. * * @param decl the configuration declaration * @return the new configuration object * @throws ConfigurationException if an error occurs */ private AbstractConfiguration createConfigurationAt( ConfigurationDeclaration decl) throws ConfigurationException { try { return (AbstractConfiguration) BeanHelper.createBean(decl); } catch (Exception ex) { // redirect to configuration exceptions throw new ConfigurationException(ex); } } /** * Returns a list with {@code SubnodeConfiguration} objects for the * child nodes of the specified configuration node. * * @param node the start node * @return a list with subnode configurations for the node's children */ private List fetchChildConfigs(ConfigurationNode node) { List children = node.getChildren(); List result = new ArrayList(children.size()); for (ConfigurationNode child : children) { result.add(createSubnodeConfiguration(child)); } return result; } /** * Returns a list with {@code SubnodeConfiguration} objects for the * child nodes of the node specified by the given key. * * @param key the key (must define exactly one node) * @return a list with subnode configurations for the node's children */ private List fetchChildConfigs(String key) { List nodes = fetchNodeList(key); if (nodes.size() > 0) { return fetchChildConfigs(nodes.get(0)); } else { return Collections.emptyList(); } } /** * Finds the override configurations that are defined as top level elements * in the configuration definition file. This method will fetch the child * elements of the root node and remove the nodes that represent other * configuration sections. The remaining nodes are treated as definitions * for override configurations. * * @return a list with subnode configurations for the top level override * configurations */ private List fetchTopLevelOverrideConfigs() { List configs = fetchChildConfigs(getRootNode()); for (Iterator it = configs.iterator(); it.hasNext();) { String nodeName = it.next().getRootNode().getName(); for (int i = 0; i < CONFIG_SECTIONS.length; i++) { if (CONFIG_SECTIONS[i].equals(nodeName)) { it.remove(); break; } } } return configs; } /** * Registers the bean factory used by this class if necessary. This method * is called by the constructor to ensure that the required bean factory is * available. */ private void registerBeanFactory() { synchronized (DefaultConfigurationBuilder.class) { if (!BeanHelper.registeredFactoryNames().contains( CONFIG_BEAN_FACTORY_NAME)) { BeanHelper.registerBeanFactory(CONFIG_BEAN_FACTORY_NAME, new ConfigurationBeanFactory()); } } } /** *

* A base class for creating and initializing configuration sources. *

*

* Concrete sub classes of this base class are responsible for creating * specific {@code Configuration} objects for the tags in the * configuration definition file. The configuration factory will parse the * definition file and try to find a matching * {@code ConfigurationProvider} for each encountered tag. This * provider is then asked to create a corresponding * {@code Configuration} object. It is up to a concrete * implementation how this object is created and initialized. *

*

* Note that at the moment only configuration classes derived from * {@link AbstractConfiguration} are supported. *

*/ public static class ConfigurationProvider extends DefaultBeanFactory { /** Stores the class of the configuration to be created. */ private Class configurationClass; /** Stores the name of the configuration class to be created.*/ private String configurationClassName; /** * Creates a new uninitialized instance of {@code ConfigurationProvider}. */ public ConfigurationProvider() { this((Class) null); } /** * Creates a new instance of {@code ConfigurationProvider} and * sets the class of the configuration created by this provider. * * @param configClass the configuration class */ public ConfigurationProvider(Class configClass) { setConfigurationClass(configClass); } /** * Creates a new instance of {@code ConfigurationProvider} and * sets the name of the class of the configuration created by this * provider. * * @param configClassName the name of the configuration class * @since 1.4 */ public ConfigurationProvider(String configClassName) { setConfigurationClassName(configClassName); } /** * Returns the class of the configuration returned by this provider. * * @return the class of the provided configuration */ public Class getConfigurationClass() { return configurationClass; } /** * Sets the class of the configuration returned by this provider. * * @param configurationClass the configuration class */ public void setConfigurationClass(Class configurationClass) { this.configurationClass = configurationClass; } /** * Returns the name of the configuration class returned by this * provider. * * @return the configuration class name * @since 1.4 */ public String getConfigurationClassName() { return configurationClassName; } /** * Sets the name of the configuration class returned by this provider. * * @param configurationClassName the name of the configuration class * @since 1.4 */ public void setConfigurationClassName(String configurationClassName) { this.configurationClassName = configurationClassName; } /** * Returns the configuration. This method is called to fetch the * configuration from the provider. This implementation will call the * inherited {@link * org.apache.commons.configuration.beanutils.DefaultBeanFactory#createBean(Class, BeanDeclaration, Object) * createBean()} method to create a new instance of the * configuration class. * * @param decl the bean declaration with initialization parameters for * the configuration * @return the new configuration object * @throws Exception if an error occurs */ public AbstractConfiguration getConfiguration( ConfigurationDeclaration decl) throws Exception { return (AbstractConfiguration) createBean(fetchConfigurationClass(), decl, null); } /** * Returns an uninitialized configuration of the represented type. This * method will be called for optional configurations when the * {@code getConfiguration()} method caused an error and the * {@code forceCreate} attribute is set. A concrete sub class can * here try to create an uninitialized, empty configuration, which may * be possible if the error was created during initialization. This base * implementation just returns null. * * @param decl the bean declaration with initialization parameters for * the configuration * @return the new configuration object * @throws Exception if an error occurs * @since 1.4 */ public AbstractConfiguration getEmptyConfiguration( ConfigurationDeclaration decl) throws Exception { return null; } /** * Returns the configuration class supported by this provider. If a * class object was set, it is returned. Otherwise the method tries to * resolve the class name. * * @return the class of the configuration to be created * @since 1.4 */ protected synchronized Class fetchConfigurationClass() throws Exception { if (getConfigurationClass() == null) { setConfigurationClass(loadClass(getConfigurationClassName())); } return getConfigurationClass(); } /** * Loads the class with the specified name dynamically. If the class's * name is null, null will also be returned. * * @param className the name of the class to be loaded * @return the class object * @throws ClassNotFoundException if class loading fails * @since 1.4 */ protected Class loadClass(String className) throws ClassNotFoundException { return (className != null) ? Class.forName(className, true, getClass().getClassLoader()) : null; } } /** *

* A specialized {@code BeanDeclaration} implementation that * represents the declaration of a configuration source. *

*

* Instances of this class are able to extract all information about a * configuration source from the configuration definition file. The * declaration of a configuration source is very similar to a bean * declaration processed by {@code XMLBeanDeclaration}. There are * very few differences, e.g. some reserved attributes like * {@code optional} and {@code at} and the fact that a bean * factory is never needed. *

*/ public static class ConfigurationDeclaration extends XMLBeanDeclaration { /** Stores a reference to the associated configuration builder. */ private DefaultConfigurationBuilder configurationBuilder; /** * Creates a new instance of {@code ConfigurationDeclaration} and * initializes it. * * @param builder the associated configuration builder * @param config the configuration this declaration is based onto */ public ConfigurationDeclaration(DefaultConfigurationBuilder builder, HierarchicalConfiguration config) { super(config); configurationBuilder = builder; } /** * Returns the associated configuration builder. * * @return the configuration builder */ public DefaultConfigurationBuilder getConfigurationBuilder() { return configurationBuilder; } /** * Returns the value of the {@code at} attribute. * * @return the value of the {@code at} attribute (can be null) */ public String getAt() { String result = this.getConfiguration().getString(ATTR_AT_RES); return (result == null) ? this.getConfiguration().getString(ATTR_AT) : result; } /** * Returns a flag whether this is an optional configuration. * * @return a flag if this declaration points to an optional * configuration */ public boolean isOptional() { Boolean value = this.getConfiguration().getBoolean(ATTR_OPTIONAL_RES, null); if (value == null) { value = this.getConfiguration().getBoolean(ATTR_OPTIONAL, Boolean.FALSE); } return value.booleanValue(); } /** * Returns a flag whether this configuration should always be created * and added to the resulting combined configuration. This flag is * evaluated only for optional configurations whose normal creation has * caused an error. If for such a configuration the * {@code forceCreate} attribute is set and the corresponding * configuration provider supports this mode, an empty configuration * will be created and added to the resulting combined configuration. * * @return the value of the {@code forceCreate} attribute * @since 1.4 */ public boolean isForceCreate() { return this.getConfiguration().getBoolean(ATTR_FORCECREATE, false); } /** * Returns the name of the bean factory. For configuration source * declarations always a reserved factory is used. This factory's name * is returned by this implementation. * * @return the name of the bean factory */ @Override public String getBeanFactoryName() { return CONFIG_BEAN_FACTORY_NAME; } /** * Returns the bean's class name. This implementation will always return * null. * * @return the name of the bean's class */ @Override public String getBeanClassName() { return null; } /** * Checks whether the given node is reserved. This method will take * further reserved attributes into account * * @param nd the node * @return a flag whether this node is reserved */ @Override protected boolean isReservedNode(ConfigurationNode nd) { if (super.isReservedNode(nd)) { return true; } return nd.isAttribute() && ((ATTR_ATNAME.equals(nd.getName()) && nd.getParentNode() .getAttributeCount(RESERVED_PREFIX + ATTR_ATNAME) == 0) || (ATTR_OPTIONALNAME .equals(nd.getName()) && nd.getParentNode() .getAttributeCount(RESERVED_PREFIX + ATTR_OPTIONALNAME) == 0)); } /** * Performs interpolation. This implementation will delegate * interpolation to the configuration builder, which takes care that the * currently constructed configuration is taken into account, too. * * @param value the value to be interpolated * @return the interpolated value */ @Override protected Object interpolate(Object value) { return getConfigurationBuilder().interpolate(value); } } /** * A specialized {@code BeanFactory} implementation that handles * configuration declarations. This class will retrieve the correct * configuration provider and delegate the task of creating the * configuration to this object. */ static class ConfigurationBeanFactory implements BeanFactory { /** The logger. */ private Log logger = LogFactory.getLog(DefaultConfigurationBuilder.class); /** * Creates an instance of a bean class. This implementation expects that * the passed in bean declaration is a declaration for a configuration. * It will determine the responsible configuration provider and delegate * the call to this instance. If creation of the configuration fails * and the {@code optional} attribute is set, the exception will * be ignored. If the {@code forceCreate} attribute is set, too, * the provider is asked to create an empty configuration. A return * value of null means that no configuration could be created. * * @param beanClass the bean class (will be ignored) * @param data the declaration * @param param an additional parameter (will be ignored) * @return the newly created configuration * @throws Exception if an error occurs */ public Object createBean(Class beanClass, BeanDeclaration data, Object param) throws Exception { ConfigurationDeclaration decl = (ConfigurationDeclaration) data; String tagName = decl.getNode().getName(); ConfigurationProvider provider = decl.getConfigurationBuilder() .providerForTag(tagName); if (provider == null) { throw new ConfigurationRuntimeException( "No ConfigurationProvider registered for tag " + tagName); } try { AbstractConfiguration config = provider.getConfiguration(decl); installInterpolator(decl, config); return config; } catch (Exception ex) { // If this is an optional configuration, ignore the exception if (!decl.isOptional()) { throw ex; } else { if (logger.isDebugEnabled()) { logger.debug("Load failed for optional configuration " + tagName + ": " + ex.getMessage()); } // Notify registered error listeners decl.getConfigurationBuilder().fireError( EVENT_ERR_LOAD_OPTIONAL, decl.getConfiguration().getString(ATTR_NAME), null, ex); if (decl.isForceCreate()) { try { return provider.getEmptyConfiguration(decl); } catch (Exception ex2) { // Ignore exception, return null in this case logger.warn("Could not create instance of optional configuration " + tagName, ex2); } } return null; } } } /** * Returns the default class for this bean factory. * * @return the default class */ public Class getDefaultBeanClass() { // Here some valid class must be returned, otherwise BeanHelper // will complain that the bean's class cannot be determined return Configuration.class; } /** * Installs a specialized {@code ConfigurationInterpolator} on a newly * created configuration which also takes the combined configuration * created by the builder into account. With this * {@code ConfigurationInterpolator} the interpolation facilities of * this child configuration are extended to include all other * configurations created by this builder. * * @param decl the {@code ConfigurationDeclaration} * @param config the newly created configuration instance */ private void installInterpolator(ConfigurationDeclaration decl, AbstractConfiguration config) { ConfigurationInterpolator parent = new ConfigurationInterpolator(); parent.setDefaultLookup(decl.getConfigurationBuilder().combinedConfigLookup); config.getInterpolator().setParentInterpolator(parent); } } /** * A specialized provider implementation that deals with file based * configurations. Ensures that the base path is correctly set and that the * load() method gets called. */ public static class FileConfigurationProvider extends ConfigurationProvider { /** * Creates a new instance of {@code FileConfigurationProvider}. */ public FileConfigurationProvider() { super(); } /** * Creates a new instance of {@code FileConfigurationProvider} * and sets the configuration class. * * @param configClass the class for the configurations to be created */ public FileConfigurationProvider(Class configClass) { super(configClass); } /** * Creates a new instance of {@code FileConfigurationProvider} * and sets the configuration class name. * * @param configClassName the name of the configuration to be created * @since 1.4 */ public FileConfigurationProvider(String configClassName) { super(configClassName); } /** * Creates the configuration. After that {@code load()} will be * called. If this configuration is marked as optional, exceptions will * be ignored. * * @param decl the declaration * @return the new configuration * @throws Exception if an error occurs */ @Override public AbstractConfiguration getConfiguration( ConfigurationDeclaration decl) throws Exception { AbstractConfiguration result = getEmptyConfiguration(decl); if (result instanceof FileSystemBased) { DefaultConfigurationBuilder builder = decl.getConfigurationBuilder(); if (builder.getFileSystem() != null) { ((FileSystemBased) result).setFileSystem(builder.getFileSystem()); } } ((FileConfiguration) result).load(); return result; } /** * Returns an uninitialized file configuration. This method will be * called for optional configurations when the * {@code getConfiguration()} method caused an error and the * {@code forceCreate} attribute is set. It will create the * configuration of the represented type, but the {@code load()} * method won't be called. This way non-existing configuration files can * be handled gracefully: If loading a the file fails, an empty * configuration will be created that is already configured with the * correct file name. * * @param decl the bean declaration with initialization parameters for * the configuration * @return the new configuration object * @throws Exception if an error occurs * @since 1.4 */ @Override public AbstractConfiguration getEmptyConfiguration( ConfigurationDeclaration decl) throws Exception { AbstractConfiguration config = super.getConfiguration(decl); /** * Some wrapper classes may need to pass the EntityResolver to XMLConfigurations * they construct buy may not be an XMLConfiguration. */ if (config instanceof EntityResolverSupport) { DefaultConfigurationBuilder builder = decl.getConfigurationBuilder(); EntityResolver resolver = builder.getEntityResolver(); ((EntityResolverSupport) config).setEntityResolver(resolver); } return config; } /** * Initializes the bean instance. Ensures that the file configuration's * base path will be initialized with the base path of the factory so * that relative path names can be correctly resolved. * * @param bean the bean to be initialized * @param data the declaration * @throws Exception if an error occurs */ @Override protected void initBeanInstance(Object bean, BeanDeclaration data) throws Exception { FileConfiguration config = (FileConfiguration) bean; config.setBasePath(((ConfigurationDeclaration) data) .getConfigurationBuilder().getConfigurationBasePath()); super.initBeanInstance(bean, data); } } /** * A specialized configuration provider for XML configurations. This * implementation acts like a {@code FileConfigurationProvider}, but * it will copy all entity IDs that have been registered for the * configuration builder to the new XML configuration before it is loaded. * * @since 1.6 */ public static class XMLConfigurationProvider extends FileConfigurationProvider { /** * Creates a new instance of {@code XMLConfigurationProvider}. */ public XMLConfigurationProvider() { super(XMLConfiguration.class); } /** * Returns a new empty configuration instance. This implementation * performs some additional initialization specific to XML * configurations. * * @param decl the configuration declaration * @return the new configuration * @throws Exception if an error occurs */ @Override public AbstractConfiguration getEmptyConfiguration( ConfigurationDeclaration decl) throws Exception { XMLConfiguration config = (XMLConfiguration) super .getEmptyConfiguration(decl); DefaultConfigurationBuilder builder = decl .getConfigurationBuilder(); EntityResolver resolver = builder.getEntityResolver(); if (resolver instanceof EntityRegistry) { // copy the registered entities config.getRegisteredEntities().putAll( builder.getRegisteredEntities()); } else { config.setEntityResolver(resolver); } return config; } } /** * A specialized configuration provider for file based configurations that * can handle configuration sources whose concrete type depends on the * extension of the file to be loaded. One example is the * {@code properties} tag: if the file ends with ".xml" a * XMLPropertiesConfiguration object must be created, otherwise a * PropertiesConfiguration object. */ static class FileExtensionConfigurationProvider extends FileConfigurationProvider { /** * Stores the class to be created when the file extension matches. */ private Class matchingClass; /** * Stores the name of the class to be created when the file extension * matches. */ private String matchingClassName; /** * Stores the class to be created when the file extension does not * match. */ private Class defaultClass; /** * Stores the name of the class to be created when the file extension * does not match. */ private String defaultClassName; /** Stores the file extension to be checked against. */ private String fileExtension; /** * Creates a new instance of * {@code FileExtensionConfigurationProvider} and initializes it. * * @param matchingClass the class to be created when the file extension * matches * @param defaultClass the class to be created when the file extension * does not match * @param extension the file extension to be checked against */ public FileExtensionConfigurationProvider(Class matchingClass, Class defaultClass, String extension) { this.matchingClass = matchingClass; this.defaultClass = defaultClass; fileExtension = extension; } /** * Creates a new instance of * {@code FileExtensionConfigurationProvider} and initializes it * with the names of the classes to be created. * * @param matchingClassName the name of the class to be created when the * file extension matches * @param defaultClassName the name of the class to be created when the * file extension does not match * @param extension the file extension to be checked against * @since 1.4 */ public FileExtensionConfigurationProvider(String matchingClassName, String defaultClassName, String extension) { this.matchingClassName = matchingClassName; this.defaultClassName = defaultClassName; fileExtension = extension; } /** * Returns the matching class object, no matter whether it was defined * as a class or as a class name. * * @return the matching class object * @throws Exception if an error occurs * @since 1.4 */ protected synchronized Class fetchMatchingClass() throws Exception { if (matchingClass == null) { matchingClass = loadClass(matchingClassName); } return matchingClass; } /** * Returns the default class object, no matter whether it was defined as * a class or as a class name. * * @return the default class object * @throws Exception if an error occurs * @since 1.4 */ protected synchronized Class fetchDefaultClass() throws Exception { if (defaultClass == null) { defaultClass = loadClass(defaultClassName); } return defaultClass; } /** * Creates the configuration object. The class is determined by the file * name's extension. * * @param beanClass the class * @param data the bean declaration * @return the new bean * @throws Exception if an error occurs */ @Override protected Object createBeanInstance(Class beanClass, BeanDeclaration data) throws Exception { String fileName = ((ConfigurationDeclaration) data) .getConfiguration().getString(ATTR_FILENAME); if (fileName != null && fileName.toLowerCase().trim().endsWith(fileExtension)) { return super.createBeanInstance(fetchMatchingClass(), data); } else { return super.createBeanInstance(fetchDefaultClass(), data); } } } /** * A specialized configuration provider class that allows to include other * configuration definition files. */ static class ConfigurationBuilderProvider extends ConfigurationProvider { /** * Creates a new instance of {@code ConfigurationBuilderProvider}. */ public ConfigurationBuilderProvider() { super(DefaultConfigurationBuilder.class); } /** * Creates the configuration. First creates a configuration builder * object. Then returns the configuration created by this builder. * * @param decl the configuration declaration * @return the configuration * @exception Exception if an error occurs */ @Override public AbstractConfiguration getConfiguration( ConfigurationDeclaration decl) throws Exception { DefaultConfigurationBuilder builder = (DefaultConfigurationBuilder) super .getConfiguration(decl); return builder.getConfiguration(true); } /** * Returns an empty configuration in case of an optional configuration * could not be created. This implementation returns an empty combined * configuration. * * @param decl the configuration declaration * @return the configuration * @exception Exception if an error occurs * @since 1.4 */ @Override public AbstractConfiguration getEmptyConfiguration( ConfigurationDeclaration decl) throws Exception { return new CombinedConfiguration(); } /** * {@inheritDoc} This implementation ensures that the configuration * builder created by this provider inherits the properties from the * current configuration builder. */ @Override protected void initBeanInstance(Object bean, BeanDeclaration data) throws Exception { ConfigurationDeclaration decl = (ConfigurationDeclaration) data; initChildBuilder(decl.getConfigurationBuilder(), (DefaultConfigurationBuilder) bean); super.initBeanInstance(bean, data); } /** * Initializes the given child configuration builder from its parent * builder. This method copies the values of some properties from the * parent builder to the child builder so that the child inherits * properties from its parent. * * @param parent the parent builder * @param child the child builder */ private static void initChildBuilder( DefaultConfigurationBuilder parent, DefaultConfigurationBuilder child) { child.setAttributeSplittingDisabled(parent .isAttributeSplittingDisabled()); child.setBasePath(parent.getBasePath()); child.setDelimiterParsingDisabled(parent .isDelimiterParsingDisabled()); child.setListDelimiter(parent.getListDelimiter()); child.setThrowExceptionOnMissing(parent.isThrowExceptionOnMissing()); child.setLogger(parent.getLogger()); child.clearConfigurationListeners(); for (ConfigurationListener l : parent.getConfigurationListeners()) { child.addConfigurationListener(l); } child.clearErrorListeners(); for (ConfigurationErrorListener l : parent.getErrorListeners()) { child.addErrorListener(l); } } } } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DefaultFileSystem.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DefaultFileSystem.java100644 24312 12232154103 33457 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.HttpURLConnection; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * FileSystem that uses java.io.File or HttpClient * @since 1.7 * @author Commons Configuration team */ public class DefaultFileSystem extends FileSystem { /** * The Log for diagnostic messages. */ private Log log = LogFactory.getLog(DefaultFileSystem.class); @Override public InputStream getInputStream(String basePath, String fileName) throws ConfigurationException { try { URL url = ConfigurationUtils.locate(this, basePath, fileName); if (url == null) { throw new ConfigurationException("Cannot locate configuration source " + fileName); } return getInputStream(url); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration file " + fileName, e); } } @Override public InputStream getInputStream(URL url) throws ConfigurationException { // throw an exception if the target URL is a directory File file = ConfigurationUtils.fileFromURL(url); if (file != null && file.isDirectory()) { throw new ConfigurationException("Cannot load a configuration from a directory"); } try { return url.openStream(); } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration from the URL " + url, e); } } @Override public OutputStream getOutputStream(URL url) throws ConfigurationException { // file URLs have to be converted to Files since FileURLConnection is // read only (http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4191800) File file = ConfigurationUtils.fileFromURL(url); if (file != null) { return getOutputStream(file); } else { // for non file URLs save through an URLConnection OutputStream out; try { URLConnection connection = url.openConnection(); connection.setDoOutput(true); // use the PUT method for http URLs if (connection instanceof HttpURLConnection) { HttpURLConnection conn = (HttpURLConnection) connection; conn.setRequestMethod("PUT"); } out = connection.getOutputStream(); // check the response code for http URLs and throw an exception if an error occured if (connection instanceof HttpURLConnection) { out = new HttpOutputStream(out, (HttpURLConnection) connection); } return out; } catch (IOException e) { throw new ConfigurationException("Could not save to URL " + url, e); } } } @Override public OutputStream getOutputStream(File file) throws ConfigurationException { try { // create the file if necessary createPath(file); return new FileOutputStream(file); } catch (FileNotFoundException e) { throw new ConfigurationException("Unable to save to file " + file, e); } } @Override public String getPath(File file, URL url, String basePath, String fileName) { String path = null; // if resource was loaded from jar file may be null if (file != null) { path = file.getAbsolutePath(); } // try to see if file was loaded from a jar if (path == null) { if (url != null) { path = url.getPath(); } else { try { path = getURL(basePath, fileName).getPath(); } catch (Exception e) { // simply ignore it and return null if (log.isDebugEnabled()) { log.debug(String.format("Could not determine URL for " + "basePath = %s, fileName = %s.", basePath, fileName), e); } } } } return path; } @Override public String getBasePath(String path) { URL url; try { url = getURL(null, path); return ConfigurationUtils.getBasePath(url); } catch (Exception e) { return null; } } @Override public String getFileName(String path) { URL url; try { url = getURL(null, path); return ConfigurationUtils.getFileName(url); } catch (Exception e) { return null; } } @Override public URL getURL(String basePath, String file) throws MalformedURLException { File f = new File(file); if (f.isAbsolute()) // already absolute? { return ConfigurationUtils.toURL(f); } try { if (basePath == null) { return new URL(file); } else { URL base = new URL(basePath); return new URL(base, file); } } catch (MalformedURLException uex) { return ConfigurationUtils.toURL(ConfigurationUtils.constructFile(basePath, file)); } } @Override public URL locateFromURL(String basePath, String fileName) { try { URL url; if (basePath == null) { return new URL(fileName); //url = new URL(name); } else { URL baseURL = new URL(basePath); url = new URL(baseURL, fileName); // check if the file exists InputStream in = null; try { in = url.openStream(); } finally { if (in != null) { in.close(); } } return url; } } catch (IOException e) { if (log.isDebugEnabled()) { log.debug("Could not locate file " + fileName + " at " + basePath + ": " + e.getMessage()); } return null; } } /** * Create the path to the specified file. * * @param file the target file */ private void createPath(File file) { if (file != null) { // create the path to the file if the file doesn't exist if (!file.exists()) { File parent = file.getParentFile(); if (parent != null && !parent.exists()) { parent.mkdirs(); } } } } /** * Wraps the output stream so errors can be detected in the HTTP response. * @since 1.7 * @author Commons Configuration team */ private static class HttpOutputStream extends VerifiableOutputStream { /** The wrapped OutputStream */ private final OutputStream stream; /** The HttpURLConnection */ private final HttpURLConnection connection; public HttpOutputStream(OutputStream stream, HttpURLConnection connection) { this.stream = stream; this.connection = connection; } @Override public void write(byte[] bytes) throws IOException { stream.write(bytes); } @Override public void write(byte[] bytes, int i, int i1) throws IOException { stream.write(bytes, i, i1); } @Override public void flush() throws IOException { stream.flush(); } @Override public void close() throws IOException { stream.close(); } @Override public void write(int i) throws IOException { stream.write(i); } @Override public String toString() { return stream.toString(); } @Override public void verify() throws IOException { if (connection.getResponseCode() >= HttpURLConnection.HTTP_BAD_REQUEST) { throw new IOException("HTTP Error " + connection.getResponseCode() + " " + connection.getResponseMessage()); } } } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DynamicCombinedConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DynamicCombinedConfigu100644 64433 12232154102 33515 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.commons.configuration.event.ConfigurationErrorListener; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.ExpressionEngine; import org.apache.commons.configuration.tree.NodeCombiner; import org.apache.commons.lang.text.StrSubstitutor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * DynamicCombinedConfiguration allows a set of CombinedConfigurations to be used. Each CombinedConfiguration * is referenced by a key that is dynamically constructed from a key pattern on each call. The key pattern * will be resolved using the configured ConfigurationInterpolator. * @since 1.6 * @author Commons * Configuration team * @version $Id: DynamicCombinedConfiguration.java 1534064 2013-10-21 08:44:33Z henning $ */ public class DynamicCombinedConfiguration extends CombinedConfiguration { /** * Prevent recursion while resolving unprefixed properties. */ private static ThreadLocal recursive = new ThreadLocal() { @Override protected synchronized Boolean initialValue() { return Boolean.FALSE; } }; /** The CombinedConfigurations */ private final ConcurrentMap configs = new ConcurrentHashMap(); /** Stores a list with the contained configurations. */ private List configurations = new ArrayList(); /** Stores a map with the named configurations. */ private Map namedConfigurations = new HashMap(); /** The key pattern for the CombinedConfiguration map */ private String keyPattern; /** Stores the combiner. */ private NodeCombiner nodeCombiner; /** The name of the logger to use for each CombinedConfiguration */ private String loggerName = DynamicCombinedConfiguration.class.getName(); /** The object for handling variable substitution in key patterns. */ private StrSubstitutor localSubst = new StrSubstitutor(new ConfigurationInterpolator()); /** * Creates a new instance of {@code DynamicCombinedConfiguration} and * initializes the combiner to be used. * * @param comb the node combiner (can be null, then a union combiner * is used as default) */ public DynamicCombinedConfiguration(NodeCombiner comb) { super(); setNodeCombiner(comb); setIgnoreReloadExceptions(false); setLogger(LogFactory.getLog(DynamicCombinedConfiguration.class)); } /** * Creates a new instance of {@code DynamicCombinedConfiguration} that uses * a union combiner. * * @see org.apache.commons.configuration.tree.UnionCombiner */ public DynamicCombinedConfiguration() { super(); setIgnoreReloadExceptions(false); setLogger(LogFactory.getLog(DynamicCombinedConfiguration.class)); } public void setKeyPattern(String pattern) { this.keyPattern = pattern; } public String getKeyPattern() { return this.keyPattern; } /** * Set the name of the Logger to use on each CombinedConfiguration. * @param name The Logger name. */ public void setLoggerName(String name) { this.loggerName = name; } /** * Returns the node combiner that is used for creating the combined node * structure. * * @return the node combiner */ @Override public NodeCombiner getNodeCombiner() { return nodeCombiner; } /** * Sets the node combiner. This object will be used when the combined node * structure is to be constructed. It must not be null, otherwise an * {@code IllegalArgumentException} exception is thrown. Changing the * node combiner causes an invalidation of this combined configuration, so * that the new combiner immediately takes effect. * * @param nodeCombiner the node combiner */ @Override public void setNodeCombiner(NodeCombiner nodeCombiner) { if (nodeCombiner == null) { throw new IllegalArgumentException( "Node combiner must not be null!"); } this.nodeCombiner = nodeCombiner; invalidateAll(); } /** * Adds a new configuration to this combined configuration. It is possible * (but not mandatory) to give the new configuration a name. This name must * be unique, otherwise a {@code ConfigurationRuntimeException} will * be thrown. With the optional {@code at} argument you can specify * where in the resulting node structure the content of the added * configuration should appear. This is a string that uses dots as property * delimiters (independent on the current expression engine). For instance * if you pass in the string {@code "database.tables"}, * all properties of the added configuration will occur in this branch. * * @param config the configuration to add (must not be null) * @param name the name of this configuration (can be null) * @param at the position of this configuration in the combined tree (can be * null) */ @Override public void addConfiguration(AbstractConfiguration config, String name, String at) { ConfigData cd = new ConfigData(config, name, at); configurations.add(cd); if (name != null) { namedConfigurations.put(name, config); } } /** * Returns the number of configurations that are contained in this combined * configuration. * * @return the number of contained configurations */ @Override public int getNumberOfConfigurations() { return configurations.size(); } /** * Returns the configuration at the specified index. The contained * configurations are numbered in the order they were added to this combined * configuration. The index of the first configuration is 0. * * @param index the index * @return the configuration at this index */ @Override public Configuration getConfiguration(int index) { ConfigData cd = configurations.get(index); return cd.getConfiguration(); } /** * Returns the configuration with the given name. This can be null * if no such configuration exists. * * @param name the name of the configuration * @return the configuration with this name */ @Override public Configuration getConfiguration(String name) { return namedConfigurations.get(name); } /** * Returns a set with the names of all configurations contained in this * combined configuration. Of course here are only these configurations * listed, for which a name was specified when they were added. * * @return a set with the names of the contained configurations (never * null) */ @Override public Set getConfigurationNames() { return namedConfigurations.keySet(); } /** * Removes the configuration with the specified name. * * @param name the name of the configuration to be removed * @return the removed configuration (null if this configuration * was not found) */ @Override public Configuration removeConfiguration(String name) { Configuration conf = getConfiguration(name); if (conf != null) { removeConfiguration(conf); } return conf; } /** * Removes the specified configuration from this combined configuration. * * @param config the configuration to be removed * @return a flag whether this configuration was found and could be removed */ @Override public boolean removeConfiguration(Configuration config) { for (int index = 0; index < getNumberOfConfigurations(); index++) { if (configurations.get(index).getConfiguration() == config) { removeConfigurationAt(index); } } return super.removeConfiguration(config); } /** * Removes the configuration at the specified index. * * @param index the index * @return the removed configuration */ @Override public Configuration removeConfigurationAt(int index) { ConfigData cd = configurations.remove(index); if (cd.getName() != null) { namedConfigurations.remove(cd.getName()); } return super.removeConfigurationAt(index); } /** * Returns the configuration root node of this combined configuration. This * method will construct a combined node structure using the current node * combiner if necessary. * * @return the combined root node */ @Override public ConfigurationNode getRootNode() { return getCurrentConfig().getRootNode(); } @Override public void setRootNode(ConfigurationNode rootNode) { if (configs != null) { this.getCurrentConfig().setRootNode(rootNode); } else { super.setRootNode(rootNode); } } @Override public void addProperty(String key, Object value) { this.getCurrentConfig().addProperty(key, value); } @Override public void clear() { if (configs != null) { this.getCurrentConfig().clear(); } } @Override public void clearProperty(String key) { this.getCurrentConfig().clearProperty(key); } @Override public boolean containsKey(String key) { return this.getCurrentConfig().containsKey(key); } @Override public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) { return this.getCurrentConfig().getBigDecimal(key, defaultValue); } @Override public BigDecimal getBigDecimal(String key) { return this.getCurrentConfig().getBigDecimal(key); } @Override public BigInteger getBigInteger(String key, BigInteger defaultValue) { return this.getCurrentConfig().getBigInteger(key, defaultValue); } @Override public BigInteger getBigInteger(String key) { return this.getCurrentConfig().getBigInteger(key); } @Override public boolean getBoolean(String key, boolean defaultValue) { return this.getCurrentConfig().getBoolean(key, defaultValue); } @Override public Boolean getBoolean(String key, Boolean defaultValue) { return this.getCurrentConfig().getBoolean(key, defaultValue); } @Override public boolean getBoolean(String key) { return this.getCurrentConfig().getBoolean(key); } @Override public byte getByte(String key, byte defaultValue) { return this.getCurrentConfig().getByte(key, defaultValue); } @Override public Byte getByte(String key, Byte defaultValue) { return this.getCurrentConfig().getByte(key, defaultValue); } @Override public byte getByte(String key) { return this.getCurrentConfig().getByte(key); } @Override public double getDouble(String key, double defaultValue) { return this.getCurrentConfig().getDouble(key, defaultValue); } @Override public Double getDouble(String key, Double defaultValue) { return this.getCurrentConfig().getDouble(key, defaultValue); } @Override public double getDouble(String key) { return this.getCurrentConfig().getDouble(key); } @Override public float getFloat(String key, float defaultValue) { return this.getCurrentConfig().getFloat(key, defaultValue); } @Override public Float getFloat(String key, Float defaultValue) { return this.getCurrentConfig().getFloat(key, defaultValue); } @Override public float getFloat(String key) { return this.getCurrentConfig().getFloat(key); } @Override public int getInt(String key, int defaultValue) { return this.getCurrentConfig().getInt(key, defaultValue); } @Override public int getInt(String key) { return this.getCurrentConfig().getInt(key); } @Override public Integer getInteger(String key, Integer defaultValue) { return this.getCurrentConfig().getInteger(key, defaultValue); } @Override public Iterator getKeys() { return this.getCurrentConfig().getKeys(); } @Override public Iterator getKeys(String prefix) { return this.getCurrentConfig().getKeys(prefix); } @Override public List getList(String key, List defaultValue) { return this.getCurrentConfig().getList(key, defaultValue); } @Override public List getList(String key) { return this.getCurrentConfig().getList(key); } @Override public long getLong(String key, long defaultValue) { return this.getCurrentConfig().getLong(key, defaultValue); } @Override public Long getLong(String key, Long defaultValue) { return this.getCurrentConfig().getLong(key, defaultValue); } @Override public long getLong(String key) { return this.getCurrentConfig().getLong(key); } @Override public Properties getProperties(String key) { return this.getCurrentConfig().getProperties(key); } @Override public Object getProperty(String key) { return this.getCurrentConfig().getProperty(key); } @Override public short getShort(String key, short defaultValue) { return this.getCurrentConfig().getShort(key, defaultValue); } @Override public Short getShort(String key, Short defaultValue) { return this.getCurrentConfig().getShort(key, defaultValue); } @Override public short getShort(String key) { return this.getCurrentConfig().getShort(key); } @Override public String getString(String key, String defaultValue) { return this.getCurrentConfig().getString(key, defaultValue); } @Override public String getString(String key) { return this.getCurrentConfig().getString(key); } @Override public String[] getStringArray(String key) { return this.getCurrentConfig().getStringArray(key); } @Override public boolean isEmpty() { return this.getCurrentConfig().isEmpty(); } @Override public void setProperty(String key, Object value) { if (configs != null) { this.getCurrentConfig().setProperty(key, value); } } @Override public Configuration subset(String prefix) { return this.getCurrentConfig().subset(prefix); } @Override public Node getRoot() { return this.getCurrentConfig().getRoot(); } @Override public void setRoot(Node node) { if (configs != null) { this.getCurrentConfig().setRoot(node); } else { super.setRoot(node); } } @Override public ExpressionEngine getExpressionEngine() { return super.getExpressionEngine(); } @Override public void setExpressionEngine(ExpressionEngine expressionEngine) { super.setExpressionEngine(expressionEngine); } @Override public void addNodes(String key, Collection nodes) { this.getCurrentConfig().addNodes(key, nodes); } @Override public SubnodeConfiguration configurationAt(String key, boolean supportUpdates) { return this.getCurrentConfig().configurationAt(key, supportUpdates); } @Override public SubnodeConfiguration configurationAt(String key) { return this.getCurrentConfig().configurationAt(key); } @Override public List configurationsAt(String key) { return this.getCurrentConfig().configurationsAt(key); } @Override public void clearTree(String key) { this.getCurrentConfig().clearTree(key); } @Override public int getMaxIndex(String key) { return this.getCurrentConfig().getMaxIndex(key); } @Override public Configuration interpolatedConfiguration() { return this.getCurrentConfig().interpolatedConfiguration(); } /** * Returns the configuration source, in which the specified key is defined. * This method will determine the configuration node that is identified by * the given key. The following constellations are possible: *
    *
  • If no node object is found for this key, null is returned.
  • *
  • If the key maps to multiple nodes belonging to different * configuration sources, a {@code IllegalArgumentException} is * thrown (in this case no unique source can be determined).
  • *
  • If exactly one node is found for the key, the (child) configuration * object, to which the node belongs is determined and returned.
  • *
  • For keys that have been added directly to this combined * configuration and that do not belong to the namespaces defined by * existing child configurations this configuration will be returned.
  • *
* * @param key the key of a configuration property * @return the configuration, to which this property belongs or null * if the key cannot be resolved * @throws IllegalArgumentException if the key maps to multiple properties * and the source cannot be determined, or if the key is null */ @Override public Configuration getSource(String key) { if (key == null) { throw new IllegalArgumentException("Key must not be null!"); } return getCurrentConfig().getSource(key); } @Override public void addConfigurationListener(ConfigurationListener l) { super.addConfigurationListener(l); for (CombinedConfiguration cc : configs.values()) { cc.addConfigurationListener(l); } } @Override public boolean removeConfigurationListener(ConfigurationListener l) { for (CombinedConfiguration cc : configs.values()) { cc.removeConfigurationListener(l); } return super.removeConfigurationListener(l); } @Override public Collection getConfigurationListeners() { return super.getConfigurationListeners(); } @Override public void clearConfigurationListeners() { for (CombinedConfiguration cc : configs.values()) { cc.clearConfigurationListeners(); } super.clearConfigurationListeners(); } @Override public void addErrorListener(ConfigurationErrorListener l) { for (CombinedConfiguration cc : configs.values()) { cc.addErrorListener(l); } super.addErrorListener(l); } @Override public boolean removeErrorListener(ConfigurationErrorListener l) { for (CombinedConfiguration cc : configs.values()) { cc.removeErrorListener(l); } return super.removeErrorListener(l); } @Override public void clearErrorListeners() { for (CombinedConfiguration cc : configs.values()) { cc.clearErrorListeners(); } super.clearErrorListeners(); } @Override public Collection getErrorListeners() { return super.getErrorListeners(); } /** * Returns a copy of this object. This implementation performs a deep clone, * i.e. all contained configurations will be cloned, too. For this to work, * all contained configurations must be cloneable. Registered event * listeners won't be cloned. The clone will use the same node combiner than * the original. * * @return the copied object */ @Override public Object clone() { return super.clone(); } /** * Invalidates the current combined configuration. This means that the next time a * property is accessed the combined node structure must be re-constructed. * Invalidation of a combined configuration also means that an event of type * {@code EVENT_COMBINED_INVALIDATE} is fired. Note that while other * events most times appear twice (once before and once after an update), * this event is only fired once (after update). */ @Override public void invalidate() { getCurrentConfig().invalidate(); } public void invalidateAll() { if (configs == null) { return; } for (CombinedConfiguration cc : configs.values()) { cc.invalidate(); } } /* * Don't allow resolveContainerStore to be called recursively. * @param key The key to resolve. * @return The value of the key. */ @Override protected Object resolveContainerStore(String key) { if (recursive.get().booleanValue()) { return null; } recursive.set(Boolean.TRUE); try { return super.resolveContainerStore(key); } finally { recursive.set(Boolean.FALSE); } } private CombinedConfiguration getCurrentConfig() { String key = localSubst.replace(keyPattern); CombinedConfiguration config = configs.get(key); // The double-checked works here due to the Thread guarantees of ConcurrentMap. if (config == null) { synchronized (configs) { config = configs.get(key); if (config == null) { config = new CombinedConfiguration(getNodeCombiner()); if (loggerName != null) { Log log = LogFactory.getLog(loggerName); if (log != null) { config.setLogger(log); } } config.setIgnoreReloadExceptions(isIgnoreReloadExceptions()); config.setExpressionEngine(this.getExpressionEngine()); config.setDelimiterParsingDisabled(isDelimiterParsingDisabled()); config.setConversionExpressionEngine(getConversionExpressionEngine()); config.setListDelimiter(getListDelimiter()); for (ConfigurationErrorListener listener : getErrorListeners()) { config.addErrorListener(listener); } for (ConfigurationListener listener : getConfigurationListeners()) { config.addConfigurationListener(listener); } config.setForceReloadCheck(isForceReloadCheck()); for (ConfigData data : configurations) { config.addConfiguration(data.getConfiguration(), data.getName(), data.getAt()); } configs.put(key, config); } } } if (getLogger().isDebugEnabled()) { getLogger().debug("Returning config for " + key + ": " + config); } return config; } /** * Internal class that identifies each Configuration. */ static class ConfigData { /** Stores a reference to the configuration. */ private AbstractConfiguration configuration; /** Stores the name under which the configuration is stored. */ private String name; /** Stores the at string.*/ private String at; /** * Creates a new instance of {@code ConfigData} and initializes * it. * * @param config the configuration * @param n the name * @param at the at position */ public ConfigData(AbstractConfiguration config, String n, String at) { configuration = config; name = n; this.at = at; } /** * Returns the stored configuration. * * @return the configuration */ public AbstractConfiguration getConfiguration() { return configuration; } /** * Returns the configuration's name. * * @return the name */ public String getName() { return name; } /** * Returns the at position of this configuration. * * @return the at position */ public String getAt() { return at; } } } ././@LongLink100644 0 0 154 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/EnvironmentConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/EnvironmentConfigurati100644 6334 12232154102 33630 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.HashMap; /** *

A Configuration implementation that reads the platform specific * environment variables using the map returned by {@link System#getenv()}.

* *

This configuration implementation is read-only. It allows read access to the * defined OS environment variables, but their values cannot be changed. Any * attempts to add or remove a property will throw an * {@link UnsupportedOperationException}

* *

Usage of this class is easy: After an instance has been created the get * methods provided by the {@code Configuration} interface can be used * for querying environment variables, e.g.:

* *
 * Configuration envConfig = new EnvironmentConfiguration();
 * System.out.println("JAVA_HOME=" + envConfig.getString("JAVA_HOME");
 * 
* * @author Nicolas De Loof * @version $Id: EnvironmentConfiguration.java 1210171 2011-12-04 18:32:07Z oheger $ * @since 1.5 */ public class EnvironmentConfiguration extends MapConfiguration { /** * Create a Configuration based on the environment variables. * * @see System#getenv() */ public EnvironmentConfiguration() { super(new HashMap(System.getenv())); } /** * Adds a property to this configuration. Because this configuration is * read-only, this operation is not allowed and will cause an exception. * * @param key the key of the property to be added * @param value the property value */ @Override protected void addPropertyDirect(String key, Object value) { throw new UnsupportedOperationException("EnvironmentConfiguration is read-only!"); } /** * Removes a property from this configuration. Because this configuration is * read-only, this operation is not allowed and will cause an exception. * * @param key the key of the property to be removed */ @Override public void clearProperty(String key) { throw new UnsupportedOperationException("EnvironmentConfiguration is read-only!"); } /** * Removes all properties from this configuration. Because this * configuration is read-only, this operation is not allowed and will cause * an exception. */ @Override public void clear() { throw new UnsupportedOperationException("EnvironmentConfiguration is read-only!"); } } ././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ConfigurationErrorEvent.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ConfigurationErr100644 7170 12232154102 33531 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; /** *

* An event class that is used for reporting errors that occurred while * processing configuration properties. *

*

* Some configuration implementations (e.g. * {@link org.apache.commons.configuration.DatabaseConfiguration} * or {@link org.apache.commons.configuration.JNDIConfiguration} * use an underlying storage that can throw an exception on each property * access. In earlier versions of this library such exceptions were logged and * then silently ignored. This makes it impossible for a client to find out that * something went wrong. *

*

* To give clients better control over the handling of errors that occur during * access of a configuration object a new event listener mechanism specific for * exceptions is introduced: Clients can register itself at a configuration * object as an error listener and are then notified about all * internal errors related to the source configuration object. *

*

* By inheriting from {@code ConfigurationEvent} this event class * supports all properties that describe an operation on a configuration * instance. In addition a {@code Throwable} object is available * representing the occurred error. The event's type determines the operation * that caused the error. Note that depending on the event type and the occurred * exception not all of the other properties (e.g. name of the affected property * or its value) may be available. *

* * @author Commons * Configuration team * @version $Id: ConfigurationErrorEvent.java 1207610 2011-11-28 21:06:22Z oheger $ * @since 1.4 * @see ConfigurationEvent */ public class ConfigurationErrorEvent extends ConfigurationEvent { /** * The serial version UID. */ private static final long serialVersionUID = -7433184493062648409L; /** Stores the exception that caused this event. */ private Throwable cause; /** * Creates a new instance of {@code ConfigurationErrorEvent} and * initializes it. * * @param source the event source * @param type the event's type * @param propertyName the name of the affected property * @param propertyValue the value of the affected property * @param cause the exception object that caused this event */ public ConfigurationErrorEvent(Object source, int type, String propertyName, Object propertyValue, Throwable cause) { super(source, type, propertyName, propertyValue, true); this.cause = cause; } /** * Returns the cause of this error event. This is the {@code Throwable} * object that caused this event to be fired. * * @return the cause of this error event */ public Throwable getCause() { return cause; } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ConfigurationErrorListener.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ConfigurationErr100644 4112 12232154102 33522 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; /** *

* An event listener interface to be implemented by observers that are * interested in internal errors caused by processing of configuration * properties. *

*

* Some configuration classes use an underlying storage where each access of a * property can cause an exception. In earlier versions of this library such * exceptions were typically ignored. By implementing this interface and * registering at a configuration object as an error listener it is now possible * for clients to receive notifications about those internal problems. *

* * @author Commons * Configuration team * @version $Id: ConfigurationErrorListener.java 1207610 2011-11-28 21:06:22Z oheger $ * @since 1.4 * @see ConfigurationErrorEvent */ public interface ConfigurationErrorListener { /** * Notifies this listener that in an observed configuration an error * occurred. All information available about this error, including the * causing {@code Throwable} object, can be obtained from the passed * in event object. * * @param event the event object with information about the error */ void configurationError(ConfigurationErrorEvent event); } ././@LongLink100644 0 0 154 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ConfigurationEvent.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ConfigurationEve100644 12741 12232154102 33540 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import java.util.EventObject; /** *

* An event class for reporting updates on a configuration object. *

*

* Event objects of this type are used for "raw" events, i.e. * unfiltered modifications of any kind. A level with semantically higher events * (e.g. for property changes) may be built on top of this fundamental event * mechanism. *

*

* Each event can contain the following data: *

    *
  • A source object, which is usually the configuration object that was * modified.
  • *
  • The event's type. This is a numeric value that corresponds to constant * declarations in concrete configuration classes. It describes what exactly has * happended.
  • *
  • If available, the name of the property whose modification caused the * event.
  • *
  • If available, the value of the property that caused this event.
  • *
  • A flag whether this event was generated before or after the update of * the source configuration. A modification of a configuration typically causes * two events: one event before and one event after the modification is * performed. This allows event listeners to react at the correct point of time.
  • *
*

*

* The following standard events are generated by typical configuration * implementations (the constants for the event types are defined in * {@link org.apache.commons.configuration.AbstractConfiguration}): *

*
EVENT_ADD_PROPERTY
*
This event is triggered for each call of the {@code addProperty()} * method of a configuration object. It contains the name of the property, to * which new data is added, and the value object that is added to this property * (this may be an array or a list if multiple values are added).
*
EVENT_SET_PROPERTY
*
Calling the {@code setProperty()} method triggers this event. The * event object stores the name of the affected property and its new value.
*
EVENT_CLEAR_PROPERTY
*
If a property is removed from a configuration (by calling the * {@code clearProperty()} method), an event of this type is fired. In * this case the event object only stores the name of the removed property, the * value is null.
*
EVENT_CLEAR
*
This event is fired when the whole configuration is cleared. The * corresponding event object contains no additional data.
*
*

* * @author Commons * Configuration team * @version $Id: ConfigurationEvent.java 1207610 2011-11-28 21:06:22Z oheger $ * @since 1.3 */ public class ConfigurationEvent extends EventObject { /** * The serial version UID. */ private static final long serialVersionUID = 3277238219073504136L; /** Stores the event type. */ private int type; /** Stores the property name. */ private String propertyName; /** Stores the property value. */ private Object propertyValue; /** Stores the before update flag. */ private boolean beforeUpdate; /** * Creates a new instance of {@code ConfigurationEvent} and * initializes it. * * @param source the event source * @param type the event's type * @param propertyName the name of the affected property * @param propertyValue the value of the affected property * @param beforeUpdate the before update flag */ public ConfigurationEvent(Object source, int type, String propertyName, Object propertyValue, boolean beforeUpdate) { super(source); this.type = type; this.propertyName = propertyName; this.propertyValue = propertyValue; this.beforeUpdate = beforeUpdate; } /** * Returns the name of the affected property. This can be null if no * property change has lead to this event. * * @return the name of the property */ public String getPropertyName() { return propertyName; } /** * Returns the value of the affected property if available. * * @return the value of the property; can be null */ public Object getPropertyValue() { return propertyValue; } /** * Returns the type of this event. This describes the update process that * caused this event. * * @return the event's type */ public int getType() { return type; } /** * Returns a flag if this event was generated before or after an update. * * @return true if this event was generated before an update; * false otherwise */ public boolean isBeforeUpdate() { return beforeUpdate; } } ././@LongLink100644 0 0 157 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ConfigurationListener.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ConfigurationLis100644 3266 12232154102 33532 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; /** *

* A simple event listener interface for configuration observers. *

*

* This interface can be implemented by classes that are interested in * "raw" events caused by configuration objects. Each manipulation on * a configuration object will generate such an event. There is only a single * method that is invoked when an event occurs. *

* * @author Commons * Configuration team * @version $Id: ConfigurationListener.java 561230 2007-07-31 04:17:09Z rahul $ * @since 1.3 */ public interface ConfigurationListener { /** * Notifies this listener about a manipulation on a monitored configuration * object. * * @param event the event describing the manipulation */ void configurationChanged(ConfigurationEvent event); } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/EventSource.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/EventSource.java100644 31223 12232154102 33447 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.concurrent.CopyOnWriteArrayList; /** *

* A base class for objects that can generate configuration events. *

*

* This class implements functionality for managing a set of event listeners * that can be notified when an event occurs. It can be extended by * configuration classes that support the event mechanism. In this case these * classes only need to call the {@code fireEvent()} method when an event * is to be delivered to the registered listeners. *

*

* Adding and removing event listeners can happen concurrently to manipulations * on a configuration that cause events. The operations are synchronized. *

*

* With the {@code detailEvents} property the number of detail events can * be controlled. Some methods in configuration classes are implemented in a way * that they call other methods that can generate their own events. One example * is the {@code setProperty()} method that can be implemented as a * combination of {@code clearProperty()} and {@code addProperty()}. * With {@code detailEvents} set to true, all involved methods * will generate events (i.e. listeners will receive property set events, * property clear events, and property add events). If this mode is turned off * (which is the default), detail events are suppressed, so only property set * events will be received. Note that the number of received detail events may * differ for different configuration implementations. * {@link org.apache.commons.configuration.HierarchicalConfiguration HierarchicalConfiguration} * for instance has a custom implementation of {@code setProperty()}, * which does not generate any detail events. *

*

* In addition to "normal" events, error events are supported. Such * events signal an internal problem that occurred during access of properties. * For them a special listener interface exists: * {@link ConfigurationErrorListener}. There is another set of * methods dealing with event listeners of this type. The * {@code fireError()} method can be used by derived classes to send * notifications about errors to registered observers. *

* * @author Commons Configuration team * @version $Id: EventSource.java 1234617 2012-01-22 21:31:01Z oheger $ * @since 1.3 */ public class EventSource { /** A collection for the registered event listeners. */ private Collection listeners; /** A collection for the registered error listeners.*/ private Collection errorListeners; /** A lock object for guarding access to the detail events counter. */ private final Object lockDetailEventsCount = new Object(); /** A counter for the detail events. */ private int detailEvents; /** * Creates a new instance of {@code EventSource}. */ public EventSource() { initListeners(); } /** * Adds a configuration listener to this object. * * @param l the listener to add */ public void addConfigurationListener(ConfigurationListener l) { checkListener(l); listeners.add(l); } /** * Removes the specified event listener so that it does not receive any * further events caused by this object. * * @param l the listener to be removed * @return a flag whether the event listener was found */ public boolean removeConfigurationListener(ConfigurationListener l) { return listeners.remove(l); } /** * Returns a collection with all configuration event listeners that are * currently registered at this object. * * @return a collection with the registered * {@code ConfigurationListener}s (this collection is a snapshot * of the currently registered listeners; manipulating it has no effect * on this event source object) */ public Collection getConfigurationListeners() { return Collections.unmodifiableCollection(new ArrayList(listeners)); } /** * Removes all registered configuration listeners. */ public void clearConfigurationListeners() { listeners.clear(); } /** * Returns a flag whether detail events are enabled. * * @return a flag if detail events are generated */ public boolean isDetailEvents() { return checkDetailEvents(0); } /** * Determines whether detail events should be generated. If enabled, some * methods can generate multiple update events. Note that this method * records the number of calls, i.e. if for instance * {@code setDetailEvents(false)} was called three times, you will * have to invoke the method as often to enable the details. * * @param enable a flag if detail events should be enabled or disabled */ public void setDetailEvents(boolean enable) { synchronized (lockDetailEventsCount) { if (enable) { detailEvents++; } else { detailEvents--; } } } /** * Adds a new configuration error listener to this object. This listener * will then be notified about internal problems. * * @param l the listener to register (must not be null) * @since 1.4 */ public void addErrorListener(ConfigurationErrorListener l) { checkListener(l); errorListeners.add(l); } /** * Removes the specified error listener so that it does not receive any * further events caused by this object. * * @param l the listener to remove * @return a flag whether the listener could be found and removed * @since 1.4 */ public boolean removeErrorListener(ConfigurationErrorListener l) { return errorListeners.remove(l); } /** * Removes all registered error listeners. * * @since 1.4 */ public void clearErrorListeners() { errorListeners.clear(); } /** * Returns a collection with all configuration error listeners that are * currently registered at this object. * * @return a collection with the registered * {@code ConfigurationErrorListener}s (this collection is a * snapshot of the currently registered listeners; it cannot be manipulated) * @since 1.4 */ public Collection getErrorListeners() { return Collections.unmodifiableCollection(new ArrayList(errorListeners)); } /** * Creates an event object and delivers it to all registered event * listeners. The method will check first if sending an event is allowed * (making use of the {@code detailEvents} property), and if * listeners are registered. * * @param type the event's type * @param propName the name of the affected property (can be null) * @param propValue the value of the affected property (can be null) * @param before the before update flag */ protected void fireEvent(int type, String propName, Object propValue, boolean before) { if (checkDetailEvents(-1)) { Iterator it = listeners.iterator(); if (it.hasNext()) { ConfigurationEvent event = createEvent(type, propName, propValue, before); while (it.hasNext()) { it.next().configurationChanged(event); } } } } /** * Creates a {@code ConfigurationEvent} object based on the passed in * parameters. This is called by {@code fireEvent()} if it decides * that an event needs to be generated. * * @param type the event's type * @param propName the name of the affected property (can be null) * @param propValue the value of the affected property (can be null) * @param before the before update flag * @return the newly created event object */ protected ConfigurationEvent createEvent(int type, String propName, Object propValue, boolean before) { return new ConfigurationEvent(this, type, propName, propValue, before); } /** * Creates an error event object and delivers it to all registered error * listeners. * * @param type the event's type * @param propName the name of the affected property (can be null) * @param propValue the value of the affected property (can be null) * @param ex the {@code Throwable} object that caused this error event * @since 1.4 */ protected void fireError(int type, String propName, Object propValue, Throwable ex) { Iterator it = errorListeners.iterator(); if (it.hasNext()) { ConfigurationErrorEvent event = createErrorEvent(type, propName, propValue, ex); while (it.hasNext()) { it.next().configurationError(event); } } } /** * Creates a {@code ConfigurationErrorEvent} object based on the * passed in parameters. This is called by {@code fireError()} if it * decides that an event needs to be generated. * * @param type the event's type * @param propName the name of the affected property (can be null) * @param propValue the value of the affected property (can be null) * @param ex the {@code Throwable} object that caused this error * event * @return the event object * @since 1.4 */ protected ConfigurationErrorEvent createErrorEvent(int type, String propName, Object propValue, Throwable ex) { return new ConfigurationErrorEvent(this, type, propName, propValue, ex); } /** * Overrides the {@code clone()} method to correctly handle so far * registered event listeners. This implementation ensures that the clone * will have empty event listener lists, i.e. the listeners registered at an * {@code EventSource} object will not be copied. * * @return the cloned object * @throws CloneNotSupportedException if cloning is not allowed * @since 1.4 */ @Override protected Object clone() throws CloneNotSupportedException { EventSource copy = (EventSource) super.clone(); copy.initListeners(); return copy; } /** * Checks whether the specified event listener is not null. If this * is the case, an {@code IllegalArgumentException} exception is thrown. * * @param l the listener to be checked * @throws IllegalArgumentException if the listener is null */ private static void checkListener(Object l) { if (l == null) { throw new IllegalArgumentException("Listener must not be null!"); } } /** * Initializes the collections for storing registered event listeners. */ private void initListeners() { listeners = new CopyOnWriteArrayList(); errorListeners = new CopyOnWriteArrayList(); } /** * Helper method for checking the current counter for detail events. This * method checks whether the counter is greater than the passed in limit. * * @param limit the limit to be compared to * @return true if the counter is greater than the limit, * false otherwise */ private boolean checkDetailEvents(int limit) { synchronized (lockDetailEventsCount) { return detailEvents > limit; } } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/package.html100644 2066 12232154102 32606 0ustarhenningstaff 0 0

This package contains interfaces and classes for receiving notifications about changes at configurations.

$Id: package.html 439648 2006-09-02 20:42:10Z oheger $

././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/FileConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/FileConfiguration.java100644 21400 12232154102 33467 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.net.URL; import org.apache.commons.configuration.reloading.ReloadingStrategy; /** * A persistent configuration loaded and saved to a file. * * @author Emmanuel Bourg * @version $Id: FileConfiguration.java 1209883 2011-12-03 10:56:57Z oheger $ * @since 1.0-rc2 */ public interface FileConfiguration extends Configuration { /** * Load the configuration from the underlying URL. If the URL is not * specified, it attempts to locate the specified file name. * * @throws ConfigurationException if an error occurs during the load operation */ void load() throws ConfigurationException; /** * Locate the specified file and load the configuration. * * @param fileName the name of the file loaded * * @throws ConfigurationException if an error occurs during the load operation */ void load(String fileName) throws ConfigurationException; /** * Load the configuration from the specified file. * * @param file the loaded file * * @throws ConfigurationException if an error occurs during the load operation */ void load(File file) throws ConfigurationException; /** * Load the configuration from the specified URL. * * @param url the URL of the file loaded * * @throws ConfigurationException if an error occurs during the load operation */ void load(URL url) throws ConfigurationException; /** * Load the configuration from the specified stream, using the encoding * returned by {@link #getEncoding()}. * * @param in the input stream * * @throws ConfigurationException if an error occurs during the load operation */ void load(InputStream in) throws ConfigurationException; /** * Load the configuration from the specified stream, using the specified * encoding. If the encoding is null the default encoding is used. * * @param in the input stream * @param encoding the encoding used. {@code null} to use the default encoding * * @throws ConfigurationException if an error occurs during the load operation */ void load(InputStream in, String encoding) throws ConfigurationException; /** * Load the configuration from the specified reader. * * @param in the reader * * @throws ConfigurationException if an error occurs during the load operation */ void load(Reader in) throws ConfigurationException; /** * Save the configuration. * * @throws ConfigurationException if an error occurs during the save operation */ void save() throws ConfigurationException; /** * Save the configuration to the specified file. * * @param fileName the name of the file to be saved * * @throws ConfigurationException if an error occurs during the save operation */ void save(String fileName) throws ConfigurationException; /** * Save the configuration to the specified file. * * @param file specifies the file to be saved * * @throws ConfigurationException if an error occurs during the save operation */ void save(File file) throws ConfigurationException; /** * Save the configuration to the specified URL. * * @param url the URL * * @throws ConfigurationException if an error occurs during the save operation */ void save(URL url) throws ConfigurationException; /** * Save the configuration to the specified stream, using the encoding * returned by {@link #getEncoding()}. * * @param out the output stream * * @throws ConfigurationException if an error occurs during the save operation */ void save(OutputStream out) throws ConfigurationException; /** * Save the configuration to the specified stream, using the specified * encoding. If the encoding is null the default encoding is used. * * @param out the output stream * @param encoding the encoding to be used * @throws ConfigurationException if an error occurs during the save operation */ void save(OutputStream out, String encoding) throws ConfigurationException; /** * Save the configuration to the specified writer. * * @param out the writer * * @throws ConfigurationException if an error occurs during the save operation */ void save(Writer out) throws ConfigurationException; /** * Return the name of the file. * * @return the file name */ String getFileName(); /** * Set the name of the file. * * @param fileName the name of the file */ void setFileName(String fileName); /** * Returns the base path. One way to specify the location of a configuration * source is by setting its base path and its file name. This method returns * this base path. The concrete value returned by this method depends on the * way the location of the configuration file was set. If methods like * {@code setFile()} or {@code setURL()} were used, the base * path typically points to the parent directory of the configuration file * (e.g. for the URL {@code file:/temp/test.properties} the base path * will be {@code file:/temp/}). If the base path was explicitly set * using {@code setBasePath()}, this method will return the exact * value specified here without further modifications. * * @return the base path * @see AbstractFileConfiguration#setBasePath(String) */ String getBasePath(); /** * Sets the base path. The methods {@code setBasePath()} and * {@code setFileName()} can be used together to specify the location * of the configuration file to be loaded. If relative file names are to * be resolved (e.g. for the include files supported by * {@code PropertiesConfiguration}), this base path will be used. * * @param basePath the base path. */ void setBasePath(String basePath); /** * Return the file where the configuration is stored. * * @return the configuration file */ File getFile(); /** * Set the file where the configuration is stored. * * @param file the file */ void setFile(File file); /** * Return the URL where the configuration is stored. * * @return the URL of the configuration */ URL getURL(); /** * The URL where the configuration is stored. * * @param url the URL */ void setURL(URL url); /** * Enable or disable the automatically saving of modified properties to the disk. * * @param autoSave {@code true} to enable, {@code false} to disable * @since 1.1 */ void setAutoSave(boolean autoSave); /** * Tells if properties are automatically saved to the disk. * * @return {@code true} if auto-saving is enabled, {@code false} otherwise * @since 1.1 */ boolean isAutoSave(); /** * Return the reloading strategy. * * @return the reloading strategy currently used * @since 1.1 */ ReloadingStrategy getReloadingStrategy(); /** * Set the reloading strategy. * * @param strategy the reloading strategy to use * @since 1.1 */ void setReloadingStrategy(ReloadingStrategy strategy); /** * Reload the configuration. * * @since 1.1 */ void reload(); /** * Return the encoding used to store the configuration file. If the value * is null the default encoding is used. * * @return the current encoding * @since 1.1 */ String getEncoding(); /** * Set the encoding used to store the configuration file. Set the encoding * to null to use the default encoding. * * @param encoding the encoding to use * @since 1.1 */ void setEncoding(String encoding); } ././@LongLink100644 0 0 147 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/FileOptionsProvider.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/FileOptionsProvider.ja100644 5502 12232154103 33465 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Map; /** * Some FileSystems allow options to be passed on File operations. Users of commons * configuration can implement this interface and register it with the FileSystem. * @since 1.7 * @author Commons Configuration team * @version $Id: FileOptionsProvider.java 1209884 2011-12-03 10:57:38Z oheger $ */ public interface FileOptionsProvider { /** * Key used to identify the user to be associated with the current file operations. * The value associated with this key is a String identifying the current user. */ String CURRENT_USER = "currentUser"; /** * Key used to indicate whether Webdav versioning support should be enabled. * The value associated with this key is a Boolean where True indicates versioning should * be enabled. */ String VERSIONING = "versioning"; /** * Key used to identify the proxy host to connect through. * The value associated with this key is a String identifying the host name of the proxy. */ String PROXY_HOST = "proxyHost"; /** * Key used to identify the proxy port to connect through. * The value associated with this key is an Integer identifying the port on the proxy. */ String PROXY_PORT = "proxyPort"; /** * Key used to identify the maximum number of connections allowed to a single host. * The value associated with this key is an Integer identifying the maximum number of * connections allowed to a single host. */ String MAX_HOST_CONNECTIONS = "maxHostConnections"; /** * Key used to identify the maximum number of connections allowed to all hosts. * The value associated with this key is an Integer identifying the maximum number of * connections allowed to all hosts. */ String MAX_TOTAL_CONNECTIONS = "maxTotalConnections"; /** * * @return Options to be used for this file. */ Map getOptions(); } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/FileSystem.java100644 12651 12232154102 32154 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.net.MalformedURLException; import java.net.URL; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.impl.NoOpLog; /** * Abstract layer to allow various types of file systems. * @since 1.7 * @author Commons Configuration team * @version $Id: FileSystem.java 1209996 2011-12-03 20:24:21Z oheger $ */ public abstract class FileSystem { /** The name of the system property that can be used to set the file system class name */ private static final String FILE_SYSTEM = "org.apache.commons.configuration.filesystem"; /** The default file system */ private static FileSystem fileSystem; /** The Logger */ private Log log; /** FileSystem options provider */ private FileOptionsProvider optionsProvider; public FileSystem() { setLogger(null); } /** * Returns the logger used by this FileSystem. * * @return the logger */ public Log getLogger() { return log; } /** * Allows to set the logger to be used by this FileSystem. This * method makes it possible for clients to exactly control logging behavior. * Per default a logger is set that will ignore all log messages. Derived * classes that want to enable logging should call this method during their * initialization with the logger to be used. * * @param log the new logger */ public void setLogger(Log log) { this.log = (log != null) ? log : new NoOpLog(); } static { String fsClassName = System.getProperty(FILE_SYSTEM); if (fsClassName != null) { Log log = LogFactory.getLog(FileSystem.class); try { Class clazz = Class.forName(fsClassName); if (FileSystem.class.isAssignableFrom(clazz)) { fileSystem = (FileSystem) clazz.newInstance(); if (log.isDebugEnabled()) { log.debug("Using " + fsClassName); } } } catch (InstantiationException ex) { log.error("Unable to create " + fsClassName, ex); } catch (IllegalAccessException ex) { log.error("Unable to create " + fsClassName, ex); } catch (ClassNotFoundException ex) { log.error("Unable to create " + fsClassName, ex); } } if (fileSystem == null) { fileSystem = new DefaultFileSystem(); } } /** * Set the FileSystem to use. * @param fs The FileSystem * @throws NullPointerException if the FileSystem parameter is null. */ public static void setDefaultFileSystem(FileSystem fs) throws NullPointerException { if (fs == null) { throw new NullPointerException("A FileSystem implementation is required"); } fileSystem = fs; } /** * Reset the FileSystem to the default. */ public static void resetDefaultFileSystem() { fileSystem = new DefaultFileSystem(); } /** * Retrieve the FileSystem being used. * @return The FileSystem. */ public static FileSystem getDefaultFileSystem() { return fileSystem; } /** * Set the FileOptionsProvider * @param provider The FileOptionsProvider */ public void setFileOptionsProvider(FileOptionsProvider provider) { this.optionsProvider = provider; } public FileOptionsProvider getFileOptionsProvider() { return this.optionsProvider; } public abstract InputStream getInputStream(String basePath, String fileName) throws ConfigurationException; public abstract InputStream getInputStream(URL url) throws ConfigurationException; public abstract OutputStream getOutputStream(URL url) throws ConfigurationException; public abstract OutputStream getOutputStream(File file) throws ConfigurationException; public abstract String getPath(File file, URL url, String basePath, String fileName); public abstract String getBasePath(String path); public abstract String getFileName(String path); public abstract URL locateFromURL(String basePath, String fileName); public abstract URL getURL(String basePath, String fileName) throws MalformedURLException; } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/FileSystemBased.java100644 2231 12232154103 33065 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; /** * Interface used to install or locate the FileSystem * @since 1.7 * @author Commons Configuration team */ public interface FileSystemBased { void setFileSystem(FileSystem fileSystem); void resetFileSystem(); FileSystem getFileSystem(); } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalConfigurat100644 170265 12232154103 33577 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.Serializable; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.LinkedList; import java.util.List; import java.util.Set; import java.util.Stack; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.ConfigurationNodeVisitorAdapter; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.configuration.tree.DefaultExpressionEngine; import org.apache.commons.configuration.tree.ExpressionEngine; import org.apache.commons.configuration.tree.NodeAddData; import org.apache.commons.configuration.tree.ViewNode; import org.apache.commons.lang.StringUtils; /** *

A specialized configuration class that extends its base class by the * ability of keeping more structure in the stored properties.

There * are some sources of configuration data that cannot be stored very well in a * {@code BaseConfiguration} object because then their structure is lost. * This is especially true for XML documents. This class can deal with such * structured configuration sources by storing the properties in a tree-like * organization.

The internal used storage form allows for a more * sophisticated access to single properties. As an example consider the * following XML document:

* *

 * <database>
 *   <tables>
 *     <table>
 *       <name>users</name>
 *       <fields>
 *         <field>
 *           <name>lid</name>
 *           <type>long</name>
 *         </field>
 *         <field>
 *           <name>usrName</name>
 *           <type>java.lang.String</type>
 *         </field>
 *        ...
 *       </fields>
 *     </table>
 *     <table>
 *       <name>documents</name>
 *       <fields>
 *         <field>
 *           <name>docid</name>
 *           <type>long</type>
 *         </field>
 *         ...
 *       </fields>
 *     </table>
 *     ...
 *   </tables>
 * </database>
 * 
* *

If this document is parsed and stored in a * {@code HierarchicalConfiguration} object (which can be done by one of * the sub classes), there are enhanced possibilities of accessing properties. * The keys for querying information can contain indices that select a certain * element if there are multiple hits.

For instance the key * {@code tables.table(0).name} can be used to find out the name of the * first table. In opposite {@code tables.table.name} would return a * collection with the names of all available tables. Similarly the key * {@code tables.table(1).fields.field.name} returns a collection with * the names of all fields of the second table. If another index is added after * the {@code field} element, a single field can be accessed: * {@code tables.table(1).fields.field(0).name}.

There is a * {@code getMaxIndex()} method that returns the maximum allowed index * that can be added to a given property key. This method can be used to iterate * over all values defined for a certain property.

*

Since the 1.3 release of Commons Configuration hierarchical * configurations support an expression engine. This expression engine * is responsible for evaluating the passed in configuration keys and map them * to the stored properties. The examples above are valid for the default * expression engine, which is used when a new {@code HierarchicalConfiguration} * instance is created. With the {@code setExpressionEngine()} method a * different expression engine can be set. For instance with * {@link org.apache.commons.configuration.tree.xpath.XPathExpressionEngine} * there is an expression engine available that supports configuration keys in * XPATH syntax.

*

In addition to the events common for all configuration classes hierarchical * configurations support some more events that correspond to some specific * methods and features: *

EVENT_ADD_NODES
The {@code addNodes()} method * was called; the event object contains the key, to which the nodes were added, * and a collection with the new nodes as value.
*
EVENT_CLEAR_TREE
The {@code clearTree()} method was * called; the event object stores the key of the removed sub tree.
*
EVENT_SUBNODE_CHANGED
A {@code SubnodeConfiguration} * that was created from this configuration has been changed. The value property * of the event object contains the original event object as it was sent by the * subnode configuration.

*

Note:Configuration objects of this type can be read concurrently * by multiple threads. However if one of these threads modifies the object, * synchronization has to be performed manually.

* * @author Oliver Heger * @version $Id: HierarchicalConfiguration.java 1330666 2012-04-26 06:12:30Z oheger $ */ public class HierarchicalConfiguration extends AbstractConfiguration implements Serializable, Cloneable { /** * Constant for the clear tree event. * @since 1.3 */ public static final int EVENT_CLEAR_TREE = 10; /** * Constant for the add nodes event. * @since 1.3 */ public static final int EVENT_ADD_NODES = 11; /** * Constant for the subnode configuration modified event. * @since 1.5 */ public static final int EVENT_SUBNODE_CHANGED = 12; /** * The serial version UID. */ private static final long serialVersionUID = 3373812230395363192L; /** Stores the default expression engine to be used for new objects.*/ private static ExpressionEngine defaultExpressionEngine; /** Stores the root node of this configuration. This field is required for * backwards compatibility only. */ private Node root; /** Stores the root configuration node.*/ private ConfigurationNode rootNode; /** Stores the expression engine for this instance.*/ private transient ExpressionEngine expressionEngine; /** * Creates a new instance of {@code HierarchicalConfiguration}. */ public HierarchicalConfiguration() { setRootNode(new Node()); } /** * Creates a new instance of {@code HierarchicalConfiguration} and * copies all data contained in the specified configuration into the new * one. * * @param c the configuration that is to be copied (if null, this * constructor will behave like the standard constructor) * @since 1.4 */ public HierarchicalConfiguration(HierarchicalConfiguration c) { this(); if (c != null) { CloneVisitor visitor = new CloneVisitor(); c.getRootNode().visit(visitor); setRootNode(visitor.getClone()); } } /** * Returns the object to synchronize on a reload. This class is not * reloadable so this object isn't important * * @return the lock object */ public Object getReloadLock() { return this; } /** * Returns the root node of this hierarchical configuration. This method * exists for backwards compatibility only. New code should use the * {@link #getRootNode()} method instead, which operates on * the preferred data type {@code ConfigurationNode}. * * @return the root node */ public Node getRoot() { if (root == null && rootNode != null) { // Dynamically create a snapshot of the root node return new Node(rootNode); } return root; } /** * Sets the root node of this hierarchical configuration. This method * exists for backwards compatibility only. New code should use the * {@link #setRootNode(ConfigurationNode)} method instead, * which operates on the preferred data type {@code ConfigurationNode}. * * @param node the root node */ public void setRoot(Node node) { if (node == null) { throw new IllegalArgumentException("Root node must not be null!"); } root = node; rootNode = null; } /** * Returns the root node of this hierarchical configuration. * * @return the root node * @since 1.3 */ public ConfigurationNode getRootNode() { return (rootNode != null) ? rootNode : root; } /** * Sets the root node of this hierarchical configuration. * * @param rootNode the root node * @since 1.3 */ public void setRootNode(ConfigurationNode rootNode) { if (rootNode == null) { throw new IllegalArgumentException("Root node must not be null!"); } this.rootNode = rootNode; // For backward compatibility also set the old root field. root = (rootNode instanceof Node) ? (Node) rootNode : null; } /** * Returns the default expression engine. * * @return the default expression engine * @since 1.3 */ public static synchronized ExpressionEngine getDefaultExpressionEngine() { if (defaultExpressionEngine == null) { defaultExpressionEngine = new DefaultExpressionEngine(); } return defaultExpressionEngine; } /** * Sets the default expression engine. This expression engine will be used * if no specific engine was set for an instance. It is shared between all * hierarchical configuration instances. So modifying its properties will * impact all instances, for which no specific engine is set. * * @param engine the new default expression engine * @since 1.3 */ public static synchronized void setDefaultExpressionEngine(ExpressionEngine engine) { if (engine == null) { throw new IllegalArgumentException( "Default expression engine must not be null!"); } defaultExpressionEngine = engine; } /** * Returns the expression engine used by this configuration. This method * will never return null; if no specific expression engine was set, * the default expression engine will be returned. * * @return the current expression engine * @since 1.3 */ public ExpressionEngine getExpressionEngine() { return (expressionEngine != null) ? expressionEngine : getDefaultExpressionEngine(); } /** * Sets the expression engine to be used by this configuration. All property * keys this configuration has to deal with will be interpreted by this * engine. * * @param expressionEngine the new expression engine; can be null, * then the default expression engine will be used * @since 1.3 */ public void setExpressionEngine(ExpressionEngine expressionEngine) { this.expressionEngine = expressionEngine; } /** * Fetches the specified property. This task is delegated to the associated * expression engine. * * @param key the key to be looked up * @return the found value */ public Object getProperty(String key) { List nodes = fetchNodeList(key); if (nodes.size() == 0) { return null; } else { List list = new ArrayList(); for (ConfigurationNode node : nodes) { if (node.getValue() != null) { list.add(node.getValue()); } } if (list.size() < 1) { return null; } else { return (list.size() == 1) ? list.get(0) : list; } } } /** * Adds the property with the specified key. This task will be delegated to * the associated {@code ExpressionEngine}, so the passed in key * must match the requirements of this implementation. * * @param key the key of the new property * @param obj the value of the new property */ @Override protected void addPropertyDirect(String key, Object obj) { NodeAddData data = getExpressionEngine().prepareAdd(getRootNode(), key); ConfigurationNode node = processNodeAddData(data); node.setValue(obj); } /** * Adds a collection of nodes at the specified position of the configuration * tree. This method works similar to {@code addProperty()}, but * instead of a single property a whole collection of nodes can be added - * and thus complete configuration sub trees. E.g. with this method it is * possible to add parts of another {@code HierarchicalConfiguration} * object to this object. (However be aware that a * {@code ConfigurationNode} object can only belong to a single * configuration. So if nodes from one configuration are directly added to * another one using this method, the structure of the source configuration * will be broken. In this case you should clone the nodes to be added * before calling {@code addNodes()}.) If the passed in key refers to * an existing and unique node, the new nodes are added to this node. * Otherwise a new node will be created at the specified position in the * hierarchy. * * @param key the key where the nodes are to be added; can be null , * then they are added to the root node * @param nodes a collection with the {@code Node} objects to be * added */ public void addNodes(String key, Collection nodes) { if (nodes == null || nodes.isEmpty()) { return; } fireEvent(EVENT_ADD_NODES, key, nodes, true); ConfigurationNode parent; List target = fetchNodeList(key); if (target.size() == 1) { // existing unique key parent = target.get(0); } else { // otherwise perform an add operation parent = processNodeAddData(getExpressionEngine().prepareAdd( getRootNode(), key)); } if (parent.isAttribute()) { throw new IllegalArgumentException( "Cannot add nodes to an attribute node!"); } for (ConfigurationNode child : nodes) { if (child.isAttribute()) { parent.addAttribute(child); } else { parent.addChild(child); } clearReferences(child); } fireEvent(EVENT_ADD_NODES, key, nodes, false); } /** * Checks if this configuration is empty. Empty means that there are no keys * with any values, though there can be some (empty) nodes. * * @return a flag if this configuration is empty */ public boolean isEmpty() { return !nodeDefined(getRootNode()); } /** * Creates a new {@code Configuration} object containing all keys * that start with the specified prefix. This implementation will return a * {@code HierarchicalConfiguration} object so that the structure of * the keys will be saved. The nodes selected by the prefix (it is possible * that multiple nodes are selected) are mapped to the root node of the * returned configuration, i.e. their children and attributes will become * children and attributes of the new root node. However a value of the root * node is only set if exactly one of the selected nodes contain a value (if * multiple nodes have a value, there is simply no way to decide how these * values are merged together). Note that the returned * {@code Configuration} object is not connected to its source * configuration: updates on the source configuration are not reflected in * the subset and vice versa. * * @param prefix the prefix of the keys for the subset * @return a new configuration object representing the selected subset */ @Override public Configuration subset(String prefix) { Collection nodes = fetchNodeList(prefix); if (nodes.isEmpty()) { return new HierarchicalConfiguration(); } final HierarchicalConfiguration parent = this; HierarchicalConfiguration result = new HierarchicalConfiguration() { // Override interpolate to always interpolate on the parent @Override protected Object interpolate(Object value) { return parent.interpolate(value); } }; CloneVisitor visitor = new CloneVisitor(); // Initialize the new root node Object value = null; int valueCount = 0; for (ConfigurationNode nd : nodes) { if (nd.getValue() != null) { value = nd.getValue(); valueCount++; } nd.visit(visitor); for (ConfigurationNode c : visitor.getClone().getChildren()) { result.getRootNode().addChild(c); } for (ConfigurationNode attr : visitor.getClone().getAttributes()) { result.getRootNode().addAttribute(attr); } } // Determine the value of the new root if (valueCount == 1) { result.getRootNode().setValue(value); } return (result.isEmpty()) ? new HierarchicalConfiguration() : result; } /** *

* Returns a hierarchical subnode configuration object that wraps the * configuration node specified by the given key. This method provides an * easy means of accessing sub trees of a hierarchical configuration. In the * returned configuration the sub tree can directly be accessed, it becomes * the root node of this configuration. Because of this the passed in key * must select exactly one configuration node; otherwise an * {@code IllegalArgumentException} will be thrown. *

*

* The difference between this method and the * {@link #subset(String)} method is that * {@code subset()} supports arbitrary subsets of configuration nodes * while {@code configurationAt()} only returns a single sub tree. * Please refer to the documentation of the * {@code SubnodeConfiguration} class to obtain further information * about subnode configurations and when they should be used. *

*

* With the {@code supportUpdate} flag the behavior of the returned * {@code SubnodeConfiguration} regarding updates of its parent * configuration can be determined. A subnode configuration operates on the * same nodes as its parent, so changes at one configuration are normally * directly visible for the other configuration. There are however changes * of the parent configuration, which are not recognized by the subnode * configuration per default. An example for this is a reload operation (for * file-based configurations): Here the complete node set of the parent * configuration is replaced, but the subnode configuration still references * the old nodes. If such changes should be detected by the subnode * configuration, the {@code supportUpdates} flag must be set to * true. This causes the subnode configuration to reevaluate the key * used for its creation each time it is accessed. This guarantees that the * subnode configuration always stays in sync with its key, even if the * parent configuration's data significantly changes. If such a change * makes the key invalid - because it now no longer points to exactly one * node -, the subnode configuration is not reconstructed, but keeps its * old data. It is then quasi detached from its parent. *

* * @param key the key that selects the sub tree * @param supportUpdates a flag whether the returned subnode configuration * should be able to handle updates of its parent * @return a hierarchical configuration that contains this sub tree * @see SubnodeConfiguration * @since 1.5 */ public SubnodeConfiguration configurationAt(String key, boolean supportUpdates) { List nodes = fetchNodeList(key); if (nodes.size() != 1) { throw new IllegalArgumentException( "Passed in key must select exactly one node: " + key); } return supportUpdates ? createSubnodeConfiguration( nodes.get(0), key) : createSubnodeConfiguration(nodes.get(0)); } /** * Returns a hierarchical subnode configuration for the node specified by * the given key. This is a short form for {@code configurationAt(key, * false)}. * * @param key the key that selects the sub tree * @return a hierarchical configuration that contains this sub tree * @see SubnodeConfiguration * @since 1.3 */ public SubnodeConfiguration configurationAt(String key) { return configurationAt(key, false); } /** * Returns a list of sub configurations for all configuration nodes selected * by the given key. This method will evaluate the passed in key (using the * current {@code ExpressionEngine}) and then create a subnode * configuration for each returned node (like * {@link #configurationAt(String)}}). This is especially * useful when dealing with list-like structures. As an example consider the * configuration that contains data about database tables and their fields. * If you need access to all fields of a certain table, you can simply do * *
     * List fields = config.configurationsAt("tables.table(0).fields.field");
     * for(Iterator it = fields.iterator(); it.hasNext();)
     * {
     *     HierarchicalConfiguration sub = (HierarchicalConfiguration) it.next();
     *     // now the children and attributes of the field node can be
     *     // directly accessed
     *     String fieldName = sub.getString("name");
     *     String fieldType = sub.getString("type");
     *     ...
     * 
* * @param key the key for selecting the desired nodes * @return a list with hierarchical configuration objects; each * configuration represents one of the nodes selected by the passed in key * @since 1.3 */ public List configurationsAt(String key) { List nodes = fetchNodeList(key); List configs = new ArrayList(nodes.size()); for (ConfigurationNode node : nodes) { configs.add(createSubnodeConfiguration(node)); } return configs; } /** * Creates a subnode configuration for the specified node. This method is * called by {@code configurationAt()} and * {@code configurationsAt()}. * * @param node the node, for which a subnode configuration is to be created * @return the configuration for the given node * @since 1.3 */ protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node) { SubnodeConfiguration result = new SubnodeConfiguration(this, node); registerSubnodeConfiguration(result); return result; } /** * Creates a new subnode configuration for the specified node and sets its * construction key. A subnode configuration created this way will be aware * of structural changes of its parent. * * @param node the node, for which a subnode configuration is to be created * @param subnodeKey the key used to construct the configuration * @return the configuration for the given node * @since 1.5 */ protected SubnodeConfiguration createSubnodeConfiguration( ConfigurationNode node, String subnodeKey) { SubnodeConfiguration result = createSubnodeConfiguration(node); result.setSubnodeKey(subnodeKey); return result; } /** * This method is always called when a subnode configuration created from * this configuration has been modified. This implementation transforms the * received event into an event of type {@code EVENT_SUBNODE_CHANGED} * and notifies the registered listeners. * * @param event the event describing the change * @since 1.5 */ protected void subnodeConfigurationChanged(ConfigurationEvent event) { fireEvent(EVENT_SUBNODE_CHANGED, null, event, event.isBeforeUpdate()); } /** * Registers this instance at the given subnode configuration. This * implementation will register a change listener, so that modifications of * the subnode configuration can be tracked. * * @param config the subnode configuration * @since 1.5 */ void registerSubnodeConfiguration(SubnodeConfiguration config) { config.addConfigurationListener(new ConfigurationListener() { public void configurationChanged(ConfigurationEvent event) { subnodeConfigurationChanged(event); } }); } /** * Checks if the specified key is contained in this configuration. Note that * for this configuration the term "contained" means that the key * has an associated value. If there is a node for this key that has no * value but children (either defined or undefined), this method will still * return false . * * @param key the key to be chekced * @return a flag if this key is contained in this configuration */ public boolean containsKey(String key) { return getProperty(key) != null; } /** * Sets the value of the specified property. * * @param key the key of the property to set * @param value the new value of this property */ @Override public void setProperty(String key, Object value) { fireEvent(EVENT_SET_PROPERTY, key, value, true); // Update the existing nodes for this property Iterator itNodes = fetchNodeList(key).iterator(); Iterator itValues; if (!isDelimiterParsingDisabled() || !(value instanceof String)) { itValues = PropertyConverter.toIterator(value, getListDelimiter()); } else { itValues = Collections.singleton(value).iterator(); } while (itNodes.hasNext() && itValues.hasNext()) { itNodes.next().setValue(itValues.next()); } // Add additional nodes if necessary while (itValues.hasNext()) { addPropertyDirect(key, itValues.next()); } // Remove remaining nodes while (itNodes.hasNext()) { clearNode(itNodes.next()); } fireEvent(EVENT_SET_PROPERTY, key, value, false); } /** * Clears this configuration. This is a more efficient implementation than * the one inherited from the base class. It directly removes all data from * the root node. */ @Override public void clear() { fireEvent(EVENT_CLEAR, null, null, true); getRootNode().removeAttributes(); getRootNode().removeChildren(); getRootNode().setValue(null); fireEvent(EVENT_CLEAR, null, null, false); } /** * Removes all values of the property with the given name and of keys that * start with this name. So if there is a property with the key * "foo" and a property with the key "foo.bar", a call * of {@code clearTree("foo")} would remove both properties. * * @param key the key of the property to be removed */ public void clearTree(String key) { fireEvent(EVENT_CLEAR_TREE, key, null, true); List nodes = fetchNodeList(key); for (ConfigurationNode node : nodes) { removeNode(node); } fireEvent(EVENT_CLEAR_TREE, key, nodes, false); } /** * Removes the property with the given key. Properties with names that start * with the given key (i.e. properties below the specified key in the * hierarchy) won't be affected. * * @param key the key of the property to be removed */ @Override public void clearProperty(String key) { fireEvent(EVENT_CLEAR_PROPERTY, key, null, true); List nodes = fetchNodeList(key); for (ConfigurationNode node : nodes) { clearNode(node); } fireEvent(EVENT_CLEAR_PROPERTY, key, null, false); } /** * Returns an iterator with all keys defined in this configuration. * Note that the keys returned by this method will not contain any * indices. This means that some structure will be lost.

* * @return an iterator with the defined keys in this configuration */ public Iterator getKeys() { DefinedKeysVisitor visitor = new DefinedKeysVisitor(); getRootNode().visit(visitor); return visitor.getKeyList().iterator(); } /** * Returns an iterator with all keys defined in this configuration that * start with the given prefix. The returned keys will not contain any * indices. This implementation tries to locate a node whose key is the same * as the passed in prefix. Then the subtree of this node is traversed, and * the keys of all nodes encountered (including attributes) are added to the * result set. * * @param prefix the prefix of the keys to start with * @return an iterator with the found keys */ @Override public Iterator getKeys(String prefix) { DefinedKeysVisitor visitor = new DefinedKeysVisitor(prefix); if (containsKey(prefix)) { // explicitly add the prefix visitor.getKeyList().add(prefix); } List nodes = fetchNodeList(prefix); for (ConfigurationNode node : nodes) { for (ConfigurationNode c : node.getChildren()) { c.visit(visitor); } for (ConfigurationNode attr : node.getAttributes()) { attr.visit(visitor); } } return visitor.getKeyList().iterator(); } /** * Returns the maximum defined index for the given key. This is useful if * there are multiple values for this key. They can then be addressed * separately by specifying indices from 0 to the return value of this * method. * * @param key the key to be checked * @return the maximum defined index for this key */ public int getMaxIndex(String key) { return fetchNodeList(key).size() - 1; } /** * Creates a copy of this object. This new configuration object will contain * copies of all nodes in the same structure. Registered event listeners * won't be cloned; so they are not registered at the returned copy. * * @return the copy * @since 1.2 */ @Override public Object clone() { try { HierarchicalConfiguration copy = (HierarchicalConfiguration) super .clone(); // clone the nodes, too CloneVisitor v = new CloneVisitor(); getRootNode().visit(v); copy.setRootNode(v.getClone()); return copy; } catch (CloneNotSupportedException cex) { // should not happen throw new ConfigurationRuntimeException(cex); } } /** * Returns a configuration with the same content as this configuration, but * with all variables replaced by their actual values. This implementation * is specific for hierarchical configurations. It clones the current * configuration and runs a specialized visitor on the clone, which performs * interpolation on the single configuration nodes. * * @return a configuration with all variables interpolated * @since 1.5 */ @Override public Configuration interpolatedConfiguration() { HierarchicalConfiguration c = (HierarchicalConfiguration) clone(); c.getRootNode().visit(new ConfigurationNodeVisitorAdapter() { @Override public void visitAfterChildren(ConfigurationNode node) { node.setValue(interpolate(node.getValue())); } }); return c; } /** * Helper method for fetching a list of all nodes that are addressed by the * specified key. * * @param key the key * @return a list with all affected nodes (never null ) */ protected List fetchNodeList(String key) { return getExpressionEngine().query(getRootNode(), key); } /** * Recursive helper method for fetching a property. This method processes * all facets of a configuration key, traverses the tree of properties and * fetches the the nodes of all matching properties. * * @param keyPart the configuration key iterator * @param node the actual node * @param nodes here the found nodes are stored * @deprecated Property keys are now evaluated by the expression engine * associated with the configuration; this method will no longer be called. * If you want to modify the way properties are looked up, consider * implementing you own {@code ExpressionEngine} implementation. */ @Deprecated protected void findPropertyNodes(ConfigurationKey.KeyIterator keyPart, Node node, Collection nodes) { } /** * Checks if the specified node is defined. * * @param node the node to be checked * @return a flag if this node is defined * @deprecated Use the method {@link #nodeDefined(ConfigurationNode)} * instead. */ @Deprecated protected boolean nodeDefined(Node node) { return nodeDefined((ConfigurationNode) node); } /** * Checks if the specified node is defined. * * @param node the node to be checked * @return a flag if this node is defined */ protected boolean nodeDefined(ConfigurationNode node) { DefinedVisitor visitor = new DefinedVisitor(); node.visit(visitor); return visitor.isDefined(); } /** * Removes the specified node from this configuration. This method ensures * that parent nodes that become undefined by this operation are also * removed. * * @param node the node to be removed * @deprecated Use the method {@link #removeNode(ConfigurationNode)} * instead. */ @Deprecated protected void removeNode(Node node) { removeNode((ConfigurationNode) node); } /** * Removes the specified node from this configuration. This method ensures * that parent nodes that become undefined by this operation are also * removed. * * @param node the node to be removed */ protected void removeNode(ConfigurationNode node) { ConfigurationNode parent = node.getParentNode(); if (parent != null) { parent.removeChild(node); if (!nodeDefined(parent)) { removeNode(parent); } } } /** * Clears the value of the specified node. If the node becomes undefined by * this operation, it is removed from the hierarchy. * * @param node the node to be cleared * @deprecated Use the method {@link #clearNode(ConfigurationNode)} * instead */ @Deprecated protected void clearNode(Node node) { clearNode((ConfigurationNode) node); } /** * Clears the value of the specified node. If the node becomes undefined by * this operation, it is removed from the hierarchy. * * @param node the node to be cleared */ protected void clearNode(ConfigurationNode node) { node.setValue(null); if (!nodeDefined(node)) { removeNode(node); } } /** * Returns a reference to the parent node of an add operation. Nodes for new * properties can be added as children of this node. If the path for the * specified key does not exist so far, it is created now. * * @param keyIt the iterator for the key of the new property * @param startNode the node to start the search with * @return the parent node for the add operation * @deprecated Adding new properties is now to a major part delegated to the * {@code ExpressionEngine} associated with this configuration instance. * This method will no longer be called. Developers who want to modify the * process of adding new properties should consider implementing their own * expression engine. */ @Deprecated protected Node fetchAddNode(ConfigurationKey.KeyIterator keyIt, Node startNode) { return null; } /** * Finds the last existing node for an add operation. This method traverses * the configuration tree along the specified key. The last existing node on * this path is returned. * * @param keyIt the key iterator * @param node the actual node * @return the last existing node on the given path * @deprecated Adding new properties is now to a major part delegated to the * {@code ExpressionEngine} associated with this configuration instance. * This method will no longer be called. Developers who want to modify the * process of adding new properties should consider implementing their own * expression engine. */ @Deprecated protected Node findLastPathNode(ConfigurationKey.KeyIterator keyIt, Node node) { return null; } /** * Creates the missing nodes for adding a new property. This method ensures * that there are corresponding nodes for all components of the specified * configuration key. * * @param keyIt the key iterator * @param root the base node of the path to be created * @return the last node of the path * @deprecated Adding new properties is now to a major part delegated to the * {@code ExpressionEngine} associated with this configuration instance. * This method will no longer be called. Developers who want to modify the * process of adding new properties should consider implementing their own * expression engine. */ @Deprecated protected Node createAddPath(ConfigurationKey.KeyIterator keyIt, Node root) { return null; } /** * Creates a new {@code Node} object with the specified name. This * method can be overloaded in derived classes if a specific node type is * needed. This base implementation always returns a new object of the * {@code Node} class. * * @param name the name of the new node * @return the new node */ protected Node createNode(String name) { return new Node(name); } /** * Helper method for processing a node add data object obtained from the * expression engine. This method will create all new nodes. * * @param data the data object * @return the new node * @since 1.3 */ private ConfigurationNode processNodeAddData(NodeAddData data) { ConfigurationNode node = data.getParent(); // Create missing nodes on the path for (String name : data.getPathNodes()) { ConfigurationNode child = createNode(name); node.addChild(child); node = child; } // Add new target node ConfigurationNode child = createNode(data.getNewNodeName()); if (data.isAttribute()) { node.addAttribute(child); } else { node.addChild(child); } return child; } /** * Clears all reference fields in a node structure. A configuration node can * store a so-called "reference". The meaning of this data is * determined by a concrete sub class. Typically such references are * specific for a configuration instance. If this instance is cloned or * copied, they must be cleared. This can be done using this method. * * @param node the root node of the node hierarchy, in which the references * are to be cleared * @since 1.4 */ protected static void clearReferences(ConfigurationNode node) { node.visit(new ConfigurationNodeVisitorAdapter() { @Override public void visitBeforeChildren(ConfigurationNode node) { node.setReference(null); } }); } /** * Transforms the specified object into a Node. This method treats view * nodes in a special way. This is necessary because ViewNode does not * extend HierarchicalConfiguration.Node; thus the API for the node visitor * is slightly different. Therefore a view node is transformed into a * special compatibility Node object. * * @param obj the original node object * @return the node to be used */ private static Node getNodeFor(Object obj) { Node nd; if (obj instanceof ViewNode) { final ViewNode viewNode = (ViewNode) obj; nd = new Node(viewNode) { @Override public void setReference(Object reference) { super.setReference(reference); // also set the reference at the original node viewNode.setReference(reference); } }; } else { nd = (Node) obj; } return nd; } /** * A data class for storing (hierarchical) property information. A property * can have a value and an arbitrary number of child properties. From * version 1.3 on this class is only a thin wrapper over the * {@link org.apache.commons.configuration.tree.DefaultConfigurationNode DefaultconfigurationNode} * class that exists mainly for the purpose of backwards compatibility. */ public static class Node extends DefaultConfigurationNode implements Serializable { /** * The serial version UID. */ private static final long serialVersionUID = -6357500633536941775L; /** * Creates a new instance of {@code Node}. */ public Node() { super(); } /** * Creates a new instance of {@code Node} and sets the name. * * @param name the node's name */ public Node(String name) { super(name); } /** * Creates a new instance of {@code Node} and sets the name and the value. * * @param name the node's name * @param value the value */ public Node(String name, Object value) { super(name, value); } /** * Creates a new instance of {@code Node} based on the given * source node. All properties of the source node, including its * children and attributes, will be copied. * * @param src the node to be copied */ public Node(ConfigurationNode src) { this(src.getName(), src.getValue()); setReference(src.getReference()); for (ConfigurationNode nd : src.getChildren()) { // Don't change the parent node ConfigurationNode parent = nd.getParentNode(); addChild(nd); nd.setParentNode(parent); } for (ConfigurationNode nd : src.getAttributes()) { // Don't change the parent node ConfigurationNode parent = nd.getParentNode(); addAttribute(nd); nd.setParentNode(parent); } } /** * Returns the parent of this node. * * @return this node's parent (can be null) */ public Node getParent() { return (Node) getParentNode(); } /** * Sets the parent of this node. * * @param node the parent node */ public void setParent(Node node) { setParentNode(node); } /** * Adds the given node to the children of this node. * * @param node the child to be added */ public void addChild(Node node) { addChild((ConfigurationNode) node); } /** * Returns a flag whether this node has child elements. * * @return true if there is a child node, false otherwise */ public boolean hasChildren() { return getChildrenCount() > 0 || getAttributeCount() > 0; } /** * Removes the specified child from this node. * * @param child the child node to be removed * @return a flag if the child could be found */ public boolean remove(Node child) { return child.isAttribute() ? removeAttribute(child) : removeChild(child); } /** * Removes all children with the given name. * * @param name the name of the children to be removed * @return a flag if children with this name existed */ public boolean remove(String name) { boolean childrenRemoved = removeChild(name); boolean attrsRemoved = removeAttribute(name); return childrenRemoved || attrsRemoved; } /** * A generic method for traversing this node and all of its children. * This method sends the passed in visitor to this node and all of its * children. * * @param visitor the visitor * @param key here a configuration key with the name of the root node of * the iteration can be passed; if this key is not null , the * full paths to the visited nodes are builded and passed to the * visitor's {@code visit()} methods */ public void visit(NodeVisitor visitor, ConfigurationKey key) { int length = 0; if (key != null) { length = key.length(); if (getName() != null) { key .append(StringUtils .replace( isAttribute() ? ConfigurationKey .constructAttributeKey(getName()) : getName(), String .valueOf(ConfigurationKey.PROPERTY_DELIMITER), ConfigurationKey.ESCAPED_DELIMITER)); } } visitor.visitBeforeChildren(this, key); for (Iterator it = getChildren().iterator(); it.hasNext() && !visitor.terminate();) { Object obj = it.next(); getNodeFor(obj).visit(visitor, key); } for (Iterator it = getAttributes().iterator(); it.hasNext() && !visitor.terminate();) { Object obj = it.next(); getNodeFor(obj).visit(visitor, key); } visitor.visitAfterChildren(this, key); if (key != null) { key.setLength(length); } } } /** *

Definition of a visitor class for traversing a node and all of its * children.

This class defines the interface of a visitor for * {@code Node} objects and provides a default implementation. The * method {@code visit()} of {@code Node} implements a generic * iteration algorithm based on the Visitor pattern. By providing * different implementations of visitors it is possible to collect different * data during the iteration process.

* */ public static class NodeVisitor { /** * Visits the specified node. This method is called during iteration for * each node before its children have been visited. * * @param node the actual node * @param key the key of this node (may be null ) */ public void visitBeforeChildren(Node node, ConfigurationKey key) { } /** * Visits the specified node after its children have been processed. * This gives a visitor the opportunity of collecting additional data * after the child nodes have been visited. * * @param node the node to be visited * @param key the key of this node (may be null ) */ public void visitAfterChildren(Node node, ConfigurationKey key) { } /** * Returns a flag that indicates if iteration should be stopped. This * method is called after each visited node. It can be useful for * visitors that search a specific node. If this node is found, the * whole process can be stopped. This base implementation always returns * false . * * @return a flag if iteration should be stopped */ public boolean terminate() { return false; } } /** * A specialized visitor that checks if a node is defined. * "Defined" in this terms means that the node or at least one of * its sub nodes is associated with a value. * */ static class DefinedVisitor extends ConfigurationNodeVisitorAdapter { /** Stores the defined flag. */ private boolean defined; /** * Checks if iteration should be stopped. This can be done if the first * defined node is found. * * @return a flag if iteration should be stopped */ @Override public boolean terminate() { return isDefined(); } /** * Visits the node. Checks if a value is defined. * * @param node the actual node */ @Override public void visitBeforeChildren(ConfigurationNode node) { defined = node.getValue() != null; } /** * Returns the defined flag. * * @return the defined flag */ public boolean isDefined() { return defined; } } /** * A specialized visitor that fills a list with keys that are defined in a * node hierarchy. */ class DefinedKeysVisitor extends ConfigurationNodeVisitorAdapter { /** Stores the list to be filled. */ private Set keyList; /** A stack with the keys of the already processed nodes. */ private Stack parentKeys; /** * Default constructor. */ public DefinedKeysVisitor() { keyList = new LinkedHashSet(); parentKeys = new Stack(); } /** * Creates a new {@code DefinedKeysVisitor} instance and sets the * prefix for the keys to fetch. * * @param prefix the prefix */ public DefinedKeysVisitor(String prefix) { this(); parentKeys.push(prefix); } /** * Returns the list with all defined keys. * * @return the list with the defined keys */ public Set getKeyList() { return keyList; } /** * Visits the node after its children has been processed. Removes this * node's key from the stack. * * @param node the node */ @Override public void visitAfterChildren(ConfigurationNode node) { parentKeys.pop(); } /** * Visits the specified node. If this node has a value, its key is added * to the internal list. * * @param node the node to be visited */ @Override public void visitBeforeChildren(ConfigurationNode node) { String parentKey = parentKeys.isEmpty() ? null : (String) parentKeys.peek(); String key = getExpressionEngine().nodeKey(node, parentKey); parentKeys.push(key); if (node.getValue() != null) { keyList.add(key); } } } /** * A specialized visitor that is able to create a deep copy of a node * hierarchy. */ static class CloneVisitor extends ConfigurationNodeVisitorAdapter { /** A stack with the actual object to be copied. */ private Stack copyStack; /** Stores the result of the clone process. */ private ConfigurationNode result; /** * Creates a new instance of {@code CloneVisitor}. */ public CloneVisitor() { copyStack = new Stack(); } /** * Visits the specified node after its children have been processed. * * @param node the node */ @Override public void visitAfterChildren(ConfigurationNode node) { ConfigurationNode copy = copyStack.pop(); if (copyStack.isEmpty()) { result = copy; } } /** * Visits and copies the specified node. * * @param node the node */ @Override public void visitBeforeChildren(ConfigurationNode node) { ConfigurationNode copy = (ConfigurationNode) node.clone(); copy.setParentNode(null); if (!copyStack.isEmpty()) { if (node.isAttribute()) { copyStack.peek().addAttribute(copy); } else { copyStack.peek().addChild(copy); } } copyStack.push(copy); } /** * Returns the result of the clone process. This is the root node of the * cloned node hierarchy. * * @return the cloned root node */ public ConfigurationNode getClone() { return result; } } /** * A specialized visitor base class that can be used for storing the tree of * configuration nodes. The basic idea is that each node can be associated * with a reference object. This reference object has a concrete meaning in * a derived class, e.g. an entry in a JNDI context or an XML element. When * the configuration tree is set up, the {@code load()} method is * responsible for setting the reference objects. When the configuration * tree is later modified, new nodes do not have a defined reference object. * This visitor class processes all nodes and finds the ones without a * defined reference object. For those nodes the {@code insert()} * method is called, which must be defined in concrete sub classes. This * method can perform all steps to integrate the new node into the original * structure. * */ protected abstract static class BuilderVisitor extends NodeVisitor { /** * Visits the specified node before its children have been traversed. * * @param node the node to visit * @param key the current key */ @Override public void visitBeforeChildren(Node node, ConfigurationKey key) { Collection subNodes = new LinkedList(node.getChildren()); subNodes.addAll(node.getAttributes()); Iterator children = subNodes.iterator(); Node sibling1 = null; Node nd = null; while (children.hasNext()) { // find the next new node do { sibling1 = nd; Object obj = children.next(); nd = getNodeFor(obj); } while (nd.getReference() != null && children.hasNext()); if (nd.getReference() == null) { // find all following new nodes List newNodes = new LinkedList(); newNodes.add(nd); while (children.hasNext()) { Object obj = children.next(); nd = getNodeFor(obj); if (nd.getReference() == null) { newNodes.add(nd); } else { break; } } // Insert all new nodes Node sibling2 = (nd.getReference() == null) ? null : nd; for (Node insertNode : newNodes) { if (insertNode.getReference() == null) { Object ref = insert(insertNode, node, sibling1, sibling2); if (ref != null) { insertNode.setReference(ref); } sibling1 = insertNode; } } } } } /** * Inserts a new node into the structure constructed by this builder. * This method is called for each node that has been added to the * configuration tree after the configuration has been loaded from its * source. These new nodes have to be inserted into the original * structure. The passed in nodes define the position of the node to be * inserted: its parent and the siblings between to insert. The return * value is interpreted as the new reference of the affected * {@code Node} object; if it is not null , it is passed * to the node's {@code setReference()} method. * * @param newNode the node to be inserted * @param parent the parent node * @param sibling1 the sibling after which the node is to be inserted; * can be null if the new node is going to be the first child * node * @param sibling2 the sibling before which the node is to be inserted; * can be null if the new node is going to be the last child * node * @return the reference object for the node to be inserted */ protected abstract Object insert(Node newNode, Node parent, Node sibling1, Node sibling2); } } ././@LongLink100644 0 0 166 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalConfigurationConverter.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalConfigurat100644 16701 12232154102 33550 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** *

A base class for converters that transform a normal configuration * object into a hierarchical configuration.

*

This class provides a default mechanism for iterating over the keys in a * configuration and to throw corresponding element start and end events. By * handling these events a hierarchy can be constructed that is equivalent to * the keys in the original configuration.

*

Concrete sub classes will implement event handlers that generate SAX * events for XML processing or construct a * {@code HierarchicalConfiguration} root node. All in all with this class * it is possible to treat a default configuration as if it was a hierarchical * configuration, which can be sometimes useful.

* @see HierarchicalConfiguration * * @author Commons Configuration team * @version $Id: HierarchicalConfigurationConverter.java 1234985 2012-01-23 21:09:09Z oheger $ */ abstract class HierarchicalConfigurationConverter { /** * Processes the specified configuration object. This method implements * the iteration over the configuration's keys. All defined keys are * translated into a set of element start and end events represented by * calls to the {@code elementStart()} and * {@code elementEnd()} methods. * * @param config the configuration to be processed */ public void process(Configuration config) { if (config != null) { ConfigurationKey keyEmpty = new ConfigurationKey(); ConfigurationKey keyLast = keyEmpty; Set keySet = new HashSet(); for (Iterator it = config.getKeys(); it.hasNext();) { String key = it.next(); if (keySet.contains(key)) { // this key has already been processed by openElements continue; } ConfigurationKey keyAct = new ConfigurationKey(key); closeElements(keyLast, keyAct); String elem = openElements(keyLast, keyAct, config, keySet); fireValue(elem, config.getProperty(key)); keyLast = keyAct; } // close all open closeElements(keyLast, keyEmpty); } } /** * An event handler method that is called when an element starts. * Concrete sub classes must implement it to perform a proper event * handling. * * @param name the name of the new element * @param value the element's value; can be null if the element * does not have any value */ protected abstract void elementStart(String name, Object value); /** * An event handler method that is called when an element ends. For each * call of {@code elementStart()} there will be a corresponding call * of this method. Concrete sub classes must implement it to perform a * proper event handling. * * @param name the name of the ending element */ protected abstract void elementEnd(String name); /** * Fires all necessary element end events for the specified keys. This * method is called for each key obtained from the configuration to be * converted. It calculates the common part of the actual and the last * processed key and thus determines how many elements must be * closed. * * @param keyLast the last processed key * @param keyAct the actual key */ protected void closeElements(ConfigurationKey keyLast, ConfigurationKey keyAct) { ConfigurationKey keyDiff = keyAct.differenceKey(keyLast); Iterator it = reverseIterator(keyDiff); if (it.hasNext()) { // Skip first because it has already been closed by fireValue() it.next(); } while (it.hasNext()) { elementEnd(it.next()); } } /** * Helper method for determining a reverse iterator for the specified key. * This implementation returns an iterator that returns the parts of the * given key in reverse order, ignoring indices. * * @param key the key * @return a reverse iterator for the parts of this key */ protected Iterator reverseIterator(ConfigurationKey key) { List list = new ArrayList(); for (ConfigurationKey.KeyIterator it = key.iterator(); it.hasNext();) { list.add(it.nextKey()); } Collections.reverse(list); return list.iterator(); } /** * Fires all necessary element start events for the specified key. This * method is called for each key obtained from the configuration to be * converted. It ensures that all elements "between" the last key and the * actual key are opened and their values are set. * * @param keyLast the last processed key * @param keyAct the actual key * @param config the configuration to process * @param keySet the set with the processed keys * @return the name of the last element on the path */ protected String openElements(ConfigurationKey keyLast, ConfigurationKey keyAct, Configuration config, Set keySet) { ConfigurationKey.KeyIterator it = keyLast.differenceKey(keyAct).iterator(); ConfigurationKey k = keyLast.commonKey(keyAct); for (it.nextKey(); it.hasNext(); it.nextKey()) { k.append(it.currentKey(true)); elementStart(it.currentKey(true), config.getProperty(k.toString())); keySet.add(k.toString()); } return it.currentKey(true); } /** * Fires all necessary element start events with the actual element values. * This method is called for each key obtained from the configuration to be * processed with the last part of the key as argument. The value can be * either a single value or a collection. * * @param name the name of the actual element * @param value the element's value */ protected void fireValue(String name, Object value) { if (value instanceof Collection) { Collection valueCol = (Collection) value; for (Object v : valueCol) { fireValue(name, v); } } else { elementStart(name, value); elementEnd(name); } } } ././@LongLink100644 0 0 166 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalConfigurationXMLReader.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalConfigurat100644 15132 12232154103 33546 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import org.apache.commons.configuration.HierarchicalConfiguration.Node; import org.apache.commons.configuration.tree.ConfigurationNode; import org.xml.sax.Attributes; import org.xml.sax.helpers.AttributesImpl; /** *

A specialized SAX2 XML parser that "parses" hierarchical * configuration objects.

*

This class mimics to be a SAX conform XML parser. Instead of parsing * XML documents it processes a {@code Configuration} object and * generates SAX events for the single properties defined there. This enables * the whole world of XML processing for configuration objects.

*

The {@code HierarchicalConfiguration} object to be parsed can be * specified using a constructor or the {@code setConfiguration()} method. * This object will be processed by the {@code parse()} methods. Note * that these methods ignore their argument.

* * @author Commons Configuration team * @version $Id: HierarchicalConfigurationXMLReader.java 1209998 2011-12-03 20:31:16Z oheger $ */ public class HierarchicalConfigurationXMLReader extends ConfigurationXMLReader { /** Stores the configuration object to be parsed.*/ private HierarchicalConfiguration configuration; /** * Creates a new instance of {@code HierarchicalConfigurationXMLReader}. */ public HierarchicalConfigurationXMLReader() { super(); } /** * Creates a new instance of {@code HierarchicalConfigurationXMLReader} and * sets the configuration to be parsed. * * @param config the configuration object */ public HierarchicalConfigurationXMLReader(HierarchicalConfiguration config) { this(); setConfiguration(config); } /** * Returns the configuration object to be parsed. * * @return the configuration object to be parsed */ public HierarchicalConfiguration getConfiguration() { return configuration; } /** * Sets the configuration object to be parsed. * * @param config the configuration object to be parsed */ public void setConfiguration(HierarchicalConfiguration config) { configuration = config; } /** * Returns the configuration object to be processed. * * @return the actual configuration object */ @Override public Configuration getParsedConfiguration() { return getConfiguration(); } /** * Processes the actual configuration object to generate SAX parsing events. */ @Override protected void processKeys() { getConfiguration().getRoot().visit(new SAXVisitor(), null); } /** * A specialized visitor class for generating SAX events for a * hierarchical node structure. * */ class SAXVisitor extends HierarchicalConfiguration.NodeVisitor { /** Constant for the attribute type.*/ private static final String ATTR_TYPE = "CDATA"; /** * Visits the specified node after its children have been processed. * * @param node the actual node * @param key the key of this node */ @Override public void visitAfterChildren(Node node, ConfigurationKey key) { if (!isAttributeNode(node)) { fireElementEnd(nodeName(node)); } } /** * Visits the specified node. * * @param node the actual node * @param key the key of this node */ @Override public void visitBeforeChildren(Node node, ConfigurationKey key) { if (!isAttributeNode(node)) { fireElementStart(nodeName(node), fetchAttributes(node)); if (node.getValue() != null) { fireCharacters(node.getValue().toString()); } } } /** * Checks if iteration should be terminated. This implementation stops * iteration after an exception has occurred. * * @return a flag if iteration should be stopped */ @Override public boolean terminate() { return getException() != null; } /** * Returns an object with all attributes for the specified node. * * @param node the actual node * @return an object with all attributes of this node */ protected Attributes fetchAttributes(Node node) { AttributesImpl attrs = new AttributesImpl(); for (ConfigurationNode child : node.getAttributes()) { if (child.getValue() != null) { String attr = child.getName(); attrs.addAttribute(NS_URI, attr, attr, ATTR_TYPE, child.getValue().toString()); } } return attrs; } /** * Helper method for determining the name of a node. If a node has no * name (which is true for the root node), the specified default name * will be used. * * @param node the node to be checked * @return the name for this node */ private String nodeName(Node node) { return (node.getName() == null) ? getRootName() : node.getName(); } /** * Checks if the specified node is an attribute node. In the node * hierarchy attributes are stored as normal child nodes, but with * special names. * * @param node the node to be checked * @return a flag if this is an attribute node */ private boolean isAttributeNode(Node node) { return node.isAttribute(); } } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalINIConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalINIConfigu100644 70607 12232154103 33407 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Set; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.ViewNode; /** *

* A specialized hierarchical configuration implementation for parsing ini * files. *

*

* An initialization or ini file is a configuration file typically found on * Microsoft's Windows operating system and contains data for Windows based * applications. *

*

* Although popularized by Windows, ini files can be used on any system or * platform due to the fact that they are merely text files that can easily be * parsed and modified by both humans and computers. *

*

* A typical ini file could look something like: *

*
 * [section1]
 * ; this is a comment!
 * var1 = foo
 * var2 = bar
 *
 * [section2]
 * var1 = doo
 * 
*

* The format of ini files is fairly straight forward and is composed of three * components:
*

    *
  • Sections: Ini files are split into sections, each section starting * with a section declaration. A section declaration starts with a '[' and ends * with a ']'. Sections occur on one line only.
  • *
  • Parameters: Items in a section are known as parameters. Parameters * have a typical {@code key = value} format.
  • *
  • Comments: Lines starting with a ';' are assumed to be comments.
  • *
*

*

* There are various implementations of the ini file format by various vendors * which has caused a number of differences to appear. As far as possible this * configuration tries to be lenient and support most of the differences. *

*

* Some of the differences supported are as follows: *

    *
  • Comments: The '#' character is also accepted as a comment * signifier.
  • *
  • Key value separator: The ':' character is also accepted in place of * '=' to separate keys and values in parameters, for example * {@code var1 : foo}.
  • *
  • Duplicate sections: Typically duplicate sections are not allowed, * this configuration does however support this feature. In the event of a duplicate * section, the two section's values are merged so that there is only a single * section. Note: This also affects the internal data of the * configuration. If it is saved, only a single section is written!
  • *
  • Duplicate parameters: Typically duplicate parameters are only * allowed if they are in two different sections, thus they are local to * sections; this configuration simply merges duplicates; if a section has a * duplicate parameter the values are then added to the key as a list.
  • *
*

*

* Global parameters are also allowed; any parameters declared before a section * is declared are added to a global section. It is important to note that this * global section does not have a name. *

*

* In all instances, a parameter's key is prepended with its section name and a * '.' (period). Thus a parameter named "var1" in "section1" will have the key * {@code section1.var1} in this configuration. (This is the default * behavior. Because this is a hierarchical configuration you can change this by * setting a different {@link org.apache.commons.configuration.tree.ExpressionEngine}.) *

*

*

Implementation Details:

Consider the following ini file:
*
 *  default = ok
 *
 *  [section1]
 *  var1 = foo
 *  var2 = doodle
 *
 *  [section2]
 *  ; a comment
 *  var1 = baz
 *  var2 = shoodle
 *  bad =
 *  = worse
 *
 *  [section3]
 *  # another comment
 *  var1 : foo
 *  var2 : bar
 *  var5 : test1
 *
 *  [section3]
 *  var3 = foo
 *  var4 = bar
 *  var5 = test2
 *
 *  [sectionSeparators]
 *  passwd : abc=def
 *  a:b = "value"
 *  
*

*

* This ini file will be parsed without error. Note: *

    *
  • The parameter named "default" is added to the global section, it's value * is accessed simply using {@code getProperty("default")}.
  • *
  • Section 1's parameters can be accessed using * {@code getProperty("section1.var1")}.
  • *
  • The parameter named "bad" simply adds the parameter with an empty value.
  • *
  • The empty key with value "= worse" is added using a key consisting of a * single space character. This key is still added to section 2 and the value * can be accessed using {@code getProperty("section2. ")}, notice the * period '.' and the space following the section name.
  • *
  • Section three uses both '=' and ':' to separate keys and values.
  • *
  • Section 3 has a duplicate key named "var5". The value for this key is * [test1, test2], and is represented as a List.
  • *
  • The section called sectionSeparators demonstrates how the * configuration deals with multiple occurrences of separator characters. Per * default the first separator character in a line is detected and used to * split the key from the value. Therefore the first property definition in this * section has the key {@code passwd} and the value {@code abc=def}. * This default behavior can be changed by using quotes. If there is a separator * character before the first quote character (ignoring whitespace), this * character is used as separator. Thus the second property definition in the * section has the key {@code a:b} and the value {@code value}.
  • *
*

*

* Internally, this configuration maps the content of the represented ini file * to its node structure in the following way: *

    *
  • Sections are represented by direct child nodes of the root node.
  • *
  • For the content of a section, corresponding nodes are created as children * of the section node.
  • *
* This explains how the keys for the properties can be constructed. You can * also use other methods of {@link HierarchicalConfiguration} for querying or * manipulating the hierarchy of configuration nodes, for instance the * {@code configurationAt()} method for obtaining the data of a specific * section. However, be careful that the storage scheme described above is not * violated (e.g. by adding multiple levels of nodes or inserting duplicate * section nodes). Otherwise, the special methods for ini configurations may not * work correctly! *

*

* The set of sections in this configuration can be retrieved using the * {@code getSections()} method. For obtaining a * {@code SubnodeConfiguration} with the content of a specific section the * {@code getSection()} method can be used. *

*

* Note: Configuration objects of this type can be read concurrently by * multiple threads. However if one of these threads modifies the object, * synchronization has to be performed manually. *

* * @author Commons * Configuration team * @version $Id: HierarchicalINIConfiguration.java 1234362 2012-01-21 16:59:48Z oheger $ * @since 1.6 */ public class HierarchicalINIConfiguration extends AbstractHierarchicalFileConfiguration { /** * The characters that signal the start of a comment line. */ protected static final String COMMENT_CHARS = "#;"; /** * The characters used to separate keys from values. */ protected static final String SEPARATOR_CHARS = "=:"; /** * The serial version UID. */ private static final long serialVersionUID = 2548006161386850670L; /** * Constant for the line separator. */ private static final String LINE_SEPARATOR = System.getProperty("line.separator"); /** * The characters used for quoting values. */ private static final String QUOTE_CHARACTERS = "\"'"; /** * The line continuation character. */ private static final String LINE_CONT = "\\"; /** * Create a new empty INI Configuration. */ public HierarchicalINIConfiguration() { super(); } /** * Create and load the ini configuration from the given file. * * @param filename The name pr path of the ini file to load. * @throws ConfigurationException If an error occurs while loading the file */ public HierarchicalINIConfiguration(String filename) throws ConfigurationException { super(filename); } /** * Create and load the ini configuration from the given file. * * @param file The ini file to load. * @throws ConfigurationException If an error occurs while loading the file */ public HierarchicalINIConfiguration(File file) throws ConfigurationException { super(file); } /** * Create and load the ini configuration from the given url. * * @param url The url of the ini file to load. * @throws ConfigurationException If an error occurs while loading the file */ public HierarchicalINIConfiguration(URL url) throws ConfigurationException { super(url); } /** * Save the configuration to the specified writer. * * @param writer - The writer to save the configuration to. * @throws ConfigurationException If an error occurs while writing the * configuration */ public void save(Writer writer) throws ConfigurationException { PrintWriter out = new PrintWriter(writer); Iterator it = getSections().iterator(); while (it.hasNext()) { String section = it.next(); Configuration subset; if (section != null) { out.print("["); out.print(section); out.print("]"); out.println(); subset = createSubnodeConfiguration(getSectionNode(section)); } else { subset = getSection(null); } Iterator keys = subset.getKeys(); while (keys.hasNext()) { String key = keys.next(); Object value = subset.getProperty(key); if (value instanceof Collection) { Iterator values = ((Collection) value).iterator(); while (values.hasNext()) { value = values.next(); out.print(key); out.print(" = "); out.print(formatValue(value.toString())); out.println(); } } else { out.print(key); out.print(" = "); out.print(formatValue(value.toString())); out.println(); } } out.println(); } out.flush(); } /** * Load the configuration from the given reader. Note that the * {@code clear()} method is not called so the configuration read in will * be merged with the current configuration. * * @param reader The reader to read the configuration from. * @throws ConfigurationException If an error occurs while reading the * configuration */ public void load(Reader reader) throws ConfigurationException { try { BufferedReader bufferedReader = new BufferedReader(reader); ConfigurationNode sectionNode = getRootNode(); String line = bufferedReader.readLine(); while (line != null) { line = line.trim(); if (!isCommentLine(line)) { if (isSectionLine(line)) { String section = line.substring(1, line.length() - 1); sectionNode = getSectionNode(section); } else { String key = ""; String value = ""; int index = findSeparator(line); if (index >= 0) { key = line.substring(0, index); value = parseValue(line.substring(index + 1), bufferedReader); } else { key = line; } key = key.trim(); if (key.length() < 1) { // use space for properties with no key key = " "; } createValueNodes(sectionNode, key, value); } } line = bufferedReader.readLine(); } } catch (IOException e) { throw new ConfigurationException( "Unable to load the configuration", e); } } /** * Creates the node(s) for the given key value-pair. If delimiter parsing is * enabled, the value string is split if possible, and for each single value * a node is created. Otherwise only a single node is added to the section. * * @param sectionNode the section node new nodes have to be added * @param key the key * @param value the value string */ private void createValueNodes(ConfigurationNode sectionNode, String key, String value) { Collection values; if (isDelimiterParsingDisabled()) { values = Collections.singleton(value); } else { values = PropertyConverter.split(value, getListDelimiter(), false); } for (String v : values) { ConfigurationNode node = createNode(key); node.setValue(v); sectionNode.addChild(node); } } /** * Parse the value to remove the quotes and ignoring the comment. Example: * *
     * "value" ; comment -> value
     * 
* *
     * 'value' ; comment -> value
     * 
* Note that a comment character is only recognized if there is at least one * whitespace character before it. So it can appear in the property value, * e.g.: *
     * C:\\Windows;C:\\Windows\\system32
     * 
* * @param val the value to be parsed * @param reader the reader (needed if multiple lines have to be read) * @throws IOException if an IO error occurs */ private static String parseValue(String val, BufferedReader reader) throws IOException { StringBuilder propertyValue = new StringBuilder(); boolean lineContinues; String value = val.trim(); do { boolean quoted = value.startsWith("\"") || value.startsWith("'"); boolean stop = false; boolean escape = false; char quote = quoted ? value.charAt(0) : 0; int i = quoted ? 1 : 0; StringBuilder result = new StringBuilder(); char lastChar = 0; while (i < value.length() && !stop) { char c = value.charAt(i); if (quoted) { if ('\\' == c && !escape) { escape = true; } else if (!escape && quote == c) { stop = true; } else if (escape && quote == c) { escape = false; result.append(c); } else { if (escape) { escape = false; result.append('\\'); } result.append(c); } } else { if (isCommentChar(c) && Character.isWhitespace(lastChar)) { stop = true; } else { result.append(c); } } i++; lastChar = c; } String v = result.toString(); if (!quoted) { v = v.trim(); lineContinues = lineContinues(v); if (lineContinues) { // remove trailing "\" v = v.substring(0, v.length() - 1).trim(); } } else { lineContinues = lineContinues(value, i); } propertyValue.append(v); if (lineContinues) { propertyValue.append(LINE_SEPARATOR); value = reader.readLine(); } } while (lineContinues && value != null); return propertyValue.toString(); } /** * Tests whether the specified string contains a line continuation marker. * * @param line the string to check * @return a flag whether this line continues */ private static boolean lineContinues(String line) { String s = line.trim(); return s.equals(LINE_CONT) || (s.length() > 2 && s.endsWith(LINE_CONT) && Character .isWhitespace(s.charAt(s.length() - 2))); } /** * Tests whether the specified string contains a line continuation marker * after the specified position. This method parses the string to remove a * comment that might be present. Then it checks whether a line continuation * marker can be found at the end. * * @param line the line to check * @param pos the start position * @return a flag whether this line continues */ private static boolean lineContinues(String line, int pos) { String s; if (pos >= line.length()) { s = line; } else { int end = pos; while (end < line.length() && !isCommentChar(line.charAt(end))) { end++; } s = line.substring(pos, end); } return lineContinues(s); } /** * Tests whether the specified character is a comment character. * * @param c the character * @return a flag whether this character starts a comment */ private static boolean isCommentChar(char c) { return COMMENT_CHARS.indexOf(c) >= 0; } /** * Tries to find the index of the separator character in the given string. * This method checks for the presence of separator characters in the given * string. If multiple characters are found, the first one is assumed to be * the correct separator. If there are quoting characters, they are taken * into account, too. * * @param line the line to be checked * @return the index of the separator character or -1 if none is found */ private static int findSeparator(String line) { int index = findSeparatorBeforeQuote(line, findFirstOccurrence(line, QUOTE_CHARACTERS)); if (index < 0) { index = findFirstOccurrence(line, SEPARATOR_CHARS); } return index; } /** * Checks for the occurrence of the specified separators in the given line. * The index of the first separator is returned. * * @param line the line to be investigated * @param separators a string with the separator characters to look for * @return the lowest index of a separator character or -1 if no separator * is found */ private static int findFirstOccurrence(String line, String separators) { int index = -1; for (int i = 0; i < separators.length(); i++) { char sep = separators.charAt(i); int pos = line.indexOf(sep); if (pos >= 0) { if (index < 0 || pos < index) { index = pos; } } } return index; } /** * Searches for a separator character directly before a quoting character. * If the first non-whitespace character before a quote character is a * separator, it is considered the "real" separator in this line - even if * there are other separators before. * * @param line the line to be investigated * @param quoteIndex the index of the quote character * @return the index of the separator before the quote or < 0 if there is * none */ private static int findSeparatorBeforeQuote(String line, int quoteIndex) { int index = quoteIndex - 1; while (index >= 0 && Character.isWhitespace(line.charAt(index))) { index--; } if (index >= 0 && SEPARATOR_CHARS.indexOf(line.charAt(index)) < 0) { index = -1; } return index; } /** * Add quotes around the specified value if it contains a comment character. */ private String formatValue(String value) { boolean quoted = false; for (int i = 0; i < COMMENT_CHARS.length() && !quoted; i++) { char c = COMMENT_CHARS.charAt(i); if (value.indexOf(c) != -1) { quoted = true; } } if (quoted) { return '"' + value.replaceAll("\"", "\\\\\\\"") + '"'; } else { return value; } } /** * Determine if the given line is a comment line. * * @param line The line to check. * @return true if the line is empty or starts with one of the comment * characters */ protected boolean isCommentLine(String line) { if (line == null) { return false; } // blank lines are also treated as comment lines return line.length() < 1 || COMMENT_CHARS.indexOf(line.charAt(0)) >= 0; } /** * Determine if the given line is a section. * * @param line The line to check. * @return true if the line contains a section */ protected boolean isSectionLine(String line) { if (line == null) { return false; } return line.startsWith("[") && line.endsWith("]"); } /** * Return a set containing the sections in this ini configuration. Note that * changes to this set do not affect the configuration. * * @return a set containing the sections. */ public Set getSections() { Set sections = new LinkedHashSet(); boolean globalSection = false; boolean inSection = false; for (ConfigurationNode node : getRootNode().getChildren()) { if (isSectionNode(node)) { inSection = true; sections.add(node.getName()); } else { if (!inSection && !globalSection) { globalSection = true; sections.add(null); } } } return sections; } /** * Returns a configuration with the content of the specified section. This * provides an easy way of working with a single section only. The way this * configuration is structured internally, this method is very similar to * calling {@link HierarchicalConfiguration#configurationAt(String)} with * the name of the section in question. There are the following differences * however: *
    *
  • This method never throws an exception. If the section does not exist, * it is created now. The configuration returned in this case is empty.
  • *
  • If section is contained multiple times in the configuration, the * configuration returned by this method is initialized with the first * occurrence of the section. (This can only happen if * {@code addProperty()} has been used in a way that does not conform * to the storage scheme used by {@code HierarchicalINIConfiguration}. * If used correctly, there will not be duplicate sections.)
  • *
  • There is special support for the global section: Passing in * null as section name returns a configuration with the content of * the global section (which may also be empty).
  • *
* * @param name the name of the section in question; null represents * the global section * @return a configuration containing only the properties of the specified * section */ public SubnodeConfiguration getSection(String name) { if (name == null) { return getGlobalSection(); } else { try { return configurationAt(name); } catch (IllegalArgumentException iex) { // the passed in key does not map to exactly one node // obtain the node for the section, create it on demand return new SubnodeConfiguration(this, getSectionNode(name)); } } } /** * Obtains the node representing the specified section. This method is * called while the configuration is loaded. If a node for this section * already exists, it is returned. Otherwise a new node is created. * * @param sectionName the name of the section * @return the node for this section */ private ConfigurationNode getSectionNode(String sectionName) { List nodes = getRootNode().getChildren(sectionName); if (!nodes.isEmpty()) { return nodes.get(0); } ConfigurationNode node = createNode(sectionName); markSectionNode(node); getRootNode().addChild(node); return node; } /** * Creates a sub configuration for the global section of the represented INI * configuration. * * @return the sub configuration for the global section */ private SubnodeConfiguration getGlobalSection() { ViewNode parent = new ViewNode(); for (ConfigurationNode node : getRootNode().getChildren()) { if (!isSectionNode(node)) { synchronized (node) { parent.addChild(node); } } } return createSubnodeConfiguration(parent); } /** * Marks a configuration node as a section node. This means that this node * represents a section header. This implementation uses the node's * reference property to store a flag. * * @param node the node to be marked */ private static void markSectionNode(ConfigurationNode node) { node.setReference(Boolean.TRUE); } /** * Checks whether the specified configuration node represents a section. * * @param node the node in question * @return a flag whether this node represents a section */ private static boolean isSectionNode(ConfigurationNode node) { return node.getReference() != null || node.getChildrenCount() > 0; } } ././@LongLink100644 0 0 167 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalReloadableConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalReloadable100644 5372 12232154102 33463 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import org.apache.commons.configuration.reloading.Reloadable; /** *

A base class for hierarchical configurations with specific reloading * requirements.

*

This class manages a lock object which can be used for synchronization.

* * @author Commons * Configuration team * @since 1.7 * @version $Id: HierarchicalReloadableConfiguration.java 1210000 2011-12-03 20:43:38Z oheger $ */ public class HierarchicalReloadableConfiguration extends HierarchicalConfiguration implements Reloadable { /** Constant for the name used for the lock object. */ private static final String LOCK_NAME = "HierarchicalReloadableConfigurationLock"; /** The lock object used by this instance. */ private final Object reloadLock; /** * Creates a new instance of {@code HierarchicalReloadableConfiguration}. */ public HierarchicalReloadableConfiguration() { super(); reloadLock = new Lock(LOCK_NAME); } /** * Creates a new instance of {@code HierarchicalReloadableConfiguration} and * initializes it with the given lock object. * * @param lock the lock object */ public HierarchicalReloadableConfiguration(Object lock) { super(); reloadLock = lock == null ? new Lock(LOCK_NAME) : lock; } /** * Creates a new instance of {@code HierarchicalReloadableConfiguration} and * copies all data contained in the specified configuration into the new * one. * * @param c the configuration that is to be copied (if null, this * constructor will behave like the standard constructor) */ public HierarchicalReloadableConfiguration(HierarchicalConfiguration c) { super(c); reloadLock = new Lock(LOCK_NAME); } @Override public Object getReloadLock() { return reloadLock; } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalXMLConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/HierarchicalXMLConfigu100644 3152 12232154102 33376 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; /** * A specialized hierarchical configuration class that is able to parse XML * documents. * *

The parsed document will be stored keeping its structure. The contained * properties can be accessed using all methods supported by the base class * {@code HierarchicalConfiguration}. * * @since commons-configuration 1.0 * * @author Jörg Schaible * @version $Id: HierarchicalXMLConfiguration.java 1210002 2011-12-03 20:54:17Z oheger $ * @deprecated This class is deprecated. Use {@code XMLConfiguration} * instead, which supports all features this class had offered before. */ @Deprecated public class HierarchicalXMLConfiguration extends XMLConfiguration { /** * The serial version UID. */ private static final long serialVersionUID = 5597530014798917521L; } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/INIConfiguration.java100644 35264 12232154103 33245 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.Collection; import java.util.Iterator; import java.util.Set; import java.util.TreeSet; /** *

* An initialization or ini file is a configuration file typically found on * Microsoft's Windows operating system and contains data for Windows based * applications. *

* *

* Although popularized by Windows, ini files can be used on any system or * platform due to the fact that they are merely text files that can easily be * parsed and modified by both humans and computers. *

* *

* A typical ini file could look something like: *

*
 * [section1]
 * ; this is a comment!
 * var1 = foo
 * var2 = bar
 *
 * [section2]
 * var1 = doo
 * 
* *

* The format of ini files is fairly straight forward and is composed of three * components:
*

    *
  • Sections: Ini files are split into sections, each section * starting with a section declaration. A section declaration starts with a '[' * and ends with a ']'. Sections occur on one line only.
  • *
  • Parameters: Items in a section are known as parameters. * Parameters have a typical {@code key = value} format.
  • *
  • Comments: Lines starting with a ';' are assumed to be comments. *
  • *
*

* *

* There are various implementations of the ini file format by various vendors * which has caused a number of differences to appear. As far as possible this * configuration tries to be lenient and support most of the differences. *

* *

* Some of the differences supported are as follows: *

    *
  • Comments: The '#' character is also accepted as a comment * signifier.
  • *
  • Key value separtor: The ':' character is also accepted in place * of '=' to separate keys and values in parameters, for example * {@code var1 : foo}.
  • *
  • Duplicate sections: Typically duplicate sections are not allowed , * this configuration does however support it. In the event of a duplicate * section, the two section's values are merged.
  • *
  • Duplicate parameters: Typically duplicate parameters are only * allowed if they are in two different sections, thus they are local to * sections; this configuration simply merges duplicates; if a section has a * duplicate parameter the values are then added to the key as a list.
  • *
*

*

* Global parameters are also allowed; any parameters declared before a section * is declared are added to a global section. It is important to note that this * global section does not have a name. *

*

* In all instances, a parameter's key is prepended with its section name and a * '.' (period). Thus a parameter named "var1" in "section1" will have the key * {@code section1.var1} in this configuration. Thus, a section's * parameters can easily be retrieved using the {@code subset} method * using the section name as the prefix. *

*

*

Implementation Details:

* Consider the following ini file:
*
 *  default = ok
 *
 *  [section1]
 *  var1 = foo
 *  var2 = doodle
 *
 *  [section2]
 *  ; a comment
 *  var1 = baz
 *  var2 = shoodle
 *  bad =
 *  = worse
 *
 *  [section3]
 *  # another comment
 *  var1 : foo
 *  var2 : bar
 *  var5 : test1
 *
 *  [section3]
 *  var3 = foo
 *  var4 = bar
 *  var5 = test2
 *  
*

*

* This ini file will be parsed without error. Note: *

    *
  • The parameter named "default" is added to the global section, it's value * is accessed simply using {@code getProperty("default")}.
  • *
  • Section 1's parameters can be accessed using * {@code getProperty("section1.var1")}.
  • *
  • The parameter named "bad" simply adds the parameter with an empty value. *
  • *
  • The empty key with value "= worse" is added using an empty key. This key * is still added to section 2 and the value can be accessed using * {@code getProperty("section2.")}, notice the period '.' following the * section name.
  • *
  • Section three uses both '=' and ':' to separate keys and values.
  • *
  • Section 3 has a duplicate key named "var5". The value for this key is * [test1, test2], and is represented as a List.
  • *
*

*

* The set of sections in this configuration can be retrieved using the * {@code getSections} method. *

*

* Note: Configuration objects of this type can be read concurrently * by multiple threads. However if one of these threads modifies the object, * synchronization has to be performed manually. *

* * @author Trevor Miller * @version $Id: INIConfiguration.java 1210003 2011-12-03 20:54:46Z oheger $ * @since 1.4 * @deprecated This class has been replaced by HierarchicalINIConfiguration, * which provides a superset of the functionality offered by this class. */ @Deprecated public class INIConfiguration extends AbstractFileConfiguration { /** * The characters that signal the start of a comment line. */ protected static final String COMMENT_CHARS = "#;"; /** * The characters used to separate keys from values. */ protected static final String SEPARATOR_CHARS = "=:"; /** * Create a new empty INI Configuration. */ public INIConfiguration() { super(); } /** * Create and load the ini configuration from the given file. * * @param filename The name pr path of the ini file to load. * @throws ConfigurationException If an error occurs while loading the file */ public INIConfiguration(String filename) throws ConfigurationException { super(filename); } /** * Create and load the ini configuration from the given file. * * @param file The ini file to load. * @throws ConfigurationException If an error occurs while loading the file */ public INIConfiguration(File file) throws ConfigurationException { super(file); } /** * Create and load the ini configuration from the given url. * * @param url The url of the ini file to load. * @throws ConfigurationException If an error occurs while loading the file */ public INIConfiguration(URL url) throws ConfigurationException { super(url); } /** * Save the configuration to the specified writer. * * @param writer - The writer to save the configuration to. * @throws ConfigurationException If an error occurs while writing the * configuration */ public void save(Writer writer) throws ConfigurationException { PrintWriter out = new PrintWriter(writer); Iterator it = getSections().iterator(); while (it.hasNext()) { String section = it.next(); out.print("["); out.print(section); out.print("]"); out.println(); Configuration subset = subset(section); Iterator keys = subset.getKeys(); while (keys.hasNext()) { String key = keys.next(); Object value = subset.getProperty(key); if (value instanceof Collection) { Iterator values = ((Collection) value).iterator(); while (values.hasNext()) { value = values.next(); out.print(key); out.print(" = "); out.print(formatValue(value.toString())); out.println(); } } else { out.print(key); out.print(" = "); out.print(formatValue(value.toString())); out.println(); } } out.println(); } out.flush(); } /** * Load the configuration from the given reader. Note that the * {@code clear()} method is not called so the configuration read in * will be merged with the current configuration. * * @param reader The reader to read the configuration from. * @throws ConfigurationException If an error occurs while reading the * configuration */ public void load(Reader reader) throws ConfigurationException { try { BufferedReader bufferedReader = new BufferedReader(reader); String line = bufferedReader.readLine(); String section = ""; while (line != null) { line = line.trim(); if (!isCommentLine(line)) { if (isSectionLine(line)) { section = line.substring(1, line.length() - 1) + "."; } else { String key = ""; String value = ""; int index = line.indexOf("="); if (index >= 0) { key = section + line.substring(0, index); value = parseValue(line.substring(index + 1)); } else { index = line.indexOf(":"); if (index >= 0) { key = section + line.substring(0, index); value = parseValue(line.substring(index + 1)); } else { key = section + line; } } addProperty(key.trim(), value); } } line = bufferedReader.readLine(); } } catch (IOException e) { throw new ConfigurationException("Unable to load the configuration", e); } } /** * Parse the value to remove the quotes and ignoring the comment. * Example: * *
"value" ; comment -> value
* *
'value' ; comment -> value
* * @param value */ private String parseValue(String value) { value = value.trim(); boolean quoted = value.startsWith("\"") || value.startsWith("'"); boolean stop = false; boolean escape = false; char quote = quoted ? value.charAt(0) : 0; int i = quoted ? 1 : 0; StringBuilder result = new StringBuilder(); while (i < value.length() && !stop) { char c = value.charAt(i); if (quoted) { if ('\\' == c && !escape) { escape = true; } else if (!escape && quote == c) { stop = true; } else if (escape && quote == c) { escape = false; result.append(c); } else { if (escape) { escape = false; result.append('\\'); } result.append(c); } } else { if (COMMENT_CHARS.indexOf(c) == -1) { result.append(c); } else { stop = true; } } i++; } String v = result.toString(); if (!quoted) { v = v.trim(); } return v; } /** * Add quotes around the specified value if it contains a comment character. */ private String formatValue(String value) { boolean quoted = false; for (int i = 0; i < COMMENT_CHARS.length() && !quoted; i++) { char c = COMMENT_CHARS.charAt(i); if (value.indexOf(c) != -1) { quoted = true; } } if (quoted) { return '"' + value.replaceAll("\"", "\\\\\\\"") + '"'; } else { return value; } } /** * Determine if the given line is a comment line. * * @param line The line to check. * @return true if the line is empty or starts with one of the comment * characters */ protected boolean isCommentLine(String line) { if (line == null) { return false; } // blank lines are also treated as comment lines return line.length() < 1 || COMMENT_CHARS.indexOf(line.charAt(0)) >= 0; } /** * Determine if the given line is a section. * * @param line The line to check. * @return true if the line contains a secion */ protected boolean isSectionLine(String line) { if (line == null) { return false; } return line.startsWith("[") && line.endsWith("]"); } /** * Return a set containing the sections in this ini configuration. Note that * changes to this set do not affect the configuration. * * @return a set containing the sections. */ public Set getSections() { Set sections = new TreeSet(); Iterator keys = getKeys(); while (keys.hasNext()) { String key = keys.next(); int index = key.indexOf("."); if (index >= 0) { sections.add(key.substring(0, index)); } } return sections; } } ././@LongLink100644 0 0 166 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/ConfigurationInterpolator.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/Configuration100644 33070 12232154102 33611 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.interpol; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.apache.commons.lang.text.StrLookup; /** *

* A class that handles interpolation (variable substitution) for configuration * objects. *

*

* Each instance of {@code AbstractConfiguration} is associated with an * object of this class. All interpolation tasks are delegated to this object. *

*

* {@code ConfigurationInterpolator} works together with the * {@code StrSubstitutor} class from Commons Lang. By extending * {@code StrLookup} it is able to provide values for variables that * appear in expressions. *

*

* The basic idea of this class is that it can maintain a set of primitive * {@code StrLookup} objects, each of which is identified by a special * prefix. The variables to be processed have the form * ${prefix:name}. {@code ConfigurationInterpolator} will * extract the prefix and determine, which primitive lookup object is registered * for it. Then the name of the variable is passed to this object to obtain the * actual value. It is also possible to define a default lookup object, which * will be used for variables that do not have a prefix or that cannot be * resolved by their associated lookup object. *

*

* When a new instance of this class is created it is initialized with a default * set of primitive lookup objects. This set can be customized using the static * methods {@code registerGlobalLookup()} and * {@code deregisterGlobalLookup()}. Per default it contains the * following standard lookup objects: *

*

* * * * * * * * * * * * * *
PrefixLookup object
sysWith this prefix a lookup object is associated that is able to resolve * system properties.
constThe {@code const} prefix indicates that a variable is to be * interpreted as a constant member field of a class (i.e. a field with the * static final modifiers). The name of the variable must be of the form * {@code .}, e.g. * {@code org.apache.commons.configuration.interpol.ConfigurationInterpolator.PREFIX_CONSTANTS}. *
*

*

* After an instance has been created the current set of lookup objects can be * modified using the {@code registerLookup()} and * {@code deregisterLookup()} methods. The default lookup object (that is * invoked for variables without a prefix) can be set with the * {@code setDefaultLookup()} method. (If a * {@code ConfigurationInterpolator} instance is created by a * configuration object, this lookup points to the configuration itself, so that * variables are resolved using the configuration's properties. This ensures * backward compatibility to earlier version of Commons Configuration.) *

*

* Implementation node: Instances of this class are not thread-safe related to * modifications of their current set of registered lookup objects. It is * intended that each instance is associated with a single * {@code Configuration} object and used for its interpolation tasks. *

* * @version $Id: ConfigurationInterpolator.java 1295276 2012-02-29 21:11:35Z oheger $ * @since 1.4 * @author Commons * Configuration team */ public class ConfigurationInterpolator extends StrLookup { /** * Constant for the prefix of the standard lookup object for resolving * system properties. */ public static final String PREFIX_SYSPROPERTIES = "sys"; /** * Constant for the prefix of the standard lookup object for resolving * constant values. */ public static final String PREFIX_CONSTANTS = "const"; /** * Constant for the prefix of the standard lookup object for resolving * environment properties. * @since 1.7 */ public static final String PREFIX_ENVIRONMENT = "env"; /** Constant for the prefix separator. */ private static final char PREFIX_SEPARATOR = ':'; /** A map with the globally registered lookup objects. */ private static Map globalLookups; /** A map with the locally registered lookup objects. */ private Map localLookups; /** Stores the default lookup object. */ private StrLookup defaultLookup; /** Stores a parent interpolator objects if the interpolator is nested hierarchically. */ private ConfigurationInterpolator parentInterpolator; /** * Creates a new instance of {@code ConfigurationInterpolator}. */ public ConfigurationInterpolator() { synchronized (globalLookups) { localLookups = new HashMap(globalLookups); } } /** * Registers the given lookup object for the specified prefix globally. This * means that all instances that are created later will use this lookup * object for this prefix. If for this prefix a lookup object is already * registered, the new lookup object will replace the old one. Note that the * lookup objects registered here will be shared between multiple clients. * So they should be thread-safe. * * @param prefix the variable prefix (must not be null) * @param lookup the lookup object to be used for this prefix (must not be * null) */ public static void registerGlobalLookup(String prefix, StrLookup lookup) { if (prefix == null) { throw new IllegalArgumentException( "Prefix for lookup object must not be null!"); } if (lookup == null) { throw new IllegalArgumentException( "Lookup object must not be null!"); } synchronized (globalLookups) { globalLookups.put(prefix, lookup); } } /** * Deregisters the global lookup object for the specified prefix. This means * that this lookup object won't be available for later created instances * any more. For already existing instances this operation does not have any * impact. * * @param prefix the variable prefix * @return a flag whether for this prefix a lookup object had been * registered */ public static boolean deregisterGlobalLookup(String prefix) { synchronized (globalLookups) { return globalLookups.remove(prefix) != null; } } /** * Registers the given lookup object for the specified prefix at this * instance. From now on this lookup object will be used for variables that * have the specified prefix. * * @param prefix the variable prefix (must not be null) * @param lookup the lookup object to be used for this prefix (must not be * null) */ public void registerLookup(String prefix, StrLookup lookup) { if (prefix == null) { throw new IllegalArgumentException( "Prefix for lookup object must not be null!"); } if (lookup == null) { throw new IllegalArgumentException( "Lookup object must not be null!"); } localLookups.put(prefix, lookup); } /** * Deregisters the lookup object for the specified prefix at this instance. * It will be removed from this instance. * * @param prefix the variable prefix * @return a flag whether for this prefix a lookup object had been * registered */ public boolean deregisterLookup(String prefix) { return localLookups.remove(prefix) != null; } /** * Returns a set with the prefixes, for which lookup objects are registered * at this instance. This means that variables with these prefixes can be * processed. * * @return a set with the registered variable prefixes */ public Set prefixSet() { return localLookups.keySet(); } /** * Returns the default lookup object. * * @return the default lookup object */ public StrLookup getDefaultLookup() { return defaultLookup; } /** * Sets the default lookup object. This lookup object will be used for all * variables without a special prefix. If it is set to null, such * variables won't be processed. * * @param defaultLookup the new default lookup object */ public void setDefaultLookup(StrLookup defaultLookup) { this.defaultLookup = defaultLookup; } /** * Resolves the specified variable. This implementation will try to extract * a variable prefix from the given variable name (the first colon (':') is * used as prefix separator). It then passes the name of the variable with * the prefix stripped to the lookup object registered for this prefix. If * no prefix can be found or if the associated lookup object cannot resolve * this variable, the default lookup object will be used. * * @param var the name of the variable whose value is to be looked up * @return the value of this variable or null if it cannot be * resolved */ @Override public String lookup(String var) { if (var == null) { return null; } int prefixPos = var.indexOf(PREFIX_SEPARATOR); if (prefixPos >= 0) { String prefix = var.substring(0, prefixPos); String name = var.substring(prefixPos + 1); String value = fetchLookupForPrefix(prefix).lookup(name); if (value == null && getParentInterpolator() != null) { value = getParentInterpolator().lookup(name); } if (value != null) { return value; } } String value = fetchNoPrefixLookup().lookup(var); if (value == null && getParentInterpolator() != null) { value = getParentInterpolator().lookup(var); } return value; } /** * Returns the lookup object to be used for variables without a prefix. This * implementation will check whether a default lookup object was set. If * this is the case, it will be returned. Otherwise a null lookup * object will be returned (never null). * * @return the lookup object to be used for variables without a prefix */ protected StrLookup fetchNoPrefixLookup() { return (getDefaultLookup() != null) ? getDefaultLookup() : StrLookup.noneLookup(); } /** * Obtains the lookup object for the specified prefix. This method is called * by the {@code lookup()} method. This implementation will check * whether a lookup object is registered for the given prefix. If not, a * null lookup object will be returned (never null). * * @param prefix the prefix * @return the lookup object to be used for this prefix */ protected StrLookup fetchLookupForPrefix(String prefix) { StrLookup lookup = localLookups.get(prefix); if (lookup == null) { lookup = StrLookup.noneLookup(); } return lookup; } /** * Registers the local lookup instances for the given interpolator. * * @param interpolator the instance receiving the local lookups * @since upcoming */ public void registerLocalLookups(ConfigurationInterpolator interpolator) { interpolator.localLookups.putAll(localLookups); } /** * Sets the parent interpolator. This object is used if the interpolation is nested * hierarchically and the current interpolation object cannot resolve a variable. * * @param parentInterpolator the parent interpolator object or null * @since upcoming */ public void setParentInterpolator(ConfigurationInterpolator parentInterpolator) { this.parentInterpolator = parentInterpolator; } /** * Requests the parent interpolator. This object is used if the interpolation is nested * hierarchically and the current interpolation * * @return the parent interpolator or null * @since upcoming */ public ConfigurationInterpolator getParentInterpolator() { return this.parentInterpolator; } // static initializer, sets up the map with the standard lookups static { globalLookups = new HashMap(); globalLookups.put(PREFIX_SYSPROPERTIES, StrLookup.systemPropertiesLookup()); globalLookups.put(PREFIX_CONSTANTS, new ConstantLookup()); globalLookups.put(PREFIX_ENVIRONMENT, new EnvironmentLookup()); } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/ConstantLookup.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/ConstantLooku100644 13652 12232154102 33611 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.interpol; import java.lang.reflect.Field; import java.util.HashMap; import java.util.Map; import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.text.StrLookup; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** *

* A specialized lookup implementation that allows access to constant fields of * classes. *

*

* Sometimes it is necessary in a configuration file to refer to a constant * defined in a class. This can be done with this lookup implementation. * Variable names passed in must be of the form * {@code mypackage.MyClass.FIELD}. The {@code lookup()} method * will split the passed in string at the last dot, separating the fully * qualified class name and the name of the constant (i.e. static final) * member field. Then the class is loaded and the field's value is obtained * using reflection. *

*

* Once retrieved values are cached for fast access. This class is thread-safe. * It can be used as a standard (i.e. global) lookup object and serve multiple * clients concurrently. *

* * @version $Id: ConstantLookup.java 1210218 2011-12-04 20:57:48Z oheger $ * @since 1.4 * @author Commons * Configuration team */ public class ConstantLookup extends StrLookup { /** Constant for the field separator. */ private static final char FIELD_SEPRATOR = '.'; /** An internally used cache for already retrieved values. */ private static Map constantCache = new HashMap(); /** The logger. */ private Log log = LogFactory.getLog(getClass()); /** * Tries to resolve the specified variable. The passed in variable name is * interpreted as the name of a static final member field of a * class. If the value has already been obtained, it can be retrieved from * an internal cache. Otherwise this method will invoke the * {@code resolveField()} method and pass in the name of the class * and the field. * * @param var the name of the variable to be resolved * @return the value of this variable or null if it cannot be * resolved */ @Override public String lookup(String var) { if (var == null) { return null; } String result; synchronized (constantCache) { result = constantCache.get(var); } if (result != null) { return result; } int fieldPos = var.lastIndexOf(FIELD_SEPRATOR); if (fieldPos < 0) { return null; } try { Object value = resolveField(var.substring(0, fieldPos), var .substring(fieldPos + 1)); if (value != null) { synchronized (constantCache) { // In worst case, the value will be fetched multiple times // because of this lax synchronisation, but for constant // values this shouldn't be a problem. constantCache.put(var, String.valueOf(value)); } result = value.toString(); } } catch (Exception ex) { log.warn("Could not obtain value for variable " + var, ex); } return result; } /** * Clears the shared cache with the so far resolved constants. */ public static void clear() { synchronized (constantCache) { constantCache.clear(); } } /** * Determines the value of the specified constant member field of a class. * This implementation will call {@code fetchClass()} to obtain the * {@code java.lang.Class} object for the target class. Then it will * use reflection to obtain the field's value. For this to work the field * must be accessable. * * @param className the name of the class * @param fieldName the name of the member field of that class to read * @return the field's value * @throws Exception if an error occurs */ protected Object resolveField(String className, String fieldName) throws Exception { Class clazz = fetchClass(className); Field field = clazz.getField(fieldName); return field.get(null); } /** * Loads the class with the specified name. If an application has special * needs regarding the class loaders to be used, it can hook in here. This * implementation delegates to the {@code getClass()} method of * Commons Lang's * * ClassUtils. * * @param className the name of the class to be loaded * @return the corresponding class object * @throws ClassNotFoundException if the class cannot be loaded */ protected Class fetchClass(String className) throws ClassNotFoundException { return ClassUtils.getClass(className); } } ././@LongLink100644 0 0 156 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/EnvironmentLookup.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/EnvironmentLo100644 4421 12232154102 33557 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.interpol; import org.apache.commons.configuration.EnvironmentConfiguration; import org.apache.commons.lang.text.StrLookup; /** *

* A specialized lookup implementation that allows access to environment * variables. *

*

* This implementation relies on {@link EnvironmentConfiguration} to resolve * environment variables. It can be used for referencing environment variables * in configuration files in an easy way, for instance: * *

 * java.home = ${env:JAVA_HOME}
 * 
* *

*

* {@code EnvironmentLookup} is one of the standard lookups that is * registered per default for each configuration. *

* * @author Commons * Configuration team * @since 1.7 * @version $Id: EnvironmentLookup.java 1210620 2011-12-05 20:57:31Z oheger $ */ public class EnvironmentLookup extends StrLookup { /** Stores the underlying {@code EnvironmentConfiguration}. */ private final EnvironmentConfiguration environmentConfig = new EnvironmentConfiguration(); /** * Performs a lookup for the specified variable. This implementation * directly delegates to a {@code EnvironmentConfiguration}. * * @param key the key to lookup * @return the value of this key or null if it cannot be resolved */ @Override public String lookup(String key) { return environmentConfig.getString(key); } } ././@LongLink100644 0 0 147 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/ExprLookup.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/ExprLookup.ja100644 23305 12232154102 33503 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.interpol; import java.util.ArrayList; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.ConfigurationRuntimeException; import org.apache.commons.jexl2.Expression; import org.apache.commons.jexl2.JexlContext; import org.apache.commons.jexl2.JexlEngine; import org.apache.commons.jexl2.MapContext; import org.apache.commons.lang.ClassUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.text.StrLookup; import org.apache.commons.lang.text.StrSubstitutor; /** * Lookup that allows expressions to be evaluated. * *
 *     ExprLookup.Variables vars = new ExprLookup.Variables();
 *     vars.add(new ExprLookup.Variable("String", org.apache.commons.lang.StringUtils.class));
 *     vars.add(new ExprLookup.Variable("Util", new Utility("Hello")));
 *     vars.add(new ExprLookup.Variable("System", "Class:java.lang.System"));
 *     XMLConfiguration config = new XMLConfiguration(TEST_FILE);
 *     config.setLogger(log);
 *     ExprLookup lookup = new ExprLookup(vars);
 *     lookup.setConfiguration(config);
 *     String str = lookup.lookup("'$[element] ' + String.trimToEmpty('$[space.description]')");
 * 
* * In the example above TEST_FILE contains xml that looks like: *
 * <configuration>
 *   <element>value</element>
 *   <space xml:space="preserve">
 *     <description xml:space="default">     Some text      </description>
 *   </space>
 * </configuration>
 * 
* * The result will be "value Some text". * * This lookup uses Apache Commons Jexl and requires that the dependency be added to any * projects which use this. * * @since 1.7 * @author Commons Configuration team * @version $Id: ExprLookup.java 1234539 2012-01-22 16:19:15Z oheger $ */ public class ExprLookup extends StrLookup { /** Prefix to identify a Java Class object */ private static final String CLASS = "Class:"; /** The default prefix for subordinate lookup expressions */ private static final String DEFAULT_PREFIX = "$["; /** The default suffix for subordinate lookup expressions */ private static final String DEFAULT_SUFFIX = "]"; /** Configuration being operated on */ private AbstractConfiguration configuration; /** The engine. */ private final JexlEngine engine = new JexlEngine(); /** The variables maintained by this object. */ private Variables variables; /** The String to use to start subordinate lookup expressions */ private String prefixMatcher = DEFAULT_PREFIX; /** The String to use to terminate subordinate lookup expressions */ private String suffixMatcher = DEFAULT_SUFFIX; /** * The default constructor. Will get used when the Lookup is constructed via * configuration. */ public ExprLookup() { } /** * Constructor for use by applications. * @param list The list of objects to be accessible in expressions. */ public ExprLookup(Variables list) { setVariables(list); } /** * Constructor for use by applications. * @param list The list of objects to be accessible in expressions. * @param prefix The prefix to use for subordinate lookups. * @param suffix The suffix to use for subordinate lookups. */ public ExprLookup(Variables list, String prefix, String suffix) { this(list); setVariablePrefixMatcher(prefix); setVariableSuffixMatcher(suffix); } /** * Set the prefix to use to identify subordinate expressions. This cannot be the * same as the prefix used for the primary expression. * @param prefix The String identifying the beginning of the expression. */ public void setVariablePrefixMatcher(String prefix) { prefixMatcher = prefix; } /** * Set the suffix to use to identify subordinate expressions. This cannot be the * same as the suffix used for the primary expression. * @param suffix The String identifying the end of the expression. */ public void setVariableSuffixMatcher(String suffix) { suffixMatcher = suffix; } /** * Add the Variables that will be accessible within expressions. * @param list The list of Variables. */ public void setVariables(Variables list) { variables = new Variables(list); } /** * Returns the list of Variables that are accessible within expressions. * @return the List of Variables that are accessible within expressions. */ public Variables getVariables() { return null; } /** * Set the configuration to be used to interpolate subordinate expressions. * @param config The Configuration. */ public void setConfiguration(AbstractConfiguration config) { this.configuration = config; } /** * Evaluates the expression. * @param var The expression. * @return The String result of the expression. */ @Override public String lookup(String var) { ConfigurationInterpolator interp = configuration.getInterpolator(); StrSubstitutor subst = new StrSubstitutor(interp, prefixMatcher, suffixMatcher, StrSubstitutor.DEFAULT_ESCAPE); String result = subst.replace(var); try { Expression exp = engine.createExpression(result); result = (String) exp.evaluate(createContext()); } catch (Exception e) { configuration.getLogger().debug("Error encountered evaluating " + result, e); } return result; } /** * Creates a new {@code JexlContext} and initializes it with the variables * managed by this Lookup object. * * @return the newly created context */ private JexlContext createContext() { JexlContext ctx = new MapContext(); initializeContext(ctx); return ctx; } /** * Initializes the specified context with the variables managed by this * Lookup object. * * @param ctx the context to be initialized */ private void initializeContext(JexlContext ctx) { for (Variable var : variables) { ctx.set(var.getName(), var.getValue()); } } /** * List wrapper used to allow the Variables list to be created as beans in * DefaultConfigurationBuilder. */ public static class Variables extends ArrayList { /** * The serial version UID. */ private static final long serialVersionUID = 20111205L; /** * Creates a new empty instance of {@code Variables}. */ public Variables() { super(); } /** * Creates a new instance of {@code Variables} and copies the content of * the given object. * * @param vars the {@code Variables} object to be copied */ public Variables(Variables vars) { super(vars); } public Variable getVariable() { if (size() > 0) { return get(size() - 1); } else { return null; } } } /** * The key and corresponding object that will be made available to the * JexlContext for use in expressions. */ public static class Variable { /** The name to be used in expressions */ private String key; /** The object to be accessed in expressions */ private Object value; public Variable() { } public Variable(String name, Object value) { setName(name); setValue(value); } public String getName() { return key; } public void setName(String name) { this.key = name; } public Object getValue() { return value; } public void setValue(Object value) throws ConfigurationRuntimeException { try { if (!(value instanceof String)) { this.value = value; return; } String val = (String) value; String name = StringUtils.removeStartIgnoreCase(val, CLASS); Class clazz = ClassUtils.getClass(name); if (name.length() == val.length()) { this.value = clazz.newInstance(); } else { this.value = clazz; } } catch (Exception e) { throw new ConfigurationRuntimeException("Unable to create " + value, e); } } } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/package.html100644 2030 12232154102 33310 0ustarhenningstaff 0 0

A package with helper classes used for interpolation (variable substitution).

$Id: package.html 952622 2010-06-08 11:56:30Z sebb $

././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/JNDIConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/JNDIConfiguration.java100644 32775 12232154103 33356 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameClassPair; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.NotContextException; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.LogFactory; /** * This Configuration class allows you to interface with a JNDI datasource. * A JNDIConfiguration is read-only, write operations will throw an * UnsupportedOperationException. The clear operations are supported but the * underlying JNDI data source is not changed. * * @author Eric Pugh * @version $Id: JNDIConfiguration.java 1234985 2012-01-23 21:09:09Z oheger $ */ public class JNDIConfiguration extends AbstractConfiguration { /** The prefix of the context. */ private String prefix; /** The initial JNDI context. */ private Context context; /** The base JNDI context. */ private Context baseContext; /** The Set of keys that have been virtually cleared. */ private Set clearedProperties = new HashSet(); /** * Creates a JNDIConfiguration using the default initial context as the * root of the properties. * * @throws NamingException thrown if an error occurs when initializing the default context */ public JNDIConfiguration() throws NamingException { this((String) null); } /** * Creates a JNDIConfiguration using the default initial context, shifted * with the specified prefix, as the root of the properties. * * @param prefix the prefix * * @throws NamingException thrown if an error occurs when initializing the default context */ public JNDIConfiguration(String prefix) throws NamingException { this(new InitialContext(), prefix); } /** * Creates a JNDIConfiguration using the specified initial context as the * root of the properties. * * @param context the initial context */ public JNDIConfiguration(Context context) { this(context, null); } /** * Creates a JNDIConfiguration using the specified initial context shifted * by the specified prefix as the root of the properties. * * @param context the initial context * @param prefix the prefix */ public JNDIConfiguration(Context context, String prefix) { this.context = context; this.prefix = prefix; setLogger(LogFactory.getLog(getClass())); addErrorLogListener(); } /** * This method recursive traverse the JNDI tree, looking for Context objects. * When it finds them, it traverses them as well. Otherwise it just adds the * values to the list of keys found. * * @param keys All the keys that have been found. * @param context The parent context * @param prefix What prefix we are building on. * @param processedCtx a set with the so far processed objects * @throws NamingException If JNDI has an issue. */ private void recursiveGetKeys(Set keys, Context context, String prefix, Set processedCtx) throws NamingException { processedCtx.add(context); NamingEnumeration elements = null; try { elements = context.list(""); // iterates through the context's elements while (elements.hasMore()) { NameClassPair nameClassPair = elements.next(); String name = nameClassPair.getName(); Object object = context.lookup(name); // build the key StringBuilder key = new StringBuilder(); key.append(prefix); if (key.length() > 0) { key.append("."); } key.append(name); if (object instanceof Context) { // add the keys of the sub context Context subcontext = (Context) object; if (!processedCtx.contains(subcontext)) { recursiveGetKeys(keys, subcontext, key.toString(), processedCtx); } } else { // add the key keys.add(key.toString()); } } } finally { // close the enumeration if (elements != null) { elements.close(); } } } /** * Returns an iterator with all property keys stored in this configuration. * * @return an iterator with all keys */ public Iterator getKeys() { return getKeys(""); } /** * Returns an iterator with all property keys starting with the given * prefix. * * @param prefix the prefix * @return an iterator with the selected keys */ @Override public Iterator getKeys(String prefix) { // build the path String[] splitPath = StringUtils.split(prefix, "."); List path = Arrays.asList(splitPath); try { // find the context matching the specified path Context context = getContext(path, getBaseContext()); // return all the keys under the context found Set keys = new HashSet(); if (context != null) { recursiveGetKeys(keys, context, prefix, new HashSet()); } else if (containsKey(prefix)) { // add the prefix if it matches exactly a property key keys.add(prefix); } return keys.iterator(); } catch (NameNotFoundException e) { // expected exception, no need to log it return new ArrayList().iterator(); } catch (NamingException e) { fireError(EVENT_READ_PROPERTY, null, null, e); return new ArrayList().iterator(); } } /** * Because JNDI is based on a tree configuration, we need to filter down the * tree, till we find the Context specified by the key to start from. * Otherwise return null. * * @param path the path of keys to traverse in order to find the context * @param context the context to start from * @return The context at that key's location in the JNDI tree, or null if not found * @throws NamingException if JNDI has an issue */ private Context getContext(List path, Context context) throws NamingException { // return the current context if the path is empty if (path == null || path.isEmpty()) { return context; } String key = path.get(0); // search a context matching the key in the context's elements NamingEnumeration elements = null; try { elements = context.list(""); while (elements.hasMore()) { NameClassPair nameClassPair = elements.next(); String name = nameClassPair.getName(); Object object = context.lookup(name); if (object instanceof Context && name.equals(key)) { Context subcontext = (Context) object; // recursive search in the sub context return getContext(path.subList(1, path.size()), subcontext); } } } finally { if (elements != null) { elements.close(); } } return null; } /** * Returns a flag whether this configuration is empty. * * @return the empty flag */ public boolean isEmpty() { try { NamingEnumeration enumeration = null; try { enumeration = getBaseContext().list(""); return !enumeration.hasMore(); } finally { // close the enumeration if (enumeration != null) { enumeration.close(); } } } catch (NamingException e) { fireError(EVENT_READ_PROPERTY, null, null, e); return true; } } /** *

This operation is not supported and will throw an * UnsupportedOperationException.

* * @param key the key * @param value the value * @throws UnsupportedOperationException */ @Override public void setProperty(String key, Object value) { throw new UnsupportedOperationException("This operation is not supported"); } /** * Removes the specified property. * * @param key the key of the property to remove */ @Override public void clearProperty(String key) { clearedProperties.add(key); } /** * Checks whether the specified key is contained in this configuration. * * @param key the key to check * @return a flag whether this key is stored in this configuration */ public boolean containsKey(String key) { if (clearedProperties.contains(key)) { return false; } key = key.replaceAll("\\.", "/"); try { // throws a NamingException if JNDI doesn't contain the key. getBaseContext().lookup(key); return true; } catch (NameNotFoundException e) { // expected exception, no need to log it return false; } catch (NamingException e) { fireError(EVENT_READ_PROPERTY, key, null, e); return false; } } /** * Returns the prefix. * @return the prefix */ public String getPrefix() { return prefix; } /** * Sets the prefix. * * @param prefix The prefix to set */ public void setPrefix(String prefix) { this.prefix = prefix; // clear the previous baseContext baseContext = null; } /** * Returns the value of the specified property. * * @param key the key of the property * @return the value of this property */ public Object getProperty(String key) { if (clearedProperties.contains(key)) { return null; } try { key = key.replaceAll("\\.", "/"); return getBaseContext().lookup(key); } catch (NameNotFoundException e) { // expected exception, no need to log it return null; } catch (NotContextException nctxex) { // expected exception, no need to log it return null; } catch (NamingException e) { fireError(EVENT_READ_PROPERTY, key, null, e); return null; } } /** *

This operation is not supported and will throw an * UnsupportedOperationException.

* * @param key the key * @param obj the value * @throws UnsupportedOperationException */ @Override protected void addPropertyDirect(String key, Object obj) { throw new UnsupportedOperationException("This operation is not supported"); } /** * Return the base context with the prefix applied. * * @return the base context * @throws NamingException if an error occurs */ public Context getBaseContext() throws NamingException { if (baseContext == null) { baseContext = (Context) getContext().lookup(prefix == null ? "" : prefix); } return baseContext; } /** * Return the initial context used by this configuration. This context is * independent of the prefix specified. * * @return the initial context */ public Context getContext() { return context; } /** * Set the initial context of the configuration. * * @param context the context */ public void setContext(Context context) { // forget the removed properties clearedProperties.clear(); // change the context this.context = context; } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/Lock.java100644 4563 12232154102 30743 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; /** *

* A simple class acting as lock. *

*

* Instances of this class are used by some configuration classes to synchronize * themselves. *

* * @author Commons * Configuration team * @since 1.7 * @version $Id: Lock.java 1301995 2012-03-17 20:24:16Z sebb $ */ public class Lock { /** A string used internally to synchronize counter updates. */ private static String counterLock = "Lock"; /** A counter for generating unique instance IDs. */ private static int counter; /** The name of this lock. */ private final String name; /** The unique ID of this lock instance. */ private final int instanceId; /** * Creates a new instance of {@code Lock} with the specified name. * * @param name the name of this lock */ public Lock(String name) { this.name = name; synchronized (counterLock) { instanceId = ++counter; } } /** * Returns the name of this lock. * * @return the name of this lock */ public String getName() { return name; } /** * Returns a string representation of this object. This implementation * returns a string which contains the lock name and the instance ID. * * @return a string for this object */ @Override public String toString() { return "Lock: " + name + " id = " + instanceId + ": " + super.toString(); } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/MapConfiguration.java100644 24077 12232154102 33342 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.AbstractMap; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; /** *

* A Map based Configuration. *

*

* This implementation of the {@code Configuration} interface is * initialized with a {@code java.util.Map}. The methods of the * {@code Configuration} interface are implemented on top of the content of * this map. The following storage scheme is used: *

*

* Property keys are directly mapped to map keys, i.e. the * {@code getProperty()} method directly performs a {@code get()} on * the map. Analogously, {@code setProperty()} or * {@code addProperty()} operations write new data into the map. If a value * is added to an existing property, a {@code java.util.List} is created, * which stores the values of this property. *

*

* An important use case of this class is to treat a map as a * {@code Configuration} allowing access to its data through the richer * interface. This can be a bit problematic in some cases because the map may * contain values that need not adhere to the default storage scheme used by * typical configuration implementations, e.g. regarding lists. In such cases * care must be taken when manipulating the data through the * {@code Configuration} interface, e.g. by calling * {@code addProperty()}; results may be different than expected. *

*

* An important point is the handling of list delimiters: If delimiter parsing * is enabled (which it is per default), {@code getProperty()} checks * whether the value of a property is a string and whether it contains the list * delimiter character. If this is the case, the value is split at the delimiter * resulting in a list. This split operation typically also involves trimming * the single values as the list delimiter character may be surrounded by * whitespace. Trimming can be disabled with the * {@link #setTrimmingDisabled(boolean)} method. The whole list splitting * behavior can be disabled using the * {@link #setDelimiterParsingDisabled(boolean)} method. *

*

* Notice that list splitting is only performed for single string values. If a * property has multiple values, the single values are not split even if they * contain the list delimiter character. *

*

* As the underlying {@code Map} is directly used as store of the property * values, the thread-safety of this {@code Configuration} implementation * depends on the map passed to the constructor. *

*

* Notes about type safety: For properties with multiple values this implementation * creates lists of type {@code Object} and stores them. If a property is assigned * another value, the value is added to the list. This can cause problems if the * map passed to the constructor already contains lists of other types. This * should be avoided, otherwise it cannot be guaranteed that the application * might throw {@code ClassCastException} exceptions later. *

* * @author Emmanuel Bourg * @version $Id: MapConfiguration.java 1534429 2013-10-22 00:45:36Z henning $ * @since 1.1 */ public class MapConfiguration extends AbstractConfiguration implements Cloneable { /** The Map decorated by this configuration. */ protected Map map; /** A flag whether trimming of property values should be disabled.*/ private boolean trimmingDisabled; /** * Create a Configuration decorator around the specified Map. The map is * used to store the configuration properties, any change will also affect * the Map. * * @param map the map */ public MapConfiguration(Map map) { this.map = (Map) map; } /** * Creates a new instance of {@code MapConfiguration} and initializes its * content from the specified {@code Properties} object. The resulting * configuration is not connected to the {@code Properties} object, but all * keys which are strings are copied (keys of other types are ignored). * * @param props the {@code Properties} object defining the content of this * configuration * @throws NullPointerException if the {@code Properties} object is * null * @since 1.8 */ public MapConfiguration(Properties props) { map = convertPropertiesToMap(props); } /** * Return the Map decorated by this configuration. * * @return the map this configuration is based onto */ public Map getMap() { return map; } /** * Returns the flag whether trimming of property values is disabled. * * @return true if trimming of property values is disabled; * false otherwise * @since 1.7 */ public boolean isTrimmingDisabled() { return trimmingDisabled; } /** * Sets a flag whether trimming of property values is disabled. This flag is * only evaluated if list splitting is enabled. Refer to the header comment * for more information about list splitting and trimming. * * @param trimmingDisabled a flag whether trimming of property values should * be disabled * @since 1.7 */ public void setTrimmingDisabled(boolean trimmingDisabled) { this.trimmingDisabled = trimmingDisabled; } public Object getProperty(String key) { Object value = map.get(key); if ((value instanceof String) && (!isDelimiterParsingDisabled())) { List list = PropertyConverter.split((String) value, getListDelimiter(), !isTrimmingDisabled()); return list.size() > 1 ? list : list.get(0); } else { return value; } } @Override protected void addPropertyDirect(String key, Object value) { Object previousValue = getProperty(key); if (previousValue == null) { map.put(key, value); } else if (previousValue instanceof List) { // the value is added to the existing list // Note: This is problematic. See header comment! ((List) previousValue).add(value); } else { // the previous value is replaced by a list containing the previous value and the new value List list = new ArrayList(); list.add(previousValue); list.add(value); map.put(key, list); } } public boolean isEmpty() { return map.isEmpty(); } public boolean containsKey(String key) { return map.containsKey(key); } @Override protected void clearPropertyDirect(String key) { map.remove(key); } public Iterator getKeys() { return map.keySet().iterator(); } /** * Returns a copy of this object. The returned configuration will contain * the same properties as the original. Event listeners are not cloned. * * @return the copy * @since 1.3 */ @Override public Object clone() { try { MapConfiguration copy = (MapConfiguration) super.clone(); copy.clearConfigurationListeners(); // Safe because ConfigurationUtils returns a map of the same types. @SuppressWarnings("unchecked") Map clonedMap = (Map) ConfigurationUtils.clone(map); copy.map = clonedMap; return copy; } catch (CloneNotSupportedException cex) { // cannot happen throw new ConfigurationRuntimeException(cex); } } /** * Helper method for copying all string keys from the given * {@code Properties} object to a newly created map. * * @param props the {@code Properties} to be copied * @return a newly created map with all string keys of the properties */ private static Map convertPropertiesToMap(final Properties props) { return new AbstractMap() { @Override public Set> entrySet() { Set> entries = new HashSet>(); for (final Map.Entry propertyEntry : props.entrySet()) { if (propertyEntry.getKey() instanceof String) { entries.add(new Map.Entry() { public String getKey() { return propertyEntry.getKey().toString(); } public Object getValue() { return propertyEntry.getValue(); } public Object setValue(Object value) { throw new UnsupportedOperationException(); } }); } } return entries; } }; } } ././@LongLink100644 0 0 166 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/MultiFileHierarchicalConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/MultiFileHierarchicalC100644 54500 12232154102 33443 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.InputStream; import java.io.OutputStream; import java.io.Reader; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import org.apache.commons.beanutils.BeanUtils; import org.apache.commons.configuration.event.ConfigurationErrorEvent; import org.apache.commons.configuration.event.ConfigurationErrorListener; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; import org.apache.commons.configuration.reloading.ReloadingStrategy; import org.apache.commons.configuration.resolver.EntityResolverSupport; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.ExpressionEngine; import org.apache.commons.lang.text.StrSubstitutor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.xml.sax.EntityResolver; import org.xml.sax.SAXParseException; /** * This class provides access to multiple configuration files that reside in a location that * can be specified by a pattern allowing applications to be multi-tenant. For example, * providing a pattern of "file:///opt/config/${product}/${client}/config.xml" will result in * "product" and "client" being resolved on every call. The configuration resulting from the * resolved pattern will be saved for future access. * @since 1.6 * @author Commons * Configuration team * @version $Id: MultiFileHierarchicalConfiguration.java 1534064 2013-10-21 08:44:33Z henning $ */ public class MultiFileHierarchicalConfiguration extends AbstractHierarchicalFileConfiguration implements ConfigurationListener, ConfigurationErrorListener, EntityResolverSupport { /** * Prevent recursion while resolving unprefixed properties. */ private static ThreadLocal recursive = new ThreadLocal() { @Override protected synchronized Boolean initialValue() { return Boolean.FALSE; } }; /** Map of configurations */ private final ConcurrentMap configurationsMap = new ConcurrentHashMap(); /** key pattern for configurationsMap */ private String pattern; /** True if the constructor has finished */ private boolean init; /** Return an empty configuration if loading fails */ private boolean ignoreException = true; /** Capture the schema validation setting */ private boolean schemaValidation; /** Stores a flag whether DTD or Schema validation should be performed.*/ private boolean validating; /** A flag whether attribute splitting is disabled.*/ private boolean attributeSplittingDisabled; /** The Logger name to use */ private String loggerName = MultiFileHierarchicalConfiguration.class.getName(); /** The Reloading strategy to use on created configurations */ private ReloadingStrategy fileStrategy; /** The EntityResolver */ private EntityResolver entityResolver; /** The internally used helper object for variable substitution. */ private StrSubstitutor localSubst = new StrSubstitutor(new ConfigurationInterpolator()); /** * Default Constructor. */ public MultiFileHierarchicalConfiguration() { super(); this.init = true; setLogger(LogFactory.getLog(loggerName)); } /** * Construct the configuration with the specified pattern. * @param pathPattern The pattern to use to locate configuration files. */ public MultiFileHierarchicalConfiguration(String pathPattern) { super(); this.pattern = pathPattern; this.init = true; setLogger(LogFactory.getLog(loggerName)); } public void setLoggerName(String name) { this.loggerName = name; } /** * Set the File pattern * @param pathPattern The pattern for the path to the configuration. */ public void setFilePattern(String pathPattern) { this.pattern = pathPattern; } public boolean isSchemaValidation() { return schemaValidation; } public void setSchemaValidation(boolean schemaValidation) { this.schemaValidation = schemaValidation; } public boolean isValidating() { return validating; } public void setValidating(boolean validating) { this.validating = validating; } public boolean isAttributeSplittingDisabled() { return attributeSplittingDisabled; } public void setAttributeSplittingDisabled(boolean attributeSplittingDisabled) { this.attributeSplittingDisabled = attributeSplittingDisabled; } @Override public ReloadingStrategy getReloadingStrategy() { return fileStrategy; } @Override public void setReloadingStrategy(ReloadingStrategy strategy) { this.fileStrategy = strategy; } public void setEntityResolver(EntityResolver entityResolver) { this.entityResolver = entityResolver; } public EntityResolver getEntityResolver() { return this.entityResolver; } /** * Set to true if an empty Configuration should be returned when loading fails. If * false an exception will be thrown. * @param ignoreException The ignore value. */ public void setIgnoreException(boolean ignoreException) { this.ignoreException = ignoreException; } @Override public void addProperty(String key, Object value) { this.getConfiguration().addProperty(key, value); } @Override public void clear() { this.getConfiguration().clear(); } @Override public void clearProperty(String key) { this.getConfiguration().clearProperty(key); } @Override public boolean containsKey(String key) { return this.getConfiguration().containsKey(key); } @Override public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) { return this.getConfiguration().getBigDecimal(key, defaultValue); } @Override public BigDecimal getBigDecimal(String key) { return this.getConfiguration().getBigDecimal(key); } @Override public BigInteger getBigInteger(String key, BigInteger defaultValue) { return this.getConfiguration().getBigInteger(key, defaultValue); } @Override public BigInteger getBigInteger(String key) { return this.getConfiguration().getBigInteger(key); } @Override public boolean getBoolean(String key, boolean defaultValue) { return this.getConfiguration().getBoolean(key, defaultValue); } @Override public Boolean getBoolean(String key, Boolean defaultValue) { return this.getConfiguration().getBoolean(key, defaultValue); } @Override public boolean getBoolean(String key) { return this.getConfiguration().getBoolean(key); } @Override public byte getByte(String key, byte defaultValue) { return this.getConfiguration().getByte(key, defaultValue); } @Override public Byte getByte(String key, Byte defaultValue) { return this.getConfiguration().getByte(key, defaultValue); } @Override public byte getByte(String key) { return this.getConfiguration().getByte(key); } @Override public double getDouble(String key, double defaultValue) { return this.getConfiguration().getDouble(key, defaultValue); } @Override public Double getDouble(String key, Double defaultValue) { return this.getConfiguration().getDouble(key, defaultValue); } @Override public double getDouble(String key) { return this.getConfiguration().getDouble(key); } @Override public float getFloat(String key, float defaultValue) { return this.getConfiguration().getFloat(key, defaultValue); } @Override public Float getFloat(String key, Float defaultValue) { return this.getConfiguration().getFloat(key, defaultValue); } @Override public float getFloat(String key) { return this.getConfiguration().getFloat(key); } @Override public int getInt(String key, int defaultValue) { return this.getConfiguration().getInt(key, defaultValue); } @Override public int getInt(String key) { return this.getConfiguration().getInt(key); } @Override public Integer getInteger(String key, Integer defaultValue) { return this.getConfiguration().getInteger(key, defaultValue); } @Override public Iterator getKeys() { return this.getConfiguration().getKeys(); } @Override public Iterator getKeys(String prefix) { return this.getConfiguration().getKeys(prefix); } @Override public List getList(String key, List defaultValue) { return this.getConfiguration().getList(key, defaultValue); } @Override public List getList(String key) { return this.getConfiguration().getList(key); } @Override public long getLong(String key, long defaultValue) { return this.getConfiguration().getLong(key, defaultValue); } @Override public Long getLong(String key, Long defaultValue) { return this.getConfiguration().getLong(key, defaultValue); } @Override public long getLong(String key) { return this.getConfiguration().getLong(key); } @Override public Properties getProperties(String key) { return this.getConfiguration().getProperties(key); } @Override public Object getProperty(String key) { return this.getConfiguration().getProperty(key); } @Override public short getShort(String key, short defaultValue) { return this.getConfiguration().getShort(key, defaultValue); } @Override public Short getShort(String key, Short defaultValue) { return this.getConfiguration().getShort(key, defaultValue); } @Override public short getShort(String key) { return this.getConfiguration().getShort(key); } @Override public String getString(String key, String defaultValue) { return this.getConfiguration().getString(key, defaultValue); } @Override public String getString(String key) { return this.getConfiguration().getString(key); } @Override public String[] getStringArray(String key) { return this.getConfiguration().getStringArray(key); } @Override public boolean isEmpty() { return this.getConfiguration().isEmpty(); } @Override public void setProperty(String key, Object value) { if (init) { this.getConfiguration().setProperty(key, value); } } @Override public Configuration subset(String prefix) { return this.getConfiguration().subset(prefix); } @Override public Object getReloadLock() { return this.getConfiguration().getReloadLock(); } @Override public Node getRoot() { return this.getConfiguration().getRoot(); } @Override public void setRoot(Node node) { if (init) { this.getConfiguration().setRoot(node); } else { super.setRoot(node); } } @Override public ConfigurationNode getRootNode() { return this.getConfiguration().getRootNode(); } @Override public void setRootNode(ConfigurationNode rootNode) { if (init) { this.getConfiguration().setRootNode(rootNode); } else { super.setRootNode(rootNode); } } @Override public ExpressionEngine getExpressionEngine() { return super.getExpressionEngine(); } @Override public void setExpressionEngine(ExpressionEngine expressionEngine) { super.setExpressionEngine(expressionEngine); } @Override public void addNodes(String key, Collection nodes) { this.getConfiguration().addNodes(key, nodes); } @Override public SubnodeConfiguration configurationAt(String key, boolean supportUpdates) { return this.getConfiguration().configurationAt(key, supportUpdates); } @Override public SubnodeConfiguration configurationAt(String key) { return this.getConfiguration().configurationAt(key); } @Override public List configurationsAt(String key) { return this.getConfiguration().configurationsAt(key); } @Override public void clearTree(String key) { this.getConfiguration().clearTree(key); } @Override public int getMaxIndex(String key) { return this.getConfiguration().getMaxIndex(key); } @Override public Configuration interpolatedConfiguration() { return this.getConfiguration().interpolatedConfiguration(); } @Override public void addConfigurationListener(ConfigurationListener l) { super.addConfigurationListener(l); } @Override public boolean removeConfigurationListener(ConfigurationListener l) { return super.removeConfigurationListener(l); } @Override public Collection getConfigurationListeners() { return super.getConfigurationListeners(); } @Override public void clearConfigurationListeners() { super.clearConfigurationListeners(); } @Override public void addErrorListener(ConfigurationErrorListener l) { super.addErrorListener(l); } @Override public boolean removeErrorListener(ConfigurationErrorListener l) { return super.removeErrorListener(l); } @Override public void clearErrorListeners() { super.clearErrorListeners(); } @Override public Collection getErrorListeners() { return super.getErrorListeners(); } public void save(Writer writer) throws ConfigurationException { if (init) { this.getConfiguration().save(writer); } } public void load(Reader reader) throws ConfigurationException { if (init) { this.getConfiguration().load(reader); } } @Override public void load() throws ConfigurationException { this.getConfiguration(); } @Override public void load(String fileName) throws ConfigurationException { this.getConfiguration().load(fileName); } @Override public void load(File file) throws ConfigurationException { this.getConfiguration().load(file); } @Override public void load(URL url) throws ConfigurationException { this.getConfiguration().load(url); } @Override public void load(InputStream in) throws ConfigurationException { this.getConfiguration().load(in); } @Override public void load(InputStream in, String encoding) throws ConfigurationException { this.getConfiguration().load(in, encoding); } @Override public void save() throws ConfigurationException { this.getConfiguration().save(); } @Override public void save(String fileName) throws ConfigurationException { this.getConfiguration().save(fileName); } @Override public void save(File file) throws ConfigurationException { this.getConfiguration().save(file); } @Override public void save(URL url) throws ConfigurationException { this.getConfiguration().save(url); } @Override public void save(OutputStream out) throws ConfigurationException { this.getConfiguration().save(out); } @Override public void save(OutputStream out, String encoding) throws ConfigurationException { this.getConfiguration().save(out, encoding); } @Override public void configurationChanged(ConfigurationEvent event) { if (event.getSource() instanceof XMLConfiguration) { for (ConfigurationListener listener : getConfigurationListeners()) { listener.configurationChanged(event); } } } @Override public void configurationError(ConfigurationErrorEvent event) { if (event.getSource() instanceof XMLConfiguration) { for (ConfigurationErrorListener listener : getErrorListeners()) { listener.configurationError(event); } } if (event.getType() == AbstractFileConfiguration.EVENT_RELOAD) { if (isThrowable(event.getCause())) { throw new ConfigurationRuntimeException(event.getCause()); } } } /* * Don't allow resolveContainerStore to be called recursively. * @param key The key to resolve. * @return The value of the key. */ @Override protected Object resolveContainerStore(String key) { if (recursive.get().booleanValue()) { return null; } recursive.set(Boolean.TRUE); try { return super.resolveContainerStore(key); } finally { recursive.set(Boolean.FALSE); } } /** * Remove the current Configuration. */ public void removeConfiguration() { String path = getSubstitutor().replace(pattern); configurationsMap.remove(path); } /** * First checks to see if the cache exists, if it does, get the associated Configuration. * If not it will load a new Configuration and save it in the cache. * * @return the Configuration associated with the current value of the path pattern. */ private AbstractHierarchicalFileConfiguration getConfiguration() { if (pattern == null) { throw new ConfigurationRuntimeException("File pattern must be defined"); } String path = localSubst.replace(pattern); if (configurationsMap.containsKey(path)) { return configurationsMap.get(path); } if (path.equals(pattern)) { XMLConfiguration configuration = new XMLConfiguration() { @Override public void load() throws ConfigurationException { } @Override public void save() throws ConfigurationException { } }; configurationsMap.putIfAbsent(pattern, configuration); return configuration; } XMLConfiguration configuration = new XMLConfiguration(); if (loggerName != null) { Log log = LogFactory.getLog(loggerName); if (log != null) { configuration.setLogger(log); } } configuration.setBasePath(getBasePath()); configuration.setFileName(path); configuration.setFileSystem(getFileSystem()); configuration.setExpressionEngine(getExpressionEngine()); ReloadingStrategy strategy = createReloadingStrategy(); if (strategy != null) { configuration.setReloadingStrategy(strategy); } configuration.setDelimiterParsingDisabled(isDelimiterParsingDisabled()); configuration.setAttributeSplittingDisabled(isAttributeSplittingDisabled()); configuration.setValidating(validating); configuration.setSchemaValidation(schemaValidation); configuration.setEntityResolver(entityResolver); configuration.setListDelimiter(getListDelimiter()); configuration.addConfigurationListener(this); configuration.addErrorListener(this); try { configuration.load(); } catch (ConfigurationException ce) { if (isThrowable(ce)) { throw new ConfigurationRuntimeException(ce); } } configurationsMap.putIfAbsent(path, configuration); return configurationsMap.get(path); } private boolean isThrowable(Throwable throwable) { if (!ignoreException) { return true; } Throwable cause = throwable.getCause(); while (cause != null && !(cause instanceof SAXParseException)) { cause = cause.getCause(); } return cause != null; } /** * Clone the FileReloadingStrategy since each file needs its own. * @return A new FileReloadingStrategy. */ private ReloadingStrategy createReloadingStrategy() { if (fileStrategy == null) { return null; } try { ReloadingStrategy strategy = (ReloadingStrategy) BeanUtils.cloneBean(fileStrategy); strategy.setConfiguration(null); return strategy; } catch (Exception ex) { return null; } } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/package.html100644 2354 12232154103 31466 0ustarhenningstaff 0 0

The Configuration main package. It contains the definition of the Configuration interface and frequently used implementations like PropertiesConfiguration (dealing with .properties files) or XMLConfiguration that can load XML documents.

$Id: package.html 439648 2006-09-02 20:42:10Z oheger $

././@LongLink100644 0 0 166 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PatternSubtreeConfigurationWrapper.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PatternSubtreeConfigur100644 31375 12232154102 33620 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.Reader; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Properties; import org.apache.commons.configuration.event.ConfigurationErrorListener; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.ExpressionEngine; /** * Wraps a HierarchicalConfiguration and allows subtrees to be access via a configured path with * replaceable tokens derived from the ConfigurationInterpolator. When used with injection frameworks * such as Spring it allows components to be injected with subtrees of the configuration. * @since 1.6 * @author Commons * Configuration team * @version $Id: PatternSubtreeConfigurationWrapper.java 1534064 2013-10-21 08:44:33Z henning $ */ public class PatternSubtreeConfigurationWrapper extends AbstractHierarchicalFileConfiguration { /** * Prevent recursion while resolving unprefixed properties. */ private static ThreadLocal recursive = new ThreadLocal() { @Override protected synchronized Boolean initialValue() { return Boolean.FALSE; } }; /** The wrapped configuration */ private final AbstractHierarchicalFileConfiguration config; /** The path to the subtree */ private final String path; /** True if the path ends with '/', false otherwise */ private final boolean trailing; /** True if the constructor has finished */ private boolean init; /** * Constructor * @param config The Configuration to be wrapped. * @param path The base path pattern. */ public PatternSubtreeConfigurationWrapper(AbstractHierarchicalFileConfiguration config, String path) { this.config = config; this.path = path; this.trailing = path.endsWith("/"); this.init = true; } @Override public Object getReloadLock() { return config.getReloadLock(); } @Override public void addProperty(String key, Object value) { config.addProperty(makePath(key), value); } @Override public void clear() { getConfig().clear(); } @Override public void clearProperty(String key) { config.clearProperty(makePath(key)); } @Override public boolean containsKey(String key) { return config.containsKey(makePath(key)); } @Override public BigDecimal getBigDecimal(String key, BigDecimal defaultValue) { return config.getBigDecimal(makePath(key), defaultValue); } @Override public BigDecimal getBigDecimal(String key) { return config.getBigDecimal(makePath(key)); } @Override public BigInteger getBigInteger(String key, BigInteger defaultValue) { return config.getBigInteger(makePath(key), defaultValue); } @Override public BigInteger getBigInteger(String key) { return config.getBigInteger(makePath(key)); } @Override public boolean getBoolean(String key, boolean defaultValue) { return config.getBoolean(makePath(key), defaultValue); } @Override public Boolean getBoolean(String key, Boolean defaultValue) { return config.getBoolean(makePath(key), defaultValue); } @Override public boolean getBoolean(String key) { return config.getBoolean(makePath(key)); } @Override public byte getByte(String key, byte defaultValue) { return config.getByte(makePath(key), defaultValue); } @Override public Byte getByte(String key, Byte defaultValue) { return config.getByte(makePath(key), defaultValue); } @Override public byte getByte(String key) { return config.getByte(makePath(key)); } @Override public double getDouble(String key, double defaultValue) { return config.getDouble(makePath(key), defaultValue); } @Override public Double getDouble(String key, Double defaultValue) { return config.getDouble(makePath(key), defaultValue); } @Override public double getDouble(String key) { return config.getDouble(makePath(key)); } @Override public float getFloat(String key, float defaultValue) { return config.getFloat(makePath(key), defaultValue); } @Override public Float getFloat(String key, Float defaultValue) { return config.getFloat(makePath(key), defaultValue); } @Override public float getFloat(String key) { return config.getFloat(makePath(key)); } @Override public int getInt(String key, int defaultValue) { return config.getInt(makePath(key), defaultValue); } @Override public int getInt(String key) { return config.getInt(makePath(key)); } @Override public Integer getInteger(String key, Integer defaultValue) { return config.getInteger(makePath(key), defaultValue); } @Override public Iterator getKeys() { return config.getKeys(makePath()); } @Override public Iterator getKeys(String prefix) { return config.getKeys(makePath(prefix)); } @Override public List getList(String key, List defaultValue) { return config.getList(makePath(key), defaultValue); } @Override public List getList(String key) { return config.getList(makePath(key)); } @Override public long getLong(String key, long defaultValue) { return config.getLong(makePath(key), defaultValue); } @Override public Long getLong(String key, Long defaultValue) { return config.getLong(makePath(key), defaultValue); } @Override public long getLong(String key) { return config.getLong(makePath(key)); } @Override public Properties getProperties(String key) { return config.getProperties(makePath(key)); } @Override public Object getProperty(String key) { return config.getProperty(makePath(key)); } @Override public short getShort(String key, short defaultValue) { return config.getShort(makePath(key), defaultValue); } @Override public Short getShort(String key, Short defaultValue) { return config.getShort(makePath(key), defaultValue); } @Override public short getShort(String key) { return config.getShort(makePath(key)); } @Override public String getString(String key, String defaultValue) { return config.getString(makePath(key), defaultValue); } @Override public String getString(String key) { return config.getString(makePath(key)); } @Override public String[] getStringArray(String key) { return config.getStringArray(makePath(key)); } @Override public boolean isEmpty() { return getConfig().isEmpty(); } @Override public void setProperty(String key, Object value) { getConfig().setProperty(key, value); } @Override public Configuration subset(String prefix) { return getConfig().subset(prefix); } @Override public Node getRoot() { return getConfig().getRoot(); } @Override public void setRoot(Node node) { if (init) { getConfig().setRoot(node); } else { super.setRoot(node); } } @Override public ConfigurationNode getRootNode() { return getConfig().getRootNode(); } @Override public void setRootNode(ConfigurationNode rootNode) { if (init) { getConfig().setRootNode(rootNode); } else { super.setRootNode(rootNode); } } @Override public ExpressionEngine getExpressionEngine() { return config.getExpressionEngine(); } @Override public void setExpressionEngine(ExpressionEngine expressionEngine) { if (init) { config.setExpressionEngine(expressionEngine); } else { super.setExpressionEngine(expressionEngine); } } @Override public void addNodes(String key, Collection nodes) { getConfig().addNodes(key, nodes); } @Override public SubnodeConfiguration configurationAt(String key, boolean supportUpdates) { return config.configurationAt(makePath(key), supportUpdates); } @Override public SubnodeConfiguration configurationAt(String key) { return config.configurationAt(makePath(key)); } @Override public List configurationsAt(String key) { return config.configurationsAt(makePath(key)); } @Override public void clearTree(String key) { config.clearTree(makePath(key)); } @Override public int getMaxIndex(String key) { return config.getMaxIndex(makePath(key)); } @Override public Configuration interpolatedConfiguration() { return getConfig().interpolatedConfiguration(); } @Override public void addConfigurationListener(ConfigurationListener l) { getConfig().addConfigurationListener(l); } @Override public boolean removeConfigurationListener(ConfigurationListener l) { return getConfig().removeConfigurationListener(l); } @Override public Collection getConfigurationListeners() { return getConfig().getConfigurationListeners(); } @Override public void clearConfigurationListeners() { getConfig().clearConfigurationListeners(); } @Override public void addErrorListener(ConfigurationErrorListener l) { getConfig().addErrorListener(l); } @Override public boolean removeErrorListener(ConfigurationErrorListener l) { return getConfig().removeErrorListener(l); } @Override public void clearErrorListeners() { getConfig().clearErrorListeners(); } public void save(Writer writer) throws ConfigurationException { config.save(writer); } public void load(Reader reader) throws ConfigurationException { config.load(reader); } @Override public Collection getErrorListeners() { return getConfig().getErrorListeners(); } @Override protected Object resolveContainerStore(String key) { if (recursive.get().booleanValue()) { return null; } recursive.set(Boolean.TRUE); try { return super.resolveContainerStore(key); } finally { recursive.set(Boolean.FALSE); } } private HierarchicalConfiguration getConfig() { return config.configurationAt(makePath()); } private String makePath() { String pathPattern = trailing ? path.substring(0, path.length() - 1) : path; return getSubstitutor().replace(pathPattern); } /* * Resolve the root expression and then add the item being retrieved. Insert a * separator character as required. */ private String makePath(String item) { String pathPattern; if ((item.length() == 0 || item.startsWith("/")) && trailing) { pathPattern = path.substring(0, path.length() - 1); } else if (!item.startsWith("/") || !trailing) { pathPattern = path + "/"; } else { pathPattern = path; } return getSubstitutor().replace(pathPattern) + item; } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/plist/package.html100644 2033 12232154102 32612 0ustarhenningstaff 0 0

Configuration classes supporting NeXT / OpenStep /GNUStep style configuration.

$Id: package.html 527436 2007-04-11 09:57:29Z ebourg $

././@LongLink100644 0 0 163 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/plist/PropertyListConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/plist/PropertyListConf100644 53750 12232154102 33576 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.plist; import java.io.File; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TimeZone; import org.apache.commons.codec.binary.Hex; import org.apache.commons.configuration.AbstractHierarchicalFileConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.MapConfiguration; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.lang.StringUtils; /** * NeXT / OpenStep style configuration. This configuration can read and write * ASCII plist files. It supports the GNUStep extension to specify date objects. *

* References: *

* *

Example:

*
 * {
 *     foo = "bar";
 *
 *     array = ( value1, value2, value3 );
 *
 *     data = <4f3e0145ab>;
 *
 *     date = <*D2007-05-05 20:05:00 +0100>;
 *
 *     nested =
 *     {
 *         key1 = value1;
 *         key2 = value;
 *         nested =
 *         {
 *             foo = bar
 *         }
 *     }
 * }
 * 
* * @since 1.2 * * @author Emmanuel Bourg * @version $Id: PropertyListConfiguration.java 1210637 2011-12-05 21:12:12Z oheger $ */ public class PropertyListConfiguration extends AbstractHierarchicalFileConfiguration { /** Constant for the separator parser for the date part. */ private static final DateComponentParser DATE_SEPARATOR_PARSER = new DateSeparatorParser( "-"); /** Constant for the separator parser for the time part. */ private static final DateComponentParser TIME_SEPARATOR_PARSER = new DateSeparatorParser( ":"); /** Constant for the separator parser for blanks between the parts. */ private static final DateComponentParser BLANK_SEPARATOR_PARSER = new DateSeparatorParser( " "); /** An array with the component parsers for dealing with dates. */ private static final DateComponentParser[] DATE_PARSERS = {new DateSeparatorParser("<*D"), new DateFieldParser(Calendar.YEAR, 4), DATE_SEPARATOR_PARSER, new DateFieldParser(Calendar.MONTH, 2, 1), DATE_SEPARATOR_PARSER, new DateFieldParser(Calendar.DATE, 2), BLANK_SEPARATOR_PARSER, new DateFieldParser(Calendar.HOUR_OF_DAY, 2), TIME_SEPARATOR_PARSER, new DateFieldParser(Calendar.MINUTE, 2), TIME_SEPARATOR_PARSER, new DateFieldParser(Calendar.SECOND, 2), BLANK_SEPARATOR_PARSER, new DateTimeZoneParser(), new DateSeparatorParser(">")}; /** Constant for the ID prefix for GMT time zones. */ private static final String TIME_ZONE_PREFIX = "GMT"; /** The serial version UID. */ private static final long serialVersionUID = 3227248503779092127L; /** Constant for the milliseconds of a minute.*/ private static final int MILLIS_PER_MINUTE = 1000 * 60; /** Constant for the minutes per hour.*/ private static final int MINUTES_PER_HOUR = 60; /** Size of the indentation for the generated file. */ private static final int INDENT_SIZE = 4; /** Constant for the length of a time zone.*/ private static final int TIME_ZONE_LENGTH = 5; /** Constant for the padding character in the date format.*/ private static final char PAD_CHAR = '0'; /** * Creates an empty PropertyListConfiguration object which can be * used to synthesize a new plist file by adding values and * then saving(). */ public PropertyListConfiguration() { } /** * Creates a new instance of {@code PropertyListConfiguration} and * copies the content of the specified configuration into this object. * * @param c the configuration to copy * @since 1.4 */ public PropertyListConfiguration(HierarchicalConfiguration c) { super(c); } /** * Creates and loads the property list from the specified file. * * @param fileName The name of the plist file to load. * @throws ConfigurationException Error while loading the plist file */ public PropertyListConfiguration(String fileName) throws ConfigurationException { super(fileName); } /** * Creates and loads the property list from the specified file. * * @param file The plist file to load. * @throws ConfigurationException Error while loading the plist file */ public PropertyListConfiguration(File file) throws ConfigurationException { super(file); } /** * Creates and loads the property list from the specified URL. * * @param url The location of the plist file to load. * @throws ConfigurationException Error while loading the plist file */ public PropertyListConfiguration(URL url) throws ConfigurationException { super(url); } @Override public void setProperty(String key, Object value) { // special case for byte arrays, they must be stored as is in the configuration if (value instanceof byte[]) { fireEvent(EVENT_SET_PROPERTY, key, value, true); setDetailEvents(false); try { clearProperty(key); addPropertyDirect(key, value); } finally { setDetailEvents(true); } fireEvent(EVENT_SET_PROPERTY, key, value, false); } else { super.setProperty(key, value); } } @Override public void addProperty(String key, Object value) { if (value instanceof byte[]) { fireEvent(EVENT_ADD_PROPERTY, key, value, true); addPropertyDirect(key, value); fireEvent(EVENT_ADD_PROPERTY, key, value, false); } else { super.addProperty(key, value); } } public void load(Reader in) throws ConfigurationException { PropertyListParser parser = new PropertyListParser(in); try { HierarchicalConfiguration config = parser.parse(); setRoot(config.getRoot()); } catch (ParseException e) { throw new ConfigurationException(e); } } public void save(Writer out) throws ConfigurationException { PrintWriter writer = new PrintWriter(out); printNode(writer, 0, getRoot()); writer.flush(); } /** * Append a node to the writer, indented according to a specific level. */ private void printNode(PrintWriter out, int indentLevel, ConfigurationNode node) { String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE); if (node.getName() != null) { out.print(padding + quoteString(node.getName()) + " = "); } List children = new ArrayList(node.getChildren()); if (!children.isEmpty()) { // skip a line, except for the root dictionary if (indentLevel > 0) { out.println(); } out.println(padding + "{"); // display the children Iterator it = children.iterator(); while (it.hasNext()) { ConfigurationNode child = it.next(); printNode(out, indentLevel + 1, child); // add a semi colon for elements that are not dictionaries Object value = child.getValue(); if (value != null && !(value instanceof Map) && !(value instanceof Configuration)) { out.println(";"); } // skip a line after arrays and dictionaries if (it.hasNext() && (value == null || value instanceof List)) { out.println(); } } out.print(padding + "}"); // line feed if the dictionary is not in an array if (node.getParentNode() != null) { out.println(); } } else if (node.getValue() == null) { out.println(); out.print(padding + "{ };"); // line feed if the dictionary is not in an array if (node.getParentNode() != null) { out.println(); } } else { // display the leaf value Object value = node.getValue(); printValue(out, indentLevel, value); } } /** * Append a value to the writer, indented according to a specific level. */ private void printValue(PrintWriter out, int indentLevel, Object value) { String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE); if (value instanceof List) { out.print("( "); Iterator it = ((List) value).iterator(); while (it.hasNext()) { printValue(out, indentLevel + 1, it.next()); if (it.hasNext()) { out.print(", "); } } out.print(" )"); } else if (value instanceof HierarchicalConfiguration) { printNode(out, indentLevel, ((HierarchicalConfiguration) value).getRoot()); } else if (value instanceof Configuration) { // display a flat Configuration as a dictionary out.println(); out.println(padding + "{"); Configuration config = (Configuration) value; Iterator it = config.getKeys(); while (it.hasNext()) { String key = it.next(); Node node = new Node(key); node.setValue(config.getProperty(key)); printNode(out, indentLevel + 1, node); out.println(";"); } out.println(padding + "}"); } else if (value instanceof Map) { // display a Map as a dictionary Map map = transformMap((Map) value); printValue(out, indentLevel, new MapConfiguration(map)); } else if (value instanceof byte[]) { out.print("<" + new String(Hex.encodeHex((byte[]) value)) + ">"); } else if (value instanceof Date) { out.print(formatDate((Date) value)); } else if (value != null) { out.print(quoteString(String.valueOf(value))); } } /** * Quote the specified string if necessary, that's if the string contains: *
    *
  • a space character (' ', '\t', '\r', '\n')
  • *
  • a quote '"'
  • *
  • special characters in plist files ('(', ')', '{', '}', '=', ';', ',')
  • *
* Quotes within the string are escaped. * *

Examples:

*
    *
  • abcd -> abcd
  • *
  • ab cd -> "ab cd"
  • *
  • foo"bar -> "foo\"bar"
  • *
  • foo;bar -> "foo;bar"
  • *
*/ String quoteString(String s) { if (s == null) { return null; } if (s.indexOf(' ') != -1 || s.indexOf('\t') != -1 || s.indexOf('\r') != -1 || s.indexOf('\n') != -1 || s.indexOf('"') != -1 || s.indexOf('(') != -1 || s.indexOf(')') != -1 || s.indexOf('{') != -1 || s.indexOf('}') != -1 || s.indexOf('=') != -1 || s.indexOf(',') != -1 || s.indexOf(';') != -1) { s = s.replaceAll("\"", "\\\\\\\""); s = "\"" + s + "\""; } return s; } /** * Parses a date in a format like * {@code <*D2002-03-22 11:30:00 +0100>}. * * @param s the string with the date to be parsed * @return the parsed date * @throws ParseException if an error occurred while parsing the string */ static Date parseDate(String s) throws ParseException { Calendar cal = Calendar.getInstance(); cal.clear(); int index = 0; for (DateComponentParser parser : DATE_PARSERS) { index += parser.parseComponent(s, index, cal); } return cal.getTime(); } /** * Returns a string representation for the date specified by the given * calendar. * * @param cal the calendar with the initialized date * @return a string for this date */ static String formatDate(Calendar cal) { StringBuilder buf = new StringBuilder(); for (int i = 0; i < DATE_PARSERS.length; i++) { DATE_PARSERS[i].formatComponent(buf, cal); } return buf.toString(); } /** * Returns a string representation for the specified date. * * @param date the date * @return a string for this date */ static String formatDate(Date date) { Calendar cal = Calendar.getInstance(); cal.setTime(date); return formatDate(cal); } /** * Transform a map of arbitrary types into a map with string keys and object * values. All keys of the source map which are not of type String are * dropped. * * @param src the map to be converted * @return the resulting map */ private static Map transformMap(Map src) { Map dest = new HashMap(); for (Map.Entry e : src.entrySet()) { if (e.getKey() instanceof String) { dest.put((String) e.getKey(), e.getValue()); } } return dest; } /** * A helper class for parsing and formatting date literals. Usually we would * use {@code SimpleDateFormat} for this purpose, but in Java 1.3 the * functionality of this class is limited. So we have a hierarchy of parser * classes instead that deal with the different components of a date * literal. */ private abstract static class DateComponentParser { /** * Parses a component from the given input string. * * @param s the string to be parsed * @param index the current parsing position * @param cal the calendar where to store the result * @return the length of the processed component * @throws ParseException if the component cannot be extracted */ public abstract int parseComponent(String s, int index, Calendar cal) throws ParseException; /** * Formats a date component. This method is used for converting a date * in its internal representation into a string literal. * * @param buf the target buffer * @param cal the calendar with the current date */ public abstract void formatComponent(StringBuilder buf, Calendar cal); /** * Checks whether the given string has at least {@code length} * characters starting from the given parsing position. If this is not * the case, an exception will be thrown. * * @param s the string to be tested * @param index the current index * @param length the minimum length after the index * @throws ParseException if the string is too short */ protected void checkLength(String s, int index, int length) throws ParseException { int len = (s == null) ? 0 : s.length(); if (index + length > len) { throw new ParseException("Input string too short: " + s + ", index: " + index); } } /** * Adds a number to the given string buffer and adds leading '0' * characters until the given length is reached. * * @param buf the target buffer * @param num the number to add * @param length the required length */ protected void padNum(StringBuilder buf, int num, int length) { buf.append(StringUtils.leftPad(String.valueOf(num), length, PAD_CHAR)); } } /** * A specialized date component parser implementation that deals with * numeric calendar fields. The class is able to extract fields from a * string literal and to format a literal from a calendar. */ private static class DateFieldParser extends DateComponentParser { /** Stores the calendar field to be processed. */ private int calendarField; /** Stores the length of this field. */ private int length; /** An optional offset to add to the calendar field. */ private int offset; /** * Creates a new instance of {@code DateFieldParser}. * * @param calFld the calendar field code * @param len the length of this field */ public DateFieldParser(int calFld, int len) { this(calFld, len, 0); } /** * Creates a new instance of {@code DateFieldParser} and fully * initializes it. * * @param calFld the calendar field code * @param len the length of this field * @param ofs an offset to add to the calendar field */ public DateFieldParser(int calFld, int len, int ofs) { calendarField = calFld; length = len; offset = ofs; } @Override public void formatComponent(StringBuilder buf, Calendar cal) { padNum(buf, cal.get(calendarField) + offset, length); } @Override public int parseComponent(String s, int index, Calendar cal) throws ParseException { checkLength(s, index, length); try { cal.set(calendarField, Integer.parseInt(s.substring(index, index + length)) - offset); return length; } catch (NumberFormatException nfex) { throw new ParseException("Invalid number: " + s + ", index " + index); } } } /** * A specialized date component parser implementation that deals with * separator characters. */ private static class DateSeparatorParser extends DateComponentParser { /** Stores the separator. */ private String separator; /** * Creates a new instance of {@code DateSeparatorParser} and sets * the separator string. * * @param sep the separator string */ public DateSeparatorParser(String sep) { separator = sep; } @Override public void formatComponent(StringBuilder buf, Calendar cal) { buf.append(separator); } @Override public int parseComponent(String s, int index, Calendar cal) throws ParseException { checkLength(s, index, separator.length()); if (!s.startsWith(separator, index)) { throw new ParseException("Invalid input: " + s + ", index " + index + ", expected " + separator); } return separator.length(); } } /** * A specialized date component parser implementation that deals with the * time zone part of a date component. */ private static class DateTimeZoneParser extends DateComponentParser { @Override public void formatComponent(StringBuilder buf, Calendar cal) { TimeZone tz = cal.getTimeZone(); int ofs = tz.getRawOffset() / MILLIS_PER_MINUTE; if (ofs < 0) { buf.append('-'); ofs = -ofs; } else { buf.append('+'); } int hour = ofs / MINUTES_PER_HOUR; int min = ofs % MINUTES_PER_HOUR; padNum(buf, hour, 2); padNum(buf, min, 2); } @Override public int parseComponent(String s, int index, Calendar cal) throws ParseException { checkLength(s, index, TIME_ZONE_LENGTH); TimeZone tz = TimeZone.getTimeZone(TIME_ZONE_PREFIX + s.substring(index, index + TIME_ZONE_LENGTH)); cal.setTimeZone(tz); return TIME_ZONE_LENGTH; } } } ././@LongLink100644 0 0 166 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/plist/XMLPropertyListConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/plist/XMLPropertyListC100644 61140 12232154102 33444 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.plist; import java.io.File; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.math.BigDecimal; import java.math.BigInteger; import java.net.URL; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.TimeZone; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.commons.codec.binary.Base64; import org.apache.commons.configuration.AbstractHierarchicalFileConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.MapConfiguration; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.xml.sax.Attributes; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Property list file (plist) in XML FORMAT as used by Mac OS X (http://www.apple.com/DTDs/PropertyList-1.0.dtd). * This configuration doesn't support the binary FORMAT used in OS X 10.4. * *

Example:

*
 * <?xml version="1.0"?>
 * <!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
 * <plist version="1.0">
 *     <dict>
 *         <key>string</key>
 *         <string>value1</string>
 *
 *         <key>integer</key>
 *         <integer>12345</integer>
 *
 *         <key>real</key>
 *         <real>-123.45E-1</real>
 *
 *         <key>boolean</key>
 *         <true/>
 *
 *         <key>date</key>
 *         <date>2005-01-01T12:00:00Z</date>
 *
 *         <key>data</key>
 *         <data>RHJhY28gRG9ybWllbnMgTnVucXVhbSBUaXRpbGxhbmR1cw==</data>
 *
 *         <key>array</key>
 *         <array>
 *             <string>value1</string>
 *             <string>value2</string>
 *             <string>value3</string>
 *         </array>
 *
 *         <key>dictionnary</key>
 *         <dict>
 *             <key>key1</key>
 *             <string>value1</string>
 *             <key>key2</key>
 *             <string>value2</string>
 *             <key>key3</key>
 *             <string>value3</string>
 *         </dict>
 *
 *         <key>nested</key>
 *         <dict>
 *             <key>node1</key>
 *             <dict>
 *                 <key>node2</key>
 *                 <dict>
 *                     <key>node3</key>
 *                     <string>value</string>
 *                 </dict>
 *             </dict>
 *         </dict>
 *
 *     </dict>
 * </plist>
 * 
* * @since 1.2 * * @author Emmanuel Bourg * @version $Id: XMLPropertyListConfiguration.java 1368665 2012-08-02 19:48:26Z oheger $ */ public class XMLPropertyListConfiguration extends AbstractHierarchicalFileConfiguration { /** * The serial version UID. */ private static final long serialVersionUID = -3162063751042475985L; /** Size of the indentation for the generated file. */ private static final int INDENT_SIZE = 4; /** * Creates an empty XMLPropertyListConfiguration object which can be * used to synthesize a new plist file by adding values and * then saving(). */ public XMLPropertyListConfiguration() { initRoot(); } /** * Creates a new instance of {@code XMLPropertyListConfiguration} and * copies the content of the specified configuration into this object. * * @param configuration the configuration to copy * @since 1.4 */ public XMLPropertyListConfiguration(HierarchicalConfiguration configuration) { super(configuration); } /** * Creates and loads the property list from the specified file. * * @param fileName The name of the plist file to load. * @throws org.apache.commons.configuration.ConfigurationException Error * while loading the plist file */ public XMLPropertyListConfiguration(String fileName) throws ConfigurationException { super(fileName); } /** * Creates and loads the property list from the specified file. * * @param file The plist file to load. * @throws ConfigurationException Error while loading the plist file */ public XMLPropertyListConfiguration(File file) throws ConfigurationException { super(file); } /** * Creates and loads the property list from the specified URL. * * @param url The location of the plist file to load. * @throws ConfigurationException Error while loading the plist file */ public XMLPropertyListConfiguration(URL url) throws ConfigurationException { super(url); } @Override public void setProperty(String key, Object value) { // special case for byte arrays, they must be stored as is in the configuration if (value instanceof byte[]) { fireEvent(EVENT_SET_PROPERTY, key, value, true); setDetailEvents(false); try { clearProperty(key); addPropertyDirect(key, value); } finally { setDetailEvents(true); } fireEvent(EVENT_SET_PROPERTY, key, value, false); } else { super.setProperty(key, value); } } @Override public void addProperty(String key, Object value) { if (value instanceof byte[]) { fireEvent(EVENT_ADD_PROPERTY, key, value, true); addPropertyDirect(key, value); fireEvent(EVENT_ADD_PROPERTY, key, value, false); } else { super.addProperty(key, value); } } public void load(Reader in) throws ConfigurationException { // We have to make sure that the root node is actually a PListNode. // If this object was not created using the standard constructor, the // root node is a plain Node. if (!(getRootNode() instanceof PListNode)) { initRoot(); } // set up the DTD validation EntityResolver resolver = new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) { return new InputSource(getClass().getClassLoader().getResourceAsStream("PropertyList-1.0.dtd")); } }; // parse the file XMLPropertyListHandler handler = new XMLPropertyListHandler(getRoot()); try { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(true); SAXParser parser = factory.newSAXParser(); parser.getXMLReader().setEntityResolver(resolver); parser.getXMLReader().setContentHandler(handler); parser.getXMLReader().parse(new InputSource(in)); } catch (Exception e) { throw new ConfigurationException("Unable to parse the configuration file", e); } } public void save(Writer out) throws ConfigurationException { PrintWriter writer = new PrintWriter(out); if (getEncoding() != null) { writer.println(""); } else { writer.println(""); } writer.println(""); writer.println(""); printNode(writer, 1, getRoot()); writer.println(""); writer.flush(); } /** * Append a node to the writer, indented according to a specific level. */ private void printNode(PrintWriter out, int indentLevel, ConfigurationNode node) { String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE); if (node.getName() != null) { out.println(padding + "" + StringEscapeUtils.escapeXml(node.getName()) + ""); } List children = node.getChildren(); if (!children.isEmpty()) { out.println(padding + ""); Iterator it = children.iterator(); while (it.hasNext()) { ConfigurationNode child = it.next(); printNode(out, indentLevel + 1, child); if (it.hasNext()) { out.println(); } } out.println(padding + ""); } else if (node.getValue() == null) { out.println(padding + ""); } else { Object value = node.getValue(); printValue(out, indentLevel, value); } } /** * Append a value to the writer, indented according to a specific level. */ private void printValue(PrintWriter out, int indentLevel, Object value) { String padding = StringUtils.repeat(" ", indentLevel * INDENT_SIZE); if (value instanceof Date) { synchronized (PListNode.FORMAT) { out.println(padding + "" + PListNode.FORMAT.format((Date) value) + ""); } } else if (value instanceof Calendar) { printValue(out, indentLevel, ((Calendar) value).getTime()); } else if (value instanceof Number) { if (value instanceof Double || value instanceof Float || value instanceof BigDecimal) { out.println(padding + "" + value.toString() + ""); } else { out.println(padding + "" + value.toString() + ""); } } else if (value instanceof Boolean) { if (((Boolean) value).booleanValue()) { out.println(padding + ""); } else { out.println(padding + ""); } } else if (value instanceof List) { out.println(padding + ""); Iterator it = ((List) value).iterator(); while (it.hasNext()) { printValue(out, indentLevel + 1, it.next()); } out.println(padding + ""); } else if (value instanceof HierarchicalConfiguration) { printNode(out, indentLevel, ((HierarchicalConfiguration) value).getRoot()); } else if (value instanceof Configuration) { // display a flat Configuration as a dictionary out.println(padding + ""); Configuration config = (Configuration) value; Iterator it = config.getKeys(); while (it.hasNext()) { // create a node for each property String key = it.next(); Node node = new Node(key); node.setValue(config.getProperty(key)); // print the node printNode(out, indentLevel + 1, node); if (it.hasNext()) { out.println(); } } out.println(padding + ""); } else if (value instanceof Map) { // display a Map as a dictionary Map map = transformMap((Map) value); printValue(out, indentLevel, new MapConfiguration(map)); } else if (value instanceof byte[]) { String base64 = new String(Base64.encodeBase64((byte[]) value)); out.println(padding + "" + StringEscapeUtils.escapeXml(base64) + ""); } else if (value != null) { out.println(padding + "" + StringEscapeUtils.escapeXml(String.valueOf(value)) + ""); } else { out.println(padding + ""); } } /** * Helper method for initializing the configuration's root node. */ private void initRoot() { setRootNode(new PListNode()); } /** * Transform a map of arbitrary types into a map with string keys and object * values. All keys of the source map which are not of type String are * dropped. * * @param src the map to be converted * @return the resulting map */ private static Map transformMap(Map src) { Map dest = new HashMap(); for (Map.Entry e : src.entrySet()) { if (e.getKey() instanceof String) { dest.put((String) e.getKey(), e.getValue()); } } return dest; } /** * SAX Handler to build the configuration nodes while the document is being parsed. */ private class XMLPropertyListHandler extends DefaultHandler { /** The buffer containing the text node being read */ private StringBuilder buffer = new StringBuilder(); /** The stack of configuration nodes */ private List stack = new ArrayList(); public XMLPropertyListHandler(Node root) { push(root); } /** * Return the node on the top of the stack. */ private Node peek() { if (!stack.isEmpty()) { return stack.get(stack.size() - 1); } else { return null; } } /** * Remove and return the node on the top of the stack. */ private Node pop() { if (!stack.isEmpty()) { return stack.remove(stack.size() - 1); } else { return null; } } /** * Put a node on the top of the stack. */ private void push(Node node) { stack.add(node); } @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { if ("array".equals(qName)) { push(new ArrayNode()); } else if ("dict".equals(qName)) { if (peek() instanceof ArrayNode) { // create the configuration XMLPropertyListConfiguration config = new XMLPropertyListConfiguration(); // add it to the ArrayNode ArrayNode node = (ArrayNode) peek(); node.addValue(config); // push the root on the stack push(config.getRoot()); } } } @Override public void endElement(String uri, String localName, String qName) throws SAXException { if ("key".equals(qName)) { // create a new node, link it to its parent and push it on the stack PListNode node = new PListNode(); node.setName(buffer.toString()); peek().addChild(node); push(node); } else if ("dict".equals(qName)) { // remove the root of the XMLPropertyListConfiguration previously pushed on the stack pop(); } else { if ("string".equals(qName)) { ((PListNode) peek()).addValue(buffer.toString()); } else if ("integer".equals(qName)) { ((PListNode) peek()).addIntegerValue(buffer.toString()); } else if ("real".equals(qName)) { ((PListNode) peek()).addRealValue(buffer.toString()); } else if ("true".equals(qName)) { ((PListNode) peek()).addTrueValue(); } else if ("false".equals(qName)) { ((PListNode) peek()).addFalseValue(); } else if ("data".equals(qName)) { ((PListNode) peek()).addDataValue(buffer.toString()); } else if ("date".equals(qName)) { try { ((PListNode) peek()).addDateValue(buffer.toString()); } catch (IllegalArgumentException iex) { getLogger().warn( "Ignoring invalid date property " + buffer); } } else if ("array".equals(qName)) { ArrayNode array = (ArrayNode) pop(); ((PListNode) peek()).addList(array); } // remove the plist node on the stack once the value has been parsed, // array nodes remains on the stack for the next values in the list if (!(peek() instanceof ArrayNode)) { pop(); } } buffer.setLength(0); } @Override public void characters(char[] ch, int start, int length) throws SAXException { buffer.append(ch, start, length); } } /** * Node extension with addXXX methods to parse the typed data passed by the SAX handler. * Do not use this class ! It is used internally by XMLPropertyConfiguration * to parse the configuration file, it may be removed at any moment in the future. */ public static class PListNode extends Node { /** * The serial version UID. */ private static final long serialVersionUID = -7614060264754798317L; /** * The MacOS FORMAT of dates in plist files. Note: Because * {@code SimpleDateFormat} is not thread-safe, each access has to be * synchronized. */ private static final DateFormat FORMAT = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss'Z'"); static { FORMAT.setTimeZone(TimeZone.getTimeZone("UTC")); } /** * The GNUstep FORMAT of dates in plist files. Note: Because * {@code SimpleDateFormat} is not thread-safe, each access has to be * synchronized. */ private static final DateFormat GNUSTEP_FORMAT = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss Z"); /** * Update the value of the node. If the existing value is null, it's * replaced with the new value. If the existing value is a list, the * specified value is appended to the list. If the existing value is * not null, a list with the two values is built. * * @param value the value to be added */ public void addValue(Object value) { if (getValue() == null) { setValue(value); } else if (getValue() instanceof Collection) { // This is safe because we create the collections ourselves @SuppressWarnings("unchecked") Collection collection = (Collection) getValue(); collection.add(value); } else { List list = new ArrayList(); list.add(getValue()); list.add(value); setValue(list); } } /** * Parse the specified string as a date and add it to the values of the node. * * @param value the value to be added * @throws IllegalArgumentException if the date string cannot be parsed */ public void addDateValue(String value) { try { if (value.indexOf(' ') != -1) { // parse the date using the GNUstep FORMAT synchronized (GNUSTEP_FORMAT) { addValue(GNUSTEP_FORMAT.parse(value)); } } else { // parse the date using the MacOS X FORMAT synchronized (FORMAT) { addValue(FORMAT.parse(value)); } } } catch (ParseException e) { throw new IllegalArgumentException(String.format( "'%s' cannot be parsed to a date!", value), e); } } /** * Parse the specified string as a byte array in base 64 FORMAT * and add it to the values of the node. * * @param value the value to be added */ public void addDataValue(String value) { addValue(Base64.decodeBase64(value.getBytes())); } /** * Parse the specified string as an Interger and add it to the values of the node. * * @param value the value to be added */ public void addIntegerValue(String value) { addValue(new BigInteger(value)); } /** * Parse the specified string as a Double and add it to the values of the node. * * @param value the value to be added */ public void addRealValue(String value) { addValue(new BigDecimal(value)); } /** * Add a boolean value 'true' to the values of the node. */ public void addTrueValue() { addValue(Boolean.TRUE); } /** * Add a boolean value 'false' to the values of the node. */ public void addFalseValue() { addValue(Boolean.FALSE); } /** * Add a sublist to the values of the node. * * @param node the node whose value will be added to the current node value */ public void addList(ArrayNode node) { addValue(node.getValue()); } } /** * Container for array elements. Do not use this class ! * It is used internally by XMLPropertyConfiguration to parse the * configuration file, it may be removed at any moment in the future. */ public static class ArrayNode extends PListNode { /** * The serial version UID. */ private static final long serialVersionUID = 5586544306664205835L; /** The list of values in the array. */ private List list = new ArrayList(); /** * Add an object to the array. * * @param value the value to be added */ @Override public void addValue(Object value) { list.add(value); } /** * Return the list of values in the array. * * @return the {@link List} of values */ @Override public Object getValue() { return list; } } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PrefixedKeysIterator.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PrefixedKeysIterator.j100644 7762 12232154103 33504 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Iterator; import java.util.NoSuchElementException; /** * * A specialized iterator implementation used by {@link AbstractConfiguration} * to return an iteration over all keys starting with a specified prefix. * *

This class is basically a stripped-down version of the * {@code FilterIterator} class of Commons Collections

* * @author Commons Configuration team * @version $Id: PrefixedKeysIterator.java 1205603 2011-11-23 21:17:38Z oheger $ */ class PrefixedKeysIterator implements Iterator { /** Stores the wrapped iterator. */ private final Iterator iterator; /** Stores the prefix. */ private final String prefix; /** Stores the next element in the iteration. */ private String nextElement; /** A flag whether the next element has been calculated. */ private boolean nextElementSet; /** * Creates a new instance of {@code PrefixedKeysIterator} and sets * the wrapped iterator and the prefix for the accepted keys. * * @param wrappedIterator the wrapped iterator * @param keyPrefix the prefix of the allowed keys */ public PrefixedKeysIterator(Iterator wrappedIterator, String keyPrefix) { iterator = wrappedIterator; prefix = keyPrefix; } /** * Returns a flag whether there are more elements in the iteration. * * @return a flag if there is a next element */ public boolean hasNext() { return nextElementSet || setNextElement(); } /** * Returns the next element in the iteration. This is the next key that * matches the specified prefix. * * @return the next element in the iteration * @throws NoSuchElementException if there is no next element */ public String next() { if (!nextElementSet && !setNextElement()) { throw new NoSuchElementException(); } nextElementSet = false; return nextElement; } /** * Removes from the underlying collection of the base iterator the last * element returned by this iterator. This method can only be called if * {@code next()} was called, but not after {@code hasNext()}, * because the {@code hasNext()} call changes the base iterator. * * @throws IllegalStateException if {@code hasNext()} has already * been called. */ public void remove() { if (nextElementSet) { throw new IllegalStateException("remove() cannot be called"); } iterator.remove(); } /** * Determines the next element in the iteration. The return value indicates * whether such an element can be found. * * @return a flag whether a next element exists */ private boolean setNextElement() { while (iterator.hasNext()) { String key = iterator.next(); if (key.startsWith(prefix + ".") || key.equals(prefix)) { nextElement = key; nextElementSet = true; return true; } } return false; } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PropertiesConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PropertiesConfiguratio100644 142007 12232154102 33675 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.FilterWriter; import java.io.IOException; import java.io.LineNumberReader; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import org.apache.commons.lang.ArrayUtils; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; /** * This is the "classic" Properties loader which loads the values from * a single or multiple files (which can be chained with "include =". * All given path references are either absolute or relative to the * file name supplied in the constructor. *

* In this class, empty PropertyConfigurations can be built, properties * added and later saved. include statements are (obviously) not supported * if you don't construct a PropertyConfiguration from a file. * *

The properties file syntax is explained here, basically it follows * the syntax of the stream parsed by {@link java.util.Properties#load} and * adds several useful extensions: * *

    *
  • * Each property has the syntax key <separator> value. The * separators accepted are {@code '='}, {@code ':'} and any white * space character. Examples: *
     *  key1 = value1
     *  key2 : value2
     *  key3   value3
    *
  • *
  • * The key may use any character, separators must be escaped: *
     *  key\:foo = bar
    *
  • *
  • * value may be separated on different lines if a backslash * is placed at the end of the line that continues below. *
  • *
  • * value can contain value delimiters and will then be interpreted * as a list of tokens. Default value delimiter is the comma ','. So the * following property definition *
     *  key = This property, has multiple, values
     * 
    * will result in a property with three values. You can change the value * delimiter using the {@link AbstractConfiguration#setListDelimiter(char)} * method. Setting the delimiter to 0 will disable value splitting completely. *
  • *
  • * Commas in each token are escaped placing a backslash right before * the comma. *
  • *
  • * If a key is used more than once, the values are appended * like if they were on the same line separated with commas. Note: * When the configuration file is written back to disk the associated * {@link PropertiesConfigurationLayout} object (see below) will * try to preserve as much of the original format as possible, i.e. properties * with multiple values defined on a single line will also be written back on * a single line, and multiple occurrences of a single key will be written on * multiple lines. If the {@code addProperty()} method was called * multiple times for adding multiple values to a property, these properties * will per default be written on multiple lines in the output file, too. * Some options of the {@code PropertiesConfigurationLayout} class have * influence on that behavior. *
  • *
  • * Blank lines and lines starting with character '#' or '!' are skipped. *
  • *
  • * If a property is named "include" (or whatever is defined by * setInclude() and getInclude() and the value of that property is * the full path to a file on disk, that file will be included into * the configuration. You can also pull in files relative to the parent * configuration file. So if you have something like the following: * * include = additional.properties * * Then "additional.properties" is expected to be in the same * directory as the parent configuration file. * * The properties in the included file are added to the parent configuration, * they do not replace existing properties with the same key. * *
  • *
* *

Here is an example of a valid extended properties file: * *

 *      # lines starting with # are comments
 *
 *      # This is the simplest property
 *      key = value
 *
 *      # A long property may be separated on multiple lines
 *      longvalue = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
 *                  aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
 *
 *      # This is a property with many tokens
 *      tokens_on_a_line = first token, second token
 *
 *      # This sequence generates exactly the same result
 *      tokens_on_multiple_lines = first token
 *      tokens_on_multiple_lines = second token
 *
 *      # commas may be escaped in tokens
 *      commas.escaped = Hi\, what'up?
 *
 *      # properties can reference other properties
 *      base.prop = /base
 *      first.prop = ${base.prop}/first
 *      second.prop = ${first.prop}/second
 * 
* *

A {@code PropertiesConfiguration} object is associated with an * instance of the {@link PropertiesConfigurationLayout} class, * which is responsible for storing the layout of the parsed properties file * (i.e. empty lines, comments, and such things). The {@code getLayout()} * method can be used to obtain this layout object. With {@code setLayout()} * a new layout object can be set. This should be done before a properties file * was loaded. *

Note:Configuration objects of this type can be read concurrently * by multiple threads. However if one of these threads modifies the object, * synchronization has to be performed manually. * * @see java.util.Properties#load * * @author Stefano Mazzocchi * @author Jon S. Stevens * @author Dave Bryson * @author Geir Magnusson Jr. * @author Leon Messerschmidt * @author Kent Johnson * @author Daniel Rall * @author Ilkka Priha * @author Jason van Zyl * @author Martin Poeschl * @author Henning P. Schmiedehausen * @author Eric Pugh * @author Emmanuel Bourg * @version $Id: PropertiesConfiguration.java 1534445 2013-10-22 01:19:43Z henning $ */ public class PropertiesConfiguration extends AbstractFileConfiguration { /** Constant for the supported comment characters.*/ static final String COMMENT_CHARS = "#!"; /** Constant for the default properties separator.*/ static final String DEFAULT_SEPARATOR = " = "; /** * Constant for the default {@code IOFactory}. This instance is used * when no specific factory was set. */ private static final IOFactory DEFAULT_IO_FACTORY = new DefaultIOFactory(); /** * This is the name of the property that can point to other * properties file for including other properties files. */ private static String include = "include"; /** The list of possible key/value separators */ private static final char[] SEPARATORS = new char[] {'=', ':'}; /** The white space characters used as key/value separators. */ private static final char[] WHITE_SPACE = new char[]{' ', '\t', '\f'}; /** * The default encoding (ISO-8859-1 as specified by * http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html) */ private static final String DEFAULT_ENCODING = "ISO-8859-1"; /** Constant for the platform specific line separator.*/ private static final String LINE_SEPARATOR = System.getProperty("line.separator"); /** Constant for the escaping character.*/ private static final String ESCAPE = "\\"; /** Constant for the escaped escaping character.*/ private static final String DOUBLE_ESC = ESCAPE + ESCAPE; /** Constant for the radix of hex numbers.*/ private static final int HEX_RADIX = 16; /** Constant for the length of a unicode literal.*/ private static final int UNICODE_LEN = 4; /** Stores the layout object.*/ private PropertiesConfigurationLayout layout; /** The IOFactory for creating readers and writers.*/ private volatile IOFactory ioFactory; /** Allow file inclusion or not */ private boolean includesAllowed = true; /** * Creates an empty PropertyConfiguration object which can be * used to synthesize a new Properties file by adding values and * then saving(). */ public PropertiesConfiguration() { layout = createLayout(); } /** * Creates and loads the extended properties from the specified file. * The specified file can contain "include = " properties which then * are loaded and merged into the properties. * * @param fileName The name of the properties file to load. * @throws ConfigurationException Error while loading the properties file */ public PropertiesConfiguration(String fileName) throws ConfigurationException { super(fileName); } /** * Creates and loads the extended properties from the specified file. * The specified file can contain "include = " properties which then * are loaded and merged into the properties. If the file does not exist, * an empty configuration will be created. Later the {@code save()} * method can be called to save the properties to the specified file. * * @param file The properties file to load. * @throws ConfigurationException Error while loading the properties file */ public PropertiesConfiguration(File file) throws ConfigurationException { super(file); // If the file does not exist, no layout object was created. We have to // do this manually in this case. getLayout(); } /** * Creates and loads the extended properties from the specified URL. * The specified file can contain "include = " properties which then * are loaded and merged into the properties. * * @param url The location of the properties file to load. * @throws ConfigurationException Error while loading the properties file */ public PropertiesConfiguration(URL url) throws ConfigurationException { super(url); } /** * Gets the property value for including other properties files. * By default it is "include". * * @return A String. */ public static String getInclude() { return PropertiesConfiguration.include; } /** * Sets the property value for including other properties files. * By default it is "include". * * @param inc A String. */ public static void setInclude(String inc) { PropertiesConfiguration.include = inc; } /** * Controls whether additional files can be loaded by the include = * statement or not. This is true per default. * * @param includesAllowed True if Includes are allowed. */ public void setIncludesAllowed(boolean includesAllowed) { this.includesAllowed = includesAllowed; } /** * Reports the status of file inclusion. * * @return True if include files are loaded. * * @see PropertiesConfiguration#isIncludesAllowed() * * @deprecated Only exists to not break backwards compatibility. * Use {@link PropertiesConfiguration#isIncludesAllowed()} instead. */ @Deprecated public boolean getIncludesAllowed() { return isIncludesAllowed(); } /** * Reports the status of file inclusion. * * @return True if include files are loaded. */ public boolean isIncludesAllowed() { return this.includesAllowed; } /** * Return the comment header. * * @return the comment header * @since 1.1 */ public String getHeader() { return getLayout().getHeaderComment(); } /** * Set the comment header. * * @param header the header to use * @since 1.1 */ public void setHeader(String header) { getLayout().setHeaderComment(header); } /** * Returns the footer comment. This is a comment at the very end of the * file. * * @return the footer comment * @since 1.10 */ public String getFooter() { return getLayout().getFooterComment(); } /** * Sets the footer comment. If set, this comment is written after all * properties at the end of the file. * * @param footer the footer comment * @since 1.10 */ public void setFooter(String footer) { getLayout().setFooterComment(footer); } /** * Returns the encoding to be used when loading or storing configuration * data. This implementation ensures that the default encoding will be used * if none has been set explicitly. * * @return the encoding */ @Override public String getEncoding() { String enc = super.getEncoding(); return (enc != null) ? enc : DEFAULT_ENCODING; } /** * Returns the associated layout object. * * @return the associated layout object * @since 1.3 */ public synchronized PropertiesConfigurationLayout getLayout() { if (layout == null) { layout = createLayout(); } return layout; } /** * Sets the associated layout object. * * @param layout the new layout object; can be null, then a new * layout object will be created * @since 1.3 */ public synchronized void setLayout(PropertiesConfigurationLayout layout) { // only one layout must exist if (this.layout != null) { removeConfigurationListener(this.layout); } if (layout == null) { this.layout = createLayout(); } else { this.layout = layout; } } /** * Creates the associated layout object. This method is invoked when the * layout object is accessed and has not been created yet. Derived classes * can override this method to hook in a different layout implementation. * * @return the layout object to use * @since 1.3 */ protected PropertiesConfigurationLayout createLayout() { return new PropertiesConfigurationLayout(this); } /** * Returns the {@code IOFactory} to be used for creating readers and * writers when loading or saving this configuration. * * @return the {@code IOFactory} * @since 1.7 */ public IOFactory getIOFactory() { return (ioFactory != null) ? ioFactory : DEFAULT_IO_FACTORY; } /** * Sets the {@code IOFactory} to be used for creating readers and * writers when loading or saving this configuration. Using this method a * client can customize the reader and writer classes used by the load and * save operations. Note that this method must be called before invoking * one of the {@code load()} and {@code save()} methods. * Especially, if you want to use a custom {@code IOFactory} for * changing the {@code PropertiesReader}, you cannot load the * configuration data in the constructor. * * @param ioFactory the new {@code IOFactory} (must not be null) * @throws IllegalArgumentException if the {@code IOFactory} is * null * @since 1.7 */ public void setIOFactory(IOFactory ioFactory) { if (ioFactory == null) { throw new IllegalArgumentException("IOFactory must not be null!"); } this.ioFactory = ioFactory; } /** * Load the properties from the given reader. * Note that the {@code clear()} method is not called, so * the properties contained in the loaded file will be added to the * actual set of properties. * * @param in An InputStream. * * @throws ConfigurationException if an error occurs */ public synchronized void load(Reader in) throws ConfigurationException { boolean oldAutoSave = isAutoSave(); setAutoSave(false); try { getLayout().load(in); } finally { setAutoSave(oldAutoSave); } } /** * Save the configuration to the specified stream. * * @param writer the output stream used to save the configuration * @throws ConfigurationException if an error occurs */ public void save(Writer writer) throws ConfigurationException { enterNoReload(); try { getLayout().save(writer); } finally { exitNoReload(); } } /** * Extend the setBasePath method to turn includes * on and off based on the existence of a base path. * * @param basePath The new basePath to set. */ @Override public void setBasePath(String basePath) { super.setBasePath(basePath); setIncludesAllowed(StringUtils.isNotEmpty(basePath)); } /** * Creates a copy of this object. * * @return the copy */ @Override public Object clone() { PropertiesConfiguration copy = (PropertiesConfiguration) super.clone(); if (layout != null) { copy.setLayout(new PropertiesConfigurationLayout(copy, layout)); } return copy; } /** * This method is invoked by the associated * {@link PropertiesConfigurationLayout} object for each * property definition detected in the parsed properties file. Its task is * to check whether this is a special property definition (e.g. the * {@code include} property). If not, the property must be added to * this configuration. The return value indicates whether the property * should be treated as a normal property. If it is false, the * layout object will ignore this property. * * @param key the property key * @param value the property value * @return a flag whether this is a normal property * @throws ConfigurationException if an error occurs * @since 1.3 */ boolean propertyLoaded(String key, String value) throws ConfigurationException { boolean result; if (StringUtils.isNotEmpty(getInclude()) && key.equalsIgnoreCase(getInclude())) { if (isIncludesAllowed()) { String[] files; if (!isDelimiterParsingDisabled()) { files = StringUtils.split(value, getListDelimiter()); } else { files = new String[]{value}; } for (String f : files) { loadIncludeFile(interpolate(f.trim())); } } result = false; } else { addProperty(key, value); result = true; } return result; } /** * Tests whether a line is a comment, i.e. whether it starts with a comment * character. * * @param line the line * @return a flag if this is a comment line * @since 1.3 */ static boolean isCommentLine(String line) { String s = line.trim(); // blanc lines are also treated as comment lines return s.length() < 1 || COMMENT_CHARS.indexOf(s.charAt(0)) >= 0; } /** * Returns the number of trailing backslashes. This is sometimes needed for * the correct handling of escape characters. * * @param line the string to investigate * @return the number of trailing backslashes */ private static int countTrailingBS(String line) { int bsCount = 0; for (int idx = line.length() - 1; idx >= 0 && line.charAt(idx) == '\\'; idx--) { bsCount++; } return bsCount; } /** * This class is used to read properties lines. These lines do * not terminate with new-line chars but rather when there is no * backslash sign a the end of the line. This is used to * concatenate multiple lines for readability. */ public static class PropertiesReader extends LineNumberReader { /** The regular expression to parse the key and the value of a property. */ private static final Pattern PROPERTY_PATTERN = Pattern .compile("(([\\S&&[^\\\\" + new String(SEPARATORS) + "]]|\\\\.)*)(\\s*(\\s+|[" + new String(SEPARATORS) + "])\\s*)(.*)"); /** Constant for the index of the group for the key. */ private static final int IDX_KEY = 1; /** Constant for the index of the group for the value. */ private static final int IDX_VALUE = 5; /** Constant for the index of the group for the separator. */ private static final int IDX_SEPARATOR = 3; /** Stores the comment lines for the currently processed property.*/ private List commentLines; /** Stores the name of the last read property.*/ private String propertyName; /** Stores the value of the last read property.*/ private String propertyValue; /** Stores the property separator of the last read property.*/ private String propertySeparator = DEFAULT_SEPARATOR; /** Stores the list delimiter character.*/ private char delimiter; /** * Constructor. * * @param reader A Reader. */ public PropertiesReader(Reader reader) { this(reader, AbstractConfiguration.getDefaultListDelimiter()); } /** * Creates a new instance of {@code PropertiesReader} and sets * the underlying reader and the list delimiter. * * @param reader the reader * @param listDelimiter the list delimiter character * @since 1.3 */ public PropertiesReader(Reader reader, char listDelimiter) { super(reader); commentLines = new ArrayList(); delimiter = listDelimiter; } /** * Reads a property line. Returns null if Stream is * at EOF. Concatenates lines ending with "\". * Skips lines beginning with "#" or "!" and empty lines. * The return value is a property definition (<name> * = <value>) * * @return A string containing a property value or null * * @throws IOException in case of an I/O error */ public String readProperty() throws IOException { commentLines.clear(); StringBuilder buffer = new StringBuilder(); while (true) { String line = readLine(); if (line == null) { // EOF return null; } if (isCommentLine(line)) { commentLines.add(line); continue; } line = line.trim(); if (checkCombineLines(line)) { line = line.substring(0, line.length() - 1); buffer.append(line); } else { buffer.append(line); break; } } return buffer.toString(); } /** * Parses the next property from the input stream and stores the found * name and value in internal fields. These fields can be obtained using * the provided getter methods. The return value indicates whether EOF * was reached (false) or whether further properties are * available (true). * * @return a flag if further properties are available * @throws IOException if an error occurs * @since 1.3 */ public boolean nextProperty() throws IOException { String line = readProperty(); if (line == null) { return false; // EOF } // parse the line parseProperty(line); return true; } /** * Returns the comment lines that have been read for the last property. * * @return the comment lines for the last property returned by * {@code readProperty()} * @since 1.3 */ public List getCommentLines() { return commentLines; } /** * Returns the name of the last read property. This method can be called * after {@link #nextProperty()} was invoked and its * return value was true. * * @return the name of the last read property * @since 1.3 */ public String getPropertyName() { return propertyName; } /** * Returns the value of the last read property. This method can be * called after {@link #nextProperty()} was invoked and * its return value was true. * * @return the value of the last read property * @since 1.3 */ public String getPropertyValue() { return propertyValue; } /** * Returns the separator that was used for the last read property. The * separator can be stored so that it can later be restored when saving * the configuration. * * @return the separator for the last read property * @since 1.7 */ public String getPropertySeparator() { return propertySeparator; } /** * Parses a line read from the properties file. This method is called * for each non-comment line read from the source file. Its task is to * split the passed in line into the property key and its value. The * results of the parse operation can be stored by calling the * {@code initPropertyXXX()} methods. * * @param line the line read from the properties file * @since 1.7 */ protected void parseProperty(String line) { String[] property = doParseProperty(line); initPropertyName(property[0]); initPropertyValue(property[1]); initPropertySeparator(property[2]); } /** * Sets the name of the current property. This method can be called by * {@code parseProperty()} for storing the results of the parse * operation. It also ensures that the property key is correctly * escaped. * * @param name the name of the current property * @since 1.7 */ protected void initPropertyName(String name) { propertyName = StringEscapeUtils.unescapeJava(name); } /** * Sets the value of the current property. This method can be called by * {@code parseProperty()} for storing the results of the parse * operation. It also ensures that the property value is correctly * escaped. * * @param value the value of the current property * @since 1.7 */ protected void initPropertyValue(String value) { propertyValue = unescapeJava(value, delimiter); } /** * Sets the separator of the current property. This method can be called * by {@code parseProperty()}. It allows the associated layout * object to keep track of the property separators. When saving the * configuration the separators can be restored. * * @param value the separator used for the current property * @since 1.7 */ protected void initPropertySeparator(String value) { propertySeparator = value; } /** * Checks if the passed in line should be combined with the following. * This is true, if the line ends with an odd number of backslashes. * * @param line the line * @return a flag if the lines should be combined */ private static boolean checkCombineLines(String line) { return countTrailingBS(line) % 2 != 0; } /** * Parse a property line and return the key, the value, and the separator in an array. * * @param line the line to parse * @return an array with the property's key, value, and separator */ private static String[] doParseProperty(String line) { Matcher matcher = PROPERTY_PATTERN.matcher(line); String[] result = {"", "", ""}; if (matcher.matches()) { result[0] = matcher.group(IDX_KEY).trim(); result[1] = matcher.group(IDX_VALUE).trim(); result[2] = matcher.group(IDX_SEPARATOR); } return result; } } // class PropertiesReader /** * This class is used to write properties lines. The most important method * is {@code writeProperty(String, Object, boolean)}, which is called * during a save operation for each property found in the configuration. */ public static class PropertiesWriter extends FilterWriter { /** Constant for the initial size when creating a string buffer. */ private static final int BUF_SIZE = 8; /** The delimiter for multi-valued properties.*/ private char delimiter; /** The separator to be used for the current property. */ private String currentSeparator; /** The global separator. If set, it overrides the current separator.*/ private String globalSeparator; /** The line separator.*/ private String lineSeparator; /** * Constructor. * * @param writer a Writer object providing the underlying stream * @param delimiter the delimiter character for multi-valued properties */ public PropertiesWriter(Writer writer, char delimiter) { super(writer); this.delimiter = delimiter; } /** * Returns the current property separator. * * @return the current property separator * @since 1.7 */ public String getCurrentSeparator() { return currentSeparator; } /** * Sets the current property separator. This separator is used when * writing the next property. * * @param currentSeparator the current property separator * @since 1.7 */ public void setCurrentSeparator(String currentSeparator) { this.currentSeparator = currentSeparator; } /** * Returns the global property separator. * * @return the global property separator * @since 1.7 */ public String getGlobalSeparator() { return globalSeparator; } /** * Sets the global property separator. This separator corresponds to the * {@code globalSeparator} property of * {@link PropertiesConfigurationLayout}. It defines the separator to be * used for all properties. If it is undefined, the current separator is * used. * * @param globalSeparator the global property separator * @since 1.7 */ public void setGlobalSeparator(String globalSeparator) { this.globalSeparator = globalSeparator; } /** * Returns the line separator. * * @return the line separator * @since 1.7 */ public String getLineSeparator() { return (lineSeparator != null) ? lineSeparator : LINE_SEPARATOR; } /** * Sets the line separator. Each line written by this writer is * terminated with this separator. If not set, the platform-specific * line separator is used. * * @param lineSeparator the line separator to be used * @since 1.7 */ public void setLineSeparator(String lineSeparator) { this.lineSeparator = lineSeparator; } /** * Write a property. * * @param key the key of the property * @param value the value of the property * * @throws IOException if an I/O error occurs */ public void writeProperty(String key, Object value) throws IOException { writeProperty(key, value, false); } /** * Write a property. * * @param key The key of the property * @param values The array of values of the property * * @throws IOException if an I/O error occurs */ public void writeProperty(String key, List values) throws IOException { for (int i = 0; i < values.size(); i++) { writeProperty(key, values.get(i)); } } /** * Writes the given property and its value. If the value happens to be a * list, the {@code forceSingleLine} flag is evaluated. If it is * set, all values are written on a single line using the list delimiter * as separator. * * @param key the property key * @param value the property value * @param forceSingleLine the "force single line" flag * @throws IOException if an error occurs * @since 1.3 */ public void writeProperty(String key, Object value, boolean forceSingleLine) throws IOException { String v; if (value instanceof List) { List values = (List) value; if (forceSingleLine) { v = makeSingleLineValue(values); } else { writeProperty(key, values); return; } } else { v = escapeValue(value, false); } write(escapeKey(key)); write(fetchSeparator(key, value)); write(v); writeln(null); } /** * Write a comment. * * @param comment the comment to write * @throws IOException if an I/O error occurs */ public void writeComment(String comment) throws IOException { writeln("# " + comment); } /** * Escape the separators in the key. * * @param key the key * @return the escaped key * @since 1.2 */ private String escapeKey(String key) { StringBuilder newkey = new StringBuilder(); for (int i = 0; i < key.length(); i++) { char c = key.charAt(i); if (ArrayUtils.contains(SEPARATORS, c) || ArrayUtils.contains(WHITE_SPACE, c)) { // escape the separator newkey.append('\\'); newkey.append(c); } else { newkey.append(c); } } return newkey.toString(); } /** * Escapes the given property value. Delimiter characters in the value * will be escaped. * * @param value the property value * @param inList a flag whether the value is part of a list * @return the escaped property value * @since 1.3 */ private String escapeValue(Object value, boolean inList) { String escapedValue = handleBackslashs(value, inList); if (delimiter != 0) { escapedValue = StringUtils.replace(escapedValue, String.valueOf(delimiter), ESCAPE + delimiter); } return escapedValue; } /** * Performs the escaping of backslashes in the specified properties * value. Because a double backslash is used to escape the escape * character of a list delimiter, double backslashes also have to be * escaped if the property is part of a (single line) list. Then, in all * cases each backslash has to be doubled in order to produce a valid * properties file. * * @param value the value to be escaped * @param inList a flag whether the value is part of a list * @return the value with escaped backslashes as string */ private String handleBackslashs(Object value, boolean inList) { String strValue = String.valueOf(value); if (inList && strValue.indexOf(DOUBLE_ESC) >= 0) { char esc = ESCAPE.charAt(0); StringBuilder buf = new StringBuilder(strValue.length() + BUF_SIZE); for (int i = 0; i < strValue.length(); i++) { if (strValue.charAt(i) == esc && i < strValue.length() - 1 && strValue.charAt(i + 1) == esc) { buf.append(DOUBLE_ESC).append(DOUBLE_ESC); i++; } else { buf.append(strValue.charAt(i)); } } strValue = buf.toString(); } return StringEscapeUtils.escapeJava(strValue); } /** * Transforms a list of values into a single line value. * * @param values the list with the values * @return a string with the single line value (can be null) * @since 1.3 */ private String makeSingleLineValue(List values) { if (!values.isEmpty()) { Iterator it = values.iterator(); String lastValue = escapeValue(it.next(), true); StringBuilder buf = new StringBuilder(lastValue); while (it.hasNext()) { // if the last value ended with an escape character, it has // to be escaped itself; otherwise the list delimiter will // be escaped if (lastValue.endsWith(ESCAPE) && (countTrailingBS(lastValue) / 2) % 2 != 0) { buf.append(ESCAPE).append(ESCAPE); } buf.append(delimiter); lastValue = escapeValue(it.next(), true); buf.append(lastValue); } return buf.toString(); } else { return null; } } /** * Helper method for writing a line with the platform specific line * ending. * * @param s the content of the line (may be null) * @throws IOException if an error occurs * @since 1.3 */ public void writeln(String s) throws IOException { if (s != null) { write(s); } write(getLineSeparator()); } /** * Returns the separator to be used for the given property. This method * is called by {@code writeProperty()}. The string returned here * is used as separator between the property key and its value. Per * default the method checks whether a global separator is set. If this * is the case, it is returned. Otherwise the separator returned by * {@code getCurrentSeparator()} is used, which was set by the * associated layout object. Derived classes may implement a different * strategy for defining the separator. * * @param key the property key * @param value the value * @return the separator to be used * @since 1.7 */ protected String fetchSeparator(String key, Object value) { return (getGlobalSeparator() != null) ? getGlobalSeparator() : getCurrentSeparator(); } } // class PropertiesWriter /** *

* Definition of an interface that allows customization of read and write * operations. *

*

* For reading and writing properties files the inner classes * {@code PropertiesReader} and {@code PropertiesWriter} are used. * This interface defines factory methods for creating both a * {@code PropertiesReader} and a {@code PropertiesWriter}. An * object implementing this interface can be passed to the * {@code setIOFactory()} method of * {@code PropertiesConfiguration}. Every time the configuration is * read or written the {@code IOFactory} is asked to create the * appropriate reader or writer object. This provides an opportunity to * inject custom reader or writer implementations. *

* * @since 1.7 */ public interface IOFactory { /** * Creates a {@code PropertiesReader} for reading a properties * file. This method is called whenever the * {@code PropertiesConfiguration} is loaded. The reader returned * by this method is then used for parsing the properties file. * * @param in the underlying reader (of the properties file) * @param delimiter the delimiter character for list parsing * @return the {@code PropertiesReader} for loading the * configuration */ PropertiesReader createPropertiesReader(Reader in, char delimiter); /** * Creates a {@code PropertiesWriter} for writing a properties * file. This method is called before the * {@code PropertiesConfiguration} is saved. The writer returned by * this method is then used for writing the properties file. * * @param out the underlying writer (to the properties file) * @param delimiter the delimiter character for list parsing * @return the {@code PropertiesWriter} for saving the * configuration */ PropertiesWriter createPropertiesWriter(Writer out, char delimiter); } /** *

* A default implementation of the {@code IOFactory} interface. *

*

* This class implements the {@code createXXXX()} methods defined by * the {@code IOFactory} interface in a way that the default objects * (i.e. {@code PropertiesReader} and {@code PropertiesWriter} are * returned. Customizing either the reader or the writer (or both) can be * done by extending this class and overriding the corresponding * {@code createXXXX()} method. *

* * @since 1.7 */ public static class DefaultIOFactory implements IOFactory { public PropertiesReader createPropertiesReader(Reader in, char delimiter) { return new PropertiesReader(in, delimiter); } public PropertiesWriter createPropertiesWriter(Writer out, char delimiter) { return new PropertiesWriter(out, delimiter); } } /** *

Unescapes any Java literals found in the {@code String} to a * {@code Writer}.

This is a slightly modified version of the * StringEscapeUtils.unescapeJava() function in commons-lang that doesn't * drop escaped separators (i.e '\,'). * * @param str the {@code String} to unescape, may be null * @param delimiter the delimiter for multi-valued properties * @return the processed string * @throws IllegalArgumentException if the Writer is {@code null} */ protected static String unescapeJava(String str, char delimiter) { if (str == null) { return null; } int sz = str.length(); StringBuilder out = new StringBuilder(sz); StringBuilder unicode = new StringBuilder(UNICODE_LEN); boolean hadSlash = false; boolean inUnicode = false; for (int i = 0; i < sz; i++) { char ch = str.charAt(i); if (inUnicode) { // if in unicode, then we're reading unicode // values in somehow unicode.append(ch); if (unicode.length() == UNICODE_LEN) { // unicode now contains the four hex digits // which represents our unicode character try { int value = Integer.parseInt(unicode.toString(), HEX_RADIX); out.append((char) value); unicode.setLength(0); inUnicode = false; hadSlash = false; } catch (NumberFormatException nfe) { throw new ConfigurationRuntimeException("Unable to parse unicode value: " + unicode, nfe); } } continue; } if (hadSlash) { // handle an escaped value hadSlash = false; if (ch == '\\') { out.append('\\'); } else if (ch == '\'') { out.append('\''); } else if (ch == '\"') { out.append('"'); } else if (ch == 'r') { out.append('\r'); } else if (ch == 'f') { out.append('\f'); } else if (ch == 't') { out.append('\t'); } else if (ch == 'n') { out.append('\n'); } else if (ch == 'b') { out.append('\b'); } else if (ch == delimiter) { out.append('\\'); out.append(delimiter); } else if (ch == 'u') { // uh-oh, we're in unicode country.... inUnicode = true; } else { out.append(ch); } continue; } else if (ch == '\\') { hadSlash = true; continue; } out.append(ch); } if (hadSlash) { // then we're in the weird case of a \ at the end of the // string, let's output it anyway. out.append('\\'); } return out.toString(); } /** * Helper method for loading an included properties file. This method is * called by {@code load()} when an {@code include} property * is encountered. It tries to resolve relative file names based on the * current base path. If this fails, a resolution based on the location of * this properties file is tried. * * @param fileName the name of the file to load * @throws ConfigurationException if loading fails */ private void loadIncludeFile(String fileName) throws ConfigurationException { URL url = ConfigurationUtils.locate(getFileSystem(), getBasePath(), fileName); if (url == null) { URL baseURL = getURL(); if (baseURL != null) { url = ConfigurationUtils.locate(getFileSystem(), baseURL.toString(), fileName); } } if (url == null) { throw new ConfigurationException("Cannot resolve include file " + fileName); } load(url); } } ././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PropertiesConfigurationLayout.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PropertiesConfiguratio100644 103572 12232154102 33701 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.lang.StringUtils; /** *

* A helper class used by {@link PropertiesConfiguration} to keep * the layout of a properties file. *

*

* Instances of this class are associated with a * {@code PropertiesConfiguration} object. They are responsible for * analyzing properties files and for extracting as much information about the * file layout (e.g. empty lines, comments) as possible. When the properties * file is written back again it should be close to the original. *

*

* The {@code PropertiesConfigurationLayout} object associated with a * {@code PropertiesConfiguration} object can be obtained using the * {@code getLayout()} method of the configuration. Then the methods * provided by this class can be used to alter the properties file's layout. *

*

* Implementation note: This is a very simple implementation, which is far away * from being perfect, i.e. the original layout of a properties file won't be * reproduced in all cases. One limitation is that comments for multi-valued * property keys are concatenated. Maybe this implementation can later be * improved. *

*

* To get an impression how this class works consider the following properties * file: *

*

* *

 * # A demo configuration file
 * # for Demo App 1.42
 *
 * # Application name
 * AppName=Demo App
 *
 * # Application vendor
 * AppVendor=DemoSoft
 *
 *
 * # GUI properties
 * # Window Color
 * windowColors=0xFFFFFF,0x000000
 *
 * # Include some setting
 * include=settings.properties
 * # Another vendor
 * AppVendor=TestSoft
 * 
* *

*

* For this example the following points are relevant: *

*

*

    *
  • The first two lines are set as header comment. The header comment is * determined by the last blanc line before the first property definition.
  • *
  • For the property {@code AppName} one comment line and one * leading blanc line is stored.
  • *
  • For the property {@code windowColors} two comment lines and two * leading blanc lines are stored.
  • *
  • Include files is something this class cannot deal with well. When saving * the properties configuration back, the included properties are simply * contained in the original file. The comment before the include property is * skipped.
  • *
  • For all properties except for {@code AppVendor} the "single * line" flag is set. This is relevant only for {@code windowColors}, * which has multiple values defined in one line using the separator character.
  • *
  • The {@code AppVendor} property appears twice. The comment lines * are concatenated, so that {@code layout.getComment("AppVendor");} will * result in Application vendor<CR>Another vendor, with * <CR> meaning the line separator. In addition the * "single line" flag is set to false for this property. When * the file is saved, two property definitions will be written (in series).
  • *
*

* * @author Commons * Configuration team * @version $Id: PropertiesConfigurationLayout.java 1534402 2013-10-21 22:35:52Z henning $ * @since 1.3 */ public class PropertiesConfigurationLayout implements ConfigurationListener { /** Constant for the line break character. */ private static final String CR = "\n"; /** Constant for the default comment prefix. */ private static final String COMMENT_PREFIX = "# "; /** Stores the associated configuration object. */ private PropertiesConfiguration configuration; /** Stores a map with the contained layout information. */ private Map layoutData; /** Stores the header comment. */ private String headerComment; /** Stores the footer comment. */ private String footerComment; /** The global separator that will be used for all properties. */ private String globalSeparator; /** The line separator.*/ private String lineSeparator; /** A counter for determining nested load calls. */ private int loadCounter; /** Stores the force single line flag. */ private boolean forceSingleLine; /** * Creates a new instance of {@code PropertiesConfigurationLayout} * and initializes it with the associated configuration object. * * @param config the configuration (must not be null) */ public PropertiesConfigurationLayout(PropertiesConfiguration config) { this(config, null); } /** * Creates a new instance of {@code PropertiesConfigurationLayout} * and initializes it with the given configuration object. The data of the * specified layout object is copied. * * @param config the configuration (must not be null) * @param c the layout object to be copied */ public PropertiesConfigurationLayout(PropertiesConfiguration config, PropertiesConfigurationLayout c) { if (config == null) { throw new IllegalArgumentException( "Configuration must not be null!"); } configuration = config; layoutData = new LinkedHashMap(); config.addConfigurationListener(this); if (c != null) { copyFrom(c); } } /** * Returns the associated configuration object. * * @return the associated configuration */ public PropertiesConfiguration getConfiguration() { return configuration; } /** * Returns the comment for the specified property key in a canonical form. * "Canonical" means that either all lines start with a comment * character or none. If the {@code commentChar} parameter is false, * all comment characters are removed, so that the result is only the plain * text of the comment. Otherwise it is ensured that each line of the * comment starts with a comment character. Also, line breaks in the comment * are normalized to the line separator "\n". * * @param key the key of the property * @param commentChar determines whether all lines should start with comment * characters or not * @return the canonical comment for this key (can be null) */ public String getCanonicalComment(String key, boolean commentChar) { return constructCanonicalComment(getComment(key), commentChar); } /** * Returns the comment for the specified property key. The comment is * returned as it was set (either manually by calling * {@code setComment()} or when it was loaded from a properties * file). No modifications are performed. * * @param key the key of the property * @return the comment for this key (can be null) */ public String getComment(String key) { return fetchLayoutData(key).getComment(); } /** * Sets the comment for the specified property key. The comment (or its * single lines if it is a multi-line comment) can start with a comment * character. If this is the case, it will be written without changes. * Otherwise a default comment character is added automatically. * * @param key the key of the property * @param comment the comment for this key (can be null, then the * comment will be removed) */ public void setComment(String key, String comment) { fetchLayoutData(key).setComment(comment); } /** * Returns the number of blanc lines before this property key. If this key * does not exist, 0 will be returned. * * @param key the property key * @return the number of blanc lines before the property definition for this * key */ public int getBlancLinesBefore(String key) { return fetchLayoutData(key).getBlancLines(); } /** * Sets the number of blanc lines before the given property key. This can be * used for a logical grouping of properties. * * @param key the property key * @param number the number of blanc lines to add before this property * definition */ public void setBlancLinesBefore(String key, int number) { fetchLayoutData(key).setBlancLines(number); } /** * Returns the header comment of the represented properties file in a * canonical form. With the {@code commentChar} parameter it can be * specified whether comment characters should be stripped or be always * present. * * @param commentChar determines the presence of comment characters * @return the header comment (can be null) */ public String getCanonicalHeaderComment(boolean commentChar) { return constructCanonicalComment(getHeaderComment(), commentChar); } /** * Returns the header comment of the represented properties file. This * method returns the header comment exactly as it was set using * {@code setHeaderComment()} or extracted from the loaded properties * file. * * @return the header comment (can be null) */ public String getHeaderComment() { return headerComment; } /** * Sets the header comment for the represented properties file. This comment * will be output on top of the file. * * @param comment the comment */ public void setHeaderComment(String comment) { headerComment = comment; } /** * Returns the footer comment of the represented properties file in a * canonical form. This method works like * {@code getCanonicalHeaderComment()}, but reads the footer comment. * * @param commentChar determines the presence of comment characters * @return the footer comment (can be null) * @see #getCanonicalHeaderComment(boolean) * @since 1.10 */ public String getCanonicalFooterCooment(boolean commentChar) { return constructCanonicalComment(getFooterComment(), commentChar); } /** * Returns the footer comment of the represented properties file. This * method returns the footer comment exactly as it was set using * {@code setFooterComment()} or extracted from the loaded properties * file. * * @return the footer comment (can be null) * @since 1.10 */ public String getFooterComment() { return footerComment; } /** * Sets the footer comment for the represented properties file. This comment * will be output at the bottom of the file. * * @param footerComment the footer comment * @since 1.10 */ public void setFooterComment(String footerComment) { this.footerComment = footerComment; } /** * Returns a flag whether the specified property is defined on a single * line. This is meaningful only if this property has multiple values. * * @param key the property key * @return a flag if this property is defined on a single line */ public boolean isSingleLine(String key) { return fetchLayoutData(key).isSingleLine(); } /** * Sets the "single line flag" for the specified property key. * This flag is evaluated if the property has multiple values (i.e. if it is * a list property). In this case, if the flag is set, all values will be * written in a single property definition using the list delimiter as * separator. Otherwise multiple lines will be written for this property, * each line containing one property value. * * @param key the property key * @param f the single line flag */ public void setSingleLine(String key, boolean f) { fetchLayoutData(key).setSingleLine(f); } /** * Returns the "force single line" flag. * * @return the force single line flag * @see #setForceSingleLine(boolean) */ public boolean isForceSingleLine() { return forceSingleLine; } /** * Sets the "force single line" flag. If this flag is set, all * properties with multiple values are written on single lines. This mode * provides more compatibility with {@code java.lang.Properties}, * which cannot deal with multiple definitions of a single property. This * mode has no effect if the list delimiter parsing is disabled. * * @param f the force single line flag */ public void setForceSingleLine(boolean f) { forceSingleLine = f; } /** * Returns the separator for the property with the given key. * * @param key the property key * @return the property separator for this property * @since 1.7 */ public String getSeparator(String key) { return fetchLayoutData(key).getSeparator(); } /** * Sets the separator to be used for the property with the given key. The * separator is the string between the property key and its value. For new * properties " = " is used. When a properties file is read, the * layout tries to determine the separator for each property. With this * method the separator can be changed. To be compatible with the properties * format only the characters {@code =} and {@code :} (with or * without whitespace) should be used, but this method does not enforce this * - it accepts arbitrary strings. If the key refers to a property with * multiple values that are written on multiple lines, this separator will * be used on all lines. * * @param key the key for the property * @param sep the separator to be used for this property * @since 1.7 */ public void setSeparator(String key, String sep) { fetchLayoutData(key).setSeparator(sep); } /** * Returns the global separator. * * @return the global properties separator * @since 1.7 */ public String getGlobalSeparator() { return globalSeparator; } /** * Sets the global separator for properties. With this method a separator * can be set that will be used for all properties when writing the * configuration. This is an easy way of determining the properties * separator globally. To be compatible with the properties format only the * characters {@code =} and {@code :} (with or without whitespace) * should be used, but this method does not enforce this - it accepts * arbitrary strings. If the global separator is set to null, * property separators are not changed. This is the default behavior as it * produces results that are closer to the original properties file. * * @param globalSeparator the separator to be used for all properties * @since 1.7 */ public void setGlobalSeparator(String globalSeparator) { this.globalSeparator = globalSeparator; } /** * Returns the line separator. * * @return the line separator * @since 1.7 */ public String getLineSeparator() { return lineSeparator; } /** * Sets the line separator. When writing the properties configuration, all * lines are terminated with this separator. If no separator was set, the * platform-specific default line separator is used. * * @param lineSeparator the line separator * @since 1.7 */ public void setLineSeparator(String lineSeparator) { this.lineSeparator = lineSeparator; } /** * Returns a set with all property keys managed by this object. * * @return a set with all contained property keys */ public Set getKeys() { return layoutData.keySet(); } /** * Reads a properties file and stores its internal structure. The found * properties will be added to the associated configuration object. * * @param in the reader to the properties file * @throws ConfigurationException if an error occurs */ public void load(Reader in) throws ConfigurationException { if (++loadCounter == 1) { getConfiguration().removeConfigurationListener(this); } PropertiesConfiguration.PropertiesReader reader = getConfiguration() .getIOFactory().createPropertiesReader(in, getConfiguration().getListDelimiter()); try { while (reader.nextProperty()) { if (getConfiguration().propertyLoaded(reader.getPropertyName(), reader.getPropertyValue())) { boolean contained = layoutData.containsKey(reader .getPropertyName()); int blancLines = 0; int idx = checkHeaderComment(reader.getCommentLines()); while (idx < reader.getCommentLines().size() && reader.getCommentLines().get(idx).length() < 1) { idx++; blancLines++; } String comment = extractComment(reader.getCommentLines(), idx, reader.getCommentLines().size() - 1); PropertyLayoutData data = fetchLayoutData(reader .getPropertyName()); if (contained) { data.addComment(comment); data.setSingleLine(false); } else { data.setComment(comment); data.setBlancLines(blancLines); data.setSeparator(reader.getPropertySeparator()); } } } setFooterComment(extractComment(reader.getCommentLines(), 0, reader .getCommentLines().size() - 1)); } catch (IOException ioex) { throw new ConfigurationException(ioex); } finally { if (--loadCounter == 0) { getConfiguration().addConfigurationListener(this); } } } /** * Writes the properties file to the given writer, preserving as much of its * structure as possible. * * @param out the writer * @throws ConfigurationException if an error occurs */ public void save(Writer out) throws ConfigurationException { try { char delimiter = getConfiguration().isDelimiterParsingDisabled() ? 0 : getConfiguration().getListDelimiter(); PropertiesConfiguration.PropertiesWriter writer = getConfiguration() .getIOFactory().createPropertiesWriter(out, delimiter); writer.setGlobalSeparator(getGlobalSeparator()); if (getLineSeparator() != null) { writer.setLineSeparator(getLineSeparator()); } if (headerComment != null) { writeComment(writer, getCanonicalHeaderComment(true)); writer.writeln(null); } for (String key : layoutData.keySet()) { if (getConfiguration().containsKey(key)) { // Output blank lines before property for (int i = 0; i < getBlancLinesBefore(key); i++) { writer.writeln(null); } // Output the comment writeComment(writer, getCanonicalComment(key, true)); // Output the property and its value boolean singleLine = (isForceSingleLine() || isSingleLine(key)) && !getConfiguration().isDelimiterParsingDisabled(); writer.setCurrentSeparator(getSeparator(key)); writer.writeProperty(key, getConfiguration().getProperty( key), singleLine); } } writeComment(writer, getCanonicalFooterCooment(true)); writer.flush(); } catch (IOException ioex) { throw new ConfigurationException(ioex); } } /** * The event listener callback. Here event notifications of the * configuration object are processed to update the layout object properly. * * @param event the event object */ public void configurationChanged(ConfigurationEvent event) { if (event.isBeforeUpdate()) { if (AbstractFileConfiguration.EVENT_RELOAD == event.getType()) { clear(); } } else { switch (event.getType()) { case AbstractConfiguration.EVENT_ADD_PROPERTY: boolean contained = layoutData.containsKey(event .getPropertyName()); PropertyLayoutData data = fetchLayoutData(event .getPropertyName()); data.setSingleLine(!contained); break; case AbstractConfiguration.EVENT_CLEAR_PROPERTY: layoutData.remove(event.getPropertyName()); break; case AbstractConfiguration.EVENT_CLEAR: clear(); break; case AbstractConfiguration.EVENT_SET_PROPERTY: fetchLayoutData(event.getPropertyName()); break; } } } /** * Returns a layout data object for the specified key. If this is a new key, * a new object is created and initialized with default values. * * @param key the key * @return the corresponding layout data object */ private PropertyLayoutData fetchLayoutData(String key) { if (key == null) { throw new IllegalArgumentException("Property key must not be null!"); } PropertyLayoutData data = layoutData.get(key); if (data == null) { data = new PropertyLayoutData(); data.setSingleLine(true); layoutData.put(key, data); } return data; } /** * Removes all content from this layout object. */ private void clear() { layoutData.clear(); setHeaderComment(null); } /** * Tests whether a line is a comment, i.e. whether it starts with a comment * character. * * @param line the line * @return a flag if this is a comment line */ static boolean isCommentLine(String line) { return PropertiesConfiguration.isCommentLine(line); } /** * Trims a comment. This method either removes all comment characters from * the given string, leaving only the plain comment text or ensures that * every line starts with a valid comment character. * * @param s the string to be processed * @param comment if true, a comment character will always be * enforced; if false, it will be removed * @return the trimmed comment */ static String trimComment(String s, boolean comment) { StringBuilder buf = new StringBuilder(s.length()); int lastPos = 0; int pos; do { pos = s.indexOf(CR, lastPos); if (pos >= 0) { String line = s.substring(lastPos, pos); buf.append(stripCommentChar(line, comment)).append(CR); lastPos = pos + CR.length(); } } while (pos >= 0); if (lastPos < s.length()) { buf.append(stripCommentChar(s.substring(lastPos), comment)); } return buf.toString(); } /** * Either removes the comment character from the given comment line or * ensures that the line starts with a comment character. * * @param s the comment line * @param comment if true, a comment character will always be * enforced; if false, it will be removed * @return the line without comment character */ static String stripCommentChar(String s, boolean comment) { if (s.length() < 1 || (isCommentLine(s) == comment)) { return s; } else { if (!comment) { int pos = 0; // find first comment character while (PropertiesConfiguration.COMMENT_CHARS.indexOf(s .charAt(pos)) < 0) { pos++; } // Remove leading spaces pos++; while (pos < s.length() && Character.isWhitespace(s.charAt(pos))) { pos++; } return (pos < s.length()) ? s.substring(pos) : StringUtils.EMPTY; } else { return COMMENT_PREFIX + s; } } } /** * Extracts a comment string from the given range of the specified comment * lines. The single lines are added using a line feed as separator. * * @param commentLines a list with comment lines * @param from the start index * @param to the end index (inclusive) * @return the comment string (null if it is undefined) */ private String extractComment(List commentLines, int from, int to) { if (to < from) { return null; } else { StringBuilder buf = new StringBuilder(commentLines.get(from)); for (int i = from + 1; i <= to; i++) { buf.append(CR); buf.append(commentLines.get(i)); } return buf.toString(); } } /** * Checks if parts of the passed in comment can be used as header comment. * This method checks whether a header comment can be defined (i.e. whether * this is the first comment in the loaded file). If this is the case, it is * searched for the latest blanc line. This line will mark the end of the * header comment. The return value is the index of the first line in the * passed in list, which does not belong to the header comment. * * @param commentLines the comment lines * @return the index of the next line after the header comment */ private int checkHeaderComment(List commentLines) { if (loadCounter == 1 && getHeaderComment() == null && layoutData.isEmpty()) { // This is the first comment. Search for blanc lines. int index = commentLines.size() - 1; while (index >= 0 && commentLines.get(index).length() > 0) { index--; } setHeaderComment(extractComment(commentLines, 0, index - 1)); return index + 1; } else { return 0; } } /** * Copies the data from the given layout object. * * @param c the layout object to copy */ private void copyFrom(PropertiesConfigurationLayout c) { for (String key : c.getKeys()) { PropertyLayoutData data = c.layoutData.get(key); layoutData.put(key, data.clone()); } setHeaderComment(c.getHeaderComment()); setFooterComment(c.getFooterComment()); } /** * Helper method for writing a comment line. This method ensures that the * correct line separator is used if the comment spans multiple lines. * * @param writer the writer * @param comment the comment to write * @throws IOException if an IO error occurs */ private static void writeComment( PropertiesConfiguration.PropertiesWriter writer, String comment) throws IOException { if (comment != null) { writer.writeln(StringUtils.replace(comment, CR, writer .getLineSeparator())); } } /** * Helper method for generating a comment string. Depending on the boolean * argument the resulting string either has no comment characters or a * leading comment character at each line. * * @param comment the comment string to be processed * @param commentChar determines the presence of comment characters * @return the canonical comment string (can be null) */ private static String constructCanonicalComment(String comment, boolean commentChar) { return (comment == null) ? null : trimComment(comment, commentChar); } /** * A helper class for storing all layout related information for a * configuration property. */ static class PropertyLayoutData implements Cloneable { /** Stores the comment for the property. */ private StringBuffer comment; /** The separator to be used for this property. */ private String separator; /** Stores the number of blanc lines before this property. */ private int blancLines; /** Stores the single line property. */ private boolean singleLine; /** * Creates a new instance of {@code PropertyLayoutData}. */ public PropertyLayoutData() { singleLine = true; separator = PropertiesConfiguration.DEFAULT_SEPARATOR; } /** * Returns the number of blanc lines before this property. * * @return the number of blanc lines before this property */ public int getBlancLines() { return blancLines; } /** * Sets the number of properties before this property. * * @param blancLines the number of properties before this property */ public void setBlancLines(int blancLines) { this.blancLines = blancLines; } /** * Returns the single line flag. * * @return the single line flag */ public boolean isSingleLine() { return singleLine; } /** * Sets the single line flag. * * @param singleLine the single line flag */ public void setSingleLine(boolean singleLine) { this.singleLine = singleLine; } /** * Adds a comment for this property. If already a comment exists, the * new comment is added (separated by a newline). * * @param s the comment to add */ public void addComment(String s) { if (s != null) { if (comment == null) { comment = new StringBuffer(s); } else { comment.append(CR).append(s); } } } /** * Sets the comment for this property. * * @param s the new comment (can be null) */ public void setComment(String s) { if (s == null) { comment = null; } else { comment = new StringBuffer(s); } } /** * Returns the comment for this property. The comment is returned as it * is, without processing of comment characters. * * @return the comment (can be null) */ public String getComment() { return (comment == null) ? null : comment.toString(); } /** * Returns the separator that was used for this property. * * @return the property separator */ public String getSeparator() { return separator; } /** * Sets the separator to be used for the represented property. * * @param separator the property separator */ public void setSeparator(String separator) { this.separator = separator; } /** * Creates a copy of this object. * * @return the copy */ @Override public PropertyLayoutData clone() { try { PropertyLayoutData copy = (PropertyLayoutData) super.clone(); if (comment != null) { // must copy string buffer, too copy.comment = new StringBuffer(getComment()); } return copy; } catch (CloneNotSupportedException cnex) { // This cannot happen! throw new ConfigurationRuntimeException(cnex); } } } } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PropertyConverter.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/PropertyConverter.java100644 103136 12232154103 33624 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.awt.Color; import java.lang.reflect.Array; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; import java.net.MalformedURLException; import java.net.URL; import java.net.UnknownHostException; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.Date; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Locale; import org.apache.commons.lang.BooleanUtils; import org.apache.commons.lang.StringUtils; /** * A utility class to convert the configuration properties into any type. * * @author Emmanuel Bourg * @version $Id: PropertyConverter.java 1534376 2013-10-21 21:14:18Z henning $ * @since 1.1 */ public final class PropertyConverter { /** Constant for the list delimiter as char.*/ static final char LIST_ESC_CHAR = '\\'; /** Constant for the list delimiter escaping character as string.*/ static final String LIST_ESCAPE = String.valueOf(LIST_ESC_CHAR); /** Constant for the prefix of hex numbers.*/ private static final String HEX_PREFIX = "0x"; /** Constant for the radix of hex numbers.*/ private static final int HEX_RADIX = 16; /** Constant for the prefix of binary numbers.*/ private static final String BIN_PREFIX = "0b"; /** Constant for the radix of binary numbers.*/ private static final int BIN_RADIX = 2; /** Constant for the argument classes of the Number constructor that takes a String. */ private static final Class[] CONSTR_ARGS = {String.class}; /** The fully qualified name of {@link javax.mail.internet.InternetAddress} */ private static final String INTERNET_ADDRESS_CLASSNAME = "javax.mail.internet.InternetAddress"; /** * Private constructor prevents instances from being created. */ private PropertyConverter() { // to prevent instantiation... } /** * Converts the specified value to the target class. If the class is a * primitive type (Integer.TYPE, Boolean.TYPE, etc) the value returned * will use the wrapper type (Integer.class, Boolean.class, etc). * * @param cls the target class of the converted value * @param value the value to convert * @param params optional parameters used for the conversion * @return the converted value * @throws ConversionException if the value is not compatible with the requested type * * @since 1.5 */ static Object to(Class cls, Object value, Object[] params) throws ConversionException { if (cls.isInstance(value)) { return value; // no conversion needed } if (Boolean.class.equals(cls) || Boolean.TYPE.equals(cls)) { return toBoolean(value); } else if (Character.class.equals(cls) || Character.TYPE.equals(cls)) { return toCharacter(value); } else if (Number.class.isAssignableFrom(cls) || cls.isPrimitive()) { if (Integer.class.equals(cls) || Integer.TYPE.equals(cls)) { return toInteger(value); } else if (Long.class.equals(cls) || Long.TYPE.equals(cls)) { return toLong(value); } else if (Byte.class.equals(cls) || Byte.TYPE.equals(cls)) { return toByte(value); } else if (Short.class.equals(cls) || Short.TYPE.equals(cls)) { return toShort(value); } else if (Float.class.equals(cls) || Float.TYPE.equals(cls)) { return toFloat(value); } else if (Double.class.equals(cls) || Double.TYPE.equals(cls)) { return toDouble(value); } else if (BigInteger.class.equals(cls)) { return toBigInteger(value); } else if (BigDecimal.class.equals(cls)) { return toBigDecimal(value); } } else if (Date.class.equals(cls)) { return toDate(value, (String) params[0]); } else if (Calendar.class.equals(cls)) { return toCalendar(value, (String) params[0]); } else if (URL.class.equals(cls)) { return toURL(value); } else if (Locale.class.equals(cls)) { return toLocale(value); } else if (isEnum(cls)) { return convertToEnum(cls, value); } else if (Color.class.equals(cls)) { return toColor(value); } else if (cls.getName().equals(INTERNET_ADDRESS_CLASSNAME)) { return toInternetAddress(value); } else if (InetAddress.class.isAssignableFrom(cls)) { return toInetAddress(value); } throw new ConversionException("The value '" + value + "' (" + value.getClass() + ")" + " can't be converted to a " + cls.getName() + " object"); } /** * Convert the specified object into a Boolean. Internally the * {@code org.apache.commons.lang.BooleanUtils} class from the * Commons Lang * project is used to perform this conversion. This class accepts some more * tokens for the boolean value of true, e.g. {@code yes} and * {@code on}. Please refer to the documentation of this class for more * details. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a boolean */ public static Boolean toBoolean(Object value) throws ConversionException { if (value instanceof Boolean) { return (Boolean) value; } else if (value instanceof String) { Boolean b = BooleanUtils.toBooleanObject((String) value); if (b == null) { throw new ConversionException("The value " + value + " can't be converted to a Boolean object"); } return b; } else { throw new ConversionException("The value " + value + " can't be converted to a Boolean object"); } } /** * Converts the specified value object to a {@code Character}. This method * converts the passed in object to a string. If the string has exactly one * character, this character is returned as result. Otherwise, conversion * fails. * * @param value the value to be converted * @return the resulting {@code Character} object * @throws ConversionException if the conversion is not possible */ public static Character toCharacter(Object value) throws ConversionException { String strValue = String.valueOf(value); if (strValue.length() == 1) { return Character.valueOf(strValue.charAt(0)); } else { throw new ConversionException( String.format( "The value '%s' cannot be converted to a Character object!", strValue)); } } /** * Convert the specified object into a Byte. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a byte */ public static Byte toByte(Object value) throws ConversionException { Number n = toNumber(value, Byte.class); if (n instanceof Byte) { return (Byte) n; } else { return new Byte(n.byteValue()); } } /** * Convert the specified object into a Short. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a short */ public static Short toShort(Object value) throws ConversionException { Number n = toNumber(value, Short.class); if (n instanceof Short) { return (Short) n; } else { return new Short(n.shortValue()); } } /** * Convert the specified object into an Integer. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to an integer */ public static Integer toInteger(Object value) throws ConversionException { Number n = toNumber(value, Integer.class); if (n instanceof Integer) { return (Integer) n; } else { return new Integer(n.intValue()); } } /** * Convert the specified object into a Long. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a Long */ public static Long toLong(Object value) throws ConversionException { Number n = toNumber(value, Long.class); if (n instanceof Long) { return (Long) n; } else { return new Long(n.longValue()); } } /** * Convert the specified object into a Float. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a Float */ public static Float toFloat(Object value) throws ConversionException { Number n = toNumber(value, Float.class); if (n instanceof Float) { return (Float) n; } else { return new Float(n.floatValue()); } } /** * Convert the specified object into a Double. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a Double */ public static Double toDouble(Object value) throws ConversionException { Number n = toNumber(value, Double.class); if (n instanceof Double) { return (Double) n; } else { return new Double(n.doubleValue()); } } /** * Convert the specified object into a BigInteger. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a BigInteger */ public static BigInteger toBigInteger(Object value) throws ConversionException { Number n = toNumber(value, BigInteger.class); if (n instanceof BigInteger) { return (BigInteger) n; } else { return BigInteger.valueOf(n.longValue()); } } /** * Convert the specified object into a BigDecimal. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a BigDecimal */ public static BigDecimal toBigDecimal(Object value) throws ConversionException { Number n = toNumber(value, BigDecimal.class); if (n instanceof BigDecimal) { return (BigDecimal) n; } else { return new BigDecimal(n.doubleValue()); } } /** * Tries to convert the specified object into a number object. This method * is used by the conversion methods for number types. Note that the return * value is not in always of the specified target class, but only if a new * object has to be created. * * @param value the value to be converted (must not be null) * @param targetClass the target class of the conversion (must be derived * from {@code java.lang.Number}) * @return the converted number * @throws ConversionException if the object cannot be converted */ static Number toNumber(Object value, Class targetClass) throws ConversionException { if (value instanceof Number) { return (Number) value; } else { String str = value.toString(); if (str.startsWith(HEX_PREFIX)) { try { return new BigInteger(str.substring(HEX_PREFIX.length()), HEX_RADIX); } catch (NumberFormatException nex) { throw new ConversionException("Could not convert " + str + " to " + targetClass.getName() + "! Invalid hex number.", nex); } } if (str.startsWith(BIN_PREFIX)) { try { return new BigInteger(str.substring(BIN_PREFIX.length()), BIN_RADIX); } catch (NumberFormatException nex) { throw new ConversionException("Could not convert " + str + " to " + targetClass.getName() + "! Invalid binary number.", nex); } } try { Constructor constr = targetClass.getConstructor(CONSTR_ARGS); return (Number) constr.newInstance(new Object[]{str}); } catch (InvocationTargetException itex) { throw new ConversionException("Could not convert " + str + " to " + targetClass.getName(), itex .getTargetException()); } catch (Exception ex) { // Treat all possible exceptions the same way throw new ConversionException( "Conversion error when trying to convert " + str + " to " + targetClass.getName(), ex); } } } /** * Convert the specified object into an URL. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to an URL */ public static URL toURL(Object value) throws ConversionException { if (value instanceof URL) { return (URL) value; } else if (value instanceof String) { try { return new URL((String) value); } catch (MalformedURLException e) { throw new ConversionException("The value " + value + " can't be converted to an URL", e); } } else { throw new ConversionException("The value " + value + " can't be converted to an URL"); } } /** * Convert the specified object into a Locale. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a Locale */ public static Locale toLocale(Object value) throws ConversionException { if (value instanceof Locale) { return (Locale) value; } else if (value instanceof String) { List elements = split((String) value, '_'); int size = elements.size(); if (size >= 1 && ((elements.get(0)).length() == 2 || (elements.get(0)).length() == 0)) { String language = elements.get(0); String country = (size >= 2) ? elements.get(1) : ""; String variant = (size >= 3) ? elements.get(2) : ""; return new Locale(language, country, variant); } else { throw new ConversionException("The value " + value + " can't be converted to a Locale"); } } else { throw new ConversionException("The value " + value + " can't be converted to a Locale"); } } /** * Split a string on the specified delimiter. To be removed when * commons-lang has a better replacement available (Tokenizer?). * * todo: replace with a commons-lang equivalent * * @param s the string to split * @param delimiter the delimiter * @param trim a flag whether the single elements should be trimmed * @return a list with the single tokens */ public static List split(String s, char delimiter, boolean trim) { if (s == null) { return new ArrayList(); } List list = new ArrayList(); StringBuilder token = new StringBuilder(); int begin = 0; boolean inEscape = false; while (begin < s.length()) { char c = s.charAt(begin); if (inEscape) { // last character was the escape marker // can current character be escaped? if (c != delimiter && c != LIST_ESC_CHAR) { // no, also add escape character token.append(LIST_ESC_CHAR); } token.append(c); inEscape = false; } else { if (c == delimiter) { // found a list delimiter -> add token and resetDefaultFileSystem buffer String t = token.toString(); if (trim) { t = t.trim(); } list.add(t); token = new StringBuilder(); } else if (c == LIST_ESC_CHAR) { // eventually escape next character inEscape = true; } else { token.append(c); } } begin++; } // Trailing delimiter? if (inEscape) { token.append(LIST_ESC_CHAR); } // Add last token String t = token.toString(); if (trim) { t = t.trim(); } list.add(t); return list; } /** * Split a string on the specified delimiter always trimming the elements. * This is a shortcut for {@code split(s, delimiter, true)}. * * @param s the string to split * @param delimiter the delimiter * @return a list with the single tokens */ public static List split(String s, char delimiter) { return split(s, delimiter, true); } /** * Escapes the delimiters that might be contained in the given string. This * method works like {@link #escapeListDelimiter(String, char)}. In addition, * a single backslash will also be escaped. * * @param s the string with the value * @param delimiter the list delimiter to use * @return the correctly escaped string */ public static String escapeDelimiters(String s, char delimiter) { String s1 = StringUtils.replace(s, LIST_ESCAPE, LIST_ESCAPE + LIST_ESCAPE); return escapeListDelimiter(s1, delimiter); } /** * Escapes the list delimiter if it is contained in the given string. This * method ensures that list delimiter characters that are part of a * property's value are correctly escaped when a configuration is saved to a * file. Otherwise when loaded again the property will be treated as a list * property. * * @param s the string with the value * @param delimiter the list delimiter to use * @return the escaped string * @since 1.7 */ public static String escapeListDelimiter(String s, char delimiter) { return StringUtils.replace(s, String.valueOf(delimiter), LIST_ESCAPE + delimiter); } /** * Convert the specified object into a Color. If the value is a String, * the format allowed is (#)?[0-9A-F]{6}([0-9A-F]{2})?. Examples: *
    *
  • FF0000 (red)
  • *
  • 0000FFA0 (semi transparent blue)
  • *
  • #CCCCCC (gray)
  • *
  • #00FF00A0 (semi transparent green)
  • *
* * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a Color */ public static Color toColor(Object value) throws ConversionException { if (value instanceof Color) { return (Color) value; } else if (value instanceof String && !StringUtils.isBlank((String) value)) { String color = ((String) value).trim(); int[] components = new int[3]; // check the size of the string int minlength = components.length * 2; if (color.length() < minlength) { throw new ConversionException("The value " + value + " can't be converted to a Color"); } // remove the leading # if (color.startsWith("#")) { color = color.substring(1); } try { // parse the components for (int i = 0; i < components.length; i++) { components[i] = Integer.parseInt(color.substring(2 * i, 2 * i + 2), HEX_RADIX); } // parse the transparency int alpha; if (color.length() >= minlength + 2) { alpha = Integer.parseInt(color.substring(minlength, minlength + 2), HEX_RADIX); } else { alpha = Color.black.getAlpha(); } return new Color(components[0], components[1], components[2], alpha); } catch (Exception e) { throw new ConversionException("The value " + value + " can't be converted to a Color", e); } } else { throw new ConversionException("The value " + value + " can't be converted to a Color"); } } /** * Convert the specified value into an internet address. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a InetAddress * * @since 1.5 */ static InetAddress toInetAddress(Object value) throws ConversionException { if (value instanceof InetAddress) { return (InetAddress) value; } else if (value instanceof String) { try { return InetAddress.getByName((String) value); } catch (UnknownHostException e) { throw new ConversionException("The value " + value + " can't be converted to a InetAddress", e); } } else { throw new ConversionException("The value " + value + " can't be converted to a InetAddress"); } } /** * Convert the specified value into an email address. * * @param value the value to convert * @return the converted value * @throws ConversionException thrown if the value cannot be converted to an email address * * @since 1.5 */ static Object toInternetAddress(Object value) throws ConversionException { if (value.getClass().getName().equals(INTERNET_ADDRESS_CLASSNAME)) { return value; } else if (value instanceof String) { try { Constructor ctor = Class.forName(INTERNET_ADDRESS_CLASSNAME) .getConstructor(new Class[] {String.class}); return ctor.newInstance(new Object[] {value}); } catch (Exception e) { throw new ConversionException("The value " + value + " can't be converted to a InternetAddress", e); } } else { throw new ConversionException("The value " + value + " can't be converted to a InternetAddress"); } } /** * Calls Class.isEnum() on Java 5, returns false on older JRE. */ static boolean isEnum(Class cls) { return cls.isEnum(); } /** * Convert the specified value into a Java 5 enum. * * @param value the value to convert * @param cls the type of the enumeration * @return the converted value * @throws ConversionException thrown if the value cannot be converted to an enumeration * * @since 1.5 */ static > E toEnum(Object value, Class cls) throws ConversionException { if (value.getClass().equals(cls)) { return cls.cast(value); } else if (value instanceof String) { try { return Enum.valueOf(cls, (String) value); } catch (Exception e) { throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName()); } } else if (value instanceof Number) { try { E[] enumConstants = cls.getEnumConstants(); return enumConstants[((Number) value).intValue()]; } catch (Exception e) { throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName()); } } else { throw new ConversionException("The value " + value + " can't be converted to a " + cls.getName()); } } /** * Convert the specified object into a Date. * * @param value the value to convert * @param format the DateFormat pattern to parse String values * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a Calendar */ public static Date toDate(Object value, String format) throws ConversionException { if (value instanceof Date) { return (Date) value; } else if (value instanceof Calendar) { return ((Calendar) value).getTime(); } else if (value instanceof String) { try { return new SimpleDateFormat(format).parse((String) value); } catch (ParseException e) { throw new ConversionException("The value " + value + " can't be converted to a Date", e); } } else { throw new ConversionException("The value " + value + " can't be converted to a Date"); } } /** * Convert the specified object into a Calendar. * * @param value the value to convert * @param format the DateFormat pattern to parse String values * @return the converted value * @throws ConversionException thrown if the value cannot be converted to a Calendar */ public static Calendar toCalendar(Object value, String format) throws ConversionException { if (value instanceof Calendar) { return (Calendar) value; } else if (value instanceof Date) { Calendar calendar = Calendar.getInstance(); calendar.setTime((Date) value); return calendar; } else if (value instanceof String) { try { Calendar calendar = Calendar.getInstance(); calendar.setTime(new SimpleDateFormat(format).parse((String) value)); return calendar; } catch (ParseException e) { throw new ConversionException("The value " + value + " can't be converted to a Calendar", e); } } else { throw new ConversionException("The value " + value + " can't be converted to a Calendar"); } } /** * Returns an iterator over the simple values of a composite value. This * implementation calls {@link #flatten(Object, char)} and * returns an iterator over the returned collection. * * @param value the value to "split" * @param delimiter the delimiter for String values * @return an iterator for accessing the single values */ public static Iterator toIterator(Object value, char delimiter) { return flatten(value, delimiter).iterator(); } /** * Returns a collection with all values contained in the specified object. * This method is used for instance by the {@code addProperty()} * implementation of the default configurations to gather all values of the * property to add. Depending on the type of the passed in object the * following things happen: *
    *
  • Strings are checked for delimiter characters and split if necessary.
  • *
  • For objects implementing the {@code Iterable} interface, the * corresponding {@code Iterator} is obtained, and contained elements * are added to the resulting collection.
  • *
  • Arrays are treated as {@code Iterable} objects.
  • *
  • All other types are directly inserted.
  • *
  • Recursive combinations are supported, e.g. a collection containing * an array that contains strings: The resulting collection will only * contain primitive objects (hence the name "flatten").
  • *
* * @param value the value to be processed * @param delimiter the delimiter for String values * @return a "flat" collection containing all primitive values of * the passed in object */ private static Collection flatten(Object value, char delimiter) { if (value instanceof String) { String s = (String) value; if (s.indexOf(delimiter) > 0) { return split(s, delimiter); } } Collection result = new LinkedList(); if (value instanceof Iterable) { flattenIterator(result, ((Iterable) value).iterator(), delimiter); } else if (value instanceof Iterator) { flattenIterator(result, (Iterator) value, delimiter); } else if (value != null) { if (value.getClass().isArray()) { for (int len = Array.getLength(value), idx = 0; idx < len; idx++) { result.addAll(flatten(Array.get(value, idx), delimiter)); } } else { result.add(value); } } return result; } /** * Flattens the given iterator. For each element in the iteration * {@code flatten()} will be called recursively. * * @param target the target collection * @param it the iterator to process * @param delimiter the delimiter for String values */ private static void flattenIterator(Collection target, Iterator it, char delimiter) { while (it.hasNext()) { target.addAll(flatten(it.next(), delimiter)); } } /** * Performs interpolation of the specified value. This method checks if the * given value contains variables of the form ${...}. If * this is the case, all occurrences will be substituted by their current * values. * * @param value the value to be interpolated * @param config the current configuration object * @return the interpolated value */ public static Object interpolate(Object value, AbstractConfiguration config) { if (value instanceof String) { return config.getSubstitutor().replace((String) value); } else { return value; } } /** * Helper method for converting a value to a constant of an enumeration * class. * * @param enumClass the enumeration class * @param value the value to be converted * @return the converted value */ @SuppressWarnings("unchecked") // conversion is safe because we know that the class is an Enum class private static Object convertToEnum(Class enumClass, Object value) { return toEnum(value, enumClass.asSubclass(Enum.class)); } } ././@LongLink100644 0 0 172 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/FileChangedReloadingStrategy.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/FileChangedR100644 15102 12232154102 33361 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import org.apache.commons.configuration.ConfigurationUtils; import org.apache.commons.configuration.FileConfiguration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** *

A reloading strategy that will reload the configuration every time its * underlying file is changed.

*

This reloading strategy does not actively monitor a configuration file, * but is triggered by its associated configuration whenever properties are * accessed. It then checks the configuration file's last modification date * and causes a reload if this has changed.

*

To avoid permanent disc access on successive property lookups a refresh * delay can be specified. This has the effect that the configuration file's * last modification date is only checked once in this delay period. The default * value for this refresh delay is 5 seconds.

*

This strategy only works with FileConfiguration instances.

* * @author Emmanuel Bourg * @version $Id: FileChangedReloadingStrategy.java 1210646 2011-12-05 21:25:01Z oheger $ * @since 1.1 */ public class FileChangedReloadingStrategy implements ReloadingStrategy { /** Constant for the jar URL protocol.*/ private static final String JAR_PROTOCOL = "jar"; /** Constant for the default refresh delay.*/ private static final int DEFAULT_REFRESH_DELAY = 5000; /** Stores a reference to the configuration to be monitored.*/ protected FileConfiguration configuration; /** The last time the configuration file was modified. */ protected long lastModified; /** The last time the file was checked for changes. */ protected long lastChecked; /** The minimum delay in milliseconds between checks. */ protected long refreshDelay = DEFAULT_REFRESH_DELAY; /** A flag whether a reload is required.*/ private boolean reloading; /** The Log to use for diagnostic messages */ private Log logger = LogFactory.getLog(FileChangedReloadingStrategy.class); public void setConfiguration(FileConfiguration configuration) { this.configuration = configuration; } public void init() { updateLastModified(); } public boolean reloadingRequired() { if (!reloading) { long now = System.currentTimeMillis(); if (now > lastChecked + refreshDelay) { lastChecked = now; if (hasChanged()) { if (logger.isDebugEnabled()) { logger.debug("File change detected: " + getName()); } reloading = true; } } } return reloading; } public void reloadingPerformed() { updateLastModified(); } /** * Return the minimal time in milliseconds between two reloadings. * * @return the refresh delay (in milliseconds) */ public long getRefreshDelay() { return refreshDelay; } /** * Set the minimal time between two reloadings. * * @param refreshDelay refresh delay in milliseconds */ public void setRefreshDelay(long refreshDelay) { this.refreshDelay = refreshDelay; } /** * Update the last modified time. */ protected void updateLastModified() { File file = getFile(); if (file != null) { lastModified = file.lastModified(); } reloading = false; } /** * Check if the configuration has changed since the last time it was loaded. * * @return a flag whether the configuration has changed */ protected boolean hasChanged() { File file = getFile(); if (file == null || !file.exists()) { if (logger.isWarnEnabled() && lastModified != 0) { logger.warn("File was deleted: " + getName(file)); lastModified = 0; } return false; } return file.lastModified() > lastModified; } /** * Returns the file that is monitored by this strategy. Note that the return * value can be null under some circumstances. * * @return the monitored file */ protected File getFile() { return (configuration.getURL() != null) ? fileFromURL(configuration .getURL()) : configuration.getFile(); } /** * Helper method for transforming a URL into a file object. This method * handles file: and jar: URLs. * * @param url the URL to be converted * @return the resulting file or null */ private File fileFromURL(URL url) { if (JAR_PROTOCOL.equals(url.getProtocol())) { String path = url.getPath(); try { return ConfigurationUtils.fileFromURL(new URL(path.substring(0, path.indexOf('!')))); } catch (MalformedURLException mex) { return null; } } else { return ConfigurationUtils.fileFromURL(url); } } private String getName() { return getName(getFile()); } private String getName(File file) { String name = configuration.getURL().toString(); if (name == null) { if (file != null) { name = file.getAbsolutePath(); } else { name = "base: " + configuration.getBasePath() + "file: " + configuration.getFileName(); } } return name; } } ././@LongLink100644 0 0 170 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/InvariantReloadingStrategy.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/InvariantRel100644 2604 12232154102 33467 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import org.apache.commons.configuration.FileConfiguration; /** * A strategy that never triggers a reloading. * * @author Emmanuel Bourg * @version $Id: InvariantReloadingStrategy.java 1210646 2011-12-05 21:25:01Z oheger $ * @since 1.1 */ public class InvariantReloadingStrategy implements ReloadingStrategy { public void setConfiguration(FileConfiguration configuration) { } public void init() { } public boolean reloadingRequired() { return false; } public void reloadingPerformed() { } } ././@LongLink100644 0 0 166 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/ManagedReloadingStrategy.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/ManagedReloa100644 6031 12232154102 33406 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import org.apache.commons.configuration.FileConfiguration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A strategy to reload configuration based on management requests. Designed for * JMX management. * * @author Nicolas De loof * @version $Id: ManagedReloadingStrategy.java 1210646 2011-12-05 21:25:01Z oheger $ */ public class ManagedReloadingStrategy implements ReloadingStrategy, ManagedReloadingStrategyMBean { /** The logger. */ private Log log = LogFactory.getLog(ManagedReloadingStrategy.class); /** Stores a reference to the associated configuration. */ private FileConfiguration configuration; /** A flag whether a reload is required. */ private boolean reloadingRequired; /** * @see org.apache.commons.configuration.reloading.ReloadingStrategy#init() */ public void init() { } /** * @see org.apache.commons.configuration.reloading.ReloadingStrategy#reloadingPerformed() */ public void reloadingPerformed() { reloadingRequired = false; } /** * Checks whether reloading is required. This implementation checks whether * the {@code refresh()} method has been invoked. * * @return a flag whether reloading is required * @see org.apache.commons.configuration.reloading.ReloadingStrategy#reloadingRequired() */ public boolean reloadingRequired() { return reloadingRequired; } /** * Sets the associated configuration. * * @param configuration the associated configuration */ public void setConfiguration(FileConfiguration configuration) { this.configuration = configuration; } /** * Tells this strategy that the monitored configuration file should be * refreshed. This method will typically be called from outside (through an * exposed MBean) on behalf of an administrator. * * @see org.apache.commons.configuration.reloading.ManagedReloadingStrategyMBean#refresh() */ public void refresh() { log.info("Reloading configuration."); this.reloadingRequired = true; // force reloading configuration.isEmpty(); } } ././@LongLink100644 0 0 173 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/ManagedReloadingStrategyMBean.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/ManagedReloa100644 2236 12232154102 33411 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; /** * MBean definition for managing configuration reload. * * @author Nicolas De Loof * @version $Id: ManagedReloadingStrategyMBean.java 1210646 2011-12-05 21:25:01Z oheger $ */ public interface ManagedReloadingStrategyMBean { /** * Management method to force configuration reload. */ void refresh(); } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/package.htmlcommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/package.html100644 2345 12232154102 33431 0ustarhenningstaff 0 0

The reloading package contains the definition of the ReloadingStrategy interface, which provides automatic reloading facilities for file based configurations. There are also some concrete implementations of this interface that can be used out of the box.

$Id: package.html 439648 2006-09-02 20:42:10Z oheger $

././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/Reloadable.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/Reloadable.j100644 2272 12232154102 33354 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; /** * Interface that allows other objects to synchronize on a root lock. * * @author Commons * Configuration team * @since 1.7 * @version $Id: Reloadable.java 1162387 2011-08-27 16:05:20Z oheger $ */ public interface Reloadable { Object getReloadLock(); } ././@LongLink100644 0 0 157 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/ReloadingStrategy.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/ReloadingStr100644 3265 12232154102 33472 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import org.apache.commons.configuration.FileConfiguration; /** * A strategy to decide if a configuration should be reloaded. * * @author Emmanuel Bourg * @version $Id: ReloadingStrategy.java 1210646 2011-12-05 21:25:01Z oheger $ * @since 1.1 */ public interface ReloadingStrategy { /** * Set the configuration managed by this strategy. * * @param configuration the configuration to monitor */ void setConfiguration(FileConfiguration configuration); /** * Initialize the strategy. */ void init(); /** * Tell if the evaluation of the strategy requires to reload the configuration. * * @return a flag whether a reload should be performed */ boolean reloadingRequired(); /** * Notify the strategy that the file has been reloaded. */ void reloadingPerformed(); } ././@LongLink100644 0 0 175 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/VFSFileChangedReloadingStrategy.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/VFSFileChang100644 14325 12232154102 33313 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import org.apache.commons.configuration.ConfigurationRuntimeException; import org.apache.commons.configuration.FileConfiguration; import org.apache.commons.configuration.FileSystem; import org.apache.commons.configuration.FileSystemBased; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.vfs2.FileObject; import org.apache.commons.vfs2.FileSystemException; import org.apache.commons.vfs2.FileSystemManager; import org.apache.commons.vfs2.VFS; /** *

* A file-based reloading strategy that uses Commons VFS to determine when a * file was changed. *

*

* This reloading strategy is very similar to * {@link FileChangedReloadingStrategy}, except for the fact that it uses VFS * and thus can deal with a variety of different configuration sources. *

*

* This strategy only works with FileConfiguration instances. *

* * @author Commons * Configuration team * @version $Id: VFSFileChangedReloadingStrategy.java 1162383 2011-08-27 15:57:11Z oheger $ * @since 1.7 */ public class VFSFileChangedReloadingStrategy implements ReloadingStrategy { /** Constant for the default refresh delay.*/ private static final int DEFAULT_REFRESH_DELAY = 5000; /** Stores a reference to the configuration to be monitored.*/ protected FileConfiguration configuration; /** The last time the configuration file was modified. */ protected long lastModified; /** The last time the file was checked for changes. */ protected long lastChecked; /** The minimum delay in milliseconds between checks. */ protected long refreshDelay = DEFAULT_REFRESH_DELAY; /** A flag whether a reload is required.*/ private boolean reloading; /** Stores the logger.*/ private Log log = LogFactory.getLog(getClass()); public void setConfiguration(FileConfiguration configuration) { this.configuration = configuration; } public void init() { if (configuration.getURL() == null && configuration.getFileName() == null) { return; } if (this.configuration == null) { throw new IllegalStateException("No configuration has been set for this strategy"); } updateLastModified(); } public boolean reloadingRequired() { if (!reloading) { long now = System.currentTimeMillis(); if (now > lastChecked + refreshDelay) { lastChecked = now; if (hasChanged()) { reloading = true; } } } return reloading; } public void reloadingPerformed() { updateLastModified(); } /** * Return the minimal time in milliseconds between two reloadings. * * @return the refresh delay (in milliseconds) */ public long getRefreshDelay() { return refreshDelay; } /** * Set the minimal time between two reloadings. * * @param refreshDelay refresh delay in milliseconds */ public void setRefreshDelay(long refreshDelay) { this.refreshDelay = refreshDelay; } /** * Update the last modified time. */ protected void updateLastModified() { FileObject file = getFile(); if (file != null) { try { lastModified = file.getContent().getLastModifiedTime(); } catch (FileSystemException fse) { log.error("Unable to get last modified time for" + file.getName().getURI()); } } reloading = false; } /** * Check if the configuration has changed since the last time it was loaded. * * @return a flag whether the configuration has changed */ protected boolean hasChanged() { FileObject file = getFile(); try { if (file == null || !file.exists()) { return false; } return file.getContent().getLastModifiedTime() > lastModified; } catch (FileSystemException ex) { log.error("Unable to get last modified time for" + file.getName().getURI()); return false; } } /** * Returns the file that is monitored by this strategy. Note that the return * value can be null under some circumstances. * * @return the monitored file */ protected FileObject getFile() { try { FileSystemManager fsManager = VFS.getManager(); FileSystem fs = ((FileSystemBased) configuration).getFileSystem(); String uri = fs.getPath(null, configuration.getURL(), configuration.getBasePath(), configuration.getFileName()); if (uri == null) { throw new ConfigurationRuntimeException("Unable to determine file to monitor"); } return fsManager.resolveFile(uri); } catch (FileSystemException fse) { String msg = "Unable to monitor " + configuration.getURL().toString(); log.error(msg); throw new ConfigurationRuntimeException(msg, fse); } } } ././@LongLink100644 0 0 154 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/CatalogResolver.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/CatalogResolv100644 37753 12232154102 33570 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.resolver; import java.io.IOException; import java.io.InputStream; import java.net.FileNameMap; import java.net.URL; import java.net.URLConnection; import java.util.Vector; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.ConfigurationUtils; import org.apache.commons.configuration.FileSystem; import org.apache.commons.lang.text.StrSubstitutor; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xml.resolver.CatalogException; import org.apache.xml.resolver.readers.CatalogReader; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * Thin wrapper around xml commons CatalogResolver to allow list of catalogs * to be provided. * @author Commons * Configuration team * @since 1.7 * @version $Id: CatalogResolver.java 1301991 2012-03-17 20:18:02Z sebb $ */ public class CatalogResolver implements EntityResolver { /** * Debug everything. */ private static final int DEBUG_ALL = 9; /** * Normal debug setting. */ private static final int DEBUG_NORMAL = 4; /** * Debug nothing. */ private static final int DEBUG_NONE = 0; /** * The CatalogManager */ protected CatalogManager manager = new CatalogManager(); /** * The FileSystem in use. */ protected FileSystem fs = FileSystem.getDefaultFileSystem(); /** * The CatalogResolver */ private org.apache.xml.resolver.tools.CatalogResolver resolver; /** * Stores the logger. */ private Log log; /** * Constructs the CatalogResolver */ public CatalogResolver() { manager.setIgnoreMissingProperties(true); manager.setUseStaticCatalog(false); manager.setFileSystem(fs); setLogger(null); } /** * Set the list of catalog file names * * @param catalogs The delimited list of catalog files. */ public void setCatalogFiles(String catalogs) { manager.setCatalogFiles(catalogs); } /** * Set the FileSystem. * @param fileSystem The FileSystem. */ public void setFileSystem(FileSystem fileSystem) { this.fs = fileSystem; manager.setFileSystem(fileSystem); } /** * Set the base path. * @param baseDir The base path String. */ public void setBaseDir(String baseDir) { manager.setBaseDir(baseDir); } /** * Set the StrSubstitutor. * @param substitutor The StrSubstitutor. */ public void setSubstitutor(StrSubstitutor substitutor) { manager.setSubstitutor(substitutor); } /** * Enables debug logging of xml-commons Catalog processing. * @param debug True if debugging should be enabled, false otherwise. */ public void setDebug(boolean debug) { if (debug) { manager.setVerbosity(DEBUG_ALL); } else { manager.setVerbosity(DEBUG_NONE); } } /** * Implements the {@code resolveEntity} method * for the SAX interface. *

*

Presented with an optional public identifier and a system * identifier, this function attempts to locate a mapping in the * catalogs.

*

*

If such a mapping is found, the resolver attempts to open * the mapped value as an InputSource and return it. Exceptions are * ignored and null is returned if the mapped value cannot be opened * as an input source.

*

*

If no mapping is found (or an error occurs attempting to open * the mapped value as an input source), null is returned and the system * will use the specified system identifier as if no entityResolver * was specified.

* * @param publicId The public identifier for the entity in question. * This may be null. * @param systemId The system identifier for the entity in question. * XML requires a system identifier on all external entities, so this * value is always specified. * @return An InputSource for the mapped identifier, or null. * @throws SAXException if an error occurs. */ public InputSource resolveEntity(String publicId, String systemId) throws SAXException { String resolved = getResolver().getResolvedEntity(publicId, systemId); if (resolved != null) { String badFilePrefix = "file://"; String correctFilePrefix = "file:///"; // Java 5 has a bug when constructing file URLS if (resolved.startsWith(badFilePrefix) && !resolved.startsWith(correctFilePrefix)) { resolved = correctFilePrefix + resolved.substring(badFilePrefix.length()); } try { InputStream is = fs.getInputStream(null, resolved); InputSource iSource = new InputSource(resolved); iSource.setPublicId(publicId); iSource.setByteStream(is); return iSource; } catch (Exception e) { log.warn("Failed to create InputSource for " + resolved + " (" + e.toString() + ")"); return null; } } return null; } /** * Returns the logger used by this configuration object. * * @return the logger */ public Log getLogger() { return log; } /** * Allows to set the logger to be used by this configuration object. This * method makes it possible for clients to exactly control logging behavior. * Per default a logger is set that will ignore all log messages. Derived * classes that want to enable logging should call this method during their * initialization with the logger to be used. * * @param log the new logger */ public void setLogger(Log log) { this.log = (log != null) ? log : LogFactory.getLog(CatalogResolver.class); } private synchronized org.apache.xml.resolver.tools.CatalogResolver getResolver() { if (resolver == null) { resolver = new org.apache.xml.resolver.tools.CatalogResolver(manager); } return resolver; } /** * Extend the CatalogManager to make the FileSystem and base directory accessible. */ public static class CatalogManager extends org.apache.xml.resolver.CatalogManager { /** The static catalog used by this manager. */ private static org.apache.xml.resolver.Catalog staticCatalog; /** The FileSystem */ private FileSystem fs; /** The base directory */ private String baseDir = System.getProperty("user.dir"); /** The String Substitutor */ private StrSubstitutor substitutor; /** * Set the FileSystem * @param fileSystem The FileSystem in use. */ public void setFileSystem(FileSystem fileSystem) { this.fs = fileSystem; } /** * Retrieve the FileSystem. * @return The FileSystem. */ public FileSystem getFileSystem() { return this.fs; } /** * Set the base directory. * @param baseDir The base directory. */ public void setBaseDir(String baseDir) { if (baseDir != null) { this.baseDir = baseDir; } } /** * Return the base directory. * @return The base directory. */ public String getBaseDir() { return this.baseDir; } public void setSubstitutor(StrSubstitutor substitutor) { this.substitutor = substitutor; } public StrSubstitutor getStrSubstitutor() { return this.substitutor; } /** * Get a new catalog instance. This method is only overridden because xml-resolver * might be in a parent ClassLoader and will be incapable of loading our Catalog * implementation. * * This method always returns a new instance of the underlying catalog class. * @return the Catalog. */ @Override public org.apache.xml.resolver.Catalog getPrivateCatalog() { org.apache.xml.resolver.Catalog catalog = staticCatalog; if (catalog == null || !getUseStaticCatalog()) { try { catalog = new Catalog(); catalog.setCatalogManager(this); catalog.setupReaders(); catalog.loadSystemCatalogs(); } catch (Exception ex) { ex.printStackTrace(); } if (getUseStaticCatalog()) { staticCatalog = catalog; } } return catalog; } /** * Get a catalog instance. * * If this manager uses static catalogs, the same static catalog will * always be returned. Otherwise a new catalog will be returned. * @return The Catalog. */ @Override public org.apache.xml.resolver.Catalog getCatalog() { return getPrivateCatalog(); } } /** * Overrides the Catalog implementation to use the underlying FileSystem. */ public static class Catalog extends org.apache.xml.resolver.Catalog { /** The FileSystem */ private FileSystem fs; /** FileNameMap to determine the mime type */ private FileNameMap fileNameMap = URLConnection.getFileNameMap(); /** * Load the catalogs. * @throws IOException if an error occurs. */ @Override public void loadSystemCatalogs() throws IOException { fs = ((CatalogManager) catalogManager).getFileSystem(); String base = ((CatalogManager) catalogManager).getBaseDir(); // This is safe because the catalog manager returns a vector of strings. @SuppressWarnings("unchecked") Vector catalogs = catalogManager.getCatalogFiles(); if (catalogs != null) { for (int count = 0; count < catalogs.size(); count++) { String fileName = catalogs.elementAt(count); URL url = null; InputStream is = null; try { url = ConfigurationUtils.locate(fs, base, fileName); if (url != null) { is = fs.getInputStream(url); } } catch (ConfigurationException ce) { String name = (url == null) ? fileName : url.toString(); // Ignore the exception. catalogManager.debug.message(DEBUG_ALL, "Unable to get input stream for " + name + ". " + ce.getMessage()); } if (is != null) { String mimeType = fileNameMap.getContentTypeFor(fileName); try { if (mimeType != null) { parseCatalog(mimeType, is); continue; } } catch (Exception ex) { // Ignore the exception. catalogManager.debug.message(DEBUG_ALL, "Exception caught parsing input stream for " + fileName + ". " + ex.getMessage()); } finally { is.close(); } } parseCatalog(base, fileName); } } } /** * Parse the specified catalog file. * @param baseDir The base directory, if not included in the file name. * @param fileName The catalog file. May be a full URI String. * @throws IOException If an error occurs. */ public void parseCatalog(String baseDir, String fileName) throws IOException { base = ConfigurationUtils.locate(fs, baseDir, fileName); catalogCwd = base; default_override = catalogManager.getPreferPublic(); catalogManager.debug.message(DEBUG_NORMAL, "Parse catalog: " + fileName); boolean parsed = false; for (int count = 0; !parsed && count < readerArr.size(); count++) { CatalogReader reader = (CatalogReader) readerArr.get(count); InputStream inStream; try { inStream = fs.getInputStream(base); } catch (Exception ex) { catalogManager.debug.message(DEBUG_NORMAL, "Unable to access " + base + ex.getMessage()); break; } try { reader.readCatalog(this, inStream); parsed = true; } catch (CatalogException ce) { catalogManager.debug.message(DEBUG_NORMAL, "Parse failed for " + fileName + ce.getMessage()); if (ce.getExceptionType() == CatalogException.PARSE_FAILED) { break; } else { // try again! continue; } } finally { try { inStream.close(); } catch (IOException ioe) { // Ignore the exception. inStream = null; } } } if (parsed) { parsePendingCatalogs(); } } /** * Perform character normalization on a URI reference. * * @param uriref The URI reference * @return The normalized URI reference. */ @Override protected String normalizeURI(String uriref) { StrSubstitutor substitutor = ((CatalogManager) catalogManager).getStrSubstitutor(); String resolved = substitutor != null ? substitutor.replace(uriref) : uriref; return super.normalizeURI(resolved); } } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/DefaultEntityResolver.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/DefaultEntity100644 11601 12232154102 33564 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.resolver; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.net.URLConnection; import java.util.HashMap; import java.util.Map; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; /** * The DefaultEntityResolver used by XML Configurations. * @author Commons * Configuration team * @since 1.7 * @version $Id: DefaultEntityResolver.java 1301991 2012-03-17 20:18:02Z sebb $ */ public class DefaultEntityResolver implements EntityResolver, EntityRegistry { /** Stores a map with the registered public IDs.*/ private Map registeredEntities = new HashMap(); /** *

* Registers the specified URL for the specified public identifier. *

*

* This implementation maps {@code PUBLICID}'s to URLs (from which * the resource will be loaded). A common use case for this method is to * register local URLs (possibly computed at runtime by a class loader) for * DTDs and Schemas. This allows the performance advantage of using a local * version without having to ensure every {@code SYSTEM} URI on every * processed XML document is local. This implementation provides only basic * functionality. If more sophisticated features are required, either calling * {@code XMLConfiguration.setDocumentBuilder(DocumentBuilder)} to set a custom * {@code DocumentBuilder} (which also can be initialized with a * custom {@code EntityResolver}) or creating a custom entity resolver * and registering it with the XMLConfiguration is recommended. *

* * @param publicId Public identifier of the Entity to be resolved * @param entityURL The URL to use for reading this Entity * @throws IllegalArgumentException if the public ID is undefined */ public void registerEntityId(String publicId, URL entityURL) { if (publicId == null) { throw new IllegalArgumentException("Public ID must not be null!"); } getRegisteredEntities().put(publicId, entityURL); } /** * Resolves the requested external entity. This is the default * implementation of the {@code EntityResolver} interface. It checks * the passed in public ID against the registered entity IDs and uses a * local URL if possible. * * @param publicId the public identifier of the entity being referenced * @param systemId the system identifier of the entity being referenced * @return an input source for the specified entity * @throws org.xml.sax.SAXException if a parsing exception occurs */ public InputSource resolveEntity(String publicId, String systemId) throws SAXException { // Has this system identifier been registered? URL entityURL = null; if (publicId != null) { entityURL = getRegisteredEntities().get(publicId); } if (entityURL != null) { // Obtain an InputSource for this URL. This code is based on the // createInputSourceFromURL() method of Commons Digester. try { URLConnection connection = entityURL.openConnection(); connection.setUseCaches(false); InputStream stream = connection.getInputStream(); InputSource source = new InputSource(stream); source.setSystemId(entityURL.toExternalForm()); return source; } catch (IOException e) { throw new SAXException(e); } } else { // default processing behavior return null; } } /** * Returns a map with the entity IDs that have been registered using the * {@code registerEntityId()} method. * * @return a map with the registered entity IDs */ public Map getRegisteredEntities() { return registeredEntities; } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/EntityRegistry.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/EntityRegistr100644 5217 12232154102 33605 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.resolver; import java.net.URL; import java.util.Map; /** * Interface used for registering and retrieving PUBLICID to URL mappings. * @author Commons * Configuration team * @since 1.7 * @version $Id: EntityRegistry.java 1206577 2011-11-26 20:25:52Z oheger $ */ public interface EntityRegistry { /** *

* Registers the specified URL for the specified public identifier. *

*

* This implementation maps {@code PUBLICID}'s to URLs (from which * the resource will be loaded). A common use case for this method is to * register local URLs (possibly computed at runtime by a class loader) for * DTDs and Schemas. This allows the performance advantage of using a local * version without having to ensure every {@code SYSTEM} URI on every * processed XML document is local. This implementation provides only basic * functionality. If more sophisticated features are required, either calling * {@code XMLConfiguration.setDocumentBuilder(DocumentBuilder)} to set a custom * {@code DocumentBuilder} (which also can be initialized with a * custom {@code EntityResolver}) or creating a custom entity resolver * and registering it with the XMLConfiguration is recommended. *

* * @param publicId Public identifier of the Entity to be resolved * @param entityURL The URL to use for reading this Entity * @throws IllegalArgumentException if the public ID is undefined */ void registerEntityId(String publicId, URL entityURL); /** * Returns a map with the entity IDs that have been registered using the * {@code registerEntityId()} method. * * @return a map with the registered entity IDs */ Map getRegisteredEntities(); } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/EntityResolverSupport.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/EntityResolve100644 3000 12232154102 33571 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.resolver; import org.xml.sax.EntityResolver; /** * Interface that identifies the class as using an EntityResolver * @author Commons * Configuration team * @since 1.7 * @version $Id: EntityResolverSupport.java 1206761 2011-11-27 16:35:34Z oheger $ */ public interface EntityResolverSupport { /** * Return the EntityResolver associated with the class. * @return The EntityResolver. */ EntityResolver getEntityResolver(); /** * Set the EntityResolver to associate with this class. * @param resolver The EntityResolver */ void setEntityResolver(EntityResolver resolver); } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/package.html100644 1762 12232154102 33330 0ustarhenningstaff 0 0

A package containing EntityResolvers.

$Id: package.html 1162380 2011-08-27 15:49:26Z oheger $

././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/StrictConfigurationComparator.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/StrictConfigurationCom100644 4742 12232154103 33572 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Iterator; /** * Strict comparator for configurations. * * @since 1.0 * * @author Herve Quiroz * @author Yoav Shapira * @version $Id: StrictConfigurationComparator.java 1210177 2011-12-04 18:58:19Z oheger $ */ public class StrictConfigurationComparator implements ConfigurationComparator { /** * Create a new strict comparator. */ public StrictConfigurationComparator() { } /** * Compare two configuration objects. * * @param a the first configuration * @param b the second configuration * @return true if keys from a are found in b and keys from b are * found in a and for each key in a, the corresponding value * is the sale in for the same key in b */ public boolean compare(Configuration a, Configuration b) { if (a == null && b == null) { return true; } else if (a == null || b == null) { return false; } for (Iterator keys = a.getKeys(); keys.hasNext();) { String key = keys.next(); Object value = a.getProperty(key); if (!value.equals(b.getProperty(key))) { return false; } } for (Iterator keys = b.getKeys(); keys.hasNext();) { String key = keys.next(); Object value = b.getProperty(key); if (!value.equals(a.getProperty(key))) { return false; } } return true; } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/SubnodeConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/SubnodeConfiguration.j100644 34036 12232154103 33531 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; import org.apache.commons.configuration.reloading.Reloadable; import org.apache.commons.configuration.tree.ConfigurationNode; /** *

* A specialized hierarchical configuration class that wraps a single node of * its parent configuration. *

*

* Configurations of this type are initialized with a parent configuration and a * configuration node of this configuration. This node becomes the root node of * the subnode configuration. All property accessor methods are evaluated * relative to this root node. A good use case for a * {@code SubnodeConfiguration} is when multiple properties from a * specific sub tree of the whole configuration need to be accessed. Then a * {@code SubnodeConfiguration} can be created with the parent node of * the affected sub tree as root node. This allows for simpler property keys and * is also more efficient. *

*

* A subnode configuration and its parent configuration operate on the same * hierarchy of configuration nodes. So if modifications are performed at the * subnode configuration, these changes are immediately visible in the parent * configuration. Analogously will updates of the parent configuration affect * the subnode configuration if the sub tree spanned by the subnode * configuration's root node is involved. *

*

* There are however changes at the parent configuration, which cause the * subnode configuration to become detached. An example for such a change is a * reload operation of a file-based configuration, which replaces all nodes of * the parent configuration. The subnode configuration per default still * references the old nodes. Another example are list structures: a subnode * configuration can be created to point on the ith element of the * list. Now list elements can be added or removed, so that the list elements' * indices change. In such a scenario the subnode configuration would always * point to the same list element, regardless of its current index. *

*

* To solve these problems and make a subnode configuration aware of * such structural changes of its parent, it is possible to associate a * subnode configuration with a configuration key. This can be done by calling * the {@code setSubnodeKey()} method. If here a key is set, the subnode * configuration will evaluate it on each access, thus ensuring that it is * always in sync with its parent. In this mode the subnode configuration really * behaves like a live-view on its parent. The price for this is a decreased * performance because now an additional evaluation has to be performed on each * property access. So this mode should only be used if necessary; if for * instance a subnode configuration is only used for a temporary convenient * access to a complex configuration, there is no need to make it aware for * structural changes of its parent. If a subnode configuration is created * using the {@link HierarchicalConfiguration#configurationAt(String, boolean) * configurationAt()} method of {@code HierarchicalConfiguration} * (which should be the preferred way), with an additional boolean parameter it * can be specified whether the resulting subnode configuration should be * aware of structural changes or not. Then the configuration key will be * automatically set. *

*

* Note: At the moment support for creating a subnode configuration * that is aware of structural changes of its parent from another subnode * configuration (a "sub subnode configuration") is limited. This only works if *

  1. the subnode configuration that serves as the parent for the new * subnode configuration is itself associated with a configuration key and
  2. *
  3. the key passed in to create the new subnode configuration is not too * complex (if configuration keys are used that contain indices, a corresponding * key that is valid from the parent configuration's point of view cannot be * constructed).
*

*

* When a subnode configuration is created, it inherits the settings of its * parent configuration, e.g. some flags like the * {@code throwExceptionOnMissing} flag or the settings for handling list * delimiters) or the expression engine. If these settings are changed later in * either the subnode or the parent configuration, the changes are not visible * for each other. So you could create a subnode configuration, change its * expression engine without affecting the parent configuration. *

*

* From its purpose this class is quite similar to * {@link SubsetConfiguration}. The difference is that a subset * configuration of a hierarchical configuration may combine multiple * configuration nodes from different sub trees of the configuration, while all * nodes in a subnode configuration belong to the same sub tree. If an * application can live with this limitation, it is recommended to use this * class instead of {@code SubsetConfiguration} because creating a subset * configuration is more expensive than creating a subnode configuration. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: SubnodeConfiguration.java 1210178 2011-12-04 18:58:51Z oheger $ */ public class SubnodeConfiguration extends HierarchicalReloadableConfiguration { /** * The serial version UID. */ private static final long serialVersionUID = 3105734147019386480L; /** Stores the parent configuration. */ private HierarchicalConfiguration parent; /** Stores the key that was used to construct this configuration.*/ private String subnodeKey; /** * Creates a new instance of {@code SubnodeConfiguration} and * initializes it with the parent configuration and the new root node. * * @param parent the parent configuration * @param root the root node of this subnode configuration */ public SubnodeConfiguration(HierarchicalConfiguration parent, ConfigurationNode root) { super(parent instanceof Reloadable ? ((Reloadable) parent).getReloadLock() : null); if (parent == null) { throw new IllegalArgumentException( "Parent configuration must not be null!"); } if (root == null) { throw new IllegalArgumentException("Root node must not be null!"); } setRootNode(root); this.parent = parent; initFromParent(parent); } /** * Returns the parent configuration of this subnode configuration. * * @return the parent configuration */ public HierarchicalConfiguration getParent() { return parent; } /** * Returns the key that was used to construct this configuration. If here a * non-null value is returned, the subnode configuration will * always check its parent for structural changes and reconstruct itself if * necessary. * * @return the key for selecting this configuration's root node * @since 1.5 */ public String getSubnodeKey() { return subnodeKey; } /** * Sets the key to the root node of this subnode configuration. If here a * key is set, the subnode configuration will behave like a live-view on its * parent for this key. See the class comment for more details. * * @param subnodeKey the key used to construct this configuration * @since 1.5 */ public void setSubnodeKey(String subnodeKey) { this.subnodeKey = subnodeKey; } /** * Returns the root node for this configuration. If a subnode key is set, * this implementation re-evaluates this key to find out if this subnode * configuration needs to be reconstructed. This ensures that the subnode * configuration is always synchronized with its parent configuration. * * @return the root node of this configuration * @since 1.5 * @see #setSubnodeKey(String) */ @Override public ConfigurationNode getRootNode() { if (getSubnodeKey() != null) { try { List nodes = getParent().fetchNodeList(getSubnodeKey()); if (nodes.size() != 1) { // key is invalid, so detach this subnode configuration setSubnodeKey(null); } else { ConfigurationNode currentRoot = nodes.get(0); if (currentRoot != super.getRootNode()) { // the root node was changed due to a change of the // parent fireEvent(EVENT_SUBNODE_CHANGED, null, null, true); setRootNode(currentRoot); fireEvent(EVENT_SUBNODE_CHANGED, null, null, false); } return currentRoot; } } catch (Exception ex) { // Evaluation of the key caused an exception. Probably the // expression engine has changed on the parent. Detach this // configuration, there is not much we can do about this. setSubnodeKey(null); } } return super.getRootNode(); // use stored root node } /** * Returns a hierarchical configuration object for the given sub node. * This implementation will ensure that the returned * {@code SubnodeConfiguration} object will have the same parent than * this object. * * @param node the sub node, for which the configuration is to be created * @return a hierarchical configuration for this sub node */ @Override protected SubnodeConfiguration createSubnodeConfiguration(ConfigurationNode node) { SubnodeConfiguration result = new SubnodeConfiguration(getParent(), node); getParent().registerSubnodeConfiguration(result); return result; } /** * Returns a hierarchical configuration object for the given sub node that * is aware of structural changes of its parent. Works like the method with * the same name, but also sets the subnode key for the new subnode * configuration, so it can check whether the parent has been changed. This * only works if this subnode configuration has itself a valid subnode key. * So if a subnode configuration that should be aware of structural changes * is created from an already existing subnode configuration, this subnode * configuration must also be aware of such changes. * * @param node the sub node, for which the configuration is to be created * @param subnodeKey the construction key * @return a hierarchical configuration for this sub node * @since 1.5 */ @Override protected SubnodeConfiguration createSubnodeConfiguration( ConfigurationNode node, String subnodeKey) { SubnodeConfiguration result = createSubnodeConfiguration(node); if (getSubnodeKey() != null) { // construct the correct subnode key // determine path to root node List lstPathToRoot = new ArrayList(); ConfigurationNode top = super.getRootNode(); ConfigurationNode nd = node; while (nd != top) { lstPathToRoot.add(nd); nd = nd.getParentNode(); } // construct the keys for the nodes on this path Collections.reverse(lstPathToRoot); String key = getSubnodeKey(); for (ConfigurationNode pathNode : lstPathToRoot) { key = getParent().getExpressionEngine().nodeKey(pathNode, key); } result.setSubnodeKey(key); } return result; } /** * Creates a new node. This task is delegated to the parent. * * @param name the node's name * @return the new node */ @Override protected Node createNode(String name) { return getParent().createNode(name); } /** * Initializes this subnode configuration from the given parent * configuration. This method is called by the constructor. It will copy * many settings from the parent. * * @param parentConfig the parent configuration */ protected void initFromParent(HierarchicalConfiguration parentConfig) { setExpressionEngine(parentConfig.getExpressionEngine()); setListDelimiter(parentConfig.getListDelimiter()); setDelimiterParsingDisabled(parentConfig.isDelimiterParsingDisabled()); setThrowExceptionOnMissing(parentConfig.isThrowExceptionOnMissing()); } /** * Creates a ConfigurationInterpolator with a chain to the parent's * interpolator. * * @return the new interpolator */ @Override protected ConfigurationInterpolator createInterpolator() { ConfigurationInterpolator interpolator = super.createInterpolator(); interpolator.setParentInterpolator(getParent().getInterpolator()); return interpolator; } } ././@LongLink100644 0 0 147 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/SubsetConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/SubsetConfiguration.ja100644 25464 12232154102 33544 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Iterator; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; /** *

A subset of another configuration. The new Configuration object contains * every key from the parent Configuration that starts with prefix. The prefix * is removed from the keys in the subset.

*

It is usually not necessary to use this class directly. Instead the * {@link Configuration#subset(String)} method should be used, * which will return a correctly initialized instance.

* * @author Emmanuel Bourg * @version $Id: SubsetConfiguration.java 1210202 2011-12-04 20:30:46Z oheger $ */ public class SubsetConfiguration extends AbstractConfiguration { /** The parent configuration. */ protected Configuration parent; /** The prefix used to select the properties. */ protected String prefix; /** The prefix delimiter */ protected String delimiter; /** * Create a subset of the specified configuration * * @param parent The parent configuration * @param prefix The prefix used to select the properties */ public SubsetConfiguration(Configuration parent, String prefix) { this.parent = parent; this.prefix = prefix; } /** * Create a subset of the specified configuration * * @param parent The parent configuration * @param prefix The prefix used to select the properties * @param delimiter The prefix delimiter */ public SubsetConfiguration(Configuration parent, String prefix, String delimiter) { this.parent = parent; this.prefix = prefix; this.delimiter = delimiter; } /** * Return the key in the parent configuration associated to the specified * key in this subset. * * @param key The key in the subset. * @return the key as to be used by the parent */ protected String getParentKey(String key) { if ("".equals(key) || key == null) { return prefix; } else { return delimiter == null ? prefix + key : prefix + delimiter + key; } } /** * Return the key in the subset configuration associated to the specified * key in the parent configuration. * * @param key The key in the parent configuration. * @return the key in the context of this subset configuration */ protected String getChildKey(String key) { if (!key.startsWith(prefix)) { throw new IllegalArgumentException("The parent key '" + key + "' is not in the subset."); } else { String modifiedKey = null; if (key.length() == prefix.length()) { modifiedKey = ""; } else { int i = prefix.length() + (delimiter != null ? delimiter.length() : 0); modifiedKey = key.substring(i); } return modifiedKey; } } /** * Return the parent configuration for this subset. * * @return the parent configuration */ public Configuration getParent() { return parent; } /** * Return the prefix used to select the properties in the parent configuration. * * @return the prefix used by this subset */ public String getPrefix() { return prefix; } /** * Set the prefix used to select the properties in the parent configuration. * * @param prefix the prefix */ public void setPrefix(String prefix) { this.prefix = prefix; } @Override public Configuration subset(String prefix) { return parent.subset(getParentKey(prefix)); } public boolean isEmpty() { return !getKeys().hasNext(); } public boolean containsKey(String key) { return parent.containsKey(getParentKey(key)); } @Override public void addPropertyDirect(String key, Object value) { parent.addProperty(getParentKey(key), value); } @Override protected void clearPropertyDirect(String key) { parent.clearProperty(getParentKey(key)); } public Object getProperty(String key) { return parent.getProperty(getParentKey(key)); } @Override public Iterator getKeys(String prefix) { return new SubsetIterator(parent.getKeys(getParentKey(prefix))); } public Iterator getKeys() { return new SubsetIterator(parent.getKeys(prefix)); } @Override protected Object interpolate(Object base) { if (delimiter == null && "".equals(prefix)) { return super.interpolate(base); } else { SubsetConfiguration config = new SubsetConfiguration(parent, ""); ConfigurationInterpolator interpolator = config.getInterpolator(); getInterpolator().registerLocalLookups(interpolator); if (parent instanceof AbstractConfiguration) { interpolator.setParentInterpolator(((AbstractConfiguration) parent).getInterpolator()); } return config.interpolate(base); } } @Override protected String interpolate(String base) { return super.interpolate(base); } /** * {@inheritDoc} * * Change the behavior of the parent configuration if it supports this feature. */ @Override public void setThrowExceptionOnMissing(boolean throwExceptionOnMissing) { if (parent instanceof AbstractConfiguration) { ((AbstractConfiguration) parent).setThrowExceptionOnMissing(throwExceptionOnMissing); } else { super.setThrowExceptionOnMissing(throwExceptionOnMissing); } } /** * {@inheritDoc} * * The subset inherits this feature from its parent if it supports this feature. */ @Override public boolean isThrowExceptionOnMissing() { if (parent instanceof AbstractConfiguration) { return ((AbstractConfiguration) parent).isThrowExceptionOnMissing(); } else { return super.isThrowExceptionOnMissing(); } } /** * Returns the list delimiter. This property will be fetched from the parent * configuration if supported. * * @return the list delimiter * @since 1.4 */ @Override public char getListDelimiter() { return (parent instanceof AbstractConfiguration) ? ((AbstractConfiguration) parent) .getListDelimiter() : super.getListDelimiter(); } /** * Sets the list delimiter. If the parent configuration supports this * feature, the delimiter will be set at the parent. * * @param delim the new list delimiter * @since 1.4 */ @Override public void setListDelimiter(char delim) { if (parent instanceof AbstractConfiguration) { ((AbstractConfiguration) parent).setListDelimiter(delim); } else { super.setListDelimiter(delim); } } /** * Returns a flag whether string properties should be checked for list * delimiter characters. This implementation ensures that this flag is kept * in sync with the parent configuration if this object supports this * feature. * * @return the delimiter parsing disabled flag * @since 1.4 */ @Override public boolean isDelimiterParsingDisabled() { return (parent instanceof AbstractConfiguration) ? ((AbstractConfiguration) parent) .isDelimiterParsingDisabled() : super.isDelimiterParsingDisabled(); } /** * Sets a flag whether list parsing is disabled. This implementation will * also set the flag at the parent configuration if this object supports * this feature. * * @param delimiterParsingDisabled the delimiter parsing disabled flag * @since 1.4 */ @Override public void setDelimiterParsingDisabled(boolean delimiterParsingDisabled) { if (parent instanceof AbstractConfiguration) { ((AbstractConfiguration) parent) .setDelimiterParsingDisabled(delimiterParsingDisabled); } else { super.setDelimiterParsingDisabled(delimiterParsingDisabled); } } /** * A specialized iterator to be returned by the {@code getKeys()} * methods. This implementation wraps an iterator from the parent * configuration. The keys returned by this iterator are correspondingly * transformed. */ private class SubsetIterator implements Iterator { /** Stores the wrapped iterator. */ private final Iterator parentIterator; /** * Creates a new instance of {@code SubsetIterator} and * initializes it with the parent iterator. * * @param it the iterator of the parent configuration */ public SubsetIterator(Iterator it) { parentIterator = it; } /** * Checks whether there are more elements. Delegates to the parent * iterator. * * @return a flag whether there are more elements */ public boolean hasNext() { return parentIterator.hasNext(); } /** * Returns the next element in the iteration. This is the next key from * the parent configuration, transformed to correspond to the point of * view of this subset configuration. * * @return the next element */ public String next() { return getChildKey(parentIterator.next()); } /** * Removes the current element from the iteration. Delegates to the * parent iterator. */ public void remove() { parentIterator.remove(); } } } ././@LongLink100644 0 0 147 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/SystemConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/SystemConfiguration.ja100644 6242 12232154103 33535 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Iterator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * A configuration based on the system properties. * * @author Emmanuel Bourg * @version $Id: SystemConfiguration.java 1210204 2011-12-04 20:38:02Z oheger $ * @since 1.1 */ public class SystemConfiguration extends MapConfiguration { /** The logger. */ private static Log log = LogFactory.getLog(SystemConfiguration.class); /** * Create a Configuration based on the system properties. * * @see System#getProperties */ public SystemConfiguration() { super(System.getProperties()); } /** * The method allows system properties to be set from a property file. * @param fileName The name of the property file. * @throws Exception if an error occurs. * @since 1.6 */ public static void setSystemProperties(String fileName) throws Exception { setSystemProperties(null, fileName); } /** * The method allows system properties to be set from a property file. * @param basePath The base path to look for the property file. * @param fileName The name of the property file. * @throws Exception if an error occurs. * @since 1.6 */ public static void setSystemProperties(String basePath, String fileName) throws Exception { PropertiesConfiguration config = fileName.endsWith(".xml") ? new XMLPropertiesConfiguration() : new PropertiesConfiguration(); if (basePath != null) { config.setBasePath(basePath); } config.setFileName(fileName); config.load(); setSystemProperties(config); } /** * Set System properties from a configuration file. * @param systemConfig The configuration containing the properties to be set. * @since 1.6 */ public static void setSystemProperties(PropertiesConfiguration systemConfig) { Iterator iter = systemConfig.getKeys(); while (iter.hasNext()) { String key = iter.next(); String value = (String) systemConfig.getProperty(key); if (log.isDebugEnabled()) { log.debug("Setting system property " + key + " to " + value); } System.setProperty(key, value); } } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ConfigurationNode.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ConfigurationNode100644 16467 12232154102 33535 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.List; /** *

* Definition of an interface for the nodes of a hierarchical configuration. *

*

* This interface defines a tree like structure for configuration data. A node * has a value and can have an arbitrary number of children and attributes. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: ConfigurationNode.java 1234988 2012-01-23 21:12:15Z oheger $ */ public interface ConfigurationNode { /** * Returns the name of this node. * * @return the node name */ String getName(); /** * Sets the name of this node. * * @param name the node name */ void setName(String name); /** * Returns the value of this node. * * @return the node's value */ Object getValue(); /** * Sets the value of this node. * * @param val the node's value */ void setValue(Object val); /** * Returns this node's reference. * * @return the reference */ Object getReference(); /** * Sets this node's reference. This reference can be used by concrete * Configuration implementations to store data associated with each node. A * XML based configuration for instance could here store a reference to the * corresponding DOM element. * * @param ref the reference */ void setReference(Object ref); /** * Returns this node's parent. Can be null, then this node is the * top level node. * * @return the parent of this node */ ConfigurationNode getParentNode(); /** * Sets the parent of this node. * * @param parent the parent of this node */ void setParentNode(ConfigurationNode parent); /** * Adds a child to this node. * * @param node the new child */ void addChild(ConfigurationNode node); /** * Returns a list with the child nodes of this node. The nodes in this list * should be in the order they were inserted into this node. * * @return a list with the children of this node (never null) */ List getChildren(); /** * Returns the number of this node's children. * * @return the number of the children of this node */ int getChildrenCount(); /** * Returns a list with all children of this node with the given name. * * @param name the name of the searched children * @return a list with all child nodes with this name (never null) */ List getChildren(String name); /** * Returns the number of children with the given name. * * @param name the name * @return the number of children with this name */ int getChildrenCount(String name); /** * Returns the child node with the given index. If the index does not * exist, an exception will be thrown. * @param index the index of the child node (0-based) * @return the child node with this index */ ConfigurationNode getChild(int index); /** * Removes the given node from this node's children. * * @param child the child node to be removed * @return a flag if the node could be removed */ boolean removeChild(ConfigurationNode child); /** * Removes all child nodes of this node with the given name. * * @param childName the name of the children to be removed * @return a flag if at least one child was removed */ boolean removeChild(String childName); /** * Removes all children from this node. */ void removeChildren(); /** * Returns a flag whether this node is an attribute. * * @return a flag whether this node is an attribute */ boolean isAttribute(); /** * Sets a flag whether this node is an attribute. * * @param f the attribute flag */ void setAttribute(boolean f); /** * Returns a list with this node's attributes. Attributes are also modeled * as {@code ConfigurationNode} objects. * * @return a list with the attributes */ List getAttributes(); /** * Returns the number of attributes of this node. * @return the number of attributes */ int getAttributeCount(); /** * Returns a list with the attribute nodes with the given name. Attributes * with same names can be added multiple times, so the return value of this * method is a list. * * @param name the name of the attribute * @return the attribute nodes with this name (never null) */ List getAttributes(String name); /** * Returns the number of attributes with the given name. * * @param name the name of the attribute * @return the number of attributes with this name */ int getAttributeCount(String name); /** * Returns the attribute node with the given index. If no such index exists, * an exception will be thrown. * @param index the index * @return the attribute node with this index */ ConfigurationNode getAttribute(int index); /** * Removes the specified attribute from this node. * * @param node the attribute to remove * @return a flag if the node could be removed */ boolean removeAttribute(ConfigurationNode node); /** * Removes all attributes with the given name. * * @param name the name of the attributes to be removed * @return a flag if at least one attribute was removed */ boolean removeAttribute(String name); /** * Removes all attributes of this node. */ void removeAttributes(); /** * Adds the specified attribute to this node * * @param attr the attribute node */ void addAttribute(ConfigurationNode attr); /** * Returns a flag if this node is defined. This means that the node contains * some data. * * @return a flag whether this node is defined */ boolean isDefined(); /** * Visits this node and all its sub nodes. This method provides a simple * means for going through a hierarchical structure of configuration nodes. * * @see ConfigurationNodeVisitor * @param visitor the visitor */ void visit(ConfigurationNodeVisitor visitor); /** * Returns a copy of this node. * @return the copy */ Object clone(); } ././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitor.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ConfigurationNode100644 4744 12232154102 33510 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; /** *

* Definition of a Visitor interface for a configuration node * structure. *

*

* The {@code ConfigurationNode} interface defines a {@code visit()}, * which simplifies traversal of a complex node hierarchy. A configuration node * implementation must provide a way of visiting all nodes in the current * hierarchy. This is a typical application of the GoF Visitor * pattern. *

* * @since 1.3 * @see ConfigurationNode * @author Commons * Configuration team * @version $Id: ConfigurationNodeVisitor.java 1206463 2011-11-26 15:47:08Z oheger $ */ public interface ConfigurationNodeVisitor { /** * Visits the specified node. This method is called before eventually * existing children of this node are processed. * * @param node the node to be visited */ void visitBeforeChildren(ConfigurationNode node); /** * Visits the specified node. This method is called after eventually * existing children of this node have been processed. * * @param node the node to be visited */ void visitAfterChildren(ConfigurationNode node); /** * Returns a flag whether the actual visit process should be aborted. This * method allows a visitor implementation to state that it does not need any * further data. It may be used e.g. by visitors that search for a certain * node in the hierarchy. After that node was found, there is no need to * process the remaining nodes, too. * * @return a flag if the visit process should be stopped */ boolean terminate(); } ././@LongLink100644 0 0 170 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ConfigurationNodeVisitorAdapter.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ConfigurationNode100644 3775 12232154102 33513 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; /** *

* A simple adapter class that simplifies writing custom node visitor * implementations. *

*

* This class provides dummy implementations for the methods defined in the * {@code ConfigurationNodeVisitor} interface. Derived classes only need * to override the methods they really need. *

* * @author Commons * Configuration team * @version $Id: ConfigurationNodeVisitorAdapter.java 1206464 2011-11-26 15:49:10Z oheger $ */ public class ConfigurationNodeVisitorAdapter implements ConfigurationNodeVisitor { /** * Empty dummy implementation of this interface method. * * @param node the node */ public void visitBeforeChildren(ConfigurationNode node) { } /** * Empty dummy implementation of this interface method. * * @param node the node */ public void visitAfterChildren(ConfigurationNode node) { } /** * Dummy implementation of this interface method. Returns always false. * * @return the terminate flag */ public boolean terminate() { return false; } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/DefaultConfigurationKey.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/DefaultConfigurat100644 66745 12232154102 33532 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.Iterator; import java.util.NoSuchElementException; import org.apache.commons.lang.StringUtils; /** *

* A simple class that supports creation of and iteration on configuration keys * supported by a {@link DefaultExpressionEngine} object. *

*

* For key creation the class works similar to a StringBuffer: There are several * {@code appendXXXX()} methods with which single parts of a key can be * constructed. All these methods return a reference to the actual object so * they can be written in a chain. When using this methods the exact syntax for * keys need not be known. *

*

* This class also defines a specialized iterator for configuration keys. With * such an iterator a key can be tokenized into its single parts. For each part * it can be checked whether it has an associated index. *

*

* Instances of this class are always associated with an instance of * {@link DefaultExpressionEngine}, from which the current * delimiters are obtained. So key creation and parsing is specific to this * associated expression engine. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: DefaultConfigurationKey.java 1231724 2012-01-15 18:40:31Z oheger $ */ public class DefaultConfigurationKey { /** Constant for the initial StringBuffer size. */ private static final int INITIAL_SIZE = 32; /** Stores a reference to the associated expression engine. */ private DefaultExpressionEngine expressionEngine; /** Holds a buffer with the so far created key. */ private StringBuilder keyBuffer; /** * Creates a new instance of {@code DefaultConfigurationKey} and sets * the associated expression engine. * * @param engine the expression engine */ public DefaultConfigurationKey(DefaultExpressionEngine engine) { keyBuffer = new StringBuilder(INITIAL_SIZE); setExpressionEngine(engine); } /** * Creates a new instance of {@code DefaultConfigurationKey} and sets * the associated expression engine and an initial key. * * @param engine the expression engine * @param key the key to be wrapped */ public DefaultConfigurationKey(DefaultExpressionEngine engine, String key) { setExpressionEngine(engine); keyBuffer = new StringBuilder(trim(key)); } /** * Returns the associated default expression engine. * * @return the associated expression engine */ public DefaultExpressionEngine getExpressionEngine() { return expressionEngine; } /** * Sets the associated expression engine. * * @param expressionEngine the expression engine (must not be null) */ public void setExpressionEngine(DefaultExpressionEngine expressionEngine) { if (expressionEngine == null) { throw new IllegalArgumentException( "Expression engine must not be null!"); } this.expressionEngine = expressionEngine; } /** * Appends the name of a property to this key. If necessary, a property * delimiter will be added. If the boolean argument is set to true, * property delimiters contained in the property name will be escaped. * * @param property the name of the property to be added * @param escape a flag if property delimiters in the passed in property name * should be escaped * @return a reference to this object */ public DefaultConfigurationKey append(String property, boolean escape) { String key; if (escape && property != null) { key = escapeDelimiters(property); } else { key = property; } key = trim(key); if (keyBuffer.length() > 0 && !isAttributeKey(property) && key.length() > 0) { keyBuffer.append(getExpressionEngine().getPropertyDelimiter()); } keyBuffer.append(key); return this; } /** * Appends the name of a property to this key. If necessary, a property * delimiter will be added. Property delimiters in the given string will not * be escaped. * * @param property the name of the property to be added * @return a reference to this object */ public DefaultConfigurationKey append(String property) { return append(property, false); } /** * Appends an index to this configuration key. * * @param index the index to be appended * @return a reference to this object */ public DefaultConfigurationKey appendIndex(int index) { keyBuffer.append(getExpressionEngine().getIndexStart()); keyBuffer.append(index); keyBuffer.append(getExpressionEngine().getIndexEnd()); return this; } /** * Appends an attribute to this configuration key. * * @param attr the name of the attribute to be appended * @return a reference to this object */ public DefaultConfigurationKey appendAttribute(String attr) { keyBuffer.append(constructAttributeKey(attr)); return this; } /** * Returns the actual length of this configuration key. * * @return the length of this key */ public int length() { return keyBuffer.length(); } /** * Sets the new length of this configuration key. With this method it is * possible to truncate the key, e.g. to return to a state prior calling * some {@code append()} methods. The semantic is the same as the * {@code setLength()} method of {@code StringBuilder}. * * @param len the new length of the key */ public void setLength(int len) { keyBuffer.setLength(len); } /** * Checks if two {@code ConfigurationKey} objects are equal. The * method can be called with strings or other objects, too. * * @param c the object to compare * @return a flag if both objects are equal */ @Override public boolean equals(Object c) { if (c == null) { return false; } return keyBuffer.toString().equals(c.toString()); } /** * Returns the hash code for this object. * * @return the hash code */ @Override public int hashCode() { return String.valueOf(keyBuffer).hashCode(); } /** * Returns a string representation of this object. This is the configuration * key as a plain string. * * @return a string for this object */ @Override public String toString() { return keyBuffer.toString(); } /** * Tests if the specified key represents an attribute according to the * current expression engine. * * @param key the key to be checked * @return true if this is an attribute key, false otherwise */ public boolean isAttributeKey(String key) { if (key == null) { return false; } return key.startsWith(getExpressionEngine().getAttributeStart()) && (getExpressionEngine().getAttributeEnd() == null || key .endsWith(getExpressionEngine().getAttributeEnd())); } /** * Decorates the given key so that it represents an attribute. Adds special * start and end markers. The passed in string will be modified only if does * not already represent an attribute. * * @param key the key to be decorated * @return the decorated attribute key */ public String constructAttributeKey(String key) { if (key == null) { return StringUtils.EMPTY; } if (isAttributeKey(key)) { return key; } else { StringBuilder buf = new StringBuilder(); buf.append(getExpressionEngine().getAttributeStart()).append(key); if (getExpressionEngine().getAttributeEnd() != null) { buf.append(getExpressionEngine().getAttributeEnd()); } return buf.toString(); } } /** * Extracts the name of the attribute from the given attribute key. This * method removes the attribute markers - if any - from the specified key. * * @param key the attribute key * @return the name of the corresponding attribute */ public String attributeName(String key) { return isAttributeKey(key) ? removeAttributeMarkers(key) : key; } /** * Removes leading property delimiters from the specified key. * * @param key the key * @return the key with removed leading property delimiters */ public String trimLeft(String key) { if (key == null) { return StringUtils.EMPTY; } else { String result = key; while (hasLeadingDelimiter(result)) { result = result.substring(getExpressionEngine() .getPropertyDelimiter().length()); } return result; } } /** * Removes trailing property delimiters from the specified key. * * @param key the key * @return the key with removed trailing property delimiters */ public String trimRight(String key) { if (key == null) { return StringUtils.EMPTY; } else { String result = key; while (hasTrailingDelimiter(result)) { result = result .substring(0, result.length() - getExpressionEngine().getPropertyDelimiter() .length()); } return result; } } /** * Removes delimiters at the beginning and the end of the specified key. * * @param key the key * @return the key with removed property delimiters */ public String trim(String key) { return trimRight(trimLeft(key)); } /** * Returns an iterator for iterating over the single components of this * configuration key. * * @return an iterator for this key */ public KeyIterator iterator() { return new KeyIterator(); } /** * Helper method that checks if the specified key ends with a property * delimiter. * * @param key the key to check * @return a flag if there is a trailing delimiter */ private boolean hasTrailingDelimiter(String key) { return key.endsWith(getExpressionEngine().getPropertyDelimiter()) && (getExpressionEngine().getEscapedDelimiter() == null || !key .endsWith(getExpressionEngine().getEscapedDelimiter())); } /** * Helper method that checks if the specified key starts with a property * delimiter. * * @param key the key to check * @return a flag if there is a leading delimiter */ private boolean hasLeadingDelimiter(String key) { return key.startsWith(getExpressionEngine().getPropertyDelimiter()) && (getExpressionEngine().getEscapedDelimiter() == null || !key .startsWith(getExpressionEngine().getEscapedDelimiter())); } /** * Helper method for removing attribute markers from a key. * * @param key the key * @return the key with removed attribute markers */ private String removeAttributeMarkers(String key) { return key .substring( getExpressionEngine().getAttributeStart().length(), key.length() - ((getExpressionEngine().getAttributeEnd() != null) ? getExpressionEngine() .getAttributeEnd().length() : 0)); } /** * Unescapes the delimiters in the specified string. * * @param key the key to be unescaped * @return the unescaped key */ private String unescapeDelimiters(String key) { return (getExpressionEngine().getEscapedDelimiter() == null) ? key : StringUtils.replace(key, getExpressionEngine() .getEscapedDelimiter(), getExpressionEngine() .getPropertyDelimiter()); } /** * Escapes the delimiters in the specified string. * * @param key the key to be escaped * @return the escaped key */ private String escapeDelimiters(String key) { return (getExpressionEngine().getEscapedDelimiter() == null || key .indexOf(getExpressionEngine().getPropertyDelimiter()) < 0) ? key : StringUtils.replace(key, getExpressionEngine() .getPropertyDelimiter(), getExpressionEngine() .getEscapedDelimiter()); } /** * A specialized iterator class for tokenizing a configuration key. This * class implements the normal iterator interface. In addition it provides * some specific methods for configuration keys. */ public class KeyIterator implements Iterator, Cloneable { /** Stores the current key name. */ private String current; /** Stores the start index of the actual token. */ private int startIndex; /** Stores the end index of the actual token. */ private int endIndex; /** Stores the index of the actual property if there is one. */ private int indexValue; /** Stores a flag if the actual property has an index. */ private boolean hasIndex; /** Stores a flag if the actual property is an attribute. */ private boolean attribute; /** * Returns the next key part of this configuration key. This is a short * form of {@code nextKey(false)}. * * @return the next key part */ public String nextKey() { return nextKey(false); } /** * Returns the next key part of this configuration key. The boolean * parameter indicates wheter a decorated key should be returned. This * affects only attribute keys: if the parameter is false, the * attribute markers are stripped from the key; if it is true, * they remain. * * @param decorated a flag if the decorated key is to be returned * @return the next key part */ public String nextKey(boolean decorated) { if (!hasNext()) { throw new NoSuchElementException("No more key parts!"); } hasIndex = false; indexValue = -1; String key = findNextIndices(); current = key; hasIndex = checkIndex(key); attribute = checkAttribute(current); return currentKey(decorated); } /** * Checks if there is a next element. * * @return a flag if there is a next element */ public boolean hasNext() { return endIndex < keyBuffer.length(); } /** * Returns the next object in the iteration. * * @return the next object */ public Object next() { return nextKey(); } /** * Removes the current object in the iteration. This method is not * supported by this iterator type, so an exception is thrown. */ public void remove() { throw new UnsupportedOperationException("Remove not supported!"); } /** * Returns the current key of the iteration (without skipping to the * next element). This is the same key the previous {@code next()} * call had returned. (Short form of {@code currentKey(false)}. * * @return the current key */ public String currentKey() { return currentKey(false); } /** * Returns the current key of the iteration (without skipping to the * next element). The boolean parameter indicates wheter a decorated key * should be returned. This affects only attribute keys: if the * parameter is false, the attribute markers are stripped from * the key; if it is true, they remain. * * @param decorated a flag if the decorated key is to be returned * @return the current key */ public String currentKey(boolean decorated) { return (decorated && !isPropertyKey()) ? constructAttributeKey(current) : current; } /** * Returns a flag if the current key is an attribute. This method can be * called after {@code next()}. * * @return a flag if the current key is an attribute */ public boolean isAttribute() { // if attribute emulation mode is active, the last part of a key is // always an attribute key, too return attribute || (isAttributeEmulatingMode() && !hasNext()); } /** * Returns a flag whether the current key refers to a property (i.e. is * no special attribute key). Usually this method will return the * opposite of {@code isAttribute()}, but if the delimiters for * normal properties and attributes are set to the same string, it is * possible that both methods return true. * * @return a flag if the current key is a property key * @see #isAttribute() */ public boolean isPropertyKey() { return !attribute; } /** * Returns the index value of the current key. If the current key does * not have an index, return value is -1. This method can be called * after {@code next()}. * * @return the index value of the current key */ public int getIndex() { return indexValue; } /** * Returns a flag if the current key has an associated index. This * method can be called after {@code next()}. * * @return a flag if the current key has an index */ public boolean hasIndex() { return hasIndex; } /** * Creates a clone of this object. * * @return a clone of this object */ @Override public Object clone() { try { return super.clone(); } catch (CloneNotSupportedException cex) { // should not happen return null; } } /** * Helper method for determining the next indices. * * @return the next key part */ private String findNextIndices() { startIndex = endIndex; // skip empty names while (startIndex < length() && hasLeadingDelimiter(keyBuffer.substring(startIndex))) { startIndex += getExpressionEngine().getPropertyDelimiter() .length(); } // Key ends with a delimiter? if (startIndex >= length()) { endIndex = length(); startIndex = endIndex - 1; return keyBuffer.substring(startIndex, endIndex); } else { return nextKeyPart(); } } /** * Helper method for extracting the next key part. Takes escaping of * delimiter characters into account. * * @return the next key part */ private String nextKeyPart() { int attrIdx = keyBuffer.toString().indexOf( getExpressionEngine().getAttributeStart(), startIndex); if (attrIdx < 0 || attrIdx == startIndex) { attrIdx = length(); } int delIdx = nextDelimiterPos(keyBuffer.toString(), startIndex, attrIdx); if (delIdx < 0) { delIdx = attrIdx; } endIndex = Math.min(attrIdx, delIdx); return unescapeDelimiters(keyBuffer.substring(startIndex, endIndex)); } /** * Searches the next unescaped delimiter from the given position. * * @param key the key * @param pos the start position * @param endPos the end position * @return the position of the next delimiter or -1 if there is none */ private int nextDelimiterPos(String key, int pos, int endPos) { int delimiterPos = pos; boolean found = false; do { delimiterPos = key.indexOf(getExpressionEngine() .getPropertyDelimiter(), delimiterPos); if (delimiterPos < 0 || delimiterPos >= endPos) { return -1; } int escapePos = escapedPosition(key, delimiterPos); if (escapePos < 0) { found = true; } else { delimiterPos = escapePos; } } while (!found); return delimiterPos; } /** * Checks if a delimiter at the specified position is escaped. If this * is the case, the next valid search position will be returned. * Otherwise the return value is -1. * * @param key the key to check * @param pos the position where a delimiter was found * @return information about escaped delimiters */ private int escapedPosition(String key, int pos) { if (getExpressionEngine().getEscapedDelimiter() == null) { // nothing to escape return -1; } int escapeOffset = escapeOffset(); if (escapeOffset < 0 || escapeOffset > pos) { // No escaping possible at this position return -1; } int escapePos = key.indexOf(getExpressionEngine() .getEscapedDelimiter(), pos - escapeOffset); if (escapePos <= pos && escapePos >= 0) { // The found delimiter is escaped. Next valid search position // is behind the escaped delimiter. return escapePos + getExpressionEngine().getEscapedDelimiter().length(); } else { return -1; } } /** * Determines the relative offset of an escaped delimiter in relation to * a delimiter. Depending on the used delimiter and escaped delimiter * tokens the position where to search for an escaped delimiter is * different. If, for instance, the dot character (".") is * used as delimiter, and a doubled dot ("..") as escaped * delimiter, the escaped delimiter starts at the same position as the * delimiter. If the token "\." was used, it would start one * character before the delimiter because the delimiter character * "." is the second character in the escaped delimiter * string. This relation will be determined by this method. For this to * work the delimiter string must be contained in the escaped delimiter * string. * * @return the relative offset of the escaped delimiter in relation to a * delimiter */ private int escapeOffset() { return getExpressionEngine().getEscapedDelimiter().indexOf( getExpressionEngine().getPropertyDelimiter()); } /** * Helper method for checking if the passed key is an attribute. If this * is the case, the internal fields will be set. * * @param key the key to be checked * @return a flag if the key is an attribute */ private boolean checkAttribute(String key) { if (isAttributeKey(key)) { current = removeAttributeMarkers(key); return true; } else { return false; } } /** * Helper method for checking if the passed key contains an index. If * this is the case, internal fields will be set. * * @param key the key to be checked * @return a flag if an index is defined */ private boolean checkIndex(String key) { boolean result = false; try { int idx = key.lastIndexOf(getExpressionEngine().getIndexStart()); if (idx > 0) { int endidx = key.indexOf(getExpressionEngine().getIndexEnd(), idx); if (endidx > idx + 1) { indexValue = Integer.parseInt(key.substring(idx + 1, endidx)); current = key.substring(0, idx); result = true; } } } catch (NumberFormatException nfe) { result = false; } return result; } /** * Returns a flag whether attributes are marked the same way as normal * property keys. We call this the "attribute emulating mode". * When navigating through node hierarchies it might be convenient to * treat attributes the same way than other child nodes, so an * expression engine supports to set the attribute markers to the same * value than the property delimiter. If this is the case, some special * checks have to be performed. * * @return a flag if attributes and normal property keys are treated the * same way */ private boolean isAttributeEmulatingMode() { return getExpressionEngine().getAttributeEnd() == null && StringUtils.equals(getExpressionEngine() .getPropertyDelimiter(), getExpressionEngine() .getAttributeStart()); } } } ././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/DefaultConfigurationNode.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/DefaultConfigurat100644 44672 12232154102 33525 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.LinkedList; import java.util.List; import java.util.Map; import org.apache.commons.configuration.ConfigurationRuntimeException; /** *

* A default implementation of the {@code ConfigurationNode} interface. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: DefaultConfigurationNode.java 1301991 2012-03-17 20:18:02Z sebb $ */ public class DefaultConfigurationNode implements ConfigurationNode, Cloneable { /** Stores the children of this node. */ private SubNodes children; /** Stores the attributes of this node. */ private SubNodes attributes; /** Stores a reference to this node's parent. */ private ConfigurationNode parent; /** Stores the value of this node. */ private Object value; /** Stores the reference. */ private Object reference; /** Stores the name of this node. */ private String name; /** Stores a flag if this is an attribute. */ private boolean attribute; /** * Creates a new uninitialized instance of {@code DefaultConfigurationNode}. */ public DefaultConfigurationNode() { this(null); } /** * Creates a new instance of {@code DefaultConfigurationNode} and * initializes it with the node name. * * @param name the name of this node */ public DefaultConfigurationNode(String name) { this(name, null); } /** * Creates a new instance of {@code DefaultConfigurationNode} and * initializes it with the name and a value. * * @param name the node's name * @param value the node's value */ public DefaultConfigurationNode(String name, Object value) { setName(name); setValue(value); initSubNodes(); } /** * Returns the name of this node. * * @return the name of this node */ public String getName() { return name; } /** * Sets the name of this node. * * @param name the new name */ public void setName(String name) { checkState(); this.name = name; } /** * Returns the value of this node. * * @return the value of this node */ public Object getValue() { return value; } /** * Sets the value of this node. * * @param val the value of this node */ public void setValue(Object val) { value = val; } /** * Returns the reference. * * @return the reference */ public Object getReference() { return reference; } /** * Sets the reference. * * @param reference the reference object */ public void setReference(Object reference) { this.reference = reference; } /** * Returns a reference to this node's parent. * * @return the parent node or null if this is the root */ public ConfigurationNode getParentNode() { return parent; } /** * Sets the parent of this node. * * @param parent the parent of this node */ public void setParentNode(ConfigurationNode parent) { this.parent = parent; } /** * Adds a new child to this node. * * @param child the new child */ public void addChild(ConfigurationNode child) { children.addNode(child); child.setAttribute(false); child.setParentNode(this); } /** * Returns a list with all children of this node. * * @return a list with all child nodes */ public List getChildren() { return children.getSubNodes(); } /** * Returns the number of all children of this node. * * @return the number of all children */ public int getChildrenCount() { return children.getSubNodes().size(); } /** * Returns a list of all children with the given name. * * @param name the name; can be null , then all children are returned * @return a list of all children with the given name */ public List getChildren(String name) { return children.getSubNodes(name); } /** * Returns the number of children with the given name. * * @param name the name; can be null , then the number of all * children is returned * @return the number of child nodes with this name */ public int getChildrenCount(String name) { return children.getSubNodes(name).size(); } /** * Returns the child node with the given index. * * @param index the index (0-based) * @return the child with this index */ public ConfigurationNode getChild(int index) { return children.getNode(index); } /** * Removes the specified child node from this node. * * @param child the node to be removed * @return a flag if a node was removed */ public boolean removeChild(ConfigurationNode child) { return children.removeNode(child); } /** * Removes all children with the given name. * * @param childName the name of the children to be removed * @return a flag if at least one child node was removed */ public boolean removeChild(String childName) { return children.removeNodes(childName); } /** * Removes all child nodes of this node. */ public void removeChildren() { children.clear(); } /** * Checks if this node is an attribute node. * * @return a flag if this is an attribute node */ public boolean isAttribute() { return attribute; } /** * Sets the attribute flag. Note: this method can only be called if the node * is not already part of a node hierarchy. * * @param f the attribute flag */ public void setAttribute(boolean f) { checkState(); attribute = f; } /** * Adds the specified attribute to this node. * * @param attr the attribute to be added */ public void addAttribute(ConfigurationNode attr) { attributes.addNode(attr); attr.setAttribute(true); attr.setParentNode(this); } /** * Returns a list with the attributes of this node. This list contains * {@code DefaultConfigurationNode} objects, too. * * @return the attribute list, never null */ public List getAttributes() { return attributes.getSubNodes(); } /** * Returns the number of attributes contained in this node. * * @return the number of attributes */ public int getAttributeCount() { return attributes.getSubNodes().size(); } /** * Returns a list with all attributes of this node with the given name. * * @param name the attribute's name * @return all attributes with this name */ public List getAttributes(String name) { return attributes.getSubNodes(name); } /** * Returns the number of attributes of this node with the given name. * * @param name the name * @return the number of attributes with this name */ public int getAttributeCount(String name) { return getAttributes(name).size(); } /** * Removes the specified attribute. * * @param node the attribute node to be removed * @return a flag if the attribute could be removed */ public boolean removeAttribute(ConfigurationNode node) { return attributes.removeNode(node); } /** * Removes all attributes with the specified name. * * @param name the name * @return a flag if at least one attribute was removed */ public boolean removeAttribute(String name) { return attributes.removeNodes(name); } /** * Returns the attribute with the given index. * * @param index the index (0-based) * @return the attribute with this index */ public ConfigurationNode getAttribute(int index) { return attributes.getNode(index); } /** * Removes all attributes of this node. */ public void removeAttributes() { attributes.clear(); } /** * Returns a flag if this node is defined. This means that the node contains * some data. * * @return a flag whether this node is defined */ public boolean isDefined() { return getValue() != null || getChildrenCount() > 0 || getAttributeCount() > 0; } /** * Visits this node and all its sub nodes. * * @param visitor the visitor */ public void visit(ConfigurationNodeVisitor visitor) { if (visitor == null) { throw new IllegalArgumentException("Visitor must not be null!"); } if (!visitor.terminate()) { visitor.visitBeforeChildren(this); children.visit(visitor); attributes.visit(visitor); visitor.visitAfterChildren(this); } } /** * Creates a copy of this object. This is not a deep copy, the children are * not cloned. * * @return a copy of this object */ @Override public Object clone() { try { DefaultConfigurationNode copy = (DefaultConfigurationNode) super .clone(); copy.initSubNodes(); return copy; } catch (CloneNotSupportedException cex) { // should not happen throw new ConfigurationRuntimeException("Cannot clone " + getClass()); } } /** * Checks if a modification of this node is allowed. Some properties of a * node must not be changed when the node has a parent. This method checks * this and throws a runtime exception if necessary. */ protected void checkState() { if (getParentNode() != null) { throw new IllegalStateException( "Node cannot be modified when added to a parent!"); } } /** * Creates a {@code SubNodes} instance that is used for storing * either this node's children or attributes. * * @param attributes true if the returned instance is used for * storing attributes, false for storing child nodes * @return the {@code SubNodes} object to use */ protected SubNodes createSubNodes(boolean attributes) { return new SubNodes(); } /** * Deals with the reference when a node is removed. This method is called * for each removed child node or attribute. It can be overloaded in sub * classes, for which the reference has a concrete meaning and remove * operations need some update actions. This default implementation is * empty. */ protected void removeReference() { } /** * Helper method for initializing the sub nodes objects. */ private void initSubNodes() { children = createSubNodes(false); attributes = createSubNodes(true); } /** * An internally used helper class for managing a collection of sub nodes. */ protected static class SubNodes { /** Stores a list for the sub nodes. */ private List nodes; /** Stores a map for accessing subnodes by name. */ private Map> namedNodes; /** * Adds a new sub node. * * @param node the node to add */ public void addNode(ConfigurationNode node) { if (node == null || node.getName() == null) { throw new IllegalArgumentException( "Node to add must have a defined name!"); } node.setParentNode(null); // reset, will later be set if (nodes == null) { nodes = new ArrayList(); namedNodes = new HashMap>(); } nodes.add(node); List lst = namedNodes.get(node.getName()); if (lst == null) { lst = new LinkedList(); namedNodes.put(node.getName(), lst); } lst.add(node); } /** * Removes a sub node. * * @param node the node to remove * @return a flag if the node could be removed */ public boolean removeNode(ConfigurationNode node) { if (nodes != null && node != null && nodes.contains(node)) { detachNode(node); nodes.remove(node); List lst = namedNodes.get(node.getName()); if (lst != null) { lst.remove(node); if (lst.isEmpty()) { namedNodes.remove(node.getName()); } } return true; } else { return false; } } /** * Removes all sub nodes with the given name. * * @param name the name * @return a flag if at least on sub node was removed */ public boolean removeNodes(String name) { if (nodes != null && name != null) { List lst = namedNodes.remove(name); if (lst != null) { detachNodes(lst); nodes.removeAll(lst); return true; } } return false; } /** * Removes all sub nodes. */ public void clear() { if (nodes != null) { detachNodes(nodes); nodes = null; namedNodes = null; } } /** * Returns the node with the given index. If this index cannot be found, * an {@code IndexOutOfBoundException} exception will be thrown. * * @param index the index (0-based) * @return the sub node at the specified index */ public ConfigurationNode getNode(int index) { if (nodes == null) { throw new IndexOutOfBoundsException("No sub nodes available!"); } return nodes.get(index); } /** * Returns a list with all stored sub nodes. The return value is never * null. * * @return a list with the sub nodes */ public List getSubNodes() { if (nodes == null) { return Collections.emptyList(); } else { return Collections.unmodifiableList(nodes); } } /** * Returns a list of the sub nodes with the given name. The return value * is never null. * * @param name the name; if null is passed, all sub nodes will * be returned * @return all sub nodes with this name */ public List getSubNodes(String name) { if (name == null) { return getSubNodes(); } List result; if (nodes == null) { result = null; } else { result = namedNodes.get(name); } if (result == null) { return Collections.emptyList(); } else { return Collections.unmodifiableList(result); } } /** * Let the passed in visitor visit all sub nodes. * * @param visitor the visitor */ public void visit(ConfigurationNodeVisitor visitor) { if (nodes != null) { for (Iterator it = nodes.iterator(); it.hasNext() && !visitor.terminate();) { it.next().visit(visitor); } } } /** * This method is called whenever a sub node is removed from this * object. It ensures that the removed node's parent is reset and its * {@code removeReference()} method gets called. * * @param subNode the node to be removed */ protected void detachNode(ConfigurationNode subNode) { subNode.setParentNode(null); if (subNode instanceof DefaultConfigurationNode) { ((DefaultConfigurationNode) subNode).removeReference(); } } /** * Detaches a list of sub nodes. This method calls * {@code detachNode()} for each node contained in the list. * * @param subNodes the list with nodes to be detached */ protected void detachNodes(Collection subNodes) { for (ConfigurationNode nd : subNodes) { detachNode(nd); } } } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/DefaultExpressionEngine.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/DefaultExpression100644 43425 12232154102 33556 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.Collection; import java.util.LinkedList; import java.util.List; import org.apache.commons.lang.StringUtils; /** *

* A default implementation of the {@code ExpressionEngine} interface * providing the "native"e; expression language for hierarchical * configurations. *

*

* This class implements a rather simple expression language for navigating * through a hierarchy of configuration nodes. It supports the following * operations: *

*

*

    *
  • Navigating from a node to one of its children using the child node * delimiter, which is by the default a dot (".").
  • *
  • Navigating from a node to one of its attributes using the attribute node * delimiter, which by default follows the XPATH like syntax * [@<attributeName>].
  • *
  • If there are multiple child or attribute nodes with the same name, a * specific node can be selected using a numerical index. By default indices are * written in parenthesis.
  • *
*

*

* As an example consider the following XML document: *

* *
 *  <database>
 *    <tables>
 *      <table type="system">
 *        <name>users</name>
 *        <fields>
 *          <field>
 *            <name>lid</name>
 *            <type>long</name>
 *          </field>
 *          <field>
 *            <name>usrName</name>
 *            <type>java.lang.String</type>
 *          </field>
 *         ...
 *        </fields>
 *      </table>
 *      <table>
 *        <name>documents</name>
 *        <fields>
 *          <field>
 *            <name>docid</name>
 *            <type>long</type>
 *          </field>
 *          ...
 *        </fields>
 *      </table>
 *      ...
 *    </tables>
 *  </database>
 * 
* *

*

* If this document is parsed and stored in a hierarchical configuration object, * for instance the key {@code tables.table(0).name} can be used to find * out the name of the first table. In opposite {@code tables.table.name} * would return a collection with the names of all available tables. Similarly * the key {@code tables.table(1).fields.field.name} returns a collection * with the names of all fields of the second table. If another index is added * after the {@code field} element, a single field can be accessed: * {@code tables.table(1).fields.field(0).name}. The key * {@code tables.table(0)[@type]} would select the type attribute of the * first table. *

*

* This example works with the default values for delimiters and index markers. * It is also possible to set custom values for these properties so that you can * adapt a {@code DefaultExpressionEngine} to your personal needs. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: DefaultExpressionEngine.java 1301991 2012-03-17 20:18:02Z sebb $ */ public class DefaultExpressionEngine implements ExpressionEngine { /** Constant for the default property delimiter. */ public static final String DEFAULT_PROPERTY_DELIMITER = "."; /** Constant for the default escaped property delimiter. */ public static final String DEFAULT_ESCAPED_DELIMITER = DEFAULT_PROPERTY_DELIMITER + DEFAULT_PROPERTY_DELIMITER; /** Constant for the default attribute start marker. */ public static final String DEFAULT_ATTRIBUTE_START = "[@"; /** Constant for the default attribute end marker. */ public static final String DEFAULT_ATTRIBUTE_END = "]"; /** Constant for the default index start marker. */ public static final String DEFAULT_INDEX_START = "("; /** Constant for the default index end marker. */ public static final String DEFAULT_INDEX_END = ")"; /** Stores the property delimiter. */ private String propertyDelimiter = DEFAULT_PROPERTY_DELIMITER; /** Stores the escaped property delimiter. */ private String escapedDelimiter = DEFAULT_ESCAPED_DELIMITER; /** Stores the attribute start marker. */ private String attributeStart = DEFAULT_ATTRIBUTE_START; /** Stores the attribute end marker. */ private String attributeEnd = DEFAULT_ATTRIBUTE_END; /** Stores the index start marker. */ private String indexStart = DEFAULT_INDEX_START; /** stores the index end marker. */ private String indexEnd = DEFAULT_INDEX_END; /** * Sets the attribute end marker. * * @return the attribute end marker */ public String getAttributeEnd() { return attributeEnd; } /** * Sets the attribute end marker. * * @param attributeEnd the attribute end marker; can be null if no * end marker is needed */ public void setAttributeEnd(String attributeEnd) { this.attributeEnd = attributeEnd; } /** * Returns the attribute start marker. * * @return the attribute start marker */ public String getAttributeStart() { return attributeStart; } /** * Sets the attribute start marker. Attribute start and end marker are used * together to detect attributes in a property key. * * @param attributeStart the attribute start marker */ public void setAttributeStart(String attributeStart) { this.attributeStart = attributeStart; } /** * Returns the escaped property delimiter string. * * @return the escaped property delimiter */ public String getEscapedDelimiter() { return escapedDelimiter; } /** * Sets the escaped property delimiter string. With this string a delimiter * that belongs to the key of a property can be escaped. If for instance * "." is used as property delimiter, you can set the escaped * delimiter to "\." and can then escape the delimiter with a back * slash. * * @param escapedDelimiter the escaped delimiter string */ public void setEscapedDelimiter(String escapedDelimiter) { this.escapedDelimiter = escapedDelimiter; } /** * Returns the index end marker. * * @return the index end marker */ public String getIndexEnd() { return indexEnd; } /** * Sets the index end marker. * * @param indexEnd the index end marker */ public void setIndexEnd(String indexEnd) { this.indexEnd = indexEnd; } /** * Returns the index start marker. * * @return the index start marker */ public String getIndexStart() { return indexStart; } /** * Sets the index start marker. Index start and end marker are used together * to detect indices in a property key. * * @param indexStart the index start marker */ public void setIndexStart(String indexStart) { this.indexStart = indexStart; } /** * Returns the property delimiter. * * @return the property delimiter */ public String getPropertyDelimiter() { return propertyDelimiter; } /** * Sets the property delimiter. This string is used to split the parts of a * property key. * * @param propertyDelimiter the property delimiter */ public void setPropertyDelimiter(String propertyDelimiter) { this.propertyDelimiter = propertyDelimiter; } /** * Evaluates the given key and returns all matching nodes. This method * supports the syntax as described in the class comment. * * @param root the root node * @param key the key * @return a list with the matching nodes */ public List query(ConfigurationNode root, String key) { List nodes = new LinkedList(); findNodesForKey(new DefaultConfigurationKey(this, key).iterator(), root, nodes); return nodes; } /** * Determines the key of the passed in node. This implementation takes the * given parent key, adds a property delimiter, and then adds the node's * name. (For attribute nodes the attribute delimiters are used instead.) * The name of the root node is a blanc string. Note that no indices will be * returned. * * @param node the node whose key is to be determined * @param parentKey the key of this node's parent * @return the key for the given node */ public String nodeKey(ConfigurationNode node, String parentKey) { if (parentKey == null) { // this is the root node return StringUtils.EMPTY; } else { DefaultConfigurationKey key = new DefaultConfigurationKey(this, parentKey); if (node.isAttribute()) { key.appendAttribute(node.getName()); } else { key.append(node.getName(), true); } return key.toString(); } } /** *

* Prepares Adding the property with the specified key. *

*

* To be able to deal with the structure supported by hierarchical * configuration implementations the passed in key is of importance, * especially the indices it might contain. The following example should * clarify this: Suppose the actual node structure looks like the * following: *

*

*

     *  tables
     *     +-- table
     *             +-- name = user
     *             +-- fields
     *                     +-- field
     *                             +-- name = uid
     *                     +-- field
     *                             +-- name = firstName
     *                     ...
     *     +-- table
     *             +-- name = documents
     *             +-- fields
     *                    ...
     * 
*

*

* In this example a database structure is defined, e.g. all fields of the * first table could be accessed using the key * {@code tables.table(0).fields.field.name}. If now properties are * to be added, it must be exactly specified at which position in the * hierarchy the new property is to be inserted. So to add a new field name * to a table it is not enough to say just *

*

*

     * config.addProperty("tables.table.fields.field.name", "newField");
     * 
*

*

* The statement given above contains some ambiguity. For instance it is not * clear, to which table the new field should be added. If this method finds * such an ambiguity, it is resolved by following the last valid path. Here * this would be the last table. The same is true for the {@code field}; * because there are multiple fields and no explicit index is provided, a * new {@code name} property would be added to the last field - which * is probably not what was desired. *

*

* To make things clear explicit indices should be provided whenever * possible. In the example above the exact table could be specified by * providing an index for the {@code table} element as in * {@code tables.table(1).fields}. By specifying an index it can * also be expressed that at a given position in the configuration tree a * new branch should be added. In the example above we did not want to add * an additional {@code name} element to the last field of the table, * but we want a complete new {@code field} element. This can be * achieved by specifying an invalid index (like -1) after the element where * a new branch should be created. Given this our example would run: *

*

*

     * config.addProperty("tables.table(1).fields.field(-1).name", "newField");
     * 
*

*

* With this notation it is possible to add new branches everywhere. We * could for instance create a new {@code table} element by * specifying *

*

*

     * config.addProperty("tables.table(-1).fields.field.name", "newField2");
     * 
*

*

* (Note that because after the {@code table} element a new branch is * created indices in following elements are not relevant; the branch is new * so there cannot be any ambiguities.) *

* * @param root the root node of the nodes hierarchy * @param key the key of the new property * @return a data object with information needed for the add operation */ public NodeAddData prepareAdd(ConfigurationNode root, String key) { DefaultConfigurationKey.KeyIterator it = new DefaultConfigurationKey( this, key).iterator(); if (!it.hasNext()) { throw new IllegalArgumentException( "Key for add operation must be defined!"); } NodeAddData result = new NodeAddData(); result.setParent(findLastPathNode(it, root)); while (it.hasNext()) { if (!it.isPropertyKey()) { throw new IllegalArgumentException( "Invalid key for add operation: " + key + " (Attribute key in the middle.)"); } result.addPathNode(it.currentKey()); it.next(); } result.setNewNodeName(it.currentKey()); result.setAttribute(!it.isPropertyKey()); return result; } /** * Recursive helper method for evaluating a key. This method processes all * facets of a configuration key, traverses the tree of properties and * fetches the the nodes of all matching properties. * * @param keyPart the configuration key iterator * @param node the actual node * @param nodes here the found nodes are stored */ protected void findNodesForKey(DefaultConfigurationKey.KeyIterator keyPart, ConfigurationNode node, Collection nodes) { if (!keyPart.hasNext()) { nodes.add(node); } else { String key = keyPart.nextKey(false); if (keyPart.isPropertyKey()) { processSubNodes(keyPart, node.getChildren(key), nodes); } if (keyPart.isAttribute()) { processSubNodes(keyPart, node.getAttributes(key), nodes); } } } /** * Finds the last existing node for an add operation. This method traverses * the configuration node tree along the specified key. The last existing * node on this path is returned. * * @param keyIt the key iterator * @param node the actual node * @return the last existing node on the given path */ protected ConfigurationNode findLastPathNode( DefaultConfigurationKey.KeyIterator keyIt, ConfigurationNode node) { String keyPart = keyIt.nextKey(false); if (keyIt.hasNext()) { if (!keyIt.isPropertyKey()) { // Attribute keys can only appear as last elements of the path throw new IllegalArgumentException( "Invalid path for add operation: " + "Attribute key in the middle!"); } int idx = keyIt.hasIndex() ? keyIt.getIndex() : node .getChildrenCount(keyPart) - 1; if (idx < 0 || idx >= node.getChildrenCount(keyPart)) { return node; } else { return findLastPathNode(keyIt, node.getChildren(keyPart).get(idx)); } } else { return node; } } /** * Called by {@code findNodesForKey()} to process the sub nodes of * the current node depending on the type of the current key part (children, * attributes, or both). * * @param keyPart the key part * @param subNodes a list with the sub nodes to process * @param nodes the target collection */ private void processSubNodes(DefaultConfigurationKey.KeyIterator keyPart, List subNodes, Collection nodes) { if (keyPart.hasIndex()) { if (keyPart.getIndex() >= 0 && keyPart.getIndex() < subNodes.size()) { findNodesForKey((DefaultConfigurationKey.KeyIterator) keyPart .clone(), subNodes.get(keyPart.getIndex()), nodes); } } else { for (ConfigurationNode node : subNodes) { findNodesForKey((DefaultConfigurationKey.KeyIterator) keyPart .clone(), node, nodes); } } } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ExpressionEngine.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ExpressionEngine.100644 7735 12232154102 33441 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.List; /** *

* Definition of an interface for evaluating keys for hierarchical * configurations. *

*

* An expression engine knows how to map a key for a configuration's * property to a single or a set of configuration nodes. Thus it defines the way * how properties are addressed in this configuration. Methods of a * configuration that have to handle property key (e.g. * {@code getProperty()} or {@code addProperty()} do not interpret * the passed in keys on their own, but delegate this task to an associated * expression engine. This expression engine will then find out, which * configuration nodes are addressed by the key. *

*

* Separating the task of evaluating property keys from the configuration object * has the advantage that many different expression languages (i.e. ways for * querying or setting properties) can be supported. Just set a suitable * implementation of this interface as the configuration's expression engine, * and you can use the syntax provided by this implementation. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: ExpressionEngine.java 1206474 2011-11-26 16:14:09Z oheger $ */ public interface ExpressionEngine { /** * Finds the node(s) that is (are) matched by the specified key. This is the * main method for interpreting property keys. An implementation must * traverse the given root node and its children to find all nodes that are * matched by the given key. If the key is not correct in the syntax * provided by that implementation, it is free to throw a (runtime) * exception indicating this error condition. * * @param root the root node of a hierarchy of configuration nodes * @param key the key to be evaluated * @return a list with the nodes that are matched by the key (should never * be null) */ List query(ConfigurationNode root, String key); /** * Returns the key for the specified node in the expression language * supported by an implementation. This method is called whenever a property * key for a node has to be constructed, e.g. by the * {@link org.apache.commons.configuration.Configuration#getKeys() getKeys()} * method. * * @param node the node, for which the key must be constructed * @param parentKey the key of this node's parent (can be null for * the root node) * @return this node's key */ String nodeKey(ConfigurationNode node, String parentKey); /** * Returns information needed for an add operation. This method gets called * when new properties are to be added to a configuration. An implementation * has to interpret the specified key, find the parent node for the new * elements, and provide all information about new nodes to be added. * * @param root the root node * @param key the key for the new property * @return an object with all information needed for the add operation */ NodeAddData prepareAdd(ConfigurationNode root, String key); } ././@LongLink100644 0 0 146 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/MergeCombiner.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/MergeCombiner.jav100644 13010 12232154102 33372 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.ArrayList; import java.util.Iterator; import java.util.LinkedList; import java.util.List; /** *

* A specialized implementation of the {@code NodeCombiner} interface * that performs a merge from two passed in node hierarchies. *

*

* This combiner performs the merge using a few rules: *

    *
  1. Nodes can be merged when attributes that appear in both have the same value.
  2. *
  3. Only a single node in the second file is considered a match to the node in the first file.
  4. *
  5. Attributes in nodes that match are merged. *
  6. Nodes in both files that do not match are added to the result.
  7. *
*

* * @author Commons * Configuration team * @version $Id: MergeCombiner.java 1301991 2012-03-17 20:18:02Z sebb $ * @since 1.7 */ public class MergeCombiner extends NodeCombiner { /** * Combines the given nodes to a new union node. * * @param node1 the first source node * @param node2 the second source node * @return the union node */ @Override public ConfigurationNode combine(ConfigurationNode node1, ConfigurationNode node2) { ViewNode result = createViewNode(); result.setName(node1.getName()); result.setValue(node1.getValue()); addAttributes(result, node1, node2); // Check if nodes can be combined List children2 = new LinkedList(node2.getChildren()); for (ConfigurationNode child1 : node1.getChildren()) { ConfigurationNode child2 = canCombine(node1, node2, child1, children2); if (child2 != null) { result.addChild(combine(child1, child2)); children2.remove(child2); } else { result.addChild(child1); } } // Add remaining children of node 2 for (ConfigurationNode c : children2) { result.addChild(c); } return result; } /** * Handles the attributes during a combination process. First all attributes * of the first node will be added to the result. Then all attributes of the * second node, which are not contained in the first node, will also be * added. * * @param result the resulting node * @param node1 the first node * @param node2 the second node */ protected void addAttributes(ViewNode result, ConfigurationNode node1, ConfigurationNode node2) { result.appendAttributes(node1); for (ConfigurationNode attr : node2.getAttributes()) { if (node1.getAttributeCount(attr.getName()) == 0) { result.addAttribute(attr); } } } /** * Tests if the first node can be combined with the second node. A node can * only be combined if its attributes are all present in the second node and * they all have the same value. * * @param node1 the first node * @param node2 the second node * @param child the child node (of the first node) * @return a child of the second node, with which a combination is possible */ protected ConfigurationNode canCombine(ConfigurationNode node1, ConfigurationNode node2, ConfigurationNode child, List children2) { List attrs1 = child.getAttributes(); List nodes = new ArrayList(); List children = node2.getChildren(child.getName()); Iterator it = children.iterator(); while (it.hasNext()) { ConfigurationNode node = it.next(); Iterator iter = attrs1.iterator(); while (iter.hasNext()) { ConfigurationNode attr1 = iter.next(); List list2 = node.getAttributes(attr1.getName()); if (list2.size() == 1 && !attr1.getValue().equals(list2.get(0).getValue())) { node = null; break; } } if (node != null) { nodes.add(node); } } if (nodes.size() == 1) { return nodes.get(0); } if (nodes.size() > 1 && !isListNode(child)) { Iterator iter = nodes.iterator(); while (iter.hasNext()) { children2.remove(iter.next()); } } return null; } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/NodeAddData.java100644 13301 12232154102 33110 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.Collections; import java.util.LinkedList; import java.util.List; /** *

* A simple data class used by {@link ExpressionEngine} to store * the results of the {@code prepareAdd()} operation. *

*

* If a new property is to be added to a configuration, the affected * {@code Configuration} object must know, where in its hierarchy of * configuration nodes new elements have to be added. This information is * obtained by an {@code ExpressionEngine} object that interprets the key * of the new property. This expression engine will pack all information * necessary for the configuration to perform the add operation in an instance * of this class. *

*

* Information managed by this class contains: *

    *
  • the configuration node, to which new elements must be added
  • *
  • the name of the new node
  • *
  • whether the new node is a child node or an attribute node
  • *
  • if a whole branch is to be added at once, the names of all nodes between * the parent node (the target of the add operation) and the new node
  • *
*

* * @since 1.3 * @author Commons * Configuration team * @version $Id: NodeAddData.java 1234988 2012-01-23 21:12:15Z oheger $ */ public class NodeAddData { /** Stores the parent node of the add operation. */ private ConfigurationNode parent; /** * Stores a list with nodes that are on the path between the parent node and * the new node. */ private List pathNodes; /** Stores the name of the new node. */ private String newNodeName; /** Stores the attribute flag. */ private boolean attribute; /** * Creates a new, uninitialized instance of {@code NodeAddData}. */ public NodeAddData() { this(null, null); } /** * Creates a new instance of {@code NodeAddData} and sets the most * important data fields. * * @param parent the parent node * @param nodeName the name of the new node */ public NodeAddData(ConfigurationNode parent, String nodeName) { setParent(parent); setNewNodeName(nodeName); } /** * Returns a flag if the new node to be added is an attribute. * * @return true for an attribute node, false for a child * node */ public boolean isAttribute() { return attribute; } /** * Sets the attribute flag. This flag determines whether an attribute or a * child node will be added. * * @param attribute the attribute flag */ public void setAttribute(boolean attribute) { this.attribute = attribute; } /** * Returns the name of the new node. * * @return the new node's name */ public String getNewNodeName() { return newNodeName; } /** * Sets the name of the new node. A node with this name will be added to the * configuration's node hierarchy. * * @param newNodeName the name of the new node */ public void setNewNodeName(String newNodeName) { this.newNodeName = newNodeName; } /** * Returns the parent node. * * @return the parent node */ public ConfigurationNode getParent() { return parent; } /** * Sets the parent node. New nodes will be added to this node. * * @param parent the parent node */ public void setParent(ConfigurationNode parent) { this.parent = parent; } /** * Returns a list with further nodes that must be added. This is needed if a * complete branch is to be added at once. For instance imagine that there * exists only a node {@code database}. Now the key * {@code database.connection.settings.username} (assuming the syntax * of the default expression engine) is to be added. Then * {@code username} is the name of the new node, but the nodes * {@code connection} and {@code settings} must be added to * the parent node first. In this example these names would be returned by * this method. * * @return a list with the names of nodes that must be added as parents of * the new node (never null) */ public List getPathNodes() { if (pathNodes != null) { return Collections.unmodifiableList(pathNodes); } else { return Collections.emptyList(); } } /** * Adds the name of a path node. With this method an additional node to be * added can be defined. * * @param nodeName the name of the node * @see #getPathNodes() */ public void addPathNode(String nodeName) { if (pathNodes == null) { pathNodes = new LinkedList(); } pathNodes.add(nodeName); } } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/NodeCombiner.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/NodeCombiner.java100644 10600 12232154102 33363 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.Collections; import java.util.HashSet; import java.util.Set; /** *

* A base class for node combiner implementations. *

*

* A node combiner is an object that knows how two hierarchical node * structures can be combined into a single one. Of course, there are many * possible ways of implementing such a combination, e.g. constructing a union, * an intersection, or an "override" structure (were nodes in the first * hierarchy take precedence over nodes in the second hierarchy). This abstract * base class only provides some helper methods and defines the common interface * for node combiners. Concrete sub classes will implement the diverse * combination algorithms. *

*

* For some concrete combiner implementations it is important to distinguish * whether a node is a single node or whether it belongs to a list structure. * Alone from the input structures, the combiner will not always be able to make * this decision. So sometimes it may be necessary for the developer to * configure the combiner and tell it, which nodes should be treated as list * nodes. For this purpose the {@code addListNode()} method exists. It * can be passed the name of a node, which should be considered a list node. *

* * @author Commons * Configuration team * @version $Id: NodeCombiner.java 1206476 2011-11-26 16:19:53Z oheger $ * @since 1.3 */ public abstract class NodeCombiner { /** Stores a list with node names that are known to be list nodes. */ protected Set listNodes; /** * Creates a new instance of {@code NodeCombiner}. */ public NodeCombiner() { listNodes = new HashSet(); } /** * Adds the name of a node to the list of known list nodes. This means that * nodes with this name will never be combined. * * @param nodeName the name to be added */ public void addListNode(String nodeName) { listNodes.add(nodeName); } /** * Returns a set with the names of nodes that are known to be list nodes. * * @return a set with the names of list nodes */ public Set getListNodes() { return Collections.unmodifiableSet(listNodes); } /** * Checks if a node is a list node. This implementation tests if the given * node name is contained in the set of known list nodes. Derived classes * which use different criteria may overload this method. * * @param node the node to be tested * @return a flag whether this is a list node */ public boolean isListNode(ConfigurationNode node) { return listNodes.contains(node.getName()); } /** * Combines the hierarchies represented by the given root nodes. This method * must be defined in concrete sub classes with the implementation of a * specific combination algorithm. * * @param node1 the first root node * @param node2 the second root node * @return the resulting combined node structure */ public abstract ConfigurationNode combine(ConfigurationNode node1, ConfigurationNode node2); /** * Creates a new view node. This method will be called whenever a new view * node is to be created. It can be overridden to create special view nodes. * This base implementation returns a new instance of * {@link ViewNode}. * * @return the new view node */ protected ViewNode createViewNode() { return new ViewNode(); } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/OverrideCombiner.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/OverrideCombiner.100644 12751 12232154102 33424 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; /** *

* A concrete combiner implementation that is able to construct an override * combination. *

*

* An override combination means that nodes in the first node * structure take precedence over nodes in the second, or - in other words - * nodes of the second structure are only added to the resulting structure if * they do not occur in the first one. This is especially suitable for dealing * with the properties of configurations that are defined in an * {@code override} section of a configuration definition file (hence the * name). *

*

* This combiner will iterate over the second node hierarchy and find all nodes * that are not contained in the first hierarchy; these are added to the result. * If a node can be found in both structures, it is checked whether a * combination (in a recursive way) can be constructed for the two, which will * then be added. Per default, nodes are combined, which occur only once in both * structures. This test is implemented in the {@code canCombine()} * method. *

*

* As is true for the {@link UnionCombiner}, for this combiner * list nodes are important. The {@code addListNode()} can be called to * declare certain nodes as list nodes. This has the effect that these nodes * will never be combined. *

* * @author Commons * Configuration team * @version $Id: OverrideCombiner.java 1301991 2012-03-17 20:18:02Z sebb $ * @since 1.3 */ public class OverrideCombiner extends NodeCombiner { /** * Constructs an override combination for the passed in node structures. * * @param node1 the first node * @param node2 the second node * @return the resulting combined node structure */ @Override public ConfigurationNode combine(ConfigurationNode node1, ConfigurationNode node2) { ViewNode result = createViewNode(); result.setName(node1.getName()); // Process nodes from the first structure, which override the second for (ConfigurationNode child : node1.getChildren()) { ConfigurationNode child2 = canCombine(node1, node2, child); if (child2 != null) { result.addChild(combine(child, child2)); } else { result.addChild(child); } } // Process nodes from the second structure, which are not contained // in the first structure for (ConfigurationNode child : node2.getChildren()) { if (node1.getChildrenCount(child.getName()) < 1) { result.addChild(child); } } // Handle attributes and value addAttributes(result, node1, node2); result.setValue((node1.getValue() != null) ? node1.getValue() : node2 .getValue()); return result; } /** * Handles the attributes during a combination process. First all attributes * of the first node will be added to the result. Then all attributes of the * second node, which are not contained in the first node, will also be * added. * * @param result the resulting node * @param node1 the first node * @param node2 the second node */ protected void addAttributes(ViewNode result, ConfigurationNode node1, ConfigurationNode node2) { result.appendAttributes(node1); for (ConfigurationNode attr : node2.getAttributes()) { if (node1.getAttributeCount(attr.getName()) == 0) { result.addAttribute(attr); } } } /** * Tests if a child node of the second node can be combined with the given * child node of the first node. If this is the case, the corresponding node * will be returned, otherwise null. This implementation checks * whether the child node occurs only once in both hierarchies and is no * known list node. * * @param node1 the first node * @param node2 the second node * @param child the child node (of the first node) * @return a child of the second node, with which a combination is possible */ protected ConfigurationNode canCombine(ConfigurationNode node1, ConfigurationNode node2, ConfigurationNode child) { if (node2.getChildrenCount(child.getName()) == 1 && node1.getChildrenCount(child.getName()) == 1 && !isListNode(child)) { return node2.getChildren(child.getName()).get(0); } else { return null; } } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/package.html100644 2033 12232154102 32416 0ustarhenningstaff 0 0

A package with helper and utility classes used by hierarchical configurations.

$Id: package.html 439648 2006-09-02 20:42:10Z oheger $

commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/TreeUtils.java100644 5205 12232154102 32724 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.io.PrintStream; import java.util.Iterator; /** * Utility methods. * @author Commons * Configuration team * @version $Id: TreeUtils.java 1301991 2012-03-17 20:18:02Z sebb $ * @since 1.7 */ public final class TreeUtils { /** Prevent creating this class. */ private TreeUtils() { } /** * Print out the data in the configuration. * @param stream The OutputStream. * @param result The root node of the tree. */ public static void printTree(PrintStream stream, ConfigurationNode result) { if (stream != null) { printTree(stream, "", result); } } private static void printTree(PrintStream stream, String indent, ConfigurationNode result) { StringBuffer buffer = new StringBuffer(indent).append("<").append(result.getName()); Iterator iter = result.getAttributes().iterator(); while (iter.hasNext()) { ConfigurationNode node = iter.next(); buffer.append(" ").append(node.getName()).append("='").append(node.getValue()).append("'"); } buffer.append(">"); stream.print(buffer.toString()); if (result.getValue() != null) { stream.print(result.getValue()); } boolean newline = false; if (result.getChildrenCount() > 0) { stream.print("\n"); iter = result.getChildren().iterator(); while (iter.hasNext()) { printTree(stream, indent + " ", iter.next()); } newline = true; } if (newline) { stream.print(indent); } stream.println(""); } } ././@LongLink100644 0 0 146 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/UnionCombiner.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/UnionCombiner.jav100644 16205 12232154102 33434 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import java.util.LinkedList; import java.util.List; /** *

* A specialized implementation of the {@code NodeCombiner} interface * that constructs a union from two passed in node hierarchies. *

*

* The given source hierarchies are traversed and their nodes are added to the * resulting structure. Under some circumstances two nodes can be combined * rather than adding both. This is the case if both nodes are single children * (no lists) of their parents and do not have values. The corresponding check * is implemented in the {@code findCombineNode()} method. *

*

* Sometimes it is not possible for this combiner to detect whether two nodes * can be combined or not. Consider the following two node hierarchies: *

*

* *

 * Hierarchy 1:
 *
 * Database
 *   +--Tables
 *        +--Table
 *             +--name [users]
 *             +--fields
 *                   +--field
 *                   |    +--name [uid]
 *                   +--field
 *                   |    +--name [usrname]
 *                     ...
 * 
* *

*

* *

 * Hierarchy 2:
 *
 * Database
 *   +--Tables
 *        +--Table
 *             +--name [documents]
 *             +--fields
 *                   +--field
 *                   |    +--name [docid]
 *                   +--field
 *                   |    +--name [docname]
 *                     ...
 * 
* *

*

* Both hierarchies contain data about database tables. Each describes a single * table. If these hierarchies are to be combined, the result should probably * look like the following: *

* *

 * Database
 *   +--Tables
 *        +--Table
 *        |    +--name [users]
 *        |    +--fields
 *        |          +--field
 *        |          |    +--name [uid]
 *        |            ...
 *        +--Table
 *             +--name [documents]
 *             +--fields
 *                   +--field
 *                   |    +--name [docid]
 *                     ...
 * 
* *

*

* i.e. the {@code Tables} nodes should be combined, while the * {@code Table} nodes should both be added to the resulting tree. From * the combiner's point of view there is no difference between the * {@code Tables} and the {@code Table} nodes in the source trees, * so the developer has to help out and give a hint that the {@code Table} * nodes belong to a list structure. This can be done using the * {@code addListNode()} method; this method expects the name of a node, * which should be treated as a list node. So if * {@code addListNode("Table");} was called, the combiner knows that it * must not combine the {@code Table} nodes, but add it both to the * resulting tree. *

* * @author Commons * Configuration team * @version $Id: UnionCombiner.java 1206486 2011-11-26 16:41:12Z oheger $ * @since 1.3 */ public class UnionCombiner extends NodeCombiner { /** * Combines the given nodes to a new union node. * * @param node1 the first source node * @param node2 the second source node * @return the union node */ @Override public ConfigurationNode combine(ConfigurationNode node1, ConfigurationNode node2) { ViewNode result = createViewNode(); result.setName(node1.getName()); result.appendAttributes(node1); result.appendAttributes(node2); // Check if nodes can be combined List children2 = new LinkedList(node2.getChildren()); for (ConfigurationNode child1 : node1.getChildren()) { ConfigurationNode child2 = findCombineNode(node1, node2, child1, children2); if (child2 != null) { result.addChild(combine(child1, child2)); children2.remove(child2); } else { result.addChild(child1); } } // Add remaining children of node 2 for (ConfigurationNode c : children2) { result.addChild(c); } return result; } /** *

* Tries to find a child node of the second source node, with which a child * of the first source node can be combined. During combining of the source * nodes an iteration over the first source node's children is performed. * For each child node it is checked whether a corresponding child node in * the second source node exists. If this is the case, these corresponding * child nodes are recursively combined and the result is added to the * combined node. This method implements the checks whether such a recursive * combination is possible. The actual implementation tests the following * conditions: *

*

*

    *
  • In both the first and the second source node there is only one child * node with the given name (no list structures).
  • *
  • The given name is not in the list of known list nodes, i.e. it was * not passed to the {@code addListNode()} method.
  • *
  • None of these matching child nodes has a value.
  • *
*

*

* If all of these tests are successful, the matching child node of the * second source node is returned. Otherwise the result is null. *

* * @param node1 the first source node * @param node2 the second source node * @param child the child node of the first source node to be checked * @param children a list with all children of the second source node * @return the matching child node of the second source node or null * if there is none */ protected ConfigurationNode findCombineNode(ConfigurationNode node1, ConfigurationNode node2, ConfigurationNode child, List children) { if (child.getValue() == null && !isListNode(child) && node1.getChildrenCount(child.getName()) == 1 && node2.getChildrenCount(child.getName()) == 1) { ConfigurationNode child2 = node2.getChildren( child.getName()).iterator().next(); if (child2.getValue() == null) { return child2; } } return null; } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ViewNode.java100644 7014 12232154102 32524 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; /** *

* A specialized node implementation to be used in view configurations. *

*

* Some configurations provide a logical view on the nodes of other * configurations. These configurations construct their own hierarchy of nodes * based on the node trees of their source configurations. This special node * class can be used for this purpose. It allows child nodes and attributes to * be added without changing their parent node. So a node can belong to a * hierarchy of nodes of a source configuration, but be also contained in a view * configuration. *

* * @author Commons * Configuration team * @version $Id: ViewNode.java 1206488 2011-11-26 16:42:41Z oheger $ * @since 1.3 */ public class ViewNode extends DefaultConfigurationNode { /** * Adds an attribute to this view node. The new attribute's parent node will * be saved. * * @param attr the attribute node to be added */ @Override public void addAttribute(ConfigurationNode attr) { ConfigurationNode parent = null; if (attr != null) { parent = attr.getParentNode(); super.addAttribute(attr); attr.setParentNode(parent); } else { throw new IllegalArgumentException("Attribute node must not be null!"); } } /** * Adds a child node to this view node. The new child's parent node will be * saved. * * @param child the child node to be added */ @Override public void addChild(ConfigurationNode child) { ConfigurationNode parent = null; if (child != null) { parent = child.getParentNode(); super.addChild(child); child.setParentNode(parent); } else { throw new IllegalArgumentException("Child node must not be null!"); } } /** * Adds all attribute nodes of the given source node to this view node. * * @param source the source node */ public void appendAttributes(ConfigurationNode source) { if (source != null) { for (ConfigurationNode attr : source.getAttributes()) { addAttribute(attr); } } } /** * Adds all child nodes of the given source node to this view node. * * @param source the source node */ public void appendChildren(ConfigurationNode source) { if (source != null) { for (ConfigurationNode child : source.getChildren()) { addChild(child); } } } } ././@LongLink100644 0 0 201 12232154257 10247 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorAttribute.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/Configurati100644 5404 12232154102 33463 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.jxpath.ri.QName; import org.apache.commons.jxpath.ri.model.NodePointer; /** * A specialized node iterator implementation that deals with attribute nodes. * * @author Commons * Configuration team * @version $Id: ConfigurationNodeIteratorAttribute.java 1206492 2011-11-26 16:52:16Z oheger $ */ class ConfigurationNodeIteratorAttribute extends ConfigurationNodeIteratorBase { /** Constant for the wildcard node name.*/ private static final String WILDCARD = "*"; /** * Creates a new instance of {@code ConfigurationNodeIteratorAttribute}. * @param parent the parent node pointer * @param name the name of the selected attribute */ public ConfigurationNodeIteratorAttribute(NodePointer parent, QName name) { super(parent, false); initSubNodeList(createSubNodeList((ConfigurationNode) parent.getNode(), name)); } /** * Determines which attributes are selected based on the passed in node * name. * @param node the current node * @param name the name of the selected attribute * @return a list with the selected attributes */ protected List createSubNodeList(ConfigurationNode node, QName name) { if (name.getPrefix() != null) { // namespace prefixes are not supported return Collections.emptyList(); } List result = new ArrayList(); if (!WILDCARD.equals(name.getName())) { result.addAll(node.getAttributes(name.getName())); } else { result.addAll(node.getAttributes()); } return result; } } ././@LongLink100644 0 0 174 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorBase.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/Configurati100644 12431 12232154102 33501 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import java.util.List; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.jxpath.ri.model.NodeIterator; import org.apache.commons.jxpath.ri.model.NodePointer; /** *

* A base class for implementing iterators over configuration nodes. *

*

* This class already provides common functionality for implementing the * iteration process. Derived classes will implement specific behavior based on * the concrete node type (child node or attribute node). *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: ConfigurationNodeIteratorBase.java 1206491 2011-11-26 16:51:50Z oheger $ */ abstract class ConfigurationNodeIteratorBase implements NodeIterator { /** Stores the parent node pointer. */ private NodePointer parent; /** Stores the list with the sub nodes. */ private List subNodes; /** Stores the current position. */ private int position; /** Stores the start offset of the iterator. */ private int startOffset; /** Stores the reverse flag. */ private boolean reverse; /** * Creates a new instance of {@code ConfigurationNodeIteratorBase} * and initializes it. * * @param parent the parent pointer * @param reverse the reverse flag */ protected ConfigurationNodeIteratorBase(NodePointer parent, boolean reverse) { this.parent = parent; this.reverse = reverse; } /** * Returns the position of the iteration. * * @return the position */ public int getPosition() { return position; } /** * Sets the position of the iteration. * * @param pos the new position * @return a flag if this is a valid position */ public boolean setPosition(int pos) { position = pos; return pos >= 1 && pos <= getMaxPosition(); } /** * Returns the current node pointer. * * @return the current pointer in this iteration */ public NodePointer getNodePointer() { if (getPosition() < 1 && !setPosition(1)) { return null; } return createNodePointer(subNodes.get(positionToIndex(getPosition()))); } /** * Returns the parent node pointer. * * @return the parent node pointer */ protected NodePointer getParent() { return parent; } /** * Returns the start offset of the iteration. * * @return the start offset */ protected int getStartOffset() { return startOffset; } /** * Sets the start offset of the iteration. This is used when a start element * was set. * * @param startOffset the start offset */ protected void setStartOffset(int startOffset) { this.startOffset = startOffset; if (reverse) { this.startOffset--; } else { this.startOffset++; } } /** * Initializes the list of sub nodes for the iteration. This method must be * called during initialization phase. * * @param nodes the list with the sub nodes */ protected void initSubNodeList(List nodes) { subNodes = nodes; if (reverse) { setStartOffset(subNodes.size()); } } /** * Returns the maximum position for this iterator. * * @return the maximum allowed position */ protected int getMaxPosition() { return reverse ? getStartOffset() + 1 : subNodes.size() - getStartOffset(); } /** * Creates the configuration node pointer for the current position. This * method is called by {@code getNodePointer()}. Derived classes * must create the correct pointer object. * * @param node the current configuration node * @return the node pointer */ protected NodePointer createNodePointer(ConfigurationNode node) { return new ConfigurationNodePointer(getParent(), node); } /** * Returns the index in the data list for the given position. This method * also checks the reverse flag. * * @param pos the position (1-based) * @return the corresponding list index */ protected int positionToIndex(int pos) { return (reverse ? 1 - pos : pos - 1) + getStartOffset(); } } ././@LongLink100644 0 0 200 12232154257 10246 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodeIteratorChildren.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/Configurati100644 11653 12232154102 33506 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import java.util.ArrayList; import java.util.Collections; import java.util.List; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.jxpath.ri.Compiler; import org.apache.commons.jxpath.ri.QName; import org.apache.commons.jxpath.ri.compiler.NodeNameTest; import org.apache.commons.jxpath.ri.compiler.NodeTest; import org.apache.commons.jxpath.ri.compiler.NodeTypeTest; import org.apache.commons.jxpath.ri.model.NodePointer; import org.apache.commons.lang.StringUtils; /** * A specialized iterator implementation for the child nodes of a configuration * node. * * @since 1.3 * @author Commons * Configuration team * @version $Id: ConfigurationNodeIteratorChildren.java 1206493 2011-11-26 16:56:42Z oheger $ */ class ConfigurationNodeIteratorChildren extends ConfigurationNodeIteratorBase { /** * Creates a new instance of {@code ConfigurationNodeIteratorChildren} * and initializes it. * * @param parent the parent pointer * @param nodeTest the test selecting the sub nodes * @param reverse the reverse flag * @param startsWith the first element of the iteration */ public ConfigurationNodeIteratorChildren(NodePointer parent, NodeTest nodeTest, boolean reverse, NodePointer startsWith) { super(parent, reverse); ConfigurationNode root = (ConfigurationNode) parent.getNode(); List childNodes = createSubNodeList(root, nodeTest); initSubNodeList(childNodes); if (startsWith != null) { setStartOffset(findStartIndex(root, (ConfigurationNode) startsWith.getNode())); } } /** * Creates the list with sub nodes. This method gets called during * initialization phase. It finds out, based on the given test, which nodes * must be iterated over. * * @param node the current node * @param test the test object * @return a list with the matching nodes */ protected List createSubNodeList(ConfigurationNode node, NodeTest test) { List children = node.getChildren(); if (test == null) { return children; } else { if (test instanceof NodeNameTest) { NodeNameTest nameTest = (NodeNameTest) test; QName name = nameTest.getNodeName(); if (name.getPrefix() == null) { if (nameTest.isWildcard()) { return children; } List result = new ArrayList(); for (ConfigurationNode child : children) { if (StringUtils.equals(name.getName(), child.getName())) { result.add(child); } } return result; } } else if (test instanceof NodeTypeTest) { NodeTypeTest typeTest = (NodeTypeTest) test; if (typeTest.getNodeType() == Compiler.NODE_TYPE_NODE || typeTest.getNodeType() == Compiler.NODE_TYPE_TEXT) { return children; } } } return Collections.emptyList(); } /** * Determines the start position of the iteration. Finds the index of the * given start node in the children of the root node. * * @param node the root node * @param startNode the start node * @return the start node's index */ protected int findStartIndex(ConfigurationNode node, ConfigurationNode startNode) { for (int index = 0; index < node.getChildrenCount(); index++) { if (node.getChild(index) == startNode) { return index; } } return -1; } } ././@LongLink100644 0 0 167 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointer.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/Configurati100644 16040 12232154102 33501 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import java.util.List; import java.util.Locale; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.jxpath.ri.Compiler; import org.apache.commons.jxpath.ri.QName; import org.apache.commons.jxpath.ri.compiler.NodeTest; import org.apache.commons.jxpath.ri.compiler.NodeTypeTest; import org.apache.commons.jxpath.ri.model.NodeIterator; import org.apache.commons.jxpath.ri.model.NodePointer; /** *

* A specific {@code NodePointer} implementation for configuration nodes. *

*

* This is needed for queries using JXPath. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: ConfigurationNodePointer.java 1206496 2011-11-26 17:01:14Z oheger $ */ class ConfigurationNodePointer extends NodePointer { /** * The serial version UID. */ private static final long serialVersionUID = -1087475639680007713L; /** Stores the associated configuration node. */ private ConfigurationNode node; /** * Creates a new instance of {@code ConfigurationNodePointer}. * * @param node the node * @param locale the locale */ public ConfigurationNodePointer(ConfigurationNode node, Locale locale) { super(null, locale); this.node = node; } /** * Creates a new instance of {@code ConfigurationNodePointer} and * initializes it with its parent pointer. * * @param parent the parent pointer * @param node the associated node */ public ConfigurationNodePointer(NodePointer parent, ConfigurationNode node) { super(parent); this.node = node; } /** * Returns a flag whether this node is a leaf. This is the case if there are * no child nodes. * * @return a flag if this node is a leaf */ @Override public boolean isLeaf() { return node.getChildrenCount() < 1; } /** * Returns a flag if this node is a collection. This is not the case. * * @return the collection flag */ @Override public boolean isCollection() { return false; } /** * Returns this node's length. This is always 1. * * @return the node's length */ @Override public int getLength() { return 1; } /** * Checks whether this node pointer refers to an attribute node. This method * checks the attribute flag of the associated configuration node. * * @return the attribute flag */ @Override public boolean isAttribute() { return node.isAttribute(); } /** * Returns this node's name. * * @return the name */ @Override public QName getName() { return new QName(null, node.getName()); } /** * Returns this node's base value. This is the associated configuration * node. * * @return the base value */ @Override public Object getBaseValue() { return node; } /** * Returns the immediate node. This is the associated configuration node. * * @return the immediate node */ @Override public Object getImmediateNode() { return node; } /** * Returns the value of this node. * * @return the represented node's value */ @Override public Object getValue() { return node.getValue(); } /** * Sets the value of this node. * * @param value the new value */ @Override public void setValue(Object value) { node.setValue(value); } /** * Compares two child node pointers. * * @param pointer1 one pointer * @param pointer2 another pointer * @return a flag, which pointer should be sorted first */ @Override public int compareChildNodePointers(NodePointer pointer1, NodePointer pointer2) { ConfigurationNode node1 = (ConfigurationNode) pointer1.getBaseValue(); ConfigurationNode node2 = (ConfigurationNode) pointer2.getBaseValue(); // attributes will be sorted before child nodes if (node1.isAttribute() && !node2.isAttribute()) { return -1; } else if (node2.isAttribute() && !node1.isAttribute()) { return 1; } else { // sort based on the occurrence in the sub node list List subNodes = node1.isAttribute() ? node.getAttributes() : node .getChildren(); for (ConfigurationNode child : subNodes) { if (child == node1) { return -1; } else if (child == node2) { return 1; } } return 0; // should not happen } } /** * Returns an iterator for the attributes that match the given name. * * @param name the attribute name * @return the iterator for the attributes */ @Override public NodeIterator attributeIterator(QName name) { return new ConfigurationNodeIteratorAttribute(this, name); } /** * Returns an iterator for the children of this pointer that match the given * test object. * * @param test the test object * @param reverse the reverse flag * @param startWith the start value of the iteration */ @Override public NodeIterator childIterator(NodeTest test, boolean reverse, NodePointer startWith) { return new ConfigurationNodeIteratorChildren(this, test, reverse, startWith); } /** * Tests if this node matches the given test. Configuration nodes are text * nodes, too because they can contain a value. * * @param test the test object * @return a flag if this node corresponds to the test */ @Override public boolean testNode(NodeTest test) { if (test instanceof NodeTypeTest && ((NodeTypeTest) test).getNodeType() == Compiler.NODE_TYPE_TEXT) { return true; } return super.testNode(test); } } ././@LongLink100644 0 0 176 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/ConfigurationNodePointerFactory.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/Configurati100644 6040 12232154102 33460 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import java.util.Locale; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.jxpath.ri.QName; import org.apache.commons.jxpath.ri.model.NodePointer; import org.apache.commons.jxpath.ri.model.NodePointerFactory; /** * Implementation of the {@code NodePointerFactory} interface for * configuration nodes. * * @since 1.3 * @author Commons * Configuration team * @version $Id: ConfigurationNodePointerFactory.java 1206498 2011-11-26 17:01:58Z oheger $ */ public class ConfigurationNodePointerFactory implements NodePointerFactory { /** Constant for the order of this factory. */ public static final int CONFIGURATION_NODE_POINTER_FACTORY_ORDER = 200; /** * Returns the order of this factory between other factories. * * @return this order's factory */ public int getOrder() { return CONFIGURATION_NODE_POINTER_FACTORY_ORDER; } /** * Creates a node pointer for the specified bean. If the bean is a * configuration node, a corresponding pointer is returned. * * @param name the name of the node * @param bean the bean * @param locale the locale * @return a pointer for a configuration node if the bean is such a node */ public NodePointer createNodePointer(QName name, Object bean, Locale locale) { if (bean instanceof ConfigurationNode) { return new ConfigurationNodePointer((ConfigurationNode) bean, locale); } return null; } /** * Creates a node pointer for the specified bean. If the bean is a * configuration node, a corresponding pointer is returned. * * @param parent the parent node * @param name the name * @param bean the bean * @return a pointer for a configuration node if the bean is such a node */ public NodePointer createNodePointer(NodePointer parent, QName name, Object bean) { if (bean instanceof ConfigurationNode) { return new ConfigurationNodePointer(parent, (ConfigurationNode) bean); } return null; } } ././@LongLink100644 0 0 146 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/package.htmlcommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/package.htm100644 2134 12232154102 33370 0ustarhenningstaff 0 0

This package contains the implementation of the XPathExpressionEngine class, which enables XPATH support for querying configuration properties.

$Id: package.html 439648 2006-09-02 20:42:10Z oheger $

././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/XPathExpressionEngine.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/XPathExpres100644 35020 12232154102 33441 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import java.util.Collections; import java.util.List; import java.util.StringTokenizer; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.ExpressionEngine; import org.apache.commons.configuration.tree.NodeAddData; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl; import org.apache.commons.lang.StringUtils; /** *

* A specialized implementation of the {@code ExpressionEngine} interface * that is able to evaluate XPATH expressions. *

*

* This class makes use of Commons * JXPath for handling XPath expressions and mapping them to the nodes of a * hierarchical configuration. This makes the rich and powerful XPATH syntax * available for accessing properties from a configuration object. *

*

* For selecting properties arbitrary XPATH expressions can be used, which * select single or multiple configuration nodes. The associated * {@code Configuration} instance will directly pass the specified property * keys into this engine. If a key is not syntactically correct, an exception * will be thrown. *

*

* For adding new properties, this expression engine uses a specific syntax: the * "key" of a new property must consist of two parts that are * separated by whitespace: *

    *
  1. An XPATH expression selecting a single node, to which the new element(s) * are to be added. This can be an arbitrary complex expression, but it must * select exactly one node, otherwise an exception will be thrown.
  2. *
  3. The name of the new element(s) to be added below this parent node. Here * either a single node name or a complete path of nodes (separated by the * "/" character or "@" for an attribute) can be specified.
  4. *
* Some examples for valid keys that can be passed into the configuration's * {@code addProperty()} method follow: *

*

* *

 * "/tables/table[1] type"
 * 
* *

*

* This will add a new {@code type} node as a child of the first * {@code table} element. *

*

* *

 * "/tables/table[1] @type"
 * 
* *

*

* Similar to the example above, but this time a new attribute named * {@code type} will be added to the first {@code table} element. *

*

* *

 * "/tables table/fields/field/name"
 * 
* *

*

* This example shows how a complex path can be added. Parent node is the * {@code tables} element. Here a new branch consisting of the nodes * {@code table}, {@code fields}, {@code field}, and * {@code name} will be added. *

*

* *

 * "/tables table/fields/field@type"
 * 
* *

*

* This is similar to the last example, but in this case a complex path ending * with an attribute is defined. *

*

* Note: This extended syntax for adding properties only works * with the {@code addProperty()} method. {@code setProperty()} does * not support creating new nodes this way. *

*

* From version 1.7 on, it is possible to use regular keys in calls to * {@code addProperty()} (i.e. keys that do not have to contain a * whitespace as delimiter). In this case the key is evaluated, and the biggest * part pointing to an existing node is determined. The remaining part is then * added as new path. As an example consider the key * *

 * "tables/table[last()]/fields/field/name"
 * 
* * If the key does not point to an existing node, the engine will check the * paths {@code "tables/table[last()]/fields/field"}, * {@code "tables/table[last()]/fields"}, * {@code "tables/table[last()]"}, and so on, until a key is * found which points to a node. Let's assume that the last key listed above can * be resolved in this way. Then from this key the following key is derived: * {@code "tables/table[last()] fields/field/name"} by appending * the remaining part after a whitespace. This key can now be processed using * the original algorithm. Keys of this form can also be used with the * {@code setProperty()} method. However, it is still recommended to use * the old format because it makes explicit at which position new nodes should * be added. For keys without a whitespace delimiter there may be ambiguities. *

* * @since 1.3 * @author Commons * Configuration team * @version $Id: XPathExpressionEngine.java 1206563 2011-11-26 19:47:26Z oheger $ */ public class XPathExpressionEngine implements ExpressionEngine { /** Constant for the path delimiter. */ static final String PATH_DELIMITER = "/"; /** Constant for the attribute delimiter. */ static final String ATTR_DELIMITER = "@"; /** Constant for the delimiters for splitting node paths. */ private static final String NODE_PATH_DELIMITERS = PATH_DELIMITER + ATTR_DELIMITER; /** * Constant for a space which is used as delimiter in keys for adding * properties. */ private static final String SPACE = " "; /** * Executes a query. The passed in property key is directly passed to a * JXPath context. * * @param root the configuration root node * @param key the query to be executed * @return a list with the nodes that are selected by the query */ public List query(ConfigurationNode root, String key) { if (StringUtils.isEmpty(key)) { return Collections.singletonList(root); } else { JXPathContext context = createContext(root, key); // This is safe because our node pointer implementations will return // a list of configuration nodes. @SuppressWarnings("unchecked") List result = context.selectNodes(key); if (result == null) { result = Collections.emptyList(); } return result; } } /** * Returns a (canonical) key for the given node based on the parent's key. * This implementation will create an XPATH expression that selects the * given node (under the assumption that the passed in parent key is valid). * As the {@code nodeKey()} implementation of * {@link org.apache.commons.configuration.tree.DefaultExpressionEngine DefaultExpressionEngine} * this method will not return indices for nodes. So all child nodes of a * given parent with the same name will have the same key. * * @param node the node for which a key is to be constructed * @param parentKey the key of the parent node * @return the key for the given node */ public String nodeKey(ConfigurationNode node, String parentKey) { if (parentKey == null) { // name of the root node return StringUtils.EMPTY; } else if (node.getName() == null) { // paranoia check for undefined node names return parentKey; } else { StringBuilder buf = new StringBuilder(parentKey.length() + node.getName().length() + PATH_DELIMITER.length()); if (parentKey.length() > 0) { buf.append(parentKey); buf.append(PATH_DELIMITER); } if (node.isAttribute()) { buf.append(ATTR_DELIMITER); } buf.append(node.getName()); return buf.toString(); } } /** * Prepares an add operation for a configuration property. The expected * format of the passed in key is explained in the class comment. * * @param root the configuration's root node * @param key the key describing the target of the add operation and the * path of the new node * @return a data object to be evaluated by the calling configuration object */ public NodeAddData prepareAdd(ConfigurationNode root, String key) { if (key == null) { throw new IllegalArgumentException( "prepareAdd: key must not be null!"); } String addKey = key; int index = findKeySeparator(addKey); if (index < 0) { addKey = generateKeyForAdd(root, addKey); index = findKeySeparator(addKey); } List nodes = query(root, addKey.substring(0, index).trim()); if (nodes.size() != 1) { throw new IllegalArgumentException( "prepareAdd: key must select exactly one target node!"); } NodeAddData data = new NodeAddData(); data.setParent(nodes.get(0)); initNodeAddData(data, addKey.substring(index).trim()); return data; } /** * Creates the {@code JXPathContext} used for executing a query. This * method will create a new context and ensure that it is correctly * initialized. * * @param root the configuration root node * @param key the key to be queried * @return the new context */ protected JXPathContext createContext(ConfigurationNode root, String key) { JXPathContext context = JXPathContext.newContext(root); context.setLenient(true); return context; } /** * Initializes most properties of a {@code NodeAddData} object. This * method is called by {@code prepareAdd()} after the parent node has * been found. Its task is to interpret the passed in path of the new node. * * @param data the data object to initialize * @param path the path of the new node */ protected void initNodeAddData(NodeAddData data, String path) { String lastComponent = null; boolean attr = false; boolean first = true; StringTokenizer tok = new StringTokenizer(path, NODE_PATH_DELIMITERS, true); while (tok.hasMoreTokens()) { String token = tok.nextToken(); if (PATH_DELIMITER.equals(token)) { if (attr) { invalidPath(path, " contains an attribute" + " delimiter at an unallowed position."); } if (lastComponent == null) { invalidPath(path, " contains a '/' at an unallowed position."); } data.addPathNode(lastComponent); lastComponent = null; } else if (ATTR_DELIMITER.equals(token)) { if (attr) { invalidPath(path, " contains multiple attribute delimiters."); } if (lastComponent == null && !first) { invalidPath(path, " contains an attribute delimiter at an unallowed position."); } if (lastComponent != null) { data.addPathNode(lastComponent); } attr = true; lastComponent = null; } else { lastComponent = token; } first = false; } if (lastComponent == null) { invalidPath(path, "contains no components."); } data.setNewNodeName(lastComponent); data.setAttribute(attr); } /** * Tries to generate a key for adding a property. This method is called if a * key was used for adding properties which does not contain a space * character. It splits the key at its single components and searches for * the last existing component. Then a key compatible for adding properties * is generated. * * @param root the root node of the configuration * @param key the key in question * @return the key to be used for adding the property */ private String generateKeyForAdd(ConfigurationNode root, String key) { int pos = key.lastIndexOf(PATH_DELIMITER, key.length()); while (pos >= 0) { String keyExisting = key.substring(0, pos); if (!query(root, keyExisting).isEmpty()) { StringBuilder buf = new StringBuilder(key.length() + 1); buf.append(keyExisting).append(SPACE); buf.append(key.substring(pos + 1)); return buf.toString(); } pos = key.lastIndexOf(PATH_DELIMITER, pos - 1); } return SPACE + key; } /** * Helper method for throwing an exception about an invalid path. * * @param path the invalid path * @param msg the exception message */ private void invalidPath(String path, String msg) { throw new IllegalArgumentException("Invalid node path: \"" + path + "\" " + msg); } /** * Determines the position of the separator in a key for adding new * properties. If no delimiter is found, result is -1. * * @param key the key * @return the position of the delimiter */ private static int findKeySeparator(String key) { int index = key.length() - 1; while (index >= 0 && !Character.isWhitespace(key.charAt(index))) { index--; } return index; } // static initializer: registers the configuration node pointer factory static { JXPathContextReferenceImpl .addNodePointerFactory(new ConfigurationNodePointerFactory()); } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/VerifiableOutputStream.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/VerifiableOutputStream100644 2307 12232154103 33573 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.OutputStream; import java.io.IOException; /** * OutputStream that can be checked for errors after it is written to. * @since 1.7 * @author Commons Configuration team */ abstract class VerifiableOutputStream extends OutputStream { public abstract void verify() throws IOException; } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/VFSFileSystem.java100644 31760 12232154103 32536 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.lang.reflect.Method; import java.net.MalformedURLException; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.Map; import org.apache.commons.vfs2.FileContent; import org.apache.commons.vfs2.FileName; import org.apache.commons.vfs2.FileObject; import org.apache.commons.vfs2.FileSystemConfigBuilder; import org.apache.commons.vfs2.FileSystemException; import org.apache.commons.vfs2.FileSystemManager; import org.apache.commons.vfs2.FileSystemOptions; import org.apache.commons.vfs2.FileType; import org.apache.commons.vfs2.VFS; import org.apache.commons.vfs2.provider.UriParser; /** * FileSystem that uses Commons VFS * @since 1.7 * @author Commons Configuration team * @version $Id: VFSFileSystem.java 1210205 2011-12-04 20:38:19Z oheger $ */ public class VFSFileSystem extends DefaultFileSystem { public VFSFileSystem() { } @Override public InputStream getInputStream(String basePath, String fileName) throws ConfigurationException { try { FileSystemManager manager = VFS.getManager(); FileName path; if (basePath != null) { FileName base = manager.resolveURI(basePath); path = manager.resolveName(base, fileName); } else { FileName file = manager.resolveURI(fileName); FileName base = file.getParent(); path = manager.resolveName(base, file.getBaseName()); } FileSystemOptions opts = getOptions(path.getScheme()); FileObject file = (opts == null) ? manager.resolveFile(path.getURI()) : manager.resolveFile(path.getURI(), opts); FileContent content = file.getContent(); if (content == null) { String msg = "Cannot access content of " + file.getName().getFriendlyURI(); throw new ConfigurationException(msg); } return content.getInputStream(); } catch (ConfigurationException e) { throw e; } catch (Exception e) { throw new ConfigurationException("Unable to load the configuration file " + fileName, e); } } @Override public InputStream getInputStream(URL url) throws ConfigurationException { FileObject file; try { FileSystemOptions opts = getOptions(url.getProtocol()); file = (opts == null) ? VFS.getManager().resolveFile(url.toString()) : VFS.getManager().resolveFile(url.toString(), opts); if (file.getType() != FileType.FILE) { throw new ConfigurationException("Cannot load a configuration from a directory"); } FileContent content = file.getContent(); if (content == null) { String msg = "Cannot access content of " + file.getName().getFriendlyURI(); throw new ConfigurationException(msg); } return content.getInputStream(); } catch (FileSystemException fse) { String msg = "Unable to access " + url.toString(); throw new ConfigurationException(msg, fse); } } @Override public OutputStream getOutputStream(URL url) throws ConfigurationException { try { FileSystemOptions opts = getOptions(url.getProtocol()); FileSystemManager fsManager = VFS.getManager(); FileObject file = (opts == null) ? fsManager.resolveFile(url.toString()) : fsManager.resolveFile(url.toString(), opts); // throw an exception if the target URL is a directory if (file == null || file.getType() == FileType.FOLDER) { throw new ConfigurationException("Cannot save a configuration to a directory"); } FileContent content = file.getContent(); if (content == null) { throw new ConfigurationException("Cannot access content of " + url); } return content.getOutputStream(); } catch (FileSystemException fse) { throw new ConfigurationException("Unable to access " + url, fse); } } @Override public String getPath(File file, URL url, String basePath, String fileName) { if (file != null) { return super.getPath(file, url, basePath, fileName); } try { FileSystemManager fsManager = VFS.getManager(); if (url != null) { FileName name = fsManager.resolveURI(url.toString()); if (name != null) { return name.toString(); } } if (UriParser.extractScheme(fileName) != null) { return fileName; } else if (basePath != null) { FileName base = fsManager.resolveURI(basePath); return fsManager.resolveName(base, fileName).getURI(); } else { FileName name = fsManager.resolveURI(fileName); FileName base = name.getParent(); return fsManager.resolveName(base, name.getBaseName()).getURI(); } } catch (FileSystemException fse) { fse.printStackTrace(); return null; } } @Override public String getBasePath(String path) { if (UriParser.extractScheme(path) == null) { return super.getBasePath(path); } try { FileSystemManager fsManager = VFS.getManager(); FileName name = fsManager.resolveURI(path); return name.getParent().getURI(); } catch (FileSystemException fse) { fse.printStackTrace(); return null; } } @Override public String getFileName(String path) { if (UriParser.extractScheme(path) == null) { return super.getFileName(path); } try { FileSystemManager fsManager = VFS.getManager(); FileName name = fsManager.resolveURI(path); return name.getBaseName(); } catch (FileSystemException fse) { fse.printStackTrace(); return null; } } @Override public URL getURL(String basePath, String file) throws MalformedURLException { if ((basePath != null && UriParser.extractScheme(basePath) == null) || (basePath == null && UriParser.extractScheme(file) == null)) { return super.getURL(basePath, file); } try { FileSystemManager fsManager = VFS.getManager(); FileName path; if (basePath != null && UriParser.extractScheme(file) == null) { FileName base = fsManager.resolveURI(basePath); path = fsManager.resolveName(base, file); } else { path = fsManager.resolveURI(file); } URLStreamHandler handler = new VFSURLStreamHandler(path); return new URL(null, path.getURI(), handler); } catch (FileSystemException fse) { throw new ConfigurationRuntimeException("Could not parse basePath: " + basePath + " and fileName: " + file, fse); } } @Override public URL locateFromURL(String basePath, String fileName) { String fileScheme = UriParser.extractScheme(fileName); // Use DefaultFileSystem if basePath and fileName don't have a scheme. if ((basePath == null || UriParser.extractScheme(basePath) == null) && fileScheme == null) { return super.locateFromURL(basePath, fileName); } try { FileSystemManager fsManager = VFS.getManager(); FileObject file; // Only use the base path if the file name doesn't have a scheme. if (basePath != null && fileScheme == null) { String scheme = UriParser.extractScheme(basePath); FileSystemOptions opts = (scheme != null) ? getOptions(scheme) : null; FileObject base = (opts == null) ? fsManager.resolveFile(basePath) : fsManager.resolveFile(basePath, opts); if (base.getType() == FileType.FILE) { base = base.getParent(); } file = fsManager.resolveFile(base, fileName); } else { FileSystemOptions opts = (fileScheme != null) ? getOptions(fileScheme) : null; file = (opts == null) ? fsManager.resolveFile(fileName) : fsManager.resolveFile(fileName, opts); } if (!file.exists()) { return null; } FileName path = file.getName(); URLStreamHandler handler = new VFSURLStreamHandler(path); return new URL(null, path.getURI(), handler); } catch (FileSystemException fse) { return null; } catch (MalformedURLException ex) { return null; } } private FileSystemOptions getOptions(String scheme) { FileSystemOptions opts = new FileSystemOptions(); FileSystemConfigBuilder builder; try { builder = VFS.getManager().getFileSystemConfigBuilder(scheme); } catch (Exception ex) { return null; } FileOptionsProvider provider = getFileOptionsProvider(); if (provider != null) { Map map = provider.getOptions(); if (map == null) { return null; } int count = 0; for (Map.Entry entry : map.entrySet()) { try { String key = entry.getKey(); if (FileOptionsProvider.CURRENT_USER.equals(key)) { key = "creatorName"; } setProperty(builder, opts, key, entry.getValue()); ++count; } catch (Exception ex) { // Ignore an incorrect property. continue; } } if (count > 0) { return opts; } } return null; } private void setProperty(FileSystemConfigBuilder builder, FileSystemOptions options, String key, Object value) { String methodName = "set" + key.substring(0, 1).toUpperCase() + key.substring(1); Class[] paramTypes = new Class[2]; paramTypes[0] = FileSystemOptions.class; paramTypes[1] = value.getClass(); try { Method method = builder.getClass().getMethod(methodName, paramTypes); Object[] params = new Object[2]; params[0] = options; params[1] = value; method.invoke(builder, params); } catch (Exception ex) { return; } } /** * Stream handler required to create URL. */ private static class VFSURLStreamHandler extends URLStreamHandler { /** The Protocol used */ private final String protocol; public VFSURLStreamHandler(FileName file) { this.protocol = file.getScheme(); } @Override protected URLConnection openConnection(URL url) throws IOException { throw new IOException("VFS URLs can only be used with VFS APIs"); } } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/AppletConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/AppletConfiguratio100644 4073 12232154102 33503 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import java.applet.Applet; import java.util.Arrays; import java.util.Iterator; /** * A configuration wrapper to read applet parameters. This configuration is * read only, adding or removing a property will throw an * UnsupportedOperationException. * * @author Emmanuel Bourg * @version $Id: AppletConfiguration.java 1211124 2011-12-06 20:56:16Z oheger $ * @since 1.1 */ public class AppletConfiguration extends BaseWebConfiguration { /** Stores the wrapped applet.*/ protected Applet applet; /** * Create an AppletConfiguration using the initialization parameters of * the specified Applet. * * @param applet the applet */ public AppletConfiguration(Applet applet) { this.applet = applet; } public Object getProperty(String key) { return handleDelimiters(applet.getParameter(key)); } public Iterator getKeys() { String[][] paramsInfo = applet.getParameterInfo(); String[] keys = new String[paramsInfo != null ? paramsInfo.length : 0]; for (int i = 0; i < keys.length; i++) { keys[i] = paramsInfo[i][0]; } return Arrays.asList(keys).iterator(); } } ././@LongLink100644 0 0 154 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/BaseWebConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/BaseWebConfigurati100644 7513 12232154102 33411 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import java.util.List; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.PropertyConverter; /** *

* An abstract base class for all web configurations. *

*

* This class implements common functionality used by all web based * configurations. E.g. some methods are not supported by configurations of this * type, so they throw a {@code UnsupportedOperationException} exception. *

* * @author Commons * Configuration team * @version $Id: BaseWebConfiguration.java 1211122 2011-12-06 20:55:45Z oheger $ * @since 1.2 */ abstract class BaseWebConfiguration extends AbstractConfiguration { /** * Checks if this configuration is empty. This implementation makes use of * the {@code getKeys()} method (which must be defined by concrete * sub classes) to find out whether properties exist. * * @return a flag whether this configuration is empty */ public boolean isEmpty() { return !getKeys().hasNext(); } /** * Checks whether the specified key is stored in this configuration. * * @param key the key * @return a flag whether this key exists in this configuration */ public boolean containsKey(String key) { return getProperty(key) != null; } /** * Removes the property with the given key. This operation is not * supported and will throw an UnsupportedOperationException. * * @param key the key of the property to be removed * @throws UnsupportedOperationException because this operation is not * allowed */ @Override public void clearProperty(String key) { throw new UnsupportedOperationException("Read only configuration"); } /** * Adds a property to this configuration. This operation is not * supported and will throw an UnsupportedOperationException. * * @param key the key of the property * @param obj the value to be added * @throws UnsupportedOperationException because this operation is not * allowed */ @Override protected void addPropertyDirect(String key, Object obj) { throw new UnsupportedOperationException("Read only configuration"); } /** * Takes care of list delimiters in property values. This method checks if * delimiter parsing is enabled and the passed in value contains a delimiter * character. If this is the case, a split operation is performed. * * @param value the property value to be examined * @return the processed value */ protected Object handleDelimiters(Object value) { if (!isDelimiterParsingDisabled() && value instanceof String) { List list = PropertyConverter.split((String) value, getListDelimiter()); value = list.size() > 1 ? list : list.get(0); } return value; } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/package.html100644 2110 12232154102 32230 0ustarhenningstaff 0 0

This package contains some implementations of the Configuration interface that are useful in web environments.

$Id: package.html 439648 2006-09-02 20:42:10Z oheger $

././@LongLink100644 0 0 154 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ServletConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ServletConfigurati100644 4646 12232154102 33531 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import javax.servlet.Servlet; import javax.servlet.ServletConfig; /** * A configuration wrapper around a {@link ServletConfig}. This configuration * is read only, adding or removing a property will throw an * UnsupportedOperationException. * * @author Emmanuel Bourg * @version $Id: ServletConfiguration.java 1211128 2011-12-06 20:56:41Z oheger $ * @since 1.1 */ public class ServletConfiguration extends BaseWebConfiguration { /** Stores a reference to the wrapped {@code ServletConfig}.*/ protected ServletConfig config; /** * Create a ServletConfiguration using the initialization parameter of * the specified servlet. * * @param servlet the servlet */ public ServletConfiguration(Servlet servlet) { this(servlet.getServletConfig()); } /** * Create a ServletConfiguration using the servlet initialization parameters. * * @param config the servlet configuration */ public ServletConfiguration(ServletConfig config) { this.config = config; } public Object getProperty(String key) { return handleDelimiters(config.getInitParameter(key)); } public Iterator getKeys() { // According to the documentation of getInitParameterNames() the // enumeration is of type String. @SuppressWarnings("unchecked") Enumeration en = config.getInitParameterNames(); return Collections.list(en).iterator(); } } ././@LongLink100644 0 0 163 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ServletContextConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ServletContextConf100644 4766 12232154102 33514 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import javax.servlet.Servlet; import javax.servlet.ServletContext; /** * A configuration wrapper to read the initialization parameters of a servlet * context. This configuration is read only, adding or removing a property will * throw an UnsupportedOperationException. * * @author Emmanuel Bourg * @version $Id: ServletContextConfiguration.java 1211129 2011-12-06 20:57:01Z oheger $ * @since 1.1 */ public class ServletContextConfiguration extends BaseWebConfiguration { /** Stores the wrapped servlet context.*/ protected ServletContext context; /** * Create a ServletContextConfiguration using the context of * the specified servlet. * * @param servlet the servlet */ public ServletContextConfiguration(Servlet servlet) { this.context = servlet.getServletConfig().getServletContext(); } /** * Create a ServletContextConfiguration using the servlet context * initialization parameters. * * @param context the servlet context */ public ServletContextConfiguration(ServletContext context) { this.context = context; } public Object getProperty(String key) { return handleDelimiters(context.getInitParameter(key)); } public Iterator getKeys() { // According to the documentation of getInitParameterNames() the // enumeration is of type String. @SuppressWarnings("unchecked") Enumeration en = context.getInitParameterNames(); return Collections.list(en).iterator(); } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ServletFilterConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ServletFilterConfi100644 4171 12232154102 33454 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import java.util.Collections; import java.util.Enumeration; import java.util.Iterator; import javax.servlet.FilterConfig; /** * A configuration wrapper around a {@link FilterConfig}. This configuration is * read only, adding or removing a property will throw an * UnsupportedOperationException. * * @author Emmanuel Bourg * @version $Id: ServletFilterConfiguration.java 1211130 2011-12-06 20:57:19Z oheger $ * @since 1.1 */ public class ServletFilterConfiguration extends BaseWebConfiguration { /** Stores the wrapped filter config.*/ protected FilterConfig config; /** * Create a ServletFilterConfiguration using the filter initialization parameters. * * @param config the filter configuration */ public ServletFilterConfiguration(FilterConfig config) { this.config = config; } public Object getProperty(String key) { return handleDelimiters(config.getInitParameter(key)); } public Iterator getKeys() { // According to the documentation of getInitParameterNames() the // enumeration is of type String. @SuppressWarnings("unchecked") Enumeration en = config.getInitParameterNames(); return Collections.list(en).iterator(); } } ././@LongLink100644 0 0 163 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ServletRequestConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ServletRequestConf100644 5621 12232154102 33507 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.servlet.ServletRequest; /** * A configuration wrapper to read the parameters of a servlet request. This * configuration is read only, adding or removing a property will throw an * UnsupportedOperationException. * * @author Emmanuel Bourg * @version $Id: ServletRequestConfiguration.java 1211131 2011-12-06 20:57:37Z oheger $ * @since 1.1 */ public class ServletRequestConfiguration extends BaseWebConfiguration { /** Stores the wrapped request.*/ protected ServletRequest request; /** * Create a ServletRequestConfiguration using the request parameters. * * @param request the servlet request */ public ServletRequestConfiguration(ServletRequest request) { this.request = request; } public Object getProperty(String key) { String[] values = request.getParameterValues(key); if (values == null || values.length == 0) { return null; } else if (values.length == 1) { return handleDelimiters(values[0]); } else { // ensure that escape characters in all list elements are removed List result = new ArrayList(values.length); for (int i = 0; i < values.length; i++) { Object val = handleDelimiters(values[i]); if (val instanceof Collection) { result.addAll((Collection) val); } else { result.add(val); } } return result; } } public Iterator getKeys() { // According to the documentation of getParameterMap(), keys are Strings. @SuppressWarnings("unchecked") Map parameterMap = request.getParameterMap(); return parameterMap.keySet().iterator(); } } commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/XMLConfiguration.java100644 163172 12232154102 33305 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.net.URL; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Source; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.TransformerFactoryConfigurationError; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.configuration.resolver.DefaultEntityResolver; import org.apache.commons.configuration.resolver.EntityRegistry; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.LogFactory; import org.w3c.dom.Attr; import org.w3c.dom.CDATASection; import org.w3c.dom.DOMException; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.NodeList; import org.w3c.dom.Text; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; /** *

A specialized hierarchical configuration class that is able to parse XML * documents.

* *

The parsed document will be stored keeping its structure. The class also * tries to preserve as much information from the loaded XML document as * possible, including comments and processing instructions. These will be * contained in documents created by the {@code save()} methods, too.

* *

Like other file based configuration classes this class maintains the name * and path to the loaded configuration file. These properties can be altered * using several setter methods, but they are not modified by {@code save()} * and {@code load()} methods. If XML documents contain relative paths to * other documents (e.g. to a DTD), these references are resolved based on the * path set for this configuration.

* *

By inheriting from {@link AbstractConfiguration} this class * provides some extended functionality, e.g. interpolation of property values. * Like in {@link PropertiesConfiguration} property values can * contain delimiter characters (the comma ',' per default) and are then split * into multiple values. This works for XML attributes and text content of * elements as well. The delimiter can be escaped by a backslash. As an example * consider the following XML fragment:

* *

*

 * <config>
 *   <array>10,20,30,40</array>
 *   <scalar>3\,1415</scalar>
 *   <cite text="To be or not to be\, this is the question!"/>
 * </config>
 * 
*

*

Here the content of the {@code array} element will be split at * the commas, so the {@code array} key will be assigned 4 values. In the * {@code scalar} property and the {@code text} attribute of the * {@code cite} element the comma is escaped, so that no splitting is * performed.

* *

The configuration API allows setting multiple values for a single attribute, * e.g. something like the following is legal (assuming that the default * expression engine is used): *

 * XMLConfiguration config = new XMLConfiguration();
 * config.addProperty("test.dir[@name]", "C:\\Temp\\");
 * config.addProperty("test.dir[@name]", "D:\\Data\\");
 * 

* *

Because in XML such a constellation is not directly supported (an attribute * can appear only once for a single element), the values are concatenated to a * single value. If delimiter parsing is enabled (refer to the * {@link #setDelimiterParsingDisabled(boolean)} method), the * current list delimiter character will be used as separator. Otherwise the * pipe symbol ("|") will be used for this purpose. No matter which character is * used as delimiter, it can always be escaped with a backslash. A backslash * itself can also be escaped with another backslash. Consider the following * example fragment from a configuration file: *

 * <directories names="C:\Temp\\|D:\Data\"/>
 * 
* Here the backslash after Temp is escaped. This is necessary because it * would escape the list delimiter (the pipe symbol assuming that list delimiter * parsing is disabled) otherwise. So this attribute would have two values.

* *

Note: You should ensure that the delimiter parsing disabled * property is always consistent when you load and save a configuration file. * Otherwise the values of properties can become corrupted.

* *

Whitespace in the content of XML documents is trimmed per default. In most * cases this is desired. However, sometimes whitespace is indeed important and * should be treated as part of the value of a property as in the following * example: *

 *   <indent>    </indent>
 * 

* *

Per default the spaces in the {@code indent} element will be trimmed * resulting in an empty element. To tell {@code XMLConfiguration} that * spaces are relevant the {@code xml:space} attribute can be used, which is * defined in the XML * specification. This will look as follows: *

 *   <indent xml:space="preserve">    </indent>
 * 
* The value of the {@code indent} property will now contain the spaces.

* *

{@code XMLConfiguration} implements the {@link FileConfiguration} * interface and thus provides full support for loading XML documents from * different sources like files, URLs, or streams. A full description of these * features can be found in the documentation of * {@link AbstractFileConfiguration}.

* *

Note:Configuration objects of this type can be read concurrently * by multiple threads. However if one of these threads modifies the object, * synchronization has to be performed manually.

* * @since commons-configuration 1.0 * * @author Jörg Schaible * @version $Id: XMLConfiguration.java 1534429 2013-10-22 00:45:36Z henning $ */ public class XMLConfiguration extends AbstractHierarchicalFileConfiguration implements EntityResolver, EntityRegistry { /** * The serial version UID. */ private static final long serialVersionUID = 2453781111653383552L; /** Constant for the default root element name. */ private static final String DEFAULT_ROOT_NAME = "configuration"; /** Constant for the name of the space attribute.*/ private static final String ATTR_SPACE = "xml:space"; /** Constant for the xml:space value for preserving whitespace.*/ private static final String VALUE_PRESERVE = "preserve"; /** Constant for the delimiter for multiple attribute values.*/ private static final char ATTR_VALUE_DELIMITER = '|'; /** Schema Langauge key for the parser */ private static final String JAXP_SCHEMA_LANGUAGE = "http://java.sun.com/xml/jaxp/properties/schemaLanguage"; /** Schema Language for the parser */ private static final String W3C_XML_SCHEMA = "http://www.w3.org/2001/XMLSchema"; /** The document from this configuration's data source. */ private Document document; /** Stores the name of the root element. */ private String rootElementName; /** Stores the public ID from the DOCTYPE.*/ private String publicID; /** Stores the system ID from the DOCTYPE.*/ private String systemID; /** Stores the document builder that should be used for loading.*/ private DocumentBuilder documentBuilder; /** Stores a flag whether DTD or Schema validation should be performed.*/ private boolean validating; /** Stores a flag whether DTD or Schema validation is used */ private boolean schemaValidation; /** A flag whether attribute splitting is disabled.*/ private boolean attributeSplittingDisabled; /** The EntityResolver to use */ private EntityResolver entityResolver = new DefaultEntityResolver(); /** * Creates a new instance of {@code XMLConfiguration}. */ public XMLConfiguration() { super(); setLogger(LogFactory.getLog(XMLConfiguration.class)); } /** * Creates a new instance of {@code XMLConfiguration} and copies the * content of the passed in configuration into this object. Note that only * the data of the passed in configuration will be copied. If, for instance, * the other configuration is a {@code XMLConfiguration}, too, * things like comments or processing instructions will be lost. * * @param c the configuration to copy * @since 1.4 */ public XMLConfiguration(HierarchicalConfiguration c) { super(c); clearReferences(getRootNode()); setRootElementName(getRootNode().getName()); setLogger(LogFactory.getLog(XMLConfiguration.class)); } /** * Creates a new instance of{@code XMLConfiguration}. The * configuration is loaded from the specified file * * @param fileName the name of the file to load * @throws ConfigurationException if the file cannot be loaded */ public XMLConfiguration(String fileName) throws ConfigurationException { super(fileName); setLogger(LogFactory.getLog(XMLConfiguration.class)); } /** * Creates a new instance of {@code XMLConfiguration}. * The configuration is loaded from the specified file. * * @param file the file * @throws ConfigurationException if an error occurs while loading the file */ public XMLConfiguration(File file) throws ConfigurationException { super(file); setLogger(LogFactory.getLog(XMLConfiguration.class)); } /** * Creates a new instance of {@code XMLConfiguration}. * The configuration is loaded from the specified URL. * * @param url the URL * @throws ConfigurationException if loading causes an error */ public XMLConfiguration(URL url) throws ConfigurationException { super(url); setLogger(LogFactory.getLog(XMLConfiguration.class)); } /** * Returns the name of the root element. If this configuration was loaded * from a XML document, the name of this document's root element is * returned. Otherwise it is possible to set a name for the root element * that will be used when this configuration is stored. * * @return the name of the root element */ public String getRootElementName() { if (getDocument() == null) { return (rootElementName == null) ? DEFAULT_ROOT_NAME : rootElementName; } else { return getDocument().getDocumentElement().getNodeName(); } } /** * Sets the name of the root element. This name is used when this * configuration object is stored in an XML file. Note that setting the name * of the root element works only if this configuration has been newly * created. If the configuration was loaded from an XML file, the name * cannot be changed and an {@code UnsupportedOperationException} * exception is thrown. Whether this configuration has been loaded from an * XML document or not can be found out using the {@code getDocument()} * method. * * @param name the name of the root element */ public void setRootElementName(String name) { if (getDocument() != null) { throw new UnsupportedOperationException("The name of the root element " + "cannot be changed when loaded from an XML document!"); } rootElementName = name; getRootNode().setName(name); } /** * Returns the {@code DocumentBuilder} object that is used for * loading documents. If no specific builder has been set, this method * returns null. * * @return the {@code DocumentBuilder} for loading new documents * @since 1.2 */ public DocumentBuilder getDocumentBuilder() { return documentBuilder; } /** * Sets the {@code DocumentBuilder} object to be used for loading * documents. This method makes it possible to specify the exact document * builder. So an application can create a builder, configure it for its * special needs, and then pass it to this method. * * @param documentBuilder the document builder to be used; if undefined, a * default builder will be used * @since 1.2 */ public void setDocumentBuilder(DocumentBuilder documentBuilder) { this.documentBuilder = documentBuilder; } /** * Returns the public ID of the DOCTYPE declaration from the loaded XML * document. This is null if no document has been loaded yet or if * the document does not contain a DOCTYPE declaration with a public ID. * * @return the public ID * @since 1.3 */ public String getPublicID() { return publicID; } /** * Sets the public ID of the DOCTYPE declaration. When this configuration is * saved, a DOCTYPE declaration will be constructed that contains this * public ID. * * @param publicID the public ID * @since 1.3 */ public void setPublicID(String publicID) { this.publicID = publicID; } /** * Returns the system ID of the DOCTYPE declaration from the loaded XML * document. This is null if no document has been loaded yet or if * the document does not contain a DOCTYPE declaration with a system ID. * * @return the system ID * @since 1.3 */ public String getSystemID() { return systemID; } /** * Sets the system ID of the DOCTYPE declaration. When this configuration is * saved, a DOCTYPE declaration will be constructed that contains this * system ID. * * @param systemID the system ID * @since 1.3 */ public void setSystemID(String systemID) { this.systemID = systemID; } /** * Returns the value of the validating flag. * * @return the validating flag * @since 1.2 */ public boolean isValidating() { return validating; } /** * Sets the value of the validating flag. This flag determines whether * DTD/Schema validation should be performed when loading XML documents. This * flag is evaluated only if no custom {@code DocumentBuilder} was set. * * @param validating the validating flag * @since 1.2 */ public void setValidating(boolean validating) { if (!schemaValidation) { this.validating = validating; } } /** * Returns the value of the schemaValidation flag. * * @return the schemaValidation flag * @since 1.7 */ public boolean isSchemaValidation() { return schemaValidation; } /** * Sets the value of the schemaValidation flag. This flag determines whether * DTD or Schema validation should be used. This * flag is evaluated only if no custom {@code DocumentBuilder} was set. * If set to true the XML document must contain a schemaLocation definition * that provides resolvable hints to the required schemas. * * @param schemaValidation the validating flag * @since 1.7 */ public void setSchemaValidation(boolean schemaValidation) { this.schemaValidation = schemaValidation; if (schemaValidation) { this.validating = true; } } /** * Sets a new EntityResolver. Setting this will cause RegisterEntityId to have no * effect. * @param resolver The EntityResolver to use. * @since 1.7 */ public void setEntityResolver(EntityResolver resolver) { this.entityResolver = resolver; } /** * Returns the EntityResolver. * @return The EntityResolver. * @since 1.7 */ public EntityResolver getEntityResolver() { return this.entityResolver; } /** * Returns the flag whether attribute splitting is disabled. * * @return the flag whether attribute splitting is disabled * @see #setAttributeSplittingDisabled(boolean) * @since 1.6 */ public boolean isAttributeSplittingDisabled() { return attributeSplittingDisabled; } /** *

* Sets a flag whether attribute splitting is disabled. *

*

* The Configuration API allows adding multiple values to an attribute. This * is problematic when storing the configuration because in XML an attribute * can appear only once with a single value. To solve this problem, per * default multiple attribute values are concatenated using a special * separator character and split again when the configuration is loaded. The * separator character is either the list delimiter character (see * {@link #setListDelimiter(char)}) or the pipe symbol ("|") if * list delimiter parsing is disabled. *

*

* In some constellations the splitting of attribute values can have * undesired effects, especially if list delimiter parsing is disabled and * attributes may contain the "|" character. In these cases it is * possible to disable the attribute splitting mechanism by calling this * method with a boolean value set to false. If attribute splitting * is disabled, the values of attributes will not be processed, but stored * as configuration properties exactly as they are returned by the XML * parser. *

*

* Note that in this mode multiple attribute values cannot be handled * correctly. It is possible to create a {@code XMLConfiguration} * object, add multiple values to an attribute and save it. When the * configuration is loaded again and attribute splitting is disabled, the * attribute will only have a single value, which is the concatenation of * all values set before. So it lies in the responsibility of the * application to carefully set the values of attributes. *

*

* As is true for the {@link #setDelimiterParsingDisabled(boolean)} method, * this method must be called before the configuration is loaded. So it * can't be used together with one of the constructors expecting the * specification of the file to load. Instead the default constructor has to * be used, then {@code setAttributeSplittingDisabled(false)} has to be * called, and finally the configuration can be loaded using one of its * {@code load()} methods. *

* * @param attributeSplittingDisabled true for disabling attribute * splitting, false for enabling it * @see #setDelimiterParsingDisabled(boolean) * @since 1.6 */ public void setAttributeSplittingDisabled(boolean attributeSplittingDisabled) { this.attributeSplittingDisabled = attributeSplittingDisabled; } /** * Returns the XML document this configuration was loaded from. The return * value is null if this configuration was not loaded from a XML * document. * * @return the XML document this configuration was loaded from */ public Document getDocument() { return document; } /** * Removes all properties from this configuration. If this configuration * was loaded from a file, the associated DOM document is also cleared. */ @Override public void clear() { super.clear(); setRoot(new Node()); document = null; } /** * Initializes this configuration from an XML document. * * @param document the document to be parsed * @param elemRefs a flag whether references to the XML elements should be set */ public void initProperties(Document document, boolean elemRefs) { if (document.getDoctype() != null) { setPublicID(document.getDoctype().getPublicId()); setSystemID(document.getDoctype().getSystemId()); } constructHierarchy(getRoot(), document.getDocumentElement(), elemRefs, true); getRootNode().setName(document.getDocumentElement().getNodeName()); if (elemRefs) { getRoot().setReference(document.getDocumentElement()); } } /** * Helper method for building the internal storage hierarchy. The XML * elements are transformed into node objects. * * @param node the actual node * @param element the actual XML element * @param elemRefs a flag whether references to the XML elements should be * set * @param trim a flag whether the text content of elements should be * trimmed; this controls the whitespace handling * @return a map with all attribute values extracted for the current node; * this map also contains the value of the trim flag for this node * under the key {@value #ATTR_SPACE} */ private Map> constructHierarchy(Node node, Element element, boolean elemRefs, boolean trim) { boolean trimFlag = shouldTrim(element, trim); Map> attributes = processAttributes(node, element, elemRefs); attributes.put(ATTR_SPACE, Collections.singleton(String.valueOf(trimFlag))); StringBuilder buffer = new StringBuilder(); NodeList list = element.getChildNodes(); for (int i = 0; i < list.getLength(); i++) { org.w3c.dom.Node w3cNode = list.item(i); if (w3cNode instanceof Element) { Element child = (Element) w3cNode; Node childNode = new XMLNode(child.getTagName(), elemRefs ? child : null); Map> attrmap = constructHierarchy(childNode, child, elemRefs, trimFlag); node.addChild(childNode); Collection attrSpace = attrmap.remove(ATTR_SPACE); Boolean childTrim = CollectionUtils.isEmpty(attrSpace) ? Boolean.FALSE : Boolean.valueOf(attrSpace.iterator().next()); handleDelimiters(node, childNode, childTrim.booleanValue(), attrmap); } else if (w3cNode instanceof Text) { Text data = (Text) w3cNode; buffer.append(data.getData()); } } String text = determineValue(node, buffer.toString(), trimFlag); if (text.length() > 0 || (!node.hasChildren() && node != getRoot())) { node.setValue(text); } return attributes; } /** * Determines the value of a configuration node. This method mainly checks * whether the text value is to be trimmed or not. This is normally defined * by the trim flag. However, if the node has children and its content is * only whitespace, then it makes no sense to store any value; this would * only scramble layout when the configuration is saved again. * * @param node the current {@code ConfigurationNode} * @param content the text content of this node * @param trimFlag the trim flag * @return the value to be stored for this node */ private static String determineValue(ConfigurationNode node, String content, boolean trimFlag) { boolean shouldTrim = trimFlag || (StringUtils.isBlank(content) && node .getChildrenCount() > 0); return shouldTrim ? content.trim() : content; } /** * Helper method for constructing node objects for the attributes of the * given XML element. * * @param node the current node * @param element the actual XML element * @param elemRefs a flag whether references to the XML elements should be set * @return a map with all attribute values extracted for the current node */ private Map> processAttributes(Node node, Element element, boolean elemRefs) { NamedNodeMap attributes = element.getAttributes(); Map> attrmap = new HashMap>(); for (int i = 0; i < attributes.getLength(); ++i) { org.w3c.dom.Node w3cNode = attributes.item(i); if (w3cNode instanceof Attr) { Attr attr = (Attr) w3cNode; List values; if (isAttributeSplittingDisabled()) { values = Collections.singletonList(attr.getValue()); } else { values = PropertyConverter.split(attr.getValue(), isDelimiterParsingDisabled() ? ATTR_VALUE_DELIMITER : getListDelimiter()); } appendAttributes(node, element, elemRefs, attr.getName(), values); attrmap.put(attr.getName(), values); } } return attrmap; } /** * Adds attribute nodes to the given node. For each attribute value, a new * attribute node is created and added as child to the current node. * * @param node the current node * @param element the corresponding XML element * @param attr the name of the attribute * @param values the attribute values */ private void appendAttributes(Node node, Element element, boolean elemRefs, String attr, Collection values) { for (String value : values) { Node child = new XMLNode(attr, elemRefs ? element : null); child.setValue(value); node.addAttribute(child); } } /** * Deals with elements whose value is a list. In this case multiple child * elements must be added. * * @param parent the parent element * @param child the child element * @param trim flag whether texts of elements should be trimmed * @param attrmap a map with the attributes of the current node */ private void handleDelimiters(Node parent, Node child, boolean trim, Map> attrmap) { if (child.getValue() != null) { List values; if (isDelimiterParsingDisabled()) { values = new ArrayList(); values.add(child.getValue().toString()); } else { values = PropertyConverter.split(child.getValue().toString(), getListDelimiter(), trim); } if (values.size() > 1) { Iterator it = values.iterator(); // Create new node for the original child's first value Node c = createNode(child.getName()); c.setValue(it.next()); // Copy original attributes to the new node for (ConfigurationNode ndAttr : child.getAttributes()) { ndAttr.setReference(null); c.addAttribute(ndAttr); } parent.remove(child); parent.addChild(c); // add multiple new children while (it.hasNext()) { c = new XMLNode(child.getName(), null); c.setValue(it.next()); for (Map.Entry> e : attrmap .entrySet()) { appendAttributes(c, null, false, e.getKey(), e.getValue()); } parent.addChild(c); } } else if (values.size() == 1) { // we will have to replace the value because it might // contain escaped delimiters child.setValue(values.get(0)); } } } /** * Checks whether the content of the current XML element should be trimmed. * This method checks whether a {@code xml:space} attribute is * present and evaluates its value. See * http://www.w3.org/TR/REC-xml/#sec-white-space for more details. * * @param element the current XML element * @param currentTrim the current trim flag * @return a flag whether the content of this element should be trimmed */ private boolean shouldTrim(Element element, boolean currentTrim) { Attr attr = element.getAttributeNode(ATTR_SPACE); if (attr == null) { return currentTrim; } else { return !VALUE_PRESERVE.equals(attr.getValue()); } } /** * Creates the {@code DocumentBuilder} to be used for loading files. * This implementation checks whether a specific * {@code DocumentBuilder} has been set. If this is the case, this * one is used. Otherwise a default builder is created. Depending on the * value of the validating flag this builder will be a validating or a non * validating {@code DocumentBuilder}. * * @return the {@code DocumentBuilder} for loading configuration * files * @throws ParserConfigurationException if an error occurs * @since 1.2 */ protected DocumentBuilder createDocumentBuilder() throws ParserConfigurationException { if (getDocumentBuilder() != null) { return getDocumentBuilder(); } else { DocumentBuilderFactory factory = DocumentBuilderFactory .newInstance(); if (isValidating()) { factory.setValidating(true); if (isSchemaValidation()) { factory.setNamespaceAware(true); factory.setAttribute(JAXP_SCHEMA_LANGUAGE, W3C_XML_SCHEMA); } } DocumentBuilder result = factory.newDocumentBuilder(); result.setEntityResolver(this.entityResolver); if (isValidating()) { // register an error handler which detects validation errors result.setErrorHandler(new DefaultHandler() { @Override public void error(SAXParseException ex) throws SAXException { throw ex; } }); } return result; } } /** * Creates a DOM document from the internal tree of configuration nodes. * * @return the new document * @throws ConfigurationException if an error occurs */ protected Document createDocument() throws ConfigurationException { try { if (document == null) { DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document newDocument = builder.newDocument(); Element rootElem = newDocument.createElement(getRootElementName()); newDocument.appendChild(rootElem); document = newDocument; } XMLBuilderVisitor builder = new XMLBuilderVisitor(document, isDelimiterParsingDisabled() ? (char) 0 : getListDelimiter(), isAttributeSplittingDisabled()); builder.processDocument(getRoot()); initRootElementText(document, getRootNode().getValue()); return document; } catch (DOMException domEx) { throw new ConfigurationException(domEx); } catch (ParserConfigurationException pex) { throw new ConfigurationException(pex); } } /** * Sets the text of the root element of a newly created XML Document. * * @param doc the document * @param value the new text to be set */ private void initRootElementText(Document doc, Object value) { Element elem = doc.getDocumentElement(); NodeList children = elem.getChildNodes(); // Remove all existing text nodes for (int i = 0; i < children.getLength(); i++) { org.w3c.dom.Node nd = children.item(i); if (nd.getNodeType() == org.w3c.dom.Node.TEXT_NODE) { elem.removeChild(nd); } } if (value != null) { // Add a new text node elem.appendChild(doc.createTextNode(String.valueOf(value))); } } /** * Creates a new node object. This implementation returns an instance of the * {@code XMLNode} class. * * @param name the node's name * @return the new node */ @Override protected Node createNode(String name) { return new XMLNode(name, null); } /** * Loads the configuration from the given input stream. * * @param in the input stream * @throws ConfigurationException if an error occurs */ @Override public void load(InputStream in) throws ConfigurationException { load(new InputSource(in)); } /** * Load the configuration from the given reader. * Note that the {@code clear()} method is not called, so * the properties contained in the loaded file will be added to the * actual set of properties. * * @param in An InputStream. * * @throws ConfigurationException if an error occurs */ public void load(Reader in) throws ConfigurationException { load(new InputSource(in)); } /** * Loads a configuration file from the specified input source. * @param source the input source * @throws ConfigurationException if an error occurs */ private void load(InputSource source) throws ConfigurationException { try { URL sourceURL = getDelegate().getURL(); if (sourceURL != null) { source.setSystemId(sourceURL.toString()); } DocumentBuilder builder = createDocumentBuilder(); Document newDocument = builder.parse(source); Document oldDocument = document; document = null; initProperties(newDocument, oldDocument == null); document = (oldDocument == null) ? newDocument : oldDocument; } catch (SAXParseException spe) { throw new ConfigurationException("Error parsing " + source.getSystemId(), spe); } catch (Exception e) { this.getLogger().debug("Unable to load the configuraton", e); throw new ConfigurationException("Unable to load the configuration", e); } } /** * Saves the configuration to the specified writer. * * @param writer the writer used to save the configuration * @throws ConfigurationException if an error occurs */ public void save(Writer writer) throws ConfigurationException { try { Transformer transformer = createTransformer(); Source source = new DOMSource(createDocument()); Result result = new StreamResult(writer); transformer.transform(source, result); } catch (TransformerException e) { throw new ConfigurationException("Unable to save the configuration", e); } catch (TransformerFactoryConfigurationError e) { throw new ConfigurationException("Unable to save the configuration", e); } } /** * Validate the document against the Schema. * @throws ConfigurationException if the validation fails. */ public void validate() throws ConfigurationException { try { Transformer transformer = createTransformer(); Source source = new DOMSource(createDocument()); StringWriter writer = new StringWriter(); Result result = new StreamResult(writer); transformer.transform(source, result); Reader reader = new StringReader(writer.getBuffer().toString()); DocumentBuilder builder = createDocumentBuilder(); builder.parse(new InputSource(reader)); } catch (SAXException e) { throw new ConfigurationException("Validation failed", e); } catch (IOException e) { throw new ConfigurationException("Validation failed", e); } catch (TransformerException e) { throw new ConfigurationException("Validation failed", e); } catch (ParserConfigurationException pce) { throw new ConfigurationException("Validation failed", pce); } } /** * Creates and initializes the transformer used for save operations. This * base implementation initializes all of the default settings like * indention mode and the DOCTYPE. Derived classes may overload this method * if they have specific needs. * * @return the transformer to use for a save operation * @throws TransformerException if an error occurs * @since 1.3 */ protected Transformer createTransformer() throws TransformerException { Transformer transformer = TransformerFactory.newInstance() .newTransformer(); transformer.setOutputProperty(OutputKeys.INDENT, "yes"); if (getEncoding() != null) { transformer.setOutputProperty(OutputKeys.ENCODING, getEncoding()); } if (getPublicID() != null) { transformer.setOutputProperty(OutputKeys.DOCTYPE_PUBLIC, getPublicID()); } if (getSystemID() != null) { transformer.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, getSystemID()); } return transformer; } /** * Creates a copy of this object. The new configuration object will contain * the same properties as the original, but it will lose any connection to a * source document (if one exists). This is to avoid race conditions if both * the original and the copy are modified and then saved. * * @return the copy */ @Override public Object clone() { XMLConfiguration copy = (XMLConfiguration) super.clone(); // clear document related properties copy.document = null; copy.setDelegate(copy.createDelegate()); // clear all references in the nodes, too clearReferences(copy.getRootNode()); return copy; } /** * Creates the file configuration delegate for this object. This implementation * will return an instance of a class derived from {@code FileConfigurationDelegate} * that deals with some specialties of {@code XMLConfiguration}. * @return the delegate for this object */ @Override protected FileConfigurationDelegate createDelegate() { return new XMLFileConfigurationDelegate(); } /** * Adds a collection of nodes directly to this configuration. This * implementation ensures that the nodes to be added are of the correct node * type (they have to be converted to {@code XMLNode} if necessary). * * @param key the key where the nodes are to be added * @param nodes the collection with the new nodes * @since 1.5 */ @Override public void addNodes(String key, Collection nodes) { if (nodes != null && !nodes.isEmpty()) { Collection xmlNodes; xmlNodes = new ArrayList(nodes.size()); for (ConfigurationNode node : nodes) { xmlNodes.add(convertToXMLNode(node)); } super.addNodes(key, xmlNodes); } else { super.addNodes(key, nodes); } } /** * Converts the specified node into a {@code XMLNode} if necessary. * This is required for nodes that are directly added, e.g. by * {@code addNodes()}. If the passed in node is already an instance * of {@code XMLNode}, it is directly returned, and conversion * stops. Otherwise a new {@code XMLNode} is created, and the * children are also converted. * * @param node the node to be converted * @return the converted node */ private XMLNode convertToXMLNode(ConfigurationNode node) { if (node instanceof XMLNode) { return (XMLNode) node; } XMLNode nd = (XMLNode) createNode(node.getName()); nd.setValue(node.getValue()); nd.setAttribute(node.isAttribute()); for (ConfigurationNode child : node.getChildren()) { nd.addChild(convertToXMLNode(child)); } for (ConfigurationNode attr : node.getAttributes()) { nd.addAttribute(convertToXMLNode(attr)); } return nd; } /** *

* Registers the specified DTD URL for the specified public identifier. *

*

* {@code XMLConfiguration} contains an internal * {@code EntityResolver} implementation. This maps * {@code PUBLICID}'s to URLs (from which the resource will be * loaded). A common use case for this method is to register local URLs * (possibly computed at runtime by a class loader) for DTDs. This allows * the performance advantage of using a local version without having to * ensure every {@code SYSTEM} URI on every processed XML document is * local. This implementation provides only basic functionality. If more * sophisticated features are required, using * {@link #setDocumentBuilder(DocumentBuilder)} to set a custom * {@code DocumentBuilder} (which also can be initialized with a * custom {@code EntityResolver}) is recommended. *

*

* Note: This method will have no effect when a custom * {@code DocumentBuilder} has been set. (Setting a custom * {@code DocumentBuilder} overrides the internal implementation.) *

*

* Note: This method must be called before the * configuration is loaded. So the default constructor of * {@code XMLConfiguration} should be used, the location of the * configuration file set, {@code registerEntityId()} called, and * finally the {@code load()} method can be invoked. *

* * @param publicId Public identifier of the DTD to be resolved * @param entityURL The URL to use for reading this DTD * @throws IllegalArgumentException if the public ID is undefined * @since 1.5 */ public void registerEntityId(String publicId, URL entityURL) { if (entityResolver instanceof EntityRegistry) { ((EntityRegistry) entityResolver).registerEntityId(publicId, entityURL); } } /** * Resolves the requested external entity. This is the default * implementation of the {@code EntityResolver} interface. It checks * the passed in public ID against the registered entity IDs and uses a * local URL if possible. * * @param publicId the public identifier of the entity being referenced * @param systemId the system identifier of the entity being referenced * @return an input source for the specified entity * @throws SAXException if a parsing exception occurs * @since 1.5 * @deprecated Use getEntityResolver().resolveEntity() */ @Deprecated public InputSource resolveEntity(String publicId, String systemId) throws SAXException { try { return entityResolver.resolveEntity(publicId, systemId); } catch (IOException e) { throw new SAXException(e); } } /** * Returns a map with the entity IDs that have been registered using the * {@code registerEntityId()} method. * * @return a map with the registered entity IDs */ public Map getRegisteredEntities() { if (entityResolver instanceof EntityRegistry) { return ((EntityRegistry) entityResolver).getRegisteredEntities(); } return new HashMap(); } /** * A specialized {@code Node} class that is connected with an XML * element. Changes on a node are also performed on the associated element. */ class XMLNode extends Node { /** * The serial version UID. */ private static final long serialVersionUID = -4133988932174596562L; /** * Creates a new instance of {@code XMLNode} and initializes it * with a name and the corresponding XML element. * * @param name the node's name * @param elem the XML element */ public XMLNode(String name, Element elem) { super(name); setReference(elem); } /** * Sets the value of this node. If this node is associated with an XML * element, this element will be updated, too. * * @param value the node's new value */ @Override public void setValue(Object value) { super.setValue(value); if (getReference() != null && document != null) { if (isAttribute()) { updateAttribute(); } else { updateElement(value); } } } /** * Updates the associated XML elements when a node is removed. */ @Override protected void removeReference() { if (getReference() != null) { Element element = (Element) getReference(); if (isAttribute()) { updateAttribute(); } else { org.w3c.dom.Node parentElem = element.getParentNode(); if (parentElem != null) { parentElem.removeChild(element); } } } } /** * Updates the node's value if it represents an element node. * * @param value the new value */ private void updateElement(Object value) { Text txtNode = findTextNodeForUpdate(); if (value == null) { // remove text if (txtNode != null) { ((Element) getReference()).removeChild(txtNode); } } else { if (txtNode == null) { String newValue = isDelimiterParsingDisabled() ? value.toString() : PropertyConverter.escapeDelimiters(value.toString(), getListDelimiter()); txtNode = document.createTextNode(newValue); if (((Element) getReference()).getFirstChild() != null) { ((Element) getReference()).insertBefore(txtNode, ((Element) getReference()).getFirstChild()); } else { ((Element) getReference()).appendChild(txtNode); } } else { String newValue = isDelimiterParsingDisabled() ? value.toString() : PropertyConverter.escapeDelimiters(value.toString(), getListDelimiter()); txtNode.setNodeValue(newValue); } } } /** * Updates the node's value if it represents an attribute. * */ private void updateAttribute() { XMLBuilderVisitor.updateAttribute(getParent(), getName(), getListDelimiter(), isAttributeSplittingDisabled()); } /** * Returns the only text node of this element for update. This method is * called when the element's text changes. Then all text nodes except * for the first are removed. A reference to the first is returned or * null if there is no text node at all. * * @return the first and only text node */ private Text findTextNodeForUpdate() { Text result = null; Element elem = (Element) getReference(); // Find all Text nodes NodeList children = elem.getChildNodes(); Collection textNodes = new ArrayList(); for (int i = 0; i < children.getLength(); i++) { org.w3c.dom.Node nd = children.item(i); if (nd instanceof Text) { if (result == null) { result = (Text) nd; } else { textNodes.add(nd); } } } // We don't want CDATAs if (result instanceof CDATASection) { textNodes.add(result); result = null; } // Remove all but the first Text node for (org.w3c.dom.Node tn : textNodes) { elem.removeChild(tn); } return result; } } /** * A concrete {@code BuilderVisitor} that can construct XML * documents. */ static class XMLBuilderVisitor extends BuilderVisitor { /** Stores the document to be constructed. */ private Document document; /** Stores the list delimiter.*/ private final char listDelimiter; /** True if attributes should not be split */ private boolean isAttributeSplittingDisabled; /** * Creates a new instance of {@code XMLBuilderVisitor}. * * @param doc the document to be created * @param listDelimiter the delimiter for attribute properties with multiple values * @param isAttributeSplittingDisabled true if attribute splitting is disabled. */ public XMLBuilderVisitor(Document doc, char listDelimiter, boolean isAttributeSplittingDisabled) { document = doc; this.listDelimiter = listDelimiter; this.isAttributeSplittingDisabled = isAttributeSplittingDisabled; } /** * Processes the node hierarchy and adds new nodes to the document. * * @param rootNode the root node */ public void processDocument(Node rootNode) { rootNode.visit(this, null); } /** * Inserts a new node. This implementation ensures that the correct * XML element is created and inserted between the given siblings. * * @param newNode the node to insert * @param parent the parent node * @param sibling1 the first sibling * @param sibling2 the second sibling * @return the new node */ @Override protected Object insert(Node newNode, Node parent, Node sibling1, Node sibling2) { if (newNode.isAttribute()) { updateAttribute(parent, getElement(parent), newNode.getName(), listDelimiter, isAttributeSplittingDisabled); return null; } else { Element elem = document.createElement(newNode.getName()); if (newNode.getValue() != null) { String txt = newNode.getValue().toString(); if (listDelimiter != 0) { txt = PropertyConverter.escapeListDelimiter(txt, listDelimiter); } elem.appendChild(document.createTextNode(txt)); } if (sibling2 == null) { getElement(parent).appendChild(elem); } else if (sibling1 != null) { getElement(parent).insertBefore(elem, getElement(sibling1).getNextSibling()); } else { getElement(parent).insertBefore(elem, getElement(parent).getFirstChild()); } return elem; } } /** * Helper method for updating the value of the specified node's * attribute with the given name. * * @param node the affected node * @param elem the element that is associated with this node * @param name the name of the affected attribute * @param listDelimiter the delimiter for attributes with multiple values * @param isAttributeSplittingDisabled true if attribute splitting is disabled. */ private static void updateAttribute(Node node, Element elem, String name, char listDelimiter, boolean isAttributeSplittingDisabled) { if (node != null && elem != null) { boolean hasAttribute = false; List attrs = node.getAttributes(name); StringBuilder buf = new StringBuilder(); char delimiter = (listDelimiter != 0) ? listDelimiter : ATTR_VALUE_DELIMITER; for (ConfigurationNode attr : attrs) { if (attr.getValue() != null) { hasAttribute = true; if (buf.length() > 0) { buf.append(delimiter); } String value = isAttributeSplittingDisabled ? attr.getValue().toString() : PropertyConverter.escapeDelimiters(attr.getValue().toString(), delimiter); buf.append(value); } attr.setReference(elem); } if (!hasAttribute) { elem.removeAttribute(name); } else { elem.setAttribute(name, buf.toString()); } } } /** * Updates the value of the specified attribute of the given node. * Because there can be multiple child nodes representing this attribute * the new value is determined by iterating over all those child nodes. * * @param node the affected node * @param name the name of the attribute * @param listDelimiter the delimiter for attributes with multiple values * @param isAttributeSplittingDisabled true if attributes splitting is disabled. */ static void updateAttribute(Node node, String name, char listDelimiter, boolean isAttributeSplittingDisabled) { if (node != null) { updateAttribute(node, (Element) node.getReference(), name, listDelimiter, isAttributeSplittingDisabled); } } /** * Helper method for accessing the element of the specified node. * * @param node the node * @return the element of this node */ private Element getElement(Node node) { // special treatment for root node of the hierarchy return (node.getName() != null && node.getReference() != null) ? (Element) node .getReference() : document.getDocumentElement(); } } /** * A special implementation of the {@code FileConfiguration} interface that is * used internally to implement the {@code FileConfiguration} methods * for {@code XMLConfiguration}, too. */ private class XMLFileConfigurationDelegate extends FileConfigurationDelegate { @Override public void load(InputStream in) throws ConfigurationException { XMLConfiguration.this.load(in); } } } ././@LongLink100644 0 0 156 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/XMLPropertiesConfiguration.javacommons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/XMLPropertiesConfigura100644 33025 12232154103 33522 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.PrintWriter; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.Iterator; import java.util.List; import javax.xml.parsers.SAXParser; import javax.xml.parsers.SAXParserFactory; import org.apache.commons.lang.StringEscapeUtils; import org.apache.commons.lang.StringUtils; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.Attributes; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.helpers.DefaultHandler; /** * This configuration implements the XML properties format introduced in Java * 5.0, see http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html. * An XML properties file looks like this: * *
 * <?xml version="1.0"?>
 * <!DOCTYPE properties SYSTEM "http://java.sun.com/dtd/properties.dtd">
 * <properties>
 *   <comment>Description of the property list</comment>
 *   <entry key="key1">value1</entry>
 *   <entry key="key2">value2</entry>
 *   <entry key="key3">value3</entry>
 * </properties>
 * 
* * The Java 5.0 runtime is not required to use this class. The default encoding * for this configuration format is UTF-8. Note that unlike * {@code PropertiesConfiguration}, {@code XMLPropertiesConfiguration} * does not support includes. * * Note:Configuration objects of this type can be read concurrently * by multiple threads. However if one of these threads modifies the object, * synchronization has to be performed manually. * * @author Emmanuel Bourg * @author Alistair Young * @version $Id: XMLPropertiesConfiguration.java 1534399 2013-10-21 22:25:03Z henning $ * @since 1.1 */ public class XMLPropertiesConfiguration extends PropertiesConfiguration { /** * The default encoding (UTF-8 as specified by http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html) */ private static final String DEFAULT_ENCODING = "UTF-8"; /** * Default string used when the XML is malformed */ private static final String MALFORMED_XML_EXCEPTION = "Malformed XML"; // initialization block to set the encoding before loading the file in the constructors { setEncoding(DEFAULT_ENCODING); } /** * Creates an empty XMLPropertyConfiguration object which can be * used to synthesize a new Properties file by adding values and * then saving(). An object constructed by this C'tor can not be * tickled into loading included files because it cannot supply a * base for relative includes. */ public XMLPropertiesConfiguration() { super(); } /** * Creates and loads the xml properties from the specified file. * The specified file can contain "include" properties which then * are loaded and merged into the properties. * * @param fileName The name of the properties file to load. * @throws ConfigurationException Error while loading the properties file */ public XMLPropertiesConfiguration(String fileName) throws ConfigurationException { super(fileName); } /** * Creates and loads the xml properties from the specified file. * The specified file can contain "include" properties which then * are loaded and merged into the properties. * * @param file The properties file to load. * @throws ConfigurationException Error while loading the properties file */ public XMLPropertiesConfiguration(File file) throws ConfigurationException { super(file); } /** * Creates and loads the xml properties from the specified URL. * The specified file can contain "include" properties which then * are loaded and merged into the properties. * * @param url The location of the properties file to load. * @throws ConfigurationException Error while loading the properties file */ public XMLPropertiesConfiguration(URL url) throws ConfigurationException { super(url); } /** * Creates and loads the xml properties from the specified DOM node. * * @param element The DOM element * @throws ConfigurationException Error while loading the properties file * @since 2.0 */ public XMLPropertiesConfiguration(Element element) throws ConfigurationException { super(); this.load(element); } @Override public void load(Reader in) throws ConfigurationException { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setNamespaceAware(false); factory.setValidating(true); try { SAXParser parser = factory.newSAXParser(); XMLReader xmlReader = parser.getXMLReader(); xmlReader.setEntityResolver(new EntityResolver() { public InputSource resolveEntity(String publicId, String systemId) { return new InputSource(getClass().getClassLoader().getResourceAsStream("properties.dtd")); } }); xmlReader.setContentHandler(new XMLPropertiesHandler()); xmlReader.parse(new InputSource(in)); } catch (Exception e) { throw new ConfigurationException("Unable to parse the configuration file", e); } // todo: support included properties ? } /** * Parses a DOM element containing the properties. The DOM element has to follow * the XML properties format introduced in Java 5.0, * see http://java.sun.com/j2se/1.5.0/docs/api/java/util/Properties.html * * @param element The DOM element * @throws ConfigurationException Error while interpreting the DOM * @since 2.0 */ public void load(Element element) throws ConfigurationException { if (!element.getNodeName().equals("properties")) { throw new ConfigurationException(MALFORMED_XML_EXCEPTION); } NodeList childNodes = element.getChildNodes(); for (int i = 0; i < childNodes.getLength(); i++) { Node item = childNodes.item(i); if (item instanceof Element) { if (item.getNodeName().equals("comment")) { setHeader(item.getTextContent()); } else if (item.getNodeName().equals("entry")) { String key = ((Element) item).getAttribute("key"); addProperty(key, item.getTextContent()); } else { throw new ConfigurationException(MALFORMED_XML_EXCEPTION); } } } } @Override public void save(Writer out) throws ConfigurationException { PrintWriter writer = new PrintWriter(out); String encoding = getEncoding() != null ? getEncoding() : DEFAULT_ENCODING; writer.println(""); writer.println(""); writer.println(""); if (getHeader() != null) { writer.println(" " + StringEscapeUtils.escapeXml(getHeader()) + ""); } Iterator keys = getKeys(); while (keys.hasNext()) { String key = keys.next(); Object value = getProperty(key); if (value instanceof List) { writeProperty(writer, key, (List) value); } else { writeProperty(writer, key, value); } } writer.println(""); writer.flush(); } /** * Write a property. * * @param out the output stream * @param key the key of the property * @param value the value of the property */ private void writeProperty(PrintWriter out, String key, Object value) { // escape the key String k = StringEscapeUtils.escapeXml(key); if (value != null) { // escape the value String v = StringEscapeUtils.escapeXml(String.valueOf(value)); v = StringUtils.replace(v, String.valueOf(getListDelimiter()), "\\" + getListDelimiter()); out.println(" " + v + ""); } else { out.println(" "); } } /** * Write a list property. * * @param out the output stream * @param key the key of the property * @param values a list with all property values */ private void writeProperty(PrintWriter out, String key, List values) { for (Object value : values) { writeProperty(out, key, value); } } /** * Writes the configuration as child to the given DOM node * * @param document The DOM document to add the configuration to * @param parent The DOM parent node * @since 2.0 */ public void save(Document document, Node parent) { Element properties = document.createElement("properties"); parent.appendChild(properties); if (getHeader() != null) { Element comment = document.createElement("comment"); properties.appendChild(comment); comment.setTextContent(StringEscapeUtils.escapeXml(getHeader())); } Iterator keys = getKeys(); while (keys.hasNext()) { String key = keys.next(); Object value = getProperty(key); if (value instanceof List) { writeProperty(document, properties, key, (List) value); } else { writeProperty(document, properties, key, value); } } } private void writeProperty(Document document, Node properties, String key, Object value) { Element entry = document.createElement("entry"); properties.appendChild(entry); // escape the key String k = StringEscapeUtils.escapeXml(key); entry.setAttribute("key", k); if (value != null) { // escape the value String v = StringEscapeUtils.escapeXml(String.valueOf(value)); v = StringUtils.replace(v, String.valueOf(getListDelimiter()), "\\" + getListDelimiter()); entry.setTextContent(v); } } private void writeProperty(Document document, Node properties, String key, List values) { for (Object value : values) { writeProperty(document, properties, key, value); } } /** * SAX Handler to parse a XML properties file. * * @author Alistair Young * @since 1.2 */ private class XMLPropertiesHandler extends DefaultHandler { /** The key of the current entry being parsed. */ private String key; /** The value of the current entry being parsed. */ private StringBuilder value = new StringBuilder(); /** Indicates that a comment is being parsed. */ private boolean inCommentElement; /** Indicates that an entry is being parsed. */ private boolean inEntryElement; @Override public void startElement(String uri, String localName, String qName, Attributes attrs) { if ("comment".equals(qName)) { inCommentElement = true; } if ("entry".equals(qName)) { key = attrs.getValue("key"); inEntryElement = true; } } @Override public void endElement(String uri, String localName, String qName) { if (inCommentElement) { // We've just finished a element so set the header setHeader(value.toString()); inCommentElement = false; } if (inEntryElement) { // We've just finished an element, so add the key/value pair addProperty(key, value.toString()); inEntryElement = false; } // Clear the element value buffer value = new StringBuilder(); } @Override public void characters(char[] chars, int start, int length) { /** * We're currently processing an element. All character data from now until * the next endElement() call will be the data for this element. */ value.append(chars, start, length); } } } commons-configuration-1.10-src/src/main/javacc/PropertyListParser.jj100644 15333 12232154103 25364 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ options { STATIC = false; } PARSER_BEGIN(PropertyListParser) package org.apache.commons.configuration.plist; import java.util.Date; import java.util.List; import java.util.ArrayList; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.HierarchicalConfiguration.Node; import org.apache.commons.codec.binary.Hex; /** * JavaCC based parser for the PropertyList format. * * @author Emmanuel Bourg * @version $Revision$, $Date$ */ class PropertyListParser { /** * Remove the quotes at the beginning and at the end of the specified String. */ protected String removeQuotes(String s) { if (s == null) { return null; } if (s.startsWith("\"") && s.endsWith("\"") && s.length() >= 2) { s = s.substring(1, s.length() - 1); } return s; } protected String unescapeQuotes(String s) { return s.replaceAll("\\\\\"", "\""); } /** * Remove the white spaces and the data delimiters from the specified * string and parse it as a byte array. */ protected byte[] filterData(String s) throws ParseException { if (s == null) { return null; } // remove the delimiters if (s.startsWith("<") && s.endsWith(">") && s.length() >= 2) { s = s.substring(1, s.length() - 1); } // remove the white spaces s = s.replaceAll("\\s", ""); // add a leading 0 to ensure well formed bytes if (s.length() % 2 != 0) { s = "0" + s; } // parse and return the bytes try { return Hex.decodeHex(s.toCharArray()); } catch (Exception e) { throw (ParseException) new ParseException("Unable to parse the byte[] : " + e.getMessage()); } } /** * Parse a date formatted as <*D2002-03-22 11:30:00 +0100> */ protected Date parseDate(String s) throws ParseException { return PropertyListConfiguration.parseDate(s); } } PARSER_END(PropertyListParser) SKIP : { " " | "\t" | "\n" | "\r" } // Handle comments MORE : { "/*": IN_COMMENT } < IN_COMMENT > MORE : { < ~[] > } < IN_COMMENT > SKIP : { "*/": DEFAULT } MORE : { "//": IN_SINGLE_LINE_COMMENT } < IN_SINGLE_LINE_COMMENT > SPECIAL_TOKEN : { < SINGLE_LINE_COMMENT: "\n"|"\r"|"\r\n" > : DEFAULT } < IN_SINGLE_LINE_COMMENT > MORE : { < ~[] > } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { } TOKEN : { " > } TOKEN : { } TOKEN : { < QUOTE : "\"" > } TOKEN : { < #LETTER : ~[" ", "\t", "\n", "\r", "(", ")", ",", "{", "}", ";", "=", "\""] > } TOKEN : { < #WHITE : " " | "\t" | "\n" | "\r" > } TOKEN : { < #HEXA : ["0"-"9", "a"-"f", "A"-"F"] > } TOKEN : { < DATA : ( | )* > } TOKEN : { < DATE : (["0"-"9"] | ":" | " " | "+" | "-" | "Z")* > } TOKEN : { < STRING : ()+ > } TOKEN : { < QUOTED_STRING : ( | | | | | | | | | )* > } TOKEN : { < ESCAPED_QUOTE : "\\\"" > } PropertyListConfiguration parse() : { PropertyListConfiguration configuration = null; } { configuration = Dictionary() { return configuration; } } PropertyListConfiguration Dictionary() : { PropertyListConfiguration configuration = new PropertyListConfiguration(); List children = new ArrayList(); Node child = null; } { ( child = Property() { if (child.getValue() instanceof HierarchicalConfiguration) { // prune & graft the nested configuration to the parent configuration HierarchicalConfiguration conf = (HierarchicalConfiguration) child.getValue(); Node root = conf.getRoot(); root.setName(child.getName()); children.add(root); } else { children.add(child); } } )* { for (int i = 0; i < children.size(); i++) { child = children.get(i); configuration.getRoot().addChild(child); } return configuration; } } Node Property() : { String key = null; Object value = null; Node node = new Node(); } { key = String() { node.setName(key); } value = Element() { node.setValue(value); } ()? { return node; } } Object Element() : { Object value = null; } { LOOKAHEAD(2) value = Array() { return value; } | value = Dictionary() { return value; } | value = String() { return value; } | value = Data() { return value; } | value = Date() { return value; } } List Array() : { List list = new ArrayList(); Object element = null; } { ( element = Element() { list.add(element); } ( element = Element() { list.add(element); } )* )? { return list; } } String String() : { Token token = null; String value = null; } { token = { return unescapeQuotes(removeQuotes(token.image)); } | token = { return token.image; } } byte[] Data() : { Token token; } { token = { return filterData(token.image); } } Date Date() : { Token token; } { token = { return parseDate(token.image); } } commons-configuration-1.10-src/src/main/resources/digesterRules.xml100644 3722 12232154103 25307 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/resources/properties.dtd100644 2043 12232154103 24630 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/main/resources/PropertyList-1.0.dtd100644 3450 12232154103 25413 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/site/resources/images/logo.png100644 36317 12232154103 24725 0ustarhenningstaff 0 0 PNG  IHDR,dcbKGD pHYs  ~tIME ,"CKpb IDATx=iXTWv7͢}ύfyIdu|& "5Aq%&13kce}cP@gbTąYG֫>iЈ_]9uj;u#`;(Zvÿ;ؕvhe+`WB;ءvC+] `V v%ZJh;2ؕvhe+`WB;ءvC+귓aHFjMImh9>^vF oC``e?SHHȶmEQ=1LuppG?~~F#!oSC@VիWFFFv 2qҥ4y$@{0YJdN:ա"7";v ۀڲvZDMM8.]YL&)-v`hhhdNl]RڪЄGh04c(a@SVs`T8)MMMEC޽;m;[GGhJ6??֭[怎;aʍD豩AIHHرc,)yimXm)NCճgO0l`$ @0 #eFZĤx˗$@%*+=3 '|0KC"y@n@9*_ܰFQd1֡CtBUT}ᖂ.^Ŭ-˹83F2p|1cdggEc d-%# N2Z2˵kQRPOp&'?s(|Xg$JK(SNڀ16PL9YhCaa!l0VRq3|.е)*zWF$r^ˋ y&ic|Jhuۅ (h iP@ ۵k׾}C@E)e$- 444T|4zWZ'`˭꡼8I G!33P[z=[啜5_bEdd$|ݻ/X_~O=!2) S 0Nk:zBy@}`Y.2h L5Cym&5i#!8˲[K\ݜN XONNiӦY'VhۃFش#}ӽ{w² Kg6-eiӦĉ9ŋ_~.!:mmK }a>9E 0@!+=.7___0Ɗ Eo׮s=:ujРAdÆ \ AC[J3\&5'55uԦr*}$e[\hT$ro\a0 @cR3f͚5@K?ׯ)ѣGP ǥPrVv…EEEꃙG?IESІ ${\7a]1Kކpm!fffbh\ھ}?#G4i"z(0Em61'V Ê+ ~R>Ơ{ Vbӧ1!XNWJa̙3g@UB\`tww_"jDQLMMiK>}:}֠6&$w sMN;vlff&C4QWݻNۻw/҂dJj%%%XahaũdҰl zD ={p11)c<.Xf [RVw 1}||h jt̆t룏>~΁82o޼]f{-tΝ;)w}OOCa!V?WBHJJ;N֮][TTFsp2|޺u+d)=  ~[nQêVd. OP(bbbv!xͯڄ ƍvZPu W\;w.E*uȑ.] 57od6n84`hI }ڵǩk:#:hܹ3,, PL/BQQQFcSEA*Xxx믿nm@!hnUܾ}{hh(n-܀111='O۷ƍ7%%O>cƌaiǏɮةS@d(r+k֬W\S}!MrӧOzsq(+Ȥe@fR Եk#GadddKOO?3<鼼v!Z7A֭[Nq۩R>|xС0~mxiddMXm8wTvƟ966φ`ʔ)SN%3Z>Ԫ7o޼k.<8) 76GGǴr'04ϰawtt̴4hСC{W^yFۭ[r"jcƌqqqqpp8tЅ  dCBBۭ[7Zm'44k׮}}aǝ(<9|BBB~~Uzyy͚5k鸛b899feeah#o'v4++v*lgXXXtt /RƎ[XXf2kƘGPP5cƌSIp&6NNNj~дƚ_~%++ĉ4_hh(*^&Iu؜˗/T*QQQZR PfBh?i\qqq}uttܴinj9s2WjemT;w/`,^yZE$@y̙}Š:UWW-((=qjZVXvS^Y}Ν;?*'4% 0}}\pͭcǎpTnnnii+WJJJ`WGPPЈ#0CP-q>E1҉8jRގ O1tnl!b`¡62"32ɔ@n( Zd@V!s-!ePQ>p2 BұPHg% hN`J4&{p@p(cNJۆͺjVs{qOhlO ҀDA8H`\$ǫQ'HH[)ZtMA~*<uv@;`H+Nͦ}0̟?_5k֤3FR^fDj-޸ʗK(vM,q||ccC YnֈrGI-/"%%eܸq1OOÇ jSv%|DHIIQQQ۷o^(eL&S^^(x_-e G5j(aR[Ο?i:xxxDFFRrO9焏:팈X8X~ P(`-n>|p4=l_~9|ph) bOV~h@-r111Й& VZeJ111111𸗗׊+PPPps碶={0W\I/pjp߯h,XO?eggo߾}QQQQQQӲe޽{Ν;wܽ{DUXtt42+>>.>޺u A$XqlsH PFyyyQ UH&h(۷o^nyvuNg0vڕ,jݻ{ݻw߿_UUE3yC/hp)azz:tW^~- h駟QQQUUUUUUpbiZlժU9g|ojKΝ;'N//* ]YA3g޿gϞڻw/_f.]lٲǏ8p ""b;wܹ"7~L`c,::plYUU10 ߂0Q#Gb _oa)r .@jܹTTee?UQQQYYo=|ҥK`>S5PIDAT~ rqDEEݿ\٦jΝOeeeeeeypL#ӽ{,]?)) q֬Y'gfffee㏷n2 wޥԎ;.++sNEEV`Ncz$愣G{޽¦@7oY(JСCP۳gH}ڴi>c,--AAAH$00gϞ& )..rww믽Ahhh2e Lj̠(fee/-3L aСPN B0 Bӽ+0 j;w<&a <<|ԩ1Ѩf>frOxxxmmH2@1A={? Hdg4'O駟@iȐ!F:n2&Nx!ȑ#w dE͍̽]ʷ} Mݻ2;:vV8+T )H+!jȑ#܁\x) 8r'&&6 nZZhloy嗍Fcll߆ A ,tޝ_EQւցvAnFu{n̲'L$#vh4B~ #zc4ȝ9@o[qq}jjj:tpСb777??:&^8uÇ3Ƣv0Yg_z%PB5K MI (R =x ZV<&hY|ZZ W^10z &4>EյحP(z=j`pp[o'EbւJ%ZM9sD `tvv6yF#8š 90+8p $tE  ^d60IKU*Z6sа4\;u# deeر㵵/ˢ(?o4sҥ̹00Lb䰟kEB .t:'/?~p(-fddf3fq][Ç;DQ0LHm8ED"E)_NNmHHȑ#Gmۆ!"P;vs21TQ*`0ZXXoѥ)00@h4 7f_|8@z{ټaĉl pE8dȐ &G]]psssΝ;{+P*Jx;e/~J*A00`'?H'&?p-(zyy曔ЪP{n۶ {>}N:ӎ;±0/))ALN%fj`!HF???p .uě99} <[ҡpS&@n8 ?eee5k8 ÇCPǔ)S(OBCC0r>c,-- >BD'2pWk@@I:+M#qqq;wN\8ANOi֝IUz~ɒ%H &0T0>3IR sΝ3g΋/ȠA, h Z@%%0 %r l\/"pnMAQJo}נAjjjhȊ}َcǎ͝;՞Ԏ;SNPJGDT]hHF)]PSHexp)e^xbāL6=@h|ɾEvQ13qevOe Ta@```ntF`pQ_o2PScǎ.o1TQDcL% @$+Tb mwc…H`Q _پ};0AhI 8keCb21<<^9!Ȑl6=z-))Y||̔J%aaa/ P*E@;548 arr2`=z o9s& _|h(LQ0d3BT.YJp8]WxBP\\`ESHY{ܪw1IDDAcQ`Ζ-[()!ǚK@F]>4ЊD%T+(4W ARI3)$$Ȃ{=3Y eQ:i$y, 2WXF,xxxrt3`':$QQQ;v`p+WΝ ?mڴF#Wx!???Ng͚R1`ߢЖPR8RTA Q @$j& { "'''{`䇫<9A [dNHovssDx=6]n l9CXΝkjjlŒ4=zf$816qD֨9rT 3MX7Ȃ 1oС'OFk+9'H~qqqHHHqqŋ=<DYϑ#G^}Օ+W^|Y\\#pJpqBC7E4Q?~ 4H4hDcRSPYb:3 #F1buѢErII vd2M2eΜ9nnn4hpȐ!o`BwQl<$"̙3} 쀞deeuM}ež Bh>))iСhWZMc SJi`"L&SRR… 4 MXjT*{OnJY{RJJJ^=z|yyyW@믏=rJ^ܹI.zx|AYY̙39@V4JaFgI&}wtXٌEرc`#` TZfxҤIg޽;4x:SΜ91?|zG V; 0~xھc:::޹s999gϦ,Z6))I@9zYZ={lk׮~98::8::vԉBBBPa rvvRNNN*Ņh4[lh4x|)9x l /hl޸uVOOOjԨ" M9Ru1-nrclٲUaqTC}/uMf?{v8q"DظqM!+p1;+3(fbbb֧~i&֕5:|{07nΆ$WPPPI p͛7srr@&Lj-p5gitAȸyfǎ?,]t0WƘXDgggZT*EQLOOqK/?| ^{ph"p֭={9sx77sΩ >0L&oܸQ[[ꫯbPɗ.]*,,ܹ'<N !WE@R999kР0F0pN}饗cxW_544Pj9T> VaaazzzΝ_xvB8f4oݺu֒zBQBi`(PL4h2PC "]8 ۀ(3H,>!@F@6mqQvpf3À={ ѱ<$$1v777dvl68pVrZj8Q%&ሠ|D!5AFj^b(Al  TQA`L  @ЃᩰOX~.G[dI)bN,^@c$4Lrv(&{ifYĀ,cIlR:ɓ'æuFVi `a䀚` +**JLLtwwk4B;T dChs%ND`0LdApR+HϘ13^R ~E/RX.^SV3p;"&/@n8{c+&ǁpSE ;ՎTܣ")_yWULFg41I\%RBhi(5"~B4/|CeU!ARknЎ*ql >"H9h<x䠂ihXQoR_Əc1Rɭ1`iY*@%xd2-GkM#(|I(݄ ;ЩbGQsV$4AҬNyPXξA:2e2C$ɗC$*{7RhpI {~rW,|8++뭷ނ_hdOgQõM5s"Ot:].]pwg@Eq UQj2MER_çL ?_Ĵ Ka,+~qPIMi:EԹqJBR&s0'drhqc,+H.RZtF$*[R 9aÆwy1v˗/ŋ<==i,B5F.v;+] ?\`&'L $/2cǎĻw~hh(kE]Dq,fSzW… ;w?70y<<<ߡCLW0$ Zs,$ǡ?QEjsJN*HqU?J껬b>:Mr>6c8:PqisA.(䓳SxD#&M䵅*te| AAA1V}v^x1444---...''ۛ]P,DuwfsheR㉎;n9!&'ʑ4^ZRɝ&rOɡ93KK& ߆-Çqww_d 4tTN-l|'iii- 1yyyEEEx (eayKl6<8fNGnC5E+C~gI#ttgX$TcR5n K.]hG&A6v]ck4] TB<ܩ$0µ櫁(DF[T@[Izf)دI|ڣE"2' D?TTss;ؕcN <j 2 $%5Rl3`WN=r9u4k, {eY殸Dz`;<`W_^)(,کpy" ŕ1P nf XV3Kd-nB0غmV{v6 2~p9X^m qIENDB`commons-configuration-1.10-src/src/site/resources/images/logo.xcf100644 65267 12232154103 24727 0ustarhenningstaff 0 0 gimp xcf file,dBB/ gimp-commentCreated with The GIMP&<K-i , Text Layer#2     1W,s, T    UUU8 8U88⪪ qqU8q88q8U88U8UUUUUUq8U8UUqUƪqqUU8qU8Uqq8888Uqq8q qUU8U8UU UU8UU8UU8U q8UqqUU8U8UUq8qUUqqU Uƪ8 UU8UU88U8?U;q;;q<=   U:ƪq5UUUU.q-UU,Uq8q88,,U 8.q99q;58UUUU88 8UU qUUq 8UU8UUU888ƪqqUqqUUqqU8q8UUUUqUqUU8UU8UUqq8UU88 U8  ƍ q q8U8UU8UUUUUUU8 8q8 UUUUU Uq 8U8UUqqUqU8q  U  U8 8Uq U Uq88qƪU 8UU   8UU U88UqU8UUqUUU888qq8UUqUUqqUqUƪU8q8U8U8UU8qUU8U8 8qUqqq 8qq8UqUqqU 8qq 888qUqUUq8 UU8UqU UUqq 8qq8 8qUƪUqUU qq q888U88UUUUUU   :q999U.UU/:U:9U9qUUUU8 8U8U qqU8qUU8q q8U8U8UU UUq8U8UUqUƪqqqUU8U8Uqq88Uq8UqqU8q qUU88U8UU UU888U8UU8UUq8Uq88UU8UU8UUq8qUU8UUƪ8 U8 UU88U8&Uq8UU8U$@ <Drop-Shadow#2p     -<;;;<(b0`9h"                "$&'&"  !#%'('$ &*,+'"  $')+-04662*   %)*+,.14785/&$.8?B?92, !(.12235:?DEA8, (/4654459?EHGA7,"%1?LUXUMC< '07;<:878=ELOLC5'&09?BA=977856;DMSQI;.#"*6AJNMH@844:FT`gdYI9/-5DXky}xl_S +9FOQNF<3./4>HOOH<1)(/:GRYYSI=3-.5DVgqqgVD63:J`uteX)9IU[YPD6,%%*3=DEA81.2=KXbd_TE6+%&0AVky{r`L<7=NdzwfW $6HXbc\O>."'/686203." +>Vm}yfQA:ARi~vcS/CWelh[J7&!&)**.8GXistl[H4$)>Xp|jTD>EVmq]L %:PdpriXC/  %/>Rfu|wiU>+)@Zs}jTEAI[r~jUD.D\oxvhS<'  #2F\q~wdL5",D^vzgSECNawwaK; 5Nfw~weN5!  #6Mfzs]C-1IcxuaOEFSg|nWB4 %;BRfx~pZB/$$ )A\tzeM6%.C\su_F0!"/?P]caXJ=57BTiy~wfO8( # &73358:95-$'7GTYUH6%'6EQWXTNF>70)# &3?HJHB;5100/,& -;EHC8) &2MVWQH@=>BIPW]a`ZN=+ '9KY_[QD81/38?FMRSNC4%   2EXdf_P?1'#$(.4;@A=5)  +?SdnmbP=,!"',01.'    '8MaqxtfR>, !%''$   !!$4G\p~|kVA0# $'(&!   #)0452,#"0AVlp[F5*$#&*/21-%  !$%&')+,-+'" *-3@@;3* 9;CNYbd`TD5(#&0AVmq\I<427@JSWSH9( !,6=AA?=>AGNTUPF9,!EGP\itxsfS?/'(2CYq~iUD946>KZeicUB.!/=HNOLFBBGP[dgcWG6(!MOVcr~r\F3)(1BYqs^J;206BServo^H2 .>NY\YQHAAGTcpuqdQ=-$PPWdtwaH4(&.@Wp|gP=/)*3DXlz}ubJ2 (:N^gg_RE=VnqZC0$ %1D[q~u`G0 1F[jqm`O@78CUiz{kU>,$IGN\n~t]C/#!+=Um~zgO8&"1F^tr\C,$8Ndsvo^K;35BUjzyhP:)"B@HXk{~nV>* +?Wm|~s^E/!2Jbv}mV='')#7OgyygN6"(=Ujwxm[H:5:HZlvvjWA." 47DWky|s_H1"!/E]q{xhP8$':@M]jpk^K7' /6EZmyzmYA,#3Jat{ucK3 ,C\r~}pZ@*"6Laosl^ODAFQ\de^O=, !-7I^qzwiS<)&7Ofvzq]E. 2Jcw{kT;% 0F[jplaULHKQWZWM?/"#,9Nct{udN8&)Sdopi_UNIFC>6+!)/BYn|}r_I6("&3G^pytdM5".E_uu`I2! +?UgsuoeYOG@91(-1F^s~r_J7+&+9Mbsxq^G02Jdyt_H3".DZmy|vl_SH>4*  13Jbvr_K:.+0>RftwmYA+!4Mg{s^H3#!3I`tvi\PC7+ 43Jbv}p^K:0-4CWjuuhS;&!5Nfy~p\F3$&8Nexvj]PB4&  41G^pywkZH90/7GZlurcM5" 3Jas{wjWC1#++')7BHGA7-'&-;M_kk`M7#  )6AEC<1& )3=DJMQTY_gox~r`K5#'0562,&"%.=O_heXE0  &-0.)"'2=DGFC@?AGP[ht}xiT<( "'))&#"&0@Q^c^O<(   -;FKJC:3.-1:FUeszxkW@+   %''&'+5CR[]TE2!   #3BMQMB6*" ")5EVfqriW@+  ',//04CJPQK?0   $6GSWQE7)&3CR\^WH6# (5@FHGFHJKH@4% !2COTQG:.$ '2?JRRK=- +9FMOMKIGD>4(  +;GNNG=3*%#%*2;CGE=1# *8EMOMIE@:2(   #0BA<856:?A@:/$#(+,-.049>AA=4!,:GPQK?0!(7CIH?2$+:HSXVQJFGKPSQI=/#%,1576609?GPUUOC (6GWac[K8'&6GU\YM<+$4FXekibZUTW\^\SE7,&',3;?A?<99>FR^ff^O$-=QcopfS>+"0DXglfWC/ (9Ocszxpf^Z[^`]UH<414;CIJHB<88=IXgqqgV%0BWkwwkV@-"!*;Qfuxo\E/ )=Tk}xk`YWXXUOF>:@GPX\[SG:0*,7H\oyxkV&4I`s|xhR<-',GR]dd]P@2'#(4G]pyugQ'7Mdu{ucM9,*4F^vnT:&/Gbzs^J9.)')-5AO]hkgZI8) %5J`qxraK):Qgwzq^H7-/-" (6FXhqpfUA/"'8Ndswn[E,?WlxxlYD505E\t{bG/%9SmycJ4#(:NbqvqbN9',?VjvvjU?0E\pyvhUB54=Of}v[@**@ZtqY@*,AXlxzo\F1!"3H_qzufP:4KbtzueQA89DXnpU;'0Gay}hN6" 1Iat~{lV?+)L_ukP7%$6Nh}u]D, "7Qi||jR:'"2G_tu`I4?Wm{|rbPD@ESfz~fM6%*=Vn~lS:$ &=Wp|hO8' *;Rj}u_G4D]s~tcSHEKXk}{dL6'!$0D\swbI1  )A\u}iP:+%'3F]su^G6IcwvfVLJO\m~ycK8*%)6Kbu}oX?(  *C^wlU@2-1>EQ`lqmaP?0&%+8HW_^RA.,AWitvqgZNFBDLYfprl^M=28JYbb\PD9216ANY]ZPB3'$0=IOLB3#  "3EU`ec\RG?::?IT\^YN@2)+9EKLG>3*$#'0:CGD=2&%09<:1%$2@JOOKC:3-,07?EGC:/%(0551+# (.1/*""(*(!  !+37861*$  %+/1.( !!     #$#          73 0  0 ! .  )02/' % *8AD?4&# #3CNQK>. "  %7HTWQC1! !   $5FQTNA0      /=GID8) %+-+$  &19;6-!  "-8>@;2&  ',-)!  %3AMTTM@1" "%$     &6GXdkh^N;+#&%"   $3FZmy~ykXD2%%+01.'  !#%'('$ &*,+'"*"#-?Tk~s^I7*%&,4=BB<2%   %)*+,.14785/&$.8?B?92,6*%(4G^vt^I8-*.8DOVUL>.  (/4654459?EHGA7,"%1?LUXUMC<>0)+7Kc{nWC4--5BR`hf[I5#%/9?BA=977." +>Vm}yfQA:ARi~vcS6'")9Pfw|taI3!+AZp~t_G4('1BVgstl[H4$)>Xp|jTD>EVmq]L1$"+=TjwynYA+/F_t}nYB1)-;Odt{wiU>+)@Zs}jTEAI[r~jUD-##/CZnxwhR:&!4MexziR=/+3E[p~vdL5",D^vzgSECNawwaK;*"&4I_rytdM5"&;Tk{vcL8-.:Neys\C-1IcxuaOEFSg|nWB4(#)9Oeuzq_G1,B[q~~r]G5-1@VnnU<&#8Pgy|mZJCIXmycL9.(&.@Vkyzo[C- 2Ibv}nXB3-4E]t~iO5!*?Vkx{scQECL]rpXB1)**4G]q|zmX@,%8Ph{{kU@2.7Iaw{eJ1 1F[ltrgWH@BObvyeM8*&-/;New{lV?,*>WnzhR>208KbxxaG/(9L]ilfYJ>;BRfx~pZB/$$14AUk{|lV@-!!/D\szgQ>208I`uu_F0!"/?P]caXJ=57BTiy~wfO8( #59FZo~{kU@."$2G`uyfQ>2/6EZn{|r^H4& "*6DPXYSH;1.3BVjwyn[D/"#6:H\p}yhS>-"$2G_tucO=0,1>Qdqtm]J9-(*1;EMOLC8-''0AUgqpcO9'"49FYkxzrbN;* "0D[nyyn]J9,'*5EVcieZK=3/0573358:95-$'7GTYUH6%%*4CPZ[UH9*#2CQZZRE6((4@HJHB;5100/,& -;EHC8)'3=DE@6*&3>DD>4($.59962.+)'&# ",351( #*/0,% #+//+$ $()(&$!  #$                 Fttt   !! #)0452+"*-3. %6GU[YPC4% )6AFD=3' %-0/*#      D" Text Layer      <<KK!<@DI8qU8Uq8q8q q UU88UU8qUqUUUqUUUqUUq8U8 UU 8q8U8 q   8U 8U UU UU UU 8UU U 8 88 U q 8888 q8 q8qUUUUUqU UUUU U 8qUq q8UqUU8qU 8q8U8 8UqU8qqq88qqUUqUUUqƪUqUUUU8Uqq q8UUU 88UUqq UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU UUUU qUq qUqU8qU88qU8UƍUUUU8q qq q8  8qUU88qU 88 8UU UUUU8U8UUUUUUUUU8q 8UqUUU UUUUU 8UUUU UUUUU UUUU UUUU UUUUUU UUUUUU UUUUU UUUUUU UUUUU8 UUUU qUUUUq UUUUq8UUUUUUUUqUqU88UUqqU8q8qUU 8Uq8 q 8VVV UU ⪪88888Uqqq88  q 8 qU  qU qq8qƪq888UUk 5$ Drop-ShadowD       K$Kii$L T\kd   L          &.49<=<80% &-38<>=:4," & +7BJOTX\_^WI7%   -:CJOSWZ]]ZQE5% #1@L &8HTZ\\]bkwu_D*  )beD( ;eQ*=e]9 &BhoD$*Ky0V}zT0 )LtrI'.TwK'*Mzȳ\3 >m BmoD"  3QlxoV7 >ji<  8dŢrC  6f+Sd8 0BJE5"'M~_2)QϴR) 3c5b\0  $" /[ȷX, CuԿ^1 2b ?oX,   6e̸V*8iƝh8 2b !GxW+ ;lѺW+1_ʣn<2b $L¶Z- >pԾZ-,Yʤp>2b%NǼa3 >o×a2*UȢn<2b %Mßl<  ;kɠj:)TÝh8 2b "I|ʬ}K& 6cΪvD +Vʼ_1 2b Bsѻa7  0YҴP(.[ıS) 2b8gɨ{O-  !,/*)K|Ӿ`35cuE! 2b-WӾpJ. )7@?2" =iŢrC!  @n`6 2b !EtϷpQ;-%#%,7EPQF2-SȰX1 *NzuJ&3c3[ͷgVLHJQZabXC+ m*Krƻs[@' -Lo|aI:35>Ocu|t]@% )Jw .MpĽw^C*  -IgveWPPV_hleT<% !8X~ -Gd~oX?)  )?Vjvyume`]][SF4!  )A\z &:Napz~|uiYG4"   1AOY]][WSNH@5( (<82+# +7AIM !##      !$&     ?   @         !! )   ! )&(4>DE@6(  ,8AFFA6) !(*% ,8AFD=2# PI:+%*8HYgqtoaM6#,=N^ksuoaM5  (6EOOE4'%-mѽ`4  #5YʰW2 3Yʹ]6ĶnI, 6V~ƺuO1 6U}ĶpL2%$.Deb?&&AdıhEmO5!(>ZysU:&)>ZxnR<0/9LgcF-.GeiLzm[F1!'9Nbs~|q_K7&'9Nbs}zm[I90/7EWiw~vgT?,,@ViwykXDNLF<1$)5@HMOMG?4')5@HMNLF=3*%$)1;DJNNJC9-  -:DJNNKE;0&%# !$&&$  !$&&%# #%&&%" "%&&%#         >   A      "       "$0;CGE>2#  #+17;=><7/&  $+.+"%1$ .Hfmceo|acgn{a6 %A`y}kTA516CXra?$1MpʸnfejtOHEHTlwG"  <`yZ='&9Uw^9)DiãfTJHN_z6)$&1JpdzU+ 1WjD' 7Z~R.4ZuR:,'+;Y 3Zȼa3 #FrY1 !@kɽk? (M~Һb<#"@l&Lžj:1ZyJ$,T˰Q*"ExͱR+  1^  Fxţp??mo?  Bsҿb5 CuɫzH" +W  CvƦsA &K}i85cɣp? CuȨvD )T  BuƦtB",UÜf6,WέzG$!CuǧuB (R  BuǧtC#0[ƞg6&NвL'!CuǧuB (R  BuǧtC#2^ʢl: "H|гN("CuǧuB (R  BuǧuC#1^ͨs@  ExαL'!CuǧuB (R  BuǧuC#/YѰ}I"  DwʬzH$!CuǧuB (R  BuǧuC"*RԸS) FyĢp@ CuǧuB (R  BuǧuC!$Hza3 $K~ûc6 BuǧuB (R  BuǧuB 43:H\p|yfJ-  1X˰X3 "@k*'@cb@& &@]x{j[QOS\eki[E- "=b­c@'/Nu3!/GddG. "7Odsywpha^]]\WK:(  (CcdG/#7Sr0!-@Uhw~~vhU@-+=94.& *7CJNNJC:.!%2>G "%&&%"    "%&&%"  $      ?       -  &-13321/,)! U>' )8BGHHJKNNI<) eE( 1FUZWRNMRZeljX< ĩf?  0LdmgXI@?GVj{~kI'W/&Fh}|hL6)'0B\upN*ɾm> 4[d@%+EaqhK)ȭ~K$ ?kf=  /I[XB%̷U* !EtsI( 3CE5 ̽\. Etc@'".0& `0 >leH1!a12\sXA.!b2%GrµlS=+ b2 0S{fL5" ̶b2 5UxȽx[?' b24PnŸeD(b2 .D^zf@"b2 %7MgĬ[3b2 )-$$,=XupM+ƾ}U4$@b|yeQB;;BPbquiP3 xX;$3Mcli_TLHINV^`YH2|}sbL5""3AHIGDCCEHJJD9*MOMH@4&"&()+-/121.' &$!     )p8 ,d Background     i,dijjj,djj'j3j?jKjWjcjoj{j               0002K% commons-configuration-1.10-src/src/site/resources/profile.cobertura100644 0 12232154103 25236 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/site/site.xml100644 3356 12232154103 21443 0ustarhenningstaff 0 0 Commons Configuration /images/logo.png /index.html commons-configuration-1.10-src/src/site/xdoc/building.xml100644 13062 12232154103 23244 0ustarhenningstaff 0 0 Building

Commons Configuration can be built using maven or ant.

Commons Configuration uses Maven 2 as its build tool. The recommended version is Maven 2.2.1. To build the Configuration jar, change into the directory where the source distribution resides and run "mvn install". This will compile the source and tests, run the tests, and then package the jar. The jar will also be copied into the local maven repository for use by other builds.

This build requires a JDK 1.5 or higher. It is possible to build Commons Configuration on a JDK 1.4 by specifying the "java-1.4" profile: "mvn install -Pjava-1.4". This profile and the settings required are described in detail in Testing with different Java versions. If this profile is active, some classes depending on Commons VFS (which is available for Java 1.5+ only) are excluded from compilation.

To build the web site run "mvn site". When it completes the web site will reside in the target/site directory and may be viewed by opening target/site/index.html.

TestWebdavConfigurationBuilder is a functional test that tests DefaultConfigurationBuilder with the configuration files stored in a WebDAV server. To run the test the steps that follow

  1. Copy all the files in the conf directory to the WebDAV server. Not all the files are required but it is generally easier to use a tool like cadaver and do an mput than try to copy the required files individually.
  2. Add the following to the profiles section of settings.xml in the Maven home directory. Modify the urls to match your setup. webdav false webdav://vfsusr:vfstest@192.168.10.133:80/conf ]]>
  3. run "mvn -P webdav test -Dtest=TestWebdavConfigurationBuilder". The test can also be run using "mvn -P webdav test" but this will run all the unit tests in addition to the WebDAV test.

In order to build the project with Apache Ant, some manual preparations have to be done. The problem is that Commons Configuration uses classes generated by JavaCC to process configuration files in specific formats. These classes are produced dynamically during the build process. While Maven is able to download all required artifacts automatically, the Ant build is not that smart. Therefore, it is required to download and install JavaCC manually. Then a file named build.properties has to be created in the root directory of Commons Configuration which defines the javacc_home property; here the path to the JavaCC installation has to be set. Commons Configuration already ships with a build.properties.sample file which can be copied and adapted correspondingly.

After these preparations have been done, the following Ant goals can be used:

  • To build a jar file, change into Configuration's root directory and run "ant jar". The result will be in the "target" subdirectory.
  • To build the Javadocs, run "ant javadoc". The result will be in "target/site/apidocs".

commons-configuration-1.10-src/src/site/xdoc/dependencies.xml100644 14277 12232154103 24106 0ustarhenningstaff 0 0 Runtime dependencies

Commons Configuration requires Java 5 or later.

A lot of dependencies are declared in the Maven POM. These are all needed during compile time. On runtime however you only need to add the dependencies to your classpath that are required by the parts of the Commons Configuration package you are using. The following table helps you to determine which dependencies you have to include based on the components you intend to use:

Component Dependencies
Core commons-lang
commons-logging
DefaultConfigurationBuilder commons-beanutils
ConfigurationFactory (deprecated) commons-digester
ConfigurationConverter commons-collections
PropertyListConfiguration
XMLPropertyListConfiguration
commons-codec
ConfigurationDynaBean commons-beanutils
XPathExpressionEngine commons-jxpath
CatalogResolver xml-resolver
Web configurations servlet-api
ExprLookup commons-jexl
VFSFileSystem, VFSFileChangedReloadingStrategy commons-vfs

Notes

  • Commons Configuration makes use of other Commons components. You should be able to use the current versions of these components together with Commons Configuration. In some cases, when no specific features are used, older versions will work, too. Below is a table with the version numbers that have been tested:
    Component Version
    commons-lang 2.2, 2.3, 2.4, 2.5, 2.6
    commons-collections 3.1, 3.2, 3.2.1
    commons-logging 1.0.4, 1.1, 1.1.1
    commons-digester 1.6, 1.7, 1.8, 1.8.1
    commons-beanutils 1.7.0, 1.8.0, 1.8.2, 1.8.3
    commons-codec 1.3, 1.5, 1.6
    commons-jxpath 1.2, 1.3
    commons-jexl 2.1.1
    commons-vfs 2.0
    xml-resolver 1.2

commons-configuration-1.10-src/src/site/xdoc/download_configuration.xml100644 15753 12232154103 26216 0ustarhenningstaff 0 0 Download Commons Configuration Commons Documentation Team

We recommend you use a mirror to download our release builds, but you must verify the integrity of the downloaded files using signatures downloaded from our main distribution directories. Recent releases (48 hours) may not yet be available from the mirrors.

You are currently using [preferred]. If you encounter a problem with this mirror, please select another mirror. If all mirrors are failing, there are backup mirrors (at the end of the mirrors list) that should be available.

[if-any logo][end]

Other mirrors:

The KEYS link links to the code signing keys used to sign the product. The PGP link downloads the OpenPGP compatible signature from our main site. The MD5 link downloads the checksum from the main site.

commons-configuration-1.10-bin.tar.gz md5 pgp
commons-configuration-1.10-bin.zip md5 pgp
commons-configuration-1.10-src.tar.gz md5 pgp
commons-configuration-1.10-src.zip md5 pgp

Older releases can be obtained from the archives.

commons-configuration-1.10-src/src/site/xdoc/index.xml100644 10635 12232154103 22561 0ustarhenningstaff 0 0 Pete Kazmier Martin Poeschl Jason van Zyl Eric Pugh Tim O'Brien Ralph Goers Java Configuration API

The Commons Configuration software library provides a generic configuration interface which enables a Java application to read configuration data from a variety of sources. Commons Configuration provides typed access to single, and multi-valued configuration parameters as demonstrated by the following code:

Configuration parameters may be loaded from the following sources:

  • Properties files
  • XML documents
  • Windows INI files
  • Property list files (plist)
  • JNDI
  • JDBC Datasource
  • System properties
  • Applet parameters
  • Servlet parameters
Different configuration sources can be mixed using a ConfigurationFactory and a CompositeConfiguration. Additional sources of configuration parameters can be created by using custom configuration objects. This customization can be achieved by extending AbstractConfiguration or AbstractFileConfiguration.

The full Javadoc API documentation is available here.

The latest release of Apache Commons Configuration is available from the Apache download area. It is also available from the Maven repository. The Changes Report explains all of the changes and bug fixes that have been made.

Commons Configuration started as code in Apache JServ. The JServ code was subsequently added to Jakarta Turbine. After Jakarta Turbine, this configuration interface moved to Jakarta Velocity and underwent various improvements. After Velocity, this code was introduced to the Apache Commons as ExtendedProperties. Configuration began life in the Commons as a Sandbox component, and was promoted to the Commons Proper in late 2003.

Bugs may be reported via the ASF JIRA system. Detailed information can be found on the issue tracking page.

commons-configuration-1.10-src/src/site/xdoc/issue-tracking.xml100644 13353 12232154103 24402 0ustarhenningstaff 0 0 Commons Configuration Issue tracking Commons Documentation Team

Commons Configuration uses ASF JIRA for tracking issues. See the Commons Configuration JIRA project page.

To use JIRA you may need to create an account (if you have previously created/updated Commons issues using Bugzilla an account will have been automatically created and you can use the Forgot Password page to get a new password).

If you would like to report a bug, or raise an enhancement request with Commons Configuration please do the following:

  1. Search existing open bugs. If you find your issue listed then please add a comment with your details.
  2. Search the mailing list archive(s). You may find your issue or idea has already been discussed.
  3. Decide if your issue is a bug or an enhancement.
  4. Submit either a bug report or enhancement request.

Please also remember these points:

  • the more information you provide, the better we can help you
  • test cases are vital, particularly for any proposed enhancements
  • the developers of Commons Configuration are all unpaid volunteers

For more information on subversion and creating patches see the Apache Contributors Guide.

You may also find these links useful:

commons-configuration-1.10-src/src/site/xdoc/javadocarchive.xml100644 3110 12232154103 24371 0ustarhenningstaff 0 0 Javadoc Archives

Commons Configuration 1.7 (javadoc)

Commons Configuration 1.6 (javadoc)

Commons Configuration 1.5 (javadoc)

Commons Configuration 1.4 (javadoc)

Commons Configuration 1.3 (javadoc)

Commons Configuration 1.2 (javadoc)

Commons Configuration 1.1 (javadoc)

Commons Configuration 1.0 (javadoc)

commons-configuration-1.10-src/src/site/xdoc/mail-lists.xml100644 22400 12232154103 23521 0ustarhenningstaff 0 0 Commons Configuration Mailing Lists Commons Documentation Team

Commons Configuration shares mailing lists with all the other Commons Components. To make it easier for people to only read messages related to components they are interested in, the convention in Commons is to prefix the subject line of messages with the component's name, for example:

  • [configuration] Problem with the ...

Questions related to the usage of Commons Configuration should be posted to the User List.
The Developer List is for questions and discussion related to the development of Commons Configuration.
Please do not cross-post; developers are also subscribed to the user list.

Note: please don't send patches or attachments to any of the mailing lists. Patches are best handled via the Issue Tracking system. Otherwise, please upload the file to a public server and include the URL in the mail.

Please prefix the subject line of any messages for Commons Configuration with [configuration] - thanks!

Name Subscribe Unsubscribe Post Archive Other Archives
Commons User List

Questions on using Commons Configuration.

Subscribe Unsubscribe Post mail-archives.apache.org markmail.org
www.mail-archive.com
news.gmane.org
Commons Developer List

Discussion of development of Commons Configuration.

Subscribe Unsubscribe Post mail-archives.apache.org markmail.org
www.mail-archive.com
news.gmane.org
Commons Issues List

Only for e-mails automatically generated by the issue tracking system.

Subscribe Unsubscribe read only mail-archives.apache.org markmail.org
www.mail-archive.com
Commons Commits List

Only for e-mails automatically generated by the source control sytem.

Subscribe Unsubscribe read only mail-archives.apache.org markmail.org
www.mail-archive.com

Other mailing lists which you may find useful include:

Name Subscribe Unsubscribe Post Archive Other Archives
Apache Announce List

General announcements of Apache project releases.

Subscribe Unsubscribe read only mail-archives.apache.org markmail.org
old.nabble.com
www.mail-archive.com
news.gmane.org
commons-configuration-1.10-src/src/site/xdoc/userguide/howto_basicfeatures.xml100644 40445 12232154103 27510 0ustarhenningstaff 0 0 Basic Features Oliver Heger

The Configuration interface defines a whole bunch of methods. Implementing these methods all from scratch can be quite hard. Because of that the AbstractConfiguration class exists. This class serves as a common base class for most of the Configuration implementations in Commons Configuration and provides a great deal of the functionality required by the interface. So for creating a custom Configuration implementation this class will be a good starting point.

In addition to base implementations for lots of the methods declared in the Configuration interface the AbstractConfiguration class provides some other handy and convenient features. Because this class is at the very root of the class hierarchy in Commons Configuration these features are available in most of the specific implementations of the Configuration interface provided by this library. We will cover some of these basic features in this section.

What is a configuration object supposed to do if you pass in a key to one of its get methods that does not map to an existing property? Well, the default behavior as implemented in AbstractConfiguration is to return null if the return value is an object type. For primitive types as return values returning null (or any other special value) is not possible, so in this case a NoSuchElementException is thrown:

For object types like String, BigDecimal, or BigInteger this default behavior can be changed: If the setThrowExceptionOnMissing() method is called with an argument of true, these methods will behave like their primitive counter parts and also throw an exception if the passed in property key cannot be resolved.

Note: Unfortunately support for the throwExceptionOnMissing property is not always consistent: The methods getList() and getStringArray() do not evaluate this flag, but return an empty list or array if the requested property cannot be found. Maybe this behavior will be changed in a future major release.

With getList() and getStringArray() the Configuration interface defines methods for dealing with properties that have multiple values. When a configuration source (e.g. a properties file, an XML document, or a JNDI context) is processed the corresponding Configuration implementation detects such properties with multiple values and ensures that the data is correctly stored.

When modifying properties the addProperty() and setProperty() methods of AbstractConfiguration also implement special list handling. The property value that is passed to these methods can be a list or an array resulting in a property with multiple values. If the property value is a string, it is checked whether it contains the list delimiter character. If this is the case, the string is splitted, and its single parts are added one by one. The list delimiter character is the comma by default. It is also taken into account when the configuration source is loaded (i.e. string values of properties will be checked whether they contain this delimiter). By using the setListDelimiter() method you can set it to a different character. Here are some examples:

// Change the list delimiter character to a slash config.setListDelimiter('/'); // Now add some properties config.addProperty("greeting", "Hello, how are you?"); config.addProperty("colors.pie", new String[] { "#FF0000", "#00FF00", "#0000FF" }); config.addProperty("colors.graph", "#808080/#00FFCC/#6422FF"); // Access data String salut = config.getString("greeting"); List<Object> colPie = config.getList("colors.pie"); String[] colGraph = config.getStringArray("colors.graph"); String firstPieColor = config.getString("colors.pie");

In this example the list delimiter character is changed from a comma to a slash. Because of this the greeting property won't be split, but remains a single string. The string passed as value for the colors.graph property in opposite contains the new delimiter character and thus will result in a property with three values. Note that lists are of type Object. This is because the concrete class of the values of a property is not known. For instance, if you call addProperty("answer", 42), an Integer object will be stored in the configuration.

Of interest is also the last line of the example fragment. Here the getString() method is called for a property that has multiple values. This call will return the first value of the list.

If you want to change the list delimiter character for all configuration objects, you can use the static setDefaultListDelimiter() method of AbstractConfiguration. It is also possible to disable splitting of string properties at all for a Configuration instance by calling its setDelimiterParsingDisabled() method with a value of true.

If you are familiar with Ant or Maven, you have most certainly already encountered the variables (like ${token}) that are automatically expanded when the configuration file is loaded. Commons Configuration supports this feature as well, here is an example (we use a properties file in this example, but other configuration sources work the same way; you can learn more about properties files in the chapter Properties files):

application.name = Killer App application.version = 1.6.2 application.title = ${application.name} ${application.version}

If you now retrieve the value for the application.title property, the result will be Killer App 1.6.2. So per default variables are interpreted as the keys of other properties. This is only a special case, the general syntax of a variable name is ${prefix:name}. The prefix tells Commons Configuration that the variable is to be evaluated in a certain context. We have already seen that the context is the current configuration instance if the prefix is missing. The following other prefix names are supported by default:
Prefix Description
sys This prefix marks a variable to be a system property. Commons Configuration will search for a system property with the given name and replace the variable by its value. This is a very easy means for accessing the values of system properties in every configuration implementation.
const The const prefix indicates that a variable is to be interpreted as a constant member field of a class (i.e. a field with the static final modifiers). The name of the variable must be of the form <full qualified class name>.<field name>. The specified class will be loaded and the value of this field will be obtained.
env Variables can also reference OS-specific environment properties. This is indicated by the env prefix.
Here are some examples (again using properties syntax):

If a variable cannot be resolved, e.g. because the name is invalid or an unknown prefix is used, it won't be replaced, but is returned as is including the dollar sign and the curly braces.

This sub section goes a bit behind the scenes of interpolation and explains some approaches how you can add your own interpolation facilities. Under the hood interpolation is implemented using the StrSubstitutor class of the text package of Commons Lang. This class uses objects derived from the StrLookup class for resolving variables. StrLookup defines a simple lookup() method that must be implemented by custom implementations; it expects the name of a variable as argument and returns the corresponding value (further details can be found in the documentation of Commons Lang). The standard prefixes for variables we have covered so far are indeed realized by special classes derived from StrLookup.

It is now possible to create your own implementation of StrLookup and make it available for all configuration objects under a custom prefix. We will show how this can be achieved. The first step is to create a new class derived from StrLookup, which must implement the lookup() method. As an example we implement a rather dull lookup object that simply returns a kind of "echo" for the variable passed in:

Now we want this class to be called for variables with the prefix echo. For this purpose the EchoLookup class has to be registered at the ConfigurationInterpolator class with the desired prefix. ConfigurationInterpolator implements a thin wrapper over the StrLookup API defined by Commons Lang. It has a static registerGlobalLookup() method, which we have to call as follows:

Each AbstractConfiguration object that is created after this line is executed will contain the new lookup class and can thus resolve variables of the form ${echo:my_variable}.

Each instance of AbstractConfiguration is associated with a ConfigurationInterpolator object. This object is created by the createInterpolator() method on first access of one of the interpolation features. By overriding this method even deeper intervention in the interpolation mechanism is possible. For instance a custom implementation can add further lookup objects to the interpolator, which are then only used by this configuration instance.

In addition to the simple lookup mechanisms previously described, Commond Configuration provides ExprLookup which uses Apache Commons Jexl to allow expressions to be resolved wherever a StrLookup is allowed. This example shows an alternate way of obtaining a system property if the ExprLookup is configured.

ExprLookup is not enabled by default, it must be manually added or configured via DefaultConfigurationBuilder. Builds that use Maven 2 and reference Commons Configuration will not include a dependency on Jexl, so if this feature is used the dependency on Jexl must be manually added to the project.

When using DefaultConfigurationBuilder adding ExprLookup is straightforward.

]]>

The example above shows how to invoke static methods during expression evaluation. The next example shows mixing expression evaluation with a subordinate lookup to obtain the "basePath" system property. Note the difference in how the system property was obtained in the previous example.

]]>
commons-configuration-1.10-src/src/site/xdoc/userguide/howto_beans.xml100644 43562 12232154103 25763 0ustarhenningstaff 0 0 Declaring Beans Howto Oliver Heger

Often it is good practice to make heavy use of Java interfaces and program an application or components against these interfaces rather than concrete implementation classes. This makes it possible to switch to different implementations without having to modify calling code. However the problem remains how a concrete implementation of an interface is obtained. Simply using the new operator on a specific implementation class would somehow break the interface concept because then the code would have an explicit reference to a concrete implementation.

A solution to this problem is to define the concrete implementation class that should be used in a configuration file. Client code would obtain an object (or a bean) from the configuration and cast it to the service interface. This way the caller would have no knowledge about which concrete implementation is used; it would only interact with the service through the interface. By changing the configuration file and entering a different class name for the implementation class the behavior of the application can be altered, e.g. to inject a test stub for the used service.

Note: The concept of defining service objects in configuration files and let them be created by a special container has grown popular these days. Especially IoC containers like HiveMind or Spring offer wide functionality related to this topic. Commons Configuration is not and has no ambitions to become an IoC container. The provided functionality for declaring and creating beans is very basic and limited compared to the specialists. So if you are in need of enhanced features like the creation of complete networks of service objects, life cycle handling and such things, you should in any case use a real IoC container. For simple use cases however the functionality of Commons Configuration might be sufficient, and we have tried to provide hooks for extending the predefined mechanisms.

Beans (we use the term bean here to name any plain old Java object that is defined in a configuration file and can be instantiated by Commons Configuration) are defined in configuration files in a specific format, a so called Bean declaration. Such a declaration contains all information needed to create an instance of this bean class, e.g. the full qualified name of the class and initialization parameters. We will explain how a bean declaration looks like in short.

On the Java side three entities are involved in the creation of a bean:

  • A bean factory: This is an object that implements the BeanFactory interface and knows how to create an instance of a bean class. In most cases calling code does not directly deal with a bean factory.
  • An implementation of the BeanDeclaration interface. This object knows how the bean declaration in the configuration file is organized and how the needed information can be extracted. So the way the bean is declared in the configuration file must match the expectations of this object.
  • The utility class BeanHelper brings all these together and performs the bean creation operation. Usually client code will create a BeanDeclaration object from a Configuration implementation and then pass it to one of the createBean() methods of BeanHelper. That's it!
For all of the interfaces mentioned above default implementations are provided, which in many cases can be used out of the box.

After this theory let's get into practice using an example. Consider a GUI application that makes use of a Window manager to display its windows and dialogs to the user. There is a WindowManager interface containing methods for opening, displaying, hiding, and disposing windows. Different implementations of this interface exist, e.g. providing different look & feel or special functionality. The concrete set of methods of the interface does not matter for this example.

Now in the application's configuration it shall be specified that the concrete implementation DefaultWindowManager should be used as WindowManager. This is a plain Java class implementing the WindowManager interface. Some fragments are shown in the following listing:

As you can see, the DefaultWindowManager class has some simple properties for defining the windows. There is also a property named StyleDefinition whose type is another bean (such a style definition may contain information about themes, colors, fonts of the window and so on). How can we now write a configuration file so that a bean of the DefaultWindowManager class is declared and initialization properties are defined? In an XML configuration file this will look as follows:

]]>

This XML document contains a valid bean declaration starting with the windowManager element and including its sub elements. Note the following points:

  • The (full qualified) class of the bean is specified using the config-class attribute. (Attributes starting with the prefix "config-" are reserved; they contain special meta data for the bean creation process.)
  • Other attributes of the windowManager element correspond to properties of the DefaultWindowManager class. These properties will be initialized with the values specified here.
  • For the styleDefinition property, which is itself a bean, a sub element (matching the property's name) exists. The structure of this element is analogous to the structure of the windowManager element; indeed it could even have further sub elements defining bean properties of the WindowStyleDefinition class.
The basic structure of a bean declaration should have become clear by this example.

Now let's see how we can access this declaration and create an instance. This is demonstrated in the code fragment below:

This fragment loads the configuration file using a XMLConfiguration object. Then a bean declaration object is created, in this case an instance of the XMLBeanDeclaration class, which can deal with bean declarations in XML documents. This declaration is passed to the static createBean() method of the BeanHelper class, which returns the new bean instance.

BeanHelper defines some overloaded versions of the createBean() method. Some allow to pass in a default bean class; then it is not necessary to define the class in the bean declaration - an instance of this default class will be created if it is lacking in the configuration file. If the bean cannot be created for some reason (e.g. a wrong class name was specified), a ConfigurationRuntimeException will be thrown.

As was pointed out in the introduction of this chapter support for creating beans is focused on the basics. But there are some possibilities of hooking in and add custom extensions. This can be done in the following ways:

  • By defining a custom BeanDeclaration implementation
  • By providing a custom BeanFactory implementation

A specialized bean declaration is needed when you have to deal with configuration files that contain bean declarations in a different format than the ones supported by the available default implementations. Then it is the responsibility of your implementation to parse the configuration data and extract the required information to create the bean. Basically your BeanDeclaration implementation must be able to provide the following data:

  • The name of the class for which an instance is to be created.
  • The name of the bean factory that is used to create the bean. Here null can be returned, then a default factory is used. (See below for more information about working with custom bean factories.)
  • An optional parameter to be passed to the bean factory. If a factory is used that supports additional parameters, the current parameter values are also obtained from the bean declaration.
  • A map with the properties to be set on the newly created bean. This map's keys are names of properties, its values are the corresponding property values. The default bean factory will process this map and call the corresponding setter methods on the newly created bean object.
  • A map with further BeanDeclaration objects for initializing properties of the new bean that are itself beans. These bean declarations are treated exactly as the one that is currently processed. The resulting beans will then be set as properties on the processed bean (the names of these properties are again obtained from the keys of the map).

While creating a custom BeanDeclaration implementation allows you to adapt the format of bean declarations in configuration files, you can manipulate the bean creation mechanism itself by creating a specialized implementation of the BeanFactory interface. For this purpose the following steps are necessary:

  1. Create a class implementing the BeanFactory interface. This interface is quite simple. It defines one method for creating an instance of a class whose Class object is provided, and another method, which is called for querying a default class.
  2. Register this new factory class at the BeanHelper class.
  3. In the bean declaration in your configuration file refer to the factory that should be used for creating the bean.

We will provide an example that covers all these steps. This example deals with a singleton factory, i.e. an implementation of BeanFactory that returns always the same instance of a provided bean class.

We start with the creation of the factory class. The basic idea is that the functionality for creating and initializing beans is already provided by the DefaultBeanFactory class, so we extend this class. Our implementation only has to deal with the singleton stuff: We keep a map that stores already created bean instances and can be accessed by the name of their classes. In the factory's createBean() method we check if for the passed in class already an instance exists. If this is the case, it is directly returned. Otherwise we call the inherited createBean() method and store its result in the map. (Note that this implementation is a bit simplicistic; a real world implementation would also have to take the initialization parameters into account. But for the purpose of an example it should be good enough). Here is the code:

Note the synchronized key word, which is necessary because the method can be accessed by multiple threads concurrently. Now we have to register an instance of this class at the BeanHelper class. This can be done in the initialization phase of your application and looks as follows:

To make use of the new factory a bean declaration must contain an attribute that refers to the name under which the factory was registered. This is demonstrated by the fragment below:

... ... ]]>

In this fragment the fileService element contains a bean declaration for some service object. Apart from the config-class attribute the important part is the config-factory attribute. This attribute tells the BeanHelper class that it should use a special factory when it processes this bean declaration. As was demonstrated by this example, it should not be too difficult to extend the custom mechanism for creating beans.

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_combinedconfiguration.xml100644 61160 12232154103 31235 0ustarhenningstaff 0 0 Combined Configurations Oliver Heger

The CombinedConfiguration class provides an alternative for handling multiple configuration sources. Its API is very similar to the CompositeConfiguration class, which was discussed in the last section. There are the following differences however:

  • A CombinedConfiguration is a truely hierarchical configuration. This means that all the enhanced facilities provided by HierarchicalConfiguration (e.g. expression engines) can be used.
  • A CombinedConfiguration is not limited to implementing an override semantics for the properties of the contained configurations. Instead it has the concept of so-called node combiners, which know how properties of multiple configuration sources can be combined. Node combiners are discussed later in detail. For instance, there is a node combiner implementation available that constructs a union of the contained configurations.
  • Contained configurations can be assigned a name. They can later be accessed by their name.
  • Each contained configuration can have an optional prefix. Its properties are then added under this prefix to the combined configuration.
  • There is no concept of an in memory configuration. Changes to a combined configuration are handled in a different way.

A CombinedConfiguration provides a logic view on the properties of the configurations it contains. This view is determined by the associated node combiner object. Because of that it must be re-constructed whenever one of these contained configurations is changed.

To achieve this, a CombinedConfiguration object registers itself as an event listener at the configurations that are added to it. It will then be notified for every modification that occurs. If such a notification is received, the internally managed view is invalidated. When a property of the combined configuration is to be accessed, the view is checked whether it is valid. If this is the case, the property's value can be directly fetched. Otherwise the associated node combiner is asked to re-construct the view.

A node combiner is an object of a class that inherits from the abstract NodeCombiner class. This class defines an abstract combine() method, which takes the root nodes of two hierarchical configurations and returns the root node of the combined node structure. It is up to a concrete implementation how this combined structure will look like. Commons Configuration ships with three concrete implementations OverrideCombiner, MergeCombiner and UnionCombiner, which implement an override, merge, and union semantics respectively.

Constructing a combination of multiple node hierarchies is not a trivial task. The available implementations descend the passed in node hierarchies in a recursive manner to decide, which nodes have to be copied into the resulting structure. Under certain circumstances two nodes of the source structures can be combined into a single result node, but unfortunately this process cannot be fully automated, but sometimes needs some hints from the developer. As an example consider the following XML configuration sources:

users user_id ...
]]>

and

documents document_id ...
]]>

These two configuration sources define database tables. Each source defines one table. When constructing a union for these sources the result should look as follows:

users user_id ...
documents document_id ...
]]>

As you can see, the resulting structure contains two table nodes while the nodes database and tables appear only once. For a human being this is quite logic because database and tables define the overall structure of the configuration data, and there can be multiple tables. A node combiner however does not know anything about structure nodes, list nodes, or whatever. From its point of view there is no detectable difference between the tables nodes and the table nodes in the source structures: both appear once in each source file and have no values. So without any assistance the result constructed by the UnionCombiner when applied on the two example sources would be a bit different:

users user_id ... documents document_id ...
]]>

Note that the table node would be considered a structure node, too, and would not be duplicated. This is probably not what was desired. To deal with such situations it is possible to tell the node combiner that certain nodes are list nodes and thus should not be combined. So in this concrete example the table node should be declared as a list node, then we would get the expected result. We will see below how this is done. Note that this explicit declaration of a list node is necessary only in situations where there is ambiguity. If in one of our example configuration sources multiple tables had been defined, the node combiner would have concluded itself that table is a list node and would have acted correspondigly.

The examples the follow are provided to further illustrate the differences between the combiners that are delivered with Commons Configuration. The first two files are the files that will be combined.

testfile1.xml testfile2.xml
green yellow 1 http://www.url1.org http://www.url2.org http://www.url3.org http://service1.org Admin documents docid long docname varchar authorID int
My Channel more test 2 data Test Channel Channel 4 ]]>
scotty BeamMeUp black blue 4 http://appsvr1.com http://appsvr2.com http://testsvr.com http://backupsvr.com http://service2.org http://service3.org tasks taskid long taskname varchar
Channel 1 test 1 data Channel 2 test 2 data Channel 3 test 3 data Test Channel 1 Test Channel 2 ]]>

The first listing shows the result of using the OverrideCombiner.

OverrideCombiner ResultsNotes
green yellow 1 blue http://www.url1.org http://www.url2.org http://www.url3.org http://service1.org http://appsvr1.com http://appsvr2.com http://testsvr.com http://backupsvr.com Admin BeamMeUp documents docid long docname varchar authorID int
My Channel more test 2 data Test Channel ]]>

The features that are significant in this file are:

  • In the gui section each of the child elements only appears once. The level element merges the attributes from the two files and uses the element value of the first file.
  • In the security section the user type attribute was obtained from the second file while the user value came from the first file. Alternately, the password type was obtained from the first file while the value came from the second.
  • Only the data from table 1 was included.
  • Channel 1 in the first file completely overrode Channel 1 in the second file.
  • Channel 2 in the first file completely overrode Channel 2 in the second file. While the attributes were merged in the case of the login elements the type attribute was not merged in this case.
  • Again, only Channel 3 from the first file was included.

How the Channel elements ended up may not at first be obvious. The OverrideCombiner simply noticed that the Channels element had three child elements named Channel and used that to determine that only the contents of the Channels element in the first file would be used.

The next file is the the result of using the UnionCombiner

UnionCombiner Results Notes
green yellow 1 black blue 4 http://www.url1.org http://www.url2.org http://www.url3.org http://service1.org http://service2.org http://service3.org http://appsvr1.com http://appsvr2.com http://testsvr.com http://backupsvr.com Admin scotty BeamMeUp documents docid long docname varchar authorID int taskid long taskname varchar tasks
My Channel more test 2 data Test Channel Channel 1 test 1 data Channel 2 test 2 data Channel 3 test 3 data ]]>

The feature that is significant in this file is rather obvious. It is just a simple union of the contents of the two files.

Finally, the last file is the result of using the MergeCombiner

MergeCombiner Results Notes
green yellow 1 blue http://www.url1.org http://www.url2.org http://www.url3.org http://service1.org http://appsvr1.com http://appsvr2.com http://testsvr.com http://backupsvr.com Admin documents docid long docname varchar authorID int
tasks taskid long taskname varchar
My Channel test 1 data more test 2 data Channel 2 test 2 data Test Channel Channel 3 test 3 data ]]>

The features that are significant in this file are:

  • In the gui section the elements were merged.
  • In the net section the elements were merged, with the exception of the urls.
  • In the security section the user and password were merged. Notice that the empty value for the password from the first file overrode the password in the second file.
  • Both table elements appear
  • Channel 1 and Channel 2 were merged
  • Both Channel 3 elements appear as they were determined to not be the same.

When merging elements attributes play a critical role. If an element has an attribute that appears in both sources, the value of that attribute must be the same for the elements to be merged.

Merging is only allowed between a single node in each of the files, so if an element in the first file matches more than one element in the second file no merging will take place and the element from the first file (and its contents) are included and the elements in the second file are not. If the element is marked as a list node then the elements from the second file will also be included.

To create a CombinedConfiguration object you specify the node combiner to use and then add an arbitrary number of configurations. We will show how to construct a union configuration from the two example sources introduced earlier:

Here we also specified a name for one of the configurations, so it can later be accessed by cc.getConfiguration("tab1");. Access by index is also supported. After that the properties in the combined configuration can be accessed as if it were a normal hierarchical configuration

There is nothing that prevents you from updating a combined configuration, e.g. by calling methods like addProperty() or removeProperty(). The problem is that depending on the used node combiner it might no be clear, which of the contained configurations will be modified or whether one is modified at all.

Typical node combiners work by copying parts of the node structures of the source configurations into the target structure and linking them togehter using special link nodes. So updates of the combined node structure will either effect nodes from one of the contained configuration (then the changes are directly visible in this configuration) or one of the link nodes (then they cannot really be saved).

It is also possible that a change is done at the combined node structure, which is not compatible with the current node combiner. Imagine that an OverrideCombiner is used and that a property should be removed. This property will then be removed from one of the contained configurations. Now it may happen that this removed property had hidden property values of other contained configurations. Their values won't become visible automatically, but only after the combined view was re-constructed.

Because of that it is recommended that changes are not done at the combined configuration, but only at contained configurations. This way the correct configuration to be updated can unambigously be identified. Obtaining the configuration to be updated from the combined configuration is easy when it was given a name.

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_compositeconfiguration.xml100644 10124 12232154103 31451 0ustarhenningstaff 0 0 Composite Configuration Details Eric Pugh

There are many use cases when you want to collect the properties of several configuration sources and access them like a single configuration object. One way to do that is using the CompositeConfiguration class.

A CompositeConfiguration object contains a list of other configuration objects. When properties are accessed from a composite configuration the object takes the passed in property key and iterates over the list of the contained configurations. As soon as a value is found for the key it is returned. This means that a CompositeConfiguration implements a kind of override semantics, i.e. the properties of configurations that were added first hide the property values of configurations added later.

We will discuss how you can establish a "default" choice for your Composite Configuration as well as save changes made to your Composite Configuration.

Defaults are very simple. You can just add them as your last configuration object, either through the ConfigurationFactory or manually:

If you have a non static Configuration where you want to save changes made to a configuration, and you are using a CompositeConfiguration, then you will need to pass into the constructor of the CompositeConfiguration what Configuration to save the changes via.

Alternatively, you can just request the in-memory configuration that stores the changes. The following example fragment copies all properties from the in-memory configuration into a DatabaseConfiguration, so that they are made persistent: i = changes.getKeys(); i.hasNext()){ String key = i.next(); Object value = changes.get(key); config.setProperty(key,value); } ]]>

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_configurationbuilder.xml100644 125126 12232154103 31126 0ustarhenningstaff 0 0 Configuration Builder Howto

This section explains how a DefaultConfigurationBuilderobject is setup that provides access to a collection of different configuration sources. DefaultConfigurationBuilder is the option of choice for applications that have to deal with multiple configuration sources. It provides the following features:

  • Various configuration sources can be combined to a single CombinedConfiguration object. This is a truly hierarchical configuration supporting enhanced query facilities.
  • As configuration sources the most relevant Configuration implementations provided by this library are supported. Sources are defined as bean declarations, so complex initializations are possible.
  • Meta data can be provided to fine-tune the constructed configuration.
  • DefaultConfigurationBuilder is extensible. Custom configuration sources can be added.

This document starts with some explanations of DefaultConfigurationBuilder basics. Then the configuration definition files processed by DefaultConfigurationBuilder are discussed in detail. Finally an advanced example is presented.

In previous chapters we have already seen how specific configuration classes like PropertiesConfiguration or XMLConfiguration can be used to load configuration data from a single source. This may be sufficient for small applications, but if requirements for configuration become more complex, additional support for managing a set of different configuration sources is desired. This is the domain of DefaultConfigurationBuilder which allows combining multiple configuration sources. The properties defined in these sources can then be accessed as if they were defined in a single configuration file. The sources to be loaded have to be defined in a XML document with a specific structure, a so-called configuration definition file. The following listing shows a simple example of such a definition file:

]]>

A configuration definition file can contain an arbitrary number of elements declaring the configuration sources to load. The <properties> element is one of these; it is used to include properties files. For this example we store the definition file in the same directory as the properties file and call it config.xml. The properties file used in this example is the same as in the section about properties files.

Now we have to create a DefaultConfigurationBuilder object and let it read this definition file. This is quite simple: Just create a new instance and set the name of the definition file (DefaultConfigurationBuilder is derived from XMLConfiguration, so all options for specifying the document to load are available here, too). The combined configuration collecting all sources defined in the configuration definition file can then be obtained by calling the getConfiguration() method:

Now the config object can be accessed in the usual way to query configuration properties, e.g. by using methods like getString(), or getInt(). We will see in a moment how properties defined in different configuration sources are accessed.

Using DefaultConfigurationBuilder to collect configuration sources does not make much sense if there is only a single source to be loaded. So let's add another one! This time we will embedd a XML file: gui.xml which is shown in the next listing:

#808080 #000000
#008000
15
]]>

To make this XML document part of our global configuration we have to modify our configuration definition file to also include the new file. For XML documents the element <xml> can be used so that we ave now:

]]>

The code for setting up the DefaultConfigurationBuilder object remains the same. From the Configuration object returned by the factory the new properties can be accessed in the usual way.

There is one problem with this example configuration setup: The color.background property is defined in both the properties and the XML file, and - to make things worse - with different values. Which value will be returned by a call to getString()?

The answer is that the configuration sources are searched in the order they are defined in the configuration definition file. Here the properties file is included first, then comes the XML file. Because the color.background property can be found in the properties file the value specified there will be returned (which happens to be #FFFFFF).

It might not be obvious why it makes sense to define the value of one and the same property in multiple configuration sources. But consider the following scenario: An application comes with a set of default properties and allows the user to override some or all of them. This can now easily be realized by saving the user's settings in one file and the default settings in another. Then in the configuration definition file the file with the user settings is included first and after that the file with the default values. The application code that queries these settings needs no be aware whether a property was overriden by the user. DefaultConfigurationBuilder takes care that properties defined in the first file (the user file) are found; other properties which the user has not changed will still be returned from the second file (the defaults file).

The example above with two configuration sources - one for user settings and one with default values - raises an interesting question: What happens if the user has not defined specific properties yet? Or what if a new user starts our application for the first time and thus no user specific properties exist?

The default behavior of DefaultConfigurationBuilder is to throw a ConfigurationException exception if one of the sources defined in the configuration definition file cannot be loaded. For our example this behavior is not desired: the properties file with specific user settings is not required. If it cannot be loaded, the example application should still work because a complete set of configuration properties is defined in the second file.

DefaultConfigurationBuilder supports such optional configuration sources. For this purpose in the definition of a configuration source the config-optional attribute can be placed. An example of this is shown below:

]]>

In this configuration definition file the first properties file with user specific settings is marked as optional. This means that if it cannot be loaded, DefaultConfigurationBuilder will not throw an exception, but only write a warning message to its logger. Note that the config-optional attribute is absent for the second properties file. Thus it is mandatory, and the getConfiguration() method of DefaultConfigurationBuilder would throw an exception if it could not be found.

In an earlier section about the configuration definition file for DefaultConfigurationBuilder it was stated that configuration files included first can override properties in configuraton files included later, and an example use case for this behaviour was given. There may be cases when there are other requirements.

Let's continue the example with the application that somehow process database tables and that reads the definitions of the affected tables from its configuration. This example and the corresponding XML configuration files were introduced in the section about XMLConfiguration. Now consider that this application grows larger and must be maintained by a team of developers. Each developer works on a separated set of tables. In such a scenario it would be problematic if the definitions for all tables would be kept in a single file. It can be expected that this file needs to be changed very often and thus can be a bottleneck for team development when it is nearly steadily checked out. It would be much better if each developer had an associated file with table definitions and all these information could be linked together at the end.

DefaultConfigurationBuilder provides support for such a use case, too. It is possible to specify in the configuration definition file that from a set of configuration sources a logic union configuration is to be constructed. Then all properties defined in the provided sources are collected and can be accessed as if they had been defined in a single source. To demonstrate this feature let us assume that a developer of the database application has defined a specific XML file with a table definition named tasktables.xml:

tasks taskid long name java.lang.String description java.lang.String responsibleID long creatorID long startDate java.util.Date endDate java.util.Date
]]>

This file defines the structure of an additional table, which should be added to the so far existing table definitions. To achieve this the configuration definition file has to be changed: A new section is added that contains the include elements of all configuration sources which are to be combined.

]]>

Compared to the older versions of this file some changes have been done. One major difference is that the elements for including configuration sources are no longer direct children of the root element, but are now contained in either an <override> or <additional> section. The names of these sections already imply their purpose.

The override section is not strictly necessary. Elements in this section are treated as if they were children of the root element, i.e. properties in the included configuration sources override properties in sources included later. So the <override> tags could have been ommitted, but for the sake of clearity it is recommended to use them if there is also an <additional> section.

It is the <additonal> section that introduces a new behaviour. All configuration sources listed here are combined to a union configuration. In our example we have put two xml elements in this area that load the available files with database table definitions. The syntax of elements in the additional section is analogous to the syntax described so far. In this example the config-at attribute is introduced. It specifies the position in the logic union configuration where the included properties are to be added. Here it is set for the second element to the value tables. This is because the file starts with a <table> element, but to be compatible with the other table definition file it should be accessable under the key tables.table.

After these modifications have been performed, the configuration obtained from DefaultConfigurationBuilder allows access to three database tables. A call of config.getString("tables.table(2).name"); results in a value of tasks. In an analogous way it is possible to retrieve the fields of the third table.

Note that it is also possible to override properties defined in an additonal section. This can be done by placing a configuration source in the override section that defines properties that are also defined in one of the sources listed in the additional section. The example does not make use of that. Note also that the order of the override and additional sections in a configuration definition file does not matter. Sources in an override section are always treated with higher priority (otherwise they could not override the values of other sources).

Configuration definition files are XML documents telling DefaultConfigurationBuilder which configuration sources to load and how to process them in order to create the resulting combined configuration.

Overall structure of a configuration definition file

A configuration definition file for DefaultConfigurationBuilder can contain three sections, all of which are optional. A skeleton looks as follows:

]]>

Declaring configuration sources

The override and additional sections have already been introduced when the basics of DefaultConfigurationBuilder were discussed. They contain declarations for the configuration sources to be embedded. For convenience reasons it is also possible to declare configuration sources outside these sections; they are then treated as if they were placed inside the override section.

Each declaration of a configuration source is represented by an XML element whose name determines the type of the configuration source. Attributes or nested elements can be used to provide additional configuration options for the sources to be included (e.g. a name of a file to be loaded or a reloading strategy). Below is a list of all tags which can be used out of the box:

properties
With this element properties files can be included. The name of the file to load is specified using the fileName attribute. Which configuration class is created by this tag depends on the extension of the file to load: If the extension is ".xml", a XMLPropertiesConfiguration object is created, which is able to process the XML properties format introduced in Java 5.0. Otherwise a PropertiesConfiguration object is created, the default reader for properties files.
xml
The xml element can be used to load XML configuration files. It also uses the fileName attribute to determine the name of the file to load and creates an instance of XMLConfiguration.
jndi
As the name implies, with this element JNDI resources can be included in the resulting configuration. Under the hood this is done by an instance of the JNDIConfiguration class. The prefix attribute can be used to select a subset of the JNDI tree.
plist
The plist element allows to embedd configuration files in the NeXT / OpenStep or Mac OS X format. Again the name of the file to load is specified through the fileName attribute. If a XML file is specified, a XMLPropertyListConfiguration object is created to process the file. Otherwise this task is delegated to a PropertyListConfiguration instance.
system
With this element an instance of SystemConfiguration is added to the resulting configuration allowing access to system properties. Note: Using this element system properties are directly made available. Alternatively the interpolation features introduced in version 1.4 (see Variable Interpolation for more details) can be used for referencing system properties.
configuration
The configuration tag allows other configuration definition files to be included. This makes it possible to nest these definition files up to an arbitrary depth. In fact, this tag will create another DefaultConfigurationBuilder object, initialize it, and obtain the CombinedConfiguation from it. This combined configuration will then be added to the resulting combined configuration. Like all file-based configurations the fileName attribute can be used to specify the configuration definition file to be loaded. This file must be an XML document that conforms to the format described here. Some of the most important settings are copied from the original DefaultConfigurationBuilder object to the newly created builder:
  • the base path under which configuration files are searched
  • some flags, e.g. for controlling delimiter parsing or throwing exceptions on missing properties
  • the logger
  • the configuration and error listeners
ini
This tag can be used to include an ini file into the resulting combined configuration. Behind the scenes an instance of HierarchicalINIConfiguration is used to load the ini file.
env
With this tag direct access to environment properties can be enabled. This works in the same way as the <system> tag for Java system properties.

In the declaration of a configuration source it is possible to set properties on the corresponding configuration objects. Configuration declarations are indeed Bean declarations. That means they can have attributes matching simple properties of the configuration object to create, and sub elements matching complex properties. The following example fragment shows how complex initialization can be performed in a configuration declaration:

]]>

In this example a configuration source for a properties file and one for an XML document are defined. For the properties source the throwExceptionOnMissing property is set to true, which means that it should throw an exception if a requested property is not found. In addition it is assigned a reloading strategy, which is declared and configured in a sub element. The XML configuration source is initialized in a similar way: a simple property is set, and an expression engine is assigned. More information about the format for declaring objects and initializing their properties can be found in the section about bean declarations.

In addition to the attributes that correspond to properties of the configuration object to be created, a configuration declaration can have a set of special attributes that are evaluated by DefaultConfigurationBuilder when it creates the objects. These attributes are listed in the following table:

Attribute Meaning
config-name Allows a name to be specified for this configuration. This name can be used to obtain a reference to the configuration from the resulting combined configuration (see below).
config-at With this attribute an optional prefix can be specified for the properties of the corresponding configuration.
config-optional Declares a configuration as optional. This means that errors that occur when creating the configuration are silently ignored. The default behavior when an error occurs is that no configuration is added to the resulting combined configuration. This behavior can be used to find out whether an optional configuration could be successfully created or not. If you specify a name for the optional configuration (using the config-name attribute), you can later check whether the combined configuration contains a configuration with this name. With the config-forceCreate attribute (see below) this default behavior can be changed.
config-forceCreate This boolean attribute is only evaluated for configurations declared as optional. It determines the behavior of the configuration builder when the optional configuration could not be created. If set to true, the builder tries to create an empty, uninitialized configuration of the correct type and add it to the resulting combined configuration. This is especially useful for file-based configurations. Consider a use case where an application wants to store user specific configuration files in the users' home directories. When a user starts this application for the first time, the user configuration does not exist yet. If it is declared as optional and forceCreate, the missing configuration file won't cause an error, but an empty configuration will be created. The application can then obtain this configuration, add properties to it (e.g. user specific settings) and save it. Without the config-forceCreate attribute the application would have to check whether the user configuration exists in the combined configuration and eventually create it manually. Note that not all configuration providers support this mechanism. Sometimes it may not be possible to create an empty configuration if the standard initialization fails. In this case no configuration will be added to the combined configuration (with other words: the config-forceCreate attribute will not have any effect).

Note: In older versions of Commons Configuration the attributes config-at and config-optional were named at and optional respective. They have been renamed in order to avoid possible name clashes with property names for configuration sources. However, for reasons of backwards compatibility, the old attribute names can still be used.

Another useful feature is the built-in support for interpolation (i.e. variable substitution): You can use variables in your configuration definition file that are defined in declared configuration sources. For instance, if the name of a configuration file to be loaded is defined by the system property CONFIG_FILE, you can do something like this:

]]>

Note that you can refer only to properties that have already been loaded. If you change the order of the <system> and the <properties> elements in the example above, an error will occur because the ${CONFIG_FILE} variable will then be undefined at the moment it is evaluated.

]]>

This example differs from the previous one by the systemProperties attribute added to the root element. It causes the specified to be read and all properties defined therein to be added to the system properties. So properties like CONFIG_FILE can be defined in a properties file and are then treated as if they were system properties.

The header section

In the header section properties of the resulting combined configuration object can be set. The main part of this section is a bean declaration that is used for creating the resulting configuration object. Other elements can be used for customizing the Node combiners used by the override and the union combined configuration. The following example shows a header section that uses all supported properties:

table list table ]]>

The result element points to the bean declaration for the resulting combined configuration. In this example we set some attributes and initialize the node combiner (which is not necessary because the default override combiner is specified), and the expression engine to be used. Note that the config-class attribute makes it possible to inject custom classes for the resulting configuration or the node combiner.

The combiner section allows nodes to be defined as list nodes. This can be necessary for certain node combiner implementations to work correctly. More information can be found in the section about Node combiners.

Note: From time to time the question is raised whether there is a document type definition or a schema defining exactly the structure of a configuration definition file. Frankly, the answer is no. This is due to the fact that the format is extensible. As will be shown below, it is possible to register yout own tags in order to embedd custom configuration sources.

After all that theory let's go through a more complex example! We start with the configuration definition file that looks like the following:

table
]]>

This configuration definition file includes four configuration sources and sets some properties for the resulting CombinedConfiguration. Of special interest is the forceReloadCheck property, which enables a special check for detecting property changes in the contained configuration sources. If this property is not set, reloading won't work. Because we have configured a reloading strategy for one of the included configuration sources we have to set this flag so that this reloading strategy can function properly. More details about this topic can be found in the Javadocs for CombinedConfiguration. We also set some properties for the configurations to be loaded; for instance we declare that one of the XML configurations should be validated.

With the following code we can create a DefaultConfigurationBuilder and load this file:

It would have been possible to specify the location of the configuration definition file in multiple other ways, e.g. as a URL. The boolean argument in the call to getConfiguration() determines whether the configuration definition file should be loaded. For our simple example we want this to happen, but it would also be possible to load the file manually (by calling the load() method), and after that updating the configuration. (Remember that DefaultConfigurationBuilder is derived from XMLConfiguration, that means you can use all methods provided by this class to alter its data, e.g. to add further configuration sources.) If the configuration's data was manually changed, you should call getConfiguration() with the argument false. XMLConfiguration also provides the registerEntityId() method that can be used to define the location of DTD files (refer to the section Validation of XML configuration files for more details). This method is available for DefaultConfigurationBuilder, too. The entities registered here will be passed to the loaded child XML configurations. So you can register the DTDs of all child XML configurations globally at the configuration builder.

In the header section we have chosen an XPATH expression engine for the resulting configuration. So we can query our properties using the convenient XPATH syntax. By providing the config-name attribute we have given all configuration sources a name. This name can be used to obtain the corresponding sources from the combined configuration. For configurations in the override section this is directly possible:

Configurations in the additional section are treated a bit differently: they are all packed together in another combined configuration and then added to the resulting combined configuration. So in our example the combined configuration cc will contain three configurations: the two configurations from the override section, and the combined configuration with the additional configurations. The latter is stored under a name determined by the ADDITIONAL_NAME constant of DefaultConfigurationBuilder. The following code shows how the configurations of the additional section can be accessed:

If you have written a custom configuration class, you might want to declare instances of this class in a configuration definition file, too. With DefaultConfigurationBuilder this is now possible by registering a ConfigurationProvider.

ConfigurationProvider is an inner class defined in DefaultConfigurationBuilder. Its task is to create and initialize a configuration object. Whenever DefaultConfigurationBuilder encounters a tag in the override or the additional section it checks whether for this tag a ConfigurationProvider was registered. If this is the case, the provider is asked to create a new configuration instance; otherwise an exception will be thrown.

So for adding support for a new configuration class you have to create an instance of ConfigurationProvider (or a derived class) and register it at the configuration builder using the addConfigurationProvider() method. This method expects the name of the associated tag and the provider instance as arguments.

If your custom configuration class does not need any special initialization, you can use the ConfigurationProvider class directly. It is able of creating an instance of a specified class (which must be derived from AbstractConfiguration). Let's take a look at an example where we want to add support for a configuration class called MyConfiguration. The corresponding tag in the configuration definition file should have the name myconfig. The code for registering the new provider and loading the configuration definition file looks as follows:

If your configuration provider is registered this way, your configuration definition file can contain the myconfig tag just as any other tag for declaring a configuration source:

]]>

As is demonstrated in this example, it is possible to specify attributes for initializing properties of your configuration object. In this example we set the default delimiterParsingDisabled property inherited from AbstractConfiguration. Of course you can set custom properties of your configuration class, too.

If your custom configuration class is a file-based configuration, you should use the FileConfigurationProvider class instead of ConfigurationProvider. FileConfigurationProvider is another inner class of DefaultConfigurationBuilder that knows how to deal with file-based configurations: it ensures that the correct base path is set and takes care of invoking the load() method.

If your custom configuration class requires special initialization, you need to create your own provider class that extends ConfigurationProvider. Here you will have to override the getConfiguration(ConfigurationDeclaration) method, which is responsible for creating the configuration instance (all information necessary for this purpose can be obtained from the passed in declaration object). It is recommended that you call the inherited method first, which will instantiate and initialize the new configuration object. Then you can perform your specific initialization.

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_events.xml100644 26202 12232154103 26167 0ustarhenningstaff 0 0 Configuration Events Howto Oliver Heger

All configuration classes derived from AbstractConfiguration allow to register event listeners, which are notified whenever the configuration's data is changed. This provides an easy means for tracking updates on a configuration.

Objects that are interested in update events triggered by configurations must implement the ConfigurationListener interface. This interface defines a single method configurationChanged(), which is passed a ConfigurationEvent object. The event object contains all information available about the modification, including:

  • A source object, which is usually the configuration object that was modified.
  • The event's type. This is a numeric value that corresponds to constant declarations in concrete configuration classes. It describes what exactly has happended.
  • If available, the name of the property whose modification caused the event.
  • If available, the value of the property that caused this event.
  • A flag whether this event was generated before or after the update of the source configuration. A modification of a configuration typically causes two events: one event before and one event after the modification is performed. This allows event listeners to react at the correct point of time.
Depending on the event type not all of this data may be available.

For resolving the numeric event type use constants defined in AbstractConfiguration or derived classes. These constants start with the prefix EVENT_ and have a speaking name. Here is an incomplete list of available event types with the configuration classes, in which they are defined:

AbstractConfiguration
EVENT_ADD_PROPERTY (a property was added; the name of the affected property and the value that was added can be obtained from the event object), EVENT_SET_PROPERTY (a property's value was changed; the event object stores the name of the affected property and its new value), EVENT_CLEAR_PROPERTY (a property was removed from the configuration; its name is stored in the event object), EVENT_CLEAR (the configuration was cleared)
AbstractFileConfiguration
EVENT_RELOAD (the configuration was reloaded)
HierarchicalConfiguration
EVENT_ADD_NODES (the addNodes() method was called; the event object contains the key, to which the nodes were added, and a collection with the new nodes as value), EVENT_CLEAR_TREE (the clearTree() method was called; the event object stores the key of the removed sub tree), EVENT_SUBNODE_CHANGED (a SubnodeConfiguration that was created from this configuration has been changed. The value property of the event object contains the original event object as it was sent by the subnode configuration. Note: At the moment it is not possible to map the property key as it was received from the subnode configuration into the namespace of the parent configuration.)

Implementing an event listener is quite easy. As an example we are going to define an event listener, which logs all received configuration events to the console. The class could look as follows:

Now an instance of this event listener class has to be registered at a configuration object:

Some implementations of the Configuration interface operate on underlying storages that can throw exceptions on each property access. As an example consider DatabaseConfiguration: this configuration class issues an SQL statement for each accessed property, which can potentially cause a SQLException.

In earlier versions of Commons Configuration such exceptions were simply logged and then swallowed. So for clients it was impossible to find out if something went wrong. From version 1.4 on there is a new way of dealing with those internal errors: the concept of error listeners.

A configuration error listener is very similar to a regular configuration event listener. Instead of the ConfigurationListener interface it has to implement the ConfigurationErrorListener interface, which defines a single method configurationError(). In case of an internal error this method is invoked, and a ConfigurationErrorEvent with information about that error is passed. By inheriting from ConfigurationEvent ConfigurationErrorEvent supports all information that is available for normal configuration listeners, too (e.g. the event type or the property that was accessed when the problem occurred; note that the isBefore() method does not really make sense for error events because an error can only occur after something was done, so it returns always false is this context). This data can be used to find out when and where the error happened. In addition there is the getCause() method that returns the Throwable object, which generated this event (i.e. the causing exception).

We can now continue our example from the previous section and make our example configuration listener also capable of tracing error events. To achieve this we let the ConfigurationLogListener class also implement the ConfigurationErrorListener interface:

import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.event.ConfigurationListener; public class ConfigurationLogListener implements ConfigurationListener, ConfigurationErrorListener { public void configurationChanged(ConfigurationEvent event) { // remains unchanged, see above ... } public void configurationError(ConfigurationErrorEvent event) { System.out.println("An internal error occurred!"); // Log the standard properties of the configuration event configurationChanged(event); // Now log the exception event.getCause().printStackTrace(); } }

Now the listener object has to be registered as an error listener, too. For this purpose AbstractConfiguration provides the addErrorListener() method. The following example fragment shows the registration of the log listener object:

AbstractConfiguration config = ... // somehow create the configuration ConfigurationListener listener = new ConfigurationLogListener(); config.addConfigurationListener(listener); config.addErrorListener((ConfigurationErrorListener) listener); ... config.addProperty("newProperty", "newValue"); // will fire an event

Note: AbstractConfiguration already implements a mechanism for writing internal errors to a logger object: It has the protected addErrorLogListener() method that can be called by derived classes to register a listener that will output all occurring internal errors using the default logger. Configuration implementations like DatabaseConfiguration that are affected by potential internal errors call this method during their initialization. So the default behavior of Commons Configuration for these classes is not changed: they still catch occurring exceptions and log them. However by registering specific error listeners it is now possible for clients to implement their own handling of such errors.

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_filebased.xml100644 27305 12232154103 26606 0ustarhenningstaff 0 0 File-based Configurations Oliver Heger

Often configuration properties are stored in files on the user's hard disk, e.g. in .properties files or as XML documents. Configuration classes that deal with such properties need to provide typical operations like loading or saving files. The files to be processed can be specified in several different flavors like java.io.File objects, relative or absolute path names, or URLs.

To provide a consistent way of dealing with configuration files in Commons Configuration the FileConfiguration interface exists. FileConfiguration defines a standard API for accessing files and is implemented by many configuration implementations, including PropertiesConfiguration and XMLConfiguration.

In the following sections we take a closer look at the methods of the FileConfiguration interface and how they are used.

The FileConfiguration interface contains several methods for specifying the file to be loaded. The following variants are supported:

  • With the setFile() method the data file can be specified as a java.io.File object.
  • The setURL() takes a java.net.URL as argument; the file will be loaded from this URL.
  • The methods setFileName() and setBasePath() allows to specify the path of the data file. The base path is important if relative paths are to be resolved based on this file.

While a File or a URL uniquely identify a file, the situation is a bit ambigous when only a base path and a file name are set. These can be arbitrary strings (even full URLs) whose exact meaning must be detected when the file is loaded. For this purpose file-based configurations perform the following checks (in this order):

  • If the combination from base path and file name is a full URL that points to an existing file, this URL will be used to load the file.
  • If the combination from base path and file name is an absolute file name and this file exists, it will be loaded.
  • If the combination from base path and file name is a relative file path that points to an existing file, this file will be loaded.
  • If a file with the specified name exists in the user's home directory, this file will be loaded.
  • Otherwise the file name is interpreted as a resource name, and it is checked whether the data file can be loaded from the classpath.
If all these checks fail, a ConfigurationException will be thrown.

After the file name has been defined using one of the methods mentioned above, the load() method can be called. This method tries to locate the file and open it. If this fails, a ConfigurationException is thrown.

The FileConfiguration interface defines multiple overloaded load() methods. The one that takes no argument will always operate on the file name that has been set earlier. All other methods allow to specify the source to be loaded. This can be done as java.io.File, java.net.URL, string (containing either an absolute or relative path), input stream, or reader. When using these variants of the load() method be aware of two things:

  1. They do not change the configuration's file name. To do this you have to explicitely call one of the setter methods.
  2. The load() methods do not empty the configuration before new data is loaded. This makes it easy to construct union configurations by simply calling load() multiple times. But if you want to reuse a Configuration object and load a different file, remember to call the clear() method first to ensure that old properties are wiped out.

File-based configurations typically define a set of constructors that correspond to the various setter methods for defining the data file. These constructors will set the file and then invoke the load() method. So creating a file-based configuration object and loading its content can be done in a single step.

Saving is implemented analogously to loading: There is a no argument save() method that will use the internal file name. Then for each load() method a corresponding save() method exists that will write the data contained in the configuration to different targets.

An example for loading, manipulating, and saving a configuration (based on a PropertiesConfiguration) could look as follows:

PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); config.setProperty("colors.background", "#000000"); config.save();

You can also save a copy of the configuration to another file:

PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); config.setProperty("colors.background", "#000000"); config.save("usergui.backup.properties);

If you want to ensure that every modification of a configuration object is immideately written to disk, you can enable the automatic saving mode. This is done through the setAutoSave() method as shown in the following example:

PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); config.setAutoSave(true); config.setProperty("colors.background", "#000000"); // the configuration is saved after this call

Be careful with this mode when you have many updates on your configuration. This will lead to many I/O operations, too.

A common issue with file-based configurations is to handle the reloading of the data file when it changes. This is especially important if you have long running applications and do not want to restart them when a configuration file was updated. Commons Configuration has the concept of so called reloading strategies that can be associated with a file-based configuration. Such a strategy monitors a configuration file and is able to detect changes. A default reloading strategy is FileChangedReloadingStrategy. It can be set on a file-based configuration as follows:

PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); config.setReloadingStrategy(new FileChangedReloadingStrategy());

FileChangedReloadingStrategy works as follows: On every property access the configuration checks its associated reloading strategy. FileChangedReloadingStrategy will then obtain the last modification date of the configuration file and check whether it has changed since the last access. If this is the case, a reload is triggered. To avoid often disk access when multiple properties are queried from the configuration, a refresh delay can be set on the reloading strategy. This is a time in milli seconds with the meaning that the reloading strategy will only once check the file's last modification time in the period specified here.

ManagedReloadingStrategy is an alternative to automatic reloading. It allows to hot-reload properties on a running application but only when requested by admin. The refresh() method will force a reload of the configuration source.

A typical use of this feature is to setup ManagedReloadingStrategy as a JMX MBean. The following code sample uses Springframework MBeanExporter to expose the ManagedReloadingStrategy to the JMX console : ]]> With this configuration, the JMX console will expose the "myApp:bean=configuration" MBean and it's refresh operation.

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_filesystems.xml100644 14554 12232154103 27241 0ustarhenningstaff 0 0 File Systems Ralph Goers

In its default mode of operation Commons Configuration supports retrieving and storing configuration files either on a local file system or via http. However, Commons Configuration provides support for allowing other File System adapters. All file access is accomplished through the FileSystem interface so accessing files using other mechanisms is possible.

Commons Configuration also provides a second FileSystem which allows retrieval using Apache Commons VFS. As of this writing Commons VFS supports 18 protocols for manipulating files.

The FileSystem used by Commons Configuration can be set in one of several ways:

  1. A system property named "org.apache.commons.configuration.filesystem" can be defined with the full class name of the desired FileSystem implementation to set the default FileSystem.
  2. FileSystem.setDefaultFilesystem() can be called to directly set the default FileSystem implementation.
  3. DefaultConfigurationBuilder.setFileSystem() can be called to set the FileSystem implementation. DefaultConfiguratonBuilder will use this for each configuration it creates
  4. DefaultConfigurationBuilder can be configured with the FileSystem to be used when creating each of the configurations.
  5. Each Configuration referenced in DefaultConfigurationBuilder's configuration can be configured with the FileSystem to use for that configuration.
  6. Call setFileSystem() directly on any Configuration that implements FileSystemBased. Both AbstractFileConfiguration and AbstractHierarchicalFileConfiguration implement FileSystemBased

The example that follows shows how to add FileSystem configuration to DefaultConfigurationBuilder.

]]>

Commons VFS allows options to the underlying file systems being used. Commons Configuration allows applications to provide these by implementing the FileOptionsProvider interface and registering the provider with the FileSystem. FileOptionsProvider has a single method that must be implemented, getOptions, which returns a Map containing the keys and values that the FileSystem might use. The getOptions method is called as each configuration uses VFS to create a FileOjbect to access the file. The map returned does not have to contain the same keys and/or values each time it is called. For example, the value of the currentUser key can be set to the id of the currently logged in user to allow a WebDAV save to record the userid as a file attribute.

The VFSFileChangedReloadingStrategy can be used to cause Configurations accessed via the VFSFileSystem to be monitored and reloaded when the files are modified. The example below shows how DefaultConfigurationBuilder can be configured to use VFSFilChangedReloadingStrategy. In the example below both test.properties and settings.xml would be checked for changes once per minute.

]]>
commons-configuration-1.10-src/src/site/xdoc/userguide/howto_multitenant.xml100644 20401 12232154103 27222 0ustarhenningstaff 0 0 Mutli-tenant Configurations Ralph Goers

In a multi-tenant environment a single instance of the application while run on behalf of many clients. Typically, this will require that each client have its own unique configuration. The simplest approach to enable an application to be multi-tenant is for it to not really be aware of it at all. This requires that the configuration framework take on some of the responsility for making the application work correctly.

One approach to enable this support in a web application might be to use a Servlet Filter and then use the Log4j or SLF4J MDC to save the attributes needed to identify the client. These attributes can then be used to identify the specific client configuration to be used. The classes described below use this technique to allow configurations to transparently provide the configuration appropriate for the clients.

The constructor for this class accepts a pattern. The pattern can contain keys that will be resolved using the ConfigurationInterpolator on each call to a method in the class. The configuration file will then be located using the resolved pattern and a new XMLConfiguration will be created and cached for subsequent requests. The ExpressionEngine, ReloadingStrategy and listeners will be propogated to each of the created configurations.

When used in a combined configuration it is often acceptable for a file matching a particular pattern to be missing so, by default, most exceptions encountered when loading files are ignored. To change this behavior call setIgnoreException(false) or configure the attribute to false in DefaultConfigurationBuilder's configuration file. If schema validation is enabled validation exceptions will always cause a failure.

The CombinedConfiguration class allows multiple configuration files to be merged together. However, it will not merge a MultiFileHierarchicalConfiguration properly since the underlying configuration file will be different depending on the resolution of the location pattern. DynamicCombinedConfiguration solves this by creating a new CombinedConfiguration for each pattern.

This sample configuration illustrates how to use DynamicCombinedConfiguration in combination with MultiFileHierarchicalConfiguration to create a multi-tenant configuration.

]]>

Note how the variables have multiple '$'. This is how variables are escaped and is necessary because the variables will be interpolated multiple times. Each attempt will remove the leading '$'. When there is only a single '$' in front of the '{' the interpolator will then resolve the variable. The first extra '$' is necessary because DefaultConfigurationBuilder will interpolate any variables in the configuration. In the case of the multifile configuration item two leading '$' characters are necessary before the variable because it will be interpolated by both DefaultConfigurationBuilder and DynamicCombinedConfiguration before MultiFileHierarchicalConfiguration gets the chance to evaluate it. Although in this example one would not expect system properties to change at runtime, other types of lookups such as the MDCStrLookup provided with SLF4J require that the variables be evaluated as the configuration is being accessed instead of when the configuration file is processed to behave as desired.

Applications are often composed of many components each of which need their own configuration. This can be accomodated by having a configuration file per component, but this can make things hard to manage when there are many clients and many components. A second approach is to combine them into a single configuration file. However, this either means the subcomponent has to be aware of the surrounding configuration and navigate past it or the application must be provided just the portion of the configuration it can process. PatternSubtreeConfigurationWrapper can be used for this purpose.

Normal practice when using dependency injection frameworks is to have the attributes needed to make components work correctly injected into them. When working with Commons Configuration this works very well. Components simply need to have a HierarchicalConfiguration attribute along with a corresponding setter and getter. The injection framework can then be used to provide the component with the correct configuration using PatternSubtreeConfigurationWrapper as shown in the next example.

configuration.xml ]]>

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_properties.xml100644 46550 12232154103 27067 0ustarhenningstaff 0 0 Properties files Emmanuel Bourg Oliver Heger

Properties files are a popular mean of configuring applications. Of course Commons Configuration supports this format and enhances significantly the basic java.util.Properties class. This section introduces the features of the PropertiesConfiguration class. Note that PropertiesConfiguration is a very typical example for an implementation of the Configuration interface and many of the features described in this section (e.g. list handling or interpolation) are supported by other configuration classes as well. This is because most configuration implementations that ship with Commons Configuration are derived from the common base class AbstractConfiguration, which implements these features.

Let's start with a simple properties file named usergui.properties with the following content:

To load this file, you'll write:

Configuration config = new PropertiesConfiguration("usergui.properties");

If you do not specify an absolute path, the file will be searched automatically in the following locations:

  • in the current directory
  • in the user home directory
  • in the classpath

Instead of using a constructor that takes a file name you can also invoke one of the load() methods. There are several overloaded variants that allow you to load properties from various sources. More information about loading properties files (and file-based configurations in general) can be found in the section about File-based Configurations.

After the properties file was loaded you can access its content through the methods of the Configuration interface, e.g.

String backColor = config.getString("colors.background"); Dimension size = new Dimension(config.getInt("window.width"), config.getInt("window.height"));

If a property is named "include" and the value of that property is the name of a file on the disk, that file will be included into the configuration. Here is an example:

# usergui.properties include = colors.properties include = sizes.properties # colors.properties colors.background = #FFFFFF

As was already pointed out in the section List handling of Basic features, Commons Configuration has the ability to return easily a list of values. For example a properties file can contain a list of comma separated values:

# chart colors colors.pie = #FF0000, #00FF00, #0000FF

You don't have to split the value manually, you can retrieve an array or a java.util.List directly with:

String[] colors = config.getStringArray("colors.pie"); List<Object> colorList = config.getList("colors.pie");

Alternatively, you can specify a list of values in your properties file by using the same key on several lines:

# chart colors colors.pie = #FF0000; colors.pie = #00FF00; colors.pie = #0000FF;

All of the features related to list handling described for AbstractConfiguration also apply to properties files, including changing the list delimiter or disabling list handling at all.

To save your configuration, just call the save() method:

PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); config.setProperty("colors.background", "#000000); config.save();

You can also save a copy of the configuration to another file:

PropertiesConfiguration config = new PropertiesConfiguration("usergui.properties"); config.setProperty("colors.background", "#000000); config.save("usergui.backup.properties);

More information about saving properties files (and file-based configurations in general) can be found in the section about File-based Configurations.

If you need a special character in a property like a line feed, a tabulation or an unicode character, you can specify it with the same escaped notation used for Java Strings. The list separator ("," by default), can also be escaped:

When dealing with lists of elements that contain backslash characters (e.g. file paths on Windows systems) escaping rules can become pretty complex. The first thing to keep in mind is that in order to get a single backslash, you have to write two:

This issue is not specific to Commons Configuration, but is related to the standard format for properties files. Refer to the Javadocs of the load() method of java.util.Properties for more information. Now if you want to define a list with file paths, you may be tempted to write the following:

As the comment indicates, this will not work. The trailing backslash of the first directory is interpreted as escape character for the list delimiter. So instead of a list with two elements only a single value of the property is defined - clearly not what was desired. To get a correct list the trailing backslash has to be escaped. This is achieved by duplicating it (yes, in a properties file that means that we now need 4 backslashes):

So a sequence of 4 backslashes in the value of a property is interpreted as an escaped backslash and eventually results in a single backslash. This creates another problem when a properties file should refer to the names of network shares. Typically these names start with two backslashes, so the obvious way to define such a property is as follows:

Unfortunately, this will not work because the shares contain the reserved sequence of 4 backslashes. So when reading the value of the config.dirs property a list with two elements is returned starting only with a single backslash. To fix the problem the sequence for escaping a backslash has to be duplicated - we are now at 8 backslashes:

As becomes obvious, escape sequences can become pretty complex and unreadable. In such situations it is recommended to use the alternative way of defining a list: just use the same key multiple times. In this case no additional escaping of backslashes (beyond the usual duplicating required by properties files) is needed because there is no list delimter character involved. Using this syntax the list of network shares looks like the following:

Each PropertiesConfiguration object is associated with a Layout object, an instance of the class PropertiesConfigurationLayout. This layout object is responsible for preserving most of the structure of loaded configuration files. This means that things like comments or blank lines in a saved properties file will closely resemble the original properties file (the algorithm is not 100 percent perfect, but for most use cases it should be sufficient).

Normally a developer does not have to deal with these layout objects. However, there are some methods that might be of interest if enhanced control over the output of properties files is needed. The following list describes these methods (note that corresponding get methods are of course also provided):

  • setComment()
    With this method a comment can be set for a specified property. When storing the configuration the comment is output before the property, followed by a line break. The comment can span multiple lines; in this case the newline character "\n" must be used as line separator.
  • setHeaderComment()
    With setHeaderComment() a global comment can be set for the properties file. This comment is written at the very start of the file, followed by an empty line.
  • setBlancLinesBefore()
    This methods allows defining the number of empty lines to be written before the specified property. It can be used, for instance, to devide the properties file into multiple logical sections.
  • setSingleLine()
    If a property has multiple values, with setSingleLine() it can be specified that all these values should be written into a single line separated by the default list separator. It is also possible to write multiple definitions for this property (i.e. multiple lines of the form property = value1, property = value2 etc.). This is supported by PropertiesConfiguration, but will probably not work when processing the properties file with other tools.
  • setForceSingleLine()
    This is similar to setSingleLine(), but sets a global single line flag. If set to true, all properties with multiple values are always written on a single line.
  • setGlobalSeparator()
    Sometimes it may be necessary to define the properties separator, i.e. the string that separates the property key from the value. This can be done using setGlobalSeparator(). Here an arbitrary string can be specified that will be used as separator. (Note: In order to produce valid properties files only the characters = and : should be used as separators (with or without leading or trailing whitespace), but the method does not enforce this.
  • setSeparator()
    This method is similar to setGlobalSeparator(), but allows setting the property separator for a specific property.
  • setLineSeparator()
    Using this method the line separator can be specified. Per default the platform-specific line separator is used (e.g. \n on unix).
The default settings of PropertiesConfigurationLayout are chosen in a way that most of the original layout of a properties file is retained. With the methods listed above specific layout restrictions can be enforced.

There are situations when more control over the process of reading and writing properties file is needed. For instance, an application might have to deal with some legacy properties file in a specific format, which is not supported out of the box by PropertiesConfiguration, but must not be modified. In these cases it is possible to inject a custom reader and writer for properties files.

Per default properties files are read and written by the nested classes PropertiesReader and PropertiesWriter (defined within PropertiesConfiguration). These classes are regular reader and writer classes (both are derived from typical base classes of the java.io package) that provide some additional methods making dealing with properties files more convenient. Custom implementations of properties readers and writers must extend these base classes.

For installing a custom properties reader or writer PropertiesConfiguration provides the IOFactory interface (which is also defined as a nested class). An object implementing this interface is stored in each PropertiesConfiguration instance. Whenever a properties file is to be read or written (i.e. when one of the load() or save() methods is called), the IOFactory object is asked for creating the properties reader or writer to be used.

The IOFactory interface is pretty simple; it defines one method for creating a properties reader and another one for creating a properties writer. A default implementation called DefaultIOFactory is also available and is used by PropertiesConfiguration when no specific IOFactory is set. To make this discussion more concrete we provide an example of how to inject a custom properties reader. The use case is that we have to load a properties file that contains keys with whitespace, which is not supported by PropertiesConfiguration per default. A fragment from such a properties file could look as follows:

The first step is to create a custom properties reader implementation that can deal with such properties. The class is derived from PropertiesConfiguration.PropertiesReader and overrides the parseProperty() method:

Notice the calls to the methods initPropertyName() and initPropertyValue(). Here the results of the parsing operation are stored. The next step is to provide a specialized implementation of the IOFactory interface that returns the new properties reader class. As we only want to replace the properties reader (and use the standard writer), we can derive our implementation from DefaultIOFactory and thus only have to override the createPropertiesReader() method.

Finally an instance of our new IOFactory implementation has to be created and passed to the PropertiesConfiguration object. This must be done before the load() method is called. So we cannot use one of the constructors that load the data. The code for setting up the configuration object could look as follows:

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_utilities.xml100644 32306 12232154103 26700 0ustarhenningstaff 0 0 Utility classes and Tips and Tricks Howto Oliver Heger

In this section some utility classes will be introduced that can be used to make handling of configuration objects easier. These classes already provide solutions for some often occurring problems. We will list these problems in no specific order and show how they can be solved with classes provided by Commons Configuration.

Often it is required to copy the data of one Configuration object into another one. For this purpose the AbstractConfiguration class (which serves as the base class for most of the configuration implementations shipped with this library) provides two methods implementing a basic copy operation:

  • append() takes the configuration to be copied as argument and adds all of its properties to the current configuration.
  • copy() is very similar to append(). The difference is that properties that already exist in the target configuration are replaced by the properties of the source configuration.

These methods work fine if the target configuration is not a hierarchical configuration. If a hierarchical configuration is to be copied into another one, the methods are not able to handle the hierarchical structure; so the resulting configuration will contain all of the properties of the source configuration, but the specific parent-child relations will probably be lost. If a hierarchical configuration needs to be copied, there are the following options:

  • The clone() method can be used to create a copy of a hierarchical configuration. This also works for non-hierarchical configurations. Most of the configuration implementations provided by Commons Configurations support cloning. The cloneConfiguration() method of ConfigurationUtils can be used for creating a copy of an arbitrary Configuration object. This method checks whether the passed in configuration implements the Cloneable interface and, if so, invokes its clone() method.
  • Most hierarchical configurations have a constructor, which takes another hierarchical configuration as argument. This constructor copies the content of the specified configuration into the newly created object.

Hierarchical configurations provide some enhanced features that are not available for "flat" configurations. For instance they support more sophisticated query facilities. Because of that it may be sometimes useful to transform an ordinary configuration into a hierarchical one. The following code fragment shows how this can be done:

The convertToHierarchical() method of ConfigurationUtils checks whether the passed in object is already a hierarchical configuration. If this is the case, it is returned unchanged. Otherwise a new HierarchicalConfiguration object is created, and the properties of the source configuration are copied into it.

Sometimes a flat configuration contains keys with special characters that are not compatible with the expression engine of a hierarchical configuration. For instance, a properties configuration could have the following property:

When processing this property during conversion the default expression engine of the resulting hierarchical configuration will interpret the brackets as an index marker and try to convert the string between the brackets into a number. In this example this fails with a NumberFormatException! The cause for this problem is that the property key contains characters with a special meaning for the default expression engine.

To solve this problem, it is possible to specify an alternative expression engine that will be used for the conversion. For instance, if you know that your property keys can contain brackets, you could use an instance of DefaultExpressionEngine that is configured with a different index marker. This could look as follows:

In this example an expression engine is constructed that uses square brackets as index markers. Therefore normal brackets do not have a special meaning and thus are no more problematic during conversion.

Note: When using a CombinedConfiguration flat configurations contained in the combined configuration are also converted into hierarchical configurations using the methods discussed here. The CombinedConfiguration class defines the method setConversionExpressionEngine(), which can be called to specify an expression engine to be used during this conversion. The expression engine passed to this method will be propagated to ConfigurationUtils.convertToHierarchical().

When working with the JDK the java.util.Properties class is typically used for storing configuration data. If Commons Configuration is to be integrated in such an application, there may be the requirement of converting from Properties objects to Configuration objects and vice versa. For this purpose an utility class can be used: ConfigurationConverter.

Usage of this class is pretty simple. It provides some static utility methods that perform different conversions. Below you can see some examples. In this fragment we assume that we have a method processConfiguration() that is called from older parts of an application that are not aware of the Commons Configuration API. So they pass in a Properties object and expect one as return value. Inside the method a temporary Configuration object is created and used.

Please refer to the Javadocs of ConfigurationConverter to learn more about the available conversion methods and their limitations.

Another issue with the integration of Commons Configuration with native Java applications can be variables: Configuration implementations are able to detect variables like ${myReference} or ${sys:java.version} in the values of their properties and substitute them by their current values (see the section Variable Interpolation for more details). External components probably do not know how to handle such placeholders when processing configuration files written by Commons Configuration.

AbstractConfiguration provides the method interpolatedConfiguration(). This method creates a clone of the current configuration and then performs interpolation on all of its properties. So the result of this method is a configuration object with basically the same content as the original configuration, but with all variables replaced by their actual values (as far as this was possible). The following code fragment shows how a PropertiesConfiguration object can be saved in a way that the resulting properties file does not contain any variables:

Section Error listeners introduces a way of dealing with runtime exceptions that can occur on accessing configuration properties by registering an event listener. If you do not want to provide a special error handler, but only need to propagate the exception that caused the error event, you can make use of a convenience method of the ConfigurationUtils class: enableRuntimeExceptions() registers a special error listener at the passed in configuration that will throw a ConfigurationRuntimeException exception for each received error event. The following code fragment shows an example of using this method:

enableRuntimeExceptions() can be called for all Configuration implementations that are derived from EventSource (which is the case for almost all configuration classes provided by this library). Of course the affected implementation must support the mechanism of error events, otherwise the registered listener will not be triggered. In Error listeners more information can be found.

commons-configuration-1.10-src/src/site/xdoc/userguide/howto_xml.xml100644 156602 12232154103 25513 0ustarhenningstaff 0 0 Hierarchical configurations and XML Howto Oliver Heger

This section explains how to use hierarchical and structured XML datasets.

Many sources of configuration data have a hierarchical or tree-like nature. They can represent data that is structured in many ways. Such configuration sources are represented by classes derived from HierarchicalConfiguration.

Prominent examples of hierarchical configuration sources are XML documents. They can be read and written using the XMLConfiguration class. This section explains how to deal with such structured data and demonstrates the enhanced query facilities supported by HierarchicalConfiguration. We use XML documents as examples for structured configuration sources, but the information provided here (especially the rules for accessing properties) applies to other hierarchical configurations as well. Examples for other hierarchical configuration classes are

We will start with a simple XML document to show some basics about accessing properties. The following file named gui.xml is used as example document:

#808080 #000000
#008000
${colors.header}
15 OK,Cancel,Help
]]>

(As becomes obvious, this tutorial does not bother with good design of XML documents, the example file should rather demonstrate the different ways of accessing properties.) To access the data stored in this document it must be loaded by XMLConfiguration. Like other file based configuration classes XMLConfiguration supports many ways of specifying the file to process. One way is to pass the file name to the constructor as shown in the following code fragment:

If no exception was thrown, the properties defined in the XML document are now available in the configuration object. Other hierarchical configuration classes that operate on files have corresponding constructors and methods for loading their data. The following fragment shows how the properties can be accessed:

buttons = config.getList("buttons.name"); ]]>

This listing demonstrates some important points about constructing keys for accessing properties in hierarchical configuration sources and about features of HierarchicalConfiguration in general:

  • Nested elements are accessed using a dot notation. In the example document there is an element <text> in the body of the <color> element. The corresponding key is color.text.
  • The root element is ignored when constructing keys. In the example you do not write gui-definition.color.text, but only color.text.
  • Attributes of XML elements are accessed in a XPath like notation.
  • Interpolation can be used as in PropertiesConfiguration. Here the <default> element in the colors section refers to another color.
  • Lists of properties can be defined in a short form using the delimiter character (which is the comma by default). In this example the buttons.name property has the three values OK, Cancel, and Help, so it is queried using the getList() method. This works in attributes, too. Using the static setDefaultDelimiter() method of AbstractConfiguration you can globally define a different delimiter character or - by setting the delimiter to 0 - disabling this mechanism completely. Placing a backslash before a delimiter character will escape it. This is demonstrated in the pattern attribute of the numberFormat element.

In the next section will show how data in a more complex XML document can be processed.

Consider the following scenario: An application operates on database tables and wants to load a definition of the database schema from its configuration. A XML document provides this information. It could look as follows:

users uid long uname java.lang.String firstName java.lang.String lastName java.lang.String email java.lang.String
documents docid long name java.lang.String creationDate java.util.Date authorID long version int
]]>

This XML is quite self explanatory; there is an arbitrary number of table elements, each of it has a name and a list of fields. A field in turn consists of a name and a data type. This XML document (let's call it tables.xml) can be loaded in exactly the same way as the simple document in the section before.

When we now want to access some of the properties we face a problem: the syntax for constructing configuration keys we learned so far is not powerful enough to access all of the data stored in the tables document.

Because the document contains a list of tables some properties are defined more than once. E.g. the configuration key tables.table.name refers to a name element inside a table element inside a tables element. This constellation happens to occur twice in the tables document.

Multiple definitions of a property do not cause problems and are supported by all classes of Configuration. If such a property is queried using getProperty(), the method recognizes that there are multiple values for that property and returns a collection with all these values. So we could write

) prop).size()); } ]]>

An alternative to this code would be the getList() method of Configuration. If a property is known to have multiple values (as is the table name property in this example), getList() allows retrieving all values at once. Note: it is legal to call getString() or one of the other getter methods on a property with multiple values; it returns the first element of the list.

Okay, we can obtain a list with the names of all defined tables. In the same way we can retrieve a list with the names of all table fields: just pass the key tables.table.fields.field.name to the getList() method. In our example this list would contain 10 elements, the names of all fields of all tables. This is fine, but how do we know, which field belongs to which table?

When working with such hierarchical structures the configuration keys used to query properties can have an extended syntax. All components of a key can be appended by a numerical value in parentheses that determines the index of the affected property. So if we have two table elements we can exactly specify, which one we want to address by appending the corresponding index. This is explained best by some examples:

We will now provide some configuration keys and show the results of a getProperty() call with these keys as arguments.

tables.table(0).name
Returns the name of the first table (all indices are 0 based), in this example the string users.
tables.table(0)[@tableType]
Returns the value of the tableType attribute of the first table (system).
tables.table(1).name
Analogous to the first example returns the name of the second table (documents).
tables.table(2).name
Here the name of a third table is queried, but because there are only two tables result is null. The fact that a null value is returned for invalid indices can be used to find out how many values are defined for a certain property: just increment the index in a loop as long as valid objects are returned.
tables.table(1).fields.field.name
Returns a collection with the names of all fields that belong to the second table. With such kind of keys it is now possible to find out, which fields belong to which table.
tables.table(1).fields.field(2).name
The additional index after field selects a certain field. This expression represents the name of the third field in the second table (creationDate).
tables.table.fields.field(0).type
This key may be a bit unusual but nevertheless completely valid. It selects the data types of the first fields in all tables. So here a collection would be returned with the values [long, long].

These examples should make the usage of indices quite clear. Because each configuration key can contain an arbitrary number of indices it is possible to navigate through complex structures of hierarchical configurations; each property can be uniquely identified.

Sometimes dealing with long property keys may become inconvenient, especially if always the same properties are accessed. For this case HierarchicalConfiguration provides a short cut with the configurationAt() method. This method can be passed a key that selects exactly one node of the hierarchy of nodes contained in a hierarchical configuration. Then a new hierarchical configuration will be returned whose root node is the selected node. So all property keys passed into that configuration should be relative to the new root node. For instance, if we are only interested in information about the first database table, we could do something like that:

fieldNames = sub.getList("fields.field.name"); ]]>

For dealing with complex list-like structures there is another short cut. Often it will be necessary to iterate over all items in the list and access their (sub) properties. A good example are the fields of the tables in our demo configuration. When you want to process all fields of a table (e.g. for constructing a CREATE TABLE statement), you will need all information stored for them in the configuration. An option would be to use the getList() method to fetch the required data one by one:

fieldNames = config.getList("tables.table(0).fields.field.name"); List fieldTypes = config.getList("tables.table(0).fields.field.type"); List ... // further calls for other data that might be stored in the config ]]>

But this is not very readable and will fail if not all field elements contain the same set of data (for instance the type property may be optional, then the list for the types can contain less elements than the other lists). A solution to these problems is the configurationsAt() method, a close relative to the configurationAt() method covered above. This method evaluates the passed in key and collects all configuration nodes that match this criterion. Then for each node a HierarchicalConfiguration object is created with this node as root node. A list with these configuration objects is returned. As the following example shows this comes in very handy when processing list-like structures:

fields = config.configurationsAt("tables.table(0).fields.field"); for(HierarchicalConfiguration sub : fields) { // sub contains all data about a single field String fieldName = sub.getString("name"); String fieldType = sub.getString("type"); ... ]]>

The configurations returned by the configurationAt() and configurationsAt() method are in fact instances of the SubnodeConfiguration class. The API documentation of this class contains more information about its features and limitations.

So far we have learned how to use indices to avoid ambiguities when querying properties. The same problem occurs when adding new properties to a structured configuration. As an example let's assume we want to add a new field to the second table. New properties can be added to a configuration using the addProperty() method. Of course, we have to exactly specify where in the tree like structure new data is to be inserted. A statement like

would not be sufficient because it does not contain all needed information. How is such a statement processed by the addProperty() method?

addProperty() splits the provided key into its single parts and navigates through the properties tree along the corresponding element names. In this example it will start at the root element and then find the tables element. The next key part to be processed is table, but here a problem occurs: the configuration contains two table properties below the tables element. To get rid off this ambiguity an index can be specified at this position in the key that makes clear, which of the two properties should be followed. tables.table(1).fields.field.name e.g. would select the second table property. If an index is missing, addProperty() always follows the last available element. In our example this would be the second table, too.

The following parts of the key are processed in exactly the same manner. Under the selected table property there is exactly one fields property, so this step is not problematic at all. In the next step the field part has to be processed. At the actual position in the properties tree there are multiple field (sub) properties. So we here have the same situation as for the table part. Because no explicit index is defined the last field property is selected. The last part of the key passed to addProperty() (name in this example) will always be added as new property at the position that has been reached in the former processing steps. So in our example the last field property of the second table would be given a new name sub property and the resulting structure would look like the following listing:

documents docid long name java.lang.String creationDate java.util.Date authorID long version size <== Newly added property int ]]>

This result is obviously not what was desired, but it demonstrates how addProperty() works: the method follows an existing branch in the properties tree and adds new leaves to it. (If the passed in key does not match a branch in the existing tree, a new branch will be added. E.g. if we pass the key tables.table.data.first.test, the existing tree can be navigated until the data part of the key. From here a new branch is started with the remaining parts data, first and test.)

If we want a different behavior, we must explicitely tell addProperty() what to do. In our example with the new field our intension was to create a new branch for the field part in the key, so that a new field property is added to the structure rather than adding sub properties to the last existing field property. This can be achieved by specifying the special index (-1) at the corresponding position in the key as shown below:

The first line in this fragment specifies that a new branch is to be created for the field property (index -1). In the second line no index is specified for the field, so the last one is used - which happens to be the field that has just been created. So these two statements add a fully defined field to the second table. This is the default pattern for adding new properties or whole hierarchies of properties: first create a new branch in the properties tree and then populate its sub properties. As an additional example let's add a complete new table definition to our example configuration:

For more information about adding properties to a hierarchical configuration also have a look at the javadocs for HierarchicalConfiguration.

Some characters in property keys or values require a special treatment.

Per default the dot character is used as delimiter by most configuration classes (we will learn how to change this for hierarchical configurations in a later section). In some configuration formats however, dots can be contained in the names of properties. For instance, in XML the dot is a legal character that can occur in any tag. The same is true for the names of properties in windows ini files. So the following XML document is completely valid:

42 many dots ]]>

This XML document can be loaded by XMLConfiguration without trouble, but when we want to access certain properties we face a problem: The configuration claims that it does not store any values for the properties with the keys test.value or test.complex.test.sub.element!

Of course, it is the dot character contained in the property names, which causes this problem. A dot is always interpreted as a delimiter between elements. So given the property key test.value the configuration would look for an element named test and then for a sub element with the name value. To change this behavior it is possible to escape a dot character, thus telling the configuration that it is really part of an element name. This is simply done by duplicating the dot. So the following statements will return the desired property values:

Note the duplicated dots whereever the dot does not act as delimiter. This way it is possible to access properties containing dots in arbitrary combination. However, as you can see, the escaping can be confusing sometimes. So if you have a choice, you should avoid dots in the tag names of your XML configuration files or other configuration sources.

Another source of problems is related to list delimiter characters in the values of properties. Like other configuration classes XMLConfiguration implements list handling. This means that the values of XML elements and attributes are checked whether they contain a list delimiter character. If this is the case, the value is split, and a list property is created. Per default this feature is enabled. Have a look at the following example:

3,1415 ]]>

Here we use the comma as delimiter for fraction digits (as is standard for some languages). However, the configuration will interpret the comma as list delimiter character and assign the property pi the two values 3 and 1415. This was not desired.

XML has a natural way of defining list properties by simply repeating elements. So defining multiple values of a property in a single element or attribute is a rather untypical use case. Unfortunately, early versions of Commons Configuration had list delimiter splitting enabled per default. Later it became obvious that this feature can cause serious problems related to the interpretation of property values and the escaping of delimiter characters. For reasons of backwards compatibility we have to stick to this approach in the 1.x series though.

In the next major release the handling of lists will propably be reworked. Therefore it is recommended not to use this feature. You are save if you disable it immediately after the creation of an XMLConfiguration object (and before a file is loaded). This can be achieved as follows:

In the previous chapters we saw many examples about how properties in a XMLConfiguration object (or more general in a HierarchicalConfiguration object, because this is the base class, which implements this functionality) can be queried or modified using a special syntax for the property keys. Well, this was not the full truth. Actually, property keys are not processed by the configuration object itself, but are delegated to a helper object, a so called Expression engine.

The separation of the task of interpreting property keys into a helper object is a typical application of the Strategy design pattern. In this case it also has the advantage that it becomes possible to plug in different expression engines into a HierarchicalConfiguration object. So by providing different implementations of the ExpressionEngine interface hierarchical configurations can support alternative expression languages for accessing their data.

Before we discuss the available expression engines that ship with Commons Configuration, it should be explained how an expression engine can be associated with a configuration object. HierarchicalConfiguration and all derived classes provide a setExpressionEngine() method, which expects an implementation of the ExpressionEngine interface as argument. After this method was called, the configuration object will use the passed expression engine, which means that all property keys passed to methods like getProperty(), getString(), or addProperty() must conform to the syntax supported by this engine. Property keys returned by the getKeys() method will follow this syntax, too.

In addition to instance specific expression engines that change the behavior of single configuration objects it is also possible to set a global expression engine. This engine is shared between all hierarchical configuration objects, for which no specific expression engine was set. The global expression engine can be set using the static setDefaultExpressionEngine() method of HierarchicalConfiguration. By invoking this method with a custom expression engine the syntax of all hierarchical configuration objects can be altered at once.

The syntax described so far for property keys of hierarchical configurations is implemented by a specific implementation of the ExpressionEngine interface called DefaultExpressionEngine. An instance of this class is installed as the global expression engine in HierarchicalConfiguration. So all newly created instances of this class will make use of this engine (which is the reason that our examples above worked).

After reading the examples of property keys provided so far in this document you should have a sound understanding regarding the features and the syntax supported by the DefaultExpressionEngine class. But it can do a little bit more for you: it defines a bunch of properties, which can be used to customize most tokens that can appear in a valid property key. You prefer curly brackets over paranthesis as index markers? You find the duplicated dot as escaped property delimiter counter-intuitive? Well, simply go ahead and change it! The following example shows how the syntax of a DefaultExpressionEngine object is modified. Then this object is set as the global expression engine, so that from now on all hierarchical configuration objects will take up this new syntax:

Tip: Sometimes when processing an XML document you don't want to distinguish between attributes and "normal" child nodes. You can achieve this by setting the AttributeEnd property to null and the AttributeStart property to the same value as the PropertyDelimiter property. Then the syntax for accessing attributes is the same as the syntax for other properties:

The expression language provided by the DefaultExpressionEngine class is powerful enough to address all properties in a hierarchical configuration, but it is not always convenient to use. Especially if list structures are involved, it is often necessary to iterate through the whole list to find a certain element.

Think about our example configuration that stores information about database tables. A use case could be to load all fields that belong to the "users" table. If you knew the index of this table, you could simply build a property key like tables.table(<index>).fields.field.name, but how do you find out the correct index? When using the default expression engine, the only solution to this problem is to iterate over all tables until you find the "users" table.

Life would be much easier if an expression language could be used, which would directly support queries of such kind. In the XML world, the XPATH syntax has grown popular as a powerful means of querying structured data. In XPATH a query that selects all field names of the "users" table would look something like tables/table[@name='users']/fields/name (here we assume that the table's name is modelled as an attribute). This is not only much simpler than an iteration over all tables, but also much more readable: it is quite obvious, which fields are selected by this query.

Given the power of XPATH it is no wonder that we got many user requests to add XPATH support to Commons Configuration. Well, here is it!

For enabling XPATH syntax for property keys you need the XPathExpressionEngine class. This class implements the ExpressionEngine interface and can be plugged into a HierarchicalConfiguration object using the setExpressionEngine() method. It is also possible to set an instance of this class as the global expression engine, so that all hierarchical configuration objects make use of XPATH syntax. The following code fragment shows how XPATH support can be enabled for a configuration object:

fields = config.getList("tables/table[1]/fields/name"); ]]>

XPATH expressions are not only used for selecting properties (i.e. for the several getter methods), but also for adding new properties. For this purpose the keys passed into the addProperty() method must conform to a special syntax. They consist of two parts: the first part is an arbitrary XPATH expression that selects the node where the new property is to be added to, the second part defines the new element to be added. Both parts are separated by whitespace.

Okay, let's make an example. Say, we want to add a type property under the first table (as a sibling to the name element). Then the first part of our key will have to select the first table element, the second part will simply be type, i.e. the name of the new property:

(Note that indices in XPATH are 1-based, while in the default expression language they are 0-based.) In this example the part tables/table[1] selects the target element of the add operation. This element must exist and must be unique, otherwise an exception will be thrown. type is the name of the new element that will be added. If instead of a normal element an attribute should be added, the example becomes

It is possible to add complete paths at once. Then the single elements in the new path are separated by "/" characters. The following example shows how data about a new table can be added to the configuration. Here we use full paths:

The first line of this example adds the path table/name to the tables element, i.e. a new table element will be created and added as last child to the tables element. Then a new name element is added as child to the new table element. To this element the value "tasks" is assigned. The next line adds a type attribute to the new table element. To obtain the correct table element, to which the attribute must be added, the XPATH function last() is used; this function selects the last element with a given name, which in this case is the new table element. The following lines all use the same approach to construct a new element hierarchy: At first complete new branches are added (fields/field/name), then to the newly created elements further children are added.

There is one gotcha with these keys described so far: they do not work with the setProperty() method! This is because setProperty() has to check whether the passed in key already exists; therefore it needs a key which can be interpreted by query methods. If you want to use setProperty(), you can pass in regular keys (i.e. without a whitespace separator). The method then tries to figure out which part of the key already exists in the configuration and adds new nodes as necessary. In principle such regular keys can also be used with addProperty(). However, they do not contain sufficient information to decide where new nodes should be added.

To make this clearer let's go back to the example with the tables. Consider that there is a configuration which already contains information about some database tables. In order to add a new table element in the configuration addProperty() could be used as follows:

In the configuration a <tables> element already exists, also <table> and <name> elements. How should the expression engine know where new node structures are to be added? The solution to this problem is to provide this information in the key by stating:

Now it is clear that new nodes should be added as children of the <tables> element. More information about keys and how they play together with addProperty() and setProperty() can be found in the Javadocs for XPathExpressionEngine.

Note: XPATH support is implemented through Commons JXPath. So when making use of this feature, be sure you include the commons-jxpath jar in your classpath.

In this tutorial we don't want to describe XPATH syntax and expressions in detail. Please refer to corresponding documentation. It is important to mention that by embedding Commons JXPath the full extent of the XPATH 1.0 standard can be used for constructing property keys.

XML parsers provide support for validation of XML documents to ensure that they conform to a certain DTD or XML Schema. This feature can be useful for configuration files, too. XMLConfiguration allows this feature to be enabled when files are loaded.

The easiest way to turn on validation is to simply set the validating property to true as shown in the following example:

Setting the validating flag to true will cause XMLConfiguration to use a validating XML parser. At this parser a custom ErrorHandler will be registered, which throws exceptions on simple and fatal parsing errors.

XML Parsers also provide support for validating XML documents using an XML Schema. XMLConfiguration provides a simple mechanism for enabling this by setting the schemaValidation flag to true. This will also set the validating flag to true so both do not need to be set. The XML Parser will then use the schema defined in the XML document to validate it. Enabling schema validation will also enable the parser's namespace support.

There is also some support for dealing with DTD files. Often the DTD of an XML document is stored locally so that it can be quickly accessed. However the DOCTYPE declaration of the document points to a location on the web as in the following example:

]]>

When working with XML documents directly you would use an EntityResolver in such a case. The task of such an entity resolver is to point the XML parser to the location of the file referred to by the declaration. So in our example the entity resolver would load the DTD file from a local cache instead of retrieving it from the internet.

XMLConfiguration provides a simple default implementation of an EntityResolver. This implementation is initialized by calling the registerEntityId() method with the public IDs of the entities to be retrieved and their corresponding local URLs. This method has to be called before the configuration is loaded. To continue our example, consider that the DTD file for our example document is stored on the class path. We can register it at XMLConfiguration using the following code:

This basically tells the XML configuration to use the specified URL when it encounters the given public ID. Note that the call to registerEntityId() has to be performed before the configuration is loaded. So you cannot use one of the constructors that directly load the configuration.

While the default entity resolver can be used under certain circumstances, it does not work well when using the DefaultConfigurationBuilder. Furthermore, in many circumstances the programmatic nature of registering entities will tie the application tightly to the XML content. In addition, because it only works with the public id it cannot support XML documents using an XML Schema.

XML Entity and URI Resolvers describes using a set of catalog files to resolve enitities. Commons Configuration provides support for this Catalog Resolver through its own CatalogResolver class.

555121211 John Doe 1975-05-15 Exempt 100000 ]]>

The XML sample above is an XML document using a default namespace of http://commons.apache.org/employee. The schemaLocation allows a set of namespaces and hints to the location of their corresponding schemas. When processing the document the parser will pass the hint, in this case http://commons.apache.org/sample.xsd, to the entity resolver as the system id. More information on using schema locations can be found at schemaLocation.

The example that follows shows how to use the CatalogResolver when processing an XMLConfiguration. It should be noted that by using the setEntityResolver method any EntityResolver may be used, not just those provided by Commons Configuration.

The mechanisms provided with Commons Configuration will hopefully be sufficient in most cases, however there will certainly be circumstances where they are not. XMLConfiguration provides two extension mechanisms that should provide applications with all the flexibility they may need. The first, registering a custom Entity Resolver has already been discussed in the preceeding section. The second is that XMLConfiguration provides a generic way of setting up the XML parser to use: A preconfigured DocumentBuilder object can be passed to the setDocumentBuilder() method.

So an application can create a DocumentBuilder object and initialize it according to its special needs. Then this object must be passed to the XMLConfiguration instance before invocation of the load() method. When loading a configuration file, the passed in DocumentBuilder will be used instead of the default one. Note: If a custom DocumentBuilder is used, the default implementation of the EntityResolver interface is disabled. This means that the registerEntityId() method has no effect in this mode.

commons-configuration-1.10-src/src/site/xdoc/userguide/overview.xml100644 21655 12232154103 25320 0ustarhenningstaff 0 0 Configuration Overview Eric Pugh Emmanuel Bourg

Commons Configuration allows you to access configuration properties from a variety of different sources. No matter if they are stored in a properties file, a XML document, or a JNDI tree, they can all be accessed in the same way through the generic Configuration interface.

Another strength of Commons Configuration is its ability to mix configurations from heterogeneous sources and treat them like a single logic configuration. This section will introduce you to the different configurations available and will show you how to combine them.

Currently there are quite a number of different sources of Configuration objects. But, by just using a Configuration object versus a specific type like XMLConfiguration or JNDIConfiguration, you are sheltered from the mechanics of actually retrieving the configuration values. These various sources include:

  • PropertiesConfiguration Loads configuration values from a properties file.
  • XMLConfiguration Takes values from an XML document.
  • INIConfiguration Loads the values from a .ini file as used by Windows.
  • PropertyListConfiguration Loads values from an OpenStep .plist file. XMLPropertyListConfiguration is also available to read the XML variant used by Mac OS X.
  • JNDIConfiguration Using a key in the JNDI tree, can retrieve values as configuration properties.
  • BaseConfiguration An in-memory method of populating a Configuration object.
  • HierarchicalConfiguration An in-memory Configuration object that is able to deal with complex structured data.
  • SystemConfiguration A configuration using the system properties
  • ConfigurationConverter Takes a java.util.Properties or an org.apache.commons.collections.ExtendedProperties and converts it to a Configuration object.

Often you want to provide a base set of configuration values, but allow the user to easily override them for their specific environment. Well one way is to hard code the default values into your code, and have then provide a property file that overrides this. However, this is a very rigid way of doing things. Instead, with the CompositeConfiguration you can provide many different ways of setting up a configuration. You can either do it manually:

CompositeConfiguration config = new CompositeConfiguration(); config.addConfiguration(new SystemConfiguration()); config.addConfiguration(new PropertiesConfiguration("application.properties"));

or via the ConfigurationFactory class:

ConfigurationFactory factory = new ConfigurationFactory("config.xml"); Configuration config = factory.getConfiguration();

The config.xml file used in the example above is a configuration descriptor, it specifies the Configuration objects to load. Here is an example of descriptor:

]]>

What this says is that we are loading up all system properties, as well as the properties file application.properties. The order of precedence is first to last. So in the above example, if a property is not found in the system properties, it'll be searched in the properties file. This allows you to set up default values in a properties file, and override them with the system properties.

All the classes in this package that represent different kinds of configuration sources share a single interface: Configuration. This interface allows you to access and manipulate configuration properties in a generic way.

A major part of the methods defined in the Configuration interface deals with retrieving properties of different data types. All these methods take a key as an argument that points to the desired property. This is a string value whose exact meaning depends on the concrete Configuration implementation used. They try to find the property specified by the passed in key and convert it to their target type; this converted value will be returned. There are also overloaded variants of all methods that allow to specify a default value, which will be returned if the property cannot be found. The following data types are supported:

  • BigDecimal
  • BigInteger
  • boolean
  • byte
  • double
  • float
  • int
  • long
  • short
  • String
The names of these methods start with get followed by their data type. The getString() method for instance will return String values, getInt() will operate on integers.

Properties can have multiple values, so it is also possible to query a list containing all of the available values. This is done using the getList() method.

For manipulating properties or their values the following methods can be used:

addProperty()
Adds a new property to the configuration. If this property already exists, another value is added to it (so it becomes a multi-valued property).
clearProperty()
Removes the specified property from the configuration.
setProperty()
Overwrites the value of the specified property. This is the same as removing the property and then calling addProperty() with the new property value.
clear()
Wipes out the whole configuration

The most concrete implementations of the Configuration interface that are shipped with this library are not thread-safe. They can be accessed concurrently in a read-only manner. However if one thread modifies a configuration object, manual synchronization has to be performed to ensure correctness of data. Notes about the thread safety of conrete implementation classes can be found in the Javadocs for these classes.

commons-configuration-1.10-src/src/site/xdoc/userguide/user_guide.xml100644 22676 12232154103 25611 0ustarhenningstaff 0 0 Commons Configuration User's Guide

This document describes the features of the Commons Configuration component starting with the very basics and up to the more advanced topics. If you read it in a linear way, you should get a sound understanding of the provided classes and the possibilities they offer. But you can also skip sections and jump directly to the topics you are most interested in.

././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/BaseNonStringProperties.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/BaseNonStringPropertie100644 11613 12232154104 33610 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.junit.Test; /** * Test if non-string properties are handled correctly. * * @version $Id: BaseNonStringProperties.java 1302002 2012-03-17 20:43:46Z sebb $ */ public abstract class BaseNonStringProperties { protected NonStringTestHolder nonStringTestHolder = new NonStringTestHolder(); protected Configuration conf; @Test public void testBoolean() throws Exception { nonStringTestHolder.testBoolean(); } @Test public void testBooleanDefaultValue() throws Exception { nonStringTestHolder.testBooleanDefaultValue(); } @Test public void testBooleanArrayValue() throws Exception { boolean booleanValue = conf.getBoolean("test.boolean"); assertTrue(booleanValue); assertEquals(2, conf.getList("test.boolean.array").size()); } @Test public void testByte() throws Exception { nonStringTestHolder.testByte(); } @Test public void testByteArrayValue() throws Exception { byte testValue = 10; byte byteValue = conf.getByte("test.byte"); assertEquals(testValue, byteValue); assertEquals(2, conf.getList("test.byte.array").size()); } @Test public void testDouble() throws Exception { nonStringTestHolder.testDouble(); } @Test public void testDoubleDefaultValue() throws Exception { nonStringTestHolder.testDoubleDefaultValue(); } @Test public void testDoubleArrayValue() throws Exception { double testValue = 10.25; double doubleValue = conf.getDouble("test.double"); assertEquals(testValue, doubleValue, 0.01); assertEquals(2, conf.getList("test.double.array").size()); } @Test public void testFloat() throws Exception { nonStringTestHolder.testFloat(); } @Test public void testFloatDefaultValue() throws Exception { nonStringTestHolder.testFloatDefaultValue(); } @Test public void testFloatArrayValue() throws Exception { float testValue = (float) 20.25; float floatValue = conf.getFloat("test.float"); assertEquals(testValue, floatValue, 0.01); assertEquals(2, conf.getList("test.float.array").size()); } @Test public void testInteger() throws Exception { nonStringTestHolder.testInteger(); } @Test public void testIntegerDefaultValue() throws Exception { nonStringTestHolder.testIntegerDefaultValue(); } @Test public void testIntegerArrayValue() throws Exception { int intValue = conf.getInt("test.integer"); assertEquals(10, intValue); assertEquals(2, conf.getList("test.integer.array").size()); } @Test public void testLong() throws Exception { nonStringTestHolder.testLong(); } @Test public void testLongDefaultValue() throws Exception { nonStringTestHolder.testLongDefaultValue(); } @Test public void testLongArrayValue() throws Exception { long longValue = conf.getLong("test.long"); assertEquals(1000000, longValue); assertEquals(2, conf.getList("test.long.array").size()); } @Test public void testShort() throws Exception { nonStringTestHolder.testShort(); } @Test public void testShortDefaultValue() throws Exception { nonStringTestHolder.testShortDefaultValue(); } @Test public void testShortArrayValue() throws Exception { short shortValue = conf.getShort("test.short"); assertEquals(1, shortValue); assertEquals(2, conf.getList("test.short.array").size()); } @Test public void testListMissing() throws Exception { nonStringTestHolder.testListMissing(); } @Test public void testSubset() throws Exception { nonStringTestHolder.testSubset(); } @Test public void testIsEmpty() throws Exception { nonStringTestHolder.testIsEmpty(); } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBean.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/BeanCreation100644 3174 12232154104 33505 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; /** * A simple bean class used for testing bean creation operations. * * @version $Id: BeanCreationTestBean.java 1534393 2013-10-21 22:02:27Z henning $ */ public class BeanCreationTestBean { private String stringValue; private int intValue; private BeanCreationTestBean buddy; public BeanCreationTestBean getBuddy() { return buddy; } public void setBuddy(BeanCreationTestBean buddy) { this.buddy = buddy; } public int getIntValue() { return intValue; } public void setIntValue(int intValue) { this.intValue = intValue; } public String getStringValue() { return stringValue; } public void setStringValue(String stringValue) { this.stringValue = stringValue; } } ././@LongLink100644 0 0 177 12232154257 10263 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/BeanCreationTestBeanWithListChild.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/BeanCreation100644 3564 12232154104 33510 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import java.util.ArrayList; import java.util.List; /** * A simple bean class used for testing bean creation operations that has * a list of children of a different bean type. * * @version $Id: BeanCreationTestBeanWithListChild.java 1534410 2013-10-21 23:13:34Z henning $ */ public class BeanCreationTestBeanWithListChild { private String stringValue; private int intValue; private List children = new ArrayList(); public List getChildren() { return children; } public void setChildren(List buddies) { this.children.clear(); this.children.addAll(buddies); } public int getIntValue() { return intValue; } public void setIntValue(int intValue) { this.intValue = intValue; } public String getStringValue() { return stringValue; } public void setStringValue(String stringValue) { this.stringValue = stringValue; } } ././@LongLink100644 0 0 154 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestBeanHelper.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestBeanHelp100644 47747 12232154104 33527 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.configuration.ConfigurationRuntimeException; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test class for BeanHelper. * * @since 1.3 * @author Commons * Configuration team * @version $Id: TestBeanHelper.java 1534393 2013-10-21 22:02:27Z henning $ */ public class TestBeanHelper { /** Constant for the test value of the string property. */ private static final String TEST_STRING = "testString"; /** Constant for the test value of the numeric property. */ private static final int TEST_INT = 42; /** Constant for the name of the test bean factory. */ private static final String TEST_FACTORY = "testFactory"; /** * Stores the default bean factory. Because this is a static field in * BeanHelper it is temporarily stored and reset after the tests. */ private BeanFactory tempDefaultBeanFactory; @Before public void setUp() throws Exception { tempDefaultBeanFactory = BeanHelper.getDefaultBeanFactory(); deregisterFactories(); } @After public void tearDown() throws Exception { deregisterFactories(); // Reset old default bean factory BeanHelper.setDefaultBeanFactory(tempDefaultBeanFactory); } /** * Removes all bean factories that might have been registered during a test. */ private void deregisterFactories() { for (String name : BeanHelper.registeredFactoryNames()) { BeanHelper.deregisterBeanFactory(name); } assertTrue("Remaining registered bean factories", BeanHelper .registeredFactoryNames().isEmpty()); } /** * Tests registering a new bean factory. */ @Test public void testRegisterBeanFactory() { assertTrue("List of registered factories is not empty", BeanHelper .registeredFactoryNames().isEmpty()); BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); assertEquals("Wrong number of registered factories", 1, BeanHelper .registeredFactoryNames().size()); assertTrue("Test factory is not contained", BeanHelper .registeredFactoryNames().contains(TEST_FACTORY)); } /** * Tries to register a null factory. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testRegisterBeanFactoryNull() { BeanHelper.registerBeanFactory(TEST_FACTORY, null); } /** * Tries to register a bean factory with a null name. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testRegisterBeanFactoryNullName() { BeanHelper.registerBeanFactory(null, new TestBeanFactory()); } /** * Tests to deregister a bean factory. */ @Test public void testDeregisterBeanFactory() { assertNull("deregistering non existing factory", BeanHelper .deregisterBeanFactory(TEST_FACTORY)); assertNull("deregistering null factory", BeanHelper .deregisterBeanFactory(null)); BeanFactory factory = new TestBeanFactory(); BeanHelper.registerBeanFactory(TEST_FACTORY, factory); assertSame("Could not deregister factory", factory, BeanHelper .deregisterBeanFactory(TEST_FACTORY)); assertTrue("List of factories is not empty", BeanHelper .registeredFactoryNames().isEmpty()); } /** * Tests whether the default bean factory is correctly initialized. */ @Test public void testGetDefaultBeanFactory() { assertSame("Incorrect default bean factory", DefaultBeanFactory.INSTANCE, tempDefaultBeanFactory); } /** * Tests setting the default bean factory to null. This should caus an * exception. */ @Test(expected = IllegalArgumentException.class) public void testSetDefaultBeanFactoryNull() { BeanHelper.setDefaultBeanFactory(null); } /** * Tests initializing a bean. */ @Test public void testInitBean() { BeanHelper.setDefaultBeanFactory(new TestBeanFactory()); TestBeanDeclaration data = setUpBeanDeclaration(); TestBean bean = new TestBean(); BeanHelper.initBean(bean, data); checkBean(bean); } /** * Tests initializing a bean when the bean declaration does not contain any * data. */ @Test public void testInitBeanWithNoData() { TestBeanDeclaration data = new TestBeanDeclaration(); TestBean bean = new TestBean(); BeanHelper.initBean(bean, data); assertNull("Wrong string property", bean.getStringValue()); assertEquals("Wrong int property", 0, bean.getIntValue()); assertNull("Buddy was set", bean.getBuddy()); } /** * Tries to initialize a bean with a bean declaration that contains an * invalid property value. This should cause an exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testInitBeanWithInvalidProperty() { TestBeanDeclaration data = setUpBeanDeclaration(); data.getBeanProperties().put("nonExistingProperty", Boolean.TRUE); BeanHelper.initBean(new TestBean(), data); } /** * Tests creating a bean. All necessary information is stored in the bean * declaration. */ @Test public void testCreateBean() { TestBeanFactory factory = new TestBeanFactory(); BeanHelper.registerBeanFactory(TEST_FACTORY, factory); TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanFactoryName(TEST_FACTORY); data.setBeanClassName(TestBean.class.getName()); checkBean((TestBean) BeanHelper.createBean(data, null)); assertNull("A parameter was passed", factory.parameter); } @Test public void testCreateBeanWithListChildBean() { TestBeanFactory factory = new TestBeanFactory(); BeanHelper.registerBeanFactory(TEST_FACTORY, factory); TestBeanDeclaration data = setUpBeanDeclarationWithListChild(); data.setBeanFactoryName(TEST_FACTORY); data.setBeanClassName(BeanCreationTestBeanWithListChild.class.getName()); checkBean((BeanCreationTestBeanWithListChild) BeanHelper.createBean(data, null)); assertNull("A parameter was passed", factory.parameter); } /** * Tests creating a bean when no bean declaration is provided. This should * cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testCreateBeanWithNullDeclaration() { BeanHelper.createBean(null); } /** * Tests creating a bean. The bean's class is specified as the default class * argument. */ @Test public void testCreateBeanWithDefaultClass() { BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanFactoryName(TEST_FACTORY); checkBean((TestBean) BeanHelper.createBean(data, TestBean.class)); } /** * Tests creating a bean when the bean's class is specified as the default * class of the bean factory. */ @Test public void testCreateBeanWithFactoryDefaultClass() { TestBeanFactory factory = new TestBeanFactory(); factory.supportsDefaultClass = true; BeanHelper.registerBeanFactory(TEST_FACTORY, factory); TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanFactoryName(TEST_FACTORY); checkBean((TestBean) BeanHelper.createBean(data, null)); } /** * Tries to create a bean when no class is provided. This should cause an * exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testCreateBeanWithNoClass() { BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanFactoryName(TEST_FACTORY); BeanHelper.createBean(data, null); } /** * Tries to create a bean with a non existing class. This should cause an * exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testCreateBeanWithInvalidClass() { BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanFactoryName(TEST_FACTORY); data.setBeanClassName("non.existing.ClassName"); BeanHelper.createBean(data, null); } /** * Tests creating a bean using the default bean factory. */ @Test public void testCreateBeanWithDefaultFactory() { BeanHelper.setDefaultBeanFactory(new TestBeanFactory()); TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanClassName(TestBean.class.getName()); checkBean((TestBean) BeanHelper.createBean(data, null)); } /** * Tests creating a bean using a non registered factory. */ @Test(expected = ConfigurationRuntimeException.class) public void testCreateBeanWithUnknownFactory() { TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanFactoryName(TEST_FACTORY); data.setBeanClassName(TestBean.class.getName()); BeanHelper.createBean(data, null); } /** * Tests creating a bean when the factory throws an exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testCreateBeanWithException() { BeanHelper.registerBeanFactory(TEST_FACTORY, new TestBeanFactory()); TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanFactoryName(TEST_FACTORY); data.setBeanClassName(getClass().getName()); BeanHelper.createBean(data, null); } /** * Tests if a parameter is correctly passed to the bean factory. */ @Test public void testCreateBeanWithParameter() { Object param = new Integer(42); TestBeanFactory factory = new TestBeanFactory(); BeanHelper.registerBeanFactory(TEST_FACTORY, factory); TestBeanDeclaration data = setUpBeanDeclaration(); data.setBeanFactoryName(TEST_FACTORY); data.setBeanClassName(TestBean.class.getName()); checkBean((TestBean) BeanHelper.createBean(data, null, param)); assertSame("Wrong parameter", param, factory.parameter); } /** * Returns an initialized bean declaration. * * @return the bean declaration */ private TestBeanDeclaration setUpBeanDeclaration() { TestBeanDeclaration data = new TestBeanDeclaration(); Map properties = new HashMap(); properties.put("stringValue", "testString"); properties.put("intValue", "42"); data.setBeanProperties(properties); TestBeanDeclaration buddyData = new TestBeanDeclaration(); Map properties2 = new HashMap(); properties2.put("stringValue", "Another test string"); properties2.put("intValue", new Integer(100)); buddyData.setBeanProperties(properties2); buddyData.setBeanClassName(TestBean.class.getName()); if (BeanHelper.getDefaultBeanFactory() == null) { buddyData.setBeanFactoryName(TEST_FACTORY); } Map nested = new HashMap(); nested.put("buddy", buddyData); data.setNestedBeanDeclarations(nested); return data; } /** * Same as setUpBeanDeclaration, but returns a nested array of beans * as a single property. Tests multi-value (Collection) * children construction. * * @return The bean declaration with a list child bean proerty */ private TestBeanDeclaration setUpBeanDeclarationWithListChild() { TestBeanDeclaration data = new TestBeanDeclaration(); Map properties = new HashMap(); properties.put("stringValue", TEST_STRING); properties.put("intValue", String.valueOf(TEST_INT)); data.setBeanProperties(properties); List childData = new ArrayList(); childData.add(createChildBean("child1")); childData.add(createChildBean("child2")); Map nested = new HashMap(); nested.put("children", childData); data.setNestedBeanDeclarations(nested); return data; } /** * Create a simple bean declaration that has no children for testing * of nested children bean declarations. * * @param name A name prefix that can be used to disambiguate the children * @return A simple declaration */ private TestBeanDeclaration createChildBean(String name) { TestBeanDeclaration childBean = new TestBeanDeclaration(); Map properties2 = new HashMap(); properties2.put("stringValue", name + " Another test string"); properties2.put("intValue", new Integer(100)); childBean.setBeanProperties(properties2); childBean.setBeanClassName(BeanCreationTestBean.class.getName()); if (BeanHelper.getDefaultBeanFactory() == null) { childBean.setBeanFactoryName(TEST_FACTORY); } return childBean; } /** * Tests if the bean was correctly initialized from the data of the test * bean declaration. * * @param bean the bean to be checked */ private void checkBean(TestBean bean) { assertEquals("Wrong string property", "testString", bean .getStringValue()); assertEquals("Wrong int property", 42, bean.getIntValue()); TestBean buddy = bean.getBuddy(); assertNotNull("Buddy was not set", buddy); assertEquals("Wrong string property in buddy", "Another test string", buddy.getStringValue()); assertEquals("Wrong int property in buddy", 100, buddy.getIntValue()); } /** * A simple bean class used for testing creation operations. */ public static class TestBean { private String stringValue; private int intValue; private TestBean buddy; public TestBean getBuddy() { return buddy; } public void setBuddy(TestBean buddy) { this.buddy = buddy; } public int getIntValue() { return intValue; } public void setIntValue(int intValue) { this.intValue = intValue; } public String getStringValue() { return stringValue; } public void setStringValue(String stringValue) { this.stringValue = stringValue; } } /** * Tests if the bean was correctly initialized from the data of the test * bean declaration. * * @param bean the bean to be checked */ private void checkBean(BeanCreationTestBeanWithListChild bean) { assertEquals("Wrong string property", TEST_STRING, bean .getStringValue()); assertEquals("Wrong int property", TEST_INT, bean.getIntValue()); List children = bean.getChildren(); assertNotNull("Children were not set", children); assertEquals("Wrong number of children created", children.size(), 2); assertNotNull("First child was set as null", children.get(0)); assertNotNull("Second child was set as null", children.get(1)); } /** * An implementation of the BeanFactory interface used for testing. This * implementation is really simple: If the TestBean class is provided, a new * instance will be created. Otherwise an exception is thrown. */ static class TestBeanFactory implements BeanFactory { Object parameter; boolean supportsDefaultClass; public Object createBean(Class beanClass, BeanDeclaration data, Object param) throws Exception { parameter = param; if (TestBean.class.equals(beanClass)) { TestBean bean = new TestBean(); BeanHelper.initBean(bean, data); return bean; } else if (BeanCreationTestBeanWithListChild.class.equals(beanClass)) { BeanCreationTestBeanWithListChild bean = new BeanCreationTestBeanWithListChild(); BeanHelper.initBean(bean, data); return bean; } else { throw new IllegalArgumentException("Unsupported class: " + beanClass); } } /** * Returns the default class, but only if the supportsDefaultClass flag * is set. */ public Class getDefaultBeanClass() { return supportsDefaultClass ? TestBean.class : null; } } /** * A test implementation of the BeanDeclaration interface. This * implementation allows to set the values directly, which should be * returned by the methods required by the BeanDeclaration interface. */ static class TestBeanDeclaration implements BeanDeclaration { private String beanClassName; private String beanFactoryName; private Object beanFactoryParameter; private Map beanProperties; private Map nestedBeanDeclarations; public String getBeanClassName() { return beanClassName; } public void setBeanClassName(String beanClassName) { this.beanClassName = beanClassName; } public String getBeanFactoryName() { return beanFactoryName; } public void setBeanFactoryName(String beanFactoryName) { this.beanFactoryName = beanFactoryName; } public Object getBeanFactoryParameter() { return beanFactoryParameter; } public void setBeanFactoryParameter(Object beanFactoryParameter) { this.beanFactoryParameter = beanFactoryParameter; } public Map getBeanProperties() { return beanProperties; } public void setBeanProperties(Map beanProperties) { this.beanProperties = beanProperties; } public Map getNestedBeanDeclarations() { return nestedBeanDeclarations; } public void setNestedBeanDeclarations(Map nestedBeanDeclarations) { this.nestedBeanDeclarations = nestedBeanDeclarations; } } } ././@LongLink100644 0 0 167 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestConfigurationDynaBean.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestConfigur100644 56726 12232154104 33622 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.Arrays; import java.util.HashMap; import java.util.List; import junitx.framework.ObjectAssert; import org.apache.commons.beanutils.DynaProperty; import org.apache.commons.configuration.BaseConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.MapConfiguration; import org.junit.Before; import org.junit.Test; /** *

Test Case for the ConfigurationDynaBean implementation class. * These tests were based on the ones in BasicDynaBeanTestCase * because the two classes provide similar levels of functionality.

* * @author Ricardo Gladwell * @version $Id: TestConfigurationDynaBean.java 1225349 2011-12-28 21:36:59Z oheger $ */ public class TestConfigurationDynaBean { /** * The basic test bean for each test. */ private ConfigurationDynaBean bean; /** * The set of property names we expect to have returned when calling * getDynaProperties(). You should update this list * when new properties are added to TestBean. */ String[] properties = { "booleanProperty", "booleanSecond", "doubleProperty", "floatProperty", "intProperty", "longProperty", "mappedProperty.key1", "mappedProperty.key2", "mappedProperty.key3", "mappedIntProperty.key1", "shortProperty", "stringProperty", "byteProperty", "charProperty" }; Object[] values = { Boolean.TRUE, Boolean.TRUE, new Double(Double.MAX_VALUE), new Float(Float.MAX_VALUE), new Integer(Integer.MAX_VALUE), new Long(Long.MAX_VALUE), "First Value", "Second Value", "Third Value", new Integer(Integer.MAX_VALUE), new Short(Short.MAX_VALUE), "This is a string", new Byte(Byte.MAX_VALUE), new Character(Character.MAX_VALUE) }; int[] intArray = {0, 10, 20, 30, 40}; boolean[] booleanArray = {true, false, true, false, true}; char[] charArray = {'a', 'b', 'c', 'd', 'e'}; byte[] byteArray = {0, 10, 20, 30, 40}; long[] longArray = {0, 10, 20, 30, 40}; short[] shortArray = {0, 10, 20, 30, 40}; float[] floatArray = {0, 10, 20, 30, 40}; double[] doubleArray = {0.0, 10.0, 20.0, 30.0, 40.0}; String[] stringArray = {"String 0", "String 1", "String 2", "String 3", "String 4"}; /** * Set up instance variables required by this test case. */ @Before public void setUp() throws Exception { Configuration configuration = createConfiguration(); for (int i = 0; i < properties.length; i++) { configuration.setProperty(properties[i], values[i]); } for (int a = 0; a < intArray.length; a++) { configuration.addProperty("intIndexed", new Integer(intArray[a])); } for (int a = 0; a < stringArray.length; a++) { configuration.addProperty("stringIndexed", stringArray[a]); } List list = Arrays.asList(stringArray); configuration.addProperty("listIndexed", list); bean = new ConfigurationDynaBean(configuration); bean.set("listIndexed", list); bean.set("intArray", intArray); bean.set("booleanArray", booleanArray); bean.set("charArray", charArray); bean.set("longArray", longArray); bean.set("shortArray", shortArray); bean.set("floatArray", floatArray); bean.set("doubleArray", doubleArray); bean.set("byteArray", byteArray); bean.set("stringArray", stringArray); } /** * Creates the underlying configuration object for the dyna bean. * @return the underlying configuration object */ protected Configuration createConfiguration() { return new BaseConfiguration(); } /** * Corner cases on getDynaProperty invalid arguments. */ @Test(expected = IllegalArgumentException.class) public void testGetDescriptorArguments() { DynaProperty descriptor = bean.getDynaClass().getDynaProperty("unknown"); assertNull("Unknown property descriptor should be null", descriptor); bean.getDynaClass().getDynaProperty(null); } /** * Positive getDynaProperty on property booleanProperty. */ @Test public void testGetDescriptorBoolean() { testGetDescriptorBase("booleanProperty", Boolean.TYPE); } /** * Positive getDynaProperty on property doubleProperty. */ @Test public void testGetDescriptorDouble() { testGetDescriptorBase("doubleProperty", Double.TYPE); } /** * Positive getDynaProperty on property floatProperty. */ @Test public void testGetDescriptorFloat() { testGetDescriptorBase("floatProperty", Float.TYPE); } /** * Positive getDynaProperty on property intProperty. */ @Test public void testGetDescriptorInt() { testGetDescriptorBase("intProperty", Integer.TYPE); } /** * Positive getDynaProperty on property longProperty. */ @Test public void testGetDescriptorLong() { testGetDescriptorBase("longProperty", Long.TYPE); } /** * Positive getDynaProperty on property booleanSecond * that uses an "is" method as the getter. */ @Test public void testGetDescriptorSecond() { testGetDescriptorBase("booleanSecond", Boolean.TYPE); } /** * Positive getDynaProperty on property shortProperty. */ @Test public void testGetDescriptorShort() { testGetDescriptorBase("shortProperty", Short.TYPE); } /** * Positive getDynaProperty on property stringProperty. */ @Test public void testGetDescriptorString() { testGetDescriptorBase("stringProperty", String.class); } /** * Positive test for getDynaPropertys(). Each property name * listed in properties should be returned exactly once. */ @Test public void testGetDescriptors() { DynaProperty pd[] = bean.getDynaClass().getDynaProperties(); assertNotNull("Got descriptors", pd); int count[] = new int[properties.length]; for (int i = 0; i < pd.length; i++) { String name = pd[i].getName(); for (int j = 0; j < properties.length; j++) { if (name.equals(properties[j])) { count[j]++; } } } for (int j = 0; j < properties.length; j++) { if (count[j] < 0) { fail("Missing property " + properties[j]); } else if (count[j] > 1) { fail("Duplicate property " + properties[j]); } } } /** * Corner cases on getIndexedProperty invalid arguments. */ @Test(expected = IndexOutOfBoundsException.class) public void testGetIndexedArguments() { bean.get("intArray", -1); } /** * Positive and negative tests on getIndexedProperty valid arguments. */ @Test public void testGetIndexedValues() { for (int i = 0; i < 5; i++) { Object value = bean.get("intArray", i); assertNotNull("intArray index " + i + " did not return value.", value); ObjectAssert.assertInstanceOf("intArray index " + i, Integer.class, value); assertEquals("intArray " + i + " returned incorrect value.", i * 10, ((Integer) value).intValue()); value = bean.get("intIndexed", i); assertNotNull("intIndexed index " + i + "returned value " + i, value); ObjectAssert.assertInstanceOf("intIndexed index " + i, Integer.class, value); assertEquals("intIndexed index " + i + "returned correct " + i, i * 10, ((Integer) value).intValue()); value = bean.get("listIndexed", i); assertNotNull("listIndexed index " + i + "returned value " + i, value); ObjectAssert.assertInstanceOf("list index " + i, String.class, value); assertEquals("listIndexed index " + i + "returned correct " + i, "String " + i, value); value = bean.get("stringArray", i); assertNotNull("stringArray index " + i + " returnde null.", value); assertFalse("stringArray index " + i + " returned array instead of String.", value.getClass().isArray()); ObjectAssert.assertInstanceOf("stringArray index " + i, String.class, value); assertEquals("stringArray returned correct " + i, "String " + i, value); value = bean.get("stringIndexed", i); assertNotNull("stringIndexed returned value " + i, value); ObjectAssert.assertInstanceOf("stringIndexed", String.class, value); assertEquals("stringIndexed returned correct " + i, "String " + i, value); } } /** * Corner cases on getMappedProperty invalid arguments. */ @Test public void testGetMappedArguments() { try { Object value = bean.get("mappedProperty", "unknown"); assertNull("Should not return a value", value); } catch (Throwable t) { fail("Threw " + t + " instead of returning null"); } } /** * Positive and negative tests on getMappedProperty valid arguments. */ @Test public void testGetMappedValues() { Object value = bean.get("mappedProperty", "key1"); assertEquals("Can find first value", "First Value", value); value = bean.get("mappedProperty", "key2"); assertEquals("Can find second value", "Second Value", value); value = bean.get("mappedProperty", "key3"); assertNotNull("Cannot find third value", value); } /** * Corner cases on getSimpleProperty invalid arguments. */ @Test(expected = IllegalArgumentException.class) public void testGetSimpleArguments() { bean.get("a non existing property"); } /** * Test getSimpleProperty on a boolean property. */ @Test public void testGetSimpleBoolean() { Object value = bean.get("booleanProperty"); assertNotNull("Got a value", value); ObjectAssert.assertInstanceOf("Got correct type", Boolean.class, value); assertTrue("Got correct value", ((Boolean) value).booleanValue()); } /** * Test getSimpleProperty on a double property. */ @Test public void testGetSimpleDouble() { Object value = bean.get("doubleProperty"); assertNotNull("Got a value", value); ObjectAssert.assertInstanceOf("Got correct type", Double.class, value); assertEquals("Got correct value", ((Double) value).doubleValue(), Double.MAX_VALUE, 0.005); } /** * Test getSimpleProperty on a float property. */ @Test public void testGetSimpleFloat() { Object value = bean.get("floatProperty"); assertNotNull("Got a value", value); ObjectAssert.assertInstanceOf("Got correct type", Float.class, value); assertEquals("Got correct value", ((Float) value).floatValue(), Float.MAX_VALUE, 0.005f); } /** * Test getSimpleProperty on a int property. */ @Test public void testGetSimpleInt() { Object value = bean.get("intProperty"); assertNotNull("Failed to get value", value); ObjectAssert.assertInstanceOf("Incorrect type", Integer.class, value); assertEquals("Incorrect value", ((Integer) value).intValue(), Integer.MAX_VALUE); } /** * Test getSimpleProperty on a long property. */ @Test public void testGetSimpleLong() { Object value = bean.get("longProperty"); assertNotNull("Got a value", value); ObjectAssert.assertInstanceOf("Returned incorrect type", Long.class, value); assertEquals("Returned value of Incorrect value", ((Long) value).longValue(), Long.MAX_VALUE); } /** * Test getSimpleProperty on a short property. */ @Test public void testGetSimpleShort() { Object value = bean.get("shortProperty"); assertNotNull("Got a value", value); ObjectAssert.assertInstanceOf("Got correct type", Short.class, value); assertEquals("Got correct value", ((Short) value).shortValue(), Short.MAX_VALUE); } /** * Test getSimpleProperty on a String property. */ @Test public void testGetSimpleString() { Object value = bean.get("stringProperty"); assertNotNull("Got a value", value); ObjectAssert.assertInstanceOf("Got correct type", String.class, value); assertEquals("Got correct value", value, "This is a string"); } /** * Test contains() method for mapped properties. */ @Test public void testMappedContains() { assertTrue("Can't see first key", bean.contains("mappedProperty", "key1")); assertTrue("Can see unknown key", !bean.contains("mappedProperty", "Unknown Key")); } /** * Test remove() method for mapped properties. */ @Test public void testMappedRemove() { assertTrue("Can see first key", bean.contains("mappedProperty", "key1")); bean.remove("mappedProperty", "key1"); assertTrue("Can not see first key", !bean.contains("mappedProperty", "key1")); assertTrue("Can not see unknown key", !bean.contains("mappedProperty", "key4")); bean.remove("mappedProperty", "key4"); assertTrue("Can not see unknown key", !bean.contains("mappedProperty", "key4")); } /** * Corner cases on setIndexedProperty invalid arguments. */ @Test(expected = IndexOutOfBoundsException.class) public void testSetIndexedArguments() { bean.set("intArray", -1, new Integer(0)); } /** * Positive and negative tests on setIndexedProperty valid arguments. */ @Test public void testSetIndexedValues() { bean.set("intArray", 0, new Integer(1)); Object value = bean.get("intArray", 0); assertNotNull("Returned new value 0", value); ObjectAssert.assertInstanceOf("Returned Integer new value 0", Integer.class, value); assertEquals("Returned correct new value 0", 1, ((Integer) value).intValue()); bean.set("intIndexed", 1, new Integer(11)); value = bean.get("intIndexed", 1); assertNotNull("Returned new value 1", value); ObjectAssert.assertInstanceOf("Returned Integer new value 1", Integer.class, value); assertEquals("Returned correct new value 1", 11, ((Integer) value).intValue()); bean.set("listIndexed", 2, "New Value 2"); value = bean.get("listIndexed", 2); assertNotNull("Returned new value 2", value); ObjectAssert.assertInstanceOf("Returned String new value 2", String.class, value); assertEquals("Returned correct new value 2", "New Value 2", value); bean.set("stringArray", 3, "New Value 3"); value = bean.get("stringArray", 3); assertNotNull("Returned new value 3", value); ObjectAssert.assertInstanceOf("Returned String new value 3", String.class, value); assertEquals("Returned correct new value 3", "New Value 3", value); bean.set("stringIndexed", 4, "New Value 4"); value = bean.get("stringIndexed", 4); assertNotNull("Returned new value 4", value); ObjectAssert.assertInstanceOf("Returned String new value 4", String.class, value); assertEquals("Returned correct new value 4", "New Value 4", value); } /** * Test the modification of a configuration property stored internally as an array. */ @Test public void testSetArrayValue() { MapConfiguration configuration = new MapConfiguration(new HashMap()); configuration.getMap().put("objectArray", new Object[] {"value1", "value2", "value3"}); ConfigurationDynaBean bean = new ConfigurationDynaBean(configuration); bean.set("objectArray", 1, "New Value 1"); Object value = bean.get("objectArray", 1); assertNotNull("Returned new value 1", value); ObjectAssert.assertInstanceOf("Returned String new value 1", String.class, value); assertEquals("Returned correct new value 1", "New Value 1", value); } /** * Positive and negative tests on setMappedProperty valid arguments. */ @Test public void testSetMappedValues() { bean.set("mappedProperty", "First Key", "New First Value"); assertEquals("Can replace old value", "New First Value", bean.get("mappedProperty", "First Key")); bean.set("mappedProperty", "Fourth Key", "Fourth Value"); assertEquals("Can set new value", "Fourth Value", bean.get("mappedProperty", "Fourth Key")); } /** * Test setSimpleProperty on a boolean property. */ @Test public void testSetSimpleBoolean() { boolean oldValue = ((Boolean) bean.get("booleanProperty")).booleanValue(); boolean newValue = !oldValue; bean.set("booleanProperty", new Boolean(newValue)); assertTrue("Matched new value", newValue == ((Boolean) bean.get("booleanProperty")).booleanValue()); } /** * Test setSimpleProperty on a double property. */ @Test public void testSetSimpleDouble() { double oldValue = ((Double) bean.get("doubleProperty")).doubleValue(); double newValue = oldValue + 1.0; bean.set("doubleProperty", new Double(newValue)); assertEquals("Matched new value", newValue, ((Double) bean.get("doubleProperty")).doubleValue(), 0.005); } /** * Test setSimpleProperty on a float property. */ @Test public void testSetSimpleFloat() { float oldValue = ((Float) bean.get("floatProperty")).floatValue(); float newValue = oldValue + (float) 1.0; bean.set("floatProperty", new Float(newValue)); assertEquals("Matched new value", newValue, ((Float) bean.get("floatProperty")).floatValue(), 0.005f); } /** * Test setSimpleProperty on a int property. */ @Test public void testSetSimpleInt() { int oldValue = ((Integer) bean.get("intProperty")).intValue(); int newValue = oldValue + 1; bean.set("intProperty", new Integer(newValue)); assertEquals("Matched new value", newValue, ((Integer) bean.get("intProperty")).intValue()); } /** * Test setSimpleProperty on a long property. */ @Test public void testSetSimpleLong() { long oldValue = ((Long) bean.get("longProperty")).longValue(); long newValue = oldValue + 1; bean.set("longProperty", new Long(newValue)); assertEquals("Matched new value", newValue, ((Long) bean.get("longProperty")).longValue()); } /** * Test setSimpleProperty on a short property. */ @Test public void testSetSimpleShort() { short oldValue = ((Short) bean.get("shortProperty")).shortValue(); short newValue = (short) (oldValue + 1); bean.set("shortProperty", new Short(newValue)); assertEquals("Matched new value", newValue, ((Short) bean.get("shortProperty")).shortValue()); } /** * Test setSimpleProperty on a String property. */ @Test public void testSetSimpleString() { String oldValue = (String) bean.get("stringProperty"); String newValue = oldValue + " Extra Value"; bean.set("stringProperty", newValue); assertEquals("Matched new value", newValue, bean.get("stringProperty")); } /** * Tests set on a null value: should throw NPE. */ @Test(expected = NullPointerException.class) public void testAddNullPropertyValue() { bean.set("nullProperty", null); } /** * Test the retrieval of a non-existent property. */ @Test(expected = IllegalArgumentException.class) public void testGetNonExistentProperty() { bean.get("nonexistProperty"); } /** * Base for testGetDescriptorXxxxx() series of tests. * * @param name Name of the property to be retrieved * @param type Expected class type of this property */ protected void testGetDescriptorBase(String name, Class type) { DynaProperty descriptor = bean.getDynaClass().getDynaProperty(name); assertNotNull("Failed to get descriptor", descriptor); assertEquals("Got incorrect type", type, descriptor.getType()); } /** * Tests whether nested properties can be accessed. */ @Test public void testNestedPropeties() { ConfigurationDynaBean nested = (ConfigurationDynaBean) bean.get("mappedProperty"); String value = (String) nested.get("key1"); assertEquals("Can find first value", "First Value", value); nested.set("key1", "undefined"); assertEquals("Incorrect value returned", "undefined", bean.get("mappedProperty.key1")); } /** * Tests if reading a non-indexed property using the index * get method throws an IllegalArgumentException as it * should. */ @Test(expected = IllegalArgumentException.class) public void testGetNonIndexedProperties() { bean.get("booleanProperty", 0); } /** * Tests whether accessing a non-indexed string property using the index get * method causes an exception. */ @Test(expected = IllegalArgumentException.class) public void testGetIndexedString() { bean.set("stringProp", "value"); bean.get("stringProp", 0); } /** * Tests whether an indexed access to a non-existing property causes an * exception. */ @Test(expected = IllegalArgumentException.class) public void testGetIndexedNonExisting() { bean.get("Non existing property", 0); } /** * Tests if writing a non-indexed property using the index * set method with an index > 0 throws an IllegalArgumentException as it * should. */ @Test(expected = IllegalArgumentException.class) public void testSetNonIndexedProperties() { bean.set("booleanProperty", 1, Boolean.TRUE); } } ././@LongLink100644 0 0 200 12232154257 10246 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestConfigurationDynaBeanXMLConfig.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestConfigur100644 3337 12232154104 33570 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.XMLConfiguration; /** * An additional test class for ConfigurationDynaBean. This test class performs * the same tests as the default test class, but uses a XMLConfiguration as * underlying configuration object. * * @author Commons * Configuration team * @version $Id: TestConfigurationDynaBeanXMLConfig.java 1301994 2012-03-17 20:21:23Z sebb $ */ public class TestConfigurationDynaBeanXMLConfig extends TestConfigurationDynaBean { /** * Creates the underlying configuration object. This implementation will * create a XMLConfiguration. * @return the underlying configuration */ @Override protected Configuration createConfiguration() { return new XMLConfiguration(); } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestDefaultBeanFactory.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestDefaultB100644 6272 12232154104 33503 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.HashMap; import java.util.Map; import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Before; import org.junit.Test; /** * Test class for DefaultBeanFactory. * * @since 1.3 * @author Commons * Configuration team * @version $Id: TestDefaultBeanFactory.java 1225642 2011-12-29 20:31:38Z oheger $ */ public class TestDefaultBeanFactory { /** The object to be tested. */ DefaultBeanFactory factory; @Before public void setUp() throws Exception { factory = new DefaultBeanFactory(); } /** * Tests obtaining the default class. This should be null. */ @Test public void testGetDefaultBeanClass() { assertNull("Default class is not null", factory.getDefaultBeanClass()); } /** * Tests creating a bean. */ @Test public void testCreateBean() throws Exception { Object bean = factory.createBean(PropertiesConfiguration.class, new TestBeanDeclaration(), null); assertNotNull("New bean is null", bean); assertEquals("Bean is of wrong class", PropertiesConfiguration.class, bean.getClass()); PropertiesConfiguration config = (PropertiesConfiguration) bean; assertTrue("Bean was not initialized", config .isThrowExceptionOnMissing()); } /** * A simple implementation of BeanDeclaration used for testing purposes. */ static class TestBeanDeclaration implements BeanDeclaration { public String getBeanFactoryName() { return null; } public Object getBeanFactoryParameter() { return null; } public String getBeanClassName() { return null; } public Map getBeanProperties() { Map props = new HashMap(); props.put("throwExceptionOnMissing", Boolean.TRUE); return props; } public Map getNestedBeanDeclarations() { return null; } } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestXMLBeanDeclaration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/TestXMLBeanD100644 35351 12232154104 33367 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.beanutils; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Map; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.SubnodeConfiguration; import org.apache.commons.configuration.tree.ConfigurationNode; import org.junit.Test; /** * Test class for XMLBeanDeclaration. * * @since 1.3 * @author Commons * Configuration team * @version $Id: TestXMLBeanDeclaration.java 1225643 2011-12-29 20:37:36Z oheger $ */ public class TestXMLBeanDeclaration { /** An array with some test properties. */ static final String[] TEST_PROPS = { "firstName", "lastName", "department", "age", "hobby"}; /** An array with the values for the test properties. */ static final String[] TEST_VALUES = { "John", "Smith", "Engineering", "42", "TV"}; /** An array with the names of nested (complex) properties. */ static final String[] COMPLEX_PROPS = { "address", "car"}; /** An array with the names of the classes of the complex properties. */ static final String[] COMPLEX_CLASSES = { "org.apache.commons.configuration.test.AddressTest", "org.apache.commons.configuration.test.CarTest"}; /** An array with the property names of the complex properties. */ static final String[][] COMPLEX_ATTRIBUTES = { { "street", "zip", "city", "country"}, { "brand", "color"}}; /** An array with the values of the complex properties. */ static final String[][] COMPLEX_VALUES = { { "Baker Street", "12354", "London", "UK"}, { "Bentley", "silver"}}; /** Constant for the key with the bean declaration. */ static final String KEY = "myBean"; /** Constant for the section with the variables.*/ static final String VARS = "variables."; /** Stores the object to be tested. */ XMLBeanDeclaration decl; /** * Tests creating a declaration from a null node. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testInitFromNullNode() { decl = new XMLBeanDeclaration(new HierarchicalConfiguration().configurationAt(null), (ConfigurationNode) null); } /** * Tests creating a declaration from a null configuration. This should cause * an exception. */ @Test(expected = IllegalArgumentException.class) public void testInitFromNullConfiguration() { decl = new XMLBeanDeclaration((HierarchicalConfiguration) null); } /** * Tests creating a declaration from a null configuration with a key. This * should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testInitFromNullConfigurationAndKey() { decl = new XMLBeanDeclaration(null, KEY); } /** * Tests creating a declaration from a null configuration with a node. This * should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testInitFromNullConfigurationAndNode() { decl = new XMLBeanDeclaration(null, new HierarchicalConfiguration() .getRoot()); } /** * Tests fetching the bean's class name. */ @Test public void testGetBeanClassName() { HierarchicalConfiguration config = new HierarchicalConfiguration(); config.addProperty(KEY + "[@config-class]", getClass().getName()); decl = new XMLBeanDeclaration(config, KEY); assertEquals("Wrong class name", getClass().getName(), decl .getBeanClassName()); } /** * Tests fetching the bean's class name if it is undefined. */ @Test public void testGetBeanClassNameUndefined() { decl = new XMLBeanDeclaration(new HierarchicalConfiguration()); assertNull(decl.getBeanClassName()); } /** * Tests fetching the name of the bean factory. */ @Test public void testGetBeanFactoryName() { HierarchicalConfiguration config = new HierarchicalConfiguration(); config.addProperty(KEY + "[@config-factory]", "myFactory"); decl = new XMLBeanDeclaration(config, KEY); assertEquals("Wrong factory name", "myFactory", decl .getBeanFactoryName()); } /** * Tests fetching the name of the bean factory if it is undefined. */ @Test public void testGetBeanFactoryNameUndefined() { decl = new XMLBeanDeclaration(new HierarchicalConfiguration()); assertNull(decl.getBeanFactoryName()); } /** * Tests fetching the parameter for the bean factory. */ @Test public void testGetBeanFactoryParameter() { HierarchicalConfiguration config = new HierarchicalConfiguration(); config .addProperty(KEY + "[@config-factoryParam]", "myFactoryParameter"); decl = new XMLBeanDeclaration(config, KEY); assertEquals("Wrong factory parameter", "myFactoryParameter", decl .getBeanFactoryParameter()); } /** * Tests fetching the parameter for the bean factory if it is undefined. */ @Test public void testGetBeanFactoryParameterUndefined() { decl = new XMLBeanDeclaration(new HierarchicalConfiguration()); assertNull(decl.getBeanFactoryParameter()); } /** * Tests if the bean's properties are correctly extracted from the * configuration object. */ @Test public void testGetBeanProperties() { HierarchicalConfiguration config = new HierarchicalConfiguration(); setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); decl = new XMLBeanDeclaration(config, KEY); checkProperties(decl, TEST_PROPS, TEST_VALUES); } /** * Tests obtaining the bean's properties when reserved attributes are * involved. These should be ignored. */ @Test public void testGetBeanPropertiesWithReservedAttributes() { HierarchicalConfiguration config = new HierarchicalConfiguration(); setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); config.addProperty(KEY + "[@config-testattr]", "yes"); config.addProperty(KEY + "[@config-anothertest]", "this, too"); decl = new XMLBeanDeclaration(config, KEY); checkProperties(decl, TEST_PROPS, TEST_VALUES); } /** * Tests fetching properties if none are defined. */ @Test public void testGetBeanPropertiesEmpty() { decl = new XMLBeanDeclaration(new HierarchicalConfiguration()); Map props = decl.getBeanProperties(); assertTrue("Properties found", props == null || props.isEmpty()); } /** * Creates a configuration with data for testing nested bean declarations. * @return the initialized test configuration */ private HierarchicalConfiguration prepareNestedBeanDeclarations() { HierarchicalConfiguration config = new HierarchicalConfiguration(); setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); for (int i = 0; i < COMPLEX_PROPS.length; i++) { setupBeanDeclaration(config, KEY + '.' + COMPLEX_PROPS[i], COMPLEX_ATTRIBUTES[i], COMPLEX_VALUES[i]); config.addProperty( KEY + '.' + COMPLEX_PROPS[i] + "[@config-class]", COMPLEX_CLASSES[i]); } return config; } /** * Tests fetching nested bean declarations. */ @Test public void testGetNestedBeanDeclarations() { HierarchicalConfiguration config = prepareNestedBeanDeclarations(); decl = new XMLBeanDeclaration(config, KEY); checkProperties(decl, TEST_PROPS, TEST_VALUES); Map nested = decl.getNestedBeanDeclarations(); assertEquals("Wrong number of nested declarations", COMPLEX_PROPS.length, nested.size()); for (int i = 0; i < COMPLEX_PROPS.length; i++) { XMLBeanDeclaration d = (XMLBeanDeclaration) nested .get(COMPLEX_PROPS[i]); assertNotNull("No declaration found for " + COMPLEX_PROPS[i], d); checkProperties(d, COMPLEX_ATTRIBUTES[i], COMPLEX_VALUES[i]); assertEquals("Wrong bean class", COMPLEX_CLASSES[i], d .getBeanClassName()); } } /** * Tests whether the factory method for creating nested bean declarations * gets called. */ @Test public void testGetNestedBeanDeclarationsFactoryMethod() { HierarchicalConfiguration config = prepareNestedBeanDeclarations(); decl = new XMLBeanDeclaration(config, KEY) { @Override protected BeanDeclaration createBeanDeclaration( ConfigurationNode node) { return new XMLBeanDeclarationTestImpl(getConfiguration() .configurationAt(node.getName()), node); } }; Map nested = decl.getNestedBeanDeclarations(); for (int i = 0; i < COMPLEX_PROPS.length; i++) { Object d = nested.get(COMPLEX_PROPS[i]); assertTrue("Wrong class for bean declaration: " + d, d instanceof XMLBeanDeclarationTestImpl); } } /** * Tests fetching nested bean declarations if none are defined. */ @Test public void testGetNestedBeanDeclarationsEmpty() { HierarchicalConfiguration config = new HierarchicalConfiguration(); setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); decl = new XMLBeanDeclaration(config, KEY); Map nested = decl.getNestedBeanDeclarations(); assertTrue("Found nested declarations", nested == null || nested.isEmpty()); } /** * Tests whether interpolation of bean properties works. */ @Test public void testGetInterpolatedBeanProperties() { HierarchicalConfiguration config = new HierarchicalConfiguration(); String[] varValues = new String[TEST_PROPS.length]; for(int i = 0; i < TEST_PROPS.length; i++) { varValues[i] = "${" + VARS + TEST_PROPS[i] + "}"; config.addProperty(VARS + TEST_PROPS[i], TEST_VALUES[i]); } setupBeanDeclaration(config, KEY, TEST_PROPS, varValues); decl = new XMLBeanDeclaration(config, KEY); checkProperties(decl, TEST_PROPS, TEST_VALUES); } /** * Tests constructing a bean declaration from an undefined key. This should * cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testInitFromUndefinedKey() { HierarchicalConfiguration config = new HierarchicalConfiguration(); setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); decl = new XMLBeanDeclaration(config, "undefined_key"); } /** * Tests constructing a bean declaration from a key, which is undefined when * the optional flag is set. In this case an empty declaration should be * created, which can be used for creating beans as long as a default class * is provided. */ @Test public void testInitFromUndefinedKeyOptional() { HierarchicalConfiguration config = new HierarchicalConfiguration(); setupBeanDeclaration(config, KEY, TEST_PROPS, TEST_VALUES); decl = new XMLBeanDeclaration(config, "undefined_key", true); assertNull("Found a bean class", decl.getBeanClassName()); } /** * Tests constructing a bean declaration from a key with multiple values. * This should cause an exception because keys must be unique. */ @Test(expected = IllegalArgumentException.class) public void testInitFromMultiValueKey() { HierarchicalConfiguration config = new HierarchicalConfiguration(); config.addProperty(KEY, "myFirstKey"); config.addProperty(KEY, "mySecondKey"); decl = new XMLBeanDeclaration(config, KEY); } /** * Initializes a configuration object with a bean declaration. Under the * specified key the given properties will be added. * * @param config the configuration to initialize * @param key the key of the bean declaration * @param names an array with the names of the properties * @param values an array with the corresponding values */ private void setupBeanDeclaration(HierarchicalConfiguration config, String key, String[] names, String[] values) { for (int i = 0; i < names.length; i++) { config.addProperty(key + "[@" + names[i] + "]", values[i]); } } /** * Checks the properties returned by a bean declaration. * * @param beanDecl the bean declaration * @param names an array with the expected property names * @param values an array with the expected property values */ private void checkProperties(BeanDeclaration beanDecl, String[] names, String[] values) { Map props = beanDecl.getBeanProperties(); assertEquals("Wrong number of properties", names.length, props.size()); for (int i = 0; i < names.length; i++) { assertTrue("Property " + names[i] + " not contained", props .containsKey(names[i])); assertEquals("Wrong value for property " + names[i], values[i], props.get(names[i])); } } /** * A helper class used for testing the createBeanDeclaration() factory * method. */ private static class XMLBeanDeclarationTestImpl extends XMLBeanDeclaration { public XMLBeanDeclarationTestImpl(SubnodeConfiguration config, ConfigurationNode node) { super(config, node); } } } ././@LongLink100644 0 0 147 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/ConfigurationAssert.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/ConfigurationAssert.ja100644 10707 12232154104 33567 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.Iterator; import junit.framework.Assert; /** * Assertions on configurations for the unit tests. This class also provides * access to test files. * * @author Emmanuel Bourg * @version $Id: ConfigurationAssert.java 1221893 2011-12-21 21:34:38Z oheger $ */ public class ConfigurationAssert { /** Constant for the name of the directory with the test files. */ public static final String TEST_DIR_NAME = "target/test-classes"; /** Constant for the name of the directory with the output files. */ public static final String OUT_DIR_NAME = "target"; /** The directory with the test files. */ public static final File TEST_DIR = new File(TEST_DIR_NAME); /** The directory with the output files. */ public static final File OUT_DIR = new File(OUT_DIR_NAME); /** * Checks the content of a configuration. * * @param expected the expected properties * @param actual the configuration to check */ public static void assertEquals(Configuration expected, Configuration actual) { // check that the actual configuration contains all the properties of the expected configuration for (Iterator it = expected.getKeys(); it.hasNext();) { String key = it.next(); Assert.assertTrue("The actual configuration doesn't contain the expected key '" + key + "'", actual.containsKey(key)); Assert.assertEquals("Value of the '" + key + "' property", expected.getProperty(key), actual.getProperty(key)); } // check that the actual configuration has no extra properties for (Iterator it = actual.getKeys(); it.hasNext();) { String key = it.next(); Assert.assertTrue("The actual configuration contains an extra key '" + key + "'", expected.containsKey(key)); } } /** * Returns a {@code File} object for the specified test file. * * @param name the name of the test file * @return a {@code File} object pointing to that test file */ public static File getTestFile(String name) { return new File(TEST_DIR, name); } /** * Returns a {@code File} object for the specified out file. * * @param name the name of the out file * @return a {@code File} object pointing to that out file */ public static File getOutFile(String name) { return new File(OUT_DIR, name); } /** * Returns a URL pointing to the specified test file. If the URL cannot be * constructed, a runtime exception is thrown. * * @param name the name of the test file * @return the corresponding URL */ public static URL getTestURL(String name) { return urlFromFile(getTestFile(name)); } /** * Returns a URL pointing to the specified output file. If the URL cannot be * constructed, a runtime exception is thrown. * * @param name the name of the output file * @return the corresponding URL */ public static URL getOutURL(String name) { return urlFromFile(getOutFile(name)); } /** * Helper method for converting a file to a URL. * * @param file the file * @return the corresponding URL * @throws ConfigurationRuntimeException if the URL cannot be constructed */ private static URL urlFromFile(File file) { try { return file.toURI().toURL(); } catch (MalformedURLException mex) { throw new ConfigurationRuntimeException(mex); } } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/ConfigurationErrorListenerImpl.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/ConfigurationErrorList100644 6721 12232154104 33643 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import org.apache.commons.configuration.event.ConfigurationErrorEvent; import org.apache.commons.configuration.event.ConfigurationErrorListener; /** * An implementation of the {@code ConfigurationErrorListener} interface * that can be used in unit tests. This implementation just records received * events and allows to test whether expected errors occurred. * * @author Commons * Configuration team * @version $Id: ConfigurationErrorListenerImpl.java 1222446 2011-12-22 20:57:32Z oheger $ */ public class ConfigurationErrorListenerImpl implements ConfigurationErrorListener { /** Stores the last received error event. */ private ConfigurationErrorEvent event; /** Stores the number of calls to configurationError(). */ private int errorCount; /** * An error event is received. Updates the internal counter and stores the * event. * * @param event the error event */ public void configurationError(ConfigurationErrorEvent event) { this.event = event; errorCount++; } /** * Returns the last received error event. * * @return the last error event (may be null) */ public ConfigurationErrorEvent getLastEvent() { return event; } /** * Returns the number of received error events. * * @return the number of error events */ public int getErrorCount() { return errorCount; } /** * Checks whether no error event was received. */ public void verify() { assertEquals("Error events received", 0, errorCount); } /** * Checks whether an expected error event was received. This is a * convenience method for checking whether exactly one event of a certain * type was received. * * @param type the type of the event * @param propName the name of the property * @param propValue the value of the property */ public void verify(int type, String propName, Object propValue) { assertEquals("Wrong number of error events", 1, errorCount); assertEquals("Wrong event type", type, event.getType()); assertTrue("Wrong property name", (propName == null) ? event .getPropertyName() == null : propName.equals(event .getPropertyName())); assertTrue("Wrong property value", (propValue == null) ? event .getPropertyValue() == null : propValue.equals(event .getPropertyValue())); } } ././@LongLink100644 0 0 163 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/DatabaseConfigurationTestHelper.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/DatabaseConfigurationT100644 15767 12232154104 33600 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.FileInputStream; import java.sql.Connection; import javax.sql.DataSource; import org.apache.commons.configuration.test.HsqlDB; import org.apache.commons.dbcp.BasicDataSource; import org.dbunit.database.DatabaseConnection; import org.dbunit.database.IDatabaseConnection; import org.dbunit.dataset.IDataSet; import org.dbunit.dataset.xml.XmlDataSet; import org.dbunit.operation.DatabaseOperation; /** * A helper class for performing tests for {@link DatabaseConfiguration}. This * class maintains an in-process database that stores configuration data and can * be accessed from a {@link DatabaseConfiguration} instance. Constants for * table and column names and database connection settings are provided, too. * * @version $Id: DatabaseConfigurationTestHelper.java 1222447 2011-12-22 20:59:44Z oheger $ */ public class DatabaseConfigurationTestHelper { /** Constant for the JDBC driver class. */ public final String DATABASE_DRIVER = "org.hsqldb.jdbcDriver"; /** Constant for the connection URL. */ public final String DATABASE_URL = "jdbc:hsqldb:mem:testdb"; /** Constant for the DB user name. */ public final String DATABASE_USERNAME = "sa"; /** Constant for the DB password. */ public final String DATABASE_PASSWORD = ""; /** Constant for the configuration table. */ public static final String TABLE = "configuration"; /** Constant for the multi configuration table. */ public static final String TABLE_MULTI = "configurations"; /** Constant for the column with the keys. */ public static final String COL_KEY = "key"; /** Constant for the column with the values. */ public static final String COL_VALUE = "value"; /** Constant for the column with the configuration name. */ public static final String COL_NAME = "name"; /** Constant for the name of the test configuration. */ public static final String CONFIG_NAME = "test"; /** Stores the in-process database. */ private HsqlDB hsqlDB; /** The data source. */ private DataSource datasource; /** * The auto-commit mode for the connections created by the managed data * source. */ private boolean autoCommit = true; /** * Returns the auto-commit mode of the connections created by the managed * data source. * * @return the auto-commit mode */ public boolean isAutoCommit() { return autoCommit; } /** * Sets the auto-commit mode of the connections created by the managed data * source. * * @param autoCommit the auto-commit mode */ public void setAutoCommit(boolean autoCommit) { this.autoCommit = autoCommit; } /** * Initializes this helper object. This method can be called from a * {@code setUp()} method of a unit test class. It creates the database * instance if necessary. * * @throws Exception if an error occurs */ public void setUp() throws Exception { File script = ConfigurationAssert.getTestFile("testdb.script"); hsqlDB = new HsqlDB(DATABASE_URL, DATABASE_DRIVER, script.getAbsolutePath()); } /** * Frees the resources used by this helper class. This method can be called * by a {@code tearDown()} method of a unit test class. * * @throws Exception if an error occurs */ public void tearDown() throws Exception { if (datasource != null) { datasource.getConnection().close(); } hsqlDB.close(); } /** * Creates a database configuration with default values. * * @return the configuration */ public DatabaseConfiguration setUpConfig() { return new DatabaseConfiguration(getDatasource(), TABLE, COL_KEY, COL_VALUE, !isAutoCommit()); } /** * Creates a database configuration that supports multiple configurations in * a table with default values. * * @return the configuration */ public DatabaseConfiguration setUpMultiConfig() { return setUpMultiConfig(CONFIG_NAME); } /** * Creates a database configuration that supports multiple configurations in * a table and sets the specified configuration name. * * @param configName the name of the configuration * @return the configuration */ public DatabaseConfiguration setUpMultiConfig(String configName) { return new DatabaseConfiguration(getDatasource(), TABLE_MULTI, COL_NAME, COL_KEY, COL_VALUE, configName, !isAutoCommit()); } /** * Returns the {@code DataSource} managed by this class. The data * source is created on first access. * * @return the {@code DataSource} */ public DataSource getDatasource() { if (datasource == null) { try { datasource = setUpDataSource(); } catch (Exception ex) { throw new ConfigurationRuntimeException( "Could not create data source", ex); } } return datasource; } /** * Creates the internal data source. This method also initializes the * database. * * @return the data source * @throws Exception if an error occurs */ private DataSource setUpDataSource() throws Exception { BasicDataSource ds = new BasicDataSource(); ds.setDriverClassName(DATABASE_DRIVER); ds.setUrl(DATABASE_URL); ds.setUsername(DATABASE_USERNAME); ds.setPassword(DATABASE_PASSWORD); ds.setDefaultAutoCommit(isAutoCommit()); // prepare the database Connection conn = ds.getConnection(); IDatabaseConnection connection = new DatabaseConnection(conn); IDataSet dataSet = new XmlDataSet(new FileInputStream( ConfigurationAssert.getTestFile("dataset.xml"))); try { DatabaseOperation.CLEAN_INSERT.execute(connection, dataSet); } finally { if (!isAutoCommit()) { conn.commit(); } connection.close(); } return ds; } } ././@LongLink100644 0 0 171 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/AbstractTestConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/AbstractTestConf100644 14657 12232154103 33546 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import org.apache.commons.configuration.AbstractConfiguration; import org.junit.Before; import org.junit.Test; /** * Base class for testing events generated by configuration classes derived from * AbstractConfiguration. This class implements a couple of tests related to * event generation. Concrete sub classes only have to implement the * {@code createConfiguration()} method for creating an instance of a * specific configuration class. Because tests for detail events depend on a * concrete implementation an exact sequence of events cannot be checked. * Instead the corresponding test methods check whether the enclosing events * (not the detail events) are of the expected type. * * @version $Id: AbstractTestConfigurationEvents.java 1225648 2011-12-29 20:55:07Z oheger $ */ public abstract class AbstractTestConfigurationEvents { /** Constant for a test property name. */ static final String TEST_PROPNAME = "event.test"; /** Constant for a test property value. */ static final String TEST_PROPVALUE = "a value"; /** Constant for an existing property. */ static final String EXIST_PROPERTY = "event.property"; /** The configuration to be tested. */ protected AbstractConfiguration config; /** A test event listener. */ protected ConfigurationListenerTestImpl l; @Before public void setUp() throws Exception { config = createConfiguration(); config.addProperty(EXIST_PROPERTY, "existing value"); l = new ConfigurationListenerTestImpl(config); config.addConfigurationListener(l); } /** * Creates the configuration instance to be tested. * * @return the configuration instance under test */ protected abstract AbstractConfiguration createConfiguration(); /** * Tests events generated by addProperty(). */ @Test public void testAddPropertyEvent() { config.addProperty(TEST_PROPNAME, TEST_PROPVALUE); l.checkEvent(AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_PROPNAME, TEST_PROPVALUE, true); l.checkEvent(AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_PROPNAME, TEST_PROPVALUE, false); l.done(); } /** * Tests events generated by addProperty() when detail events are enabled. */ @Test public void testAddPropertyEventWithDetails() { config.setDetailEvents(true); config.addProperty(TEST_PROPNAME, TEST_PROPVALUE); l.checkEventCount(2); l.checkEvent(AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_PROPNAME, TEST_PROPVALUE, true); l.skipToLast(AbstractConfiguration.EVENT_ADD_PROPERTY); l.checkEvent(AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_PROPNAME, TEST_PROPVALUE, false); l.done(); } /** * Tests events generated by clearProperty(). */ @Test public void testClearPropertyEvent() { config.clearProperty(EXIST_PROPERTY); l.checkEvent(AbstractConfiguration.EVENT_CLEAR_PROPERTY, EXIST_PROPERTY, null, true); l.checkEvent(AbstractConfiguration.EVENT_CLEAR_PROPERTY, EXIST_PROPERTY, null, false); l.done(); } /** * Tests events generated by clearProperty() when detail events are enabled. */ @Test public void testClearPropertyEventWithDetails() { config.setDetailEvents(true); config.clearProperty(EXIST_PROPERTY); l.checkEventCount(2); l.checkEvent(AbstractConfiguration.EVENT_CLEAR_PROPERTY, EXIST_PROPERTY, null, true); l.skipToLast(AbstractConfiguration.EVENT_CLEAR_PROPERTY); l.checkEvent(AbstractConfiguration.EVENT_CLEAR_PROPERTY, EXIST_PROPERTY, null, false); l.done(); } /** * Tests events generated by setProperty(). */ @Test public void testSetPropertyEvent() { config.setProperty(EXIST_PROPERTY, TEST_PROPVALUE); l.checkEvent(AbstractConfiguration.EVENT_SET_PROPERTY, EXIST_PROPERTY, TEST_PROPVALUE, true); l.checkEvent(AbstractConfiguration.EVENT_SET_PROPERTY, EXIST_PROPERTY, TEST_PROPVALUE, false); l.done(); } /** * Tests events generated by setProperty() when detail events are enabled. */ @Test public void testSetPropertyEventWithDetails() { config.setDetailEvents(true); config.setProperty(EXIST_PROPERTY, TEST_PROPVALUE); l.checkEventCount(2); l.checkEvent(AbstractConfiguration.EVENT_SET_PROPERTY, EXIST_PROPERTY, TEST_PROPVALUE, true); l.skipToLast(AbstractConfiguration.EVENT_SET_PROPERTY); l.checkEvent(AbstractConfiguration.EVENT_SET_PROPERTY, EXIST_PROPERTY, TEST_PROPVALUE, false); l.done(); } /** * Tests the events generated by the clear() method. */ @Test public void testClearEvent() { config.clear(); l.checkEvent(AbstractConfiguration.EVENT_CLEAR, null, null, true); l.checkEvent(AbstractConfiguration.EVENT_CLEAR, null, null, false); l.done(); } /** * Tests the events generated by the clear method when detail events are * enabled. */ @Test public void testClearEventWithDetails() { config.setDetailEvents(true); config.clear(); l.checkEventCount(2); l.checkEvent(AbstractConfiguration.EVENT_CLEAR, null, null, true); l.skipToLast(AbstractConfiguration.EVENT_CLEAR); l.checkEvent(AbstractConfiguration.EVENT_CLEAR, null, null, false); l.done(); } } ././@LongLink100644 0 0 175 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/AbstractTestFileConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/AbstractTestFile100644 11557 12232154103 33534 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import java.io.IOException; import java.net.URL; import org.apache.commons.configuration.AbstractFileConfiguration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.FileConfiguration; import org.apache.commons.configuration.reloading.ReloadingStrategy; import org.junit.Test; /** * A base test class that can be used for testing file-based configurations. * This class tests reload events, too. * * @version $Id: AbstractTestFileConfigurationEvents.java 1225648 2011-12-29 20:55:07Z oheger $ */ public abstract class AbstractTestFileConfigurationEvents extends AbstractTestConfigurationEvents { /** * Initializes the file configuration for the tests. * * @throws ConfigurationException if an error occurs */ protected void setUpFileConfiguration() throws ConfigurationException, IOException { FileConfiguration fc = (FileConfiguration) config; fc.setReloadingStrategy(new AlwaysReloadingStrategy()); fc.setURL(getSourceURL()); // deregister event listener before load because load will cause // other events being generated config.removeConfigurationListener(l); fc.load(); config.addConfigurationListener(l); } /** * Returns the URL of the file to be loaded. Must be implemented in concrete * test classes. * * @return the URL of the file-based configuration * @throws IOException if an error occurs */ protected abstract URL getSourceURL() throws IOException; /** * Tests events generated by the reload() method. */ @Test public void testReloadEvent() throws ConfigurationException, IOException { setUpFileConfiguration(); config.isEmpty(); // This should cause a reload l.checkEvent(AbstractFileConfiguration.EVENT_RELOAD, null, getSourceURL(), true); l.checkEvent(AbstractFileConfiguration.EVENT_RELOAD, null, getSourceURL(), false); l.done(); } /** * Tests events generated by the reload() method when detail events are * enabled. */ @Test public void testReloadEventWithDetails() throws ConfigurationException, IOException { setUpFileConfiguration(); config.setDetailEvents(true); config.isEmpty(); // This should cause a reload l.checkEventCount(2); l.checkEvent(AbstractFileConfiguration.EVENT_RELOAD, null, getSourceURL(), true); l.skipToLast(AbstractFileConfiguration.EVENT_RELOAD); l.checkEvent(AbstractFileConfiguration.EVENT_RELOAD, null, getSourceURL(), false); l.done(); } /** * Tests accessing a property during a reload event to ensure that no * infinite loops are possible. */ @Test public void testAccessPropertiesOnReload() throws ConfigurationException, IOException { setUpFileConfiguration(); config.addConfigurationListener(new ConfigurationListener() { public void configurationChanged(ConfigurationEvent event) { config.getString("test"); } }); config.isEmpty(); l.checkEvent(AbstractFileConfiguration.EVENT_RELOAD, null, getSourceURL(), true); l.checkEvent(AbstractFileConfiguration.EVENT_RELOAD, null, getSourceURL(), false); l.done(); } /** * A dummy implementation of the ReloadingStrategy interface. This * implementation will always indicate that a reload should be performed. So * it can be used for testing reloading events. */ static class AlwaysReloadingStrategy implements ReloadingStrategy { public void setConfiguration(FileConfiguration configuration) { } public void init() { } public boolean reloadingRequired() { return true; } public void reloadingPerformed() { } } } ././@LongLink100644 0 0 167 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/ConfigurationListenerTestImpl.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/ConfigurationLis100644 10454 12232154103 33603 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.LinkedList; import java.util.List; /** * A test event listener class that can be used for testing whether * configurations generated correct events. * * @author Commons * Configuration team * @version $Id: ConfigurationListenerTestImpl.java 1225648 2011-12-29 20:55:07Z oheger $ */ public class ConfigurationListenerTestImpl implements ConfigurationListener { /** The expected event source. */ private final Object expectedSource; /** Stores the received events. */ private final List events; /** * Creates a new instance of {@code ConfigurationListenerTestImpl} and sets * the expected event source. * * @param source the event source (null if the source need not to be * checked) */ public ConfigurationListenerTestImpl(Object source) { expectedSource = source; events = new LinkedList(); } public void configurationChanged(ConfigurationEvent event) { events.add(event); } /** * Checks if at least {@code minEvents} events have been received. * * @param minEvents the minimum number of expected events */ public void checkEventCount(int minEvents) { assertTrue("Too view events received", events.size() >= minEvents); } /** * Checks an expected event. * * @param type the event type * @param propName the expected property name * @param propValue the expected property value * @param before the expected before flag */ public void checkEvent(int type, String propName, Object propValue, boolean before) { ConfigurationEvent e = nextEvent(type); assertEquals("Wrong property name", propName, e.getPropertyName()); assertEquals("Wrong property value", propValue, e.getPropertyValue()); assertEquals("Wrong before flag", before, e.isBeforeUpdate()); } /** * Returns the next received event and checks for the expected type. This * method can be used instead of {@code checkEvent()} for comparing * complex event values. * * @param expectedType the expected type of the event * @return the event object */ public ConfigurationEvent nextEvent(int expectedType) { assertFalse("Too few events received", events.isEmpty()); ConfigurationEvent e = events.remove(0); if (expectedSource != null) { assertEquals("Wrong event source", expectedSource, e.getSource()); } assertEquals("Wrong event type", expectedType, e.getType()); return e; } /** * Skips to the last received event and checks that no events of the given * type have been received. This method is used by checks for detail events * to ignore the detail events. * * @param type the event type */ public void skipToLast(int type) { while (events.size() > 1) { ConfigurationEvent e = events.remove(0); assertTrue("Found end event in details", type != e.getType()); } } /** * Checks if all events has been processed. */ public void done() { assertTrue("Too many events received", events.isEmpty()); } } ././@LongLink100644 0 0 171 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestDatabaseConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestDatabaseConf100644 3371 12232154103 33456 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.DatabaseConfigurationTestHelper; import org.junit.After; import org.junit.Before; /** * A test class for the events generated by DatabaseConfiguration. * * @version $Id: TestDatabaseConfigurationEvents.java 1225648 2011-12-29 20:55:07Z oheger $ */ public class TestDatabaseConfigurationEvents extends AbstractTestConfigurationEvents { /** The test helper. */ private DatabaseConfigurationTestHelper helper; @Override @Before public void setUp() throws Exception { helper = new DatabaseConfigurationTestHelper(); helper.setUp(); super.setUp(); } @After public void tearDown() throws Exception { helper.tearDown(); } @Override protected AbstractConfiguration createConfiguration() { return helper.setUpConfig(); } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestEventSource.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestEventSource.100644 32234 12232154103 33504 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Collection; import org.junit.Before; import org.junit.Test; /** * Test class for EventSource. * * @version $Id: TestEventSource.java 1225652 2011-12-29 21:00:57Z oheger $ */ public class TestEventSource { /** Constant for the event type used for testing. */ static final int TEST_TYPE = 42; /** Constant for the event property name. */ static final String TEST_PROPNAME = "test.property.name"; /** Constant for the event property value. */ static final Object TEST_PROPVALUE = "a test property value"; /** The object under test. */ CountingEventSource source; @Before public void setUp() throws Exception { source = new CountingEventSource(); } /** * Tests a newly created source object. */ @Test public void testInit() { assertTrue("Listeners list is not empty", source .getConfigurationListeners().isEmpty()); assertFalse("Removing listener", source .removeConfigurationListener(new TestListener())); assertFalse("Detail events are enabled", source.isDetailEvents()); assertTrue("Error listeners list is not empty", source .getErrorListeners().isEmpty()); } /** * Tests registering a new listener. */ @Test public void testAddConfigurationListener() { TestListener l = new TestListener(); source.addConfigurationListener(l); Collection listeners = source.getConfigurationListeners(); assertEquals("Wrong number of listeners", 1, listeners.size()); assertTrue("Listener not in list", listeners.contains(l)); } /** * Tests adding an undefined configuration listener. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testAddNullConfigurationListener() { source.addConfigurationListener(null); } /** * Tests removing a listener. */ @Test public void testRemoveConfigurationListener() { TestListener l = new TestListener(); assertFalse("Listener can be removed?", source .removeConfigurationListener(l)); source.addConfigurationListener(l); source.addConfigurationListener(new TestListener()); assertFalse("Unknown listener can be removed", source .removeConfigurationListener(new TestListener())); assertTrue("Could not remove listener", source .removeConfigurationListener(l)); assertFalse("Listener still in list", source .getConfigurationListeners().contains(l)); } /** * Tests if a null listener can be removed. This should be a no-op. */ @Test public void testRemoveNullConfigurationListener() { source.addConfigurationListener(new TestListener()); assertFalse("Null listener can be removed", source .removeConfigurationListener(null)); assertEquals("Listener list was modified", 1, source .getConfigurationListeners().size()); } /** * Tests whether the listeners list is read only. */ @Test(expected = UnsupportedOperationException.class) public void testGetConfigurationListenersUpdate() { source.addConfigurationListener(new TestListener()); Collection list = source.getConfigurationListeners(); list.clear(); } /** * Tests that the collection returned by getConfigurationListeners() is * really a snapshot. A later added listener must not be visible. */ @Test public void testGetConfigurationListenersAddNew() { Collection list = source.getConfigurationListeners(); source.addConfigurationListener(new TestListener()); assertTrue("Listener snapshot not empty", list.isEmpty()); } /** * Tests enabling and disabling the detail events flag. */ @Test public void testSetDetailEvents() { source.setDetailEvents(true); assertTrue("Detail events are disabled", source.isDetailEvents()); source.setDetailEvents(true); source.setDetailEvents(false); assertTrue("Detail events are disabled again", source.isDetailEvents()); source.setDetailEvents(false); assertFalse("Detail events are still enabled", source.isDetailEvents()); } /** * Tests delivering an event to a listener. */ @Test public void testFireEvent() { TestListener l = new TestListener(); source.addConfigurationListener(l); source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, true); assertEquals("Not 1 event created", 1, source.eventCount); assertEquals("Listener not called once", 1, l.numberOfCalls); assertEquals("Wrong event type", TEST_TYPE, l.lastEvent.getType()); assertEquals("Wrong property name", TEST_PROPNAME, l.lastEvent .getPropertyName()); assertEquals("Wrong property value", TEST_PROPVALUE, l.lastEvent .getPropertyValue()); assertTrue("Wrong before event flag", l.lastEvent.isBeforeUpdate()); } /** * Tests firing an event if there are no listeners. */ @Test public void testFireEventNoListeners() { source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, false); assertEquals("An event object was created", 0, source.eventCount); } /** * Tests generating a detail event if detail events are not allowed. */ @Test public void testFireEventNoDetails() { TestListener l = new TestListener(); source.addConfigurationListener(l); source.setDetailEvents(false); source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, false); assertEquals("Event object was created", 0, source.eventCount); assertEquals("Listener was called", 0, l.numberOfCalls); } /** * Tests whether an event listener can deregister itself in reaction of a * delivered event. */ @Test public void testRemoveListenerInFireEvent() { ConfigurationListener lstRemove = new ConfigurationListener() { public void configurationChanged(ConfigurationEvent event) { source.removeConfigurationListener(this); } }; source.addConfigurationListener(lstRemove); TestListener l = new TestListener(); source.addConfigurationListener(l); source.fireEvent(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, false); assertEquals("Listener was not called", 1, l.numberOfCalls); assertEquals("Listener was not removed", 1, source .getConfigurationListeners().size()); } /** * Tests registering a new error listener. */ @Test public void testAddErrorListener() { TestListener l = new TestListener(); source.addErrorListener(l); Collection listeners = source.getErrorListeners(); assertEquals("Wrong number of listeners", 1, listeners.size()); assertTrue("Listener not in list", listeners.contains(l)); } /** * Tests adding an undefined error listener. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testAddNullErrorListener() { source.addErrorListener(null); } /** * Tests removing an error listener. */ @Test public void testRemoveErrorListener() { TestListener l = new TestListener(); assertFalse("Listener can be removed?", source.removeErrorListener(l)); source.addErrorListener(l); source.addErrorListener(new TestListener()); assertFalse("Unknown listener can be removed", source .removeErrorListener(new TestListener())); assertTrue("Could not remove listener", source.removeErrorListener(l)); assertFalse("Listener still in list", source.getErrorListeners() .contains(l)); } /** * Tests if a null error listener can be removed. This should be a no-op. */ @Test public void testRemoveNullErrorListener() { source.addErrorListener(new TestListener()); assertFalse("Null listener can be removed", source .removeErrorListener(null)); assertEquals("Listener list was modified", 1, source .getErrorListeners().size()); } /** * Tests whether the listeners list is read only. */ @Test(expected = UnsupportedOperationException.class) public void testGetErrorListenersUpdate() { source.addErrorListener(new TestListener()); Collection list = source.getErrorListeners(); list.clear(); } /** * Tests delivering an error event to a listener. */ @Test public void testFireError() { TestListener l = new TestListener(); source.addErrorListener(l); Exception testException = new Exception("A test"); source.fireError(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, testException); assertEquals("Not 1 event created", 1, source.errorCount); assertEquals("Error listener not called once", 1, l.numberOfErrors); assertEquals("Normal event was generated", 0, l.numberOfCalls); assertEquals("Wrong event type", TEST_TYPE, l.lastEvent.getType()); assertEquals("Wrong property name", TEST_PROPNAME, l.lastEvent .getPropertyName()); assertEquals("Wrong property value", TEST_PROPVALUE, l.lastEvent .getPropertyValue()); assertEquals("Wrong Throwable object", testException, ((ConfigurationErrorEvent) l.lastEvent).getCause()); } /** * Tests firing an error event if there are no error listeners. */ @Test public void testFireErrorNoListeners() { source.fireError(TEST_TYPE, TEST_PROPNAME, TEST_PROPVALUE, new Exception()); assertEquals("An error event object was created", 0, source.errorCount); } /** * Tests cloning an event source object. The registered listeners should not * be registered at the clone. */ @Test public void testClone() throws CloneNotSupportedException { source.addConfigurationListener(new TestListener()); source.addErrorListener(new TestListener()); EventSource copy = (EventSource) source.clone(); assertTrue("Configuration listeners registered for clone", copy .getConfigurationListeners().isEmpty()); assertTrue("Error listeners registered for clone", copy .getErrorListeners().isEmpty()); } /** * A test event listener implementation. */ static class TestListener implements ConfigurationListener, ConfigurationErrorListener { ConfigurationEvent lastEvent; int numberOfCalls; int numberOfErrors; public void configurationChanged(ConfigurationEvent event) { lastEvent = event; numberOfCalls++; } public void configurationError(ConfigurationErrorEvent event) { lastEvent = event; numberOfErrors++; } } /** * A specialized event source implementation that counts the number of * created event objects. It is used to test whether the * {@code fireEvent()} methods only creates event objects if * necessary. It also allows testing the clone() operation. */ static class CountingEventSource extends EventSource implements Cloneable { int eventCount; int errorCount; @Override protected ConfigurationEvent createEvent(int type, String propName, Object propValue, boolean before) { eventCount++; return super.createEvent(type, propName, propValue, before); } @Override protected ConfigurationErrorEvent createErrorEvent(int type, String propName, Object value, Throwable ex) { errorCount++; return super.createErrorEvent(type, propName, value, ex); } } } ././@LongLink100644 0 0 175 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestHierarchicalConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestHierarchical100644 11611 12232154103 33536 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Collection; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.SubnodeConfiguration; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.junit.Test; /** * Test class for the events generated by hierarchical configurations. * * @version $Id: TestHierarchicalConfigurationEvents.java 1225648 2011-12-29 20:55:07Z oheger $ */ public class TestHierarchicalConfigurationEvents extends AbstractTestConfigurationEvents { @Override protected AbstractConfiguration createConfiguration() { return new HierarchicalConfiguration(); } /** * Tests events generated by the clearTree() method. */ @Test public void testClearTreeEvent() { HierarchicalConfiguration hc = (HierarchicalConfiguration) config; String key = EXIST_PROPERTY.substring(0, EXIST_PROPERTY.indexOf('.')); Collection nodes = hc.getExpressionEngine() .query(hc.getRootNode(), key); hc.clearTree(key); l.checkEvent(HierarchicalConfiguration.EVENT_CLEAR_TREE, key, null, true); l.checkEvent(HierarchicalConfiguration.EVENT_CLEAR_TREE, key, nodes, false); l.done(); } /** * Tests events generated by the addNodes() method. */ @Test public void testAddNodesEvent() { HierarchicalConfiguration hc = (HierarchicalConfiguration) config; Collection nodes = new ArrayList(1); nodes.add(new DefaultConfigurationNode("a_key", TEST_PROPVALUE)); hc.addNodes(TEST_PROPNAME, nodes); l.checkEvent(HierarchicalConfiguration.EVENT_ADD_NODES, TEST_PROPNAME, nodes, true); l.checkEvent(HierarchicalConfiguration.EVENT_ADD_NODES, TEST_PROPNAME, nodes, false); l.done(); } /** * Tests events generated by addNodes() when the list of nodes is empty. In * this case no events should be generated. */ @Test public void testAddNodesEmptyEvent() { ((HierarchicalConfiguration) config).addNodes(TEST_PROPNAME, new ArrayList()); l.done(); } /** * Tests whether manipulations of a subnode configuration trigger correct * events. */ @Test public void testSubnodeChangedEvent() { SubnodeConfiguration sub = ((HierarchicalConfiguration) config) .configurationAt(EXIST_PROPERTY); sub.addProperty("newProp", "newValue"); checkSubnodeEvent(l .nextEvent(HierarchicalConfiguration.EVENT_SUBNODE_CHANGED), true); checkSubnodeEvent(l .nextEvent(HierarchicalConfiguration.EVENT_SUBNODE_CHANGED), false); l.done(); } /** * Tests whether a received event contains a correct subnode event. * * @param event the event object * @param before the expected before flag */ private void checkSubnodeEvent(ConfigurationEvent event, boolean before) { assertEquals("Wrong before flag of nesting event", before, event .isBeforeUpdate()); assertTrue("No subnode event found in value", event.getPropertyValue() instanceof ConfigurationEvent); ConfigurationEvent evSub = (ConfigurationEvent) event .getPropertyValue(); assertEquals("Wrong event type", HierarchicalConfiguration.EVENT_ADD_PROPERTY, evSub.getType()); assertEquals("Wrong property name", "newProp", evSub.getPropertyName()); assertEquals("Wrong property value", "newValue", evSub .getPropertyValue()); assertEquals("Wrong before flag", before, evSub.isBeforeUpdate()); } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestMapConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestMapConfigura100644 2562 12232154103 33520 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import java.util.HashMap; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.MapConfiguration; /** * Test class for the events generated by MapConfiguration. * * @version $Id: TestMapConfigurationEvents.java 1225648 2011-12-29 20:55:07Z oheger $ */ public class TestMapConfigurationEvents extends AbstractTestConfigurationEvents { @Override protected AbstractConfiguration createConfiguration() { return new MapConfiguration(new HashMap()); } } ././@LongLink100644 0 0 173 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestPropertiesConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestPropertiesCo100644 3410 12232154103 33554 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import java.io.File; import java.io.IOException; import java.net.URL; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.ConfigurationAssert; import org.apache.commons.configuration.PropertiesConfiguration; /** * Test class for the events generated by properties configurations. This class * also tests reload events. * * @version $Id: TestPropertiesConfigurationEvents.java 1225648 2011-12-29 20:55:07Z oheger $ */ public class TestPropertiesConfigurationEvents extends AbstractTestFileConfigurationEvents { /** The file to be loaded.*/ static final File TEST_FILE = ConfigurationAssert.getTestFile("test.properties"); @Override protected AbstractConfiguration createConfiguration() { return new PropertiesConfiguration(); } @Override protected URL getSourceURL() throws IOException { return TEST_FILE.toURI().toURL(); } } ././@LongLink100644 0 0 167 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestSubsetConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestSubsetConfig100644 2734 12232154103 33541 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import java.util.HashMap; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.MapConfiguration; import org.apache.commons.configuration.SubsetConfiguration; /** * Test class for the events generated by SubsetConfiguration. * * @version $Id: TestSubsetConfigurationEvents.java 1225648 2011-12-29 20:55:07Z oheger $ */ public class TestSubsetConfigurationEvents extends AbstractTestConfigurationEvents { @Override protected AbstractConfiguration createConfiguration() { return (SubsetConfiguration)new MapConfiguration(new HashMap()).subset("test"); } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestXMLConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/TestXMLConfigura100644 3217 12232154103 33441 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.event; import java.io.File; import java.io.IOException; import java.net.URL; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.ConfigurationAssert; import org.apache.commons.configuration.XMLConfiguration; /** * Test class for events generated by XMLConfiguration. * * @version $Id: TestXMLConfigurationEvents.java 1225648 2011-12-29 20:55:07Z oheger $ */ public class TestXMLConfigurationEvents extends AbstractTestFileConfigurationEvents { static final File TEST_FILE = ConfigurationAssert.getTestFile("test.xml"); @Override protected URL getSourceURL() throws IOException { return TEST_FILE.toURI().toURL(); } @Override protected AbstractConfiguration createConfiguration() { return new XMLConfiguration(); } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/FileURLStreamHandler.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/FileURLStreamHandler.j100644 4034 12232154104 33325 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; /** * A custom URLStreamHandler to test loading and saving configurations to non * standard URLs. This handler acts like a file handler with write support. * * @author Emmanuel Bourg * @version $Id: FileURLStreamHandler.java 1222450 2011-12-22 21:01:33Z oheger $ */ public class FileURLStreamHandler extends URLStreamHandler { @Override protected URLConnection openConnection(URL u) throws IOException { final File file = new File(u.getFile()); return new URLConnection(u) { @Override public void connect() throws IOException { } @Override public InputStream getInputStream() throws IOException { return new FileInputStream(file); } @Override public OutputStream getOutputStream() throws IOException { return new FileOutputStream(file); } }; } } ././@LongLink100644 0 0 172 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/TestConfigurationInterpolator.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/TestConfigura100644 26466 12232154103 33626 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.interpol; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.HashMap; import java.util.Map; import java.util.Properties; import org.apache.commons.lang.text.StrLookup; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test class for ConfigurationInterpolator. * * @version $Id: TestConfigurationInterpolator.java 1225653 2011-12-29 21:06:26Z oheger $ */ public class TestConfigurationInterpolator { /** Constant for a test variable prefix. */ private static final String TEST_PREFIX = "prefix"; /** Constant for a test variable name. */ private static final String TEST_NAME = "varname"; /** Constant for the value of the test variable. */ private static final String TEST_VALUE = "TestVariableValue"; /** Stores the object to be tested. */ private ConfigurationInterpolator interpolator; @Before public void setUp() throws Exception { interpolator = new ConfigurationInterpolator(); } /** * Cleans the test environment. Deregisters the test lookup object if * necessary. */ @After public void tearDown() throws Exception { ConfigurationInterpolator.deregisterGlobalLookup(TEST_PREFIX); } /** * Tests creating an instance. Does it contain some predefined lookups? */ @Test public void testInit() { assertNull("A default lookup is set", interpolator.getDefaultLookup()); assertFalse("No predefined lookups", interpolator.prefixSet().isEmpty()); } /** * Tries to register a global lookup for a null prefix. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testRegisterGlobalLookupNullPrefix() { ConfigurationInterpolator.registerGlobalLookup(null, StrLookup .noneLookup()); } /** * Tries to register a global null lookup. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testRegisterGlobalLookupNull() { ConfigurationInterpolator.registerGlobalLookup(TEST_PREFIX, null); } /** * Tests registering a global lookup object. This lookup object should then * be available for instances created later on. */ @Test public void testRegisterGlobalLookup() { ConfigurationInterpolator.registerGlobalLookup(TEST_PREFIX, StrLookup .noneLookup()); ConfigurationInterpolator int2 = new ConfigurationInterpolator(); assertTrue("No lookup registered for test prefix", int2.prefixSet() .contains(TEST_PREFIX)); assertFalse("Existing instance was modified", interpolator.prefixSet() .contains(TEST_PREFIX)); } /** * Tests deregistering a global lookup object. */ @Test public void testDeregisterGlobalLookup() { ConfigurationInterpolator.registerGlobalLookup(TEST_PREFIX, StrLookup .noneLookup()); assertTrue("Lookup could not be deregistered", ConfigurationInterpolator.deregisterGlobalLookup(TEST_PREFIX)); ConfigurationInterpolator int2 = new ConfigurationInterpolator(); assertFalse("Deregistered lookup still available", int2.prefixSet() .contains(TEST_PREFIX)); } /** * Tests deregistering an unknown lookup. */ @Test public void testDeregisterGlobalLookupNonExisting() { assertFalse("Could deregister unknown global lookup", ConfigurationInterpolator.deregisterGlobalLookup(TEST_PREFIX)); } /** * Tests registering a lookup object at an instance. */ @Test public void testRegisterLookup() { int cnt = interpolator.prefixSet().size(); interpolator.registerLookup(TEST_PREFIX, StrLookup.noneLookup()); assertTrue("New lookup not registered", interpolator.prefixSet() .contains(TEST_PREFIX)); assertEquals("Wrong number of registered lookups", cnt + 1, interpolator.prefixSet().size()); ConfigurationInterpolator int2 = new ConfigurationInterpolator(); assertFalse("Local registration has global impact", int2.prefixSet() .contains(TEST_PREFIX)); } /** * Tests registering a null lookup object. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testRegisterLookupNull() { interpolator.registerLookup(TEST_PREFIX, null); } /** * Tests registering a lookup object for an undefined prefix. This should * cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testRegisterLookupNullPrefix() { interpolator.registerLookup(null, StrLookup.noneLookup()); } /** * Tests deregistering a local lookup object. */ @Test public void testDeregisterLookup() { interpolator.registerLookup(TEST_PREFIX, StrLookup.noneLookup()); assertTrue("Derigstration not successfull", interpolator .deregisterLookup(TEST_PREFIX)); assertFalse("Deregistered prefix still contained", interpolator .prefixSet().contains(TEST_PREFIX)); } /** * Tests deregistering an unknown lookup object. */ @Test public void testDeregisterLookupNonExisting() { assertFalse("Could deregister unknown lookup", interpolator .deregisterLookup(TEST_PREFIX)); } /** * Tests whether a variable can be resolved using the associated lookup * object. The lookup is identified by the variable's prefix. */ @Test public void testLookupWithPrefix() { interpolator.registerLookup(TEST_PREFIX, setUpTestLookup()); assertEquals("Wrong variable value", TEST_VALUE, interpolator .lookup(TEST_PREFIX + ':' + TEST_NAME)); } /** * Tests the behavior of the lookup method for variables with an unknown * prefix. These variables should not be resolved. */ @Test public void testLookupWithUnknownPrefix() { interpolator.registerLookup(TEST_PREFIX, setUpTestLookup()); assertNull("Variable could be resolved", interpolator .lookup("UnknownPrefix:" + TEST_NAME)); assertNull("Variable with empty prefix could be resolved", interpolator .lookup(":" + TEST_NAME)); } /** * Tests looking up a variable without a prefix. This should trigger the * default lookup object. */ @Test public void testLookupDefault() { interpolator.setDefaultLookup(setUpTestLookup()); assertEquals("Wrong variable value", TEST_VALUE, interpolator .lookup(TEST_NAME)); } /** * Tests looking up a variable without a prefix when no default lookup is * specified. Result should be null in this case. */ @Test public void testLookupNoDefault() { assertNull("Variable could be resolved", interpolator.lookup(TEST_NAME)); } /** * Tests the empty variable prefix. This is a special case, but legal. */ @Test public void testLookupEmptyPrefix() { interpolator.registerLookup("", setUpTestLookup()); assertEquals("Wrong variable value", TEST_VALUE, interpolator .lookup(":" + TEST_NAME)); } /** * Tests an empty variable name. */ @Test public void testLookupEmptyVarName() { Map map = new HashMap(); map.put("", TEST_VALUE); interpolator.registerLookup(TEST_PREFIX, StrLookup.mapLookup(map)); assertEquals("Wrong variable value", TEST_VALUE, interpolator .lookup(TEST_PREFIX + ":")); } /** * Tests an empty variable name without a prefix. */ @Test public void testLookupDefaultEmptyVarName() { Map map = new HashMap(); map.put("", TEST_VALUE); interpolator.setDefaultLookup(StrLookup.mapLookup(map)); assertEquals("Wrong variable value", TEST_VALUE, interpolator .lookup("")); } /** * Tests looking up a null variable. Result shoult be null, too. */ @Test public void testLookupNull() { assertNull("Could resolve null variable", interpolator.lookup(null)); } /** * Creates a lookup object that can resolve the test variable. * * @return the test lookup object */ private StrLookup setUpTestLookup() { Map map = new HashMap(); map.put(TEST_NAME, TEST_VALUE); return StrLookup.mapLookup(map); } /** * Tests whether system properties can be correctly resolved. */ @Test public void testLookupSysProperties() { Properties sysProps = System.getProperties(); for (Object prop : sysProps.keySet()) { String key = (String) prop; assertEquals("Wrong value for system property " + key, sysProps .getProperty(key), interpolator .lookup(ConfigurationInterpolator.PREFIX_SYSPROPERTIES + ":" + key)); } } /** * Tests whether constants can be correctly resolved. */ @Test public void testLookupConstants() { String varName = ConfigurationInterpolator.class.getName() + ".PREFIX_CONSTANTS"; assertEquals("Wrong constant value", ConfigurationInterpolator.PREFIX_CONSTANTS, interpolator .lookup(ConfigurationInterpolator.PREFIX_CONSTANTS + ":" + varName)); } /** * Tests whether the default lookup is called for variables with a prefix * when the lookup that was registered for this prefix is not able to * resolve the variable. */ @Test public void testLookupDefaultAfterPrefixFails() { final String varName = TEST_PREFIX + ':' + TEST_NAME + "2"; interpolator.registerLookup(TEST_PREFIX, setUpTestLookup()); Map map = new HashMap(); map.put(varName, TEST_VALUE); interpolator.setDefaultLookup(StrLookup.mapLookup(map)); assertEquals("Variable is not resolved by default lookup", TEST_VALUE, interpolator.lookup(varName)); } } ././@LongLink100644 0 0 157 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/TestConstantLookup.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/TestConstantL100644 10525 12232154103 33603 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.interpol; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.awt.event.KeyEvent; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test class for ConstantLookup. * * @version $Id: TestConstantLookup.java 1225656 2011-12-29 21:09:11Z oheger $ */ public class TestConstantLookup { /** Constant for the name of the test class. */ private static final String CLS_NAME = ConfigurationInterpolator.class .getName() + '.'; /** Constant for the name of the test field. */ private static final String FIELD = "PREFIX_CONSTANTS"; /** Constant for the test variable name. */ private static final String VARNAME = CLS_NAME + FIELD; /** The lookup object to be tested. */ private ConstantLookup lookup; @Before public void setUp() throws Exception { lookup = new ConstantLookup(); } /** * Clears the test environment. Here the static cache of the constant lookup * class is wiped out. */ @After public void tearDown() throws Exception { ConstantLookup.clear(); } /** * Tests resolving a valid constant. */ @Test public void testLookupConstant() { assertEquals("Wrong value of constant", ConfigurationInterpolator.PREFIX_CONSTANTS, lookup .lookup(VARNAME)); } /** * Tests resolving a non existing constant. Result should be null. */ @Test public void testLookupNonExisting() { assertNull("Non null return value for non existing constant", lookup .lookup(CLS_NAME + "NO_FIELD")); } /** * Tests resolving a private constant. Because a private field cannot be * accessed this should again yield null. */ @Test public void testLookupPrivate() { assertNull("Non null return value for non accessable field", lookup .lookup(CLS_NAME + "PREFIX_SEPARATOR")); } /** * Tests resolving a field from an unknown class. */ @Test public void testLookupUnknownClass() { assertNull("Non null return value for unknown class", lookup .lookup("org.apache.commons.configuration.NonExistingConfig." + FIELD)); } /** * Tries to resolve a variable with an invalid syntax: The name does not * contain a dot as a field separator. */ @Test public void testLookupInvalidSyntax() { assertNull("Non null return value for invalid variable name", lookup .lookup("InvalidVariableName")); } /** * Tests looking up a null variable. */ @Test public void testLookupNull() { assertNull("Non null return value for null variable", lookup .lookup(null)); } /** * Tests accessing the cache by querying a variable twice. */ @Test public void testLookupCache() { testLookupConstant(); testLookupConstant(); } /** * Tests resolving a non string constant. Then looks the same variable up * from the cache. */ @Test public void testLookupNonStringFromCache() { final String var = KeyEvent.class.getName() + ".VK_ESCAPE"; final String expected = String.valueOf(KeyEvent.VK_ESCAPE); assertEquals("Wrong result of first lookup", expected, lookup .lookup(var)); assertEquals("Wrong result of 2nd lookup", expected, lookup.lookup(var)); } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/TestEnvironmentLookup.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/TestEnvironme100644 4334 12232154103 33621 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.interpol; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import java.util.Iterator; import org.apache.commons.configuration.EnvironmentConfiguration; import org.junit.Before; import org.junit.Test; /** * Test class for EnvironmentLookup. * * @author Commons * Configuration team * @version $Id: TestEnvironmentLookup.java 1225658 2011-12-29 21:11:03Z oheger $ */ public class TestEnvironmentLookup { /** The lookup to be tested. */ private EnvironmentLookup lookup; @Before public void setUp() throws Exception { lookup = new EnvironmentLookup(); } /** * Tests whether environment variables can be queried. */ @Test public void testLookup() { EnvironmentConfiguration envConf = new EnvironmentConfiguration(); for (Iterator it = envConf.getKeys(); it.hasNext();) { String var = it.next(); assertEquals("Wrong value for " + var, envConf.getString(var), lookup.lookup(var)); } } /** * Tries to lookup a non existing property. */ @Test public void testLookupNonExisting() { assertNull("Got result for non existing environment variable", lookup .lookup("a non existing variable!")); } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/TestExprLookup.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/TestExprLooku100644 6245 12232154103 33612 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.interpol; import static org.junit.Assert.assertTrue; import java.io.File; import org.apache.commons.configuration.ConfigurationAssert; import org.apache.commons.configuration.XMLConfiguration; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.impl.Log4JLogger; import org.apache.log4j.ConsoleAppender; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.SimpleLayout; import org.junit.Test; /** * Test class for ExprLookup. * * @version $Id: TestExprLookup.java 1225659 2011-12-29 21:12:54Z oheger $ */ public class TestExprLookup { private static File TEST_FILE = ConfigurationAssert.getTestFile("test.xml"); private static String PATTERN1 = "String.replace(Util.message, 'Hello', 'Goodbye') + System.getProperty('user.name')"; private static String PATTERN2 = "'$[element] ' + String.trimToEmpty('$[space.description]')"; @Test public void testLookup() throws Exception { ConsoleAppender app = new ConsoleAppender(new SimpleLayout()); Log log = LogFactory.getLog("TestLogger"); Logger logger = ((Log4JLogger)log).getLogger(); logger.addAppender(app); logger.setLevel(Level.DEBUG); logger.setAdditivity(false); ExprLookup.Variables vars = new ExprLookup.Variables(); vars.add(new ExprLookup.Variable("String", org.apache.commons.lang.StringUtils.class)); vars.add(new ExprLookup.Variable("Util", new Utility("Hello"))); vars.add(new ExprLookup.Variable("System", "Class:java.lang.System")); XMLConfiguration config = new XMLConfiguration(TEST_FILE); config.setLogger(log); ExprLookup lookup = new ExprLookup(vars); lookup.setConfiguration(config); String str = lookup.lookup(PATTERN1); assertTrue(str.startsWith("Goodbye")); str = lookup.lookup(PATTERN2); assertTrue("Incorrect value: " + str, str.equals("value Some text")); logger.removeAppender(app); } public static class Utility { String message; public Utility(String msg) { this.message = msg; } public String getMessage() { return message; } public String str(String str) { return str; } } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/InterpolationTestHelper.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/InterpolationTestHelpe100644 23242 12232154104 33650 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.awt.event.KeyEvent; import java.util.List; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; import org.apache.commons.lang.text.StrLookup; /** * A helper class that defines a bunch of tests related to variable * interpolation. It can be used for running these tests on different * configuration implementations. * * @author Commons * Configuration team * @version $Id: InterpolationTestHelper.java 1222452 2011-12-22 21:06:17Z oheger $ */ public class InterpolationTestHelper { /** * Tests basic interpolation facilities of the specified configuration. * * @param config the configuration to test */ public static void testInterpolation(Configuration config) { config.setProperty("applicationRoot", "/home/applicationRoot"); config.setProperty("db", "${applicationRoot}/db/hypersonic"); String unInterpolatedValue = "${applicationRoot2}/db/hypersonic"; config.setProperty("dbFailedInterpolate", unInterpolatedValue); String dbProp = "/home/applicationRoot/db/hypersonic"; assertEquals("Checking interpolated variable", dbProp, config .getString("db")); assertEquals("lookup fails, leave variable as is", config .getString("dbFailedInterpolate"), unInterpolatedValue); config.setProperty("arrayInt", "${applicationRoot}/1"); String[] arrayInt = config.getStringArray("arrayInt"); assertEquals("check first entry was interpolated", "/home/applicationRoot/1", arrayInt[0]); config.addProperty("path", "/temp,C:\\Temp,/usr/local/tmp"); config.setProperty("path.current", "${path}"); assertEquals("Interpolation with multi-valued property", "/temp", config.getString("path.current")); } /** * Tests an interpolation over multiple levels (i.e. the replacement of a * variable is another variable and so on). * * @param config the configuration to test */ public static void testMultipleInterpolation(Configuration config) { config.setProperty("test.base-level", "/base-level"); config .setProperty("test.first-level", "${test.base-level}/first-level"); config.setProperty("test.second-level", "${test.first-level}/second-level"); config.setProperty("test.third-level", "${test.second-level}/third-level"); String expectedValue = "/base-level/first-level/second-level/third-level"; assertEquals(config.getString("test.third-level"), expectedValue); } /** * Tests an invalid interpolation that results in an infinite loop. This * loop should be detected and an exception should be thrown. * * @param config the configuration to test */ public static void testInterpolationLoop(Configuration config) { config.setProperty("test.a", "${test.b}"); config.setProperty("test.b", "${test.a}"); try { config.getString("test.a"); fail("IllegalStateException should have been thrown for looped property references"); } catch (IllegalStateException e) { // ok } } /** * Tests interpolation when a subset configuration is involved. * * @param config the configuration to test */ public static void testInterpolationSubset(Configuration config) { config.addProperty("test.a", new Integer(42)); config.addProperty("test.b", "${test.a}"); assertEquals("Wrong interpolated value", 42, config .getInt("test.b")); Configuration subset = config.subset("test"); assertEquals("Wrong string property", "42", subset .getString("b")); assertEquals("Wrong int property", 42, subset.getInt("b")); } /** * Tests interpolation when the referred property is not found. * * @param config the configuration to test */ public static void testInterpolationUnknownProperty(Configuration config) { config.addProperty("test.interpol", "${unknown.property}"); assertEquals("Wrong interpolated unknown property", "${unknown.property}", config.getString("test.interpol")); } /** * Tests interpolation of system properties. * * @param config the configuration to test */ public static void testInterpolationSystemProperties(Configuration config) { String[] sysProperties = { "java.version", "java.vendor", "os.name", "java.class.path" }; for (int i = 0; i < sysProperties.length; i++) { config.addProperty("prop" + i, "${sys:" + sysProperties[i] + "}"); } for (int i = 0; i < sysProperties.length; i++) { assertEquals("Wrong value for system property " + sysProperties[i], System.getProperty(sysProperties[i]), config.getString("prop" + i)); } } /** * Tests interpolation of constant values. * * @param config the configuration to test */ public static void testInterpolationConstants(Configuration config) { config.addProperty("key.code", "${const:java.awt.event.KeyEvent.VK_CANCEL}"); assertEquals("Wrong value of constant variable", KeyEvent.VK_CANCEL, config.getInt("key.code")); assertEquals("Wrong value when fetching constant from cache", KeyEvent.VK_CANCEL, config.getInt("key.code")); } /** * Tests whether a variable can be escaped, so that it won't be * interpolated. * * @param config the configuration to test */ public static void testInterpolationEscaped(Configuration config) { config.addProperty("var", "x"); config.addProperty("escVar", "Use the variable $${${var}}."); assertEquals("Wrong escaped variable", "Use the variable ${x}.", config.getString("escVar")); } /** * Tests accessing and manipulating the interpolator object. * * @param config the configuration to test */ public static void testGetInterpolator(AbstractConfiguration config) { config.addProperty("var", "${echo:testVar}"); ConfigurationInterpolator interpol = config.getInterpolator(); interpol.registerLookup("echo", new StrLookup() { @Override public String lookup(String varName) { return "Value of variable " + varName; } }); assertEquals("Wrong value of echo variable", "Value of variable testVar", config.getString("var")); } /** * Tests obtaining a configuration with all variables replaced by their * actual values. * * @param config the configuration to test * @return the interpolated configuration */ public static Configuration testInterpolatedConfiguration( AbstractConfiguration config) { config.setProperty("applicationRoot", "/home/applicationRoot"); config.setProperty("db", "${applicationRoot}/db/hypersonic"); config.setProperty("inttest.interpol", "${unknown.property}"); config.setProperty("intkey.code", "${const:java.awt.event.KeyEvent.VK_CANCEL}"); config.setProperty("inttest.sysprop", "${sys:java.version}"); config.setProperty("inttest.numvalue", "3\\,1415"); config.setProperty("inttest.value", "${inttest.numvalue}"); config.setProperty("inttest.list", "${db}"); config.addProperty("inttest.list", "${inttest.value}"); Configuration c = config.interpolatedConfiguration(); assertEquals("Property not replaced", "/home/applicationRoot/db/hypersonic", c.getProperty("db")); assertEquals("Const variable not replaced", KeyEvent.VK_CANCEL, c.getInt("intkey.code")); assertEquals("Sys property not replaced", System .getProperty("java.version"), c.getProperty("inttest.sysprop")); assertEquals("Delimiter value not replaced", "3,1415", c .getProperty("inttest.value")); List lst = (List) c.getProperty("inttest.list"); assertEquals("Wrong number of list elements", 2, lst.size()); assertEquals("List element 0 not replaced", "/home/applicationRoot/db/hypersonic", lst.get(0)); assertEquals("List element 1 not replaced", "3,1415", lst .get(1)); assertEquals("Unresolvable variable not found", "${unknown.property}", c.getProperty("inttest.interpol")); return c; } } commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/Logging.java100644 17363 12232154104 31520 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import org.apache.commons.logging.impl.Log4JLogger; import org.apache.log4j.Priority; import org.apache.log4j.Level; import org.apache.log4j.Appender; import org.apache.log4j.PatternLayout; import org.apache.log4j.ConsoleAppender; /** * Configures logging for tests. * * When running with Maven do -Dmaven.surefire.debug="LogLevel=level" to set the * Log Level to the desired value. */ public class Logging extends Log4JLogger { /** * The fully qualified name of the Log4JLogger class. */ private static final String FQCN = Logging.class.getName(); private static Priority traceLevel; static { // Releases of log4j1.2 >= 1.2.12 have Priority.TRACE available, earlier // versions do not. If TRACE is not available, then we have to map // calls to Log.trace(...) onto the DEBUG level. try { traceLevel = (Priority) Level.class.getDeclaredField("TRACE").get(null); } catch (Exception ex) { // ok, trace not available traceLevel = Priority.DEBUG; } String level = System.getProperty("LogLevel"); if (level != null) { org.apache.log4j.Logger log = org.apache.log4j.Logger.getRootLogger(); log.setLevel(Level.toLevel(level)); Appender appender = new ConsoleAppender(new PatternLayout("%p %l - %m%n"), ConsoleAppender.SYSTEM_OUT); log.addAppender(appender); } } public Logging() { super(); } /** * Base constructor. */ public Logging(String name) { super(name); } /** * For use with a log4j factory. */ public Logging(org.apache.log4j.Logger logger) { super(logger); } // --------------------------------------------------------- // Implementation // // Note that in the methods below the Priority class is used to define // levels even though the Level class is supported in 1.2. This is done // so that at compile time the call definitely resolves to a call to // a method that takes a Priority rather than one that takes a Level. // // The Category class (and hence its subclass Logging) in version 1.2 only // has methods that take Priority objects. The Category class (and hence // Logging class) in version 1.3 has methods that take both Priority and // Level objects. This means that if we use Level here, and compile // against log4j 1.3 then calls would be bound to the versions of // methods taking Level objects and then would fail to run against // version 1.2 of log4j. // --------------------------------------------------------- /** * Logs a message with org.apache.log4j.Priority.TRACE. * When using a log4j version that does not support the TRACE * level, the message will be logged at the DEBUG level. * * @param message to log * @see org.apache.commons.logging.Log#trace(Object) */ @Override public void trace(Object message) { getLogger().log(FQCN, traceLevel, message, null); } /** * Logs a message with org.apache.log4j.Priority.TRACE. * When using a log4j version that does not support the TRACE * level, the message will be logged at the DEBUG level. * * @param message to log * @param t log this cause * @see org.apache.commons.logging.Log#trace(Object, Throwable) */ @Override public void trace(Object message, Throwable t) { getLogger().log(FQCN, traceLevel, message, t); } /** * Logs a message with org.apache.log4j.Priority.DEBUG. * * @param message to log * @see org.apache.commons.logging.Log#debug(Object) */ @Override public void debug(Object message) { getLogger().log(FQCN, Priority.DEBUG, message, null); } /** * Logs a message with org.apache.log4j.Priority.DEBUG. * * @param message to log * @param t log this cause * @see org.apache.commons.logging.Log#debug(Object, Throwable) */ @Override public void debug(Object message, Throwable t) { getLogger().log(FQCN, Priority.DEBUG, message, t); } /** * Logs a message with org.apache.log4j.Priority.INFO. * * @param message to log * @see org.apache.commons.logging.Log#info(Object) */ @Override public void info(Object message) { getLogger().log(FQCN, Priority.INFO, message, null); } /** * Logs a message with org.apache.log4j.Priority.INFO. * * @param message to log * @param t log this cause * @see org.apache.commons.logging.Log#info(Object, Throwable) */ @Override public void info(Object message, Throwable t) { getLogger().log(FQCN, Priority.INFO, message, t); } /** * Logs a message with org.apache.log4j.Priority.WARN. * * @param message to log * @see org.apache.commons.logging.Log#warn(Object) */ @Override public void warn(Object message) { getLogger().log(FQCN, Priority.WARN, message, null); } /** * Logs a message with org.apache.log4j.Priority.WARN. * * @param message to log * @param t log this cause * @see org.apache.commons.logging.Log#warn(Object, Throwable) */ @Override public void warn(Object message, Throwable t) { getLogger().log(FQCN, Priority.WARN, message, t); } /** * Logs a message with org.apache.log4j.Priority.ERROR. * * @param message to log * @see org.apache.commons.logging.Log#error(Object) */ @Override public void error(Object message) { getLogger().log(FQCN, Priority.ERROR, message, null); } /** * Logs a message with org.apache.log4j.Priority.ERROR. * * @param message to log * @param t log this cause * @see org.apache.commons.logging.Log#error(Object, Throwable) */ @Override public void error(Object message, Throwable t) { getLogger().log(FQCN, Priority.ERROR, message, t); } /** * Logs a message with org.apache.log4j.Priority.FATAL. * * @param message to log * @see org.apache.commons.logging.Log#fatal(Object) */ @Override public void fatal(Object message) { getLogger().log(FQCN, Priority.FATAL, message, null); } /** * Logs a message with org.apache.log4j.Priority.FATAL. * * @param message to log * @param t log this cause * @see org.apache.commons.logging.Log#fatal(Object, Throwable) */ @Override public void fatal(Object message, Throwable t) { getLogger().log(FQCN, Priority.FATAL, message, t); } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/MockInitialContextFactory.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/MockInitialContextFact100644 21074 12232154104 33552 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Hashtable; import javax.naming.Context; import javax.naming.NameClassPair; import javax.naming.NameNotFoundException; import javax.naming.NamingEnumeration; import javax.naming.NamingException; import javax.naming.spi.InitialContextFactory; import com.mockobjects.dynamic.C; import com.mockobjects.dynamic.Mock; /** * A mock implementation of the {@code InitialContextFactory} interface. * This implementation will return a mock context that contains some test data. * * @author Commons * Configuration team * @version $Id: MockInitialContextFactory.java 1222455 2011-12-22 21:10:10Z oheger $ */ public class MockInitialContextFactory implements InitialContextFactory { /** * Constant for the use cycles environment property. If this property is * present in the environment, a cyclic context will be created. */ public static final String PROP_CYCLES = "useCycles"; /** Constant for the lookup method. */ private static final String METHOD_LOOKUP = "lookup"; /** Constant for the list method. */ private static final String METHOD_LIST = "list"; /** Constant for the close method.*/ private static final String METHOD_CLOSE = "close"; /** Constant for the name of the missing property. */ private static final String MISSING_PROP = "/missing"; /** Constant for the name of the prefix. */ private static final String PREFIX = "test/"; /** An array with the names of the supported properties. */ private static final String[] PROP_NAMES = { "key", "key2", "short", "boolean", "byte", "double", "float", "integer", "long", "onlyinjndi" }; /** An array with the values of the supported properties. */ private static final String[] PROP_VALUES = { "jndivalue", "jndivalue2", "1", "true", "10", "10.25", "20.25", "10", "1000000", "true" }; /** An array with properties that are requested, but are not in the context. */ private static final String[] MISSING_NAMES = { "missing/list", "test/imaginarykey", "foo/bar" }; /** * Creates a {@code Context} object that is backed by a mock object. * The mock context can be queried for the values of certain test * properties. It also supports listing the contained (sub) properties. * * @param env the environment * @return the context mock */ public Context getInitialContext(@SuppressWarnings("rawtypes") Hashtable env) throws NamingException { boolean useCycles = env.containsKey(PROP_CYCLES); Mock mockTopCtx = createCtxMock(PREFIX); Mock mockCycleCtx = createCtxMock(""); Mock mockPrfxCtx = createCtxMock(""); Mock mockBaseCtx = new Mock(Context.class); mockBaseCtx.matchAndReturn(METHOD_LOOKUP, C.eq(""), mockTopCtx.proxy()); mockBaseCtx.matchAndReturn(METHOD_LOOKUP, C.eq("test"), mockPrfxCtx .proxy()); mockTopCtx.matchAndReturn(METHOD_LOOKUP, C.eq("test"), mockPrfxCtx .proxy()); mockPrfxCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock( mockPrfxCtx, PROP_NAMES, PROP_VALUES).proxy()); if (useCycles) { mockTopCtx.matchAndReturn(METHOD_LOOKUP, C.eq("cycle"), mockCycleCtx.proxy()); mockTopCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock( mockTopCtx, new String[] { "test", "cycle" }, new Object[] { mockPrfxCtx.proxy(), mockCycleCtx.proxy() }).proxy()); Mock mockEnum = createEnumMock(mockCycleCtx, PROP_NAMES, PROP_VALUES, false); addEnumPair(mockEnum, "cycleCtx", mockCycleCtx.proxy()); closeEnum(mockEnum); mockCycleCtx .matchAndReturn(METHOD_LIST, C.eq(""), mockEnum.proxy()); mockCycleCtx.matchAndReturn(METHOD_LOOKUP, C.eq("cycleCtx"), mockCycleCtx.proxy()); } else { mockTopCtx.matchAndReturn(METHOD_LIST, C.eq(""), createEnumMock( mockTopCtx, new String[] { "test" }, new Object[] { mockPrfxCtx.proxy() }).proxy()); } return (Context) mockBaseCtx.proxy(); } /** * Creates a mock for a Context with the specified prefix. * * @param prefix the prefix * @return the mock for the context */ private Mock createCtxMock(String prefix) { Mock mockCtx = new Mock(Context.class); for (int i = 0; i < PROP_NAMES.length; i++) { bind(mockCtx, prefix + PROP_NAMES[i], PROP_VALUES[i]); String errProp = (prefix.length() > 0) ? PROP_NAMES[i] : PREFIX + PROP_NAMES[i]; bindError(mockCtx, errProp); } for (int i = 0; i < MISSING_NAMES.length; i++) { bindError(mockCtx, MISSING_NAMES[i]); } mockCtx.matchAndReturn("hashCode", System.identityHashCode(mockCtx.proxy())); return mockCtx; } /** * Binds a property value to the mock context. * * @param mockCtx the context * @param name the name of the property * @param value the value of the property */ private void bind(Mock mockCtx, String name, String value) { mockCtx.matchAndReturn(METHOD_LOOKUP, C.eq(name), value); bindError(mockCtx, name + MISSING_PROP); } /** * Configures the mock to expect a call for a non existing property. * * @param mockCtx the mock * @param name the name of the property */ private void bindError(Mock mockCtx, String name) { mockCtx.matchAndThrow(METHOD_LOOKUP, C.eq(name), new NameNotFoundException("unknown property")); } /** * Creates and initializes a mock for a naming enumeration. * * @param mockCtx the mock representing the context * @param names the names contained in the iteration * @param values the corresponding values * @param close a flag whether the enumeration should expect to be closed * @return the mock for the enumeration */ private Mock createEnumMock(Mock mockCtx, String[] names, Object[] values, boolean close) { Mock mockEnum = new Mock(NamingEnumeration.class); for (int i = 0; i < names.length; i++) { addEnumPair(mockEnum, names[i], values[i]); } if (close) { closeEnum(mockEnum); } return mockEnum; } /** * Creates and initializes a mock for a naming enumeration that expects to * be closed. This is a shortcut of createEnumMock(mockCtx, names, values, * true); * * @param mockCtx the mock representing the context * @param names the names contained in the iteration * @param values the corresponding values * @return the mock for the enumeration */ private Mock createEnumMock(Mock mockCtx, String[] names, Object[] values) { return createEnumMock(mockCtx, names, values, true); } /** * Adds a new name-and-value pair to an enum mock. * * @param mockEnum the enum mock * @param name the name * @param value the value */ private void addEnumPair(Mock mockEnum, String name, Object value) { NameClassPair ncp = new NameClassPair(name, value.getClass().getName()); mockEnum.expectAndReturn("hasMore", true); mockEnum.expectAndReturn("next", ncp); } /** * Closes an enumeration mock. * * @param mockEnum the mock */ private void closeEnum(Mock mockEnum) { mockEnum.expectAndReturn("hasMore", false); mockEnum.expect(METHOD_CLOSE); } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/NonCloneableConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/NonCloneableConfigurat100644 3657 12232154104 33554 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Iterator; /** * A specialized configuration implementation that does not support cloning. * This class is only used in some test cases for testing implementations of * clone() methods. It does not make much sense otherwise; all methods are just * dummies. * * @version $Id: NonCloneableConfiguration.java 1222456 2011-12-22 21:11:39Z oheger $ */ public class NonCloneableConfiguration extends AbstractConfiguration { /** * Dummy implementation of this method. */ @Override protected void addPropertyDirect(String key, Object value) { } /** * Dummy implementation of this method. */ public boolean isEmpty() { return true; } /** * Dummy implementation of this method. */ public boolean containsKey(String key) { return false; } /** * Dummy implementation of this method. */ public Iterator getKeys() { return null; } /** * Dummy implementation of this method. */ public Object getProperty(String key) { return null; } } ././@LongLink100644 0 0 147 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/NonStringTestHolder.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/NonStringTestHolder.ja100644 12542 12232154104 33514 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Iterator; import java.util.List; import junit.framework.Assert; /** * Pulling out the calls to do the tests so both JUnit and Cactus tests * can share. * * @version $Id: NonStringTestHolder.java 1302002 2012-03-17 20:43:46Z sebb $ */ public class NonStringTestHolder { private Configuration configuration; public void setConfiguration(Configuration configuration) { this.configuration = configuration; } public void testBoolean() throws Exception { boolean booleanValue = configuration.getBoolean("test.boolean"); Assert.assertTrue(booleanValue); Assert.assertEquals(1, configuration.getList("test.boolean").size()); } public void testBooleanDefaultValue() throws Exception { boolean booleanValue = configuration.getBoolean("test.boolean.missing", true); Assert.assertTrue(booleanValue); Boolean booleanObject = configuration.getBoolean("test.boolean.missing", new Boolean(true)); Assert.assertEquals(new Boolean(true), booleanObject); } public void testByte() throws Exception { byte testValue = 10; byte byteValue = configuration.getByte("test.byte"); Assert.assertEquals(testValue, byteValue); Assert.assertEquals(1, configuration.getList("test.byte").size()); } public void testDouble() throws Exception { double testValue = 10.25; double doubleValue = configuration.getDouble("test.double"); Assert.assertEquals(testValue, doubleValue, 0.01); Assert.assertEquals(1, configuration.getList("test.double").size()); } public void testDoubleDefaultValue() throws Exception { double testValue = 10.25; double doubleValue = configuration.getDouble("test.double.missing", 10.25); Assert.assertEquals(testValue, doubleValue, 0.01); } public void testFloat() throws Exception { float testValue = (float) 20.25; float floatValue = configuration.getFloat("test.float"); Assert.assertEquals(testValue, floatValue, 0.01); Assert.assertEquals(1, configuration.getList("test.float").size()); } public void testFloatDefaultValue() throws Exception { float testValue = (float) 20.25; float floatValue = configuration.getFloat("test.float.missing", testValue); Assert.assertEquals(testValue, floatValue, 0.01); } public void testInteger() throws Exception { int intValue = configuration.getInt("test.integer"); Assert.assertEquals(10, intValue); Assert.assertEquals(1, configuration.getList("test.integer").size()); } public void testIntegerDefaultValue() throws Exception { int intValue = configuration.getInt("test.integer.missing", 10); Assert.assertEquals(10, intValue); } public void testLong() throws Exception { long longValue = configuration.getLong("test.long"); Assert.assertEquals(1000000, longValue); Assert.assertEquals(1, configuration.getList("test.long").size()); } public void testLongDefaultValue() throws Exception { long longValue = configuration.getLong("test.long.missing", 1000000); Assert.assertEquals(1000000, longValue); } public void testShort() throws Exception { short shortValue = configuration.getShort("test.short"); Assert.assertEquals(1, shortValue); Assert.assertEquals(1, configuration.getList("test.short").size()); } public void testShortDefaultValue() throws Exception { short shortValue = configuration.getShort("test.short.missing", (short) 1); Assert.assertEquals(1, shortValue); } public void testListMissing() throws Exception { List list = configuration.getList("missing.list"); Assert.assertTrue("'missing.list' is not empty", list.isEmpty()); } public void testSubset() throws Exception { Configuration subset = configuration.subset("test"); // search the "short" key in the subset using the key iterator boolean foundKeyValue = false; Iterator it = subset.getKeys(); while (it.hasNext() && !foundKeyValue) { String key = it.next(); foundKeyValue = "short".equals(key); } Assert.assertTrue("'short' key not found in the subset key iterator", foundKeyValue); } public void testIsEmpty() throws Exception { Assert.assertTrue("Configuration should not be empty", !configuration.isEmpty()); } } ././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/AbstractTestPListEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/AbstractTestPLis100644 4743 12232154103 33515 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.plist; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.event.AbstractTestConfigurationEvents; import org.junit.Test; /** * A base test class for testing the events generated by the plist * configurations. This class especially checks events related to the special * handling of byte arrays. * * @version $Id: AbstractTestPListEvents.java 1225901 2011-12-30 19:37:46Z oheger $ */ public abstract class AbstractTestPListEvents extends AbstractTestConfigurationEvents { /** Constant for the name of the byte array property. */ private static final String TEST_PROPBYTE = "byteData"; /** Constant for the test byte array used for testing. */ private static final byte[] TEST_DATA = { 1, 2, 3 }; /** * Tests the events generated by an added byte array property. */ @Test public void testAddByteArrayPropertyEvent() { config.addProperty(TEST_PROPBYTE, TEST_DATA); l.checkEvent(AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_PROPBYTE, TEST_DATA, true); l.checkEvent(AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_PROPBYTE, TEST_DATA, false); l.done(); } /** * Tests the events generated by setting a byte array property. */ @Test public void testSetByteArrayPropertyEvent() { config.setProperty(TEST_PROPBYTE, TEST_DATA); l.checkEvent(AbstractConfiguration.EVENT_SET_PROPERTY, TEST_PROPBYTE, TEST_DATA, true); l.checkEvent(AbstractConfiguration.EVENT_SET_PROPERTY, TEST_PROPBYTE, TEST_DATA, false); l.done(); } } ././@LongLink100644 0 0 167 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestPropertyListConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestPropertyList100644 34443 12232154103 33662 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.plist; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.StringReader; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.TimeZone; import junitx.framework.ArrayAssert; import junitx.framework.ListAssert; import junitx.framework.ObjectAssert; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationAssert; import org.apache.commons.configuration.ConfigurationComparator; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.StrictConfigurationComparator; import org.junit.Before; import org.junit.Test; /** * @author Emmanuel Bourg * @version $Id: TestPropertyListConfiguration.java 1225902 2011-12-30 19:46:24Z oheger $ */ public class TestPropertyListConfiguration { private PropertyListConfiguration config; private String testProperties = ConfigurationAssert.getTestFile("test.plist").getAbsolutePath(); @Before public void setUp() throws Exception { config = new PropertyListConfiguration(); config.setFileName(testProperties); config.load(); } @Test public void testLoad() { assertFalse("the configuration is empty", config.isEmpty()); } @Test public void testLoadWithError() { config = new PropertyListConfiguration(); try { config.load(new StringReader("")); fail("No exception thrown on loading an empty file"); } catch (ConfigurationException e) { // expected assertNotNull(e.getMessage()); } } @Test public void testString() { assertEquals("simple-string", "string1", config.getProperty("simple-string")); } @Test public void testQuotedString() { assertEquals("quoted-string", "string2", config.getProperty("quoted-string")); assertEquals("quoted-string2", "this is a string", config.getProperty("quoted-string2")); assertEquals("complex-string", "this is a \"complex\" string {(=,;)}", config.getProperty("complex-string")); } @Test public void testEmptyArray() { String key = "empty-array"; assertNotNull("array null", config.getProperty(key)); List list = (List) config.getProperty(key); assertTrue("array is not empty", list.isEmpty()); } @Test public void testArray() { String key = "array"; assertNotNull("array null", config.getProperty(key)); List list = (List) config.getProperty(key); assertFalse("array is empty", list.isEmpty()); assertEquals("1st value", "value1", list.get(0)); assertEquals("2nd value", "value2", list.get(1)); assertEquals("3rd value", "value3", list.get(2)); } @Test public void testNestedArrays() { String key = "nested-arrays"; Object array = config.getProperty(key); // root array assertNotNull("array not found", array); ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array); List list = config.getList(key); assertFalse("empty array", list.isEmpty()); assertEquals("size", 2, list.size()); // 1st array ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, list.get(0)); List list1 = (List) list.get(0); assertFalse("nested array 1 is empty", list1.isEmpty()); assertEquals("size", 2, list1.size()); assertEquals("1st element", "a", list1.get(0)); assertEquals("2nd element", "b", list1.get(1)); // 2nd array ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, list.get(1)); List list2 = (List) list.get(1); assertFalse("nested array 2 is empty", list2.isEmpty()); assertEquals("size", 2, list2.size()); assertEquals("1st element", "c", list2.get(0)); assertEquals("2nd element", "d", list2.get(1)); } @Test public void testDictionary() { assertEquals("1st element in dictionary", "bar1", config.getProperty("dictionary.foo1")); assertEquals("2nd element in dictionary", "bar2", config.getProperty("dictionary.foo2")); } @Test public void testDictionaryArray() { String key = "dictionary-array"; Object array = config.getProperty(key); // root array assertNotNull("array not found", array); ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array); List list = config.getList(key); assertFalse("empty array", list.isEmpty()); assertEquals("size", 2, list.size()); // 1st dictionary ObjectAssert.assertInstanceOf("the dict element is not parsed as a Configuration", Configuration.class, list.get(0)); Configuration conf1 = (Configuration) list.get(0); assertFalse("configuration 1 is empty", conf1.isEmpty()); assertEquals("configuration element", "bar", conf1.getProperty("foo")); // 2nd dictionary ObjectAssert.assertInstanceOf("the dict element is not parsed as a Configuration", Configuration.class, list.get(1)); Configuration conf2 = (Configuration) list.get(1); assertFalse("configuration 2 is empty", conf2.isEmpty()); assertEquals("configuration element", "value", conf2.getProperty("key")); } @Test public void testNestedDictionaries() { assertEquals("nested property", "value", config.getString("nested-dictionaries.foo.bar.key")); } @Test public void testData() { ObjectAssert.assertInstanceOf("data", (new byte[0]).getClass(), config.getProperty("data")); ArrayAssert.assertEquals("data", "foo bar".getBytes(), (byte[]) config.getProperty("data")); } @Test public void testDate() throws Exception { Calendar cal = Calendar.getInstance(); cal.clear(); cal.set(2002, 2, 22, 11, 30, 0); cal.setTimeZone(TimeZone.getTimeZone("GMT+0100")); Date date = cal.getTime(); assertEquals("date", date, config.getProperty("date")); } @Test public void testSave() throws Exception { File savedFile = new File("target/testsave.plist"); // remove the file previously saved if necessary if (savedFile.exists()) { assertTrue(savedFile.delete()); } // save the configuration String filename = savedFile.getAbsolutePath(); config.save(filename); assertTrue("The saved file doesn't exist", savedFile.exists()); // read the configuration and compare the properties Configuration checkConfig = new PropertyListConfiguration(new File(filename)); Iterator it = config.getKeys(); while (it.hasNext()) { String key = it.next(); assertTrue("The saved configuration doesn't contain the key '" + key + "'", checkConfig.containsKey(key)); Object value = checkConfig.getProperty(key); if (value instanceof byte[]) { byte[] array = (byte[]) value; ArrayAssert.assertEquals("Value of the '" + key + "' property", (byte[]) config.getProperty(key), array); } else if (value instanceof List) { List list1 = (List) config.getProperty(key); List list2 = (List) value; assertEquals("The size of the list for the key '" + key + "' doesn't match", list1.size(), list2.size()); for (int i = 0; i < list2.size(); i++) { Object value1 = list1.get(i); Object value2 = list2.get(i); if (value1 instanceof Configuration) { ConfigurationComparator comparator = new StrictConfigurationComparator(); assertTrue("The dictionnary at index " + i + " for the key '" + key + "' doesn't match", comparator.compare((Configuration) value1, (Configuration) value2)); } else { assertEquals("Element at index " + i + " for the key '" + key + "'", value1, value2); } } ListAssert.assertEquals("Value of the '" + key + "' property", (List) config.getProperty(key), list1); } else { assertEquals("Value of the '" + key + "' property", config.getProperty(key), checkConfig.getProperty(key)); } } } @Test public void testSaveEmptyDictionary() throws Exception { File savedFile = new File("target/testsave.plist"); // remove the file previously saved if necessary if (savedFile.exists()) { assertTrue(savedFile.delete()); } // save the configuration String filename = savedFile.getAbsolutePath(); config.save(filename); assertTrue("The saved file doesn't exist", savedFile.exists()); // read the configuration and compare the properties PropertyListConfiguration checkConfig = new PropertyListConfiguration(new File(filename)); assertFalse(config.getRootNode().getChildren("empty-dictionary").isEmpty()); assertFalse(checkConfig.getRootNode().getChildren("empty-dictionary").isEmpty()); } @Test public void testQuoteString() { assertEquals("null string", null, config.quoteString(null)); assertEquals("simple string", "abcd", config.quoteString("abcd")); assertEquals("string with a space", "\"ab cd\"", config.quoteString("ab cd")); assertEquals("string with a quote", "\"foo\\\"bar\"", config.quoteString("foo\"bar")); assertEquals("string with a special char", "\"foo;bar\"", config.quoteString("foo;bar")); } /** * Ensure that setProperty doesn't alter an array of byte * since it's a first class type in plist file */ @Test public void testSetDataProperty() throws Exception { byte[] expected = new byte[]{1, 2, 3, 4}; PropertyListConfiguration config = new PropertyListConfiguration(); config.setProperty("foo", expected); config.save("target/testdata.plist"); PropertyListConfiguration config2 = new PropertyListConfiguration("target/testdata.plist"); Object array = config2.getProperty("foo"); assertNotNull("data not found", array); assertEquals("property type", byte[].class, array.getClass()); ArrayAssert.assertEquals(expected, (byte[]) array); } /** * Ensure that addProperty doesn't alter an array of byte */ @Test public void testAddDataProperty() throws Exception { byte[] expected = new byte[]{1, 2, 3, 4}; PropertyListConfiguration config = new PropertyListConfiguration(); config.addProperty("foo", expected); config.save("target/testdata.plist"); PropertyListConfiguration config2 = new PropertyListConfiguration("target/testdata.plist"); Object array = config2.getProperty("foo"); assertNotNull("data not found", array); assertEquals("property type", byte[].class, array.getClass()); ArrayAssert.assertEquals(expected, (byte[]) array); } @Test public void testInitCopy() { PropertyListConfiguration copy = new PropertyListConfiguration(config); assertFalse("Nothing was copied", copy.isEmpty()); } /** * Tests parsing a date with an invalid numeric value. */ @Test(expected = ParseException.class) public void testParseDateNoNumber() throws ParseException { PropertyListConfiguration .parseDate("<*D2002-03-22 1c:30:00 +0100>"); } /** * Tests parsing a date that is not long enough. */ @Test(expected = ParseException.class) public void testParseDateTooShort() throws ParseException { PropertyListConfiguration.parseDate("<*D2002-03-22 11:3>"); } /** * Tests parsing a date that contains an invalid separator character. */ @Test(expected = ParseException.class) public void testParseDateInvalidChar() throws ParseException { PropertyListConfiguration .parseDate("<*D2002+03-22 11:30:00 +0100>"); } /** * Tries parsing a null date. This should cause an exception.n */ @Test(expected = ParseException.class) public void testParseDateNull() throws ParseException { PropertyListConfiguration.parseDate(null); } /** * Tests formatting a date. */ @Test public void testFormatDate() { Calendar cal = Calendar.getInstance(); cal.clear(); cal.set(2007, 9, 29, 23, 4, 30); cal.setTimeZone(TimeZone.getTimeZone("GMT-0230")); assertEquals("Wrong date literal (1)", "<*D2007-10-29 23:04:30 -0230>", PropertyListConfiguration.formatDate(cal)); cal.clear(); cal.set(2007, 9, 30, 22, 2, 15); cal.setTimeZone(TimeZone.getTimeZone("GMT+1111")); assertEquals("Wrong date literal (2)", "<*D2007-10-30 22:02:15 +1111>", PropertyListConfiguration.formatDate(cal)); } } ././@LongLink100644 0 0 175 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestPropertyListConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestPropertyList100644 3351 12232154103 33634 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.plist; import java.io.File; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.ConfigurationRuntimeException; /** * Test class for the events generated by PropertyListConfiguration. * * @version $Id: TestPropertyListConfigurationEvents.java 1301994 2012-03-17 20:21:23Z sebb $ */ public class TestPropertyListConfigurationEvents extends AbstractTestPListEvents { /** Constant for the test file that will be loaded. */ private static final File TEST_FILE = new File("conf/test.plist"); @Override protected AbstractConfiguration createConfiguration() { try { return new PropertyListConfiguration(TEST_FILE); } catch (ConfigurationException cex) { throw new ConfigurationRuntimeException(cex); } } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestPropertyListParser.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestPropertyList100644 6150 12232154103 33634 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.plist; import static org.junit.Assert.assertEquals; import java.io.Reader; import java.util.Calendar; import java.util.SimpleTimeZone; import junitx.framework.ArrayAssert; import org.junit.Test; /** * @author Emmanuel Bourg * @version $Id: TestPropertyListParser.java 1225903 2011-12-30 19:49:15Z oheger $ */ public class TestPropertyListParser { private PropertyListParser parser = new PropertyListParser((Reader) null); @Test public void testRemoveQuotes() { assertEquals("unquoted string", "abc", parser.removeQuotes("abc")); assertEquals("quoted string", "abc", parser.removeQuotes("\"abc\"")); assertEquals("empty quotes", "", parser.removeQuotes("\"\"")); assertEquals("empty string", "", parser.removeQuotes("")); assertEquals("null string", null, parser.removeQuotes(null)); } @Test public void testUnescapeQuotes() { assertEquals("non escaped quotes", "aaa\"bbb\"ccc", parser.unescapeQuotes("aaa\"bbb\"ccc")); assertEquals("escaped quotes", "aaa\"bbb\"ccc", parser.unescapeQuotes("aaa\\\"bbb\\\"ccc")); } @Test public void testParseDate() throws Exception { Calendar calendar = Calendar.getInstance(); calendar.set(Calendar.YEAR, 2002); calendar.set(Calendar.MONTH, Calendar.MARCH); calendar.set(Calendar.DAY_OF_MONTH, 22); calendar.set(Calendar.HOUR_OF_DAY, 11); calendar.set(Calendar.MINUTE, 30); calendar.set(Calendar.SECOND, 0); calendar.set(Calendar.MILLISECOND, 0); calendar.setTimeZone(new SimpleTimeZone(60 * 60 * 1000, "Apache/Jakarta")); assertEquals("parsed date", calendar.getTime(), parser.parseDate("<*D2002-03-22 11:30:00 +0100>")); } @Test public void testFilterData() throws Exception { byte[] expected = new byte[] {0x20, 0x20}; ArrayAssert.assertEquals("null string", null, parser.filterData(null)); ArrayAssert.assertEquals("data with < >", expected, parser.filterData("<2020>")); ArrayAssert.assertEquals("data without < >", expected, parser.filterData("2020")); ArrayAssert.assertEquals("data with space", expected, parser.filterData("20 20")); ArrayAssert.assertEquals("odd length", new byte[]{9, 0x20}, parser.filterData("920")); } } ././@LongLink100644 0 0 172 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestXMLPropertyListConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestXMLPropertyL100644 35241 12232154103 33520 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.plist; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.util.Calendar; import java.util.Iterator; import java.util.List; import java.util.TimeZone; import junitx.framework.ArrayAssert; import junitx.framework.ListAssert; import junitx.framework.ObjectAssert; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationAssert; import org.apache.commons.configuration.ConfigurationComparator; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.FileConfiguration; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.StrictConfigurationComparator; import org.junit.Before; import org.junit.Test; /** * @author Emmanuel Bourg * @version $Id: TestXMLPropertyListConfiguration.java 1367253 2012-07-30 19:59:36Z oheger $ */ public class TestXMLPropertyListConfiguration { private FileConfiguration config; @Before public void setUp() throws Exception { config = new XMLPropertyListConfiguration(); config.setFile(ConfigurationAssert.getTestFile("test.plist.xml")); config.load(); } @Test public void testString() throws Exception { assertEquals("'string' property", "value1", config.getString("string")); } @Test public void testInteger() throws Exception { assertEquals("'integer' property", 12345678900L, config.getLong("integer")); } @Test public void testReal() throws Exception { assertEquals("'real' property", -12.345, config.getDouble("real"), 0); } @Test public void testBoolean() throws Exception { assertEquals("'boolean1' property", true, config.getBoolean("boolean1")); assertEquals("'boolean2' property", false, config.getBoolean("boolean2")); } @Test public void testDictionary() { assertEquals("1st element", "value1", config.getProperty("dictionary.key1")); assertEquals("2nd element", "value2", config.getProperty("dictionary.key2")); assertEquals("3rd element", "value3", config.getProperty("dictionary.key3")); } @Test public void testDate() throws Exception { Calendar calendar = Calendar.getInstance(); calendar.clear(); calendar.setTimeZone(TimeZone.getTimeZone("UTC")); calendar.set(2005, Calendar.JANUARY, 1, 12, 0, 0); assertEquals("'date' property", calendar.getTime(), config.getProperty("date")); calendar.setTimeZone(TimeZone.getTimeZone("CET")); calendar.set(2002, Calendar.MARCH, 22, 11, 30, 0); assertEquals("'date-gnustep' property", calendar.getTime(), config.getProperty("date-gnustep")); } @Test public void testSubset() { Configuration subset = config.subset("dictionary"); Iterator keys = subset.getKeys(); String key = keys.next(); assertEquals("1st key", "key1", key); assertEquals("1st value", "value1", subset.getString(key)); key = keys.next(); assertEquals("2nd key", "key2", key); assertEquals("2nd value", "value2", subset.getString(key)); key = keys.next(); assertEquals("3rd key", "key3", key); assertEquals("3rd value", "value3", subset.getString(key)); assertFalse("more than 3 properties founds", keys.hasNext()); } @Test public void testArray() { Object array = config.getProperty("array"); assertNotNull("array not found", array); ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array); List list = config.getList("array"); assertFalse("empty array", list.isEmpty()); assertEquals("size", 3, list.size()); assertEquals("1st element", "value1", list.get(0)); assertEquals("2nd element", "value2", list.get(1)); assertEquals("3rd element", "value3", list.get(2)); } @Test public void testNestedArray() { String key = "nested-array"; Object array = config.getProperty(key); // root array assertNotNull("array not found", array); ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array); List list = config.getList(key); assertFalse("empty array", list.isEmpty()); assertEquals("size", 2, list.size()); // 1st array ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, list.get(0)); List list1 = (List) list.get(0); assertFalse("nested array 1 is empty", list1.isEmpty()); assertEquals("size", 2, list1.size()); assertEquals("1st element", "a", list1.get(0)); assertEquals("2nd element", "b", list1.get(1)); // 2nd array ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, list.get(1)); List list2 = (List) list.get(1); assertFalse("nested array 2 is empty", list2.isEmpty()); assertEquals("size", 2, list2.size()); assertEquals("1st element", "c", list2.get(0)); assertEquals("2nd element", "d", list2.get(1)); } @Test public void testDictionaryArray() { String key = "dictionary-array"; Object array = config.getProperty(key); // root array assertNotNull("array not found", array); ObjectAssert.assertInstanceOf("the array element is not parsed as a List", List.class, array); List list = config.getList(key); assertFalse("empty array", list.isEmpty()); assertEquals("size", 2, list.size()); // 1st dictionary ObjectAssert.assertInstanceOf("the dict element is not parsed as a Configuration", Configuration.class, list.get(0)); Configuration conf1 = (Configuration) list.get(0); assertFalse("configuration 1 is empty", conf1.isEmpty()); assertEquals("configuration element", "bar", conf1.getProperty("foo")); // 2nd dictionary ObjectAssert.assertInstanceOf("the dict element is not parsed as a Configuration", Configuration.class, list.get(1)); Configuration conf2 = (Configuration) list.get(1); assertFalse("configuration 2 is empty", conf2.isEmpty()); assertEquals("configuration element", "value", conf2.getProperty("key")); } @Test public void testNested() { assertEquals("nested property", "value", config.getString("nested.node1.node2.node3")); } @Test public void testSave() throws Exception { File savedFile = new File("target/testsave.plist.xml"); // remove the file previously saved if necessary if (savedFile.exists()) { assertTrue(savedFile.delete()); } // add an array of strings to the configuration /* config.addProperty("string", "value1"); List list = new ArrayList(); for (int i = 1; i < 5; i++) { list.add("value" + i); } config.addProperty("newarray", list);*/ // todo : investigate why the array structure of 'newarray' is lost in the saved file // add a map of strings /* Map map = new HashMap(); map.put("foo", "bar"); map.put("int", new Integer(123)); config.addProperty("newmap", map); */ // todo : a Map added to a HierarchicalConfiguration should be decomposed as list of nodes // save the configuration String filename = savedFile.getAbsolutePath(); config.save(filename); assertTrue("The saved file doesn't exist", savedFile.exists()); // read the configuration and compare the properties Configuration checkConfig = new XMLPropertyListConfiguration(new File(filename)); Iterator it = config.getKeys(); while (it.hasNext()) { String key = it.next(); assertTrue("The saved configuration doesn't contain the key '" + key + "'", checkConfig.containsKey(key)); Object value = checkConfig.getProperty(key); if (value instanceof byte[]) { byte[] array = (byte[]) value; ArrayAssert.assertEquals("Value of the '" + key + "' property", (byte[]) config.getProperty(key), array); } else if (value instanceof List) { List list1 = (List) config.getProperty(key); List list2 = (List) value; assertEquals("The size of the list for the key '" + key + "' doesn't match", list1.size(), list2.size()); for (int i = 0; i < list2.size(); i++) { Object value1 = list1.get(i); Object value2 = list2.get(i); if (value1 instanceof Configuration) { ConfigurationComparator comparator = new StrictConfigurationComparator(); assertTrue("The dictionnary at index " + i + " for the key '" + key + "' doesn't match", comparator.compare((Configuration) value1, (Configuration) value2)); } else { assertEquals("Element at index " + i + " for the key '" + key + "'", value1, value2); } } ListAssert.assertEquals("Value of the '" + key + "' property", (List) config.getProperty(key), list1); } else { assertEquals("Value of the '" + key + "' property", config.getProperty(key), checkConfig.getProperty(key)); } } } @Test public void testSaveEmptyDictionary() throws Exception { File savedFile = new File("target/testsave.plist.xml"); // remove the file previously saved if necessary if (savedFile.exists()) { assertTrue(savedFile.delete()); } // save the configuration String filename = savedFile.getAbsolutePath(); config.save(filename); assertTrue("The saved file doesn't exist", savedFile.exists()); // read the configuration and compare the properties Configuration checkConfig = new XMLPropertyListConfiguration(new File(filename)); assertEquals(null, config.getProperty("empty-dictionary")); assertEquals(null, checkConfig.getProperty("empty-dictionary")); } /** * Ensure that setProperty doesn't alter an array of byte * since it's a first class type in plist file */ @Test public void testSetDataProperty() throws Exception { byte[] expected = new byte[]{1, 2, 3, 4}; XMLPropertyListConfiguration config = new XMLPropertyListConfiguration(); config.setProperty("foo", expected); config.save("target/testdata.plist.xml"); XMLPropertyListConfiguration config2 = new XMLPropertyListConfiguration("target/testdata.plist.xml"); Object array = config2.getProperty("foo"); assertNotNull("data not found", array); assertEquals("property type", byte[].class, array.getClass()); ArrayAssert.assertEquals(expected, (byte[]) array); } /** * Ensure that addProperty doesn't alter an array of byte */ @Test public void testAddDataProperty() throws Exception { byte[] expected = new byte[]{1, 2, 3, 4}; XMLPropertyListConfiguration config = new XMLPropertyListConfiguration(); config.addProperty("foo", expected); config.save("target/testdata.plist.xml"); XMLPropertyListConfiguration config2 = new XMLPropertyListConfiguration("target/testdata.plist.xml"); Object array = config2.getProperty("foo"); assertNotNull("data not found", array); assertEquals("property type", byte[].class, array.getClass()); ArrayAssert.assertEquals(expected, (byte[]) array); } @Test public void testInitCopy() { XMLPropertyListConfiguration copy = new XMLPropertyListConfiguration((HierarchicalConfiguration) config); StrictConfigurationComparator comp = new StrictConfigurationComparator(); assertTrue("Configurations are not equal", comp.compare(config, copy)); } /** * Tests whether a configuration can be loaded that does not start with a * {@code dict} element. This test case is related to * CONFIGURATION-405. */ @Test public void testLoadNoDict() throws ConfigurationException { XMLPropertyListConfiguration plist = new XMLPropertyListConfiguration(); plist.setFile(ConfigurationAssert.getTestFile("test2.plist.xml")); plist.load(); assertFalse("Configuration is empty", plist.isEmpty()); } /** * Tests whether a configuration that does not start with a * {@code dict} element can be loaded from a constructor. This test * case is related to CONFIGURATION-405. */ @Test public void testLoadNoDictConstr() throws ConfigurationException { XMLPropertyListConfiguration plist = new XMLPropertyListConfiguration( ConfigurationAssert.getTestFile("test2.plist.xml")); assertFalse("Configuration is empty", plist.isEmpty()); } /** * Tests a configuration file which contains an invalid date property value. * This test is related to CONFIGURATION-501. */ @Test public void testSetDatePropertyInvalid() throws ConfigurationException { config.clear(); config.setFile(ConfigurationAssert.getTestFile("test_invalid_date.plist.xml")); config.load(); assertEquals("'string' property", "value1", config.getString("string")); assertFalse("Date property was loaded", config.containsKey("date")); } } ././@LongLink100644 0 0 200 12232154257 10246 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestXMLPropertyListConfigurationEvents.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/TestXMLPropertyL100644 3370 12232154103 33476 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.plist; import java.io.File; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.ConfigurationRuntimeException; /** * Test class for the events generated by XMLPropertyListConfiguration. * * @version $Id: TestXMLPropertyListConfigurationEvents.java 1301994 2012-03-17 20:21:23Z sebb $ */ public class TestXMLPropertyListConfigurationEvents extends AbstractTestPListEvents { /** Constant for the test file that will be loaded. */ private static final File TEST_FILE = new File("conf/test.plist.xml"); @Override protected AbstractConfiguration createConfiguration() { try { return new XMLPropertyListConfiguration(TEST_FILE); } catch (ConfigurationException cex) { throw new ConfigurationRuntimeException(cex); } } } ././@LongLink100644 0 0 171 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/FileAlwaysReloadingStrategy.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/FileAlwaysRe100644 3243 12232154103 33454 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import java.io.File; /** * A specialized reloading strategy for files that will always report a change * of the monitored file. Thus it is well suited for testing reloading * operations on file-based configurations. * * @version $Id: FileAlwaysReloadingStrategy.java 1301995 2012-03-17 20:24:16Z sebb $ */ public class FileAlwaysReloadingStrategy extends FileChangedReloadingStrategy { /** * Checks whether a reload is necessary. This implementation returns always * true. * * @return a flag whether a reload is required */ @Override public boolean reloadingRequired() { return true; } /** * Returns the file that is watched by this strategy. * * @return the monitored file */ public File getMonitoredFile() { return getFile(); } } ././@LongLink100644 0 0 171 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/FileRandomReloadingStrategy.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/FileRandomRe100644 4626 12232154103 33442 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.io.File; import java.util.Random; /** * A ReloadingStrategy that randomly returns true or false; */ public class FileRandomReloadingStrategy extends FileChangedReloadingStrategy { Random random = new Random(); /** The Log to use for diagnostic messages */ private Log logger = LogFactory.getLog(FileRandomReloadingStrategy.class); /** * Checks whether a reload is necessary. * * @return a flag whether a reload is required */ @Override public boolean reloadingRequired() { boolean result = random.nextBoolean(); if (result) { if (logger.isDebugEnabled()) { logger.debug("File change detected: " + getName()); } } return result; } /** * Returns the file that is watched by this strategy. * * @return the monitored file */ public File getMonitoredFile() { return getFile(); } private String getName() { return getName(getFile()); } private String getName(File file) { String name = configuration.getURL().toString(); if (name == null) { if (file != null) { name = file.getAbsolutePath(); } else { name = "base: " + configuration.getBasePath() + "file: " + configuration.getFileName(); } } return name; } } ././@LongLink100644 0 0 176 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/TestFileChangedReloadingStrategy.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/TestFileChan100644 17711 12232154103 33463 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileWriter; import java.net.URL; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.apache.log4j.Appender; import org.apache.log4j.Layout; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.PatternLayout; import org.apache.log4j.WriterAppender; import org.junit.Test; /** * Test case for the ReloadableConfiguration class. * * @author Emmanuel Bourg * @version $Id: TestFileChangedReloadingStrategy.java 1225906 2011-12-30 20:01:37Z oheger $ */ public class TestFileChangedReloadingStrategy { /** Constant for the name of a test properties file.*/ private static final String TEST_FILE = "test.properties"; @Test public void testAutomaticReloading() throws Exception { // create a new configuration File file = new File("target/testReload.properties"); if (file.exists()) { file.delete(); } // create the configuration file FileWriter out = new FileWriter(file); out.write("string=value1"); out.flush(); out.close(); // load the configuration PropertiesConfiguration config = new PropertiesConfiguration("target/testReload.properties"); FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy(); strategy.setRefreshDelay(500); config.setReloadingStrategy(strategy); assertEquals("Initial value", "value1", config.getString("string")); Thread.sleep(2000); // change the file out = new FileWriter(file); out.write("string=value2"); out.flush(); out.close(); // test the automatic reloading assertEquals("Modified value with enabled reloading", "value2", config.getString("string")); } @Test public void testNewFileReloading() throws Exception { // create a new configuration File file = new File("target/testReload.properties"); if (file.exists()) { file.delete(); } PropertiesConfiguration config = new PropertiesConfiguration(); config.setFile(file); FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy(); strategy.setRefreshDelay(500); config.setReloadingStrategy(strategy); assertNull("Initial value", config.getString("string")); // change the file FileWriter out = new FileWriter(file); out.write("string=value1"); out.flush(); out.close(); Thread.sleep(2000); // test the automatic reloading assertEquals("Modified value with enabled reloading", "value1", config.getString("string")); } @Test public void testGetRefreshDelay() { FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy(); strategy.setRefreshDelay(500); assertEquals("refresh delay", 500, strategy.getRefreshDelay()); } /** * Tests if a file from the classpath can be monitored. */ @Test public void testFromClassPath() throws Exception { PropertiesConfiguration config = new PropertiesConfiguration(); config.setFileName(TEST_FILE); config.load(); assertTrue(config.getBoolean("configuration.loaded")); FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy(); config.setReloadingStrategy(strategy); assertEquals(config.getURL().toExternalForm(), strategy.getFile().toURI().toURL().toExternalForm()); } /** * Tests to watch a configuration file in a jar. In this case the jar file * itself should be monitored. */ @Test public void testFromJar() throws Exception { XMLConfiguration config = new XMLConfiguration(); // use some jar: URL config.setURL(new URL("jar:" + new File("conf/resources.jar").getAbsoluteFile().toURI().toURL() + "!/test-jar.xml")); FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy(); config.setReloadingStrategy(strategy); File file = strategy.getFile(); assertNotNull("Strategy's file is null", file); assertEquals("Strategy does not monitor the jar file", "resources.jar", file.getName()); } /** * Tests calling reloadingRequired() multiple times before a reload actually * happens. This test is related to CONFIGURATION-302. */ @Test public void testReloadingRequiredMultipleTimes() throws ConfigurationException { FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy() { @Override protected boolean hasChanged() { // signal always a change return true; } }; strategy.setRefreshDelay(100000); PropertiesConfiguration config = new PropertiesConfiguration(TEST_FILE); config.setReloadingStrategy(strategy); assertTrue("Reloading not required", strategy.reloadingRequired()); assertTrue("Reloading no more required", strategy.reloadingRequired()); strategy.reloadingPerformed(); assertFalse("Reloading still required", strategy.reloadingRequired()); } @Test public void testFileDeletion() throws Exception { Logger logger = Logger.getLogger(FileChangedReloadingStrategy.class.getName()); Layout layout = new PatternLayout("%p - %m%n"); ByteArrayOutputStream os = new ByteArrayOutputStream(); Appender appender = new WriterAppender(layout, os); logger.addAppender(appender); logger.setLevel(Level.WARN); logger.setAdditivity(false); // create a new configuration File file = new File("target/testReload.properties"); if (file.exists()) { file.delete(); } // create the configuration file FileWriter out = new FileWriter(file); out.write("string=value1"); out.flush(); out.close(); // load the configuration PropertiesConfiguration config = new PropertiesConfiguration("target/testReload.properties"); FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy(); strategy.setRefreshDelay(500); config.setReloadingStrategy(strategy); assertEquals("Initial value", "value1", config.getString("string")); Thread.sleep(2000); // Delete the file. file.delete(); //Old value should still be returned. assertEquals("Initial value", "value1", config.getString("string")); logger.removeAppender(appender); String str = os.toString(); //System.out.println(str); assertTrue("No error was logged", str != null && str.length() > 0); } } ././@LongLink100644 0 0 172 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/TestManagedReloadingStrategy.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/TestManagedR100644 4514 12232154103 33445 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import static org.junit.Assert.assertEquals; import java.io.File; import java.io.FileWriter; import org.apache.commons.configuration.PropertiesConfiguration; import org.junit.Test; /** * Test case for the ManagedReloadingStrategy class. * * @author Nicolas De loof * @version $Id: TestManagedReloadingStrategy.java 1225908 2011-12-30 20:04:48Z oheger $ */ public class TestManagedReloadingStrategy { @Test public void testManagedRefresh() throws Exception { File file = new File("target/testReload.properties"); if (file.exists()) { file.delete(); } // create the configuration file FileWriter out = new FileWriter(file); out.write("string=value1"); out.flush(); out.close(); // load the configuration PropertiesConfiguration config = new PropertiesConfiguration("target/testReload.properties"); ManagedReloadingStrategy strategy = new ManagedReloadingStrategy(); config.setReloadingStrategy(strategy); assertEquals("Initial value", "value1", config.getString("string")); // change the file out = new FileWriter(file); out.write("string=value2"); out.flush(); out.close(); // test the automatic reloading assertEquals("No automatic reloading", "value1", config.getString("string")); strategy.refresh(); assertEquals("Modified value with enabled reloading", "value2", config.getString("string")); } } ././@LongLink100644 0 0 201 12232154257 10247 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/TestVFSFileChangedReloadingStrategy.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/TestVFSFileC100644 12303 12232154103 33343 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.reloading; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileWriter; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.FileSystem; import org.apache.commons.configuration.PropertiesConfiguration; import org.apache.commons.configuration.VFSFileSystem; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test case for the VFSFileMonitorReloadingStrategy class. * * @author Ralph Goers * @version $Id: TestVFSFileChangedReloadingStrategy.java 1225909 2011-12-30 20:09:00Z oheger $ */ public class TestVFSFileChangedReloadingStrategy { /** Constant for the name of a test properties file.*/ private static final String TEST_FILE = "test.properties"; @Before public void setUp() throws Exception { FileSystem.setDefaultFileSystem(new VFSFileSystem()); } @After public void tearDown() throws Exception { FileSystem.resetDefaultFileSystem(); } @Test public void testAutomaticReloading() throws Exception { // create a new configuration File file = new File("target/testReload.properties"); if (file.exists()) { file.delete(); } // create the configuration file FileWriter out = new FileWriter(file); out.write("string=value1"); out.flush(); out.close(); // load the configuration PropertiesConfiguration config = new PropertiesConfiguration("target/testReload.properties"); VFSFileChangedReloadingStrategy strategy = new VFSFileChangedReloadingStrategy(); strategy.setRefreshDelay(500); config.setReloadingStrategy(strategy); assertEquals("Initial value", "value1", config.getString("string")); Thread.sleep(2000); // change the file out = new FileWriter(file); out.write("string=value2"); out.flush(); out.close(); // test the automatic reloading assertEquals("Modified value with enabled reloading", "value2", config.getString("string")); } @Test public void testNewFileReloading() throws Exception { // create a new configuration File file = new File("target/testReload.properties"); if (file.exists()) { file.delete(); } PropertiesConfiguration config = new PropertiesConfiguration(); config.setFile(file); VFSFileChangedReloadingStrategy strategy = new VFSFileChangedReloadingStrategy(); strategy.setRefreshDelay(500); config.setReloadingStrategy(strategy); assertNull("Initial value", config.getString("string")); // change the file FileWriter out = new FileWriter(file); out.write("string=value1"); out.flush(); out.close(); Thread.sleep(2000); // test the automatic reloading assertEquals("Modified value with enabled reloading", "value1", config.getString("string")); } @Test public void testGetRefreshDelay() throws Exception { VFSFileChangedReloadingStrategy strategy = new VFSFileChangedReloadingStrategy(); strategy.setRefreshDelay(500); assertEquals("refresh delay", 500, strategy.getRefreshDelay()); } /** * Tests calling reloadingRequired() multiple times before a reload actually * happens. This test is related to CONFIGURATION-302. */ @Test public void testReloadingRequiredMultipleTimes() throws ConfigurationException { VFSFileChangedReloadingStrategy strategy = new VFSFileChangedReloadingStrategy() { @Override protected boolean hasChanged() { // signal always a change return true; } }; strategy.setRefreshDelay(100000); PropertiesConfiguration config = new PropertiesConfiguration(TEST_FILE); config.setReloadingStrategy(strategy); assertTrue("Reloading not required", strategy.reloadingRequired()); assertTrue("Reloading no more required", strategy.reloadingRequired()); strategy.reloadingPerformed(); assertFalse("Reloading still required", strategy.reloadingRequired()); } }commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/test/HsqlDB.java100644 6504 12232154103 32200 0ustarhenningstaff 0 0 package org.apache.commons.configuration.test; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import java.io.FileReader; import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Stolen from Turbine * * @author Henning P. Schmiedehausen * @version $Id: HsqlDB.java 439648 2006-09-02 20:42:10Z oheger $ */ public class HsqlDB { private Connection connection = null; private static Log log = LogFactory.getLog(HsqlDB.class); public HsqlDB(String uri, String databaseDriver, String loadFile) throws Exception { Class.forName(databaseDriver); this.connection = DriverManager.getConnection(uri, "sa", ""); if (StringUtils.isNotEmpty(loadFile)) { loadSqlFile(loadFile); } this.connection.commit(); } public Connection getConnection() { return connection; } public void close() { try { connection.close(); } catch (Exception e) { } } private void loadSqlFile(String fileName) throws Exception { Statement statement = null; try { statement = connection.createStatement(); String commands = getFileContents(fileName); for (int targetPos = commands.indexOf(';'); targetPos > -1; targetPos = commands.indexOf(';')) { String cmd = commands.substring(0, targetPos + 1); try { statement.execute(cmd); } catch (SQLException sqle) { log.warn("Statement: " + cmd + ": " + sqle.getMessage()); } commands = commands.substring(targetPos + 2); } } finally { if (statement != null) { statement.close(); } } } private String getFileContents(String fileName) throws Exception { FileReader fr = new FileReader(fileName); char fileBuf[] = new char[1024]; StringBuffer sb = new StringBuffer(1000); int res = -1; while ((res = fr.read(fileBuf, 0, 1024)) > -1) { sb.append(fileBuf, 0, res); } fr.close(); return sb.toString(); } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestAbstractConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestAbstractConfigurat100644 14034 12232154104 33627 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import junitx.framework.ListAssert; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.Test; /** * Abstract TestCase for implementations of {@link AbstractConfiguration}. * * @author Emmanuel Bourg * @version $Id: TestAbstractConfiguration.java 1222465 2011-12-22 21:32:56Z oheger $ */ public abstract class TestAbstractConfiguration { /** * Return an abstract configuration with the following data:
*
     * key1 = value1
     * key2 = value2
     * list = value1, value2
     * listesc = value1\\,value2
     * 
*/ protected abstract AbstractConfiguration getConfiguration(); /** * Return an empty configuration. */ protected abstract AbstractConfiguration getEmptyConfiguration(); @Test public void testGetProperty() { Configuration config = getConfiguration(); assertEquals("key1", "value1", config.getProperty("key1")); assertEquals("key2", "value2", config.getProperty("key2")); assertNull("key3", config.getProperty("key3")); } @Test public void testList() { Configuration config = getConfiguration(); List list = config.getList("list"); assertNotNull("list not found", config.getProperty("list")); assertEquals("list size", 2, list.size()); assertTrue("'value1' is not in the list", list.contains("value1")); assertTrue("'value2' is not in the list", list.contains("value2")); } /** * Tests whether the escape character for list delimiters is recocknized and * removed. */ @Test public void testListEscaped() { assertEquals("Wrong value for escaped list", "value1,value2", getConfiguration().getString("listesc")); } @Test public void testAddPropertyDirect() { AbstractConfiguration config = getConfiguration(); config.addPropertyDirect("key3", "value3"); assertEquals("key3", "value3", config.getProperty("key3")); config.addPropertyDirect("key3", "value4"); config.addPropertyDirect("key3", "value5"); List list = config.getList("key3"); assertNotNull("no list found for the 'key3' property", list); List expected = new ArrayList(); expected.add("value3"); expected.add("value4"); expected.add("value5"); ListAssert.assertEquals("values for the 'key3' property", expected, list); } @Test public void testIsEmpty() { Configuration config = getConfiguration(); assertFalse("the configuration is empty", config.isEmpty()); assertTrue("the configuration is not empty", getEmptyConfiguration().isEmpty()); } @Test public void testContainsKey() { Configuration config = getConfiguration(); assertTrue("key1 not found", config.containsKey("key1")); assertFalse("key3 found", config.containsKey("key3")); } @Test public void testClearProperty() { Configuration config = getConfiguration(); config.clearProperty("key2"); assertFalse("key2 not cleared", config.containsKey("key2")); } @Test public void testGetKeys() { Configuration config = getConfiguration(); Iterator keys = config.getKeys(); List expectedKeys = new ArrayList(); expectedKeys.add("key1"); expectedKeys.add("key2"); expectedKeys.add("list"); expectedKeys.add("listesc"); assertNotNull("null iterator", keys); assertTrue("empty iterator", keys.hasNext()); List actualKeys = new ArrayList(); while (keys.hasNext()) { actualKeys.add(keys.next()); } ListAssert.assertEquals("keys", expectedKeys, actualKeys); } /** * Tests accessing the configuration's logger. */ @Test public void testSetLogger() { AbstractConfiguration config = getEmptyConfiguration(); assertNotNull("Default logger is null", config.getLogger()); Log log = LogFactory.getLog(config.getClass()); config.setLogger(log); assertSame("Logger was not set", log, config.getLogger()); } /** * Tests the exception message triggered by the conversion to BigInteger. * This test is related to CONFIGURATION-357. */ @Test public void testGetBigIntegerConversion() { Configuration config = getConfiguration(); try { config.getBigInteger("key1"); fail("No conversion exception thrown!"); } catch (ConversionException cex) { assertEquals("Wrong exception message", "'key1' doesn't map to a BigInteger object", cex .getMessage()); } } } ././@LongLink100644 0 0 172 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestAbstractConfigurationBasicFeatures.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestAbstractConfigurat100644 42603 12232154104 33632 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.junit.Test; /** * A test class for some of the basic functionality implemented by * AbstractConfiguration. * * @version $Id: TestAbstractConfigurationBasicFeatures.java 1222823 2011-12-23 20:03:10Z oheger $ */ public class TestAbstractConfigurationBasicFeatures { /** Constant for the prefix of test keys.*/ private static final String KEY_PREFIX = "key"; /** Constant for the number of properties in tests for copy operations.*/ private static final int PROP_COUNT = 12; /** * Tests the clear() implementation of AbstractConfiguration if the iterator * returned by getKeys() does not support the remove() operation. */ @Test public void testClearIteratorNoRemove() { AbstractConfiguration config = new TestConfigurationImpl( new BaseConfiguration()) { // return an iterator that does not support remove operations @Override public Iterator getKeys() { Collection keyCol = new ArrayList(); CollectionUtils.addAll(keyCol, getUnderlyingConfiguration() .getKeys()); String[] keys = keyCol.toArray(new String[keyCol.size()]); return Arrays.asList(keys).iterator(); } }; for (int i = 0; i < 20; i++) { config.addProperty("key" + i, "value" + i); } config.clear(); assertTrue("Configuration not empty", config.isEmpty()); } /** * Tests escaping the variable marker, so that no interpolation will be * performed. */ @Test public void testInterpolateEscape() { AbstractConfiguration config = new TestConfigurationImpl( new PropertiesConfiguration()); config .addProperty( "mypath", "$${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc.jar\\,$${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc_license_cu.jar"); assertEquals( "Wrong interpolated value", "${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc.jar,${DB2UNIVERSAL_JDBC_DRIVER_PATH}/db2jcc_license_cu.jar", config.getString("mypath")); } /** * Tests adding list properties. The single elements of the list should be * added. */ @Test public void testAddPropertyList() { checkAddListProperty(new TestConfigurationImpl( new PropertiesConfiguration())); } /** * Tests adding list properties when delimiter parsing is disabled. */ @Test public void testAddPropertyListNoDelimiterParsing() { AbstractConfiguration config = new TestConfigurationImpl( new PropertiesConfiguration()); config.setDelimiterParsingDisabled(true); checkAddListProperty(config); } /** * Helper method for adding properties with multiple values. * * @param config the configuration to be used for testing */ private void checkAddListProperty(AbstractConfiguration config) { config.addProperty("test", "value1"); Object[] lstValues1 = new Object[] { "value2", "value3" }; Object[] lstValues2 = new Object[] { "value4", "value5", "value6" }; config.addProperty("test", lstValues1); config.addProperty("test", Arrays.asList(lstValues2)); List lst = config.getList("test"); assertEquals("Wrong number of list elements", 6, lst.size()); for (int i = 0; i < lst.size(); i++) { assertEquals("Wrong list element at " + i, "value" + (i + 1), lst .get(i)); } } /** * Tests the copy() method. */ @Test public void testCopy() { AbstractConfiguration config = setUpDestConfig(); Configuration srcConfig = setUpSourceConfig(); config.copy(srcConfig); for (int i = 0; i < PROP_COUNT; i++) { String key = KEY_PREFIX + i; if (srcConfig.containsKey(key)) { assertEquals("Value not replaced: " + key, srcConfig .getProperty(key), config.getProperty(key)); } else { assertEquals("Value modified: " + key, "value" + i, config .getProperty(key)); } } } /** * Tests the copy() method when properties with multiple values and escaped * list delimiters are involved. */ @Test public void testCopyWithLists() { Configuration srcConfig = setUpSourceConfig(); AbstractConfiguration config = setUpDestConfig(); config.copy(srcConfig); checkListProperties(config); } /** * Tests the events generated by a copy() operation. */ @Test public void testCopyEvents() { AbstractConfiguration config = setUpDestConfig(); Configuration srcConfig = setUpSourceConfig(); CollectingConfigurationListener l = new CollectingConfigurationListener(); config.addConfigurationListener(l); config.copy(srcConfig); checkCopyEvents(l, srcConfig, AbstractConfiguration.EVENT_SET_PROPERTY); } /** * Tests copying a null configuration. This should be a noop. */ @Test public void testCopyNull() { AbstractConfiguration config = setUpDestConfig(); config.copy(null); ConfigurationAssert.assertEquals(setUpDestConfig(), config); } /** * Tests the append() method. */ @Test public void testAppend() { AbstractConfiguration config = setUpDestConfig(); Configuration srcConfig = setUpSourceConfig(); config.append(srcConfig); for (int i = 0; i < PROP_COUNT; i++) { String key = KEY_PREFIX + i; if (srcConfig.containsKey(key)) { List values = config.getList(key); assertEquals("Value not added: " + key, 2, values.size()); assertEquals("Wrong value 1 for " + key, "value" + i, values .get(0)); assertEquals("Wrong value 2 for " + key, "src" + i, values .get(1)); } else { assertEquals("Value modified: " + key, "value" + i, config .getProperty(key)); } } } /** * Tests the append() method when properties with multiple values and * escaped list delimiters are involved. */ @Test public void testAppendWithLists() { AbstractConfiguration config = setUpDestConfig(); config.append(setUpSourceConfig()); checkListProperties(config); } /** * Tests the events generated by an append() operation. */ @Test public void testAppendEvents() { AbstractConfiguration config = setUpDestConfig(); Configuration srcConfig = setUpSourceConfig(); CollectingConfigurationListener l = new CollectingConfigurationListener(); config.addConfigurationListener(l); config.append(srcConfig); checkCopyEvents(l, srcConfig, AbstractConfiguration.EVENT_ADD_PROPERTY); } /** * Tests appending a null configuration. This should be a noop. */ @Test public void testAppendNull() { AbstractConfiguration config = setUpDestConfig(); config.append(null); ConfigurationAssert.assertEquals(setUpDestConfig(), config); } /** * Tests whether environment variables can be interpolated. */ @Test public void testInterpolateEnvironmentVariables() { AbstractConfiguration config = new TestConfigurationImpl( new PropertiesConfiguration()); EnvironmentConfiguration envConfig = new EnvironmentConfiguration(); Map env = new HashMap(); for (Iterator it = envConfig.getKeys(); it.hasNext();) { String key = it.next(); String propKey = "envtest." + key; env.put(propKey, envConfig.getString(key)); config.addProperty(propKey, "${env:" + key + "}"); } assertFalse("No environment properties", env.isEmpty()); for (Map.Entry e : env.entrySet()) { assertEquals("Wrong value for " + e.getKey(), e.getValue(), config .getString(e.getKey())); } } /** * Tests getList() for single non-string values. */ @Test public void testGetListNonString() { checkGetListScalar(Integer.valueOf(42)); checkGetListScalar(Long.valueOf(42)); checkGetListScalar(Short.valueOf((short) 42)); checkGetListScalar(Byte.valueOf((byte) 42)); checkGetListScalar(Float.valueOf(42)); checkGetListScalar(Double.valueOf(42)); checkGetListScalar(Boolean.TRUE); } /** * Tests getStringArray() for single son-string values. */ @Test public void testGetStringArrayNonString() { checkGetStringArrayScalar(Integer.valueOf(42)); checkGetStringArrayScalar(Long.valueOf(42)); checkGetStringArrayScalar(Short.valueOf((short) 42)); checkGetStringArrayScalar(Byte.valueOf((byte) 42)); checkGetStringArrayScalar(Float.valueOf(42)); checkGetStringArrayScalar(Double.valueOf(42)); checkGetStringArrayScalar(Boolean.TRUE); } /** * Helper method for checking getList() if the property value is a scalar. * @param value the value of the property */ private void checkGetListScalar(Object value) { BaseConfiguration config = new BaseConfiguration(); config.addProperty(KEY_PREFIX, value); List lst = config.getList(KEY_PREFIX); assertEquals("Wrong number of values", 1, lst.size()); assertEquals("Wrong value", value.toString(), lst.get(0)); } /** * Helper method for checking getStringArray() if the property value is a * scalar. * * @param value the value of the property */ private void checkGetStringArrayScalar(Object value) { BaseConfiguration config = new BaseConfiguration(); config.addProperty(KEY_PREFIX, value); String[] array = config.getStringArray(KEY_PREFIX); assertEquals("Weong number of elements", 1, array.length); assertEquals("Wrong value", value.toString(), array[0]); } /** * Tests whether interpolation works in variable names. */ @Test public void testNestedVariableInterpolation() { BaseConfiguration config = new BaseConfiguration(); config.getSubstitutor().setEnableSubstitutionInVariables(true); config.addProperty("java.version", "1.4"); config.addProperty("jre-1.4", "C:\\java\\1.4"); config.addProperty("jre.path", "${jre-${java.version}}"); assertEquals("Wrong path", "C:\\java\\1.4", config.getString("jre.path")); } /** * Creates the source configuration for testing the copy() and append() * methods. This configuration contains keys with an odd index and values * starting with the prefix "src". There are also some list properties. * * @return the source configuration for copy operations */ private Configuration setUpSourceConfig() { BaseConfiguration config = new BaseConfiguration(); for (int i = 1; i < PROP_COUNT; i += 2) { config.addProperty(KEY_PREFIX + i, "src" + i); } config.addProperty("list1", "1,2,3"); config.addProperty("list2", "3\\,1415,9\\,81"); return config; } /** * Creates the destination configuration for testing the copy() and append() * methods. This configuration contains keys with a running index and * corresponding values starting with the prefix "value". * * @return the destination configuration for copy operations */ private AbstractConfiguration setUpDestConfig() { AbstractConfiguration config = new TestConfigurationImpl( new PropertiesConfiguration()); for (int i = 0; i < PROP_COUNT; i++) { config.addProperty(KEY_PREFIX + i, "value" + i); } return config; } /** * Tests the values of list properties after a copy operation. * * @param config the configuration to test */ private void checkListProperties(Configuration config) { List values = config.getList("list1"); assertEquals("Wrong number of elements in list 1", 3, values.size()); values = config.getList("list2"); assertEquals("Wrong number of elements in list 2", 2, values.size()); assertEquals("Wrong value 1", "3,1415", values.get(0)); assertEquals("Wrong value 2", "9,81", values.get(1)); } /** * Tests whether the correct events are received for a copy operation. * * @param l the event listener * @param src the configuration that was copied * @param eventType the expected event type */ private void checkCopyEvents(CollectingConfigurationListener l, Configuration src, int eventType) { Map events = new HashMap(); for (ConfigurationEvent e : l.events) { assertEquals("Wrong event type", eventType, e.getType()); assertTrue("Unknown property: " + e.getPropertyName(), src .containsKey(e.getPropertyName())); assertEquals("Wrong property value for " + e.getPropertyName(), e .getPropertyValue(), src.getProperty(e.getPropertyName())); if (!e.isBeforeUpdate()) { assertTrue("After event without before event", events .containsKey(e.getPropertyName())); } else { events.put(e.getPropertyName(), e); } } for (Iterator it = src.getKeys(); it.hasNext();) { String key = it.next(); assertTrue("No event received for key " + key, events .containsKey(key)); } } /** * A test configuration implementation. This implementation inherits * directly from AbstractConfiguration. For implementing the required * functionality another implementation of AbstractConfiguration is used; * all methods that need to be implemented delegate to this wrapped * configuration. */ static class TestConfigurationImpl extends AbstractConfiguration { /** Stores the underlying configuration. */ private AbstractConfiguration config; public AbstractConfiguration getUnderlyingConfiguration() { return config; } public TestConfigurationImpl(AbstractConfiguration wrappedConfig) { config = wrappedConfig; } @Override protected void addPropertyDirect(String key, Object value) { config.addPropertyDirect(key, value); } public boolean containsKey(String key) { return config.containsKey(key); } public Iterator getKeys() { return config.getKeys(); } public Object getProperty(String key) { return config.getProperty(key); } public boolean isEmpty() { return config.isEmpty(); } @Override protected void clearPropertyDirect(String key) { config.clearPropertyDirect(key); } } /** * An event listener implementation that simply collects all received * configuration events. */ static class CollectingConfigurationListener implements ConfigurationListener { List events = new ArrayList(); public void configurationChanged(ConfigurationEvent event) { events.add(event); } } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestBaseConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestBaseConfiguration.100644 62375 12232154104 33535 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.math.BigDecimal; import java.math.BigInteger; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.NoSuchElementException; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import junitx.framework.ListAssert; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.junit.Before; import org.junit.Test; /** * Tests some basic functions of the BaseConfiguration class. Missing keys will * throw Exceptions * * @version $Id: TestBaseConfiguration.java 1231721 2012-01-15 18:32:07Z oheger $ */ public class TestBaseConfiguration { /** Constant for the number key.*/ static final String KEY_NUMBER = "number"; protected BaseConfiguration config = null; protected static Class missingElementException = NoSuchElementException.class; protected static Class incompatibleElementException = ConversionException.class; @Before public void setUp() throws Exception { config = new BaseConfiguration(); config.setThrowExceptionOnMissing(true); } @Test public void testThrowExceptionOnMissing() { assertTrue("Throw Exception Property is not set!", config.isThrowExceptionOnMissing()); } @Test public void testGetProperty() { /* should be empty and return null */ assertEquals("This returns null", config.getProperty("foo"), null); /* add a real value, and get it two different ways */ config.setProperty("number", "1"); assertEquals("This returns '1'", config.getProperty("number"), "1"); assertEquals("This returns '1'", config.getString("number"), "1"); } @Test public void testGetByte() { config.setProperty("number", "1"); byte oneB = 1; byte twoB = 2; assertEquals("This returns 1(byte)", oneB, config.getByte("number")); assertEquals("This returns 1(byte)", oneB, config.getByte("number", twoB)); assertEquals("This returns 2(default byte)", twoB, config.getByte("numberNotInConfig", twoB)); assertEquals("This returns 1(Byte)", new Byte(oneB), config.getByte("number", new Byte("2"))); } @Test(expected = NoSuchElementException.class) public void testGetByteUnknown() { config.getByte("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetByteIncompatibleType() { config.setProperty("test.empty", ""); config.getByte("test.empty"); } @Test public void testGetShort() { config.setProperty("numberS", "1"); short oneS = 1; short twoS = 2; assertEquals("This returns 1(short)", oneS, config.getShort("numberS")); assertEquals("This returns 1(short)", oneS, config.getShort("numberS", twoS)); assertEquals("This returns 2(default short)", twoS, config.getShort("numberNotInConfig", twoS)); assertEquals("This returns 1(Short)", new Short(oneS), config.getShort("numberS", new Short("2"))); } @Test(expected = NoSuchElementException.class) public void testGetShortUnknown() { config.getShort("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetShortIncompatibleType() { config.setProperty("test.empty", ""); config.getShort("test.empty"); } @Test public void testGetLong() { config.setProperty("numberL", "1"); long oneL = 1; long twoL = 2; assertEquals("This returns 1(long)", oneL, config.getLong("numberL")); assertEquals("This returns 1(long)", oneL, config.getLong("numberL", twoL)); assertEquals("This returns 2(default long)", twoL, config.getLong("numberNotInConfig", twoL)); assertEquals("This returns 1(Long)", new Long(oneL), config.getLong("numberL", new Long("2"))); } @Test(expected = NoSuchElementException.class) public void testGetLongUnknown() { config.getLong("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetLongIncompatibleTypes() { config.setProperty("test.empty", ""); config.getLong("test.empty"); } @Test public void testGetFloat() { config.setProperty("numberF", "1.0"); float oneF = 1; float twoF = 2; assertEquals("This returns 1(float)", oneF, config.getFloat("numberF"), 0); assertEquals("This returns 1(float)", oneF, config.getFloat("numberF", twoF), 0); assertEquals("This returns 2(default float)", twoF, config.getFloat("numberNotInConfig", twoF), 0); assertEquals("This returns 1(Float)", new Float(oneF), config.getFloat("numberF", new Float("2"))); } @Test(expected = NoSuchElementException.class) public void testGetFloatUnknown() { config.getFloat("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetFloatIncompatibleType() { config.setProperty("test.empty", ""); config.getFloat("test.empty"); } @Test public void testGetDouble() { config.setProperty("numberD", "1.0"); double oneD = 1; double twoD = 2; assertEquals("This returns 1(double)", oneD, config.getDouble("numberD"), 0); assertEquals("This returns 1(double)", oneD, config.getDouble("numberD", twoD), 0); assertEquals("This returns 2(default double)", twoD, config.getDouble("numberNotInConfig", twoD), 0); assertEquals("This returns 1(Double)", new Double(oneD), config.getDouble("numberD", new Double("2"))); } @Test(expected = NoSuchElementException.class) public void testGetDoubleUnknown() { config.getDouble("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetDoubleIncompatibleType() { config.setProperty("test.empty", ""); config.getDouble("test.empty"); } @Test public void testGetBigDecimal() { config.setProperty("numberBigD", "123.456"); BigDecimal number = new BigDecimal("123.456"); BigDecimal defaultValue = new BigDecimal("654.321"); assertEquals("Existing key", number, config.getBigDecimal("numberBigD")); assertEquals("Existing key with default value", number, config.getBigDecimal("numberBigD", defaultValue)); assertEquals("Missing key with default value", defaultValue, config.getBigDecimal("numberNotInConfig", defaultValue)); } @Test(expected = NoSuchElementException.class) public void testGetBigDecimalUnknown() { config.getBigDecimal("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetBigDecimalIncompatibleType() { config.setProperty("test.empty", ""); config.getBigDecimal("test.empty"); } @Test public void testGetBigInteger() { config.setProperty("numberBigI", "1234567890"); BigInteger number = new BigInteger("1234567890"); BigInteger defaultValue = new BigInteger("654321"); assertEquals("Existing key", number, config.getBigInteger("numberBigI")); assertEquals("Existing key with default value", number, config.getBigInteger("numberBigI", defaultValue)); assertEquals("Missing key with default value", defaultValue, config.getBigInteger("numberNotInConfig", defaultValue)); } @Test(expected = NoSuchElementException.class) public void testGetBigIntegerUnknown() { config.getBigInteger("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetBigIntegerIncompatibleType() { config.setProperty("test.empty", ""); config.getBigInteger("test.empty"); } @Test public void testGetString() { config.setProperty("testString", "The quick brown fox"); String string = "The quick brown fox"; String defaultValue = "jumps over the lazy dog"; assertEquals("Existing key", string, config.getString("testString")); assertEquals("Existing key with default value", string, config.getString("testString", defaultValue)); assertEquals("Missing key with default value", defaultValue, config.getString("stringNotInConfig", defaultValue)); } @Test(expected = NoSuchElementException.class) public void testGetStringUnknown() { config.getString("stringNotInConfig"); } @Test public void testGetBoolean() { config.setProperty("boolA", Boolean.TRUE); boolean boolT = true, boolF = false; assertEquals("This returns true", boolT, config.getBoolean("boolA")); assertEquals("This returns true, not the default", boolT, config.getBoolean("boolA", boolF)); assertEquals("This returns false(default)", boolF, config.getBoolean("boolNotInConfig", boolF)); assertEquals("This returns true(Boolean)", new Boolean(boolT), config.getBoolean("boolA", new Boolean(boolF))); } @Test(expected = NoSuchElementException.class) public void testGetBooleanUnknown() { config.getBoolean("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetBooleanIncompatibleType() { config.setProperty("test.empty", ""); config.getBoolean("test.empty"); } @Test public void testGetList() { config.addProperty("number", "1"); config.addProperty("number", "2"); List list = config.getList("number"); assertNotNull("The list is null", list); assertEquals("List size", 2, list.size()); assertTrue("The number 1 is missing from the list", list.contains("1")); assertTrue("The number 2 is missing from the list", list.contains("2")); } /** * Tests that the first scalar of a list is returned. */ @Test public void testGetStringForListValue() { config.addProperty("number", "1"); config.addProperty("number", "2"); assertEquals("Wrong result", "1", config.getString("number")); } @Test public void testGetInterpolatedList() { config.addProperty("number", "1"); config.addProperty("array", "${number}"); config.addProperty("array", "${number}"); List list = new ArrayList(); list.add("1"); list.add("1"); ListAssert.assertEquals("'array' property", list, config.getList("array")); } @Test public void testGetInterpolatedPrimitives() { config.addProperty("number", "1"); config.addProperty("value", "${number}"); config.addProperty("boolean", "true"); config.addProperty("booleanValue", "${boolean}"); // primitive types assertEquals("boolean interpolation", true, config.getBoolean("booleanValue")); assertEquals("byte interpolation", 1, config.getByte("value")); assertEquals("short interpolation", 1, config.getShort("value")); assertEquals("int interpolation", 1, config.getInt("value")); assertEquals("long interpolation", 1, config.getLong("value")); assertEquals("float interpolation", 1, config.getFloat("value"), 0); assertEquals("double interpolation", 1, config.getDouble("value"), 0); // primitive wrappers assertEquals("Boolean interpolation", Boolean.TRUE, config.getBoolean("booleanValue", null)); assertEquals("Byte interpolation", new Byte("1"), config.getByte("value", null)); assertEquals("Short interpolation", new Short("1"), config.getShort("value", null)); assertEquals("Integer interpolation", new Integer("1"), config.getInteger("value", null)); assertEquals("Long interpolation", new Long("1"), config.getLong("value", null)); assertEquals("Float interpolation", new Float("1"), config.getFloat("value", null)); assertEquals("Double interpolation", new Double("1"), config.getDouble("value", null)); assertEquals("BigInteger interpolation", new BigInteger("1"), config.getBigInteger("value", null)); assertEquals("BigDecimal interpolation", new BigDecimal("1"), config.getBigDecimal("value", null)); } @Test public void testCommaSeparatedString() { String prop = "hey, that's a test"; config.setProperty("prop.string", prop); List list = config.getList("prop.string"); assertEquals("Wrong number of list elements", 2, list.size()); assertEquals("Wrong element 1", "hey", list.get(0)); } @Test public void testCommaSeparatedStringEscaped() { String prop2 = "hey\\, that's a test"; config.setProperty("prop.string", prop2); assertEquals("Wrong value", "hey, that's a test", config.getString("prop.string")); } @Test public void testAddProperty() throws Exception { Collection props = new ArrayList(); props.add("one"); props.add("two,three,four"); props.add(new String[] { "5.1", "5.2", "5.3,5.4", "5.5" }); props.add("six"); config.addProperty("complex.property", props); Object val = config.getProperty("complex.property"); assertTrue(val instanceof Collection); Collection col = (Collection) val; assertEquals(10, col.size()); props = new ArrayList(); props.add("quick"); props.add("brown"); props.add("fox,jumps"); Object[] data = new Object[] { "The", props, "over,the", "lazy", "dog." }; config.setProperty("complex.property", data); val = config.getProperty("complex.property"); assertTrue(val instanceof Collection); col = (Collection) val; Iterator it = col.iterator(); StringTokenizer tok = new StringTokenizer("The quick brown fox jumps over the lazy dog.", " "); while(tok.hasMoreTokens()) { assertTrue(it.hasNext()); assertEquals(tok.nextToken(), it.next()); } assertFalse(it.hasNext()); config.setProperty("complex.property", null); assertFalse(config.containsKey("complex.property")); } @Test public void testPropertyAccess() { config.clearProperty("prop.properties"); config.setProperty("prop.properties", ""); assertEquals( "This returns an empty Properties object", config.getProperties("prop.properties"), new Properties()); config.clearProperty("prop.properties"); config.setProperty("prop.properties", "foo=bar, baz=moo, seal=clubber"); Properties p = new Properties(); p.setProperty("foo", "bar"); p.setProperty("baz", "moo"); p.setProperty("seal", "clubber"); assertEquals( "This returns a filled in Properties object", config.getProperties("prop.properties"), p); } @Test public void testSubset() { /* * test subset : assure we don't reprocess the data elements * when generating the subset */ String prop = "hey, that's a test"; String prop2 = "hey\\, that's a test"; config.setProperty("prop.string", prop2); config.setProperty("property.string", "hello"); Configuration subEprop = config.subset("prop"); assertEquals( "Returns the full string", prop, subEprop.getString("string")); assertEquals("Wrong list size", 1, subEprop.getList("string").size()); Iterator it = subEprop.getKeys(); it.next(); assertFalse(it.hasNext()); subEprop = config.subset("prop."); it = subEprop.getKeys(); assertFalse(it.hasNext()); } @Test public void testInterpolation() { InterpolationTestHelper.testInterpolation(config); } @Test public void testMultipleInterpolation() { InterpolationTestHelper.testMultipleInterpolation(config); } @Test public void testInterpolationLoop() { InterpolationTestHelper.testInterpolationLoop(config); } /** * Tests interpolation when a subset configuration is involved. */ @Test public void testInterpolationSubset() { InterpolationTestHelper.testInterpolationSubset(config); } /** * Tests interpolation when the referred property is not found. */ @Test public void testInterpolationUnknownProperty() { InterpolationTestHelper.testInterpolationUnknownProperty(config); } /** * Tests interpolation of system properties. */ @Test public void testInterpolationSystemProperties() { InterpolationTestHelper.testInterpolationSystemProperties(config); } /** * Tests interpolation of constant values. */ @Test public void testInterpolationConstants() { InterpolationTestHelper.testInterpolationConstants(config); } /** * Tests whether a variable can be escaped, so that it won't be * interpolated. */ @Test public void testInterpolationEscaped() { InterpolationTestHelper.testInterpolationEscaped(config); } /** * Tests accessing and manipulating the interpolator object. */ @Test public void testGetInterpolator() { InterpolationTestHelper.testGetInterpolator(config); } /** * Tests obtaining a configuration with all variables replaced by their * actual values. */ @Test public void testInterpolatedConfiguration() { InterpolationTestHelper.testInterpolatedConfiguration(config); } @Test public void testGetHexadecimalValue() { config.setProperty("number", "0xFF"); assertEquals("byte value", (byte) 0xFF, config.getByte("number")); config.setProperty("number", "0xFFFF"); assertEquals("short value", (short) 0xFFFF, config.getShort("number")); config.setProperty("number", "0xFFFFFFFF"); assertEquals("int value", 0xFFFFFFFF, config.getInt("number")); config.setProperty("number", "0xFFFFFFFFFFFFFFFF"); assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getLong("number")); assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getBigInteger("number").longValue()); } @Test public void testGetBinaryValue() { config.setProperty("number", "0b11111111"); assertEquals("byte value", (byte) 0xFF, config.getByte("number")); config.setProperty("number", "0b1111111111111111"); assertEquals("short value", (short) 0xFFFF, config.getShort("number")); config.setProperty("number", "0b11111111111111111111111111111111"); assertEquals("int value", 0xFFFFFFFF, config.getInt("number")); config.setProperty("number", "0b1111111111111111111111111111111111111111111111111111111111111111"); assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getLong("number")); assertEquals("long value", 0xFFFFFFFFFFFFFFFFL, config.getBigInteger("number").longValue()); } @Test public void testResolveContainerStore() { AbstractConfiguration config = new BaseConfiguration(); // array of objects config.addPropertyDirect("array", new String[] { "foo", "bar" }); assertEquals("first element of the 'array' property", "foo", config.resolveContainerStore("array")); // list of objects List list = new ArrayList(); list.add("foo"); list.add("bar"); config.addPropertyDirect("list", list); assertEquals("first element of the 'list' property", "foo", config.resolveContainerStore("list")); // set of objects Set set = new LinkedHashSet(); set.add("foo"); set.add("bar"); config.addPropertyDirect("set", set); assertEquals("first element of the 'set' property", "foo", config.resolveContainerStore("set")); // arrays of primitives config.addPropertyDirect("array.boolean", new boolean[] { true, false }); assertEquals("first element of the 'array.boolean' property", true, config.getBoolean("array.boolean")); config.addPropertyDirect("array.byte", new byte[] { 1, 2 }); assertEquals("first element of the 'array.byte' property", 1, config.getByte("array.byte")); config.addPropertyDirect("array.short", new short[] { 1, 2 }); assertEquals("first element of the 'array.short' property", 1, config.getShort("array.short")); config.addPropertyDirect("array.int", new int[] { 1, 2 }); assertEquals("first element of the 'array.int' property", 1, config.getInt("array.int")); config.addPropertyDirect("array.long", new long[] { 1, 2 }); assertEquals("first element of the 'array.long' property", 1, config.getLong("array.long")); config.addPropertyDirect("array.float", new float[] { 1, 2 }); assertEquals("first element of the 'array.float' property", 1, config.getFloat("array.float"), 0); config.addPropertyDirect("array.double", new double[] { 1, 2 }); assertEquals("first element of the 'array.double' property", 1, config.getDouble("array.double"), 0); } /** * Tests if conversion between number types is possible. */ @Test public void testNumberConversions() { config.setProperty(KEY_NUMBER, new Integer(42)); assertEquals("Wrong int returned", 42, config.getInt(KEY_NUMBER)); assertEquals("Wrong long returned", 42L, config.getLong(KEY_NUMBER)); assertEquals("Wrong byte returned", (byte) 42, config .getByte(KEY_NUMBER)); assertEquals("Wrong float returned", 42.0f, config.getFloat(KEY_NUMBER), 0.01f); assertEquals("Wrong double returned", 42.0, config .getDouble(KEY_NUMBER), 0.001); assertEquals("Wrong Long returned", new Long(42L), config.getLong( KEY_NUMBER, null)); assertEquals("Wrong BigInt returned", new BigInteger("42"), config .getBigInteger(KEY_NUMBER)); assertEquals("Wrong DigDecimal returned", new BigDecimal("42"), config .getBigDecimal(KEY_NUMBER)); } /** * Tests cloning a BaseConfiguration. */ @Test public void testClone() { for (int i = 0; i < 10; i++) { config.addProperty("key" + i, new Integer(i)); } BaseConfiguration config2 = (BaseConfiguration) config.clone(); for (Iterator it = config.getKeys(); it.hasNext();) { String key = it.next(); assertTrue("Key not found: " + key, config2.containsKey(key)); assertEquals("Wrong value for key " + key, config.getProperty(key), config2.getProperty(key)); } } /** * Tests whether a cloned configuration is decoupled from its original. */ @Test public void testCloneModify() { ConfigurationListener l = new ConfigurationListener() { public void configurationChanged(ConfigurationEvent event) { // just a dummy } }; config.addConfigurationListener(l); config.addProperty("original", Boolean.TRUE); BaseConfiguration config2 = (BaseConfiguration) config.clone(); config2.addProperty("clone", Boolean.TRUE); assertFalse("New key appears in original", config.containsKey("clone")); config2.setProperty("original", Boolean.FALSE); assertTrue("Wrong value of original property", config .getBoolean("original")); assertEquals("Event listener was copied", 0, config2 .getConfigurationListeners().size()); } /** * Tests the clone() method if a list property is involved. */ @Test public void testCloneListProperty() { final String key = "list"; config.addProperty(key, "value1"); config.addProperty(key, "value2"); BaseConfiguration config2 = (BaseConfiguration) config.clone(); config2.addProperty(key, "value3"); assertEquals("Wrong number of original properties", 2, config.getList( key).size()); } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestBaseConfigurationXMLReader.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestBaseConfigurationX100644 13241 12232154104 33573 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.Arrays; import java.util.Iterator; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.sax.SAXSource; import org.apache.commons.jxpath.JXPathContext; import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * Test class for BaseConfigurationXMLReader. * * @version $Id: TestBaseConfigurationXMLReader.java 1222835 2011-12-23 20:37:22Z oheger $ */ public class TestBaseConfigurationXMLReader { private static final String[] CONTINENTS = { "Africa", "America", "Asia", "Australia", "Europe" }; private BaseConfiguration config; private BaseConfigurationXMLReader configReader; @Before public void setUp() throws Exception { config = new BaseConfiguration(); config.addProperty("world.continents.continent", Arrays.asList(CONTINENTS)); config.addProperty("world.greeting", "Hello"); config.addProperty("world.greeting", "Salute"); config.addProperty("world.wish", "Peace"); config.addProperty("application.mail.smtp", "smtp.mymail.org"); config.addProperty("application.mail.pop", "pop3.mymail.org"); config.addProperty("application.mail.account.type", "pop3"); config.addProperty("application.mail.account.user", "postmaster"); config.addProperty("application.mail.account.pwd", "?.-gulp*#"); config.addProperty("application.mail.timeout", new Integer(42)); config.addProperty("test", Boolean.TRUE); configReader = new BaseConfigurationXMLReader(config); } @Test public void testParse() throws Exception { checkDocument(configReader, "config"); } @Test(expected = SAXException.class) public void testParseSAXException() throws IOException, SAXException { configReader.setContentHandler(new TestContentHandler()); configReader.parse("systemID"); } @Test(expected = IOException.class) public void testParseIOException() throws SAXException, IOException { BaseConfigurationXMLReader reader = new BaseConfigurationXMLReader(); reader.parse("document"); } @Test public void testSetRootName() throws Exception { BaseConfigurationXMLReader reader = new BaseConfigurationXMLReader(config); reader.setRootName("apache"); checkDocument(reader, "apache"); } private void checkDocument(BaseConfigurationXMLReader creader, String rootName) throws Exception { SAXSource source = new SAXSource(creader, new InputSource()); DOMResult result = new DOMResult(); Transformer trans = TransformerFactory.newInstance().newTransformer(); trans.transform(source, result); Node root = ((Document) result.getNode()).getDocumentElement(); JXPathContext ctx = JXPathContext.newContext(root); assertEquals("Wrong root name", rootName, root.getNodeName()); assertEquals("Wrong number of children", 3, ctx.selectNodes("/*").size()); check(ctx, "world/continents/continent", CONTINENTS); check(ctx, "world/greeting", new String[] { "Hello", "Salute" }); check(ctx, "world/wish", "Peace"); check(ctx, "application/mail/smtp", "smtp.mymail.org"); check(ctx, "application/mail/timeout", "42"); check(ctx, "application/mail/account/type", "pop3"); check(ctx, "application/mail/account/user", "postmaster"); check(ctx, "test", "true"); } /** * Helper method for checking values in the created document. * * @param ctx the JXPath context * @param path the path to be checked * @param values the expected element values */ private void check(JXPathContext ctx, String path, String[] values) { Iterator it = ctx.iterate(path); for (int i = 0; i < values.length; i++) { assertTrue("Too few values", it.hasNext()); assertEquals("Wrong property value", values[i], it.next()); } assertFalse("Too many values", it.hasNext()); } private void check(JXPathContext ctx, String path, String value) { check(ctx, path, new String[] { value }); } // A ContentHandler that raises an exception private static class TestContentHandler extends DefaultHandler { @Override public void characters(char[] ch, int start, int length) throws SAXException { throw new SAXException("Test exception during parsing"); } } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestBaseNullConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestBaseNullConfigurat100644 35275 12232154104 33603 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.math.BigDecimal; import java.math.BigInteger; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Properties; import org.junit.Before; import org.junit.Test; /** * Tests some basic functions of the BaseConfiguration class. Missing keys might * return null. * * @version $Id: TestBaseNullConfiguration.java 1222842 2011-12-23 20:56:58Z oheger $ */ public class TestBaseNullConfiguration { protected BaseConfiguration config; @Before public void setUp() throws Exception { config = new BaseConfiguration(); config.setThrowExceptionOnMissing(false); } @Test public void testThrowExceptionOnMissing() { assertFalse("Throw Exception Property is set!", config.isThrowExceptionOnMissing()); } @Test public void testGetProperty() { /* should be empty and return null */ assertEquals("This returns null", config.getProperty("foo"), null); /* add a real value, and get it two different ways */ config.setProperty("number", "1"); assertEquals("This returns '1'", config.getProperty("number"), "1"); assertEquals("This returns '1'", config.getString("number"), "1"); } @Test public void testGetByte() { config.setProperty("number", "1"); byte oneB = 1; byte twoB = 2; assertEquals("This returns 1(byte)", oneB, config.getByte("number")); assertEquals("This returns 1(byte)", oneB, config.getByte("number", twoB)); assertEquals("This returns 2(default byte)", twoB, config.getByte("numberNotInConfig", twoB)); assertEquals("This returns 1(Byte)", new Byte(oneB), config.getByte("number", new Byte("2"))); } @Test(expected = NoSuchElementException.class) public void testGetByteUnknown() { config.getByte("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetByteIncompatibleType() { config.setProperty("test.empty", ""); config.getByte("test.empty"); } @Test public void testGetShort() { config.setProperty("numberS", "1"); short oneS = 1; short twoS = 2; assertEquals("This returns 1(short)", oneS, config.getShort("numberS")); assertEquals("This returns 1(short)", oneS, config.getShort("numberS", twoS)); assertEquals("This returns 2(default short)", twoS, config.getShort("numberNotInConfig", twoS)); assertEquals("This returns 1(Short)", new Short(oneS), config.getShort("numberS", new Short("2"))); } @Test(expected = NoSuchElementException.class) public void testGetShortUnknown() { config.getShort("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetShortIncompatibleType() { config.setProperty("test.empty", ""); config.getShort("test.empty"); } @Test public void testGetLong() { config.setProperty("numberL", "1"); long oneL = 1; long twoL = 2; assertEquals("This returns 1(long)", oneL, config.getLong("numberL")); assertEquals("This returns 1(long)", oneL, config.getLong("numberL", twoL)); assertEquals("This returns 2(default long)", twoL, config.getLong("numberNotInConfig", twoL)); assertEquals("This returns 1(Long)", new Long(oneL), config.getLong("numberL", new Long("2"))); } @Test(expected = NoSuchElementException.class) public void testGetLongUnknown() { config.getLong("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetLongIncompatibleTypes() { config.setProperty("test.empty", ""); config.getLong("test.empty"); } @Test public void testGetFloat() { config.setProperty("numberF", "1.0"); float oneF = 1; float twoF = 2; assertEquals("This returns 1(float)", oneF, config.getFloat("numberF"), 0); assertEquals("This returns 1(float)", oneF, config.getFloat("numberF", twoF), 0); assertEquals("This returns 2(default float)", twoF, config.getFloat("numberNotInConfig", twoF), 0); assertEquals("This returns 1(Float)", new Float(oneF), config.getFloat("numberF", new Float("2"))); } @Test(expected = NoSuchElementException.class) public void testGetFloatUnknown() { config.getFloat("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetFloatIncompatibleType() { config.setProperty("test.empty", ""); config.getFloat("test.empty"); } @Test public void testGetDouble() { config.setProperty("numberD", "1.0"); double oneD = 1; double twoD = 2; assertEquals("This returns 1(double)", oneD, config.getDouble("numberD"), 0); assertEquals("This returns 1(double)", oneD, config.getDouble("numberD", twoD), 0); assertEquals("This returns 2(default double)", twoD, config.getDouble("numberNotInConfig", twoD), 0); assertEquals("This returns 1(Double)", new Double(oneD), config.getDouble("numberD", new Double("2"))); } @Test(expected = NoSuchElementException.class) public void testGetDoubleUnknown() { config.getDouble("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetDoubleIncompatibleType() { config.setProperty("test.empty", ""); config.getDouble("test.empty"); } @Test public void testGetBigDecimal() { config.setProperty("numberBigD", "123.456"); BigDecimal number = new BigDecimal("123.456"); BigDecimal defaultValue = new BigDecimal("654.321"); assertEquals("Existing key", number, config.getBigDecimal("numberBigD")); assertEquals("Existing key with default value", number, config.getBigDecimal("numberBigD", defaultValue)); assertEquals("Missing key with default value", defaultValue, config.getBigDecimal("numberNotInConfig", defaultValue)); } @Test public void testGetBigDecimalUnknown() { assertNull("Missing Key is not null!", config.getBigDecimal("numberNotInConfig")); } @Test(expected = ConversionException.class) public void testGetBigDecimalIncompatibleType() { config.setProperty("test.empty", ""); config.getBigDecimal("test.empty"); } @Test public void testGetBigInteger() { config.setProperty("numberBigI", "1234567890"); BigInteger number = new BigInteger("1234567890"); BigInteger defaultValue = new BigInteger("654321"); assertEquals("Existing key", number, config.getBigInteger("numberBigI")); assertEquals("Existing key with default value", number, config.getBigInteger("numberBigI", defaultValue)); assertEquals("Missing key with default value", defaultValue, config.getBigInteger("numberNotInConfig", defaultValue)); } @Test public void testGetBigIntegerUnknown() { assertNull("Missing Key is not null!", config.getBigInteger("numberNotInConfig")); } @Test(expected = ConversionException.class) public void testGetBigIntegerIncompatibleType() { config.setProperty("test.empty", ""); config.getBigInteger("test.empty"); } @Test public void testGetString() { config.setProperty("testString", "The quick brown fox"); String string = new String("The quick brown fox"); String defaultValue = new String("jumps over the lazy dog"); assertEquals("Existing key", string, config.getString("testString")); assertEquals("Existing key with default value", string, config.getString("testString", defaultValue)); assertEquals("Missing key with default value", defaultValue, config.getString("stringNotInConfig", defaultValue)); } @Test public void testGetStringUnknown() { assertNull("Missing Key is not null!", config.getString("stringNotInConfig")); } @Test public void testGetBoolean() { config.setProperty("boolA", Boolean.TRUE); boolean boolT = true, boolF = false; assertEquals("This returns true", boolT, config.getBoolean("boolA")); assertEquals("This returns true, not the default", boolT, config.getBoolean("boolA", boolF)); assertEquals("This returns false(default)", boolF, config.getBoolean("boolNotInConfig", boolF)); assertEquals("This returns true(Boolean)", new Boolean(boolT), config.getBoolean("boolA", new Boolean(boolF))); } @Test(expected = NoSuchElementException.class) public void testGetBooleanUnknown() { config.getBoolean("numberNotInConfig"); } @Test(expected = ConversionException.class) public void testGetBooleanIncompatibleType() { config.setProperty("test.empty", ""); config.getBoolean("test.empty"); } @Test public void testGetList() { config.addProperty("number", "1"); config.addProperty("number", "2"); List list = config.getList("number"); assertNotNull("The list is null", list); assertEquals("List size", 2, list.size()); assertTrue("The number 1 is missing from the list", list.contains("1")); assertTrue("The number 2 is missing from the list", list.contains("2")); } @Test public void testGetListAsScalar() { config.addProperty("number", "1"); config.addProperty("number", "2"); assertEquals("Wrong value", "1", config.getString("number")); } @Test public void testCommaSeparatedString() { String prop = "hey, that's a test"; config.setProperty("prop.string", prop); List list = config.getList("prop.string"); assertEquals("Wrong number of elements", 2, list.size()); assertEquals("Wrong element 1", "hey", list.get(0)); } @Test public void testCommaSeparatedStringEscaped() { String prop2 = "hey\\, that's a test"; config.clearProperty("prop.string"); config.setProperty("prop.string", prop2); assertEquals("Wrong value", "hey, that's a test", config.getString("prop.string")); } @Test public void testPropertyAccess() { config.clearProperty("prop.properties"); config.setProperty("prop.properties", ""); assertEquals( "This returns an empty Properties object", config.getProperties("prop.properties"), new Properties()); config.clearProperty("prop.properties"); config.setProperty("prop.properties", "foo=bar, baz=moo, seal=clubber"); Properties p = new Properties(); p.setProperty("foo", "bar"); p.setProperty("baz", "moo"); p.setProperty("seal", "clubber"); assertEquals( "This returns a filled in Properties object", config.getProperties("prop.properties"), p); } @Test public void testSubset() { /* * test subset : assure we don't reprocess the data elements * when generating the subset */ String prop = "hey, that's a test"; String prop2 = "hey\\, that's a test"; config.setProperty("prop.string", prop2); config.setProperty("property.string", "hello"); Configuration subEprop = config.subset("prop"); assertEquals( "Returns the full string", prop, subEprop.getString("string")); assertEquals("Wrong list size", 1, subEprop.getList("string").size()); Iterator it = subEprop.getKeys(); it.next(); assertFalse(it.hasNext()); subEprop = config.subset("prop."); it = subEprop.getKeys(); assertFalse(it.hasNext()); } @Test public void testInterpolation() throws Exception { config.setProperty("applicationRoot", "/home/applicationRoot"); config.setProperty("db", "${applicationRoot}/db/hypersonic"); String unInterpolatedValue = "${applicationRoot2}/db/hypersonic"; config.setProperty("dbFailedInterpolate", unInterpolatedValue); String dbProp = "/home/applicationRoot/db/hypersonic"; //construct a new config, using config as the defaults config for it. BaseConfiguration superProp = config; assertEquals( "Checking interpolated variable",dbProp, superProp.getString("db")); assertEquals( "lookup fails, leave variable as is", superProp.getString("dbFailedInterpolate"), unInterpolatedValue); superProp.setProperty("arrayInt", "${applicationRoot}/1"); String[] arrayInt = superProp.getStringArray("arrayInt"); assertEquals( "check first entry was interpolated", "/home/applicationRoot/1", arrayInt[0]); } @Test public void testMultipleInterpolation() throws Exception { config.setProperty("test.base-level", "/base-level"); config.setProperty("test.first-level", "${test.base-level}/first-level"); config.setProperty( "test.second-level", "${test.first-level}/second-level"); config.setProperty( "test.third-level", "${test.second-level}/third-level"); String expectedValue = "/base-level/first-level/second-level/third-level"; assertEquals(config.getString("test.third-level"), expectedValue); } @Test(expected = IllegalStateException.class) public void testInterpolationLoop() throws Exception { config.setProperty("test.a", "${test.b}"); config.setProperty("test.b", "${test.a}"); config.getString("test.a"); } } ././@LongLink100644 0 0 147 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestCatalogResolver.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestCatalogResolver.ja100644 6206 12232154104 33511 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import org.apache.commons.configuration.resolver.CatalogResolver; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test class for CatalogResolver. * * @version $Id: TestCatalogResolver.java 1223006 2011-12-24 19:41:41Z oheger $ */ public class TestCatalogResolver { private static final String CATALOG_FILES = "catalog.xml"; private static final String PUBLIC_FILE = "testResolver.xml"; private static final String REWRITE_SYSTEM_FILE = "test.properties.xml"; private static final String REWRITE_SCHEMA_FILE = "sample.xml"; private CatalogResolver resolver; private XMLConfiguration config; @Before public void setUp() throws Exception { resolver = new CatalogResolver(); resolver.setCatalogFiles(CATALOG_FILES); // resolver.setDebug(true); config = new XMLConfiguration(); config.setEntityResolver(resolver); } @After public void tearDown() throws Exception { resolver = null; config = null; } @Test public void testPublic() throws Exception { config.setFileName(PUBLIC_FILE); config.load(); } @Test public void testRewriteSystem() throws Exception { config.setFileName(REWRITE_SYSTEM_FILE); config.load(); } /** * Tests that the schema can be resolved and that XMLConfiguration will * validate the file using the schema. * @throws Exception */ @Test public void testSchemaResolver() throws Exception { config.setFileName(REWRITE_SCHEMA_FILE); config.setSchemaValidation(true); config.load(); } @Test public void testDebug() throws Exception { resolver.setDebug(true); // There is no really good way to check this except to do something // that causes debug output. } @Test public void testLogger() throws Exception { Log log = LogFactory.getLog(this.getClass()); resolver.setLogger(log); assertNotNull("No Logger returned", resolver.getLogger()); assertTrue("Incorrect Logger", log == resolver.getLogger()); } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestCombinedConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestCombinedConfigurat100644 106132 12232154104 33625 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.text.MessageFormat; import java.util.Collection; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import junit.framework.Assert; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy; import org.apache.commons.configuration.reloading.FileRandomReloadingStrategy; import org.apache.commons.configuration.tree.DefaultExpressionEngine; import org.apache.commons.configuration.tree.MergeCombiner; import org.apache.commons.configuration.tree.NodeCombiner; import org.apache.commons.configuration.tree.OverrideCombiner; import org.apache.commons.configuration.tree.UnionCombiner; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; /** * Test class for CombinedConfiguration. * * @version $Id: TestCombinedConfiguration.java 1327061 2012-04-17 12:18:27Z rgoers $ */ public class TestCombinedConfiguration { /** Constant for the name of a sub configuration. */ private static final String TEST_NAME = "SUBCONFIG"; /** Constant for a test key. */ private static final String TEST_KEY = "test.value"; /** Constant for the name of the first child configuration.*/ private static final String CHILD1 = TEST_NAME + "1"; /** Constant for the name of the second child configuration.*/ private static final String CHILD2 = TEST_NAME + "2"; /** Constant for the name of the XML reload test file.*/ private static final String RELOAD_XML_NAME = "reload.xml"; /** Constant for the content of a XML reload test file.*/ private static final String RELOAD_XML_CONTENT = "{0}"; /** Constant for the name of the properties reload test file.*/ private static final String RELOAD_PROPS_NAME = "reload.properties"; /** Constant for the content of a properties reload test file.*/ private static final String RELOAD_PROPS_CONTENT = "propsReload = {0}"; /** Helper object for managing temporary files. */ @Rule public TemporaryFolder folder = new TemporaryFolder(); /** The configuration to be tested. */ private CombinedConfiguration config; /** The test event listener. */ private CombinedListener listener; @Before public void setUp() throws Exception { config = new CombinedConfiguration(); listener = new CombinedListener(); config.addConfigurationListener(listener); } /** * Tests accessing a newly created combined configuration. */ @Test public void testInit() { assertEquals("Already configurations contained", 0, config .getNumberOfConfigurations()); assertTrue("Set of names is not empty", config.getConfigurationNames() .isEmpty()); assertTrue("Wrong node combiner", config.getNodeCombiner() instanceof UnionCombiner); assertNull("Test config was found", config.getConfiguration(TEST_NAME)); assertFalse("Force reload check flag is set", config.isForceReloadCheck()); } /** * Tests adding a configuration (without further information). */ @Test public void testAddConfiguration() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c); checkAddConfig(c); assertEquals("Wrong number of configs", 1, config .getNumberOfConfigurations()); assertTrue("Name list is not empty", config.getConfigurationNames() .isEmpty()); assertSame("Added config not found", c, config.getConfiguration(0)); assertTrue("Wrong property value", config.getBoolean(TEST_KEY)); listener.checkEvent(1, 0); } /** * Tests adding a configuration with a name. */ @Test public void testAddConfigurationWithName() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c, TEST_NAME); checkAddConfig(c); assertEquals("Wrong number of configs", 1, config .getNumberOfConfigurations()); assertSame("Added config not found", c, config.getConfiguration(0)); assertSame("Added config not found by name", c, config .getConfiguration(TEST_NAME)); Set names = config.getConfigurationNames(); assertEquals("Wrong number of config names", 1, names.size()); assertTrue("Name not found", names.contains(TEST_NAME)); assertTrue("Wrong property value", config.getBoolean(TEST_KEY)); listener.checkEvent(1, 0); } /** * Tests adding a configuration with a name when this name already exists. * This should cause an exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testAddConfigurationWithNameTwice() { config.addConfiguration(setUpTestConfiguration(), TEST_NAME); config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "prefix"); } /** * Tests adding a configuration and specifying an at position. */ @Test public void testAddConfigurationAt() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c, null, "my"); checkAddConfig(c); assertTrue("Wrong property value", config.getBoolean("my." + TEST_KEY)); } /** * Tests adding a configuration with a complex at position. Here the at path * contains a dot, which must be escaped. */ @Test public void testAddConfigurationComplexAt() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c, null, "This..is.a.complex"); checkAddConfig(c); assertTrue("Wrong property value", config .getBoolean("This..is.a.complex." + TEST_KEY)); } /** * Checks if a configuration was correctly added to the combined config. * * @param c the config to check */ private void checkAddConfig(AbstractConfiguration c) { Collection listeners = c.getConfigurationListeners(); assertEquals("Wrong number of configuration listeners", 1, listeners .size()); assertTrue("Combined config is no listener", listeners.contains(config)); } /** * Tests adding a null configuration. This should cause an exception to be * thrown. */ @Test(expected = IllegalArgumentException.class) public void testAddNullConfiguration() { config.addConfiguration(null); } /** * Tests accessing properties if no configurations have been added. */ @Test public void testAccessPropertyEmpty() { assertFalse("Found a key", config.containsKey(TEST_KEY)); assertNull("Key has a value", config.getString("test.comment")); assertTrue("Config is not empty", config.isEmpty()); } /** * Tests accessing properties if multiple configurations have been added. */ @Test public void testAccessPropertyMulti() { config.addConfiguration(setUpTestConfiguration()); config.addConfiguration(setUpTestConfiguration(), null, "prefix1"); config.addConfiguration(setUpTestConfiguration(), null, "prefix2"); assertTrue("Prop1 not found", config.getBoolean(TEST_KEY)); assertTrue("Prop 2 not found", config.getBoolean("prefix1." + TEST_KEY)); assertTrue("Prop 3 not found", config.getBoolean("prefix2." + TEST_KEY)); assertFalse("Configuration is empty", config.isEmpty()); listener.checkEvent(3, 0); } /** * Tests removing a configuration. */ @Test public void testRemoveConfiguration() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c); checkAddConfig(c); assertTrue("Config could not be removed", config.removeConfiguration(c)); checkRemoveConfig(c); } /** * Tests removing a configuration by index. */ @Test public void testRemoveConfigurationAt() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c); assertSame("Wrong config removed", c, config.removeConfigurationAt(0)); checkRemoveConfig(c); } /** * Tests removing a configuration by name. */ @Test public void testRemoveConfigurationByName() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c, TEST_NAME); assertSame("Wrong config removed", c, config .removeConfiguration(TEST_NAME)); checkRemoveConfig(c); } /** * Tests removing a configuration with a name. */ @Test public void testRemoveNamedConfiguration() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c, TEST_NAME); config.removeConfiguration(c); checkRemoveConfig(c); } /** * Tests removing a named configuration by index. */ @Test public void testRemoveNamedConfigurationAt() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c, TEST_NAME); assertSame("Wrong config removed", c, config.removeConfigurationAt(0)); checkRemoveConfig(c); } /** * Tests removing a configuration that was not added prior. */ @Test public void testRemoveNonContainedConfiguration() { assertFalse("Could remove non contained config", config .removeConfiguration(setUpTestConfiguration())); listener.checkEvent(0, 0); } /** * Tests removing a configuration by name, which is not contained. */ @Test public void testRemoveConfigurationByUnknownName() { assertNull("Could remove configuration by unknown name", config .removeConfiguration("unknownName")); listener.checkEvent(0, 0); } /** * Tests whether a configuration was completely removed. * * @param c the removed configuration */ private void checkRemoveConfig(AbstractConfiguration c) { assertTrue("Listener was not removed", c.getConfigurationListeners() .isEmpty()); assertEquals("Wrong number of contained configs", 0, config .getNumberOfConfigurations()); assertTrue("Name was not removed", config.getConfigurationNames() .isEmpty()); listener.checkEvent(2, 0); } /** * Tests if an update of a contained configuration leeds to an invalidation * of the combined configuration. */ @Test public void testUpdateContainedConfiguration() { AbstractConfiguration c = setUpTestConfiguration(); config.addConfiguration(c); c.addProperty("test.otherTest", "yes"); assertEquals("New property not found", "yes", config .getString("test.otherTest")); listener.checkEvent(2, 0); } /** * Tests if setting a node combiner causes an invalidation. */ @Test public void testSetNodeCombiner() { NodeCombiner combiner = new UnionCombiner(); config.setNodeCombiner(combiner); assertSame("Node combiner was not set", combiner, config .getNodeCombiner()); listener.checkEvent(1, 0); } /** * Tests setting a null node combiner. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testSetNullNodeCombiner() { config.setNodeCombiner(null); } /** * Tests cloning a combined configuration. */ @Test public void testClone() { config.addConfiguration(setUpTestConfiguration()); config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "conf2"); config.addConfiguration(new PropertiesConfiguration(), "props"); CombinedConfiguration cc2 = (CombinedConfiguration) config.clone(); assertEquals("Wrong number of contained configurations", config .getNumberOfConfigurations(), cc2.getNumberOfConfigurations()); assertSame("Wrong node combiner", config.getNodeCombiner(), cc2 .getNodeCombiner()); assertEquals("Wrong number of names", config.getConfigurationNames() .size(), cc2.getConfigurationNames().size()); assertTrue("Event listeners were cloned", cc2 .getConfigurationListeners().isEmpty()); StrictConfigurationComparator comp = new StrictConfigurationComparator(); for (int i = 0; i < config.getNumberOfConfigurations(); i++) { assertNotSame("Configuration at " + i + " was not cloned", config .getConfiguration(i), cc2.getConfiguration(i)); assertEquals("Wrong config class at " + i, config.getConfiguration( i).getClass(), cc2.getConfiguration(i).getClass()); assertTrue("Configs not equal at " + i, comp.compare(config .getConfiguration(i), cc2.getConfiguration(i))); } assertTrue("Combined configs not equal", comp.compare(config, cc2)); } /** * Tests if the cloned configuration is decoupled from the original. */ @Test public void testCloneModify() { config.addConfiguration(setUpTestConfiguration(), TEST_NAME); CombinedConfiguration cc2 = (CombinedConfiguration) config.clone(); assertTrue("Name is missing", cc2.getConfigurationNames().contains( TEST_NAME)); cc2.removeConfiguration(TEST_NAME); assertFalse("Names in original changed", config.getConfigurationNames() .isEmpty()); } /** * Tests clearing a combined configuration. This should remove all contained * configurations. */ @Test public void testClear() { config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "test"); config.addConfiguration(setUpTestConfiguration()); config.clear(); assertEquals("Still configs contained", 0, config .getNumberOfConfigurations()); assertTrue("Still names contained", config.getConfigurationNames() .isEmpty()); assertTrue("Config is not empty", config.isEmpty()); listener.checkEvent(3, 2); } /** * Tests if file-based configurations can be reloaded. */ @Test public void testReloading() throws Exception { config.setForceReloadCheck(true); File testXmlFile = writeReloadFile(RELOAD_XML_NAME, RELOAD_XML_CONTENT, 0); File testPropsFile = writeReloadFile(RELOAD_PROPS_NAME, RELOAD_PROPS_CONTENT, 0); XMLConfiguration c1 = new XMLConfiguration(testXmlFile); c1.setReloadingStrategy(new FileAlwaysReloadingStrategy()); PropertiesConfiguration c2 = new PropertiesConfiguration(testPropsFile); c2.setThrowExceptionOnMissing(true); c2.setReloadingStrategy(new FileAlwaysReloadingStrategy()); config.addConfiguration(c1); config.addConfiguration(c2); assertEquals("Wrong xml reload value", 0, config.getInt("xmlReload")); assertEquals("Wrong props reload value", 0, config .getInt("propsReload")); writeReloadFile(RELOAD_XML_NAME, RELOAD_XML_CONTENT, 1); assertEquals("XML reload not detected", 1, config.getInt("xmlReload")); config.setForceReloadCheck(false); writeReloadFile(RELOAD_PROPS_NAME, RELOAD_PROPS_CONTENT, 1); assertEquals("Props reload detected though check flag is false", 0, config .getInt("propsReload")); } /** * Tests whether the reload check works with a subnode configuration. This * test is related to CONFIGURATION-341. */ @Test public void testReloadingSubnodeConfig() throws IOException, ConfigurationException { config.setForceReloadCheck(true); File testXmlFile = writeReloadFile(RELOAD_XML_NAME, RELOAD_XML_CONTENT, 0); XMLConfiguration c1 = new XMLConfiguration(testXmlFile); c1.setReloadingStrategy(new FileAlwaysReloadingStrategy()); final String prefix = "reloadCheck"; config.addConfiguration(c1, CHILD1, prefix); SubnodeConfiguration sub = config.configurationAt(prefix, true); writeReloadFile(RELOAD_XML_NAME, RELOAD_XML_CONTENT, 1); assertEquals("Reload not detected", 1, sub.getInt("xmlReload")); } /** * Tests whether reloading works for a combined configuration nested in * another combined configuration. */ @Test public void testReloadingNestedCC() throws IOException, ConfigurationException { config.setForceReloadCheck(true); File testXmlFile = writeReloadFile(RELOAD_XML_NAME, RELOAD_XML_CONTENT, 0); File testPropsFile = writeReloadFile(RELOAD_PROPS_NAME, RELOAD_PROPS_CONTENT, 0); XMLConfiguration c1 = new XMLConfiguration(testXmlFile); c1.setReloadingStrategy(new FileAlwaysReloadingStrategy()); PropertiesConfiguration c2 = new PropertiesConfiguration(testPropsFile); c2.setReloadingStrategy(new FileAlwaysReloadingStrategy()); config.addConfiguration(c2); CombinedConfiguration cc2 = new CombinedConfiguration(); cc2.setForceReloadCheck(true); cc2.addConfiguration(c1); config.addConfiguration(cc2); assertEquals("Wrong xml reload value", 0, config.getInt("xmlReload")); writeReloadFile(RELOAD_XML_NAME, RELOAD_XML_CONTENT, 1); assertEquals("XML reload not detected", 1, config.getInt("xmlReload")); } /** * Prepares a test of the getSource() method. */ private void setUpSourceTest() { HierarchicalConfiguration c1 = new HierarchicalConfiguration(); PropertiesConfiguration c2 = new PropertiesConfiguration(); c1.addProperty(TEST_KEY, TEST_NAME); c2.addProperty("another.key", "test"); config.addConfiguration(c1, CHILD1); config.addConfiguration(c2, CHILD2); } /** * Tests the gestSource() method when the source property is defined in a * hierarchical configuration. */ @Test public void testGetSourceHierarchical() { setUpSourceTest(); assertEquals("Wrong source configuration", config .getConfiguration(CHILD1), config.getSource(TEST_KEY)); } /** * Tests whether the source configuration can be detected for non * hierarchical configurations. */ @Test public void testGetSourceNonHierarchical() { setUpSourceTest(); assertEquals("Wrong source configuration", config .getConfiguration(CHILD2), config.getSource("another.key")); } /** * Tests the getSource() method when the passed in key is not contained. * Result should be null in this case. */ @Test public void testGetSourceUnknown() { setUpSourceTest(); assertNull("Wrong result for unknown key", config .getSource("an.unknown.key")); } /** * Tests the getSource() method when a null key is passed in. This should * cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testGetSourceNull() { config.getSource(null); } /** * Tests the getSource() method when the passed in key belongs to the * combined configuration itself. */ @Test public void testGetSourceCombined() { setUpSourceTest(); final String key = "yet.another.key"; config.addProperty(key, Boolean.TRUE); assertEquals("Wrong source for key", config, config.getSource(key)); } /** * Tests the getSource() method when the passed in key refers to multiple * values, which are all defined in the same source configuration. */ @Test public void testGetSourceMulti() { setUpSourceTest(); final String key = "list.key"; config.getConfiguration(CHILD1).addProperty(key, "1,2,3"); assertEquals("Wrong source for multi-value property", config .getConfiguration(CHILD1), config.getSource(key)); } /** * Tests the getSource() method when the passed in key refers to multiple * values defined by different sources. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testGetSourceMultiSources() { setUpSourceTest(); final String key = "list.key"; config.getConfiguration(CHILD1).addProperty(key, "1,2,3"); config.getConfiguration(CHILD2).addProperty(key, "a,b,c"); config.getSource(key); } /** * Tests whether escaped list delimiters are treated correctly. */ @Test public void testEscapeListDelimiters() { PropertiesConfiguration sub = new PropertiesConfiguration(); sub.addProperty("test.pi", "3\\,1415"); config.addConfiguration(sub); assertEquals("Wrong value", "3,1415", config.getString("test.pi")); } /** * Tests whether an invalidate event is fired only after a change. This test * is related to CONFIGURATION-315. */ @Test public void testInvalidateAfterChange() { ConfigurationEvent event = new ConfigurationEvent(config, 0, null, null, true); config.configurationChanged(event); assertEquals("Invalidate event fired", 0, listener.invalidateEvents); event = new ConfigurationEvent(config, 0, null, null, false); config.configurationChanged(event); assertEquals("No invalidate event fired", 1, listener.invalidateEvents); } /** * Tests using a conversion expression engine for child configurations with * strange keys. This test is related to CONFIGURATION-336. */ @Test public void testConversionExpressionEngine() { PropertiesConfiguration child = new PropertiesConfiguration(); child.addProperty("test(a)", "1,2,3"); config.addConfiguration(child); DefaultExpressionEngine engineQuery = new DefaultExpressionEngine(); engineQuery.setIndexStart("<"); engineQuery.setIndexEnd(">"); config.setExpressionEngine(engineQuery); DefaultExpressionEngine engineConvert = new DefaultExpressionEngine(); engineConvert.setIndexStart("["); engineConvert.setIndexEnd("]"); config.setConversionExpressionEngine(engineConvert); assertEquals("Wrong property 1", "1", config.getString("test(a)<0>")); assertEquals("Wrong property 2", "2", config.getString("test(a)<1>")); assertEquals("Wrong property 3", "3", config.getString("test(a)<2>")); } /** * Tests whether reload operations can cause a deadlock when the combined * configuration is accessed concurrently. This test is related to * CONFIGURATION-344. */ @Test public void testDeadlockWithReload() throws ConfigurationException, InterruptedException { final PropertiesConfiguration child = new PropertiesConfiguration( "test.properties"); child.setReloadingStrategy(new FileAlwaysReloadingStrategy()); config.addConfiguration(child); final int count = 1000; class TestDeadlockReloadThread extends Thread { boolean error = false; @Override public void run() { for (int i = 0; i < count && !error; i++) { try { if (!child.getBoolean("configuration.loaded")) { error = true; } } catch (NoSuchElementException nsex) { error = true; } } } } TestDeadlockReloadThread reloadThread = new TestDeadlockReloadThread(); reloadThread.start(); for (int i = 0; i < count; i++) { assertEquals("Wrong value of combined property", 10, config .getInt("test.integer")); } reloadThread.join(); assertFalse("Failure in thread", reloadThread.error); } @Test public void testGetConfigurations() throws Exception { config.addConfiguration(setUpTestConfiguration()); config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "conf2"); AbstractConfiguration pc = new PropertiesConfiguration(); config.addConfiguration(pc, "props"); List list = config.getConfigurations(); assertNotNull("No list of configurations returned", list); assertTrue("Incorrect number of configurations", list.size() == 3); AbstractConfiguration c = list.get(2); assertTrue("Incorrect configuration", c == pc); } @Test public void testGetConfigurationNameList() throws Exception { config.addConfiguration(setUpTestConfiguration()); config.addConfiguration(setUpTestConfiguration(), TEST_NAME, "conf2"); AbstractConfiguration pc = new PropertiesConfiguration(); config.addConfiguration(pc, "props"); List list = config.getConfigurationNameList(); assertNotNull("No list of configurations returned", list); assertTrue("Incorrect number of configurations", list.size() == 3); String name = list.get(1); assertNotNull("No name returned", name); assertTrue("Incorrect configuration name", TEST_NAME.equals(name)); } /** * Tests whether changes on a sub node configuration that is part of a * combined configuration are detected. This test is related to * CONFIGURATION-368. */ @Test public void testReloadWithSubNodeConfig() throws Exception { final String reloadContent = "{0}"; config.setForceReloadCheck(true); config.setNodeCombiner(new OverrideCombiner()); File testXmlFile1 = writeReloadFile(RELOAD_XML_NAME, reloadContent, 0); final String prefix1 = "default"; XMLConfiguration c1 = new XMLConfiguration(testXmlFile1); SubnodeConfiguration sub1 = c1.configurationAt(prefix1, true); assertEquals("Inital test for sub config 1 failed", 0, sub1 .getInt("xmlReload1")); config.addConfiguration(sub1); assertEquals( "Could not get value for sub config 1 from combined config", 0, config.getInt("xmlReload1")); c1.setReloadingStrategy(new FileAlwaysReloadingStrategy()); writeReloadFile(RELOAD_XML_NAME, reloadContent, 1); assertEquals("Reload of sub config 1 not detected", 1, config .getInt("xmlReload1")); } @Test public void testConcurrentGetAndReload() throws Exception { final int threadCount = 5; final int loopCount = 1000; config.setForceReloadCheck(true); config.setNodeCombiner(new MergeCombiner()); final XMLConfiguration xml = new XMLConfiguration("configA.xml"); xml.setReloadingStrategy(new FileRandomReloadingStrategy()); config.addConfiguration(xml); final XMLConfiguration xml2 = new XMLConfiguration("configB.xml"); xml2.setReloadingStrategy(new FileRandomReloadingStrategy()); config.addConfiguration(xml2); config.setExpressionEngine(new XPathExpressionEngine()); assertEquals(config.getString("/property[@name='config']/@value"), "100"); Thread testThreads[] = new Thread[threadCount]; int failures[] = new int[threadCount]; for (int i = 0; i < testThreads.length; ++i) { testThreads[i] = new ReloadThread(config, failures, i, loopCount); testThreads[i].start(); } int totalFailures = 0; for (int i = 0; i < testThreads.length; ++i) { testThreads[i].join(); totalFailures += failures[i]; } assertTrue(totalFailures + " failures Occurred", totalFailures == 0); } /** * Tests whether a combined configuration can be copied to an XML * configuration. This test is related to CONFIGURATION-445. */ @Test public void testCombinedCopyToXML() throws ConfigurationException { XMLConfiguration x1 = new XMLConfiguration(); x1.addProperty("key1", "value1"); x1.addProperty("key1[@override]", "USER1"); x1.addProperty("key2", "value2"); x1.addProperty("key2[@override]", "USER2"); XMLConfiguration x2 = new XMLConfiguration(); x2.addProperty("key2", "value2.2"); x2.addProperty("key2[@override]", "USER2"); config.setNodeCombiner(new OverrideCombiner()); config.addConfiguration(x2); config.addConfiguration(x1); XMLConfiguration x3 = new XMLConfiguration(config); assertEquals("Wrong element value", "value2.2", x3.getString("key2")); assertEquals("Wrong attribute value", "USER2", x3.getString("key2[@override]")); StringWriter w = new StringWriter(); x3.save(w); String s = w.toString(); x3 = new XMLConfiguration(); x3.load(new StringReader(s)); assertEquals("Wrong element value after load", "value2.2", x3.getString("key2")); assertEquals("Wrong attribute value after load", "USER2", x3.getString("key2[@override]")); } private class ReloadThread extends Thread { CombinedConfiguration combined; int[] failures; int index; int count; ReloadThread(CombinedConfiguration config, int[] failures, int index, int count) { combined = config; this.failures = failures; this.index = index; this.count = count; } @Override public void run() { failures[index] = 0; for (int i = 0; i < count; i++) { try { String value = combined.getString("/property[@name='config']/@value"); if (value == null || !value.equals("100")) { ++failures[index]; } } catch (Exception ex) { ++failures[index]; } } } } /** * Helper method for writing a file. The file is also added to a list and * will be deleted in teadDown() automatically. * * @param file the file to be written * @param content the file's content * @throws IOException if an error occurs */ private void writeFile(File file, String content) throws IOException { PrintWriter out = null; try { out = new PrintWriter(new FileWriter(file)); out.print(content); } finally { if (out != null) { out.close(); } } } /** * Helper method for writing a test file. The file will be created in the * test directory. It is also scheduled for automatic deletion after the * test. * * @param fileName the name of the test file * @param content the content of the file * @return the File object for the test file * @throws IOException if an error occurs */ private File writeFile(String fileName, String content) throws IOException { File file = new File(folder.getRoot(), fileName); writeFile(file, content); return file; } /** * Writes a file for testing reload operations. * * @param name the name of the reload test file * @param content the content of the file * @param value the value of the reload test property * @return the file that was written * @throws IOException if an error occurs */ private File writeReloadFile(String name, String content, int value) throws IOException { return writeFile(name, MessageFormat.format(content, new Object[] { new Integer(value) })); } /** * Helper method for creating a test configuration to be added to the * combined configuration. * * @return the test configuration */ private AbstractConfiguration setUpTestConfiguration() { HierarchicalConfiguration config = new HierarchicalConfiguration(); config.addProperty(TEST_KEY, Boolean.TRUE); config.addProperty("test.comment", "This is a test"); return config; } /** * Test event listener class for checking if the expected invalidate events * are fired. */ static class CombinedListener implements ConfigurationListener { int invalidateEvents; int otherEvents; public void configurationChanged(ConfigurationEvent event) { if (event.getType() == CombinedConfiguration.EVENT_COMBINED_INVALIDATE) { invalidateEvents++; } else { otherEvents++; } } /** * Checks if the expected number of events was fired. * * @param expectedInvalidate the expected number of invalidate events * @param expectedOthers the expected number of other events */ public void checkEvent(int expectedInvalidate, int expectedOthers) { Assert.assertEquals("Wrong number of invalidate events", expectedInvalidate, invalidateEvents); Assert.assertEquals("Wrong number of other events", expectedOthers, otherEvents); } } } ././@LongLink100644 0 0 156 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestCompositeConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestCompositeConfigura100644 75262 12232154104 33654 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy; import org.easymock.EasyMock; import org.junit.Before; import org.junit.Test; /** * Test loading multiple configurations. * * @version $Id: TestCompositeConfiguration.java 1233058 2012-01-18 20:49:12Z oheger $ */ public class TestCompositeConfiguration { /** Constant for a test property to be checked.*/ private static final String TEST_PROPERTY = "test.source.property"; protected PropertiesConfiguration conf1; protected PropertiesConfiguration conf2; protected XMLConfiguration xmlConf; protected CompositeConfiguration cc; /** * The File that we test with */ private String testProperties = ConfigurationAssert.getTestFile("test.properties").getAbsolutePath(); private String testProperties2 = ConfigurationAssert.getTestFile("test2.properties").getAbsolutePath(); private String testPropertiesXML = ConfigurationAssert.getTestFile("test.xml").getAbsolutePath(); @Before public void setUp() throws Exception { cc = new CompositeConfiguration(); conf1 = new PropertiesConfiguration(testProperties); conf2 = new PropertiesConfiguration(testProperties2); xmlConf = new XMLConfiguration(new File(testPropertiesXML)); cc.setThrowExceptionOnMissing(true); } @Test public void testThrowExceptionOnMissing() { assertTrue("Throw Exception Property is not set!", cc.isThrowExceptionOnMissing()); } @Test public void testAddRemoveConfigurations() throws Exception { cc.addConfiguration(conf1); assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations()); cc.addConfiguration(conf1); assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations()); cc.addConfiguration(conf2); assertEquals("Number of configurations", 3, cc.getNumberOfConfigurations()); cc.removeConfiguration(conf1); assertEquals("Number of configurations", 2, cc.getNumberOfConfigurations()); cc.clear(); assertEquals("Number of configurations", 1, cc.getNumberOfConfigurations()); } @Test public void testGetPropertyWIncludes() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(conf2); List l = cc.getList("packages"); assertTrue(l.contains("packagea")); } @Test public void testGetProperty() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(conf2); assertEquals("Make sure we get the property from conf1 first", "test.properties", cc.getString("propertyInOrder")); cc.clear(); cc.addConfiguration(conf2); cc.addConfiguration(conf1); assertEquals("Make sure we get the property from conf2 first", "test2.properties", cc.getString("propertyInOrder")); } @Test public void testCantRemoveMemoryConfig() throws Exception { cc.clear(); assertEquals(1, cc.getNumberOfConfigurations()); Configuration internal = cc.getConfiguration(0); cc.removeConfiguration(internal); assertEquals(1, cc.getNumberOfConfigurations()); } @Test public void testGetPropertyMissing() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(conf2); try { assertNull(cc.getString("bogus.property")); fail("Should have thrown a NoSuchElementException"); } catch (NoSuchElementException nsee) { assertTrue(nsee.getMessage().indexOf("bogus.property") > -1); } assertTrue("Should be false", !cc.getBoolean("test.missing.boolean", false)); assertTrue("Should be true", cc.getBoolean("test.missing.boolean.true", true)); } /** * Tests {@code List} parsing. */ @Test public void testMultipleTypesOfConfigs() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); assertEquals("Make sure we get the property from conf1 first", 1, cc.getInt("test.short")); cc.clear(); cc.addConfiguration(xmlConf); cc.addConfiguration(conf1); assertEquals("Make sure we get the property from xml", 8, cc.getInt("test.short")); } @Test public void testPropertyExistsInOnlyOneConfig() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); assertEquals("value", cc.getString("element")); } /** * Tests getting a default when the key doesn't exist */ @Test public void testDefaultValueWhenKeyMissing() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); assertEquals("default", cc.getString("bogus", "default")); assertTrue(1.4 == cc.getDouble("bogus", 1.4)); assertTrue(1.4 == cc.getDouble("bogus", 1.4)); } @Test public void testGettingConfiguration() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); assertEquals(PropertiesConfiguration.class, cc.getConfiguration(0).getClass()); assertEquals(XMLConfiguration.class, cc.getConfiguration(1).getClass()); } /** * Tests setting values. These are set in memory mode only! */ @Test public void testClearingProperty() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); cc.clearProperty("test.short"); assertTrue("Make sure test.short is gone!", !cc.containsKey("test.short")); } /** * Tests adding values. Make sure they _DON'T_ override any other properties but add to the * existing properties and keep sequence */ @Test public void testAddingProperty() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); String[] values = cc.getStringArray("test.short"); assertEquals("Number of values before add is wrong!", 1, values.length); assertEquals("First Value before add is wrong", "1", values[0]); cc.addProperty("test.short", "88"); values = cc.getStringArray("test.short"); assertEquals("Number of values is wrong!", 2, values.length); assertEquals("First Value is wrong", "1", values[0]); assertEquals("Third Value is wrong", "88", values[1]); } /** * Tests setting values. These are set in memory mode only! */ @Test public void testSettingMissingProperty() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); cc.setProperty("my.new.property", "supernew"); assertEquals("supernew", cc.getString("my.new.property")); } /** * Tests retrieving subsets of configurations */ @Test public void testGettingSubset() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); Configuration subset = cc.subset("test"); assertNotNull(subset); assertFalse("Shouldn't be empty", subset.isEmpty()); assertEquals("Make sure the initial loaded configs subset overrides any later add configs subset", "1", subset.getString("short")); cc.setProperty("test.short", "43"); subset = cc.subset("test"); assertEquals("Make sure the initial loaded configs subset overrides any later add configs subset", "43", subset.getString("short")); } /** * Tests subsets and still can resolve elements */ @Test public void testSubsetCanResolve() throws Exception { cc = new CompositeConfiguration(); final BaseConfiguration config = new BaseConfiguration(); config.addProperty("subset.tempfile", "${java.io.tmpdir}/file.tmp"); cc.addConfiguration(config); cc.addConfiguration(ConfigurationConverter.getConfiguration(System.getProperties())); Configuration subset = cc.subset("subset"); assertEquals(System.getProperty("java.io.tmpdir") + "/file.tmp", subset.getString("tempfile")); } /** * Tests {@code List} parsing. */ @Test public void testList() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); List packages = cc.getList("packages"); // we should get 3 packages here assertEquals(3, packages.size()); List defaultList = new ArrayList(); defaultList.add("1"); defaultList.add("2"); packages = cc.getList("packages.which.dont.exist", defaultList); // we should get 2 packages here assertEquals(2, packages.size()); } /** * Tests {@code String} array parsing. */ @Test public void testStringArray() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); String[] packages = cc.getStringArray("packages"); // we should get 3 packages here assertEquals(3, packages.length); packages = cc.getStringArray("packages.which.dont.exist"); // we should get 0 packages here assertEquals(0, packages.length); } @Test public void testGetList() { Configuration conf1 = new BaseConfiguration(); conf1.addProperty("array", "value1"); conf1.addProperty("array", "value2"); Configuration conf2 = new BaseConfiguration(); conf2.addProperty("array", "value3"); conf2.addProperty("array", "value4"); cc.addConfiguration(conf1); cc.addConfiguration(conf2); // check the composite 'array' property List list = cc.getList("array"); assertNotNull("null list", list); assertEquals("list size", 2, list.size()); assertTrue("'value1' not found in the list", list.contains("value1")); assertTrue("'value2' not found in the list", list.contains("value2")); // add an element to the list in the composite configuration cc.addProperty("array", "value5"); // test the new list list = cc.getList("array"); assertNotNull("null list", list); assertEquals("list size", 3, list.size()); assertTrue("'value1' not found in the list", list.contains("value1")); assertTrue("'value2' not found in the list", list.contains("value2")); assertTrue("'value5' not found in the list", list.contains("value5")); } /** * Tests {@code getKeys} preserves the order */ @Test public void testGetKeysPreservesOrder() throws Exception { cc.addConfiguration(conf1); List orderedList = new ArrayList(); for (Iterator keys = conf1.getKeys(); keys.hasNext();) { orderedList.add(keys.next()); } List iteratedList = new ArrayList(); for (Iterator keys = cc.getKeys(); keys.hasNext();) { iteratedList.add(keys.next()); } assertEquals(orderedList.size(), iteratedList.size()); for (int i = 0; i < orderedList.size(); i++) { assertEquals(orderedList.get(i), iteratedList.get(i)); } } /** * Tests {@code getKeys(String key)} preserves the order */ @Test public void testGetKeys2PreservesOrder() throws Exception { cc.addConfiguration(conf1); List orderedList = new ArrayList(); for (Iterator keys = conf1.getKeys("test"); keys.hasNext();) { orderedList.add(keys.next()); } List iteratedList = new ArrayList(); for (Iterator keys = cc.getKeys("test"); keys.hasNext();) { iteratedList.add(keys.next()); } assertEquals(orderedList.size(), iteratedList.size()); for (int i = 0; i < orderedList.size(); i++) { assertEquals(orderedList.get(i), iteratedList.get(i)); } } @Test public void testGetStringWithDefaults() { BaseConfiguration defaults = new BaseConfiguration(); defaults.addProperty("default", "default string"); CompositeConfiguration c = new CompositeConfiguration(defaults); c.setThrowExceptionOnMissing(cc.isThrowExceptionOnMissing()); c.addProperty("string", "test string"); assertEquals("test string", c.getString("string")); try { c.getString("XXX"); fail("Should throw NoSuchElementException exception"); } catch (NoSuchElementException e) { //ok } catch (Exception e) { fail("Should throw NoSuchElementException exception, not " + e); } //test defaults assertEquals("test string", c.getString("string", "some default value")); assertEquals("default string", c.getString("default")); assertEquals("default string", c.getString("default", "some default value")); assertEquals("some default value", c.getString("XXX", "some default value")); } @Test public void testCheckingInMemoryConfiguration() throws Exception { String TEST_KEY = "testKey"; Configuration defaults = new PropertiesConfiguration(); defaults.setProperty(TEST_KEY, "testValue"); Configuration testConfiguration = new CompositeConfiguration(defaults); assertTrue(testConfiguration.containsKey(TEST_KEY)); assertFalse(testConfiguration.isEmpty()); boolean foundTestKey = false; Iterator i = testConfiguration.getKeys(); //assertTrue(i instanceof IteratorChain); //IteratorChain ic = (IteratorChain)i; //assertEquals(2,i.size()); for (; i.hasNext();) { String key = i.next(); if (key.equals(TEST_KEY)) { foundTestKey = true; } } assertTrue(foundTestKey); testConfiguration.clearProperty(TEST_KEY); assertFalse(testConfiguration.containsKey(TEST_KEY)); } @Test public void testStringArrayInterpolation() { CompositeConfiguration config = new CompositeConfiguration(); config.addProperty("base", "foo"); config.addProperty("list", "${base}.bar1"); config.addProperty("list", "${base}.bar2"); config.addProperty("list", "${base}.bar3"); String[] array = config.getStringArray("list"); assertEquals("size", 3, array.length); assertEquals("1st element", "foo.bar1", array[0]); assertEquals("2nd element", "foo.bar2", array[1]); assertEquals("3rd element", "foo.bar3", array[2]); } /** * Tests whether global interpolation works with lists. */ @Test public void testListInterpolation() { PropertiesConfiguration c1 = new PropertiesConfiguration(); c1.addProperty("c1.value", "test1"); c1.addProperty("c1.value", "${c2.value}"); cc.addConfiguration(c1); PropertiesConfiguration c2 = new PropertiesConfiguration(); c2.addProperty("c2.value", "test2"); cc.addConfiguration(c2); List lst = cc.getList("c1.value"); assertEquals("Wrong list size", 2, lst.size()); assertEquals("Wrong first element", "test1", lst.get(0)); assertEquals("Wrong second element", "test2", lst.get(1)); } /** * Tests interpolation in combination with reloading. */ @Test public void testInterpolationWithReload() throws IOException, ConfigurationException { File testFile = new File("target/testConfig.properties"); final String propFirst = "first.name"; final String propFull = "full.name"; try { writeTestConfig(testFile, propFirst, "John"); PropertiesConfiguration c1 = new PropertiesConfiguration(testFile); c1.setReloadingStrategy(new FileAlwaysReloadingStrategy()); PropertiesConfiguration c2 = new PropertiesConfiguration(); c2.addProperty(propFull, "${" + propFirst + "} Doe"); CompositeConfiguration cc = new CompositeConfiguration(); cc.addConfiguration(c1); cc.addConfiguration(c2); assertEquals("Wrong name", "John Doe", cc.getString(propFull)); writeTestConfig(testFile, propFirst, "Jane"); assertEquals("First name not changed", "Jane", c1 .getString(propFirst)); assertEquals("First name not changed in composite", "Jane", cc .getString(propFirst)); assertEquals("Full name not changed", "Jane Doe", cc .getString(propFull)); } finally { if (testFile.exists()) { testFile.delete(); } } } /** * Writes a test properties file containing a single property definition. * * @param f the file to write * @param prop the property name * @param value the property value * @throws IOException if an error occurs */ private void writeTestConfig(File f, String prop, String value) throws IOException { PrintWriter out = new PrintWriter(new FileWriter(f)); out.print(prop); out.print("="); out.println(value); out.close(); } @Test public void testInstanciateWithCollection() { Collection configs = new ArrayList(); configs.add(xmlConf); configs.add(conf1); configs.add(conf2); CompositeConfiguration config = new CompositeConfiguration(configs); assertEquals("Number of configurations", 4, config.getNumberOfConfigurations()); assertTrue("The in memory configuration is not empty", config.getInMemoryConfiguration().isEmpty()); } @Test public void testClone() { CompositeConfiguration cc2 = (CompositeConfiguration) cc.clone(); assertEquals("Wrong number of contained configurations", cc .getNumberOfConfigurations(), cc2.getNumberOfConfigurations()); StrictConfigurationComparator comp = new StrictConfigurationComparator(); for (int i = 0; i < cc.getNumberOfConfigurations(); i++) { assertEquals("Wrong configuration class at " + i, cc .getConfiguration(i).getClass(), cc2.getConfiguration(i) .getClass()); assertNotSame("Configuration was not cloned", cc .getConfiguration(i), cc2.getConfiguration(i)); assertTrue("Configurations at " + i + " not equal", comp.compare(cc .getConfiguration(i), cc2.getConfiguration(i))); } assertTrue("Configurations are not equal", comp.compare(cc, cc2)); } /** * Tests cloning if one of the contained configurations does not support * this operation. This should cause an exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testCloneNotSupported() { cc.addConfiguration(new NonCloneableConfiguration()); cc.clone(); } /** * Ensures that event listeners are not cloned. */ @Test public void testCloneEventListener() { cc.addConfigurationListener(new TestEventListenerImpl()); CompositeConfiguration cc2 = (CompositeConfiguration) cc.clone(); assertTrue("Listeners have been cloned", cc2 .getConfigurationListeners().isEmpty()); } /** * Tests whether add property events are triggered. */ @Test public void testEventAddProperty() { TestEventListenerImpl l = new TestEventListenerImpl(); cc.addConfigurationListener(l); cc.addProperty("test", "value"); assertEquals("No add events received", 2, l.eventCount); } /** * Tests whether set property events are triggered. */ @Test public void testEventSetProperty() { TestEventListenerImpl l = new TestEventListenerImpl(); cc.addConfigurationListener(l); cc.setProperty("test", "value"); assertEquals("No set events received", 2, l.eventCount); } /** * Tests whether clear property events are triggered. */ @Test public void testEventClearProperty() { cc.addConfiguration(conf1); assertTrue("Wrong value for property", cc .getBoolean("configuration.loaded")); TestEventListenerImpl l = new TestEventListenerImpl(); cc.addConfigurationListener(l); cc.clearProperty("configuration.loaded"); assertFalse("Key still present", cc.containsKey("configuration.loaded")); assertEquals("No clear events received", 2, l.eventCount); } /** * Tests changing the list delimiter character. */ @Test public void testSetListDelimiter() { cc.setListDelimiter('/'); checkSetListDelimiter(); } /** * Tests whether the correct list delimiter is set after a clear operation. */ @Test public void testSetListDelimiterAfterClear() { cc.setListDelimiter('/'); cc.clear(); checkSetListDelimiter(); } /** * Helper method for testing whether the list delimiter is correctly * handled. */ private void checkSetListDelimiter() { cc.addProperty("test.list", "a/b/c"); cc.addProperty("test.property", "a,b,c"); assertEquals("Wrong number of list elements", 3, cc .getList("test.list").size()); assertEquals("Wrong value of property", "a,b,c", cc .getString("test.property")); } /** * Tests whether list splitting can be disabled. */ @Test public void testSetDelimiterParsingDisabled() { cc.setDelimiterParsingDisabled(true); checkSetListDelimiterParsingDisabled(); } /** * Tests whether the list parsing flag is correctly handled after a clear() * operation. */ @Test public void testSetDelimiterParsingDisabledAfterClear() { cc.setDelimiterParsingDisabled(true); cc.clear(); checkSetListDelimiterParsingDisabled(); } /** * Helper method for checking whether the list parsing flag is correctly * handled. */ private void checkSetListDelimiterParsingDisabled() { cc.addProperty("test.property", "a,b,c"); assertEquals("Wrong value of property", "a,b,c", cc .getString("test.property")); } /** * Prepares a test of the getSource() method. */ private void setUpSourceTest() { cc.addConfiguration(conf1); cc.addConfiguration(conf2); } /** * Tests the getSource() method if the property is defined in a single child * configuration. */ @Test public void testGetSourceSingle() { setUpSourceTest(); conf1.addProperty(TEST_PROPERTY, Boolean.TRUE); assertSame("Wrong source configuration", conf1, cc .getSource(TEST_PROPERTY)); } /** * Tests the getSource() method for an unknown property key. */ @Test public void testGetSourceUnknown() { setUpSourceTest(); assertNull("Wrong source for unknown key", cc.getSource(TEST_PROPERTY)); } /** * Tests the getSource() method for a property contained in the in memory * configuration. */ @Test public void testGetSourceInMemory() { setUpSourceTest(); cc.addProperty(TEST_PROPERTY, Boolean.TRUE); assertSame("Source not found in in-memory config", cc .getInMemoryConfiguration(), cc.getSource(TEST_PROPERTY)); } /** * Tests the getSource() method if the property is defined by multiple child * configurations. In this case an exception should be thrown. */ @Test(expected = IllegalArgumentException.class) public void testGetSourceMultiple() { setUpSourceTest(); conf1.addProperty(TEST_PROPERTY, Boolean.TRUE); cc.addProperty(TEST_PROPERTY, "a value"); cc.getSource(TEST_PROPERTY); } /** * Tests the getSource() method for a null key. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testGetSourceNull() { cc.getSource(null); } /** * Prepares a test for interpolation with multiple configurations and * similar properties. */ private void prepareInterpolationTest() { PropertiesConfiguration p = new PropertiesConfiguration(); p.addProperty("foo", "initial"); p.addProperty("bar", "${foo}"); p.addProperty("prefix.foo", "override"); cc.addConfiguration(p.subset("prefix")); cc.addConfiguration(p); assertEquals("Wrong value on direct access", "override", cc .getString("bar")); } /** * Tests querying a list when a tricky interpolation is involved. This is * related to CONFIGURATION-339. */ @Test public void testGetListWithInterpolation() { prepareInterpolationTest(); List lst = cc.getList("bar"); assertEquals("Wrong number of values", 1, lst.size()); assertEquals("Wrong value in list", "override", lst.get(0)); } /** * Tests querying a string array when a tricky interpolation is involved. */ @Test public void testGetStringArrayWithInterpolation() { prepareInterpolationTest(); String[] values = cc.getStringArray("bar"); assertEquals("Wrong number of values", 1, values.length); assertEquals("Wrong value in array", "override", values[0]); } /** * Tests whether interpolation works if multiple configurations are * involved. This test is related to CONFIGURATION-441. */ @Test public void testInterpolationInMultipleConfigs() { Configuration c1 = new PropertiesConfiguration(); c1.addProperty("property.one", "one"); c1.addProperty("property.two", "two"); Configuration c2 = new PropertiesConfiguration(); c2.addProperty("property.one.ref", "${property.one}"); cc.addConfiguration(c1); cc.addConfiguration(c2); assertEquals("Wrong interpolated value", "one", cc.getString("property.one.ref")); } /** * Tests the behavior of setListDelimiter() if the in-memory configuration * is not derived from BaseConfiguration. This test is related to * CONFIGURATION-476. */ @Test public void testSetListDelimiterInMemoryConfigNonBaseConfig() { Configuration inMemoryConfig = EasyMock.createMock(Configuration.class); EasyMock.replay(inMemoryConfig); cc = new CompositeConfiguration(inMemoryConfig); cc.setListDelimiter(';'); } /** * Tests the behavior of setDelimiterParsingDisabled() if the in-memory * configuration is not derived from BaseConfiguration. This test is related * to CONFIGURATION-476. */ @Test public void testSetDelimiterParsingDisabledInMemoryConfigNonBaseConfig() { Configuration inMemoryConfig = EasyMock.createMock(Configuration.class); EasyMock.replay(inMemoryConfig); cc = new CompositeConfiguration(inMemoryConfig); cc.setDelimiterParsingDisabled(true); } /** * Tests whether a configuration can act as both regular child configuration * and in-memory configuration. This test is related to CONFIGURATION-471. */ @Test public void testUseChildConfigAsInMemoryConfig() { conf1.setProperty(TEST_PROPERTY, "conf1"); conf2.setProperty(TEST_PROPERTY, "conf2"); cc.addConfiguration(conf1, true); cc.addConfiguration(conf2); assertEquals("Wrong number of configurations", 2, cc.getNumberOfConfigurations()); assertEquals("Wrong property", "conf1", cc.getString(TEST_PROPERTY)); cc.addProperty("newProperty", "newValue"); assertEquals("Not added to in-memory config", "newValue", conf1.getString("newProperty")); } /** * Tests whether the in-memory configuration can be replaced by a new child * configuration. */ @Test public void testReplaceInMemoryConfig() { conf1.setProperty(TEST_PROPERTY, "conf1"); conf2.setProperty(TEST_PROPERTY, "conf2"); cc.addConfiguration(conf1, true); cc.addProperty("newProperty1", "newValue1"); cc.addConfiguration(conf2, true); cc.addProperty("newProperty2", "newValue2"); assertEquals("Wrong property", "conf1", cc.getString(TEST_PROPERTY)); assertEquals("Not added to in-memory config", "newValue1", conf1.getString("newProperty1")); assertEquals("In-memory config not changed", "newValue2", conf2.getString("newProperty2")); } /** * A test configuration event listener that counts the number of received * events. Used for testing the event facilities. */ static class TestEventListenerImpl implements ConfigurationListener { /** The number of received events.*/ int eventCount; public void configurationChanged(ConfigurationEvent event) { eventCount++; } } } ././@LongLink100644 0 0 201 12232154257 10247 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestCompositeConfigurationNonStringProperties.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestCompositeConfigura100644 3032 12232154104 33616 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import org.junit.Before; /** * Test if non-string properties are handled correctly. * * @version $Id: TestCompositeConfigurationNonStringProperties.java 1222445 2011-12-22 20:53:47Z oheger $ */ public class TestCompositeConfigurationNonStringProperties extends BaseNonStringProperties { /** The File that we test with */ private String testProperties = ConfigurationAssert.getTestFile("test.properties").getAbsolutePath(); @Before public void setUp() throws Exception { CompositeConfiguration cc = new CompositeConfiguration(); cc.addConfiguration(new PropertiesConfiguration(testProperties)); conf = cc; nonStringTestHolder.setConfiguration(conf); } } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfiguration.java100644 2766 12232154104 33562 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.UUID; import org.junit.Assert; import org.junit.Test; public class TestConfiguration { @Test public void testConfigurationGetList() { final List defaults = new ArrayList(); String key = UUID.randomUUID().toString(); for (int i = 0; i < 10; i++) { defaults.add(UUID.randomUUID().toString()); } final Configuration c = new MapConfiguration(Collections.emptyMap()); final List values = c.getList(key, defaults); Assert.assertEquals(defaults, values); } } ././@LongLink100644 0 0 156 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationConverter.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationConve100644 12472 12232154104 33650 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.util.List; import java.util.Map; import java.util.Properties; import org.apache.commons.collections.ExtendedProperties; import org.junit.Test; /** * Tests the ConfigurationConverter class. * * @author Martin Poeschl * @author Emmanuel Bourg * @version $Id: TestConfigurationConverter.java 1223010 2011-12-24 20:21:36Z oheger $ */ public class TestConfigurationConverter { @Test public void testExtendedPropertiesToConfiguration() { ExtendedProperties eprops = new ExtendedProperties(); eprops.setProperty("string", "teststring"); eprops.setProperty("int", "123"); eprops.addProperty("list", "item 1"); eprops.addProperty("list", "item 2"); Configuration config = ConfigurationConverter.getConfiguration(eprops); assertEquals("This returns 'teststring'", "teststring", config.getString("string")); List item1 = config.getList("list"); assertEquals("This returns 'item 1'", "item 1", item1.get(0)); assertEquals("This returns 123", 123, config.getInt("int")); } @Test public void testPropertiesToConfiguration() { Properties props = new Properties(); props.setProperty("string", "teststring"); props.setProperty("int", "123"); props.setProperty("list", "item 1, item 2"); Configuration config = ConfigurationConverter.getConfiguration(props); assertEquals("This returns 'teststring'", "teststring", config.getString("string")); List item1 = config.getList("list"); assertEquals("This returns 'item 1'", "item 1", item1.get(0)); assertEquals("This returns 123", 123, config.getInt("int")); } @Test public void testConfigurationToExtendedProperties() { Configuration config = new BaseConfiguration(); config.setProperty("string", "teststring"); config.setProperty("int", "123"); config.addProperty("list", "item 1"); config.addProperty("list", "item 2"); ExtendedProperties eprops = ConfigurationConverter.getExtendedProperties(config); assertEquals("This returns 'teststring'", "teststring", eprops.getString("string")); List list = eprops.getVector("list"); assertEquals("This returns 'item 1'", "item 1", list.get(0)); assertEquals("This returns 123", 123, eprops.getInt("int")); } @Test public void testConfigurationToProperties() { BaseConfiguration config = new BaseConfiguration(); config.addProperty("string", "teststring"); config.addProperty("array", "item 1"); config.addProperty("array", "item 2"); config.addProperty("interpolated", "${string}"); config.addProperty("interpolated-array", "${interpolated}"); config.addProperty("interpolated-array", "${interpolated}"); Properties props = ConfigurationConverter.getProperties(config); assertNotNull("null properties", props); assertEquals("'string' property", "teststring", props.getProperty("string")); assertEquals("'interpolated' property", "teststring", props.getProperty("interpolated")); assertEquals("'array' property", "item 1,item 2", props.getProperty("array")); assertEquals("'interpolated-array' property", "teststring,teststring", props.getProperty("interpolated-array")); // change the list delimiter config.setListDelimiter(';'); props = ConfigurationConverter.getProperties(config); assertEquals("'array' property", "item 1;item 2", props.getProperty("array")); } /** * Tests the conversion of a configuration object to properties if scalar * values are involved. This test is related to CONFIGURATION-432. */ @Test public void testConfigurationToPropertiesScalarValue() { BaseConfiguration config = new BaseConfiguration(); config.addProperty("scalar", new Integer(42)); Properties props = ConfigurationConverter.getProperties(config); assertEquals("Wrong value", "42", props.getProperty("scalar")); } @Test public void testConfigurationToMap() { Configuration config = new BaseConfiguration(); config.addProperty("string", "teststring"); Map map = ConfigurationConverter.getMap(config); assertNotNull("null map", map); assertEquals("'string' property", "teststring", map.get("string")); } } ././@LongLink100644 0 0 154 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationFactory.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationFacto100644 41300 12232154104 33622 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.FileWriter; import java.net.URL; import java.util.Collection; import java.util.List; import org.junit.Before; import org.junit.Test; import org.xml.sax.SAXException; /** * Test the ConfigurationFactory. * * @version $Id: TestConfigurationFactory.java 1223011 2011-12-24 20:30:45Z oheger $ */ @SuppressWarnings("deprecation") public class TestConfigurationFactory { /** The Files that we test with */ private URL digesterRules = getClass().getResource("/digesterRules.xml"); private File testDigesterFile = ConfigurationAssert.getTestFile("testDigesterConfiguration.xml"); private File testDigesterFileReverseOrder = ConfigurationAssert.getTestFile("testDigesterConfigurationReverseOrder.xml"); private File testDigesterFileNamespaceAware = ConfigurationAssert.getTestFile("testDigesterConfigurationNamespaceAware.xml"); private File testDigesterFileBasePath = ConfigurationAssert.getTestFile("testDigesterConfigurationBasePath.xml"); private File testDigesterFileEnhanced = ConfigurationAssert.getTestFile("testDigesterConfiguration2.xml"); private File testDigesterFileComplete = ConfigurationAssert.getTestFile("testDigesterConfiguration3.xml"); private File testDigesterFileOptional = ConfigurationAssert.getTestFile("testDigesterOptionalConfiguration.xml"); private File testDigesterFileOptionalEx = ConfigurationAssert.getTestFile("testDigesterOptionalConfigurationEx.xml"); private File testDigesterFileSysProps = ConfigurationAssert.getTestFile("testDigesterConfigurationSysProps.xml"); private File testDigesterFileInitProps = ConfigurationAssert.getTestFile("testDigesterConfigurationWithProps.xml"); private File testDigesterBadXML = ConfigurationAssert.getTestFile("testDigesterBadXML.xml"); private String testBasePath = new File("conf").getAbsolutePath(); private File testProperties = ConfigurationAssert.getTestFile("test.properties"); private File testAbsConfig = ConfigurationAssert.getOutFile("testAbsConfig.xml"); private Configuration configuration; private CompositeConfiguration compositeConfiguration; private ConfigurationFactory factory; @Before public void setUp() throws Exception { System.setProperty("java.naming.factory.initial", "org.apache.commons.configuration.MockInitialContextFactory"); factory = new ConfigurationFactory(); } @Test public void testJNDI() throws Exception { JNDIConfiguration jndiConfiguration = new JNDIConfiguration(); Object o = jndiConfiguration.getProperty("test.boolean"); assertNotNull(o); assertEquals("true", o.toString()); } @Test public void testLoadingConfiguration() throws Exception { factory.setConfigurationFileName(testDigesterFile.toString()); compositeConfiguration = (CompositeConfiguration) factory.getConfiguration(); assertEquals("Number of configurations", 4, compositeConfiguration.getNumberOfConfigurations()); assertEquals(PropertiesConfiguration.class, compositeConfiguration.getConfiguration(0).getClass()); assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration.getConfiguration(1).getClass()); assertEquals(XMLConfiguration.class, compositeConfiguration.getConfiguration(2).getClass()); // check the first configuration PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration.getConfiguration(0); assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc.getFileName()); // check some properties assertTrue("Make sure we have loaded our key", compositeConfiguration.getBoolean("test.boolean")); assertEquals("I'm complex!", compositeConfiguration.getProperty("element2.subelement.subsubelement")); assertEquals("property in the XMLPropertiesConfiguration", "value1", compositeConfiguration.getProperty("key1")); } @Test public void testLoadingConfigurationWithRulesXML() throws Exception { factory.setConfigurationFileName(testDigesterFile.toString()); factory.setDigesterRules(digesterRules); compositeConfiguration = (CompositeConfiguration) factory.getConfiguration(); assertEquals("Number of configurations", 4, compositeConfiguration.getNumberOfConfigurations()); assertEquals(PropertiesConfiguration.class, compositeConfiguration.getConfiguration(0).getClass()); //assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration.getConfiguration(1).getClass()); // doesn't work assertEquals(XMLConfiguration.class, compositeConfiguration.getConfiguration(2).getClass()); // check the first configuration PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration.getConfiguration(0); assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc.getFileName()); // check some properties assertTrue("Make sure we have loaded our key", pc.getBoolean("test.boolean")); assertTrue("Make sure we have loaded our key", compositeConfiguration.getBoolean("test.boolean")); assertEquals("I'm complex!", compositeConfiguration.getProperty("element2.subelement.subsubelement")); } @Test public void testLoadingConfigurationReverseOrder() throws Exception { factory.setConfigurationFileName(testDigesterFileReverseOrder.toString()); configuration = factory.getConfiguration(); assertEquals("8", configuration.getProperty("test.short")); factory.setConfigurationFileName(testDigesterFile.toString()); configuration = factory.getConfiguration(); assertEquals("1", configuration.getProperty("test.short")); } @Test public void testLoadingConfigurationNamespaceAware() throws Exception { factory.setConfigurationFileName(testDigesterFileNamespaceAware.toString()); factory.setDigesterRuleNamespaceURI("namespace-one"); checkCompositeConfiguration(); } @Test public void testLoadingConfigurationBasePath() throws Exception { factory.setConfigurationFileName(testDigesterFileBasePath.toString()); factory.setBasePath(testBasePath); //factory.setDigesterRuleNamespaceURI("namespace-one"); checkCompositeConfiguration(); } @Test public void testLoadingAdditional() throws Exception { factory.setConfigurationFileName(testDigesterFileEnhanced.toString()); factory.setBasePath(null); checkUnionConfig(); } @Test public void testLoadingURL() throws Exception { factory.setConfigurationURL(testDigesterFileEnhanced.toURL()); checkUnionConfig(); } @Test(expected = ConfigurationException.class) public void testLoadingURLNonExisting() throws Exception { factory = new ConfigurationFactory(); File nonExistingFile = new File("conf/nonexisting.xml"); factory.setConfigurationURL(nonExistingFile.toURL()); factory.getConfiguration(); } @Test public void testThrowingConfigurationInitializationException() throws Exception { factory.setConfigurationFileName(testDigesterBadXML.toString()); try { factory.getConfiguration(); fail("Should have throw an Exception"); } catch (ConfigurationException cle) { assertTrue("Unexpected cause: " + cle.getCause(), cle.getCause() instanceof SAXException); } } // Tests if properties from all sources can be loaded @Test public void testAllConfiguration() throws Exception { factory.setConfigurationURL(testDigesterFileComplete.toURL()); Configuration config = factory.getConfiguration(); assertFalse(config.isEmpty()); assertTrue(config instanceof CompositeConfiguration); CompositeConfiguration cc = (CompositeConfiguration) config; assertTrue(cc.getNumberOfConfigurations() > 1); // Currently fails, should be 4? Only 2? //assertEquals(4, cc.getNumberOfConfigurations()); assertNotNull(config.getProperty("tables.table(0).fields.field(2).name")); assertNotNull(config.getProperty("element2.subelement.subsubelement")); assertEquals("value", config.getProperty("element3")); assertEquals("foo", config.getProperty("element3[@name]")); assertNotNull(config.getProperty("mail.account.user")); // test JNDIConfiguration assertNotNull(config.getProperty("test.onlyinjndi")); assertTrue(config.getBoolean("test.onlyinjndi")); Configuration subset = config.subset("test"); assertNotNull(subset.getProperty("onlyinjndi")); assertTrue(subset.getBoolean("onlyinjndi")); // test SystemConfiguration assertNotNull(config.getProperty("java.version")); assertEquals(System.getProperty("java.version"), config.getString("java.version")); } // Checks if optional configurations work @Test public void testOptionalConfigurations() throws Exception { factory.setConfigurationURL(testDigesterFileOptional.toURL()); Configuration config = factory.getConfiguration(); assertTrue(config.getBoolean("test.boolean")); assertEquals("value", config.getProperty("element")); factory.setConfigurationURL(testDigesterFileOptionalEx.toURL()); try { config = factory.getConfiguration(); fail("Unexisting properties loaded!"); } catch(ConfigurationException cex) { // fine } } // Checks if a file with an absolute path can be loaded @Test public void testLoadAbsolutePath() throws Exception { try { FileWriter out = null; try { out = new FileWriter(testAbsConfig); out.write(""); out.write(""); out.write(""); out.write(""); } finally { if (out != null) { out.close(); } } factory.setConfigurationFileName(testAbsConfig.toString()); Configuration config = factory.getConfiguration(); assertTrue(config.getBoolean("configuration.loaded")); } finally { if (testAbsConfig.exists()) { testAbsConfig.delete(); } } } @Test public void testBasePath() throws Exception { assertEquals(".", factory.getBasePath()); factory.setConfigurationFileName(testDigesterFile.getAbsolutePath()); // if no specific base path has been set, the base is determined // from the file name assertEquals(testDigesterFile.getParentFile().getAbsolutePath(), factory.getBasePath()); String homeDir = System.getProperty("user.home"); factory = new ConfigurationFactory(); factory.setBasePath(homeDir); factory.setConfigurationFileName(testDigesterFile.getAbsolutePath()); // if a base path was set, the file name does not play a role assertEquals(homeDir, factory.getBasePath()); factory = new ConfigurationFactory(testDigesterFile.getAbsolutePath()); assertEquals(testDigesterFile.getParentFile().getAbsolutePath(), factory.getBasePath()); factory.setBasePath(homeDir); assertEquals(homeDir, factory.getBasePath()); factory = new ConfigurationFactory(); factory.setConfigurationURL(testDigesterFile.toURL()); assertEquals(testDigesterFile.toURL().toString(), factory.getBasePath()); } // Tests if system properties can be resolved in the configuration // definition @Test public void testLoadingWithSystemProperties() throws ConfigurationException { System.setProperty("config.file", "test.properties"); factory.setConfigurationFileName(testDigesterFileSysProps .getAbsolutePath()); Configuration config = factory.getConfiguration(); assertTrue("Configuration not loaded", config .getBoolean("configuration.loaded")); } // Tests if the properties of a configuration object are correctly set // before it is loaded. @Test public void testLoadInitProperties() throws ConfigurationException { factory.setConfigurationFileName(testDigesterFileInitProps .getAbsolutePath()); Configuration config = factory.getConfiguration(); PropertiesConfiguration c = (PropertiesConfiguration) ((CompositeConfiguration) config) .getConfiguration(0); assertEquals("List delimiter was not set", ';', c.getListDelimiter()); List l = c.getList("test.mixed.array"); assertEquals("Wrong number of list elements", 2, l.size()); assertEquals("List delimiter was not applied", "b, c, d", l.get(1)); } private void checkUnionConfig() throws Exception { compositeConfiguration = (CompositeConfiguration) factory.getConfiguration(); assertEquals("Verify how many configs", 3, compositeConfiguration.getNumberOfConfigurations()); // Test if union was constructed correctly Object prop = compositeConfiguration.getProperty("tables.table.name"); assertTrue(prop instanceof Collection); assertEquals(3, ((Collection) prop).size()); assertEquals("users", compositeConfiguration.getProperty("tables.table(0).name")); assertEquals("documents", compositeConfiguration.getProperty("tables.table(1).name")); assertEquals("tasks", compositeConfiguration.getProperty("tables.table(2).name")); prop = compositeConfiguration.getProperty("tables.table.fields.field.name"); assertTrue(prop instanceof Collection); assertEquals(17, ((Collection) prop).size()); assertEquals("smtp.mydomain.org", compositeConfiguration.getString("mail.host.smtp")); assertEquals("pop3.mydomain.org", compositeConfiguration.getString("mail.host.pop")); // This was overriden assertEquals("masterOfPost", compositeConfiguration.getString("mail.account.user")); assertEquals("topsecret", compositeConfiguration.getString("mail.account.psswd")); // This was overriden, too, but not in additional section assertEquals("enhanced factory", compositeConfiguration.getString("test.configuration")); } private void checkCompositeConfiguration() throws Exception { compositeConfiguration = (CompositeConfiguration) factory.getConfiguration(); assertEquals("Verify how many configs", 2, compositeConfiguration.getNumberOfConfigurations()); assertEquals(PropertiesConfiguration.class, compositeConfiguration.getConfiguration(0).getClass()); PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration.getConfiguration(0); assertNotNull("Make sure we have a fileName:" + pc.getFileName(), pc.getFileName()); assertTrue("Make sure we have loaded our key", pc.getBoolean("test.boolean")); assertTrue("Make sure we have loaded our key", compositeConfiguration.getBoolean("test.boolean")); Object property = compositeConfiguration.getProperty("element2.subelement.subsubelement"); assertNull("Should have returned a null", property); } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationKey.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationKey.j100644 20572 12232154104 33556 0ustarhenningstaff 0 0 package org.apache.commons.configuration; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.NoSuchElementException; import org.junit.Test; /** * Test class for ConfigurationKey. * * @version $Id: TestConfigurationKey.java 1231749 2012-01-15 20:48:56Z oheger $ */ @SuppressWarnings("deprecation") public class TestConfigurationKey { private static final String TESTPROPS = "tables.table(0).fields.field(1)"; private static final String TESTATTR = "[@dataType]"; private static final String TESTKEY = TESTPROPS + TESTATTR; @Test public void testAppend() { ConfigurationKey key = new ConfigurationKey(); key.append("tables").append("table.").appendIndex(0); key.append("fields.").append("field").appendIndex(1); key.appendAttribute("dataType"); assertEquals(TESTKEY, key.toString()); } @Test public void testIterate() { ConfigurationKey key = new ConfigurationKey(TESTKEY); ConfigurationKey.KeyIterator it = key.iterator(); assertTrue(it.hasNext()); assertEquals("tables", it.nextKey()); assertEquals("table", it.nextKey()); assertTrue(it.hasIndex()); assertEquals(0, it.getIndex()); assertEquals("fields", it.nextKey()); assertFalse(it.hasIndex()); assertEquals("field", it.nextKey(true)); assertEquals(1, it.getIndex()); assertFalse(it.isAttribute()); assertEquals("field", it.currentKey(true)); assertEquals("dataType", it.nextKey()); assertEquals("[@dataType]", it.currentKey(true)); assertTrue(it.isAttribute()); assertFalse(it.hasNext()); try { it.next(); fail("Could iterate over the iteration's end!"); } catch(NoSuchElementException nex) { //ok } key = new ConfigurationKey(); assertFalse(key.iterator().hasNext()); key.append("simple"); it = key.iterator(); assertTrue(it.hasNext()); assertEquals("simple", it.next()); try { it.remove(); fail("Could remove key component!"); } catch(UnsupportedOperationException uex) { //ok } } @Test public void testAttribute() { assertTrue(ConfigurationKey.isAttributeKey(TESTATTR)); assertFalse(ConfigurationKey.isAttributeKey(TESTPROPS)); assertFalse(ConfigurationKey.isAttributeKey(TESTKEY)); ConfigurationKey key = new ConfigurationKey(TESTPROPS); key.append(TESTATTR); assertEquals(TESTKEY, key.toString()); } @Test public void testLength() { ConfigurationKey key = new ConfigurationKey(TESTPROPS); assertEquals(TESTPROPS.length(), key.length()); key.appendAttribute("dataType"); assertEquals(TESTKEY.length(), key.length()); key.setLength(TESTPROPS.length()); assertEquals(TESTPROPS.length(), key.length()); assertEquals(TESTPROPS, key.toString()); } @Test public void testConstructAttributeKey() { assertEquals("[@attribute]", ConfigurationKey.constructAttributeKey("attribute")); assertEquals("attribute", ConfigurationKey.attributeName("[@attribute]")); assertEquals("attribute", ConfigurationKey.attributeName("attribute")); } @Test public void testEquals() { ConfigurationKey k1 = new ConfigurationKey(TESTKEY); ConfigurationKey k2 = new ConfigurationKey(TESTKEY); assertTrue(k1.equals(k2)); assertTrue(k2.equals(k1)); assertEquals(k1.hashCode(), k2.hashCode()); k2.append("anotherPart"); assertFalse(k1.equals(k2)); assertFalse(k2.equals(k1)); assertFalse(k1.equals(null)); assertTrue(k1.equals(TESTKEY)); } @Test public void testCommonKey() { ConfigurationKey k1 = new ConfigurationKey(TESTKEY); ConfigurationKey k2 = new ConfigurationKey("tables.table(0).name"); ConfigurationKey kc = k1.commonKey(k2); assertEquals(new ConfigurationKey("tables.table(0)"), kc); assertEquals(kc, k2.commonKey(k1)); k2 = new ConfigurationKey("tables.table(1).fields.field(1)"); kc = k1.commonKey(k2); assertEquals(new ConfigurationKey("tables"), kc); k2 = new ConfigurationKey("completely.different.key"); kc = k1.commonKey(k2); assertEquals(0, kc.length()); k2 = new ConfigurationKey(); kc = k1.commonKey(k2); assertEquals(0, kc.length()); kc = k1.commonKey(k1); assertEquals(kc, k1); try { kc.commonKey(null); fail("Could construct common key with null key!"); } catch(IllegalArgumentException iex) { //ok } } @Test public void testDifferenceKey() { ConfigurationKey k1 = new ConfigurationKey(TESTKEY); ConfigurationKey kd = k1.differenceKey(k1); assertEquals(0, kd.length()); ConfigurationKey k2 = new ConfigurationKey("tables.table(0).name"); kd = k1.differenceKey(k2); assertEquals("name", kd.toString()); k2 = new ConfigurationKey("tables.table(1).fields.field(1)"); kd = k1.differenceKey(k2); assertEquals("table(1).fields.field(1)", kd.toString()); k2 = new ConfigurationKey("completely.different.key"); kd = k1.differenceKey(k2); assertEquals(k2, kd); } @Test public void testEscapedDelimiters() { ConfigurationKey k = new ConfigurationKey(); k.append("my..elem"); k.append("trailing..dot.."); k.append("strange"); assertEquals("my..elem.trailing..dot...strange", k.toString()); ConfigurationKey.KeyIterator kit = k.iterator(); assertEquals("my.elem", kit.nextKey()); assertEquals("trailing.dot.", kit.nextKey()); assertEquals("strange", kit.nextKey()); assertFalse(kit.hasNext()); } /** * Tests some funny keys. */ @Test public void testIterateStrangeKeys() { ConfigurationKey k = new ConfigurationKey("key."); ConfigurationKey.KeyIterator it = k.iterator(); assertTrue(it.hasNext()); assertEquals("key", it.next()); assertFalse(it.hasNext()); k = new ConfigurationKey("."); it = k.iterator(); assertFalse(it.hasNext()); k = new ConfigurationKey("key().index()undefined(0).test"); it = k.iterator(); assertEquals("key()", it.next()); assertFalse(it.hasIndex()); assertEquals("index()undefined", it.nextKey(false)); assertTrue(it.hasIndex()); assertEquals(0, it.getIndex()); } /** * Tests iterating over an attribute key that has an index. */ @Test public void testAttributeKeyWithIndex() { ConfigurationKey k = new ConfigurationKey(TESTATTR); k.appendIndex(0); assertEquals("Wrong attribute key with index", TESTATTR + "(0)", k.toString()); ConfigurationKey.KeyIterator it = k.iterator(); assertTrue("No first element", it.hasNext()); it.next(); assertTrue("Index not found", it.hasIndex()); assertEquals("Incorrect index", 0, it.getIndex()); assertTrue("Attribute not found", it.isAttribute()); assertEquals("Wrong plain key", "dataType", it.currentKey(false)); assertEquals("Wrong decorated key", TESTATTR, it.currentKey(true)); } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationMap.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationMap.j100644 5332 12232154104 33520 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * @author Ricardo Gladwell */ public class TestConfigurationMap { ConfigurationMap map; String[] properties = { "booleanProperty", "doubleProperty", "floatProperty", "intProperty", "longProperty", "shortProperty", "stringProperty" }; Object[] values = { Boolean.TRUE, new Double(Double.MAX_VALUE), new Float(Float.MAX_VALUE), new Integer(Integer.MAX_VALUE), new Long(Long.MAX_VALUE), new Short(Short.MAX_VALUE), "This is a string" }; /** * Set up instance variables required by this test case. */ @Before public void setUp() throws Exception { BaseConfiguration configuration = new BaseConfiguration(); for(int i = 0; i < properties.length ; i++) configuration.setProperty(properties[i], values[i]); map = new ConfigurationMap(configuration); } /** * Tear down instance variables required by this test case. */ @After public void tearDown() { map = null; } /** * Class under test for Object put(Object, Object) */ @Test public void testPut() { for(int i = 0; i < properties.length; i++) { Object object = map.put(properties[i], values[i]); assertNotNull("Returned null from put.",object); assertEquals("Returned wrong result.",values[i],object); object = map.get(properties[i]); assertNotNull("Returned null from get.",object); assertEquals("Returned wrong result.",values[i],object); } } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationSet.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationSet.j100644 6230 12232154104 33534 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.Map; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * @author rgladwel */ public class TestConfigurationSet { ConfigurationMap.ConfigurationSet set; String[] properties = { "booleanProperty", "doubleProperty", "floatProperty", "intProperty", "longProperty", "shortProperty", "stringProperty" }; Object[] values = { Boolean.TRUE, new Double(Double.MAX_VALUE), new Float(Float.MAX_VALUE), new Integer(Integer.MAX_VALUE), new Long(Long.MAX_VALUE), new Short(Short.MAX_VALUE), "This is a string" }; /** * Set up instance variables required by this test case. */ @Before public void setUp() throws Exception { BaseConfiguration configuration = new BaseConfiguration(); for(int i = 0; i < properties.length ; i++) configuration.setProperty(properties[i], values[i]); set = new ConfigurationMap.ConfigurationSet(configuration); } /** * Tear down instance variables required by this test case. */ @After public void tearDown() { set = null; } @Test public void testSize() { assertEquals("Entry set does not match properties size.", properties.length, set.size()); } /** * Class under test for Iterator iterator() */ @Test public void testIterator() { Iterator> iterator = set.iterator(); while(iterator.hasNext()) { Map.Entry entry = iterator.next(); boolean found = false; for(int i = 0; i < properties.length; i++) { if(entry.getKey().equals(properties[i])) { assertEquals("Incorrect value for property " + properties[i],values[i],entry.getValue()); found = true; } } assertTrue("Could not find property " + entry.getKey(),found); iterator.remove(); } assertTrue("Iterator failed to remove all properties.",set.isEmpty()); } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationUtils.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestConfigurationUtils100644 41265 12232154104 33700 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import junitx.framework.ListAssert; import org.apache.commons.configuration.tree.DefaultExpressionEngine; import org.apache.commons.configuration.tree.ExpressionEngine; import org.junit.Test; import com.mockobjects.dynamic.Mock; /** * Tests the ConfigurationUtils class * * @version $Id: TestConfigurationUtils.java 1301996 2012-03-17 20:30:39Z sebb $ */ public class TestConfigurationUtils { protected Configuration config = new BaseConfiguration(); @Test public void testToString() { String lineSeparator = System.getProperty("line.separator"); assertEquals("String representation of an empty configuration", "", ConfigurationUtils.toString(config)); config.setProperty("one", "1"); assertEquals("String representation of a configuration", "one=1", ConfigurationUtils.toString(config)); config.setProperty("two", "2"); assertEquals("String representation of a configuration", "one=1" + lineSeparator + "two=2" , ConfigurationUtils.toString(config)); config.clearProperty("one"); assertEquals("String representation of a configuration", "two=2" , ConfigurationUtils.toString(config)); config.setProperty("one","1"); assertEquals("String representation of a configuration", "two=2" + lineSeparator + "one=1" , ConfigurationUtils.toString(config)); } @Test public void testGetURL() throws Exception { assertEquals( "http://localhost:8080/webapp/config/config.xml", ConfigurationUtils .getURL( "http://localhost:8080/webapp/config/baseConfig.xml", "config.xml") .toString()); assertEquals( "http://localhost:8080/webapp/config/config.xml", ConfigurationUtils .getURL( "http://localhost:8080/webapp/baseConfig.xml", "config/config.xml") .toString()); URL url = ConfigurationUtils.getURL(null, "config.xml"); assertEquals("file", url.getProtocol()); assertEquals("", url.getHost()); assertEquals( "http://localhost:8080/webapp/config/config.xml", ConfigurationUtils .getURL( "ftp://ftp.server.com/downloads/baseConfig.xml", "http://localhost:8080/webapp/config/config.xml") .toString()); assertEquals( "http://localhost:8080/webapp/config/config.xml", ConfigurationUtils .getURL(null, "http://localhost:8080/webapp/config/config.xml") .toString()); File absFile = new File("config.xml").getAbsoluteFile(); assertEquals( absFile.toURI().toURL(), ConfigurationUtils.getURL( "http://localhost:8080/webapp/config/baseConfig.xml", absFile.getAbsolutePath())); assertEquals( absFile.toURI().toURL(), ConfigurationUtils.getURL(null, absFile.getAbsolutePath())); assertEquals(absFile.toURI().toURL(), ConfigurationUtils.getURL(absFile.getParent(), "config.xml")); } @Test public void testGetBasePath() throws Exception { URL url = new URL("http://xyz.net/foo/bar.xml"); assertEquals("base path of " + url, "http://xyz.net/foo/", ConfigurationUtils.getBasePath(url)); url = new URL("http://xyz.net/foo/"); assertEquals("base path of " + url, "http://xyz.net/foo/", ConfigurationUtils.getBasePath(url)); url = new URL("http://xyz.net/foo"); assertEquals("base path of " + url, "http://xyz.net/", ConfigurationUtils.getBasePath(url)); url = new URL("http://xyz.net/"); assertEquals("base path of " + url, "http://xyz.net/", ConfigurationUtils.getBasePath(url)); url = new URL("http://xyz.net"); assertEquals("base path of " + url, "http://xyz.net", ConfigurationUtils.getBasePath(url)); } @Test public void testGetFileName() throws Exception { assertEquals("file name for a null URL", null, ConfigurationUtils.getFileName(null)); URL url = new URL("http://xyz.net/foo/"); assertEquals("file for a directory URL " + url, null, ConfigurationUtils.getFileName(url)); url = new URL("http://xyz.net/foo/bar.xml"); assertEquals("file name for a valid URL " + url, "bar.xml", ConfigurationUtils.getFileName(url)); } @Test public void testCopy() { // create the source configuration Configuration conf1 = new BaseConfiguration(); conf1.addProperty("key1", "value1"); conf1.addProperty("key2", "value2"); // create the target configuration Configuration conf2 = new BaseConfiguration(); conf2.addProperty("key1", "value3"); conf2.addProperty("key2", "value4"); // copy the source configuration into the target configuration ConfigurationUtils.copy(conf1, conf2); assertEquals("'key1' property", "value1", conf2.getProperty("key1")); assertEquals("'key2' property", "value2", conf2.getProperty("key2")); } @Test public void testAppend() { // create the source configuration Configuration conf1 = new BaseConfiguration(); conf1.addProperty("key1", "value1"); conf1.addProperty("key2", "value2"); // create the target configuration Configuration conf2 = new BaseConfiguration(); conf2.addProperty("key1", "value3"); conf2.addProperty("key2", "value4"); // append the source configuration to the target configuration ConfigurationUtils.append(conf1, conf2); List expected = new ArrayList(); expected.add("value3"); expected.add("value1"); ListAssert.assertEquals("'key1' property", expected, conf2.getList("key1")); expected = new ArrayList(); expected.add("value4"); expected.add("value2"); ListAssert.assertEquals("'key2' property", expected, conf2.getList("key2")); } @Test public void testGetFile() throws Exception { File directory = new File("target"); File reference = new File(directory, "test.txt").getAbsoluteFile(); assertEquals(reference, ConfigurationUtils.getFile(null, reference.getAbsolutePath())); assertEquals(reference, ConfigurationUtils.getFile(directory.getAbsolutePath(), reference.getAbsolutePath())); assertEquals(reference, ConfigurationUtils.getFile(directory.getAbsolutePath(), reference.getName())); assertEquals(reference, ConfigurationUtils.getFile(directory.toURI().toURL().toString(), reference.getName())); assertEquals(reference, ConfigurationUtils.getFile("invalid", reference.toURI().toURL().toString())); assertEquals(reference, ConfigurationUtils.getFile( "jar:file:/C:/myjar.jar!/my-config.xml/someprops.properties", reference.getAbsolutePath())); } /** * Tests whether a "+" character in the file name is handled correctly by * fileFromURL(). This test is related to CONFIGURATION-415. */ @Test public void testFileFromURLWithPlus() throws MalformedURLException { File file = new File(new File("target"), "foo+bar.txt") .getAbsoluteFile(); URL fileURL = file.toURI().toURL(); File file2 = ConfigurationUtils.fileFromURL(fileURL); assertEquals("Wrong file", file, file2); } /** * Tests whether fileFromURL() handles null URLs correctly. */ @Test public void testFileFromURLNull() throws Exception { assertNull("Wrong file for null URL", ConfigurationUtils .fileFromURL(null)); } @Test public void testLocateWithNullTCCL() throws Exception { ClassLoader cl = Thread.currentThread().getContextClassLoader(); try { Thread.currentThread().setContextClassLoader(null); assertNull(ConfigurationUtils.locate("abase", "aname")); // This assert fails when maven 2 is used, so commented out //assertNotNull(ConfigurationUtils.locate("test.xml")); } finally { Thread.currentThread().setContextClassLoader(cl); } } /** * Tests converting a configuration into a hierarchical one. */ @Test public void testConvertToHierarchical() { Configuration conf = new BaseConfiguration(); for (int i = 0; i < 10; i++) { conf.addProperty("test" + i, "value" + i); conf.addProperty("test.list", "item" + i); } HierarchicalConfiguration hc = ConfigurationUtils .convertToHierarchical(conf); for (Iterator it = conf.getKeys(); it.hasNext();) { String key = it.next(); assertEquals("Wrong value for key " + key, conf.getProperty(key), hc.getProperty(key)); } } /** * Tests converting a configuration into a hierarchical one that is already * hierarchical. */ @Test public void testConvertHierarchicalToHierarchical() { Configuration conf = new HierarchicalConfiguration(); conf.addProperty("test", "yes"); assertSame("Wrong configuration returned", conf, ConfigurationUtils .convertToHierarchical(conf)); } /** * Tests converting a null configuration to a hierarchical one. The result * should be null, too. */ @Test public void testConvertNullToHierarchical() { assertNull("Wrong conversion result for null config", ConfigurationUtils.convertToHierarchical(null)); } /** * Tests converting a configuration into a hierarchical one if some of its * properties contain escaped list delimiter characters. */ @Test public void testConvertToHierarchicalDelimiters() { Configuration conf = new BaseConfiguration(); conf.addProperty("test.key", "1\\,2\\,3"); assertEquals("Wrong property value", "1,2,3", conf .getString("test.key")); HierarchicalConfiguration hc = ConfigurationUtils .convertToHierarchical(conf); assertEquals("Escaped list delimiters not correctly handled", "1,2,3", hc.getString("test.key")); } /** * Tests converting a configuration to a hierarchical one using a specific * expression engine. */ @Test public void testConvertToHierarchicalEngine() { Configuration conf = new BaseConfiguration(); conf.addProperty("test(a)", Boolean.TRUE); conf.addProperty("test(b)", Boolean.FALSE); DefaultExpressionEngine engine = new DefaultExpressionEngine(); engine.setIndexStart("["); engine.setIndexEnd("]"); HierarchicalConfiguration hc = ConfigurationUtils .convertToHierarchical(conf, engine); assertTrue("Wrong value for test(a)", hc.getBoolean("test(a)")); assertFalse("Wrong value for test(b)", hc.getBoolean("test(b)")); } /** * Tests converting an already hierarchical configuration using an * expression engine. The new engine should be set. */ @Test public void testConvertHierarchicalToHierarchicalEngine() { HierarchicalConfiguration hc = new HierarchicalConfiguration(); ExpressionEngine engine = new DefaultExpressionEngine(); assertSame("Created new configuration", hc, ConfigurationUtils .convertToHierarchical(hc, engine)); assertSame("Engine was not set", engine, hc.getExpressionEngine()); } /** * Tests converting an already hierarchical configuration using a null * expression engine. In this case the expression engine of the * configuration should not be touched. */ @Test public void testConvertHierarchicalToHierarchicalNullEngine() { HierarchicalConfiguration hc = new HierarchicalConfiguration(); ExpressionEngine engine = new DefaultExpressionEngine(); hc.setExpressionEngine(engine); assertSame("Created new configuration", hc, ConfigurationUtils .convertToHierarchical(hc, null)); assertSame("Expression engine was changed", engine, hc .getExpressionEngine()); } /** * Tests converting a configuration to a hierarchical one that contains a * property with multiple values. This test is related to CONFIGURATION-346. */ @Test public void testConvertToHierarchicalMultiValues() { BaseConfiguration config = new BaseConfiguration(); config.addProperty("test", "1,2,3"); HierarchicalConfiguration hc = ConfigurationUtils .convertToHierarchical(config); assertEquals("Wrong value 1", 1, hc.getInt("test(0)")); assertEquals("Wrong value 2", 2, hc.getInt("test(1)")); assertEquals("Wrong value 3", 3, hc.getInt("test(2)")); } /** * Tests cloning a configuration that supports this operation. */ @Test public void testCloneConfiguration() { HierarchicalConfiguration conf = new HierarchicalConfiguration(); conf.addProperty("test", "yes"); HierarchicalConfiguration copy = (HierarchicalConfiguration) ConfigurationUtils .cloneConfiguration(conf); assertNotSame("Same object was returned", conf, copy); assertEquals("Property was not cloned", "yes", copy.getString("test")); } /** * Tests cloning a configuration that does not support this operation. This * should cause an exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testCloneConfigurationNotSupported() { Configuration myNonCloneableConfig = new NonCloneableConfiguration(); ConfigurationUtils.cloneConfiguration(myNonCloneableConfig); } /** * Tests cloning a null configuration. */ @Test public void testCloneConfigurationNull() { assertNull("Wrong return value", ConfigurationUtils .cloneConfiguration(null)); } /** * Tests whether runtime exceptions can be enabled. */ @Test(expected = ConfigurationRuntimeException.class) public void testEnableRuntimeExceptions() { PropertiesConfiguration config = new PropertiesConfiguration() { @Override protected void addPropertyDirect(String key, Object value) { // always simulate an exception fireError(EVENT_ADD_PROPERTY, key, value, new RuntimeException( "A faked exception!")); } }; config.clearErrorListeners(); ConfigurationUtils.enableRuntimeExceptions(config); config.addProperty("test", "testValue"); } /** * Tries to enable runtime exceptions for a configuration that does not * inherit from EventSource. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testEnableRuntimeExceptionsInvalid() { ConfigurationUtils.enableRuntimeExceptions((Configuration) new Mock( Configuration.class).proxy()); } /** * Tries to enable runtime exceptions for a null configuration. This should * cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testEnableRuntimeExceptionsNull() { ConfigurationUtils.enableRuntimeExceptions(null); } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestDatabaseConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestDatabaseConfigurat100644 42777 12232154104 33607 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.sql.Connection; import java.sql.SQLException; import java.util.Iterator; import java.util.List; import javax.sql.DataSource; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test for database stored configurations. Note, when running this Unit * Test in Eclipse it sometimes takes a couple tries. Otherwise you may get * database is already in use by another process errors. * * @version $Id: TestDatabaseConfiguration.java 1223016 2011-12-24 20:56:52Z oheger $ */ public class TestDatabaseConfiguration { /** Constant for another configuration name. */ private static final String CONFIG_NAME2 = "anotherTestConfig"; /** An error listener for testing whether internal errors occurred.*/ private ConfigurationErrorListenerImpl listener; /** The test helper. */ private DatabaseConfigurationTestHelper helper; @Before public void setUp() throws Exception { /* * Thread.sleep may or may not help with the database is already in * use exception. */ //Thread.sleep(1000); // set up the datasource helper = new DatabaseConfigurationTestHelper(); helper.setUp(); } @After public void tearDown() throws Exception { // if an error listener is defined, we check whether an error occurred if(listener != null) { assertEquals("An internal error occurred", 0, listener.getErrorCount()); } helper.tearDown(); } /** * Creates a database configuration with default values. * * @return the configuration */ private PotentialErrorDatabaseConfiguration setUpConfig() { return new PotentialErrorDatabaseConfiguration(helper.getDatasource(), DatabaseConfigurationTestHelper.TABLE, DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE); } /** * Creates an error listener and adds it to the specified configuration. * * @param config the configuration */ private void setUpErrorListener(PotentialErrorDatabaseConfiguration config) { // remove log listener to avoid exception longs config.removeErrorListener(config.getErrorListeners().iterator().next()); listener = new ConfigurationErrorListenerImpl(); config.addErrorListener(listener); config.failOnConnect = true; } /** * Prepares a test for a database error. Sets up a config and registers an * error listener. * * @return the initialized configuration */ private PotentialErrorDatabaseConfiguration setUpErrorConfig() { PotentialErrorDatabaseConfiguration config = setUpConfig(); setUpErrorListener(config); return config; } /** * Checks the error listener for an expected error. The properties of the * error event will be compared with the expected values. * * @param type the expected type of the error event * @param key the expected property key * @param value the expected property value */ private void checkErrorListener(int type, String key, Object value) { listener.verify(type, key, value); assertTrue( "Wrong event source", listener.getLastEvent().getSource() instanceof DatabaseConfiguration); assertTrue("Wrong exception", listener.getLastEvent().getCause() instanceof SQLException); listener = null; // mark as checked } /** * Tests the default value of the doCommits property. */ @Test public void testDoCommitsDefault() { DatabaseConfiguration config = new DatabaseConfiguration(helper .getDatasource(), DatabaseConfigurationTestHelper.TABLE, DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE); assertFalse("Wrong commits flag", config.isDoCommits()); } /** * Tests the default value of the doCommits property for multiple * configurations in a table. */ @Test public void testDoCommitsDefaultMulti() { DatabaseConfiguration config = new DatabaseConfiguration(helper .getDatasource(), DatabaseConfigurationTestHelper.TABLE, DatabaseConfigurationTestHelper.COL_NAME, DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE, DatabaseConfigurationTestHelper.CONFIG_NAME); assertFalse("Wrong commits flag", config.isDoCommits()); } @Test public void testAddPropertyDirectSingle() { DatabaseConfiguration config = helper.setUpConfig(); config.addPropertyDirect("key", "value"); assertTrue("missing property", config.containsKey("key")); } /** * Tests whether a commit is performed after a property was added. */ @Test public void testAddPropertyDirectCommit() { helper.setAutoCommit(false); DatabaseConfiguration config = helper.setUpConfig(); config.addPropertyDirect("key", "value"); assertTrue("missing property", config.containsKey("key")); } @Test public void testAddPropertyDirectMultiple() { DatabaseConfiguration config = helper.setUpMultiConfig(); config.addPropertyDirect("key", "value"); assertTrue("missing property", config.containsKey("key")); } @Test public void testAddNonStringProperty() { DatabaseConfiguration config = helper.setUpConfig(); config.addPropertyDirect("boolean", Boolean.TRUE); assertTrue("missing property", config.containsKey("boolean")); } @Test public void testGetPropertyDirectSingle() { Configuration config = setUpConfig(); assertEquals("property1", "value1", config.getProperty("key1")); assertEquals("property2", "value2", config.getProperty("key2")); assertEquals("unknown property", null, config.getProperty("key3")); } @Test public void testGetPropertyDirectMultiple() { Configuration config = helper.setUpMultiConfig(); assertEquals("property1", "value1", config.getProperty("key1")); assertEquals("property2", "value2", config.getProperty("key2")); assertEquals("unknown property", null, config.getProperty("key3")); } @Test public void testClearPropertySingle() { Configuration config = helper.setUpConfig(); config.clearProperty("key1"); assertFalse("property not cleared", config.containsKey("key1")); } @Test public void testClearPropertyMultiple() { Configuration config = helper.setUpMultiConfig(); config.clearProperty("key1"); assertFalse("property not cleared", config.containsKey("key1")); } /** * Tests that another configuration is not affected when clearing * properties. */ @Test public void testClearPropertyMultipleOtherConfig() { DatabaseConfiguration config = helper.setUpMultiConfig(); DatabaseConfiguration config2 = helper.setUpMultiConfig(CONFIG_NAME2); config2.addProperty("key1", "some test"); config.clearProperty("key1"); assertFalse("property not cleared", config.containsKey("key1")); assertTrue("Property cleared in other config", config2 .containsKey("key1")); } /** * Tests whether a commit is performed after a property was cleared. */ @Test public void testClearPropertyCommit() { helper.setAutoCommit(false); Configuration config = helper.setUpConfig(); config.clearProperty("key1"); assertFalse("property not cleared", config.containsKey("key1")); } @Test public void testClearSingle() { Configuration config = helper.setUpConfig(); config.clear(); assertTrue("configuration is not cleared", config.isEmpty()); } @Test public void testClearMultiple() { Configuration config = helper.setUpMultiConfig(); config.clear(); assertTrue("configuration is not cleared", config.isEmpty()); } /** * Tests whether a commit is performed after a clear operation. */ @Test public void testClearCommit() { helper.setAutoCommit(false); Configuration config = helper.setUpConfig(); config.clear(); assertTrue("configuration is not cleared", config.isEmpty()); } @Test public void testGetKeysSingle() { Configuration config = setUpConfig(); Iterator it = config.getKeys(); assertEquals("1st key", "key1", it.next()); assertEquals("2nd key", "key2", it.next()); } @Test public void testGetKeysMultiple() { Configuration config = helper.setUpMultiConfig(); Iterator it = config.getKeys(); assertEquals("1st key", "key1", it.next()); assertEquals("2nd key", "key2", it.next()); } @Test public void testContainsKeySingle() { Configuration config = setUpConfig(); assertTrue("missing key1", config.containsKey("key1")); assertTrue("missing key2", config.containsKey("key2")); } @Test public void testContainsKeyMultiple() { Configuration config = helper.setUpMultiConfig(); assertTrue("missing key1", config.containsKey("key1")); assertTrue("missing key2", config.containsKey("key2")); } @Test public void testIsEmptySingle() { Configuration config1 = setUpConfig(); assertFalse("The configuration is empty", config1.isEmpty()); } @Test public void testIsEmptyMultiple() { Configuration config1 = helper.setUpMultiConfig(); assertFalse("The configuration named 'test' is empty", config1.isEmpty()); Configuration config2 = new DatabaseConfiguration(helper.getDatasource(), DatabaseConfigurationTestHelper.TABLE_MULTI, DatabaseConfigurationTestHelper.COL_NAME, DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE, "testIsEmpty"); assertTrue("The configuration named 'testIsEmpty' is not empty", config2.isEmpty()); } @Test public void testGetList() { Configuration config1 = new DatabaseConfiguration(helper.getDatasource(), "configurationList", DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE); List list = config1.getList("key3"); assertEquals(3,list.size()); } @Test public void testGetKeys() { Configuration config1 = new DatabaseConfiguration(helper.getDatasource(), "configurationList", DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE); Iterator i = config1.getKeys(); assertTrue(i.hasNext()); Object key = i.next(); assertEquals("key3",key.toString()); assertFalse(i.hasNext()); } @Test public void testClearSubset() { Configuration config = setUpConfig(); Configuration subset = config.subset("key1"); subset.clear(); assertTrue("the subset is not empty", subset.isEmpty()); assertFalse("the parent configuration is empty", config.isEmpty()); } /** * Tests whether the configuration has already an error listener registered * that is used for logging. */ @Test public void testLogErrorListener() { DatabaseConfiguration config = new DatabaseConfiguration(helper.getDatasource(), DatabaseConfigurationTestHelper.TABLE, DatabaseConfigurationTestHelper.COL_KEY, DatabaseConfigurationTestHelper.COL_VALUE); assertEquals("No error listener registered", 1, config.getErrorListeners().size()); } /** * Tests handling of errors in getProperty(). */ @Test public void testGetPropertyError() { setUpErrorConfig().getProperty("key1"); checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, "key1", null); } /** * Tests handling of errors in addPropertyDirect(). */ @Test public void testAddPropertyError() { setUpErrorConfig().addProperty("key1", "value"); checkErrorListener(AbstractConfiguration.EVENT_ADD_PROPERTY, "key1", "value"); } /** * Tests handling of errors in isEmpty(). */ @Test public void testIsEmptyError() { assertTrue("Wrong return value for failure", setUpErrorConfig().isEmpty()); checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, null, null); } /** * Tests handling of errors in containsKey(). */ @Test public void testContainsKeyError() { assertFalse("Wrong return value for failure", setUpErrorConfig().containsKey("key1")); checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, "key1", null); } /** * Tests handling of errors in clearProperty(). */ @Test public void testClearPropertyError() { setUpErrorConfig().clearProperty("key1"); checkErrorListener(AbstractConfiguration.EVENT_CLEAR_PROPERTY, "key1", null); } /** * Tests handling of errors in clear(). */ @Test public void testClearError() { setUpErrorConfig().clear(); checkErrorListener(AbstractConfiguration.EVENT_CLEAR, null, null); } /** * Tests handling of errors in getKeys(). */ @Test public void testGetKeysError() { Iterator it = setUpErrorConfig().getKeys(); checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, null, null); assertFalse("Iteration is not empty", it.hasNext()); } /** * Tests obtaining a property as list whose value contains the list * delimiter. Multiple values should be returned. */ @Test public void testGetListWithDelimiter() { DatabaseConfiguration config = setUpConfig(); config.setListDelimiter(';'); List values = config.getList("keyMulti"); assertEquals("Wrong number of list elements", 3, values.size()); assertEquals("Wrong list element 0", "a", values.get(0)); assertEquals("Wrong list element 2", "c", values.get(2)); } /** * Tests obtaining a property whose value contains the list delimiter when * delimiter parsing is disabled. */ @Test public void testGetListWithDelimiterParsingDisabled() { DatabaseConfiguration config = setUpConfig(); config.setListDelimiter(';'); config.setDelimiterParsingDisabled(true); assertEquals("Wrong value of property", "a;b;c", config.getString("keyMulti")); } /** * Tests adding a property containing the list delimiter. When this property * is queried multiple values should be returned. */ @Test public void testAddWithDelimiter() { DatabaseConfiguration config = setUpConfig(); config.setListDelimiter(';'); config.addProperty("keyList", "1;2;3"); String[] values = config.getStringArray("keyList"); assertEquals("Wrong number of property values", 3, values.length); assertEquals("Wrong value at index 1", "2", values[1]); } /** * Tests setProperty() if the property value contains the list delimiter. */ @Test public void testSetPropertyWithDelimiter() { DatabaseConfiguration config = helper.setUpMultiConfig(); config.setListDelimiter(';'); config.setProperty("keyList", "1;2;3"); String[] values = config.getStringArray("keyList"); assertEquals("Wrong number of property values", 3, values.length); assertEquals("Wrong value at index 1", "2", values[1]); } /** * A specialized database configuration implementation that can be * configured to throw an exception when obtaining a connection. This way * database exceptions can be simulated. */ static class PotentialErrorDatabaseConfiguration extends DatabaseConfiguration { /** A flag whether a getConnection() call should fail. */ boolean failOnConnect; public PotentialErrorDatabaseConfiguration(DataSource datasource, String table, String keyColumn, String valueColumn) { super(datasource, table, keyColumn, valueColumn); } @Override protected Connection getConnection() throws SQLException { if (failOnConnect) { throw new SQLException("Simulated DB error"); } return super.getConnection(); } } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestDataConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestDataConfiguration.100644 242241 12232154104 33544 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.awt.Color; import java.math.BigDecimal; import java.math.BigInteger; import java.net.InetAddress; import java.net.URL; import java.text.DateFormat; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.NoSuchElementException; import junitx.framework.ArrayAssert; import junitx.framework.ListAssert; import org.junit.Before; import org.junit.Test; /** * @author Emmanuel Bourg * @version $Id: TestDataConfiguration.java 1535297 2013-10-24 07:53:37Z henning $ */ public class TestDataConfiguration { private DataConfiguration conf; @Before public void setUp() throws Exception { conf = new DataConfiguration(new BaseConfiguration()); // empty value conf.addProperty("empty", ""); // lists of boolean conf.addProperty("boolean.list1", "true"); conf.addProperty("boolean.list1", "false"); conf.addProperty("boolean.list2", "true, false"); conf.addProperty("boolean.list3", Boolean.TRUE); conf.addProperty("boolean.list3", Boolean.FALSE); conf.addPropertyDirect("boolean.list4", new Boolean[] { Boolean.TRUE, Boolean.FALSE }); conf.addPropertyDirect("boolean.list5", new boolean[] { true, false }); List booleans = new ArrayList(); booleans.add(Boolean.TRUE); booleans.add(Boolean.FALSE); conf.addProperty("boolean.list6", booleans); conf.addProperty("boolean.string", "true"); conf.addProperty("boolean.object", Boolean.TRUE); conf.addProperty("boolean.list.interpolated", "${boolean.string},false"); // lists of bytes conf.addProperty("byte.list1", "1"); conf.addProperty("byte.list1", "2"); conf.addProperty("byte.list2", "1, 2"); conf.addProperty("byte.list3", new Byte("1")); conf.addProperty("byte.list3", new Byte("2")); conf.addPropertyDirect("byte.list4", new Byte[] { new Byte("1"), new Byte("2") }); conf.addPropertyDirect("byte.list5", new byte[] { 1, 2 }); List bytes = new ArrayList(); bytes.add(new Byte("1")); bytes.add(new Byte("2")); conf.addProperty("byte.list6", bytes); conf.addProperty("byte.string", "1"); conf.addProperty("byte.object", new Byte("1")); conf.addProperty("byte.list.interpolated", "${byte.string},2"); // lists of shorts conf.addProperty("short.list1", "1"); conf.addProperty("short.list1", "2"); conf.addProperty("short.list2", "1, 2"); conf.addProperty("short.list3", new Short("1")); conf.addProperty("short.list3", new Short("2")); conf.addPropertyDirect("short.list4", new Short[] { new Short("1"), new Short("2") }); conf.addPropertyDirect("short.list5", new short[] { 1, 2 }); List shorts = new ArrayList(); shorts.add(new Short("1")); shorts.add(new Short("2")); conf.addProperty("short.list6", shorts); conf.addProperty("short.string", "1"); conf.addProperty("short.object", new Short("1")); conf.addProperty("short.list.interpolated", "${short.string},2"); // lists of integers conf.addProperty("integer.list1", "1"); conf.addProperty("integer.list1", "2"); conf.addProperty("integer.list2", "1, 2"); conf.addProperty("integer.list3", new Integer("1")); conf.addProperty("integer.list3", new Integer("2")); conf.addPropertyDirect("integer.list4", new Integer[] { new Integer("1"), new Integer("2") }); conf.addPropertyDirect("integer.list5", new int[] { 1, 2 }); List integers = new ArrayList(); integers.add(new Integer("1")); integers.add(new Integer("2")); conf.addProperty("integer.list6", integers); conf.addProperty("integer.string", "1"); conf.addProperty("integer.object", new Integer("1")); conf.addProperty("integer.list.interpolated", "${integer.string},2"); // lists of longs conf.addProperty("long.list1", "1"); conf.addProperty("long.list1", "2"); conf.addProperty("long.list2", "1, 2"); conf.addProperty("long.list3", new Long("1")); conf.addProperty("long.list3", new Long("2")); conf.addPropertyDirect("long.list4", new Long[] { new Long("1"), new Long("2") }); conf.addPropertyDirect("long.list5", new long[] { 1, 2 }); List longs = new ArrayList(); longs.add(new Long("1")); longs.add(new Long("2")); conf.addProperty("long.list6", longs); conf.addProperty("long.string", "1"); conf.addProperty("long.object", new Long("1")); conf.addProperty("long.list.interpolated", "${long.string},2"); // lists of floats conf.addProperty("float.list1", "1"); conf.addProperty("float.list1", "2"); conf.addProperty("float.list2", "1, 2"); conf.addProperty("float.list3", new Float("1")); conf.addProperty("float.list3", new Float("2")); conf.addPropertyDirect("float.list4", new Float[] { new Float("1"), new Float("2") }); conf.addPropertyDirect("float.list5", new float[] { 1, 2 }); List floats = new ArrayList(); floats.add(new Float("1")); floats.add(new Float("2")); conf.addProperty("float.list6", floats); conf.addProperty("float.string", "1"); conf.addProperty("float.object", new Float("1")); conf.addProperty("float.list.interpolated", "${float.string},2"); // lists of doubles conf.addProperty("double.list1", "1"); conf.addProperty("double.list1", "2"); conf.addProperty("double.list2", "1, 2"); conf.addProperty("double.list3", new Double("1")); conf.addProperty("double.list3", new Double("2")); conf.addPropertyDirect("double.list4", new Double[] { new Double("1"), new Double("2") }); conf.addPropertyDirect("double.list5", new double[] { 1, 2 }); List doubles = new ArrayList(); doubles.add(new Double("1")); doubles.add(new Double("2")); conf.addProperty("double.list6", doubles); conf.addProperty("double.string", "1"); conf.addProperty("double.object", new Double("1")); conf.addProperty("double.list.interpolated", "${double.string},2"); // lists of big integers conf.addProperty("biginteger.list1", "1"); conf.addProperty("biginteger.list1", "2"); conf.addProperty("biginteger.list2", "1, 2"); conf.addProperty("biginteger.list3", new BigInteger("1")); conf.addProperty("biginteger.list3", new BigInteger("2")); conf.addPropertyDirect("biginteger.list4", new BigInteger[] { new BigInteger("1"), new BigInteger("2") }); List bigintegers = new ArrayList(); bigintegers.add(new BigInteger("1")); bigintegers.add(new BigInteger("2")); conf.addProperty("biginteger.list6", bigintegers); conf.addProperty("biginteger.string", "1"); conf.addProperty("biginteger.object", new BigInteger("1")); conf.addProperty("biginteger.list.interpolated", "${biginteger.string},2"); // lists of big decimals conf.addProperty("bigdecimal.list1", "1"); conf.addProperty("bigdecimal.list1", "2"); conf.addProperty("bigdecimal.list2", "1, 2"); conf.addProperty("bigdecimal.list3", new BigDecimal("1")); conf.addProperty("bigdecimal.list3", new BigDecimal("2")); conf.addPropertyDirect("bigdecimal.list4", new BigDecimal[] { new BigDecimal("1"), new BigDecimal("2") }); List bigdecimals = new ArrayList(); bigdecimals.add(new BigDecimal("1")); bigdecimals.add(new BigDecimal("2")); conf.addProperty("bigdecimal.list6", bigdecimals); conf.addProperty("bigdecimal.string", "1"); conf.addProperty("bigdecimal.object", new BigDecimal("1")); conf.addProperty("bigdecimal.list.interpolated", "${bigdecimal.string},2"); // URLs String url1 = "http://jakarta.apache.org"; String url2 = "http://www.apache.org"; conf.addProperty("url.string", url1); conf.addProperty("url.string.interpolated", "${url.string}"); conf.addProperty("url.object", new URL(url1)); conf.addProperty("url.list1", url1); conf.addProperty("url.list1", url2); conf.addProperty("url.list2", url1 + ", " + url2); conf.addProperty("url.list3", new URL(url1)); conf.addProperty("url.list3", new URL(url2)); conf.addPropertyDirect("url.list4", new URL[] { new URL(url1), new URL(url2) }); List urls = new ArrayList(); urls.add(new URL(url1)); urls.add(new URL(url2)); conf.addProperty("url.list6", urls); conf.addProperty("url.list.interpolated", "${url.string}," + url2); // Locales conf.addProperty("locale.string", "fr"); conf.addProperty("locale.string.interpolated", "${locale.string}"); conf.addProperty("locale.object", Locale.FRENCH); conf.addProperty("locale.list1", "fr"); conf.addProperty("locale.list1", "de"); conf.addProperty("locale.list2", "fr, de"); conf.addProperty("locale.list3", Locale.FRENCH); conf.addProperty("locale.list3", Locale.GERMAN); conf.addPropertyDirect("locale.list4", new Locale[] { Locale.FRENCH, Locale.GERMAN }); List locales = new ArrayList(); locales.add(Locale.FRENCH); locales.add(Locale.GERMAN); conf.addProperty("locale.list6", locales); conf.addProperty("locale.list.interpolated", "${locale.string},de"); // Colors String color1 = "FF0000"; String color2 = "0000FF"; conf.addProperty("color.string", color1); conf.addProperty("color.string.interpolated", "${color.string}"); conf.addProperty("color.object", Color.red); conf.addProperty("color.list1", color1); conf.addProperty("color.list1", color2); conf.addProperty("color.list2", color1 + ", " + color2); conf.addProperty("color.list3", Color.red); conf.addProperty("color.list3", Color.blue); conf.addPropertyDirect("color.list4", new Color[] { Color.red, Color.blue }); List colors = new ArrayList(); colors.add(Color.red); colors.add(Color.blue); conf.addProperty("color.list6", colors); conf.addProperty("color.list.interpolated", "${color.string}," + color2); // Dates & Calendars String pattern = "yyyy-MM-dd"; DateFormat format = new SimpleDateFormat(pattern); conf.setProperty(DataConfiguration.DATE_FORMAT_KEY, pattern); Date date1 = format.parse("2004-01-01"); Date date2 = format.parse("2004-12-31"); Calendar calendar1 = Calendar.getInstance(); calendar1.setTime(date1); Calendar calendar2 = Calendar.getInstance(); calendar2.setTime(date2); conf.addProperty("date.string", "2004-01-01"); conf.addProperty("date.string.interpolated", "${date.string}"); conf.addProperty("date.object", date1); conf.addProperty("date.list1", "2004-01-01"); conf.addProperty("date.list1", "2004-12-31"); conf.addProperty("date.list2", "2004-01-01, 2004-12-31"); conf.addProperty("date.list3", date1); conf.addProperty("date.list3", date2); conf.addPropertyDirect("date.list4", new Date[] { date1, date2 }); conf.addPropertyDirect("date.list5", new Calendar[] { calendar1, calendar2 }); List dates = new ArrayList(); dates.add(date1); dates.add(date2); conf.addProperty("date.list6", dates); conf.addProperty("date.list.interpolated", "${date.string},2004-12-31"); conf.addPropertyDirect("date.list7", new String[] { "2004-01-01", "2004-12-31" }); conf.addProperty("calendar.string", "2004-01-01"); conf.addProperty("calendar.string.interpolated", "${calendar.string}"); conf.addProperty("calendar.object", calendar1); conf.addProperty("calendar.list1", "2004-01-01"); conf.addProperty("calendar.list1", "2004-12-31"); conf.addProperty("calendar.list2", "2004-01-01, 2004-12-31"); conf.addProperty("calendar.list3", calendar1); conf.addProperty("calendar.list3", calendar2); conf.addPropertyDirect("calendar.list4", new Calendar[] { calendar1, calendar2 }); conf.addPropertyDirect("calendar.list5", new Date[] { date1, date2 }); List calendars = new ArrayList(); calendars.add(date1); calendars.add(date2); conf.addProperty("calendar.list6", calendars); conf.addProperty("calendar.list.interpolated", "${calendar.string},2004-12-31"); conf.addPropertyDirect("calendar.list7", new String[] { "2004-01-01", "2004-12-31" }); // host address conf.addProperty("ip.string", "127.0.0.1"); conf.addProperty("ip.string.interpolated", "${ip.string}"); conf.addProperty("ip.object", InetAddress.getByName("127.0.0.1")); // email address conf.addProperty("email.string", "ebourg@apache.org"); conf.addProperty("email.string.interpolated", "${email.string}"); conf.addProperty("email.object", createInternetAddress("ebourg@apache.org")); } @Test public void testGetConfiguration() { Configuration baseconf = new BaseConfiguration(); DataConfiguration conf = new DataConfiguration(baseconf); assertEquals("base configuration", baseconf, conf.getConfiguration()); } @Test public void testIsEmpty() { Configuration baseconf = new BaseConfiguration(); DataConfiguration conf = new DataConfiguration(baseconf); assertTrue("not empty", conf.isEmpty()); baseconf.setProperty("foo", "bar"); assertFalse("empty", conf.isEmpty()); } @Test public void testContainsKey() { Configuration baseconf = new BaseConfiguration(); DataConfiguration conf = new DataConfiguration(baseconf); assertFalse(conf.containsKey("foo")); baseconf.setProperty("foo", "bar"); assertTrue(conf.containsKey("foo")); } @Test public void testGetKeys() { Configuration baseconf = new BaseConfiguration(); DataConfiguration conf = new DataConfiguration(baseconf); baseconf.setProperty("foo", "bar"); Iterator it = conf.getKeys(); assertTrue("the iterator is empty", it.hasNext()); assertEquals("unique key", "foo", it.next()); assertFalse("the iterator is not exhausted", it.hasNext()); } @Test(expected = ConversionException.class) public void testGetInvalidType() { conf.get(Boolean.class, "url.object", null); } @Test public void testGetUnknown() { assertNull("non null object for a missing key", conf.get(Object.class, "unknownkey")); } @Test(expected = NoSuchElementException.class) public void testGetUnknownException() { conf.setThrowExceptionOnMissing(true); conf.get(Object.class, "unknownkey"); } @Test(expected = IllegalArgumentException.class) public void testGetArrayInvalidDefaultType() { conf.getArray(Boolean.class, "unknownkey", new URL[] {}); } @Test(expected = ConversionException.class) public void testGetPrimitiveArrayInvalidType() { conf.getArray(Boolean.TYPE, "calendar.list4"); } @Test public void testGetBooleanArray() { // missing list boolean[] defaultValue = new boolean[] { false, true }; ArrayAssert.assertEquals(defaultValue, conf.getBooleanArray("boolean.list", defaultValue)); boolean[] expected = new boolean[] { true, false }; // list of strings ArrayAssert.assertEquals(expected, conf.getBooleanArray("boolean.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getBooleanArray("boolean.list2")); // list of Boolean objects ArrayAssert.assertEquals(expected, conf.getBooleanArray("boolean.list3")); // array of Boolean objects ArrayAssert.assertEquals(expected, conf.getBooleanArray("boolean.list4")); // array of boolean primitives ArrayAssert.assertEquals(expected, conf.getBooleanArray("boolean.list5")); // list of Boolean objects ArrayAssert.assertEquals(expected, conf.getBooleanArray("boolean.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getBooleanArray("boolean.list.interpolated")); // single boolean values ArrayAssert.assertEquals(new boolean[] { true }, conf.getBooleanArray("boolean.string")); ArrayAssert.assertEquals(new boolean[] { true }, conf.getBooleanArray("boolean.object")); // empty array ArrayAssert.assertEquals(new boolean[] { }, conf.getBooleanArray("empty")); } @Test public void testGetBooleanList() { // missing list ListAssert.assertEquals(null, conf.getBooleanList("boolean.list", null)); List expected = new ArrayList(); expected.add(Boolean.TRUE); expected.add(Boolean.FALSE); // list of strings ListAssert.assertEquals(expected, conf.getBooleanList("boolean.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getBooleanList("boolean.list2")); // list of Boolean objects ListAssert.assertEquals(expected, conf.getBooleanList("boolean.list3")); // array of Boolean objects ListAssert.assertEquals(expected, conf.getBooleanList("boolean.list4")); // array of boolean primitives ListAssert.assertEquals(expected, conf.getBooleanList("boolean.list5")); // list of Boolean objects ListAssert.assertEquals(expected, conf.getBooleanList("boolean.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getBooleanList("boolean.list.interpolated")); // single boolean values expected = new ArrayList(); expected.add(Boolean.TRUE); ListAssert.assertEquals(expected, conf.getBooleanList("boolean.string")); ListAssert.assertEquals(expected, conf.getBooleanList("boolean.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getBooleanList("empty")); } @Test public void testGetByteArray() { // missing list byte[] defaultValue = new byte[] { 1, 2}; ArrayAssert.assertEquals(defaultValue, conf.getByteArray("byte.list", defaultValue)); byte[] expected = new byte[] { 1, 2 }; // list of strings ArrayAssert.assertEquals(expected, conf.getByteArray("byte.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getByteArray("byte.list2")); // list of Byte objects ArrayAssert.assertEquals(expected, conf.getByteArray("byte.list3")); // array of Byte objects ArrayAssert.assertEquals(expected, conf.getByteArray("byte.list4")); // array of byte primitives ArrayAssert.assertEquals(expected, conf.getByteArray("byte.list5")); // list of Byte objects ArrayAssert.assertEquals(expected, conf.getByteArray("byte.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getByteArray("byte.list.interpolated")); // single byte values ArrayAssert.assertEquals(new byte[] { 1 }, conf.getByteArray("byte.string")); ArrayAssert.assertEquals(new byte[] { 1 }, conf.getByteArray("byte.object")); // empty array ArrayAssert.assertEquals(new byte[] { }, conf.getByteArray("empty")); } @Test public void testGetByteList() { // missing list ListAssert.assertEquals(null, conf.getByteList("byte.list", null)); List expected = new ArrayList(); expected.add(new Byte("1")); expected.add(new Byte("2")); // list of strings ListAssert.assertEquals(expected, conf.getByteList("byte.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getByteList("byte.list2")); // list of Byte objects ListAssert.assertEquals(expected, conf.getByteList("byte.list3")); // array of Byte objects ListAssert.assertEquals(expected, conf.getByteList("byte.list4")); // array of byte primitives ListAssert.assertEquals(expected, conf.getByteList("byte.list5")); // list of Byte objects ListAssert.assertEquals(expected, conf.getByteList("byte.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getByteList("byte.list.interpolated")); // single byte values expected = new ArrayList(); expected.add(new Byte("1")); ListAssert.assertEquals(expected, conf.getByteList("byte.string")); ListAssert.assertEquals(expected, conf.getByteList("byte.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getByteList("empty")); } @Test public void testGetShortArray() { // missing list short[] defaultValue = new short[] { 2, 1}; ArrayAssert.assertEquals(defaultValue, conf.getShortArray("short.list", defaultValue)); short[] expected = new short[] { 1, 2 }; // list of strings ArrayAssert.assertEquals(expected, conf.getShortArray("short.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getShortArray("short.list2")); // list of Byte objects ArrayAssert.assertEquals(expected, conf.getShortArray("short.list3")); // array of Byte objects ArrayAssert.assertEquals(expected, conf.getShortArray("short.list4")); // array of byte primitives ArrayAssert.assertEquals(expected, conf.getShortArray("short.list5")); // list of Byte objects ArrayAssert.assertEquals(expected, conf.getShortArray("short.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getShortArray("short.list.interpolated")); // single byte values ArrayAssert.assertEquals(new short[] { 1 }, conf.getShortArray("short.string")); ArrayAssert.assertEquals(new short[] { 1 }, conf.getShortArray("short.object")); // empty array ArrayAssert.assertEquals(new short[] { }, conf.getShortArray("empty")); } @Test public void testGetShortList() { // missing list ListAssert.assertEquals(null, conf.getShortList("short.list", null)); List expected = new ArrayList(); expected.add(new Short("1")); expected.add(new Short("2")); // list of strings ListAssert.assertEquals(expected, conf.getShortList("short.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getShortList("short.list2")); // list of Short objects ListAssert.assertEquals(expected, conf.getShortList("short.list3")); // array of Short objects ListAssert.assertEquals(expected, conf.getShortList("short.list4")); // array of short primitives ListAssert.assertEquals(expected, conf.getShortList("short.list5")); // list of Short objects ListAssert.assertEquals(expected, conf.getShortList("short.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getShortList("short.list.interpolated")); // single short values expected = new ArrayList(); expected.add(new Short("1")); ListAssert.assertEquals(expected, conf.getShortList("short.string")); ListAssert.assertEquals(expected, conf.getShortList("short.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getShortList("empty")); } @Test public void testGetIntegerArray() { // missing list int[] defaultValue = new int[] { 2, 1}; ArrayAssert.assertEquals(defaultValue, conf.getIntArray("integer.list", defaultValue)); int[] expected = new int[] { 1, 2 }; // list of strings ArrayAssert.assertEquals(expected, conf.getIntArray("integer.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getIntArray("integer.list2")); // list of Integer objects ArrayAssert.assertEquals(expected, conf.getIntArray("integer.list3")); // array of Integer objects ArrayAssert.assertEquals(expected, conf.getIntArray("integer.list4")); // array of int primitives ArrayAssert.assertEquals(expected, conf.getIntArray("integer.list5")); // list of Integer objects ArrayAssert.assertEquals(expected, conf.getIntArray("integer.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getIntArray("integer.list.interpolated")); // single int values ArrayAssert.assertEquals(new int[] { 1 }, conf.getIntArray("integer.string")); ArrayAssert.assertEquals(new int[] { 1 }, conf.getIntArray("integer.object")); // empty array ArrayAssert.assertEquals(new int[] { }, conf.getIntArray("empty")); } @Test public void testGetIntegerList() { // missing list ListAssert.assertEquals(null, conf.getIntegerList("integer.list", null)); List expected = new ArrayList(); expected.add(new Integer("1")); expected.add(new Integer("2")); // list of strings ListAssert.assertEquals(expected, conf.getIntegerList("integer.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getIntegerList("integer.list2")); // list of Integer objects ListAssert.assertEquals(expected, conf.getIntegerList("integer.list3")); // array of Integer objects ListAssert.assertEquals(expected, conf.getIntegerList("integer.list4")); // array of int primitives ListAssert.assertEquals(expected, conf.getIntegerList("integer.list5")); // list of Integer objects ListAssert.assertEquals(expected, conf.getIntegerList("integer.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getIntegerList("integer.list.interpolated")); // single int values expected = new ArrayList(); expected.add(new Integer("1")); ListAssert.assertEquals(expected, conf.getIntegerList("integer.string")); ListAssert.assertEquals(expected, conf.getIntegerList("integer.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getIntegerList("empty")); } @Test public void testGetLongArray() { // missing list long[] defaultValue = new long[] { 2, 1}; ArrayAssert.assertEquals(defaultValue, conf.getLongArray("long.list", defaultValue)); long[] expected = new long[] { 1, 2 }; // list of strings ArrayAssert.assertEquals(expected, conf.getLongArray("long.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getLongArray("long.list2")); // list of Long objects ArrayAssert.assertEquals(expected, conf.getLongArray("long.list3")); // array of Long objects ArrayAssert.assertEquals(expected, conf.getLongArray("long.list4")); // array of long primitives ArrayAssert.assertEquals(expected, conf.getLongArray("long.list5")); // list of Long objects ArrayAssert.assertEquals(expected, conf.getLongArray("long.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getLongArray("long.list.interpolated")); // single long values ArrayAssert.assertEquals(new long[] { 1 }, conf.getLongArray("long.string")); ArrayAssert.assertEquals(new long[] { 1 }, conf.getLongArray("long.object")); // empty array ArrayAssert.assertEquals(new long[] { }, conf.getLongArray("empty")); } @Test public void testGetLongList() { // missing list ListAssert.assertEquals(null, conf.getLongList("long.list", null)); List expected = new ArrayList(); expected.add(new Long("1")); expected.add(new Long("2")); // list of strings ListAssert.assertEquals(expected, conf.getLongList("long.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getLongList("long.list2")); // list of Long objects ListAssert.assertEquals(expected, conf.getLongList("long.list3")); // array of Long objects ListAssert.assertEquals(expected, conf.getLongList("long.list4")); // array of long primitives ListAssert.assertEquals(expected, conf.getLongList("long.list5")); // list of Long objects ListAssert.assertEquals(expected, conf.getLongList("long.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getLongList("long.list.interpolated")); // single long values expected = new ArrayList(); expected.add(new Long("1")); ListAssert.assertEquals(expected, conf.getLongList("long.string")); ListAssert.assertEquals(expected, conf.getLongList("long.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getLongList("empty")); } @Test public void testGetFloatArray() { // missing list float[] defaultValue = new float[] { 2, 1}; ArrayAssert.assertEquals(defaultValue, conf.getFloatArray("float.list", defaultValue), 0); float[] expected = new float[] { 1, 2 }; // list of strings ArrayAssert.assertEquals(expected, conf.getFloatArray("float.list1"), 0); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getFloatArray("float.list2"), 0); // list of Float objects ArrayAssert.assertEquals(expected, conf.getFloatArray("float.list3"), 0); // array of Float objects ArrayAssert.assertEquals(expected, conf.getFloatArray("float.list4"), 0); // array of float primitives ArrayAssert.assertEquals(expected, conf.getFloatArray("float.list5"), 0); // list of Float objects ArrayAssert.assertEquals(expected, conf.getFloatArray("float.list6"), 0); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getFloatArray("float.list.interpolated"), 0); // single float values ArrayAssert.assertEquals(new float[] { 1 }, conf.getFloatArray("float.string"), 0); ArrayAssert.assertEquals(new float[] { 1 }, conf.getFloatArray("float.object"), 0); // empty array ArrayAssert.assertEquals(new float[] { }, conf.getFloatArray("empty"), 0); } @Test public void testGetFloatList() { // missing list ListAssert.assertEquals(null, conf.getFloatList("float.list", null)); List expected = new ArrayList(); expected.add(new Float("1")); expected.add(new Float("2")); // list of strings ListAssert.assertEquals(expected, conf.getFloatList("float.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getFloatList("float.list2")); // list of Float objects ListAssert.assertEquals(expected, conf.getFloatList("float.list3")); // array of Float objects ListAssert.assertEquals(expected, conf.getFloatList("float.list4")); // array of float primitives ListAssert.assertEquals(expected, conf.getFloatList("float.list5")); // list of Float objects ListAssert.assertEquals(expected, conf.getFloatList("float.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getFloatList("float.list.interpolated")); // single float values expected = new ArrayList(); expected.add(new Float("1")); ListAssert.assertEquals(expected, conf.getFloatList("float.string")); ListAssert.assertEquals(expected, conf.getFloatList("float.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getFloatList("empty")); } @Test public void testGetDoubleArray() { // missing list double[] defaultValue = new double[] { 2, 1 }; ArrayAssert.assertEquals(defaultValue, conf.getDoubleArray("double.list", defaultValue), 0); double[] expected = new double[] { 1, 2 }; // list of strings ArrayAssert.assertEquals(expected, conf.getDoubleArray("double.list1"), 0); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getDoubleArray("double.list2"), 0); // list of Double objects ArrayAssert.assertEquals(expected, conf.getDoubleArray("double.list3"), 0); // array of Double objects ArrayAssert.assertEquals(expected, conf.getDoubleArray("double.list4"), 0); // array of double primitives ArrayAssert.assertEquals(expected, conf.getDoubleArray("double.list5"), 0); // list of Double objects ArrayAssert.assertEquals(expected, conf.getDoubleArray("double.list6"), 0); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getDoubleArray("double.list.interpolated"), 0); // single double values ArrayAssert.assertEquals(new double[] { 1 }, conf.getDoubleArray("double.string"), 0); ArrayAssert.assertEquals(new double[] { 1 }, conf.getDoubleArray("double.object"), 0); // empty array ArrayAssert.assertEquals(new double[] { }, conf.getDoubleArray("empty"), 0); } @Test public void testGetDoubleList() { // missing list ListAssert.assertEquals(null, conf.getDoubleList("double.list", null)); List expected = new ArrayList(); expected.add(new Double("1")); expected.add(new Double("2")); // list of strings ListAssert.assertEquals(expected, conf.getDoubleList("double.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getDoubleList("double.list2")); // list of Double objects ListAssert.assertEquals(expected, conf.getDoubleList("double.list3")); // array of Double objects ListAssert.assertEquals(expected, conf.getDoubleList("double.list4")); // array of double primitives ListAssert.assertEquals(expected, conf.getDoubleList("double.list5")); // list of Double objects ListAssert.assertEquals(expected, conf.getDoubleList("double.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getDoubleList("double.list.interpolated")); // single double values expected = new ArrayList(); expected.add(new Double("1")); ListAssert.assertEquals(expected, conf.getDoubleList("double.string")); ListAssert.assertEquals(expected, conf.getDoubleList("double.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getDoubleList("empty")); } @Test public void testGetBigIntegerArray() { // missing list BigInteger[] defaultValue = new BigInteger[] { new BigInteger("2"), new BigInteger("1") }; ArrayAssert.assertEquals(defaultValue, conf.getBigIntegerArray("biginteger.list", defaultValue)); BigInteger[] expected = new BigInteger[] { new BigInteger("1"), new BigInteger("2") }; // list of strings ArrayAssert.assertEquals(expected, conf.getBigIntegerArray("biginteger.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getBigIntegerArray("biginteger.list2")); // list of BigInteger objects ArrayAssert.assertEquals(expected, conf.getBigIntegerArray("biginteger.list3")); // array of BigInteger objects ArrayAssert.assertEquals(expected, conf.getBigIntegerArray("biginteger.list4")); // list of BigInteger objects ArrayAssert.assertEquals(expected, conf.getBigIntegerArray("biginteger.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getBigIntegerArray("biginteger.list.interpolated")); // single BigInteger values ArrayAssert.assertEquals(new BigInteger[] { new BigInteger("1") }, conf.getBigIntegerArray("biginteger.string")); ArrayAssert.assertEquals(new BigInteger[] { new BigInteger("1") }, conf.getBigIntegerArray("biginteger.object")); // empty array ArrayAssert.assertEquals(new BigInteger[] { }, conf.getBigIntegerArray("empty")); } @Test public void testGetBigIntegerList() { // missing list ListAssert.assertEquals(null, conf.getBigIntegerList("biginteger.list", null)); List expected = new ArrayList(); expected.add(new BigInteger("1")); expected.add(new BigInteger("2")); // list of strings ListAssert.assertEquals(expected, conf.getBigIntegerList("biginteger.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getBigIntegerList("biginteger.list2")); // list of BigInteger objects ListAssert.assertEquals(expected, conf.getBigIntegerList("biginteger.list3")); // array of BigInteger objects ListAssert.assertEquals(expected, conf.getBigIntegerList("biginteger.list4")); // list of BigInteger objects ListAssert.assertEquals(expected, conf.getBigIntegerList("biginteger.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getBigIntegerList("biginteger.list.interpolated")); // single BigInteger values expected = new ArrayList(); expected.add(new BigInteger("1")); ListAssert.assertEquals(expected, conf.getBigIntegerList("biginteger.string")); ListAssert.assertEquals(expected, conf.getBigIntegerList("biginteger.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getBigIntegerList("empty")); } @Test public void testGetBigDecimalArray() { // missing list BigDecimal[] defaultValue = new BigDecimal[] { new BigDecimal("2"), new BigDecimal("1") }; ArrayAssert.assertEquals(defaultValue, conf.getBigDecimalArray("bigdecimal.list", defaultValue)); BigDecimal[] expected = new BigDecimal[] { new BigDecimal("1"), new BigDecimal("2") }; // list of strings ArrayAssert.assertEquals(expected, conf.getBigDecimalArray("bigdecimal.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getBigDecimalArray("bigdecimal.list2")); // list of BigDecimal objects ArrayAssert.assertEquals(expected, conf.getBigDecimalArray("bigdecimal.list3")); // array of BigDecimal objects ArrayAssert.assertEquals(expected, conf.getBigDecimalArray("bigdecimal.list4")); // list of BigDecimal objects ArrayAssert.assertEquals(expected, conf.getBigDecimalArray("bigdecimal.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getBigDecimalArray("bigdecimal.list.interpolated")); // single BigDecimal values ArrayAssert.assertEquals(new BigDecimal[] { new BigDecimal("1") }, conf.getBigDecimalArray("bigdecimal.string")); ArrayAssert.assertEquals(new BigDecimal[] { new BigDecimal("1") }, conf.getBigDecimalArray("bigdecimal.object")); // empty array ArrayAssert.assertEquals(new BigDecimal[] { }, conf.getBigDecimalArray("empty")); } @Test public void testGetBigDecimalList() { // missing list ListAssert.assertEquals(null, conf.getBigDecimalList("bigdecimal.list", null)); List expected = new ArrayList(); expected.add(new BigDecimal("1")); expected.add(new BigDecimal("2")); // list of strings ListAssert.assertEquals(expected, conf.getBigDecimalList("bigdecimal.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getBigDecimalList("bigdecimal.list2")); // list of BigDecimal objects ListAssert.assertEquals(expected, conf.getBigDecimalList("bigdecimal.list3")); // array of BigDecimal objects ListAssert.assertEquals(expected, conf.getBigDecimalList("bigdecimal.list4")); // list of BigDecimal objects ListAssert.assertEquals(expected, conf.getBigDecimalList("bigdecimal.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getBigDecimalList("bigdecimal.list.interpolated")); // single BigDecimal values expected = new ArrayList(); expected.add(new BigDecimal("1")); ListAssert.assertEquals(expected, conf.getBigDecimalList("bigdecimal.string")); ListAssert.assertEquals(expected, conf.getBigDecimalList("bigdecimal.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getBigDecimalList("empty")); } @Test public void testGetURL() throws Exception { // missing URL URL defaultValue = new URL("http://www.google.com"); assertEquals(defaultValue, conf.getURL("url", defaultValue)); URL expected = new URL("http://jakarta.apache.org"); // URL string assertEquals(expected, conf.getURL("url.string")); // URL object assertEquals(expected, conf.getURL("url.object")); // interpolated value assertEquals(expected, conf.getURL("url.string.interpolated")); } @Test public void testGetURLArray() throws Exception { // missing list URL[] defaultValue = new URL[] { new URL("http://www.apache.org"), new URL("http://jakarta.apache.org") }; ArrayAssert.assertEquals(defaultValue, conf.getURLArray("url.list", defaultValue)); URL[] expected = new URL[] { new URL("http://jakarta.apache.org"), new URL("http://www.apache.org") }; // list of strings ArrayAssert.assertEquals(expected, conf.getURLArray("url.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getURLArray("url.list2")); // list of URL objects ArrayAssert.assertEquals(expected, conf.getURLArray("url.list3")); // array of URL objects ArrayAssert.assertEquals(expected, conf.getURLArray("url.list4")); // list of URL objects ArrayAssert.assertEquals(expected, conf.getURLArray("url.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getURLArray("url.list.interpolated")); // single URL values ArrayAssert.assertEquals(new URL[] { new URL("http://jakarta.apache.org") }, conf.getURLArray("url.string")); ArrayAssert.assertEquals(new URL[] { new URL("http://jakarta.apache.org") }, conf.getURLArray("url.object")); // empty array ArrayAssert.assertEquals(new URL[] { }, conf.getURLArray("empty")); } @Test public void testGetURLList() throws Exception { // missing list ListAssert.assertEquals(null, conf.getURLList("url.list", null)); List expected = new ArrayList(); expected.add(new URL("http://jakarta.apache.org")); expected.add(new URL("http://www.apache.org")); // list of strings ListAssert.assertEquals(expected, conf.getURLList("url.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getURLList("url.list2")); // list of URL objects ListAssert.assertEquals(expected, conf.getURLList("url.list3")); // array of URL objects ListAssert.assertEquals(expected, conf.getURLList("url.list4")); // list of URL objects ListAssert.assertEquals(expected, conf.getURLList("url.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getURLList("url.list.interpolated")); // single URL values expected = new ArrayList(); expected.add(new URL("http://jakarta.apache.org")); ListAssert.assertEquals(expected, conf.getURLList("url.string")); ListAssert.assertEquals(expected, conf.getURLList("url.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getURLList("empty")); } @Test public void testGetLocale() { // language conf.setProperty("locale", "fr"); assertEquals("language", new Locale("fr", ""), conf.getLocale("locale")); // language + variant conf.setProperty("locale", "fr__POSIX"); assertEquals("language + variant", new Locale("fr", "", "POSIX"), conf.getLocale("locale")); // country conf.setProperty("locale", "_FR"); assertEquals("country", new Locale("", "FR"), conf.getLocale("locale")); // country + variant conf.setProperty("locale", "_FR_WIN"); assertEquals("country + variant", new Locale("", "FR", "WIN"), conf.getLocale("locale")); // language + country conf.setProperty("locale", "fr_FR"); assertEquals("language + country", new Locale("fr", "FR"), conf.getLocale("locale")); // language + country + variant conf.setProperty("locale", "fr_FR_MAC"); assertEquals("language + country + variant", new Locale("fr", "FR", "MAC"), conf.getLocale("locale")); // default value conf.setProperty("locale", "fr"); assertEquals("Existing key with default value", Locale.FRENCH, conf.getLocale("locale", Locale.GERMAN)); assertEquals("Missing key with default value", Locale.GERMAN, conf.getLocale("localeNotInConfig", Locale.GERMAN)); // interpolated value assertEquals(Locale.FRENCH, conf.getLocale("locale.string.interpolated")); } @Test public void testGetLocaleArray() throws Exception { // missing list Locale[] defaultValue = new Locale[] { Locale.GERMAN, Locale.FRENCH }; ArrayAssert.assertEquals(defaultValue, conf.getLocaleArray("locale.list", defaultValue)); Locale[] expected = new Locale[] { Locale.FRENCH, Locale.GERMAN }; // list of strings ArrayAssert.assertEquals(expected, conf.getLocaleArray("locale.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getLocaleArray("locale.list2")); // list of Locale objects ArrayAssert.assertEquals(expected, conf.getLocaleArray("locale.list3")); // array of Locale objects ArrayAssert.assertEquals(expected, conf.getLocaleArray("locale.list4")); // list of Locale objects ArrayAssert.assertEquals(expected, conf.getLocaleArray("locale.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getLocaleArray("locale.list.interpolated")); // single Locale values ArrayAssert.assertEquals(new Locale[] { Locale.FRENCH }, conf.getLocaleArray("locale.string")); ArrayAssert.assertEquals(new Locale[] { Locale.FRENCH }, conf.getLocaleArray("locale.object")); // empty array ArrayAssert.assertEquals(new Locale[] { }, conf.getLocaleArray("empty")); } @Test public void testGetLocaleList() throws Exception { // missing list ListAssert.assertEquals(null, conf.getLocaleList("locale.list", null)); List expected = new ArrayList(); expected.add(Locale.FRENCH); expected.add(Locale.GERMAN); // list of strings ListAssert.assertEquals(expected, conf.getLocaleList("locale.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getLocaleList("locale.list2")); // list of Locale objects ListAssert.assertEquals(expected, conf.getLocaleList("locale.list3")); // array of Locale objects ListAssert.assertEquals(expected, conf.getLocaleList("locale.list4")); // list of Locale objects ListAssert.assertEquals(expected, conf.getLocaleList("locale.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getLocaleList("locale.list.interpolated")); // single Locale values expected = new ArrayList(); expected.add(Locale.FRENCH); ListAssert.assertEquals(expected, conf.getLocaleList("locale.string")); ListAssert.assertEquals(expected, conf.getLocaleList("locale.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getLocaleList("empty")); } @Test public void testGetColor() { // RRGGBB conf.setProperty("color", "FF0000"); assertEquals("color", Color.red, conf.getColor("color")); // #RRGGBB conf.setProperty("color", "#00FF00"); assertEquals("color", Color.green, conf.getColor("color")); // #RRGGBBAA conf.setProperty("color", "#01030507"); Color color = conf.getColor("color"); assertNotNull("null color", color); assertEquals("red", 1, color.getRed()); assertEquals("green", 3, color.getGreen()); assertEquals("blue", 5, color.getBlue()); assertEquals("alpha", 7, color.getAlpha()); // interpolated value assertEquals(Color.red, conf.getColor("color.string.interpolated")); // default value assertEquals(Color.cyan, conf.getColor("unknownkey", Color.cyan)); } @Test public void testGetColorArray() throws Exception { // missing list Color[] defaultValue = new Color[] { Color.red, Color.blue }; ArrayAssert.assertEquals(defaultValue, conf.getColorArray("color.list", defaultValue)); Color[] expected = new Color[] { Color.red, Color.blue }; // list of strings ArrayAssert.assertEquals(expected, conf.getColorArray("color.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getColorArray("color.list2")); // list of Color objects ArrayAssert.assertEquals(expected, conf.getColorArray("color.list3")); // array of Color objects ArrayAssert.assertEquals(expected, conf.getColorArray("color.list4")); // list of Color objects ArrayAssert.assertEquals(expected, conf.getColorArray("color.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getColorArray("color.list.interpolated")); // single Color values ArrayAssert.assertEquals(new Color[] { Color.red }, conf.getColorArray("color.string")); ArrayAssert.assertEquals(new Color[] { Color.red }, conf.getColorArray("color.object")); // empty array ArrayAssert.assertEquals(new Color[] { }, conf.getColorArray("empty")); } @Test public void testGetColorList() throws Exception { // missing list ListAssert.assertEquals(null, conf.getColorList("color.list", null)); List expected = new ArrayList(); expected.add(Color.red); expected.add(Color.blue); // list of strings ListAssert.assertEquals(expected, conf.getColorList("color.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getColorList("color.list2")); // list of Color objects ListAssert.assertEquals(expected, conf.getColorList("color.list3")); // array of Color objects ListAssert.assertEquals(expected, conf.getColorList("color.list4")); // list of Color objects ListAssert.assertEquals(expected, conf.getColorList("color.list6")); // list of interpolated values ListAssert.assertEquals(expected, conf.getColorList("color.list.interpolated")); // single Color values expected = new ArrayList(); expected.add(Color.red); ListAssert.assertEquals(expected, conf.getColorList("color.string")); ListAssert.assertEquals(expected, conf.getColorList("color.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getColorList("empty")); } @Test public void testGetDate() throws Exception { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); // missing Date Date defaultValue = new Date(); assertEquals(defaultValue, conf.getDate("date", defaultValue)); assertNull("non null object for a missing key", conf.getDate("unknownkey", "yyyy-MM-dd")); conf.setThrowExceptionOnMissing(true); try { conf.getDate("unknownkey", "yyyy-MM-dd"); fail("NoSuchElementException should be thrown for missing properties"); } catch (NoSuchElementException e) { // expected } Date expected = format.parse("2004-01-01"); // Date string assertEquals(expected, conf.getDate("date.string")); assertEquals(expected, conf.getDate("date.string", "yyyy-MM-dd")); // Date object assertEquals(expected, conf.getDate("date.object")); // Calendar object assertEquals(expected, conf.getDate("calendar.object")); // interpolated value assertEquals(expected, conf.getDate("date.string.interpolated")); } @Test public void testGetDateArray() throws Exception { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date date1 = format.parse("2004-01-01"); Date date2 = format.parse("2004-12-31"); // missing list Date[] defaultValue = new Date[] { date2, date1 }; ArrayAssert.assertEquals(defaultValue, conf.getDateArray("date.list", defaultValue)); Date[] expected = new Date[] { date1, date2 }; // list of strings ArrayAssert.assertEquals(expected, conf.getDateArray("date.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getDateArray("date.list2")); // list of Date objects ArrayAssert.assertEquals(expected, conf.getDateArray("date.list3")); // array of Date objects ArrayAssert.assertEquals(expected, conf.getDateArray("date.list4")); // list of Calendar objects ArrayAssert.assertEquals(expected, conf.getDateArray("date.list5")); // list of Date objects ArrayAssert.assertEquals(expected, conf.getDateArray("date.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getDateArray("date.list.interpolated")); // single Date values ArrayAssert.assertEquals(new Date[] { date1 }, conf.getDateArray("date.string")); ArrayAssert.assertEquals(new Date[] { date1 }, conf.getDateArray("date.object")); // empty array ArrayAssert.assertEquals(new Date[] { }, conf.getDateArray("empty")); } @Test public void testGetDateArrayWithFormat() throws Exception { DateFormat format = new SimpleDateFormat("MM/dd/yyyy"); Date date1 = format.parse("01/01/2004"); Date date2 = format.parse("12/31/2004"); Date[] expected = new Date[] { date1, date2 }; conf.addProperty("date.format", "01/01/2004"); conf.addProperty("date.format", "12/31/2004"); ArrayAssert.assertEquals("Wrong dates with format", expected, conf.getDateArray("date.format", "MM/dd/yyyy")); } @Test public void testGetDateList() throws Exception { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date date1 = format.parse("2004-01-01"); Date date2 = format.parse("2004-12-31"); // missing list List nullList = null; ListAssert.assertEquals(null, conf.getDateList("date.list", nullList)); List expected = new ArrayList(); expected.add(date1); expected.add(date2); // list of strings ListAssert.assertEquals(expected, conf.getDateList("date.list1")); ListAssert.assertEquals(expected, conf.getList(Date.class, "date.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getDateList("date.list2")); // list of Date objects ListAssert.assertEquals(expected, conf.getDateList("date.list3")); // array of Date objects ListAssert.assertEquals(expected, conf.getDateList("date.list4")); // list of Calendar objects ListAssert.assertEquals(expected, conf.getDateList("date.list5")); // list of Date objects ListAssert.assertEquals(expected, conf.getDateList("date.list6")); // array of strings ListAssert.assertEquals(expected, conf.getList(Date.class, "date.list7")); // list of interpolated values ListAssert.assertEquals(expected, conf.getDateList("date.list.interpolated")); // single Date values expected = new ArrayList(); expected.add(date1); ListAssert.assertEquals(expected, conf.getDateList("date.string")); ListAssert.assertEquals(expected, conf.getDateList("date.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getDateList("empty")); } @Test public void testGetCalendar() throws Exception { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); // missing Date Calendar defaultValue = Calendar.getInstance(); defaultValue.setTime(new Date()); assertEquals(defaultValue, conf.getCalendar("calendar", defaultValue)); assertNull("non null object for a missing key", conf.getCalendar("unknownkey", "yyyy-MM-dd")); conf.setThrowExceptionOnMissing(true); try { conf.getCalendar("unknownkey", "yyyy-MM-dd"); fail("NoSuchElementException should be thrown for missing properties"); } catch (NoSuchElementException e) { // expected } Calendar expected = Calendar.getInstance(); expected.setTime(format.parse("2004-01-01")); // Calendar string assertEquals(expected, conf.getCalendar("calendar.string")); assertEquals(expected, conf.getCalendar("calendar.string", "yyyy-MM-dd")); // Calendar object assertEquals(expected, conf.getCalendar("calendar.object")); // Date object assertEquals(expected, conf.getCalendar("date.object")); // interpolated value assertEquals(expected, conf.getCalendar("calendar.string.interpolated")); } @Test public void testGetCalendarArray() throws Exception { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date date1 = format.parse("2004-01-01"); Date date2 = format.parse("2004-12-31"); Calendar calendar1 = Calendar.getInstance(); calendar1.setTime(date1); Calendar calendar2 = Calendar.getInstance(); calendar2.setTime(date2); // missing list Calendar[] defaultValue = new Calendar[] { calendar2, calendar1 }; ArrayAssert.assertEquals(defaultValue, conf.getCalendarArray("calendar.list", defaultValue)); Calendar[] expected = new Calendar[] { calendar1, calendar2 }; // list of strings ArrayAssert.assertEquals(expected, conf.getCalendarArray("calendar.list1")); // list of strings, comma separated ArrayAssert.assertEquals(expected, conf.getCalendarArray("calendar.list2")); // list of Calendar objects ArrayAssert.assertEquals(expected, conf.getCalendarArray("calendar.list3")); // array of Calendar objects ArrayAssert.assertEquals(expected, conf.getCalendarArray("calendar.list4")); // list of Date objects ArrayAssert.assertEquals(expected, conf.getCalendarArray("calendar.list5")); // list of Calendar objects ArrayAssert.assertEquals(expected, conf.getCalendarArray("calendar.list6")); // list of interpolated values ArrayAssert.assertEquals(expected, conf.getCalendarArray("calendar.list.interpolated")); // single Calendar values ArrayAssert.assertEquals(new Calendar[] { calendar1 }, conf.getCalendarArray("calendar.string")); ArrayAssert.assertEquals(new Calendar[] { calendar1 }, conf.getCalendarArray("calendar.object")); // empty array ArrayAssert.assertEquals(new Calendar[] { }, conf.getCalendarArray("empty")); } @Test public void testGetCalendarArrayWithFormat() throws Exception { DateFormat format = new SimpleDateFormat("MM/dd/yyyy"); Date date1 = format.parse("01/01/2004"); Date date2 = format.parse("12/31/2004"); Calendar calendar1 = Calendar.getInstance(); calendar1.setTime(date1); Calendar calendar2 = Calendar.getInstance(); calendar2.setTime(date2); Calendar[] expected = new Calendar[] { calendar1, calendar2 }; conf.addProperty("calendar.format", "01/01/2004"); conf.addProperty("calendar.format", "12/31/2004"); ArrayAssert.assertEquals("Wrong calendars with format", expected, conf.getCalendarArray("calendar.format", "MM/dd/yyyy")); } @Test public void testGetCalendarList() throws Exception { DateFormat format = new SimpleDateFormat("yyyy-MM-dd"); Date date1 = format.parse("2004-01-01"); Date date2 = format.parse("2004-12-31"); Calendar calendar1 = Calendar.getInstance(); calendar1.setTime(date1); Calendar calendar2 = Calendar.getInstance(); calendar2.setTime(date2); // missing list List nullList = null; ListAssert.assertEquals(null, conf.getCalendarList("calendar.list", nullList)); List expected = new ArrayList(); expected.add(calendar1); expected.add(calendar2); // list of strings ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list1")); ListAssert.assertEquals(expected, conf.getList(Calendar.class, "calendar.list1")); // list of strings, comma separated ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list2")); // list of Calendar objects ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list3")); // array of Calendar objects ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list4")); // list of Date objects ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list5")); // list of Calendar objects ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list6")); // array of strings ListAssert.assertEquals(expected, conf.getList(Calendar.class, "calendar.list7")); // list of interpolated values ListAssert.assertEquals(expected, conf.getCalendarList("calendar.list.interpolated")); // single Calendar values expected = new ArrayList(); expected.add(calendar1); ListAssert.assertEquals(expected, conf.getCalendarList("date.string")); ListAssert.assertEquals(expected, conf.getCalendarList("date.object")); // empty list ListAssert.assertEquals(new ArrayList(), conf.getCalendarList("empty")); } @Test public void testGetInetAddress() throws Exception { InetAddress expected = InetAddress.getByName("127.0.0.1"); // address as string assertEquals(expected, conf.get(InetAddress.class, "ip.string")); // address object assertEquals(expected, conf.get(InetAddress.class, "ip.object")); // interpolated value assertEquals(expected, conf.get(InetAddress.class, "ip.string.interpolated")); } @Test(expected = ConversionException.class) public void testGetInetAddressInvalidType() { conf.setProperty("ip.unknownhost", "random-foo-that-does-not-exist.ever"); conf.get(InetAddress.class, "ip.unknownhost"); } @Test public void testGetInternetAddress() throws Exception { Object expected = createInternetAddress("ebourg@apache.org"); // address as string assertEquals(expected, conf.get(expected.getClass(), "email.string")); // address object assertEquals(expected, conf.get(expected.getClass(), "email.object")); // interpolated value assertEquals(expected, conf.get(expected.getClass(), "email.string.interpolated")); conf.setProperty("email.invalid", "ebourg@apache@org"); try { conf.get(expected.getClass(), "email.invalid"); fail("ConversionException should be thrown for invalid emails"); } catch (ConversionException e) { // expected } } @Test(expected = ConversionException.class) public void testGetInternetAddressInvalidType() throws Exception { Object expected = createInternetAddress("ebourg@apache.org"); conf.setProperty("email.invalid", "ebourg@apache@org"); conf.get(expected.getClass(), "email.invalid"); } /** * Create an instance of InternetAddress. This trick is necessary to * compile and run the test with Java 1.3 and the javamail-1.4 which * is not compatible with Java 1.3 */ private Object createInternetAddress(String email) throws Exception { Class cls = Class.forName("javax.mail.internet.InternetAddress"); return cls.getConstructor(new Class[]{String.class}).newInstance(new Object[]{email}); } @Test public void testConversionException() throws Exception { conf.addProperty("key1", new Object()); conf.addProperty("key2", "xxxxxx"); try { conf.getBooleanArray("key1"); fail("getBooleanArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBooleanArray("key2"); fail("getBooleanArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBooleanList("key1"); fail("getBooleanList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBooleanList("key2"); fail("getBooleanList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getByteArray("key1"); fail("getByteArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getByteArray("key2"); fail("getByteArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getByteList("key1"); fail("getByteList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getByteList("key2"); fail("getByteList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getShortArray("key1"); fail("getShortArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getShortArray("key2"); fail("getShortArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getShortList("key1"); fail("getShortList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getShortList("key2"); fail("getShortList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getIntArray("key1"); fail("getIntArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getIntArray("key2"); fail("getIntArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getIntegerList("key1"); fail("getIntegerList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getIntegerList("key2"); fail("getIntegerList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getLongArray("key1"); fail("getLongArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getLongArray("key2"); fail("getLongArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getLongList("key1"); fail("getLongList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getLongList("key2"); fail("getLongList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getFloatArray("key1"); fail("getFloatArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getFloatArray("key2"); fail("getFloatArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getFloatList("key1"); fail("getFloatList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getFloatList("key2"); fail("getFloatList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDoubleArray("key1"); fail("getDoubleArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDoubleArray("key2"); fail("getDoubleArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDoubleList("key1"); fail("getDoubleList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDoubleList("key2"); fail("getDoubleList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBigIntegerArray("key1"); fail("getBigIntegerArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBigIntegerArray("key2"); fail("getBigIntegerArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBigIntegerList("key1"); fail("getBigIntegerList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBigIntegerList("key2"); fail("getBigIntegerList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBigDecimalArray("key1"); fail("getBigDecimalArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBigDecimalArray("key2"); fail("getBigDecimalArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBigDecimalList("key1"); fail("getBigDecimalList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getBigDecimalList("key2"); fail("getBigDecimalList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getURLArray("key1"); fail("getURLArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getURLArray("key2"); fail("getURLArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getURLList("key1"); fail("getURLList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getURLList("key2"); fail("getURLList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getLocaleArray("key1"); fail("getLocaleArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getLocaleArray("key2"); fail("getLocaleArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getLocaleList("key1"); fail("getLocaleList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getLocaleList("key2"); fail("getLocaleList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getColorArray("key1"); fail("getColorArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getColorArray("key2"); fail("getColorArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getColorList("key1"); fail("getColorList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getColorList("key2"); fail("getColorList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDateArray("key1"); fail("getDateArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDate("key1", "yyyy-MM-dd"); fail("getDate didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDate("key2", "yyyy-MM-dd"); fail("getDate didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDateArray("key2"); fail("getDateArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDateList("key1"); fail("getDateList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getDateList("key2"); fail("getDateList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getCalendar("key1", "yyyy-MM-dd"); fail("getCalendar didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getCalendar("key2","yyyy-MM-dd"); fail("getCalendar didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getCalendarArray("key1"); fail("getCalendarArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getCalendarArray("key2"); fail("getCalendarArray didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getCalendarList("key1"); fail("getCalendarList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.getCalendarList("key2"); fail("getCalendarList didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.get(InetAddress.class, "key1"); fail("getInetAddress didn't throw a ConversionException"); } catch (ConversionException e) { // expected } try { conf.get(Class.forName("javax.mail.internet.InternetAddress"), "key1"); fail("getInternetAddress didn't throw a ConversionException"); } catch (ConversionException e) { // expected } } /** * Tests whether a string property can be obtained through get() if no type * conversion is required. */ @Test public void testGetPropertyWithoutConversion() { String key = "test.str"; String value = "someTestValue"; conf.addProperty(key, value); assertEquals("Wrong result", value, conf.get(String.class, key)); } } ././@LongLink100644 0 0 163 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestDefaultConfigurationBuilder.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestDefaultConfigurati100644 142767 12232154104 33660 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.StringWriter; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.net.URL; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.commons.configuration.beanutils.BeanHelper; import org.apache.commons.configuration.event.ConfigurationListenerTestImpl; import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.apache.commons.lang.SystemUtils; import org.apache.commons.lang.text.StrLookup; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.impl.Log4JLogger; import org.apache.log4j.Level; import org.apache.log4j.Logger; import org.apache.log4j.SimpleLayout; import org.apache.log4j.WriterAppender; import org.junit.Before; import org.junit.Test; /** * Test class for DefaultConfigurationBuilder. * * @author Commons * Configuration team * @version $Id: TestDefaultConfigurationBuilder.java 1301997 2012-03-17 20:32:02Z sebb $ */ public class TestDefaultConfigurationBuilder { /** Test configuration definition file. */ private static final File TEST_FILE = ConfigurationAssert .getTestFile("testDigesterConfiguration.xml"); private static final File ADDITIONAL_FILE = ConfigurationAssert .getTestFile("testDigesterConfiguration2.xml"); private static final File OPTIONAL_FILE = ConfigurationAssert .getTestFile("testDigesterOptionalConfiguration.xml"); private static final File OPTIONALEX_FILE = ConfigurationAssert .getTestFile("testDigesterOptionalConfigurationEx.xml"); private static final File MULTI_FILE = ConfigurationAssert .getTestFile("testDigesterConfiguration3.xml"); private static final File INIT_FILE = ConfigurationAssert .getTestFile("testComplexInitialization.xml"); private static final File CLASS_FILE = ConfigurationAssert .getTestFile("testExtendedClass.xml"); private static final File PROVIDER_FILE = ConfigurationAssert .getTestFile("testConfigurationProvider.xml"); private static final File EXTENDED_PROVIDER_FILE = ConfigurationAssert .getTestFile("testExtendedXMLConfigurationProvider.xml"); private static final File GLOBAL_LOOKUP_FILE = ConfigurationAssert .getTestFile("testGlobalLookup.xml"); private static final File SYSTEM_PROPS_FILE = ConfigurationAssert .getTestFile("testSystemProperties.xml"); private static final File VALIDATION_FILE = ConfigurationAssert .getTestFile("testValidation.xml"); private static final File VALIDATION3_FILE = ConfigurationAssert .getTestFile("testValidation3.xml"); private static final File MULTI_TENENT_FILE = ConfigurationAssert .getTestFile("testMultiTenentConfigurationBuilder.xml"); private static final File EXPRESSION_FILE = ConfigurationAssert .getTestFile("testExpression.xml"); /** Constant for the name of an optional configuration.*/ private static final String OPTIONAL_NAME = "optionalConfig"; /** Stores the object to be tested. */ DefaultConfigurationBuilder factory; @Before public void setUp() throws Exception { System .setProperty("java.naming.factory.initial", "org.apache.commons.configuration.MockInitialContextFactory"); System.setProperty("test_file_xml", "test.xml"); System.setProperty("test_file_combine", "testcombine1.xml"); factory = new DefaultConfigurationBuilder(); factory.clearErrorListeners(); // avoid exception messages } /** * Tests the isReservedNode() method of ConfigurationDeclaration. */ @Test public void testConfigurationDeclarationIsReserved() { DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory); DefaultConfigurationNode parent = new DefaultConfigurationNode(); DefaultConfigurationNode nd = new DefaultConfigurationNode("at"); parent.addAttribute(nd); assertTrue("Attribute at not recognized", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("optional"); parent.addAttribute(nd); assertTrue("Attribute optional not recognized", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("config-class"); parent.addAttribute(nd); assertTrue("Inherited attribute not recognized", decl .isReservedNode(nd)); nd = new DefaultConfigurationNode("different"); parent.addAttribute(nd); assertFalse("Wrong reserved attribute", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("at"); parent.addChild(nd); assertFalse("Node type not evaluated", decl.isReservedNode(nd)); } /** * Tests if the at attribute is correctly detected as reserved attribute. */ @Test public void testConfigurationDeclarationIsReservedAt() { checkOldReservedAttribute("at"); } /** * Tests if the optional attribute is correctly detected as reserved * attribute. */ @Test public void testConfigurationDeclarationIsReservedOptional() { checkOldReservedAttribute("optional"); } /** * Tests if special reserved attributes are recognized by the * isReservedNode() method. For compatibility reasons the attributes "at" * and "optional" are also treated as reserved attributes, but only if there * are no corresponding attributes with the "config-" prefix. * * @param name the attribute name */ private void checkOldReservedAttribute(String name) { DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory); DefaultConfigurationNode parent = new DefaultConfigurationNode(); DefaultConfigurationNode nd = new DefaultConfigurationNode("config-" + name); parent.addAttribute(nd); assertTrue("config-" + name + " attribute not recognized", decl .isReservedNode(nd)); DefaultConfigurationNode nd2 = new DefaultConfigurationNode(name); parent.addAttribute(nd2); assertFalse(name + " is reserved though config- exists", decl .isReservedNode(nd2)); assertTrue("config- attribute not recognized when " + name + " exists", decl.isReservedNode(nd)); } /** * Tests access to certain reserved attributes of a * ConfigurationDeclaration. */ public void testConfigurationDeclarationGetAttributes() { factory.addProperty("xml.fileName", "test.xml"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("xml")); assertNull("Found an at attribute", decl.getAt()); assertFalse("Found an optional attribute", decl.isOptional()); factory.addProperty("xml[@config-at]", "test1"); assertEquals("Wrong value of at attribute", "test1", decl.getAt()); factory.addProperty("xml[@at]", "test2"); assertEquals("Wrong value of config-at attribute", "test1", decl.getAt()); factory.clearProperty("xml[@config-at]"); assertEquals("Old at attribute not detected", "test2", decl.getAt()); factory.addProperty("xml[@config-optional]", "true"); assertTrue("Wrong value of optional attribute", decl.isOptional()); factory.addProperty("xml[@optional]", "false"); assertTrue("Wrong value of config-optional attribute", decl.isOptional()); factory.clearProperty("xml[@config-optional]"); factory.setProperty("xml[@optional]", Boolean.TRUE); assertTrue("Old optional attribute not detected", decl.isOptional()); } /** * Tests whether an invalid value of an optional attribute is detected. */ @Test(expected = ConfigurationRuntimeException.class) public void testConfigurationDeclarationOptionalAttributeInvalid() { factory.addProperty("xml.fileName", "test.xml"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("xml")); factory.setProperty("xml[@optional]", "invalid value"); decl.isOptional(); } /** * Tests adding a new configuration provider. */ @Test public void testAddConfigurationProvider() { DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider(); assertNull("Provider already registered", factory .providerForTag("test")); factory.addConfigurationProvider("test", provider); assertSame("Provider not registered", provider, factory .providerForTag("test")); } /** * Tries to register a null configuration provider. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testAddConfigurationProviderNull() { factory.addConfigurationProvider("test", null); } /** * Tries to register a configuration provider for a null tag. This should * cause an exception to be thrown. */ @Test(expected = IllegalArgumentException.class) public void testAddConfigurationProviderNullTag() { factory.addConfigurationProvider(null, new DefaultConfigurationBuilder.ConfigurationProvider()); } /** * Tests removing configuration providers. */ @Test public void testRemoveConfigurationProvider() { assertNull("Removing unknown provider", factory .removeConfigurationProvider("test")); assertNull("Removing provider for null tag", factory .removeConfigurationProvider(null)); DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider(); factory.addConfigurationProvider("test", provider); assertSame("Failed to remove provider", provider, factory .removeConfigurationProvider("test")); assertNull("Provider still registered", factory.providerForTag("test")); } /** * Tests creating a configuration object from a configuration declaration. */ @Test public void testConfigurationBeanFactoryCreateBean() { factory.addConfigurationProvider("test", new DefaultConfigurationBuilder.ConfigurationProvider( PropertiesConfiguration.class)); factory.addProperty("test[@throwExceptionOnMissing]", "true"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("test")); PropertiesConfiguration conf = (PropertiesConfiguration) BeanHelper .createBean(decl); assertTrue("Property was not initialized", conf .isThrowExceptionOnMissing()); } /** * Tests creating a configuration object from an unknown tag. This should * cause an exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testConfigurationBeanFactoryCreateUnknownTag() { factory.addProperty("test[@throwExceptionOnMissing]", "true"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("test")); BeanHelper.createBean(decl); } /** * Tests loading a simple configuration definition file. */ @Test public void testLoadConfiguration() throws ConfigurationException { factory.setFile(TEST_FILE); checkConfiguration(); } /** * Tests the file constructor. */ @Test public void testLoadConfigurationFromFile() throws ConfigurationException { factory = new DefaultConfigurationBuilder(TEST_FILE); checkConfiguration(); } /** * Tests the file name constructor. */ @Test public void testLoadConfigurationFromFileName() throws ConfigurationException { factory = new DefaultConfigurationBuilder(TEST_FILE.getAbsolutePath()); checkConfiguration(); } /** * Tests the URL constructor. */ @Test public void testLoadConfigurationFromURL() throws Exception { factory = new DefaultConfigurationBuilder(TEST_FILE.toURI().toURL()); checkConfiguration(); } /** * Tests if the configuration was correctly created by the factory. */ private void checkConfiguration() throws ConfigurationException { CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory .getConfiguration(); assertEquals("Number of configurations", 3, compositeConfiguration .getNumberOfConfigurations()); assertEquals(PropertiesConfiguration.class, compositeConfiguration .getConfiguration(0).getClass()); assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration .getConfiguration(1).getClass()); assertEquals(XMLConfiguration.class, compositeConfiguration .getConfiguration(2).getClass()); // check the first configuration PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration .getConfiguration(0); assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc .getFileName()); // check some properties checkProperties(compositeConfiguration); } /** * Checks if the passed in configuration contains the expected properties. * * @param compositeConfiguration the configuration to check */ private void checkProperties(Configuration compositeConfiguration) { assertTrue("Make sure we have loaded our key", compositeConfiguration .getBoolean("test.boolean")); assertEquals("I'm complex!", compositeConfiguration .getProperty("element2.subelement.subsubelement")); assertEquals("property in the XMLPropertiesConfiguration", "value1", compositeConfiguration.getProperty("key1")); } /** * Tests loading a configuration definition file with an additional section. */ @Test public void testLoadAdditional() throws ConfigurationException { factory.setFile(ADDITIONAL_FILE); CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory .getConfiguration(); assertEquals("Verify how many configs", 2, compositeConfiguration .getNumberOfConfigurations()); // Test if union was constructed correctly Object prop = compositeConfiguration.getProperty("tables.table.name"); assertTrue(prop instanceof Collection); assertEquals(3, ((Collection) prop).size()); assertEquals("users", compositeConfiguration .getProperty("tables.table(0).name")); assertEquals("documents", compositeConfiguration .getProperty("tables.table(1).name")); assertEquals("tasks", compositeConfiguration .getProperty("tables.table(2).name")); prop = compositeConfiguration .getProperty("tables.table.fields.field.name"); assertTrue(prop instanceof Collection); assertEquals(17, ((Collection) prop).size()); assertEquals("smtp.mydomain.org", compositeConfiguration .getString("mail.host.smtp")); assertEquals("pop3.mydomain.org", compositeConfiguration .getString("mail.host.pop")); // This was overriden assertEquals("masterOfPost", compositeConfiguration .getString("mail.account.user")); assertEquals("topsecret", compositeConfiguration .getString("mail.account.psswd")); // This was overriden, too, but not in additional section assertEquals("enhanced factory", compositeConfiguration .getString("test.configuration")); } /** * Tests whether a default log error listener is registered at the builder * instance. */ @Test public void testLogErrorListener() { assertEquals("No default error listener registered", 1, new DefaultConfigurationBuilder().getErrorListeners().size()); } /** * Tests loading a definition file that contains optional configurations. */ @Test public void testLoadOptional() throws Exception { factory.setURL(OPTIONAL_FILE.toURI().toURL()); Configuration config = factory.getConfiguration(); assertTrue(config.getBoolean("test.boolean")); assertEquals("value", config.getProperty("element")); } /** * Tests whether loading a failing optional configuration causes an error * event. */ @Test public void testLoadOptionalErrorEvent() throws Exception { factory.clearErrorListeners(); ConfigurationErrorListenerImpl listener = new ConfigurationErrorListenerImpl(); factory.addErrorListener(listener); prepareOptionalTest("configuration", false); listener.verify(DefaultConfigurationBuilder.EVENT_ERR_LOAD_OPTIONAL, OPTIONAL_NAME, null); } /** * Tests loading a definition file with optional and non optional * configuration sources. One non optional does not exist, so this should * cause an exception. */ @Test(expected = ConfigurationException.class) public void testLoadOptionalWithException() throws ConfigurationException { factory.setFile(OPTIONALEX_FILE); factory.getConfiguration(); } /** * Tries to load a configuration file with an optional, non file-based * configuration. The optional attribute should work for other configuration * classes, too. */ @Test public void testLoadOptionalNonFileBased() throws ConfigurationException { CombinedConfiguration config = prepareOptionalTest("configuration", false); assertTrue("Configuration not empty", config.isEmpty()); assertEquals("Wrong number of configurations", 0, config .getNumberOfConfigurations()); } /** * Tests an optional, non existing configuration with the forceCreate * attribute. This configuration should be added to the resulting * configuration. */ @Test public void testLoadOptionalForceCreate() throws ConfigurationException { factory.setBasePath(TEST_FILE.getParent()); CombinedConfiguration config = prepareOptionalTest("xml", true); assertEquals("Wrong number of configurations", 1, config .getNumberOfConfigurations()); FileConfiguration fc = (FileConfiguration) config .getConfiguration(OPTIONAL_NAME); assertNotNull("Optional config not found", fc); assertEquals("File name was not set", "nonExisting.xml", fc .getFileName()); assertNotNull("Base path was not set", fc.getBasePath()); } /** * Tests loading an embedded optional configuration builder with the force * create attribute. */ @Test public void testLoadOptionalBuilderForceCreate() throws ConfigurationException { CombinedConfiguration config = prepareOptionalTest("configuration", true); assertEquals("Wrong number of configurations", 1, config .getNumberOfConfigurations()); assertTrue( "Wrong optional configuration type", config.getConfiguration(OPTIONAL_NAME) instanceof CombinedConfiguration); } /** * Tests loading an optional configuration with the force create attribute * set. The provider will always throw an exception. In this case the * configuration will not be added to the resulting combined configuration. */ @Test public void testLoadOptionalForceCreateWithException() throws ConfigurationException { factory.addConfigurationProvider("test", new DefaultConfigurationBuilder.ConfigurationBuilderProvider() { // Throw an exception here, too @Override public AbstractConfiguration getEmptyConfiguration( DefaultConfigurationBuilder.ConfigurationDeclaration decl) throws Exception { throw new Exception("Unable to create configuration!"); } }); CombinedConfiguration config = prepareOptionalTest("test", true); assertEquals("Optional configuration could be created", 0, config .getNumberOfConfigurations()); } /** * Prepares a test for loading a configuration definition file with an * optional configuration declaration. * * @param tag the tag name with the optional configuration * @param force the forceCreate attribute * @return the combined configuration obtained from the builder * @throws ConfigurationException if an error occurs */ private CombinedConfiguration prepareOptionalTest(String tag, boolean force) throws ConfigurationException { String prefix = "override." + tag; factory.addProperty(prefix + "[@fileName]", "nonExisting.xml"); factory.addProperty(prefix + "[@config-optional]", Boolean.TRUE); factory.addProperty(prefix + "[@config-name]", OPTIONAL_NAME); if (force) { factory.addProperty(prefix + "[@config-forceCreate]", Boolean.TRUE); } return factory.getConfiguration(false); } /** * Tests whether the error log message caused by an optional configuration * can be suppressed if a child builder is involved. */ @Test public void testLoadOptionalChildBuilderSuppressErrorLog() throws ConfigurationException { factory.addProperty("override.configuration[@fileName]", OPTIONAL_FILE.getAbsolutePath()); // a special invocation handler which checks that the warn() method of // a logger is not called InvocationHandler handler = new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { String methodName = method.getName(); if (methodName.startsWith("is")) { return Boolean.TRUE; } if ("warn".equals(methodName)) { fail("Unexpected log output!"); } return null; } }; factory.setLogger((Log) Proxy.newProxyInstance(getClass() .getClassLoader(), new Class[] { Log.class }, handler)); factory.getConfiguration(false); } /** * Tests loading a definition file with multiple different sources. */ @Test public void testLoadDifferentSources() throws ConfigurationException { factory.setFile(MULTI_FILE); Configuration config = factory.getConfiguration(); assertFalse(config.isEmpty()); assertTrue(config instanceof CombinedConfiguration); CombinedConfiguration cc = (CombinedConfiguration) config; assertEquals("Wrong number of configurations", 1, cc .getNumberOfConfigurations()); assertNotNull(config .getProperty("tables.table(0).fields.field(2).name")); assertNotNull(config.getProperty("element2.subelement.subsubelement")); assertEquals("value", config.getProperty("element3")); assertEquals("foo", config.getProperty("element3[@name]")); assertNotNull(config.getProperty("mail.account.user")); // test JNDIConfiguration assertNotNull(config.getProperty("test.onlyinjndi")); assertTrue(config.getBoolean("test.onlyinjndi")); Configuration subset = config.subset("test"); assertNotNull(subset.getProperty("onlyinjndi")); assertTrue(subset.getBoolean("onlyinjndi")); // test SystemConfiguration assertNotNull(config.getProperty("java.version")); assertEquals(System.getProperty("java.version"), config .getString("java.version")); // test INIConfiguration assertEquals("Property from ini file not found", "yes", config.getString("testini.loaded")); // test environment configuration EnvironmentConfiguration envConf = new EnvironmentConfiguration(); for (Iterator it = envConf.getKeys(); it.hasNext();) { String key = it.next(); String combinedKey = "env." + key; assertEquals("Wrong value for env property " + key, envConf.getString(key), config.getString(combinedKey)); } } /** * Tests if the base path is correctly evaluated. */ @Test public void testSetConfigurationBasePath() throws ConfigurationException { factory.addProperty("properties[@fileName]", "test.properties"); File deepDir = new File(ConfigurationAssert.TEST_DIR, "config/deep"); factory.setConfigurationBasePath(deepDir.getAbsolutePath()); Configuration config = factory.getConfiguration(false); assertEquals("Wrong property value", "somevalue", config .getString("somekey")); } /** * Tests reading a configuration definition file that contains complex * initialization of properties of the declared configuration sources. */ @Test public void testComplexInitialization() throws ConfigurationException { factory.setFile(INIT_FILE); CombinedConfiguration cc = (CombinedConfiguration) factory .getConfiguration(); assertEquals("System property not found", "test.xml", cc.getString("test_file_xml")); PropertiesConfiguration c1 = (PropertiesConfiguration) cc .getConfiguration(1); assertTrue( "Reloading strategy was not set", c1.getReloadingStrategy() instanceof FileChangedReloadingStrategy); assertEquals("Refresh delay was not set", 10000, ((FileChangedReloadingStrategy) c1.getReloadingStrategy()) .getRefreshDelay()); Configuration xmlConf = cc.getConfiguration("xml"); assertEquals("Property not found", "I'm complex!", xmlConf .getString("element2/subelement/subsubelement")); assertEquals("List index not found", "two", xmlConf .getString("list[0]/item[1]")); assertEquals("Property in combiner file not found", "yellow", cc .getString("/gui/selcolor")); assertTrue("Delimiter flag was not set", cc .isDelimiterParsingDisabled()); assertTrue("Expression engine was not set", cc.getExpressionEngine() instanceof XPathExpressionEngine); } /** * Tests if the returned combined configuration has the expected structure. */ @Test public void testCombinedConfigurationStructure() throws ConfigurationException { factory.setFile(INIT_FILE); CombinedConfiguration cc = (CombinedConfiguration) factory .getConfiguration(); assertNotNull("Properties configuration not found", cc .getConfiguration("properties")); assertNotNull("XML configuration not found", cc.getConfiguration("xml")); assertEquals("Wrong number of contained configs", 4, cc .getNumberOfConfigurations()); CombinedConfiguration cc2 = (CombinedConfiguration) cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); assertNotNull("No additional configuration found", cc2); Set names = cc2.getConfigurationNames(); assertEquals("Wrong number of contained additional configs", 2, names .size()); assertTrue("Config 1 not contained", names.contains("combiner1")); assertTrue("Config 2 not contained", names.contains("combiner2")); } /** * Helper method for testing the attributes of a combined configuration * created by the builder. * * @param cc the configuration to be checked */ private void checkCombinedConfigAttrs(CombinedConfiguration cc) { assertTrue("Wrong delimiter parsing flag", cc.isDelimiterParsingDisabled()); assertTrue("Wrong reload check", cc.isForceReloadCheck()); assertTrue("Wrong ignore reload ex flag", cc.isIgnoreReloadExceptions()); } /** * Tests whether attributes are correctly set on the combined configurations * for the override and additional sections. */ @Test public void testCombinedConfigurationAttributes() throws ConfigurationException { factory.setFile(INIT_FILE); CombinedConfiguration cc = (CombinedConfiguration) factory .getConfiguration(); checkCombinedConfigAttrs(cc); CombinedConfiguration cc2 = (CombinedConfiguration) cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); checkCombinedConfigAttrs(cc2); } /** * Tests the structure of the returned combined configuration if there is no * additional section. */ @Test public void testCombinedConfigurationNoAdditional() throws ConfigurationException { factory.setFile(TEST_FILE); CombinedConfiguration cc = factory.getConfiguration(true); assertNull("Additional configuration was found", cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME)); } /** * Tests whether the list node definition was correctly processed. */ @Test public void testCombinedConfigurationListNodes() throws ConfigurationException { factory.setFile(INIT_FILE); CombinedConfiguration cc = factory.getConfiguration(true); Set listNodes = cc.getNodeCombiner().getListNodes(); assertEquals("Wrong number of list nodes", 2, listNodes.size()); assertTrue("table node not a list node", listNodes.contains("table")); assertTrue("list node not a list node", listNodes.contains("list")); CombinedConfiguration cca = (CombinedConfiguration) cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); listNodes = cca.getNodeCombiner().getListNodes(); assertTrue("Found list nodes for additional combiner", listNodes .isEmpty()); } /** * Tests whether a configuration builder can itself be declared in a * configuration definition file. */ @Test public void testConfigurationBuilderProvider() throws ConfigurationException { factory.addProperty("override.configuration[@fileName]", TEST_FILE .getAbsolutePath()); CombinedConfiguration cc = factory.getConfiguration(false); assertEquals("Wrong number of configurations", 1, cc .getNumberOfConfigurations()); checkProperties(cc); } /** * Tests whether settings of the builder are propagated to child builders. */ @Test public void testConfigurationBuilderProviderInheritProperties() throws Exception { factory.addProperty("override.configuration[@fileName]", TEST_FILE.getAbsolutePath()); factory.setBasePath("conf"); factory.setAttributeSplittingDisabled(true); factory.setDelimiterParsingDisabled(true); factory.setListDelimiter('/'); factory.setThrowExceptionOnMissing(true); Log log = LogFactory.getLog(getClass()); factory.setLogger(log); factory.clearErrorListeners(); factory.clearConfigurationListeners(); ConfigurationListenerTestImpl l = new ConfigurationListenerTestImpl(factory); factory.addConfigurationListener(l); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("override.configuration")); DefaultConfigurationBuilder.ConfigurationBuilderProvider provider = new DefaultConfigurationBuilder.ConfigurationBuilderProvider(); DefaultConfigurationBuilder child = (DefaultConfigurationBuilder) provider.createBean( provider.fetchConfigurationClass(), decl, null); assertEquals("Wrong base path", factory.getBasePath(), child.getBasePath()); assertEquals("Wrong attribute splitting flag", factory.isAttributeSplittingDisabled(), child.isAttributeSplittingDisabled()); assertEquals("Wrong delimiter parsing flag", factory.isDelimiterParsingDisabled(), child.isDelimiterParsingDisabled()); assertEquals("Wrong list delimiter", factory.getListDelimiter(), child.getListDelimiter()); assertEquals("Wrong exception flag", factory.isThrowExceptionOnMissing(), child.isThrowExceptionOnMissing()); assertSame("Wrong logger", log, child.getLogger()); assertTrue("Got error listeners", child.getErrorListeners().isEmpty()); assertEquals("Wrong number of listeners", 1, child .getConfigurationListeners().size()); assertEquals("Wrong listener", l, child.getConfigurationListeners() .iterator().next()); } /** * Tests whether properties of the parent configuration can be overridden. */ @Test public void testConfigurationBuilderProviderOverrideProperties() throws Exception { factory.addProperty("override.configuration[@fileName]", TEST_FILE.getAbsolutePath()); factory.addProperty("override.configuration[@basePath]", "base"); factory.addProperty("override.configuration[@throwExceptionOnMissing]", "false"); factory.setBasePath("conf"); factory.setThrowExceptionOnMissing(true); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("override.configuration")); DefaultConfigurationBuilder.ConfigurationBuilderProvider provider = new DefaultConfigurationBuilder.ConfigurationBuilderProvider(); DefaultConfigurationBuilder child = (DefaultConfigurationBuilder) provider.createBean( provider.fetchConfigurationClass(), decl, null); assertEquals("Wrong base path", "base", child.getBasePath()); assertFalse("Wrong exception flag", child.isThrowExceptionOnMissing()); } /** * Tests whether XML settings can be inherited. */ @Test public void testLoadXMLWithSettings() throws Exception { File confDir = new File("conf"); File targetDir = new File("target"); File testXMLValidationSource = new File(confDir, "testValidateInvalid.xml"); File testSavedXML = new File(targetDir, "testSave.xml"); File testSavedFactory = new File(targetDir, "testSaveFactory.xml"); URL dtdFile = getClass().getResource("/properties.dtd"); final String publicId = "http://commons.apache.org/test.dtd"; XMLConfiguration config = new XMLConfiguration("testDtd.xml"); config.setPublicID(publicId); config.save(testSavedXML); factory.addProperty("xml[@fileName]", testSavedXML.getAbsolutePath()); factory.addProperty("xml(0)[@validating]", "true"); factory.addProperty("xml(-1)[@fileName]", testXMLValidationSource .getAbsolutePath()); factory.addProperty("xml(1)[@config-optional]", "true"); factory.addProperty("xml(1)[@validating]", "true"); factory.save(testSavedFactory); factory = new DefaultConfigurationBuilder(); factory.setFile(testSavedFactory); factory.registerEntityId(publicId, dtdFile); factory.clearErrorListeners(); Configuration c = factory.getConfiguration(); assertEquals("Wrong property value", "value1", c.getString("entry(0)")); assertFalse("Invalid XML source was loaded", c .containsKey("table.name")); testSavedXML.delete(); testSavedFactory.delete(); } /** * Tests loading a configuration definition file that defines a custom * result class. */ @Test public void testExtendedClass() throws ConfigurationException { factory.setFile(CLASS_FILE); CombinedConfiguration cc = factory.getConfiguration(true); assertEquals("Extended", cc.getProperty("test")); assertTrue("Wrong result class: " + cc.getClass(), cc instanceof ExtendedCombinedConfiguration); } /** * Tests loading a configuration definition file that defines new providers. */ @Test public void testConfigurationProvider() throws ConfigurationException { factory.setFile(PROVIDER_FILE); factory.getConfiguration(true); DefaultConfigurationBuilder.ConfigurationProvider provider = factory .providerForTag("test"); assertNotNull("Provider 'test' not registered", provider); } /** * Tests loading a configuration definition file that defines new providers. */ @Test public void testExtendedXMLConfigurationProvider() throws ConfigurationException { factory.setFile(EXTENDED_PROVIDER_FILE); CombinedConfiguration cc = factory.getConfiguration(true); DefaultConfigurationBuilder.ConfigurationProvider provider = factory .providerForTag("test"); assertNotNull("Provider 'test' not registered", provider); Configuration config = cc.getConfiguration("xml"); assertNotNull("Test configuration not present", config); assertTrue("Configuration is not ExtendedXMLConfiguration, is " + config.getClass().getName(), config instanceof ExtendedXMLConfiguration); } @Test public void testGlobalLookup() throws Exception { factory.setFile(GLOBAL_LOOKUP_FILE); CombinedConfiguration cc = factory.getConfiguration(true); String value = cc.getInterpolator().lookup("test:test_key"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","test.value",value); } @Test public void testSystemProperties() throws Exception { factory.setFile(SYSTEM_PROPS_FILE); factory.getConfiguration(true); String value = System.getProperty("key1"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","value1",value); } @Test public void testValidation() throws Exception { factory.setFile(VALIDATION_FILE); factory.getConfiguration(true); String value = System.getProperty("key1"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","value1",value); } @Test public void testValidation3() throws Exception { System.getProperties().remove("Id"); factory.setFile(VALIDATION3_FILE); CombinedConfiguration config = factory.getConfiguration(true); String value = config.getString("Employee/Name"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","John Doe",value); System.setProperty("Id", "1001"); value = config.getString("Employee/Name"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","Jane Doe",value); } @Test public void testMultiTenentConfiguration() throws Exception { factory.setFile(MULTI_TENENT_FILE); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testMultiTenentConfiguration2() throws Exception { factory.setFile(MULTI_TENENT_FILE); System.setProperty("Id", "1004"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testMultiTenentConfiguration3() throws Exception { factory.setFile(MULTI_TENENT_FILE); StringWriter writer = new StringWriter(); WriterAppender app = new WriterAppender(new SimpleLayout(), writer); Log log = LogFactory.getLog("TestLogger"); Logger logger = ((Log4JLogger)log).getLogger(); logger.addAppender(app); logger.setLevel(Level.DEBUG); logger.setAdditivity(false); System.setProperty("Id", "1005"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); String xml = writer.getBuffer().toString(); assertNotNull("No XML returned", xml); assertTrue("Incorect configuration data", xml.indexOf("15") >= 0); logger.removeAppender(app); logger.setLevel(Level.OFF); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testMultiTenantConfigurationAt() throws Exception { factory.setFile(MULTI_TENENT_FILE); System.setProperty("Id", "1001"); CombinedConfiguration config = factory.getConfiguration(true); HierarchicalConfiguration sub1 = config.configurationAt("Channels/Channel[@id='1']"); assertEquals("My Channel", sub1.getString("Name")); assertEquals("test 1 data", sub1.getString("ChannelData")); HierarchicalConfiguration sub2 = config.configurationAt("Channels/Channel[@id='2']"); assertEquals("Channel 2", sub2.getString("Name")); assertEquals("more test 2 data", sub2.getString("MoreChannelData")); } @Test public void testMerge() throws Exception { factory.setFile(MULTI_TENENT_FILE); System.setProperty("Id", "1004"); Map map = new HashMap(); map.put("default", "${colors.header4}"); map.put("background", "#40404040"); map.put("text", "#000000"); map.put("header", "#444444"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); List list = config.configurationsAt("colors/*"); Iterator iter = list.iterator(); while (iter.hasNext()) { SubnodeConfiguration sub = (SubnodeConfiguration)iter.next(); ConfigurationNode node = sub.getRootNode(); String value = (node.getValue() == null) ? "null" : node.getValue().toString(); if (map.containsKey(node.getName())) { assertEquals(map.get(node.getName()), value); } } } @Test public void testDelimiterParsingDisabled() throws Exception { factory.setFile(MULTI_TENENT_FILE); System.setProperty("Id", "1004"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); assertEquals("a,b,c", config.getString("split/list3/@values")); assertEquals(0, config.getMaxIndex("split/list3/@values")); assertEquals("a\\,b\\,c", config.getString("split/list4/@values")); assertEquals("a,b,c", config.getString("split/list1")); assertEquals(0, config.getMaxIndex("split/list1")); assertEquals("a\\,b\\,c", config.getString("split/list2")); } @Test public void testExpression() throws Exception { if (SystemUtils.isJavaVersionAtLeast(150)) { factory.setFile(EXPRESSION_FILE); factory.setAttributeSplittingDisabled(true); System.getProperties().remove("Id"); org.slf4j.MDC.clear(); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); } } /** * Tests whether variable substitution works across multiple child * configurations. This test is related to CONFIGURATION-481. */ @Test public void testInterpolationOverMultipleSources() throws ConfigurationException { File testFile = ConfigurationAssert.getTestFile("testInterpolationBuilder.xml"); factory.setFile(testFile); CombinedConfiguration combConfig = factory.getConfiguration(true); assertEquals("Wrong value", "abc-product", combConfig.getString("products.product.desc")); XMLConfiguration xmlConfig = (XMLConfiguration) combConfig.getConfiguration("test"); assertEquals("Wrong value from XML config", "abc-product", xmlConfig.getString("products/product/desc")); SubnodeConfiguration subConfig = xmlConfig .configurationAt("products/product[@name='abc']", true); assertEquals("Wrong value from sub config", "abc-product", subConfig.getString("desc")); } private void verify(String key, CombinedConfiguration config, int rows) { System.setProperty("Id", key); org.slf4j.MDC.put("Id", key); int actual = config.getInt("rowsPerPage"); assertTrue("expected: " + rows + " actual: " + actual, actual == rows); } /** * A specialized combined configuration implementation used for testing * custom result classes. */ public static class ExtendedCombinedConfiguration extends CombinedConfiguration { /** * The serial version UID. */ private static final long serialVersionUID = 4678031745085083392L; @Override public Object getProperty(String key) { if (key.equals("test")) { return "Extended"; } return super.getProperty(key); } } public static class ExtendedXMLConfiguration extends XMLConfiguration { private static final long serialVersionUID = 1L; public ExtendedXMLConfiguration() { } } public static class TestLookup extends StrLookup { Map map = new HashMap(); public TestLookup() { map.put("test_file_xml", "test.xml"); map.put("test_file_combine", "testcombine1.xml"); map.put("test_key", "test.value"); } @Override public String lookup(String key) { if (key == null) { return null; } return map.get(key); } } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestDynamicCombinedConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestDynamicCombinedCon100644 30037 12232154104 33530 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.apache.commons.lang.text.StrLookup; import org.junit.Test; public class TestDynamicCombinedConfiguration { private static String PATTERN = "${sys:Id}"; private static String PATTERN1 = "target/test-classes/testMultiConfiguration_${sys:Id}.xml"; private static String DEFAULT_FILE = "target/test-classes/testMultiConfiguration_default.xml"; private static final File MULTI_TENENT_FILE = new File( "conf/testMultiTenentConfigurationBuilder4.xml"); private static final File MULTI_DYNAMIC_FILE = new File( "conf/testMultiTenentConfigurationBuilder5.xml"); /** Constant for the number of test threads. */ private static final int THREAD_COUNT = 3; /** Constant for the number of loops in the multi-thread tests. */ private static final int LOOP_COUNT = 100; @Test public void testConfiguration() throws Exception { DynamicCombinedConfiguration config = new DynamicCombinedConfiguration(); XPathExpressionEngine engine = new XPathExpressionEngine(); config.setExpressionEngine(engine); config.setKeyPattern(PATTERN); config.setDelimiterParsingDisabled(true); MultiFileHierarchicalConfiguration multi = new MultiFileHierarchicalConfiguration(PATTERN1); multi.setExpressionEngine(engine); config.addConfiguration(multi, "Multi"); XMLConfiguration xml = new XMLConfiguration(); xml.setExpressionEngine(engine); xml.setDelimiterParsingDisabled(true); xml.setFile(new File(DEFAULT_FILE)); xml.load(); config.addConfiguration(xml, "Default"); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); assertEquals("a,b,c", config.getString("split/list3/@values")); assertEquals(0, config.getMaxIndex("split/list3/@values")); assertEquals("a\\,b\\,c", config.getString("split/list4/@values")); assertEquals("a,b,c", config.getString("split/list1")); assertEquals(0, config.getMaxIndex("split/list1")); assertEquals("a\\,b\\,c", config.getString("split/list2")); } @Test public void testConcurrentGetAndReload() throws Exception { System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_TENENT_FILE); CombinedConfiguration config = factory.getConfiguration(true); assertEquals(config.getString("rowsPerPage"), "50"); Thread testThreads[] = new Thread[THREAD_COUNT]; int failures[] = new int[THREAD_COUNT]; for (int i = 0; i < testThreads.length; ++i) { testThreads[i] = new ReloadThread(config, failures, i, LOOP_COUNT, false, null, "50"); testThreads[i].start(); } int totalFailures = 0; for (int i = 0; i < testThreads.length; ++i) { testThreads[i].join(); totalFailures += failures[i]; } assertTrue(totalFailures + " failures Occurred", totalFailures == 0); } @Test public void testConcurrentGetAndReload2() throws Exception { System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_TENENT_FILE); CombinedConfiguration config = factory.getConfiguration(true); assertEquals(config.getString("rowsPerPage"), "50"); Thread testThreads[] = new Thread[THREAD_COUNT]; int failures[] = new int[THREAD_COUNT]; System.setProperty("Id", "2002"); assertEquals(config.getString("rowsPerPage"), "25"); for (int i = 0; i < testThreads.length; ++i) { testThreads[i] = new ReloadThread(config, failures, i, LOOP_COUNT, false, null, "25"); testThreads[i].start(); } int totalFailures = 0; for (int i = 0; i < testThreads.length; ++i) { testThreads[i].join(); totalFailures += failures[i]; } System.getProperties().remove("Id"); assertTrue(totalFailures + " failures Occurred", totalFailures == 0); } @Test public void testConcurrentGetAndReloadMultipleClients() throws Exception { System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_TENENT_FILE); CombinedConfiguration config = factory.getConfiguration(true); assertEquals(config.getString("rowsPerPage"), "50"); Thread testThreads[] = new Thread[THREAD_COUNT]; int failures[] = new int[THREAD_COUNT]; String[] ids = new String[] {null, "2002", "3001", "3002", "3003"}; String[] expected = new String[] {"50", "25", "15", "25", "50"}; for (int i = 0; i < testThreads.length; ++i) { testThreads[i] = new ReloadThread(config, failures, i, LOOP_COUNT, true, ids[i], expected[i]); testThreads[i].start(); } int totalFailures = 0; for (int i = 0; i < testThreads.length; ++i) { testThreads[i].join(); totalFailures += failures[i]; } System.getProperties().remove("Id"); if (totalFailures != 0) { System.out.println("Failures:"); for (int i = 0; i < testThreads.length; ++i) { System.out.println("Thread " + i + " " + failures[i]); } } assertTrue(totalFailures + " failures Occurred", totalFailures == 0); } @Test public void testConcurrentGetAndReloadFile() throws Exception { final int threadCount = 25; System.getProperties().remove("Id"); // create a new configuration File input = new File("target/test-classes/testMultiDynamic_default.xml"); File output = new File("target/test-classes/testwrite/testMultiDynamic_default.xml"); output.delete(); output.getParentFile().mkdir(); copyFile(input, output); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_DYNAMIC_FILE); CombinedConfiguration config = factory.getConfiguration(true); assertEquals(config.getString("Product/FIIndex/FI[@id='123456781']"), "ID0001"); ReaderThread testThreads[] = new ReaderThread[threadCount]; for (int i = 0; i < testThreads.length; ++i) { testThreads[i] = new ReaderThread(config); testThreads[i].start(); } Thread.sleep(2000); input = new File("target/test-classes/testMultiDynamic_default2.xml"); copyFile(input, output); Thread.sleep(2000); String id = config.getString("Product/FIIndex/FI[@id='123456782']"); assertNotNull("File did not reload, id is null", id); String rows = config.getString("rowsPerPage"); assertTrue("Incorrect value for rowsPerPage", "25".equals(rows)); for (int i = 0; i < testThreads.length; ++i) { testThreads[i].shutdown(); testThreads[i].join(); } for (int i = 0; i < testThreads.length; ++i) { assertFalse(testThreads[i].failed()); } assertEquals("ID0002", config.getString("Product/FIIndex/FI[@id='123456782']")); output.delete(); } private class ReloadThread extends Thread { CombinedConfiguration combined; int[] failures; int index; int count; String expected; String id; boolean useId; ReloadThread(CombinedConfiguration config, int[] failures, int index, int count, boolean useId, String id, String expected) { combined = config; this.failures = failures; this.index = index; this.count = count; this.expected = expected; this.id = id; this.useId = useId; } @Override public void run() { failures[index] = 0; if (useId) { ThreadLookup.setId(id); } for (int i = 0; i < count; i++) { try { String value = combined.getString("rowsPerPage", null); if (value == null || !value.equals(expected)) { ++failures[index]; } } catch (Exception ex) { ++failures[index]; } } } } private class ReaderThread extends Thread { private boolean running = true; private boolean failed = false; CombinedConfiguration combined; public ReaderThread(CombinedConfiguration c) { combined = c; } @Override public void run() { while (running) { String bcId = combined.getString("Product/FIIndex/FI[@id='123456781']"); if ("ID0001".equalsIgnoreCase(bcId)) { if (failed) { System.out.println("Thread failed, but recovered"); } failed = false; } else { failed = true; } } } public boolean failed() { return failed; } public void shutdown() { running = false; } } private void verify(String key, DynamicCombinedConfiguration config, int rows) { System.setProperty("Id", key); assertTrue(config.getInt("rowsPerPage") == rows); } private void copyFile(File input, File output) throws IOException { Reader reader = new FileReader(input); Writer writer = new FileWriter(output); char[] buffer = new char[4096]; int n = 0; while (-1 != (n = reader.read(buffer))) { writer.write(buffer, 0, n); } reader.close(); writer.close(); } public static class ThreadLookup extends StrLookup { private static ThreadLocal id = new ThreadLocal(); public ThreadLookup() { } public static void setId(String value) { id.set(value); } @Override public String lookup(String key) { if (key == null || !key.equals("Id")) { return null; } String value = System.getProperty("Id"); if (value != null) { return value; } return id.get(); } } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestEnvironmentConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestEnvironmentConfigu100644 6216 12232154104 33644 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.util.Iterator; import org.junit.Before; import org.junit.Test; /** * Test class for EnvironmentConfiguration. * * @author Commons * Configuration team * @version $Id: TestEnvironmentConfiguration.java 1224637 2011-12-25 19:47:21Z oheger $ */ public class TestEnvironmentConfiguration { /** Stores the configuration to be tested. */ private EnvironmentConfiguration config; @Before public void setUp() throws Exception { config = new EnvironmentConfiguration(); } /** * Tests whether a newly created configuration contains some properties. (We * expect that at least some properties are set in each environment.) */ @Test public void testInit() { boolean found = false; assertFalse("No properties found", config.isEmpty()); for (Iterator it = config.getKeys(); it.hasNext();) { String key = it.next(); assertTrue("Key not found: " + key, config.containsKey(key)); assertNotNull("No value for property " + key, config.getString(key)); found = true; } assertTrue("No property keys returned", found); } /** * Tests removing properties. This should not be possible. */ @Test(expected = UnsupportedOperationException.class) public void testClearProperty() { String key = config.getKeys().next(); config.clearProperty(key); } /** * Tests removing all properties. This should not be possible. */ @Test(expected = UnsupportedOperationException.class) public void testClear() { config.clear(); } /** * Tries to add another property. This should cause an exception. */ @Test(expected = UnsupportedOperationException.class) public void testAddProperty() { config.addProperty("JAVA_HOME", "C:\\java"); } /** * Tries to set the value of a property. This should cause an exception. */ @Test(expected = UnsupportedOperationException.class) public void testSetProperty() { config.setProperty("JAVA_HOME", "C:\\java"); } } ././@LongLink100644 0 0 146 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestEqualBehaviour.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestEqualBehaviour.jav100644 20757 12232154104 33546 0ustarhenningstaff 0 0 package org.apache.commons.configuration; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.List; import org.junit.Test; /** * Compare the behavior of various methods between CompositeConfiguration * and normal (Properties) Configuration * * @version $Id: TestEqualBehaviour.java 1224638 2011-12-25 19:51:09Z oheger $ */ public class TestEqualBehaviour { private Configuration setupSimpleConfiguration() throws Exception { String simpleConfigurationFile = ConfigurationAssert.getTestFile("testEqual.properties").getAbsolutePath(); return new PropertiesConfiguration(simpleConfigurationFile); } @SuppressWarnings("deprecation") private Configuration setupCompositeConfiguration() throws Exception { String compositeConfigurationFile = ConfigurationAssert.getTestFile("testEqualDigester.xml").getAbsolutePath(); ConfigurationFactory configurationFactory = new ConfigurationFactory(); configurationFactory.setConfigurationFileName(compositeConfigurationFile); return configurationFactory.getConfiguration(); } /** * Checks whether two configurations have the same size, * the same key sequence and contain the same key -> value mappings */ private void checkEquality(String msg, Configuration c1, Configuration c2) { Iterator it1 = c1.getKeys(); Iterator it2 = c2.getKeys(); while(it1.hasNext() && it2.hasNext()) { String key1 = it1.next(); String key2 = it2.next(); assertEquals(msg + ", Keys: ", key1, key2); assertEquals(msg + ", Contains: ", c1.containsKey(key1), c2.containsKey(key2)); } assertEquals(msg + ", Iterator: ", it1.hasNext(), it2.hasNext()); } /** * Checks whether two configurations have the same key -> value mapping */ private void checkSameKey(String msg, String key, Configuration c1, Configuration c2) { String [] s1 = c1.getStringArray(key); String [] s2 = c2.getStringArray(key); assertEquals(msg + ", length: ", s1.length, s2.length); for (int i = 0; i < s1.length ; i++) { assertEquals(msg + ", String Array: ", s1[i], s2[i]); } List list1 = c1.getList(key); List list2 = c2.getList(key); assertEquals(msg + ", Size: ", list1.size(), list2.size()); Iterator it1 = list1.iterator(); Iterator it2 = list2.iterator(); while(it1.hasNext() && it2.hasNext()) { String val1 = (String) it1.next(); String val2 = (String) it2.next(); assertEquals(msg + ", List: ", val1, val2); } assertEquals(msg + ", Iterator End: ", it1.hasNext(), it2.hasNext()); } /** * Are both configurations equal after loading? */ @Test public void testLoading() throws Exception { Configuration simple = setupSimpleConfiguration(); Configuration composite = setupCompositeConfiguration(); checkEquality("testLoading", simple, composite); } /** * If we delete a key, does it vanish? Does it leave all * the other keys unchanged? How about an unset key? */ @Test public void testDeletingExisting() throws Exception { Configuration simple = setupSimpleConfiguration(); Configuration composite = setupCompositeConfiguration(); String key = "clear.property"; assertTrue(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); simple.clearProperty(key); composite.clearProperty(key); assertFalse(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); checkEquality("testDeletingExisting", simple, composite); } @Test public void testDeletingNonExisting() throws Exception { Configuration simple = setupSimpleConfiguration(); Configuration composite = setupCompositeConfiguration(); String key = "nonexisting.clear.property"; assertFalse(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); simple.clearProperty(key); composite.clearProperty(key); assertFalse(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); checkEquality("testDeletingNonExisting", simple, composite); } /** * If we set a key, does it work? How about an existing * key? Can we change it? */ @Test public void testSettingNonExisting() throws Exception { Configuration simple = setupSimpleConfiguration(); Configuration composite = setupCompositeConfiguration(); String key = "nonexisting.property"; String value = "new value"; assertFalse(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); simple.setProperty(key, value); composite.setProperty(key, value); assertTrue(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); checkSameKey("testSettingNonExisting", key, simple, composite); checkEquality("testSettingNonExisting", simple, composite); } @Test public void testSettingExisting() throws Exception { Configuration simple = setupSimpleConfiguration(); Configuration composite = setupCompositeConfiguration(); String key = "existing.property"; String value = "new value"; assertTrue(simple.containsKey(key)); assertFalse(simple.getString(key).equals(value)); assertEquals(simple.containsKey(key), composite.containsKey(key)); simple.setProperty(key, value); composite.setProperty(key, value); assertTrue(simple.containsKey(key)); assertEquals(simple.getString(key), value); assertEquals(simple.containsKey(key), composite.containsKey(key)); checkSameKey("testSettingExisting", key, simple, composite); checkEquality("testSettingExisting", simple, composite); } /** * If we add a key, does it work? */ @Test public void testAddingUnset() throws Exception { Configuration simple = setupSimpleConfiguration(); Configuration composite = setupCompositeConfiguration(); String key = "nonexisting.property"; String value = "new value"; assertFalse(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); simple.addProperty(key, value); composite.addProperty(key, value); checkSameKey("testAddingUnset", key, simple, composite); checkEquality("testAddingUnset", simple, composite); } /** * If we add a to an existing key, does it work? */ @Test public void testAddingSet() throws Exception { Configuration simple = setupSimpleConfiguration(); Configuration composite = setupCompositeConfiguration(); String key = "existing.property"; String value = "new value"; assertTrue(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); simple.addProperty(key, value); composite.addProperty(key, value); assertTrue(simple.containsKey(key)); assertEquals(simple.containsKey(key), composite.containsKey(key)); checkSameKey("testAddingSet", key, simple, composite); checkEquality("testAddingSet", simple, composite); } } ././@LongLink100644 0 0 146 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestEqualsProperty.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestEqualsProperty.jav100644 2741 12232154104 33602 0ustarhenningstaff 0 0 package org.apache.commons.configuration; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static org.junit.Assert.assertEquals; import org.junit.Test; /** * test if properties that contain a "=" will be loaded correctly. * * @version $Id: TestEqualsProperty.java 1224639 2011-12-25 19:52:46Z oheger $ */ public class TestEqualsProperty { /** The File that we test with */ private String testProperties = ConfigurationAssert.getTestFile("test.properties").getAbsolutePath(); @Test public void testEquals() throws Exception { PropertiesConfiguration conf = new PropertiesConfiguration(testProperties); String equals = conf.getString("test.equals"); assertEquals("value=one", equals); } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestFileConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestFileConfiguration.100644 52607 12232154104 33537 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.net.URL; import java.util.Iterator; import java.util.Properties; import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy; import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; /** * @author Emmanuel Bourg * @version $Id: TestFileConfiguration.java 1231721 2012-01-15 18:32:07Z oheger $ */ public class TestFileConfiguration { /** Constant for the name of a test file.*/ private static final String TEST_FILENAME = "test.properties"; /** Constant for a test file.*/ private static final File TEST_FILE = ConfigurationAssert.getTestFile(TEST_FILENAME); /** Constant for a test output file. */ private static final File OUT_FILE = new File( "target/test-resources/foo/bar/test.properties"); /** Constant for the name of a resource to be resolved.*/ private static final String RESOURCE_NAME = "config/deep/deeptest.properties"; /** Helper object for managing temporary files. */ @Rule public TemporaryFolder folder = new TemporaryFolder(); /** * Initializes the test environment. This implementation ensures that the * test output file does not exist. */ @Before public void setUp() throws Exception { removeOutFile(); } /** * Performs cleanup after a test case. This implementation removes temporary * files that have been created. */ protected void tearDown() throws Exception { removeOutFile(); } /** * Removes a file if it exists. * * @param file the file to be removed */ private static void removeFile(File file) { if (file.exists()) { assertTrue("Cannot remove file: " + file, file.delete()); } } /** * Removes the test output file if it exists. Its parent directories are * also removed. */ private static void removeOutFile() { removeFile(OUT_FILE); File parent = OUT_FILE.getParentFile(); removeFile(parent); parent = parent.getParentFile(); removeFile(parent); } @Test public void testSetURL() throws Exception { // http URL FileConfiguration config = new PropertiesConfiguration(); config.setURL(new URL("http://commons.apache.org/configuration/index.html")); assertEquals("base path", "http://commons.apache.org/configuration/", config.getBasePath()); assertEquals("file name", "index.html", config.getFileName()); // file URL - This url is invalid, a valid url would be file:///temp/test.properties. config.setURL(new URL("file:/temp/test.properties")); assertEquals("base path", "file:///temp/", config.getBasePath()); assertEquals("file name", "test.properties", config.getFileName()); } @Test public void testSetURLWithParams() throws Exception { FileConfiguration config = new PropertiesConfiguration(); URL url = new URL("http://issues.apache.org/bugzilla/show_bug.cgi?id=37886"); config.setURL(url); assertEquals("Base path incorrect", "http://issues.apache.org/bugzilla/", config.getBasePath()); assertEquals("File name incorrect", "show_bug.cgi", config.getFileName()); assertEquals("URL was not correctly stored", url, config.getURL()); } @Test public void testLocations() throws Exception { PropertiesConfiguration config = new PropertiesConfiguration(); File directory = ConfigurationAssert.TEST_DIR; File file = TEST_FILE; config.setFile(file); assertEquals(directory.getAbsolutePath(), config.getBasePath()); assertEquals(TEST_FILENAME, config.getFileName()); assertEquals(file.getAbsolutePath(), config.getPath()); config.setPath(ConfigurationAssert.TEST_DIR_NAME + File.separator + TEST_FILENAME); assertEquals(TEST_FILENAME, config.getFileName()); assertEquals(directory.getAbsolutePath(), config.getBasePath()); assertEquals(file.getAbsolutePath(), config.getPath()); assertEquals(file.toURI().toURL(), config.getURL()); config.setBasePath(null); config.setFileName(TEST_FILENAME); assertNull(config.getBasePath()); assertEquals(TEST_FILENAME, config.getFileName()); } @Test public void testCreateFile1() throws Exception { assertFalse("The file should not exist", OUT_FILE.exists()); FileConfiguration config = new PropertiesConfiguration(OUT_FILE); config.save(); assertTrue("The file doesn't exist", OUT_FILE.exists()); } @Test public void testCreateFile2() throws Exception { FileConfiguration config = new PropertiesConfiguration(); config.setFile(OUT_FILE); config.save(); assertTrue("The file doesn't exist", OUT_FILE.exists()); } @Test public void testCreateFile3() throws Exception { FileConfiguration config = new PropertiesConfiguration(); config.save(OUT_FILE); assertTrue("The file doesn't exist", OUT_FILE.exists()); } /** * Tests collaboration with ConfigurationFactory: Is the base path set on * loading is valid in file based configurations? * * @throws Exception if an error occurs */ @SuppressWarnings("deprecation") @Test public void testWithConfigurationFactory() throws Exception { File file = folder.newFile(); ConfigurationFactory factory = new ConfigurationFactory(); factory.setConfigurationURL(ConfigurationAssert.getTestURL( "testDigesterConfiguration2.xml")); CompositeConfiguration cc = (CompositeConfiguration) factory.getConfiguration(); PropertiesConfiguration config = null; for (int i = 0; config == null; i++) { if (cc.getConfiguration(i) instanceof PropertiesConfiguration) { config = (PropertiesConfiguration) cc.getConfiguration(i); } } config.setProperty("test", "yes"); config.save(file); assertTrue(file.exists()); config = new PropertiesConfiguration(); config.setFile(file); config.load(); assertEquals("yes", config.getProperty("test")); assertEquals("masterOfPost", config.getProperty("mail.account.user")); } /** * Tests if invalid URLs cause an exception. */ @Test(expected = ConfigurationException.class) public void testSaveInvalidURL() throws Exception { FileConfiguration config = new PropertiesConfiguration(); config.save(new URL("http://jakarta.apache.org/test.properties")); } /** * Tests if an invalid URL string causes an exception. */ @Test(expected = ConfigurationException.class) public void testSaveInvalidURLString() throws ConfigurationException { FileConfiguration config = new PropertiesConfiguration(); config.save("http://www.apache.org/test.properties"); } /** * Tests if the URL used by the load() method is also used by save(). */ @Test public void testFileOverwrite() throws Exception { FileOutputStream out = null; FileInputStream in = null; File tempFile = null; try { tempFile = folder.newFile(); Properties props = new Properties(); props.setProperty("1", "one"); out = new FileOutputStream(tempFile); props.store(out, "TestFileOverwrite"); out.close(); out = null; FileConfiguration config = new PropertiesConfiguration(tempFile); config.load(); String value = config.getString("1"); assertTrue("one".equals(value)); config.setProperty("1", "two"); config.save(); props = new Properties(); in = new FileInputStream(tempFile); props.load(in); String value2 = props.getProperty("1"); assertTrue("two".equals(value2)); } finally { if (out != null) { try { out.close(); } catch (IOException ioex) { ioex.printStackTrace(); } } if (in != null) { try { in.close(); } catch (IOException ioex) { ioex.printStackTrace(); } } } } /** * Tests setting a file changed reloading strategy together with the auto * save feature. */ @Test public void testReloadingWithAutoSave() throws Exception { File configFile = folder.newFile(); PrintWriter out = null; try { out = new PrintWriter(new FileWriter(configFile)); out.println("a = one"); out.close(); out = null; PropertiesConfiguration config = new PropertiesConfiguration( configFile); config.setReloadingStrategy(new FileChangedReloadingStrategy()); config.setAutoSave(true); assertEquals("one", config.getProperty("a")); config.setProperty("b", "two"); assertEquals("one", config.getProperty("a")); } finally { if (out != null) { out.close(); } } } /** * Tests loading and saving a configuration file with a complicated path * name including spaces. (related to issue 35210) */ @Test public void testPathWithSpaces() throws Exception { File path = folder.newFolder("path with spaces"); File confFile = new File(path, "config-test.properties"); PrintWriter out = null; try { out = new PrintWriter(new FileWriter(confFile)); out.println("saved = false"); out.close(); out = null; URL url = confFile.toURI().toURL(); PropertiesConfiguration config = new PropertiesConfiguration(url); config.load(); assertFalse(config.getBoolean("saved")); config.setProperty("saved", Boolean.TRUE); config.save(); config = new PropertiesConfiguration(); config.setFile(confFile); config.load(); assertTrue(config.getBoolean("saved")); } finally { if (out != null) { out.close(); } } } /** * Tests whether file names containing a "+" character are handled * correctly. This test is related to CONFIGURATION-415. */ @Test public void testPathWithPlus() throws ConfigurationException, IOException { File saveFile = folder.newFile("test+config.properties"); FileConfiguration config = new PropertiesConfiguration(saveFile); config.addProperty("test", Boolean.TRUE); config.save(); File configFile = config.getFile(); assertEquals("Wrong configuration file", saveFile, configFile); } /** * Tests the getFile() method. */ @Test public void testGetFile() throws ConfigurationException { FileConfiguration config = new PropertiesConfiguration(); assertNull(config.getFile()); File file = TEST_FILE.getAbsoluteFile(); config.setFile(file); assertEquals(file, config.getFile()); config.load(); assertEquals(file, config.getFile()); } /** * Tests whether getFile() returns a valid file after a configuration has * been loaded. */ @Test public void testGetFileAfterLoad() throws ConfigurationException, IOException { FileConfiguration config = new PropertiesConfiguration(); config.load(TEST_FILE.getAbsolutePath()); assertNotNull("No source URL set", config.getURL()); assertEquals("Wrong source file", TEST_FILE.getCanonicalFile(), config .getFile().getCanonicalFile()); } /** * Tests whether calling load() multiple times changes the source. This * should not be the case. */ @Test public void testLoadMultiple() throws ConfigurationException { FileConfiguration config = new PropertiesConfiguration(); config.load(TEST_FILE.getAbsolutePath()); URL srcUrl = config.getURL(); File srcFile = config.getFile(); File file2 = ConfigurationAssert.getTestFile("testEqual.properties"); config.load(file2.getAbsolutePath()); assertEquals("Source URL was changed", srcUrl, config.getURL()); assertEquals("Source file was changed", srcFile, config.getFile()); } @Test(expected = ConfigurationException.class) public void testSaveWithoutFileNameFile() throws Exception { FileConfiguration config = new PropertiesConfiguration(); config.load(TEST_FILE); config.save(); } @Test(expected = ConfigurationException.class) public void testSaveWithoutFileNameURL() throws Exception { FileConfiguration config = new PropertiesConfiguration(); config.load(TEST_FILE.toURI().toURL()); config.save(); } /** * Checks that loading a directory instead of a file throws an exception. */ @Test(expected = ConfigurationException.class) public void testLoadDirectoryString() throws ConfigurationException { PropertiesConfiguration config = new PropertiesConfiguration(); config.load("target"); } /** * Tests that it is not possible to load a directory using the load() method * which expects a File. */ @Test(expected = ConfigurationException.class) public void testLoadDirectoryFile() throws ConfigurationException { PropertiesConfiguration config = new PropertiesConfiguration(); config.load(new File("target")); } /** * Tests that it is not possible to load a directory using the String constructor. */ @Test(expected = ConfigurationException.class) public void testLoadDirectoryConstrString() throws ConfigurationException { new PropertiesConfiguration("target"); } /** * Tests that it is not possible to load a directory using the File constructor. */ @Test(expected = ConfigurationException.class) public void testLoadDirectoryConstrFile() throws ConfigurationException { new PropertiesConfiguration(new File("target")); } /** * Tests whether the constructor behaves the same as setFileName() when the * configuration source is in the classpath. */ @Test public void testInitFromClassPath() throws ConfigurationException { PropertiesConfiguration config1 = new PropertiesConfiguration(); config1.setFileName(RESOURCE_NAME); config1.load(); PropertiesConfiguration config2 = new PropertiesConfiguration( RESOURCE_NAME); compare(config1, config2); } /** * Tests the loading of configuration file in a Combined configuration * when the configuration source is in the classpath. */ @Test public void testLoadFromClassPath() throws ConfigurationException { DefaultConfigurationBuilder cf = new DefaultConfigurationBuilder("config/deep/testFileFromClasspath.xml"); CombinedConfiguration config = cf.getConfiguration(true); Configuration config1 = config.getConfiguration("propConf"); Configuration config2 = config.getConfiguration("propConfDeep"); compare(config1, config2); } /** * Tests cloning a file based configuration. */ @Test public void testClone() throws ConfigurationException { PropertiesConfiguration config = new PropertiesConfiguration( RESOURCE_NAME); PropertiesConfiguration copy = (PropertiesConfiguration) config.clone(); compare(config, copy); assertNull("URL was not reset", copy.getURL()); assertNull("Base path was not reset", copy.getBasePath()); assertNull("File name was not reset", copy.getFileName()); assertNotSame("Reloading strategy was not reset", config .getReloadingStrategy(), copy.getReloadingStrategy()); } /** * Tests whether an error log listener was registered at the configuration. */ @Test public void testLogErrorListener() { PropertiesConfiguration config = new PropertiesConfiguration(); assertEquals("No error log listener registered", 1, config .getErrorListeners().size()); } /** * Tests handling of errors in the reload() method. */ @Test public void testReloadError() throws ConfigurationException { ConfigurationErrorListenerImpl l = new ConfigurationErrorListenerImpl(); PropertiesConfiguration config = new PropertiesConfiguration( RESOURCE_NAME); config.clearErrorListeners(); config.addErrorListener(l); config.setReloadingStrategy(new FileAlwaysReloadingStrategy()); config.getString("test"); config.setFileName("Not existing file"); config.getString("test"); l.verify(AbstractFileConfiguration.EVENT_RELOAD, null, null); assertNotNull("Exception is not set", l.getLastEvent().getCause()); } /** * Tests iterating over the keys of a non hierarchical file-based * configuration while a reload happens. This test is related to * CONFIGURATION-347. */ @Test public void testIterationWithReloadFlat() throws ConfigurationException { PropertiesConfiguration config = new PropertiesConfiguration(TEST_FILE); checkIterationWithReload(config); } /** * Tests iterating over the keys of a hierarchical file-based configuration * while a reload happens. This test is related to CONFIGURATION-347. */ @Test public void testIterationWithReloadHierarchical() throws ConfigurationException { XMLConfiguration config = new XMLConfiguration("test.xml"); checkIterationWithReload(config); } /** * Tests whether a configuration can be refreshed. */ @Test public void testRefresh() throws ConfigurationException { PropertiesConfiguration config = new PropertiesConfiguration(TEST_FILE); assertEquals("Wrong value", 10, config.getInt("test.integer")); config.setProperty("test.integer", new Integer(42)); assertEquals("Wrong value after update", 42, config.getInt("test.integer")); config.refresh(); assertEquals("Wrong value after refresh", 10, config.getInt("test.integer")); } /** * Tests refresh if the configuration is not associated with a file. */ @Test(expected = ConfigurationException.class) public void testRefreshNoFile() throws ConfigurationException { PropertiesConfiguration config = new PropertiesConfiguration(); config.refresh(); } /** * Helper method for testing an iteration over the keys of a file-based * configuration while a reload happens. * * @param config the configuration to test */ private void checkIterationWithReload(FileConfiguration config) { config.setReloadingStrategy(new FileAlwaysReloadingStrategy()); for (Iterator it = config.getKeys(); it.hasNext();) { String key = it.next(); assertNotNull("No value for key " + key, config.getProperty(key)); } } /** * Helper method for comparing the content of two configuration objects. * * @param config1 the first configuration * @param config2 the second configuration */ private void compare(Configuration config1, Configuration config2) { StrictConfigurationComparator cc = new StrictConfigurationComparator(); assertTrue("Configurations are different", cc.compare(config1, config2)); } }././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestHierarchicalConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestHierarchicalConfig100644 127321 12232154104 33572 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.configuration.HierarchicalConfiguration.Node; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationKey; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.configuration.tree.DefaultExpressionEngine; import org.apache.commons.configuration.tree.ExpressionEngine; import org.junit.Before; import org.junit.Test; /** * Test class for HierarchicalConfiguration. * * @version $Id: TestHierarchicalConfiguration.java 1231749 2012-01-15 20:48:56Z oheger $ */ public class TestHierarchicalConfiguration { private static String[] tables = { "users", "documents" }; private static String[][] fields = { { "uid", "uname", "firstName", "lastName", "email" }, { "docid", "name", "creationDate", "authorID", "version" } }; private HierarchicalConfiguration config; @Before public void setUp() throws Exception { /** * Initialize the configuration with the following structure: * * tables * table * name * fields * field * name * field * name */ config = new HierarchicalConfiguration(); HierarchicalConfiguration.Node nodeTables = createNode("tables", null); for(int i = 0; i < tables.length; i++) { HierarchicalConfiguration.Node nodeTable = createNode("table", null); nodeTables.addChild(nodeTable); HierarchicalConfiguration.Node nodeName = createNode("name", tables[i]); nodeTable.addChild(nodeName); HierarchicalConfiguration.Node nodeFields = createNode("fields", null); nodeTable.addChild(nodeFields); for (int j = 0; j < fields[i].length; j++) { nodeFields.addChild(createFieldNode(fields[i][j])); } } config.getRoot().addChild(nodeTables); } @Test public void testSetRoot() { config.setRoot(new HierarchicalConfiguration.Node("test")); assertTrue(config.isEmpty()); } @Test(expected = IllegalArgumentException.class) public void testSetRootNull() { config.setRoot(null); } @Test public void testSetRootNode() { config.setRootNode(new DefaultConfigurationNode("testNode")); assertNotSame("Same root node", config.getRootNode(), config.getRoot()); assertEquals("Wrong name of root node", "testNode", config.getRoot().getName()); config.setRootNode(new HierarchicalConfiguration.Node("test")); assertSame("Wrong root node", config.getRootNode(), config.getRoot()); } @Test(expected = IllegalArgumentException.class) public void testSetRootNodeNull() { config.setRootNode(null); } @Test public void testIsEmpty() { assertFalse(config.isEmpty()); HierarchicalConfiguration conf2 = new HierarchicalConfiguration(); assertTrue(conf2.isEmpty()); HierarchicalConfiguration.Node child1 = new HierarchicalConfiguration.Node("child1"); HierarchicalConfiguration.Node child2 = new HierarchicalConfiguration.Node("child2"); child1.addChild(child2); conf2.getRoot().addChild(child1); assertTrue(conf2.isEmpty()); } @Test public void testGetProperty() { assertNull(config.getProperty("tables.table.resultset")); assertNull(config.getProperty("tables.table.fields.field")); Object prop = config.getProperty("tables.table(0).fields.field.name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(5, ((Collection) prop).size()); prop = config.getProperty("tables.table.fields.field.name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(10, ((Collection) prop).size()); prop = config.getProperty("tables.table.fields.field(3).name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(2, ((Collection) prop).size()); prop = config.getProperty("tables.table(1).fields.field(2).name"); assertNotNull(prop); assertEquals("creationDate", prop.toString()); } @Test public void testSetProperty() { config.setProperty("tables.table(0).name", "resources"); assertEquals("resources", config.getString("tables.table(0).name")); config.setProperty("tables.table.name", "tab1,tab2"); assertEquals("tab1", config.getString("tables.table(0).name")); assertEquals("tab2", config.getString("tables.table(1).name")); config.setProperty("test.items.item", new int[] { 2, 4, 8, 16 }); assertEquals(3, config.getMaxIndex("test.items.item")); assertEquals(8, config.getInt("test.items.item(2)")); config.setProperty("test.items.item(2)", new Integer(6)); assertEquals(6, config.getInt("test.items.item(2)")); config.setProperty("test.items.item(2)", new int[] { 7, 9, 11 }); assertEquals(5, config.getMaxIndex("test.items.item")); config.setProperty("test", Boolean.TRUE); config.setProperty("test.items", "01/01/05"); assertEquals(5, config.getMaxIndex("test.items.item")); assertTrue(config.getBoolean("test")); assertEquals("01/01/05", config.getProperty("test.items")); config.setProperty("test.items.item", new Integer(42)); assertEquals(0, config.getMaxIndex("test.items.item")); assertEquals(42, config.getInt("test.items.item")); } @Test public void testClear() { config.setProperty(null, "value"); config.addProperty("[@attr]", "defined"); config.clear(); assertTrue("Configuration not empty", config.isEmpty()); } @Test public void testClearProperty() { config.clearProperty("tables.table(0).fields.field(0).name"); assertEquals("uname", config.getProperty("tables.table(0).fields.field(0).name")); config.clearProperty("tables.table(0).name"); assertFalse(config.containsKey("tables.table(0).name")); assertEquals("firstName", config.getProperty("tables.table(0).fields.field(1).name")); assertEquals("documents", config.getProperty("tables.table.name")); config.clearProperty("tables.table"); assertEquals("documents", config.getProperty("tables.table.name")); config.addProperty("test", "first"); config.addProperty("test.level", "second"); config.clearProperty("test"); assertEquals("second", config.getString("test.level")); assertFalse(config.containsKey("test")); } @Test public void testClearTree() { Object prop = config.getProperty("tables.table(0).fields.field.name"); assertNotNull(prop); config.clearTree("tables.table(0).fields.field(3)"); prop = config.getProperty("tables.table(0).fields.field.name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(4, ((Collection) prop).size()); config.clearTree("tables.table(0).fields"); assertNull(config.getProperty("tables.table(0).fields.field.name")); prop = config.getProperty("tables.table.fields.field.name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(5, ((Collection) prop).size()); config.clearTree("tables.table(1)"); assertNull(config.getProperty("tables.table.fields.field.name")); } /** * Tests removing more complex node structures. */ @Test public void testClearTreeComplex() { final int count = 5; // create the structure for (int idx = 0; idx < count; idx++) { config.addProperty("indexList.index(-1)[@default]", Boolean.FALSE); config.addProperty("indexList.index[@name]", "test" + idx); config.addProperty("indexList.index.dir", "testDir" + idx); } assertEquals("Wrong number of nodes", count - 1, config .getMaxIndex("indexList.index[@name]")); // Remove a sub tree boolean found = false; for (int idx = 0; true; idx++) { String name = config.getString("indexList.index(" + idx + ")[@name]"); if (name == null) { break; } if ("test3".equals(name)) { assertEquals("Wrong dir", "testDir3", config .getString("indexList.index(" + idx + ").dir")); config.clearTree("indexList.index(" + idx + ")"); found = true; } } assertTrue("Key to remove not found", found); assertEquals("Wrong number of nodes after remove", count - 2, config .getMaxIndex("indexList.index[@name]")); assertEquals("Wrong number of dir nodes after remove", count - 2, config.getMaxIndex("indexList.index.dir")); // Verify for (int idx = 0; true; idx++) { String name = config.getString("indexList.index(" + idx + ")[@name]"); if (name == null) { break; } if ("test3".equals(name)) { fail("Key was not removed!"); } } } /** * Tests the clearTree() method on a hierarchical structure of nodes. This * is a test case for CONFIGURATION-293. */ @Test public void testClearTreeHierarchy() { config.addProperty("a.b.c", "c"); config.addProperty("a.b.c.d", "d"); config.addProperty("a.b.c.d.e", "e"); config.clearTree("a.b.c"); assertFalse("Property not removed", config.containsKey("a.b.c")); assertFalse("Sub property not removed", config.containsKey("a.b.c.d")); } @Test public void testContainsKey() { assertTrue(config.containsKey("tables.table(0).name")); assertTrue(config.containsKey("tables.table(1).name")); assertFalse(config.containsKey("tables.table(2).name")); assertTrue(config.containsKey("tables.table(0).fields.field.name")); assertFalse(config.containsKey("tables.table(0).fields.field")); config.clearTree("tables.table(0).fields"); assertFalse(config.containsKey("tables.table(0).fields.field.name")); assertTrue(config.containsKey("tables.table.fields.field.name")); } @Test public void testGetKeys() { List keys = new ArrayList(); for (Iterator it = config.getKeys(); it.hasNext();) { keys.add(it.next()); } assertEquals(2, keys.size()); assertTrue(keys.contains("tables.table.name")); assertTrue(keys.contains("tables.table.fields.field.name")); // test the order of the keys returned config.addProperty("order.key1", "value1"); config.addProperty("order.key2", "value2"); config.addProperty("order.key3", "value3"); Iterator it = config.getKeys("order"); assertEquals("1st key", "order.key1", it.next()); assertEquals("2nd key", "order.key2", it.next()); assertEquals("3rd key", "order.key3", it.next()); } @Test public void testGetKeysString() { // add some more properties to make it more interesting config.addProperty("tables.table(0).fields.field(1).type", "VARCHAR"); config.addProperty("tables.table(0)[@type]", "system"); config.addProperty("tables.table(0).size", "42"); config.addProperty("tables.table(0).fields.field(0).size", "128"); config.addProperty("connections.connection.param.url", "url1"); config.addProperty("connections.connection.param.user", "me"); config.addProperty("connections.connection.param.pwd", "secret"); config.addProperty("connections.connection(-1).param.url", "url2"); config.addProperty("connections.connection(1).param.user", "guest"); checkKeys("tables.table(1)", new String[] { "name", "fields.field.name" }); checkKeys("tables.table(0)", new String[] { "name", "fields.field.name", "tables.table(0)[@type]", "size", "fields.field.type", "fields.field.size" }); checkKeys("connections.connection(0).param", new String[] {"url", "user", "pwd" }); checkKeys("connections.connection(1).param", new String[] {"url", "user" }); } /** * Tests getKeys() with a prefix when the prefix matches exactly a key. */ @Test public void testGetKeysWithKeyAsPrefix() { config.addProperty("order.key1", "value1"); config.addProperty("order.key2", "value2"); Iterator it = config.getKeys("order.key1"); assertTrue("no key found", it.hasNext()); assertEquals("1st key", "order.key1", it.next()); assertFalse("more keys than expected", it.hasNext()); } /** * Tests getKeys() with a prefix when the prefix matches exactly a key, and * there are multiple keys starting with this prefix. */ @Test public void testGetKeysWithKeyAsPrefixMultiple() { config.addProperty("order.key1", "value1"); config.addProperty("order.key1.test", "value2"); config.addProperty("order.key1.test.complex", "value2"); Iterator it = config.getKeys("order.key1"); assertEquals("Wrong key 1", "order.key1", it.next()); assertEquals("Wrong key 2", "order.key1.test", it.next()); assertEquals("Wrong key 3", "order.key1.test.complex", it.next()); assertFalse("More keys than expected", it.hasNext()); } @Test public void testAddProperty() { config.addProperty("tables.table(0).fields.field(-1).name", "phone"); Object prop = config.getProperty("tables.table(0).fields.field.name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(6, ((Collection) prop).size()); config.addProperty("tables.table(0).fields.field.name", "fax"); prop = config.getProperty("tables.table.fields.field(5).name"); assertNotNull(prop); assertTrue(prop instanceof List); List list = (List) prop; assertEquals("phone", list.get(0)); assertEquals("fax", list.get(1)); config.addProperty("tables.table(-1).name", "config"); prop = config.getProperty("tables.table.name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(3, ((Collection) prop).size()); config.addProperty("tables.table(2).fields.field(0).name", "cid"); config.addProperty("tables.table(2).fields.field(-1).name", "confName"); prop = config.getProperty("tables.table(2).fields.field.name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(2, ((Collection) prop).size()); assertEquals("confName", config.getProperty("tables.table(2).fields.field(1).name")); config.addProperty("connection.user", "scott"); config.addProperty("connection.passwd", "tiger"); assertEquals("tiger", config.getProperty("connection.passwd")); DefaultConfigurationKey key = createConfigurationKey(); key.append("tables").append("table").appendIndex(0); key.appendAttribute("tableType"); config.addProperty(key.toString(), "system"); assertEquals("system", config.getProperty(key.toString())); } /** * Creates a {@code DefaultConfigurationKey} object. * * @return the new key object */ private static DefaultConfigurationKey createConfigurationKey() { return new DefaultConfigurationKey(new DefaultExpressionEngine()); } @Test(expected = IllegalArgumentException.class) public void testAddPropertyInvalidKey() { config.addProperty(".", "InvalidKey"); } @Test public void testGetMaxIndex() { assertEquals(4, config.getMaxIndex("tables.table(0).fields.field")); assertEquals(4, config.getMaxIndex("tables.table(1).fields.field")); assertEquals(1, config.getMaxIndex("tables.table")); assertEquals(1, config.getMaxIndex("tables.table.name")); assertEquals(0, config.getMaxIndex("tables.table(0).name")); assertEquals(0, config.getMaxIndex("tables.table(1).fields.field(1)")); assertEquals(-1, config.getMaxIndex("tables.table(2).fields")); int maxIdx = config.getMaxIndex("tables.table(0).fields.field.name"); for(int i = 0; i <= maxIdx; i++) { DefaultConfigurationKey key = new DefaultConfigurationKey(new DefaultExpressionEngine(), "tables.table(0).fields"); key.append("field").appendIndex(i).append("name"); assertNotNull(config.getProperty(key.toString())); } } @Test public void testSubset() { // test the subset on the first table Configuration subset = config.subset("tables.table(0)"); assertEquals(tables[0], subset.getProperty("name")); Object prop = subset.getProperty("fields.field.name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(5, ((Collection) prop).size()); for (int i = 0; i < fields[0].length; i++) { DefaultConfigurationKey key = createConfigurationKey(); key.append("fields").append("field").appendIndex(i); key.append("name"); assertEquals(fields[0][i], subset.getProperty(key.toString())); } // test the subset on the second table assertTrue("subset is not empty", config.subset("tables.table(2)").isEmpty()); // test the subset on the fields subset = config.subset("tables.table.fields.field"); prop = subset.getProperty("name"); assertTrue("prop is not a collection", prop instanceof Collection); assertEquals(10, ((Collection) prop).size()); assertEquals(fields[0][0], subset.getProperty("name(0)")); // test the subset on the field names subset = config.subset("tables.table.fields.field.name"); assertTrue("subset is not empty", subset.isEmpty()); } /** * Tests the subset() method when the specified node has a value. This value * must be available in the subset, too. Related to CONFIGURATION-295. */ @Test public void testSubsetNodeWithValue() { config.setProperty("tables.table(0).fields", "My fields"); Configuration subset = config.subset("tables.table(0).fields"); assertEquals("Wrong field name", fields[0][0], subset .getString("field(0).name")); assertEquals("Wrong value of root", "My fields", subset.getString("")); } /** * Tests the subset() method when the specified key selects multiple keys. * The resulting root node should have a value only if exactly one of the * selected nodes has a value. Related to CONFIGURATION-295. */ @Test public void testSubsetMultipleNodesWithValues() { config.setProperty("tables.table(0).fields", "My fields"); Configuration subset = config.subset("tables.table.fields"); assertEquals("Wrong value of root", "My fields", subset.getString("")); config.setProperty("tables.table(1).fields", "My other fields"); subset = config.subset("tables.table.fields"); assertNull("Root value is not null though there are multiple values", subset.getString("")); } /** * Tests the configurationAt() method to obtain a configuration for a sub * tree. */ @Test public void testConfigurationAt() { HierarchicalConfiguration subConfig = config .configurationAt("tables.table(1)"); assertEquals("Wrong table name", tables[1], subConfig.getString("name")); List lstFlds = subConfig.getList("fields.field.name"); assertEquals("Wrong number of fields", fields[1].length, lstFlds.size()); for (int i = 0; i < fields[1].length; i++) { assertEquals("Wrong field at position " + i, fields[1][i], lstFlds .get(i)); } subConfig.setProperty("name", "testTable"); assertEquals("Change not visible in parent", "testTable", config .getString("tables.table(1).name")); config.setProperty("tables.table(1).fields.field(2).name", "testField"); assertEquals("Change not visible in sub config", "testField", subConfig .getString("fields.field(2).name")); } /** * Tests the configurationAt() method when the passed in key does not exist. */ @Test(expected = IllegalArgumentException.class) public void testConfigurationAtUnknownSubTree() { config.configurationAt("non.existing.key"); } /** * Tests the configurationAt() method when the passed in key selects * multiple nodes. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testConfigurationAtMultipleNodes() { config.configurationAt("tables.table.name"); } /** * Tests whether a sub configuration obtained by configurationAt() can be * cleared. */ @Test public void testConfigurationAtClear() { config.addProperty("test.sub.test", "fail"); assertEquals("Wrong index (1)", 0, config.getMaxIndex("test")); SubnodeConfiguration sub = config.configurationAt("test.sub"); assertEquals("Wrong value", "fail", sub.getString("test")); sub.clear(); assertNull("Key still found", config.getString("test.sub.key")); sub.setProperty("test", "success"); assertEquals("Property not set", "success", config.getString("test.sub.test")); assertEquals("Wrong index (2)", 0, config.getMaxIndex("test")); } /** * Tests the configurationsAt() method. */ @Test public void testConfigurationsAt() { List lstFlds = config.configurationsAt("tables.table(1).fields.field"); assertEquals("Wrong size of fields", fields[1].length, lstFlds.size()); for (int i = 0; i < fields[1].length; i++) { HierarchicalConfiguration sub = lstFlds.get(i); assertEquals("Wrong field at position " + i, fields[1][i], sub .getString("name")); } } /** * Tests the configurationsAt() method when the passed in key does not * select any sub nodes. */ @Test public void testConfigurationsAtEmpty() { assertTrue("List is not empty", config.configurationsAt("unknown.key") .isEmpty()); } @Test public void testClone() { Configuration copy = (Configuration) config.clone(); assertTrue(copy instanceof HierarchicalConfiguration); checkContent(copy); } /** * Tests whether registered event handlers are handled correctly when a * configuration is cloned. They should not be registered at the clone. */ @Test public void testCloneWithEventListeners() { config.addConfigurationListener(new ConfigurationListener() { public void configurationChanged(ConfigurationEvent event) { // just a dummy } }); HierarchicalConfiguration copy = (HierarchicalConfiguration) config .clone(); assertTrue("Event listener registered at clone", copy .getConfigurationListeners().isEmpty()); } @Test public void testAddNodes() { Collection nodes = new ArrayList(); nodes.add(createFieldNode("birthDate")); nodes.add(createFieldNode("lastLogin")); nodes.add(createFieldNode("language")); config.addNodes("tables.table(0).fields", nodes); assertEquals(7, config.getMaxIndex("tables.table(0).fields.field")); assertEquals("birthDate", config.getString("tables.table(0).fields.field(5).name")); assertEquals("lastLogin", config.getString("tables.table(0).fields.field(6).name")); assertEquals("language", config.getString("tables.table(0).fields.field(7).name")); } /** * Tests the addNodes() method when the provided key does not exist. In * this case, a new node (or even a complete new branch) will be created. */ @Test public void testAddNodesForNonExistingKey() { Collection nodes = new ArrayList(); nodes.add(createNode("usr", "scott")); Node nd = createNode("pwd", "tiger"); nd.setAttribute(true); nodes.add(nd); config.addNodes("database.connection.settings", nodes); assertEquals("Usr node not found", "scott", config.getString("database.connection.settings.usr")); assertEquals("Pwd node not found", "tiger", config.getString("database.connection.settings[@pwd]")); } /** * Tests the addNodes() method when the new nodes should be added to an * attribute node. This is not allowed. */ @Test(expected = IllegalArgumentException.class) public void testAddNodesWithAttributeKey() { Collection nodes = new ArrayList(); nodes.add(createNode("testNode", "yes")); config.addNodes("database.connection[@settings]", nodes); } /** * Tests copying nodes from one configuration to another one. */ @Test public void testAddNodesCopy() { HierarchicalConfiguration configDest = new HierarchicalConfiguration(); configDest.addProperty("test", "TEST"); Collection nodes = config.getRootNode().getChildren(); assertEquals("Wrong number of children", 1, nodes.size()); configDest.addNodes("newNodes", nodes); for (int i = 0; i < tables.length; i++) { String keyTab = "newNodes.tables.table(" + i + ")."; assertEquals("Table " + i + " not found", tables[i], configDest .getString(keyTab + "name")); for (int j = 0; j < fields[i].length; j++) { assertEquals("Invalid field " + j + " in table " + i, fields[i][j], configDest.getString(keyTab + "fields.field(" + j + ").name")); } } } /** * Tests adding an attribute node with the addNodes() method. */ @Test public void testAddNodesAttributeNode() { Collection nodes = new ArrayList(); ConfigurationNode nd = createNode("length", "10"); nd.setAttribute(true); nodes.add(nd); config.addNodes("tables.table(0).fields.field(1)", nodes); assertEquals("Attribute was not added", "10", config .getString("tables.table(0).fields.field(1)[@length]")); } /** * Tests removing children from a configuration node. */ @Test public void testNodeRemove() { HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node( "parent", "test"); assertFalse(node.hasChildren()); node.removeChildren(); // should have no effect assertFalse(node.remove("child")); node.addChild(createNode("test", "test")); assertTrue(node.hasChildren()); assertTrue(node.remove("test")); assertFalse(node.hasChildren()); for (int i = 0; i < 10; i++) { node.addChild(createNode("child" + i, "test" + i)); } assertTrue(node.hasChildren()); assertFalse(node.remove("child")); assertTrue(node.remove("child2")); assertTrue(node.getChildren("child2").isEmpty()); HierarchicalConfiguration.Node child = createNode("child0", "testChild"); assertFalse(node.remove(child)); node.addChild(child); assertTrue(node.remove(child)); assertEquals(1, node.getChildren("child0").size()); assertEquals("test0", ((HierarchicalConfiguration.Node) node .getChildren("child0").get(0)).getValue()); assertTrue(node.remove("child0")); assertFalse(node.remove(child)); node.removeChildren(); assertTrue(node.getChildren().isEmpty()); assertFalse(node.remove(child)); } /** * Tests the visitor mechanism. */ @Test public void testNodeVisitor() { CountVisitor v = new CountVisitor(); config.getRoot().visit(v, null); assertEquals("Wrong number of visits", 28, v.beforeCount); assertEquals("Different number of before and after visits", v.beforeCount, v.afterCount); } /** * Tests the visitor mechanism if a ConfigurationKey is passed in. */ @Test public void testNodeVisitorKeys() { CountVisitor v = new CountVisitor(); @SuppressWarnings("deprecation") ConfigurationKey configKey = new ConfigurationKey(); config.getRoot().visit(v, configKey); for (Iterator it = config.getKeys(); it.hasNext();) { String key = it.next(); assertTrue("Key not found in before keys: " + key, v.beforeKeys .contains(key)); assertTrue("Key not found in after keys: " + key, v.afterKeys .contains(key)); } } /** * Tests setting a custom expression engine, which uses a slightly different * syntax. */ @Test public void testSetExpressionEngine() { config.setExpressionEngine(null); assertNotNull("Expression engine is null", config.getExpressionEngine()); assertSame("Default engine is not used", HierarchicalConfiguration .getDefaultExpressionEngine(), config.getExpressionEngine()); config.setExpressionEngine(createAlternativeExpressionEngine()); checkAlternativeSyntax(); } /** * Tests setting the default expression engine. This should impact all * configuration instances that do not have their own engine. */ @Test public void testSetDefaultExpressionEngine() { ExpressionEngine engineOld = HierarchicalConfiguration.getDefaultExpressionEngine(); HierarchicalConfiguration .setDefaultExpressionEngine(createAlternativeExpressionEngine()); checkAlternativeSyntax(); HierarchicalConfiguration.setDefaultExpressionEngine(engineOld); } /** * Tests setting the default expression engine to null. This should not be * allowed. */ @Test(expected = IllegalArgumentException.class) public void testSetDefaultExpressionEngineNull() { HierarchicalConfiguration.setDefaultExpressionEngine(null); } /** * Tests the copy constructor. */ @Test public void testInitCopy() { HierarchicalConfiguration copy = new HierarchicalConfiguration(config); checkContent(copy); } /** * Tests whether the nodes of a copied configuration are independent from * the source configuration. */ @Test public void testInitCopyUpdate() { HierarchicalConfiguration copy = new HierarchicalConfiguration(config); config.setProperty("tables.table(0).name", "NewTable"); checkContent(copy); } /** * Tests interpolation facilities. */ @Test public void testInterpolation() { config.addProperty("base.dir", "/home/foo"); config.addProperty("test.absolute.dir.dir1", "${base.dir}/path1"); config.addProperty("test.absolute.dir.dir2", "${base.dir}/path2"); config.addProperty("test.absolute.dir.dir3", "${base.dir}/path3"); Configuration sub = config.subset("test.absolute.dir"); for (int i = 1; i < 4; i++) { assertEquals("Wrong interpolation in parent", "/home/foo/path" + i, config.getString("test.absolute.dir.dir" + i)); assertEquals("Wrong interpolation in subnode", "/home/foo/path" + i, sub.getString("dir" + i)); } } /** * Basic interpolation tests. */ @Test public void testInterpolationBasic() { InterpolationTestHelper.testInterpolation(config); } /** * Tests multiple levels of interpolation. */ @Test public void testInterpolationMultipleLevels() { InterpolationTestHelper.testMultipleInterpolation(config); } /** * Tests an invalid interpolation that causes an endless loop. */ @Test public void testInterpolationLoop() { InterpolationTestHelper.testInterpolationLoop(config); } /** * Tests interpolation with a subset. */ @Test public void testInterpolationSubset() { InterpolationTestHelper.testInterpolationSubset(config); } /** * Tests whether interpolation with a subset configuration works over * multiple layers. */ @Test public void testInterpolationSubsetMultipleLayers() { config.clear(); config.addProperty("var", "value"); config.addProperty("prop2.prop[@attr]", "${var}"); Configuration sub1 = config.subset("prop2"); Configuration sub2 = sub1.subset("prop"); assertEquals("Wrong value", "value", sub2.getString("[@attr]")); } /** * Tests interpolation of a variable, which cannot be resolved. */ @Test public void testInterpolationUnknownProperty() { InterpolationTestHelper.testInterpolationUnknownProperty(config); } /** * Tests interpolation with system properties. */ @Test public void testInterpolationSysProperties() { InterpolationTestHelper.testInterpolationSystemProperties(config); } /** * Tests interpolation with constant values. */ @Test public void testInterpolationConstants() { InterpolationTestHelper.testInterpolationConstants(config); } /** * Tests escaping variables. */ @Test public void testInterpolationEscaped() { InterpolationTestHelper.testInterpolationEscaped(config); } /** * Tests manipulating the interpolator. */ @Test public void testInterpolator() { InterpolationTestHelper.testGetInterpolator(config); } /** * Tests obtaining a configuration with all variables substituted. */ @Test public void testInterpolatedConfiguration() { HierarchicalConfiguration c = (HierarchicalConfiguration) InterpolationTestHelper .testInterpolatedConfiguration(config); // tests whether the hierarchical structure has been maintained config = c; testGetProperty(); } /** * Tests the copy constructor when a null reference is passed. */ @Test public void testInitCopyNull() { HierarchicalConfiguration copy = new HierarchicalConfiguration(null); assertTrue("Configuration not empty", copy.isEmpty()); } /** * Tests the parents of nodes when setRootNode() is involved. This is * related to CONFIGURATION-334. */ @Test public void testNodeParentsAfterSetRootNode() { DefaultConfigurationNode root = new DefaultConfigurationNode(); DefaultConfigurationNode child1 = new DefaultConfigurationNode( "child1", "test1"); root.addChild(child1); config.setRootNode(root); config.addProperty("child2", "test2"); List nodes = config.getExpressionEngine().query(config.getRootNode(), "child2"); assertEquals("Wrong number of result nodes", 1, nodes.size()); ConfigurationNode child2 = nodes.get(0); assertEquals("Different parent nodes", child1.getParentNode(), child2 .getParentNode()); } /** * Tests calling getRoot() after a root node was set using setRootNode() and * further child nodes have been added. The newly add child nodes should be * present in the root node returned. */ @Test public void testGetRootAfterSetRootNode() { DefaultConfigurationNode root = new DefaultConfigurationNode(); DefaultConfigurationNode child1 = new DefaultConfigurationNode( "child1", "test1"); root.addChild(child1); config.setRootNode(root); config.addProperty("child2", "test2"); ConfigurationNode oldRoot = config.getRoot(); assertEquals("Wrong number of children", 2, oldRoot.getChildrenCount()); } /** * Tests whether keys that contains brackets can be used. */ @Test public void testGetPropertyKeyWithBrackets() { final String key = "test.directory.platform(x86)"; config.addProperty(key, "C:\\Temp"); assertEquals("Wrong property value", "C:\\Temp", config.getString(key)); } /** * Helper method for testing the getKeys(String) method. * * @param prefix the key to pass into getKeys() * @param expected the expected result */ private void checkKeys(String prefix, String[] expected) { Set values = new HashSet(); for(int i = 0; i < expected.length; i++) { values.add((expected[i].startsWith(prefix)) ? expected[i] : prefix + "." + expected[i]); } Iterator itKeys = config.getKeys(prefix); while(itKeys.hasNext()) { String key = itKeys.next(); if(!values.contains(key)) { fail("Found unexpected key: " + key); } else { values.remove(key); } } assertTrue("Remaining keys " + values, values.isEmpty()); } /** * Helper method for checking keys using an alternative syntax. */ private void checkAlternativeSyntax() { assertNull(config.getProperty("tables/table/resultset")); assertNull(config.getProperty("tables/table/fields/field")); Object prop = config.getProperty("tables/table[0]/fields/field/name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(5, ((Collection) prop).size()); prop = config.getProperty("tables/table/fields/field/name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(10, ((Collection) prop).size()); prop = config.getProperty("tables/table/fields/field[3]/name"); assertNotNull(prop); assertTrue(prop instanceof Collection); assertEquals(2, ((Collection) prop).size()); prop = config.getProperty("tables/table[1]/fields/field[2]/name"); assertNotNull(prop); assertEquals("creationDate", prop.toString()); Set keys = new HashSet(); CollectionUtils.addAll(keys, config.getKeys()); assertEquals("Wrong number of defined keys", 2, keys.size()); assertTrue("Key not found", keys.contains("tables/table/name")); assertTrue("Key not found", keys .contains("tables/table/fields/field/name")); } /** * Checks the content of the passed in configuration object. Used by some * tests that copy a configuration. * * @param c the configuration to check */ private void checkContent(Configuration c) { for (int i = 0; i < tables.length; i++) { assertEquals(tables[i], c.getString("tables.table(" + i + ").name")); for (int j = 0; j < fields[i].length; j++) { assertEquals(fields[i][j], c.getString("tables.table(" + i + ").fields.field(" + j + ").name")); } } } private ExpressionEngine createAlternativeExpressionEngine() { DefaultExpressionEngine engine = new DefaultExpressionEngine(); engine.setPropertyDelimiter("/"); engine.setIndexStart("["); engine.setIndexEnd("]"); return engine; } /** * Helper method for creating a field node with its children. * * @param name the name of the field * @return the field node */ private static HierarchicalConfiguration.Node createFieldNode(String name) { HierarchicalConfiguration.Node fld = createNode("field", null); fld.addChild(createNode("name", name)); return fld; } /** * Helper method for creating a configuration node. * @param name the node's name * @param value the node's value * @return the new node */ private static HierarchicalConfiguration.Node createNode(String name, Object value) { HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node(name); node.setValue(value); return node; } /** * A test visitor implementation for checking whether all visitor methods * are correctly called. */ @SuppressWarnings("deprecation") static class CountVisitor extends HierarchicalConfiguration.NodeVisitor { /** The number of invocations of visitBeforeChildren(). */ int beforeCount; /** The number of invocations of visitAfterChildren(). */ int afterCount; /** A set with the keys passed to visitBeforeChildren(). */ final Set beforeKeys = new HashSet(); /** A set with the keys passed to visitAfterChildren(). */ final Set afterKeys = new HashSet(); @Override public void visitAfterChildren(Node node, ConfigurationKey key) { super.visitAfterChildren(node, key); afterCount++; if (key != null) { afterKeys.add(key.toString()); } } @Override public void visitBeforeChildren(Node node, ConfigurationKey key) { super.visitBeforeChildren(node, key); beforeCount++; if (key != null) { beforeKeys.add(key.toString()); } } } } ././@LongLink100644 0 0 172 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestHierarchicalConfigurationXMLReader.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestHierarchicalConfig100644 5730 12232154104 33531 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMResult; import javax.xml.transform.sax.SAXSource; import org.apache.commons.jxpath.JXPathContext; import org.junit.Before; import org.junit.Test; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.xml.sax.InputSource; /** * Test class for HierarchicalConfigurationXMLReader. * * @version $Id: TestHierarchicalConfigurationXMLReader.java 1224644 2011-12-25 20:34:22Z oheger $ */ public class TestHierarchicalConfigurationXMLReader { private static final String TEST_FILE = ConfigurationAssert.getTestFile( "testHierarchicalXMLConfiguration.xml").getAbsolutePath(); private HierarchicalConfigurationXMLReader parser; @Before public void setUp() throws Exception { XMLConfiguration config = new XMLConfiguration(); config.setFileName(TEST_FILE); config.load(); parser = new HierarchicalConfigurationXMLReader(config); } @Test public void testParse() throws Exception { SAXSource source = new SAXSource(parser, new InputSource()); DOMResult result = new DOMResult(); Transformer trans = TransformerFactory.newInstance().newTransformer(); trans.transform(source, result); Node root = ((Document) result.getNode()).getDocumentElement(); JXPathContext ctx = JXPathContext.newContext(root); assertEquals("Wrong name of root element", "database", root.getNodeName()); assertEquals("Wrong number of children of root", 1, ctx.selectNodes( "/*").size()); assertEquals("Wrong number of tables", 2, ctx.selectNodes( "/tables/table").size()); assertEquals("Wrong name of first table", "users", ctx .getValue("/tables/table[1]/name")); assertEquals("Wrong number of fields in first table", 5, ctx .selectNodes("/tables/table[1]/fields/field").size()); assertEquals("Wrong attribute value", "system", ctx .getValue("/tables/table[1]/@tableType")); } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestHierarchicalINIConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestHierarchicalINICon100644 102421 12232154104 33436 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.junit.After; import org.junit.Test; /** * Test class for HierarchicalINIConfiguration. * * @author Commons * Configuration team * @version $Id: TestHierarchicalINIConfiguration.java 1234362 2012-01-21 16:59:48Z oheger $ */ public class TestHierarchicalINIConfiguration { private static String LINE_SEPARATOR = System.getProperty("line.separator"); /** Constant for the content of an ini file. */ private static final String INI_DATA = "[section1]" + LINE_SEPARATOR + "var1 = foo" + LINE_SEPARATOR + "var2 = 451" + LINE_SEPARATOR + LINE_SEPARATOR + "[section2]" + LINE_SEPARATOR + "var1 = 123.45" + LINE_SEPARATOR + "var2 = bar" + LINE_SEPARATOR + LINE_SEPARATOR + "[section3]" + LINE_SEPARATOR + "var1 = true" + LINE_SEPARATOR + "interpolated = ${section3.var1}" + LINE_SEPARATOR + "multi = foo" + LINE_SEPARATOR + "multi = bar" + LINE_SEPARATOR + LINE_SEPARATOR; private static final String INI_DATA2 = "[section4]" + LINE_SEPARATOR + "var1 = \"quoted value\"" + LINE_SEPARATOR + "var2 = \"quoted value\\nwith \\\"quotes\\\"\"" + LINE_SEPARATOR + "var3 = 123 ; comment" + LINE_SEPARATOR + "var4 = \"1;2;3\" ; comment" + LINE_SEPARATOR + "var5 = '\\'quoted\\' \"value\"' ; comment" + LINE_SEPARATOR + "var6 = \"\"" + LINE_SEPARATOR; private static final String INI_DATA3 = "[section5]" + LINE_SEPARATOR + "multiLine = one \\" + LINE_SEPARATOR + " two \\" + LINE_SEPARATOR + " three" + LINE_SEPARATOR + "singleLine = C:\\Temp\\" + LINE_SEPARATOR + "multiQuoted = one \\" + LINE_SEPARATOR + "\" two \" \\" + LINE_SEPARATOR + " three" + LINE_SEPARATOR + "multiComment = one \\ ; a comment" + LINE_SEPARATOR + "two" + LINE_SEPARATOR + "multiQuotedComment = \" one \" \\ ; comment" + LINE_SEPARATOR + "two" + LINE_SEPARATOR + "noFirstLine = \\" + LINE_SEPARATOR + " line 2" + LINE_SEPARATOR + "continueNoLine = one \\" + LINE_SEPARATOR; private static final String INI_DATA_SEPARATORS = "[section]" + LINE_SEPARATOR + "var1 = value1" + LINE_SEPARATOR + "var2 : value2" + LINE_SEPARATOR + "var3=value3" + LINE_SEPARATOR + "var4:value4" + LINE_SEPARATOR + "var5 : value=5" + LINE_SEPARATOR + "var:6=value" + LINE_SEPARATOR + "var:7=\"value7\"" + LINE_SEPARATOR + "var:8 = \"value8\"" + LINE_SEPARATOR; /** An ini file that contains only a property in the global section. */ private static final String INI_DATA_GLOBAL_ONLY = "globalVar = testGlobal" + LINE_SEPARATOR + LINE_SEPARATOR; /** An ini file with a global section. */ private static final String INI_DATA_GLOBAL = INI_DATA_GLOBAL_ONLY + INI_DATA; /** A test ini file. */ private static final File TEST_FILE = new File("target/test.ini"); @After public void tearDown() throws Exception { if (TEST_FILE.exists()) { assertTrue("Cannot remove test file: " + TEST_FILE, TEST_FILE .delete()); } } /** * Creates a HierarchicalINIConfiguration object that is initialized from * the given data. * * @param data the data of the configuration (an ini file as string) * @return the initialized configuration * @throws ConfigurationException if an error occurs */ private static HierarchicalINIConfiguration setUpConfig(String data) throws ConfigurationException { HierarchicalINIConfiguration instance = new HierarchicalINIConfiguration(); load(instance, data); return instance; } /** * Loads the specified content into the given configuration instance. * * @param instance the configuration * @param data the data to be loaded * @throws ConfigurationException if an error occurs */ private static void load(HierarchicalINIConfiguration instance, String data) throws ConfigurationException { StringReader reader = new StringReader(data); instance.load(reader); reader.close(); } /** * Writes a test ini file. * * @param content the content of the file * @throws IOException if an error occurs */ private static void writeTestFile(String content) throws IOException { PrintWriter out = new PrintWriter(new FileWriter(TEST_FILE)); try { out.println(content); } finally { out.close(); } } /** * Test of save method, of class {@link HierarchicalINIConfiguration}. */ @Test public void testSave() throws Exception { Writer writer = new StringWriter(); HierarchicalINIConfiguration instance = new HierarchicalINIConfiguration(); instance.addProperty("section1.var1", "foo"); instance.addProperty("section1.var2", "451"); instance.addProperty("section2.var1", "123.45"); instance.addProperty("section2.var2", "bar"); instance.addProperty("section3.var1", "true"); instance.addProperty("section3.interpolated", "${section3.var1}"); instance.addProperty("section3.multi", "foo"); instance.addProperty("section3.multi", "bar"); instance.save(writer); assertEquals("Wrong content of ini file", INI_DATA, writer.toString()); } /** * Helper method for testing a save operation. This method constructs a * configuration from the specified content string. Then it saves this * configuration and checks whether the result matches the original content. * * @param content the content of the configuration * @throws ConfigurationException if an error occurs */ private void checkSave(String content) throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(content); StringWriter writer = new StringWriter(); config.save(writer); assertEquals("Wrong content of ini file", content, writer.toString()); } /** * Tests saving a configuration that contains a global section. */ @Test public void testSaveWithGlobalSection() throws ConfigurationException { checkSave(INI_DATA_GLOBAL); } /** * Tests whether a configuration that contains only a global section can be * saved correctly. */ @Test public void testSaveWithOnlyGlobalSection() throws ConfigurationException { checkSave(INI_DATA_GLOBAL_ONLY); } /** * Test of load method, of class {@link HierarchicalINIConfiguration}. */ @Test public void testLoad() throws Exception { checkLoad(INI_DATA); } /** * Tests the load() method when the alternative value separator is used (a * ':' for '='). */ @Test public void testLoadAlternativeSeparator() throws Exception { checkLoad(INI_DATA.replace('=', ':')); } /** * Tests loading a configuration from a File. */ @Test public void testLoadFile() throws ConfigurationException, IOException { writeTestFile(INI_DATA); HierarchicalINIConfiguration config = new HierarchicalINIConfiguration( TEST_FILE); checkContent(config); } /** * Tests loading a configuration from a file name. */ @Test public void testLoadFileName() throws ConfigurationException, IOException { writeTestFile(INI_DATA); HierarchicalINIConfiguration config = new HierarchicalINIConfiguration( TEST_FILE.getAbsolutePath()); checkContent(config); } /** * Tests loading a configuration from a URL. */ @Test public void testLoadURL() throws ConfigurationException, IOException { writeTestFile(INI_DATA); HierarchicalINIConfiguration config = new HierarchicalINIConfiguration( TEST_FILE.toURI().toURL()); checkContent(config); } /** * Tests the values of some properties to ensure that the configuration was * correctly loaded. * * @param instance the configuration to check */ private void checkContent(HierarchicalINIConfiguration instance) { assertTrue(instance.getString("section1.var1").equals("foo")); assertTrue(instance.getInt("section1.var2") == 451); assertTrue(instance.getDouble("section2.var1") == 123.45); assertTrue(instance.getString("section2.var2").equals("bar")); assertTrue(instance.getBoolean("section3.var1")); assertTrue(instance.getSections().size() == 3); } /** * Helper method for testing the load operation. Loads the specified content * into a configuration and then checks some properties. * * @param data the data to load */ private void checkLoad(String data) throws ConfigurationException { HierarchicalINIConfiguration instance = setUpConfig(data); checkContent(instance); } /** * Test of isCommentLine method, of class * {@link HierarchicalINIConfiguration}. */ @Test public void testIsCommentLine() { HierarchicalINIConfiguration instance = new HierarchicalINIConfiguration(); assertTrue(instance.isCommentLine("#comment1")); assertTrue(instance.isCommentLine(";comment1")); assertFalse(instance.isCommentLine("nocomment=true")); assertFalse(instance.isCommentLine(null)); } /** * Test of isSectionLine method, of class * {@link HierarchicalINIConfiguration}. */ @Test public void testIsSectionLine() { HierarchicalINIConfiguration instance = new HierarchicalINIConfiguration(); assertTrue(instance.isSectionLine("[section]")); assertFalse(instance.isSectionLine("nosection=true")); assertFalse(instance.isSectionLine(null)); } /** * Test of getSections method, of class {@link HierarchicalINIConfiguration} * . */ @Test public void testGetSections() { HierarchicalINIConfiguration instance = new HierarchicalINIConfiguration(); instance.addProperty("test1.foo", "bar"); instance.addProperty("test2.foo", "abc"); Set expResult = new HashSet(); expResult.add("test1"); expResult.add("test2"); Set result = instance.getSections(); assertEquals(expResult, result); } @Test public void testQuotedValue() throws Exception { HierarchicalINIConfiguration config = setUpConfig(INI_DATA2); assertEquals("value", "quoted value", config.getString("section4.var1")); } @Test public void testQuotedValueWithQuotes() throws Exception { HierarchicalINIConfiguration config = setUpConfig(INI_DATA2); assertEquals("value", "quoted value\\nwith \"quotes\"", config .getString("section4.var2")); } @Test public void testValueWithComment() throws Exception { HierarchicalINIConfiguration config = setUpConfig(INI_DATA2); assertEquals("value", "123", config.getString("section4.var3")); } @Test public void testQuotedValueWithComment() throws Exception { HierarchicalINIConfiguration config = setUpConfig(INI_DATA2); assertEquals("value", "1;2;3", config.getString("section4.var4")); } @Test public void testQuotedValueWithSingleQuotes() throws Exception { HierarchicalINIConfiguration config = setUpConfig(INI_DATA2); assertEquals("value", "'quoted' \"value\"", config .getString("section4.var5")); } @Test public void testWriteValueWithCommentChar() throws Exception { HierarchicalINIConfiguration config = new HierarchicalINIConfiguration(); config.setProperty("section.key1", "1;2;3"); StringWriter writer = new StringWriter(); config.save(writer); HierarchicalINIConfiguration config2 = new HierarchicalINIConfiguration(); config2.load(new StringReader(writer.toString())); assertEquals("value", "1;2;3", config2.getString("section.key1")); } /** * Tests whether whitespace is left unchanged for quoted values. */ @Test public void testQuotedValueWithWhitespace() throws Exception { final String content = "CmdPrompt = \" [test@cmd ~]$ \""; HierarchicalINIConfiguration config = setUpConfig(content); assertEquals("Wrong propert value", " [test@cmd ~]$ ", config .getString("CmdPrompt")); } /** * Tests a quoted value with space and a comment. */ @Test public void testQuotedValueWithWhitespaceAndComment() throws Exception { final String content = "CmdPrompt = \" [test@cmd ~]$ \" ; a comment"; HierarchicalINIConfiguration config = setUpConfig(content); assertEquals("Wrong propert value", " [test@cmd ~]$ ", config .getString("CmdPrompt")); } /** * Tests an empty quoted value. */ @Test public void testQuotedValueEmpty() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA2); assertEquals("Wrong value for empty property", "", config .getString("section4.var6")); } /** * Tests a property that has no value. */ @Test public void testGetPropertyNoValue() throws ConfigurationException { final String data = INI_DATA2 + LINE_SEPARATOR + "noValue =" + LINE_SEPARATOR; HierarchicalINIConfiguration config = setUpConfig(data); assertEquals("Wrong value of key", "", config .getString("section4.noValue")); } /** * Tests a property that has no key. */ @Test public void testGetPropertyNoKey() throws ConfigurationException { final String data = INI_DATA2 + LINE_SEPARATOR + "= noKey" + LINE_SEPARATOR; HierarchicalINIConfiguration config = setUpConfig(data); assertEquals("Cannot find property with no key", "noKey", config .getString("section4. ")); } /** * Tests reading a property from the global section. */ @Test public void testGlobalProperty() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA_GLOBAL); assertEquals("Wrong value of global property", "testGlobal", config .getString("globalVar")); } /** * Tests whether the specified configuration contains exactly the expected * sections. * * @param config the configuration to check * @param expected an array with the expected sections */ private void checkSectionNames(HierarchicalINIConfiguration config, String[] expected) { Set sectionNames = config.getSections(); Iterator it = sectionNames.iterator(); for (int idx = 0; idx < expected.length; idx++) { assertEquals("Wrong section at " + idx, expected[idx], it.next()); } assertFalse("Too many sections", it.hasNext()); } /** * Tests the names of the sections returned by the configuration. * * @param data the data of the ini configuration * @param expected the expected section names * @return the configuration instance */ private HierarchicalINIConfiguration checkSectionNames(String data, String[] expected) throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(data); checkSectionNames(config, expected); return config; } /** * Tests querying the sections if a global section if available. */ @Test public void testGetSectionsWithGlobal() throws ConfigurationException { checkSectionNames(INI_DATA_GLOBAL, new String[] { null, "section1", "section2", "section3" }); } /** * Tests querying the sections if there is no global section. */ @Test public void testGetSectionsNoGlobal() throws ConfigurationException { checkSectionNames(INI_DATA, new String[] { "section1", "section2", "section3" }); } /** * Tests whether the sections of a configuration can be queried that * contains only a global section. */ @Test public void testGetSectionsGlobalOnly() throws ConfigurationException { checkSectionNames(INI_DATA_GLOBAL_ONLY, new String[] { null }); } /** * Tests whether variables containing a dot are not misinterpreted as * sections. This test is related to CONFIGURATION-327. */ @Test public void testGetSectionsDottedVar() throws ConfigurationException { final String data = "dotted.var = 1" + LINE_SEPARATOR + INI_DATA_GLOBAL; HierarchicalINIConfiguration config = checkSectionNames(data, new String[] { null, "section1", "section2", "section3" }); assertEquals("Wrong value of dotted variable", 1, config .getInt("dotted..var")); } /** * Tests whether a section added later is also found by getSections(). */ @Test public void testGetSectionsAdded() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA2); config.addProperty("section5.test", Boolean.TRUE); checkSectionNames(config, new String[] { "section4", "section5" }); } /** * Tests querying the properties of an existing section. */ @Test public void testGetSectionExisting() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA); SubnodeConfiguration section = config.getSection("section1"); assertEquals("Wrong value of var1", "foo", section.getString("var1")); assertEquals("Wrong value of var2", "451", section.getString("var2")); } /** * Tests querying the properties of a section that was merged from two * sections with the same name. */ @Test public void testGetSectionMerged() throws ConfigurationException { final String data = INI_DATA + "[section1]" + LINE_SEPARATOR + "var3 = merged" + LINE_SEPARATOR; HierarchicalINIConfiguration config = setUpConfig(data); SubnodeConfiguration section = config.getSection("section1"); assertEquals("Wrong value of var1", "foo", section.getString("var1")); assertEquals("Wrong value of var2", "451", section.getString("var2")); assertEquals("Wrong value of var3", "merged", section.getString("var3")); } /** * Tests querying the content of the global section. */ @Test public void testGetSectionGlobal() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA_GLOBAL); SubnodeConfiguration section = config.getSection(null); assertEquals("Wrong value of global variable", "testGlobal", section .getString("globalVar")); } /** * Tests concurrent access to the global section. */ @Test public void testGetSectionGloabalMultiThreaded() throws ConfigurationException, InterruptedException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA_GLOBAL); final int threadCount = 10; GlobalSectionTestThread[] threads = new GlobalSectionTestThread[threadCount]; for (int i = 0; i < threadCount; i++) { threads[i] = new GlobalSectionTestThread(config); threads[i].start(); } for (int i = 0; i < threadCount; i++) { threads[i].join(); assertFalse("Exception occurred", threads[i].error); } } /** * Tests querying the content of the global section if there is none. */ @Test public void testGetSectionGlobalNonExisting() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA); SubnodeConfiguration section = config.getSection(null); assertTrue("Sub config not empty", section.isEmpty()); } /** * Tests querying a non existing section. */ @Test public void testGetSectionNonExisting() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA); SubnodeConfiguration section = config .getSection("Non existing section"); assertTrue("Sub config not empty", section.isEmpty()); } /** * Tests a property whose value spans multiple lines. */ @Test public void testLineContinuation() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA3); assertEquals("Wrong value", "one" + LINE_SEPARATOR + "two" + LINE_SEPARATOR + "three", config .getString("section5.multiLine")); } /** * Tests a property value that ends on a backslash, which is no line * continuation character. */ @Test public void testLineContinuationNone() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA3); assertEquals("Wrong value", "C:\\Temp\\", config .getString("section5.singleLine")); } /** * Tests a property whose value spans multiple lines when quoting is * involved. In this case whitespace must not be trimmed. */ @Test public void testLineContinuationQuoted() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA3); assertEquals("Wrong value", "one" + LINE_SEPARATOR + " two " + LINE_SEPARATOR + "three", config .getString("section5.multiQuoted")); } /** * Tests a property whose value spans multiple lines with a comment. */ @Test public void testLineContinuationComment() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA3); assertEquals("Wrong value", "one" + LINE_SEPARATOR + "two", config .getString("section5.multiComment")); } /** * Tests a property with a quoted value spanning multiple lines and a * comment. */ @Test public void testLineContinuationQuotedComment() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA3); assertEquals("Wrong value", " one " + LINE_SEPARATOR + "two", config .getString("section5.multiQuotedComment")); } /** * Tests a multi-line property value with an empty line. */ @Test public void testLineContinuationEmptyLine() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA3); assertEquals("Wrong value", LINE_SEPARATOR + "line 2", config .getString("section5.noFirstLine")); } /** * Tests a line continuation at the end of the file. */ @Test public void testLineContinuationAtEnd() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA3); assertEquals("Wrong value", "one" + LINE_SEPARATOR, config .getString("section5.continueNoLine")); } /** * Tests whether a configuration can be saved that contains section keys * with delimiter characters. This test is related to CONFIGURATION-409. */ @Test public void testSaveKeysWithDelimiters() throws ConfigurationException { HierarchicalINIConfiguration conf = new HierarchicalINIConfiguration(); final String section = "Section..with..dots"; conf.addProperty(section + ".test1", "test1"); conf.addProperty(section + ".test2", "test2"); conf.save(TEST_FILE); conf = new HierarchicalINIConfiguration(); conf.load(TEST_FILE); assertEquals("Wrong value (1)", "test1", conf.getString(section + ".test1")); assertEquals("Wrong value (2)", "test2", conf.getString(section + ".test2")); } /** * Tests whether a value which contains a semicolon can be loaded * successfully. This test is related to CONFIGURATION-434. */ @Test public void testValueWithSemicolon() throws ConfigurationException { final String path = "C:\\Program Files\\jar\\manage.jar;" + "C:\\Program Files\\jar\\guiLauncher.jar"; final String content = "[Environment]" + LINE_SEPARATOR + "Application Type=any" + LINE_SEPARATOR + "Class Path=" + path + " ;comment" + LINE_SEPARATOR + "Path=" + path + "\t; another comment"; HierarchicalINIConfiguration config = setUpConfig(content); assertEquals("Wrong class path", path, config.getString("Environment.Class Path")); assertEquals("Wrong path", path, config.getString("Environment.Path")); } /** * Tests whether the different separators with or without whitespace are * recognized. */ @Test public void testSeparators() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA_SEPARATORS); for (int i = 1; i <= 4; i++) { assertEquals("Wrong value", "value" + i, config.getString("section.var" + i)); } } /** * Tests property definitions containing multiple separators. */ @Test public void testMultipleSeparators() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA_SEPARATORS); assertEquals("Wrong value for var5", "value=5", config.getString("section.var5")); assertEquals("Wrong value for var6", "6=value", config.getString("section.var")); } /** * Tests property definitions containing multiple separators that are * quoted. */ @Test public void testMultipleSeparatorsQuoted() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA_SEPARATORS); assertEquals("Wrong value for var7", "value7", config.getString("section.var:7")); assertEquals("Wrong value for var8", "value8", config.getString("section.var:8")); } /** * Tests whether a section that has been cleared can be manipulated and * saved later. */ @Test public void testSaveClearedSection() throws ConfigurationException { final String data = "[section]\ntest = failed\n"; HierarchicalINIConfiguration config = setUpConfig(data); SubnodeConfiguration sub = config.getSection("section"); assertFalse("No content", sub.isEmpty()); sub.clear(); sub.setProperty("test", "success"); StringWriter writer = new StringWriter(); config.save(writer); HierarchicalConfiguration config2 = setUpConfig(writer.toString()); assertEquals("Wrong value", "success", config2.getString("section.test")); } /** * Tests whether a duplicate session is merged. */ @Test public void testMergeDuplicateSection() throws ConfigurationException { final String data = "[section]\nvar1 = sec1\n\n" + "[section]\nvar2 = sec2\n"; HierarchicalINIConfiguration config = setUpConfig(data); assertEquals("Wrong value 1", "sec1", config.getString("section.var1")); assertEquals("Wrong value 2", "sec2", config.getString("section.var2")); SubnodeConfiguration sub = config.getSection("section"); assertEquals("Wrong sub value 1", "sec1", sub.getString("var1")); assertEquals("Wrong sub value 2", "sec2", sub.getString("var2")); StringWriter writer = new StringWriter(); config.save(writer); String content = writer.toString(); int pos = content.indexOf("[section]"); assertTrue("Section not found: " + content, pos >= 0); assertTrue("Section found multiple times: " + content, content.indexOf("[section]", pos + 1) < 0); } /** * Tests whether a section that was created by getSection() can be * manipulated. */ @Test public void testGetSectionNonExistingManipulate() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig(INI_DATA); SubnodeConfiguration section = config.getSection("newSection"); section.addProperty("test", "success"); assertEquals("Main config not updated", "success", config.getString("newSection.test")); StringWriter writer = new StringWriter(); config.save(writer); HierarchicalINIConfiguration config2 = setUpConfig(writer.toString()); section = config2.getSection("newSection"); assertEquals("Wrong value", "success", section.getString("test")); } /** * Tests whether getSection() can deal with duplicate sections. */ @Test public void testGetSectionDuplicate() { HierarchicalINIConfiguration config = new HierarchicalINIConfiguration(); config.addProperty("section.var1", "value1"); config.addProperty("section(-1).var2", "value2"); SubnodeConfiguration section = config.getSection("section"); Iterator keys = section.getKeys(); assertEquals("Wrong key", "var1", keys.next()); assertFalse("Too many keys", keys.hasNext()); } /** * Tests whether the list delimiter character is recognized. */ @Test public void testValueWithDelimiters() throws ConfigurationException { HierarchicalINIConfiguration config = setUpConfig("[test]" + LINE_SEPARATOR + "list=1,2,3" + LINE_SEPARATOR); List list = config.getList("test.list"); assertEquals("Wrong number of elements", 3, list.size()); assertEquals("Wrong element at 1", "1", list.get(0)); assertEquals("Wrong element at 2", "2", list.get(1)); assertEquals("Wrong element at 3", "3", list.get(2)); } /** * Tests whether parsing of lists can be disabled. */ @Test public void testListParsingDisabled() throws ConfigurationException { HierarchicalINIConfiguration config = new HierarchicalINIConfiguration(); config.setDelimiterParsingDisabled(true); load(config, "[test]" + LINE_SEPARATOR + "nolist=1,2,3"); assertEquals("Wrong value", "1,2,3", config.getString("test.nolist")); } /** * A thread class for testing concurrent access to the global section. */ private static class GlobalSectionTestThread extends Thread { /** The configuration. */ private final HierarchicalINIConfiguration config; /** A flag whether an error was found. */ volatile boolean error; /** * Creates a new instance of GlobalSectionTestThread and * initializes it. * * @param conf the configuration object */ public GlobalSectionTestThread(HierarchicalINIConfiguration conf) { config = conf; } /** * Accesses the global section in a loop. If there is no correct * synchronization, this can cause an exception. */ @Override public void run() { final int loopCount = 250; for (int i = 0; i < loopCount && !error; i++) { try { config.getSection(null); } catch (IllegalStateException istex) { error = true; } } } } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestHierarchicalXMLConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestHierarchicalXMLCon100644 26300 12232154104 33440 0ustarhenningstaff 0 0 package org.apache.commons.configuration; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import java.util.Collection; import java.util.Iterator; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; /** * Test class for XMLConfiguration. In addition to TestXMLConfiguration this * class especially tests the hierarchical nature of this class and structured * data access. * * @author Emmanuel Bourg * @author Mark Woodman * @version $Id: TestHierarchicalXMLConfiguration.java 1224764 2011-12-26 17:14:49Z oheger $ */ public class TestHierarchicalXMLConfiguration { /** Test resources directory. */ private static final String TEST_DIR = "conf"; /** Test file #1 **/ private static final String TEST_FILENAME = "testHierarchicalXMLConfiguration.xml"; /** Test file #2 **/ private static final String TEST_FILENAME2 = "testHierarchicalXMLConfiguration2.xml"; /** Test file path #1 **/ private static final String TEST_FILE = ConfigurationAssert.getTestFile(TEST_FILENAME).getAbsolutePath(); /** Test file path #2 **/ private static final String TEST_FILE2 = ConfigurationAssert.getTestFile(TEST_FILENAME2).getAbsolutePath(); /** Test file path #3.*/ private static final String TEST_FILE3 = ConfigurationAssert.getTestFile("test.xml").getAbsolutePath(); /** File name for saving.*/ private static final String TEST_SAVENAME = "testhierarchicalsave.xml"; /** Helper object for creating temporary files. */ @Rule public TemporaryFolder folder = new TemporaryFolder(); /** Instance config used for tests. */ private XMLConfiguration config; /** Fixture setup. */ @Before public void setUp() throws Exception { config = new XMLConfiguration(); } private void configTest(XMLConfiguration config) { assertEquals(1, config.getMaxIndex("tables.table")); assertEquals("system", config.getProperty("tables.table(0)[@tableType]")); assertEquals("application", config.getProperty("tables.table(1)[@tableType]")); assertEquals("users", config.getProperty("tables.table(0).name")); assertEquals("documents", config.getProperty("tables.table(1).name")); Object prop = config.getProperty("tables.table.fields.field.name"); assertTrue(prop instanceof Collection); assertEquals(10, ((Collection) prop).size()); prop = config.getProperty("tables.table(0).fields.field.type"); assertTrue(prop instanceof Collection); assertEquals(5, ((Collection) prop).size()); prop = config.getProperty("tables.table(1).fields.field.type"); assertTrue(prop instanceof Collection); assertEquals(5, ((Collection) prop).size()); } @Test public void testGetProperty() throws Exception { config.setFileName(TEST_FILE); config.load(); configTest(config); } @Test public void testLoadURL() throws Exception { config.load(new File(TEST_FILE).getAbsoluteFile().toURI().toURL()); configTest(config); } @Test public void testLoadBasePath1() throws Exception { config.setBasePath(TEST_DIR); config.setFileName(TEST_FILENAME); config.load(); configTest(config); } @Test public void testLoadBasePath2() throws Exception { config.setBasePath(new File(TEST_FILE).getAbsoluteFile().toURI().toURL().toString()); config.setFileName(TEST_FILENAME); config.load(); configTest(config); } /** * Ensure various node types are correctly processed in config. * @throws Exception */ @Test public void testXmlNodeTypes() throws Exception { // Number of keys expected from test configuration file final int KEY_COUNT = 5; // Load the configuration file config.load(new File(TEST_FILE2).getAbsoluteFile().toURI().toURL()); // Validate comment in element ignored assertEquals("Comment in element must not change element value.", "Case1Text", config .getString("case1")); // Validate sibling comment ignored assertEquals("Comment as sibling must not change element value.", "Case2Text", config .getString("case2.child")); // Validate comment ignored, CDATA processed assertEquals("Comment and use of CDATA must not change element value.", "Case3Text", config .getString("case3")); // Validate comment and processing instruction ignored assertEquals("Comment and use of PI must not change element value.", "Case4Text", config .getString("case4")); // Validate comment ignored in parent attribute assertEquals("Comment must not change attribute node value.", "Case5Text", config .getString("case5[@attr]")); // Validate non-text nodes haven't snuck in as keys Iterator iter = config.getKeys(); int count = 0; while (iter.hasNext()) { iter.next(); count++; } assertEquals("Config must contain only " + KEY_COUNT + " keys.", KEY_COUNT, count); } @Test public void testSave() throws Exception { config.setFileName(TEST_FILE3); config.load(); File saveFile = folder.newFile(TEST_SAVENAME); config.save(saveFile); config = new XMLConfiguration(); config.load(saveFile.toURI().toURL()); assertEquals("value", config.getProperty("element")); assertEquals("I'm complex!", config.getProperty("element2.subelement.subsubelement")); assertEquals(8, config.getInt("test.short")); assertEquals("one", config.getString("list(0).item(0)[@name]")); assertEquals("two", config.getString("list(0).item(1)")); assertEquals("six", config.getString("list(1).sublist.item(1)")); } /** * Tests to save a newly created configuration. */ @Test public void testSaveNew() throws Exception { config.addProperty("connection.url", "jdbc://mydb:1234"); config.addProperty("connection.user", "scott"); config.addProperty("connection.passwd", "tiger"); config.addProperty("connection[@type]", "system"); config.addProperty("tables.table.name", "tests"); config.addProperty("tables.table(0).fields.field.name", "test_id"); config.addProperty("tables.table(0).fields.field(-1).name", "test_name"); config.addProperty("tables.table(-1).name", "results"); config.addProperty("tables.table(1).fields.field.name", "res_id"); config.addProperty("tables.table(1).fields.field(0).type", "int"); config.addProperty("tables.table(1).fields.field(-1).name", "value"); config.addProperty("tables.table(1).fields.field(1).type", "string"); config.addProperty("tables.table(1).fields.field(1)[@null]", "true"); File saveFile = folder.newFile(TEST_SAVENAME); config.setFile(saveFile); config.setRootElementName("myconfig"); config.save(); config = new XMLConfiguration(); config.load(saveFile); assertEquals(1, config.getMaxIndex("tables.table.name")); assertEquals("tests", config.getString("tables.table(0).name")); assertEquals("test_name", config.getString("tables.table(0).fields.field(1).name")); assertEquals("int", config.getString("tables.table(1).fields.field(0).type")); assertTrue(config.getBoolean("tables.table(1).fields.field(1)[@null]")); assertEquals("tiger", config.getString("connection.passwd")); assertEquals("system", config.getProperty("connection[@type]")); assertEquals("myconfig", config.getRootElementName()); } /** * Tests to save a modified configuration. */ @Test public void testSaveModified() throws Exception { config.setFile(new File(TEST_FILE3)); config.load(); assertTrue(config.getString("mean").startsWith("This is\n A long story...")); assertTrue(config.getString("mean").indexOf("And even longer") > 0); config.clearProperty("test.entity[@name]"); config.setProperty("element", "new value"); config.setProperty("test(0)", "A value"); config.addProperty("test(1).int", new Integer(9)); config.addProperty("list(1).sublist.item", "seven"); config.setProperty("clear", "yes"); config.setProperty("mean", "now it's simple"); config.addProperty("[@topattr]", "available"); config.addProperty("[@topattr]", "successfull"); File saveFile = folder.newFile(TEST_SAVENAME); config.save(saveFile); config = new XMLConfiguration(); config.load(saveFile.getAbsolutePath()); assertFalse(config.containsKey("test.entity[@name]")); assertEquals("1<2", config.getProperty("test.entity")); assertEquals("new value", config.getString("element")); assertEquals("A value", config.getProperty("test(0)")); assertEquals((short) 8, config.getShort("test(1).short")); assertEquals(9, config.getInt("test(1).int")); assertEquals("six", config.getProperty("list(1).sublist.item(1)")); assertEquals("seven", config.getProperty("list(1).sublist.item(2)")); assertEquals("yes", config.getProperty("clear")); assertEquals("now it's simple", config.getString("mean")); assertEquals("available", config.getString("[@topattr](0)")); assertEquals("successfull", config.getString("[@topattr](1)")); } /** * Tests manipulation of the root element's name. */ @Test public void testRootElement() throws Exception { assertEquals("configuration", config.getRootElementName()); config.setRootElementName("newRootName"); assertEquals("newRootName", config.getRootElementName()); } /** * Tests that it is not allowed to change the root element name when the * configuration was loaded from a file. */ @Test(expected = UnsupportedOperationException.class) public void testSetRootElementNameWhenLoadedFromFile() throws Exception { config.setFile(new File(TEST_FILE3)); config.load(); assertEquals("testconfig", config.getRootElementName()); config.setRootElementName("anotherRootElement"); } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestINIConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestINIConfiguration.j100644 21071 12232154104 33440 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with this * work for additional information regarding copyright ownership. The ASF * licenses this file to You under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the * License for the specific language governing permissions and limitations under * the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.util.HashSet; import java.util.Set; import org.junit.Test; /** * Test class for INIConfiguration. * * @author Trevor Miller * @version $Id: TestINIConfiguration.java 1224770 2011-12-26 17:18:36Z oheger $ */ @SuppressWarnings("deprecation") public class TestINIConfiguration { private static String LINE_SEPARATOR = System.getProperty("line.separator"); /** Constant for the content of an ini file. */ private static final String INI_DATA = "[section1]" + LINE_SEPARATOR + "var1 = foo" + LINE_SEPARATOR + "var2 = 451" + LINE_SEPARATOR + LINE_SEPARATOR + "[section2]" + LINE_SEPARATOR + "var1 = 123.45" + LINE_SEPARATOR + "var2 = bar" + LINE_SEPARATOR + LINE_SEPARATOR + "[section3]" + LINE_SEPARATOR + "var1 = true" + LINE_SEPARATOR + "interpolated = ${section3.var1}" + LINE_SEPARATOR + "multi = foo" + LINE_SEPARATOR + "multi = bar" + LINE_SEPARATOR + LINE_SEPARATOR; private static final String INI_DATA2 = "[section4]" + LINE_SEPARATOR + "var1 = \"quoted value\"" + LINE_SEPARATOR + "var2 = \"quoted value\\nwith \\\"quotes\\\"\"" + LINE_SEPARATOR + "var3 = 123 ; comment" + LINE_SEPARATOR + "var4 = \"1;2;3\" ; comment" + LINE_SEPARATOR + "var5 = '\\'quoted\\' \"value\"' ; comment"; /** * Test of save method, of class {@link INIConfiguration}. */ @Test public void testSave() throws Exception { Writer writer = new StringWriter(); INIConfiguration instance = new INIConfiguration(); instance.addProperty("section1.var1", "foo"); instance.addProperty("section1.var2", "451"); instance.addProperty("section2.var1", "123.45"); instance.addProperty("section2.var2", "bar"); instance.addProperty("section3.var1", "true"); instance.addProperty("section3.interpolated", "${section3.var1}"); instance.addProperty("section3.multi", "foo"); instance.addProperty("section3.multi", "bar"); instance.save(writer); assertEquals("Wrong content of ini file", INI_DATA, writer.toString()); } /** * Test of load method, of class {@link INIConfiguration}. */ @Test public void testLoad() throws Exception { checkLoad(INI_DATA); } /** * Tests the load() method when the alternative value separator is used (a * ':' for '='). */ @Test public void testLoadAlternativeSeparator() throws Exception { checkLoad(INI_DATA.replace('=', ':')); } /** * Helper method for testing the load operation. Loads the specified content * into a configuration and then checks some properties. * * @param data the data to load */ private void checkLoad(String data) throws ConfigurationException, IOException { Reader reader = new StringReader(data); INIConfiguration instance = new INIConfiguration(); instance.load(reader); reader.close(); assertTrue(instance.getString("section1.var1").equals("foo")); assertTrue(instance.getInt("section1.var2") == 451); assertTrue(instance.getDouble("section2.var1") == 123.45); assertTrue(instance.getString("section2.var2").equals("bar")); assertTrue(instance.getBoolean("section3.var1")); assertTrue(instance.getSections().size() == 3); } /** * Test of isCommentLine method, of class {@link INIConfiguration}. */ @Test public void testIsCommentLine() { INIConfiguration instance = new INIConfiguration(); assertTrue(instance.isCommentLine("#comment1")); assertTrue(instance.isCommentLine(";comment1")); assertFalse(instance.isCommentLine("nocomment=true")); assertFalse(instance.isCommentLine(null)); } /** * Test of isSectionLine method, of class {@link INIConfiguration}. */ @Test public void testIsSectionLine() { INIConfiguration instance = new INIConfiguration(); assertTrue(instance.isSectionLine("[section]")); assertFalse(instance.isSectionLine("nosection=true")); assertFalse(instance.isSectionLine(null)); } /** * Test of getSections method, of class {@link INIConfiguration}. */ @Test public void testGetSections() { INIConfiguration instance = new INIConfiguration(); instance.addProperty("test1.foo", "bar"); instance.addProperty("test2.foo", "abc"); Set expResult = new HashSet(); expResult.add("test1"); expResult.add("test2"); Set result = instance.getSections(); assertEquals(expResult, result); } @Test public void testQuotedValue() throws Exception { INIConfiguration config = new INIConfiguration(); config.load(new StringReader(INI_DATA2)); assertEquals("value", "quoted value", config.getString("section4.var1")); } @Test public void testQuotedValueWithQuotes() throws Exception { INIConfiguration config = new INIConfiguration(); config.load(new StringReader(INI_DATA2)); assertEquals("value", "quoted value\\nwith \"quotes\"", config.getString("section4.var2")); } @Test public void testValueWithComment() throws Exception { INIConfiguration config = new INIConfiguration(); config.load(new StringReader(INI_DATA2)); assertEquals("value", "123", config.getString("section4.var3")); } @Test public void testQuotedValueWithComment() throws Exception { INIConfiguration config = new INIConfiguration(); config.load(new StringReader(INI_DATA2)); assertEquals("value", "1;2;3", config.getString("section4.var4")); } @Test public void testQuotedValueWithSingleQuotes() throws Exception { INIConfiguration config = new INIConfiguration(); config.load(new StringReader(INI_DATA2)); assertEquals("value", "'quoted' \"value\"", config.getString("section4.var5")); } @Test public void testWriteValueWithCommentChar() throws Exception { INIConfiguration config = new INIConfiguration(); config.setProperty("section.key1", "1;2;3"); StringWriter writer = new StringWriter(); config.save(writer); INIConfiguration config2 = new INIConfiguration(); config2.load(new StringReader(writer.toString())); assertEquals("value", "1;2;3", config2.getString("section.key1")); } /** * Tests whether whitespace is left unchanged for quoted values. */ @Test public void testQuotedValueWithWhitespace() throws Exception { final String content = "CmdPrompt = \" [test@cmd ~]$ \""; INIConfiguration config = new INIConfiguration(); config.load(new StringReader(content)); assertEquals("Wrong propert value", " [test@cmd ~]$ ", config .getString("CmdPrompt")); } /** * Tests a quoted value with space and a comment. */ @Test public void testQuotedValueWithWhitespaceAndComment() throws Exception { final String content = "CmdPrompt = \" [test@cmd ~]$ \" ; a comment"; INIConfiguration config = new INIConfiguration(); config.load(new StringReader(content)); assertEquals("Wrong propert value", " [test@cmd ~]$ ", config .getString("CmdPrompt")); } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestJNDIConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestJNDIConfiguration.100644 25543 12232154104 33403 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Hashtable; import java.util.Properties; import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NameNotFoundException; import javax.naming.NamingException; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test to see if the JNDIConfiguration works properly. * * @version $Id: TestJNDIConfiguration.java 1301996 2012-03-17 20:30:39Z sebb $ */ public class TestJNDIConfiguration { public static final String CONTEXT_FACTORY = MockInitialContextFactory.class.getName(); private PotentialErrorJNDIConfiguration conf; private NonStringTestHolder nonStringTestHolder; /** A test error listener for counting internal errors.*/ private ConfigurationErrorListenerImpl listener; @Before public void setUp() throws Exception { System.setProperty("java.naming.factory.initial", CONTEXT_FACTORY); Properties props = new Properties(); props.put("java.naming.factory.initial", CONTEXT_FACTORY); Context ctx = new InitialContext(props); conf = new PotentialErrorJNDIConfiguration(ctx); nonStringTestHolder = new NonStringTestHolder(); nonStringTestHolder.setConfiguration(conf); listener = new ConfigurationErrorListenerImpl(); conf.addErrorListener(listener); } /** * Clears the test environment. If an error listener is defined, checks * whether no error event was received. */ @After public void tearDown() throws Exception { if (listener != null) { listener.verify(); } } @Test public void testBoolean() throws Exception { nonStringTestHolder.testBoolean(); } @Test public void testBooleanDefaultValue() throws Exception { nonStringTestHolder.testBooleanDefaultValue(); } @Test public void testByte() throws Exception { nonStringTestHolder.testByte(); } @Test public void testDouble() throws Exception { nonStringTestHolder.testDouble(); } @Test public void testDoubleDefaultValue() throws Exception { nonStringTestHolder.testDoubleDefaultValue(); } @Test public void testFloat() throws Exception { nonStringTestHolder.testFloat(); } @Test public void testFloatDefaultValue() throws Exception { nonStringTestHolder.testFloatDefaultValue(); } @Test public void testInteger() throws Exception { nonStringTestHolder.testInteger(); } @Test public void testIntegerDefaultValue() throws Exception { nonStringTestHolder.testIntegerDefaultValue(); } @Test public void testLong() throws Exception { nonStringTestHolder.testLong(); } @Test public void testLongDefaultValue() throws Exception { nonStringTestHolder.testLongDefaultValue(); } @Test public void testShort() throws Exception { nonStringTestHolder.testShort(); } @Test public void testShortDefaultValue() throws Exception { nonStringTestHolder.testShortDefaultValue(); } @Test public void testListMissing() throws Exception { nonStringTestHolder.testListMissing(); } @Test public void testSubset() throws Exception { nonStringTestHolder.testSubset(); } @Test public void testProperties() throws Exception { Object o = conf.getProperty("test.boolean"); assertNotNull(o); assertEquals("true", o.toString()); } @Test public void testContainsKey() { String key = "test.boolean"; assertTrue("'" + key + "' not found", conf.containsKey(key)); conf.clearProperty(key); assertFalse("'" + key + "' still found", conf.containsKey(key)); } @Test public void testChangePrefix() { assertEquals("'test.boolean' property", "true", conf.getString("test.boolean")); assertEquals("'boolean' property", null, conf.getString("boolean")); // change the prefix conf.setPrefix("test"); assertEquals("'test.boolean' property", null, conf.getString("test.boolean")); assertEquals("'boolean' property", "true", conf.getString("boolean")); } @Test public void testResetRemovedProperties() throws Exception { assertEquals("'test.boolean' property", "true", conf.getString("test.boolean")); // remove the property conf.clearProperty("test.boolean"); assertEquals("'test.boolean' property", null, conf.getString("test.boolean")); // change the context conf.setContext(new InitialContext()); // get the property assertEquals("'test.boolean' property", "true", conf.getString("test.boolean")); } @Test public void testConstructor() throws Exception { // test the constructor accepting a context JNDIConfiguration c = new JNDIConfiguration(new InitialContext()); assertEquals("'test.boolean' property", "true", c.getString("test.boolean")); // test the constructor accepting a context and a prefix c = new JNDIConfiguration(new InitialContext(), "test"); assertEquals("'boolean' property", "true", c.getString("boolean")); } /** * Configures the test config to throw an exception. */ private PotentialErrorJNDIConfiguration setUpErrorConfig() { conf.installException(); conf.removeErrorListener(conf.getErrorListeners().iterator().next()); return conf; } /** * Tests whether the expected error events have been received. * * @param type the expected event type * @param propName the name of the property * @param propValue the property value */ private void checkErrorListener(int type, String propName, Object propValue) { listener.verify(type, propName, propValue); assertTrue("Wrong exception class", listener.getLastEvent().getCause() instanceof NamingException); listener = null; } /** * Tests whether a JNDI configuration registers an error log listener. */ @Test public void testLogListener() throws NamingException { JNDIConfiguration c = new JNDIConfiguration(); assertEquals("No error log listener registered", 1, c .getErrorListeners().size()); } /** * Tests handling of errors in getKeys(). */ @Test public void testGetKeysError() { assertFalse("Iteration not empty", setUpErrorConfig().getKeys() .hasNext()); checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, null, null); } /** * Tests handling of errors in isEmpty(). */ @Test public void testIsEmptyError() throws Exception { assertTrue("Error config not empty", setUpErrorConfig().isEmpty()); checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, null, null); } /** * Tests handling of errors in the containsKey() method. */ @Test public void testContainsKeyError() { assertFalse("Key contained after error", setUpErrorConfig() .containsKey("key")); checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, "key", null); } /** * Tests handling of errors in getProperty(). */ @Test public void testGetPropertyError() { assertNull("Wrong property value after error", setUpErrorConfig() .getProperty("key")); checkErrorListener(AbstractConfiguration.EVENT_READ_PROPERTY, "key", null); } /** * Tests the getKeys() method when there are cycles in the tree. */ @Test public void testGetKeysWithCycles() throws NamingException { Hashtable env = new Hashtable(); env.put(MockInitialContextFactory.PROP_CYCLES, Boolean.TRUE); InitialContext initCtx = new InitialContext(env); JNDIConfiguration c = new JNDIConfiguration(initCtx); c.getKeys("cycle"); } /** * Tests getKeys() if no data is found. This should not cause a problem and * not notify the error listeners. */ @Test public void testGetKeysNoData() { conf.installException(new NameNotFoundException("Test exception")); assertFalse("Got keys", conf.getKeys().hasNext()); listener.verify(); } /** * A special JNDI configuration implementation that can be configured to * throw an exception when accessing the base context. Used for testing the * exception handling. */ public static class PotentialErrorJNDIConfiguration extends JNDIConfiguration { /** An exception to be thrown by getBaseContext(). */ private NamingException exception; public PotentialErrorJNDIConfiguration(Context ctx) throws NamingException { super(ctx); } /** * Prepares this object to throw an exception when the JNDI context is * queried. * * @param nex the exception to be thrown */ public void installException(NamingException nex) { exception = nex; } /** * Prepares this object to throw a standard exception when the JNDI * context is queried. */ public void installException() { installException(new NamingException("Simulated JNDI exception!")); } /** * Returns the JNDI context. Optionally throws an exception. */ @Override public Context getBaseContext() throws NamingException { if (exception != null) { throw exception; } return super.getBaseContext(); } } }././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestJNDIEnvironmentValues.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestJNDIEnvironmentVal100644 10526 12232154104 33460 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.NoSuchElementException; import org.junit.Before; import org.junit.Test; public class TestJNDIEnvironmentValues { private JNDIConfiguration conf = null; @Before public void setUp() throws Exception { System.setProperty("java.naming.factory.initial", TestJNDIConfiguration.CONTEXT_FACTORY); conf = new JNDIConfiguration(); conf.setThrowExceptionOnMissing(true); } @Test public void testThrowExceptionOnMissing() { assertTrue("Throw Exception Property is not set!", conf.isThrowExceptionOnMissing()); } @Test public void testSimpleGet() throws Exception { String s = conf.getString("test.key"); assertEquals("jndivalue", s); } @Test public void testMoreGets() throws Exception { String s = conf.getString("test.key"); assertEquals("jndivalue", s); assertEquals("jndivalue2", conf.getString("test.key2")); assertEquals(1, conf.getShort("test.short")); } @Test(expected = NoSuchElementException.class) public void testGetMissingKey() throws Exception { conf.getString("test.imaginarykey"); } @Test public void testGetMissingKeyWithDefault() throws Exception { String result = conf.getString("test.imaginarykey", "bob"); assertEquals("bob", result); } @Test public void testContainsKey() throws Exception { assertTrue(conf.containsKey("test.key")); assertTrue(!conf.containsKey("test.imaginarykey")); } @Test public void testClearProperty() { assertNotNull("null short for the 'test.short' key", conf.getShort("test.short", null)); conf.clearProperty("test.short"); assertNull("'test.short' property not cleared", conf.getShort("test.short", null)); } @Test public void testIsEmpty() { assertFalse("the configuration shouldn't be empty", conf.isEmpty()); } @Test public void testGetKeys() throws Exception { boolean found = false; Iterator it = conf.getKeys(); assertTrue("no key found", it.hasNext()); while (it.hasNext() && !found) { found = "test.boolean".equals(it.next()); } assertTrue("'test.boolean' key not found", found); } @Test public void testGetKeysWithUnknownPrefix() { // test for a unknown prefix Iterator it = conf.getKeys("foo.bar"); assertFalse("no key should be found", it.hasNext()); } @Test public void testGetKeysWithExistingPrefix() { // test for an existing prefix Iterator it = conf.getKeys("test"); boolean found = false; while (it.hasNext() && !found) { found = "test.boolean".equals(it.next()); } assertTrue("'test.boolean' key not found", found); } @Test public void testGetKeysWithKeyAsPrefix() { // test for a prefix matching exactly the key of a property Iterator it = conf.getKeys("test.boolean"); boolean found = false; while (it.hasNext() && !found) { found = "test.boolean".equals(it.next()); } assertTrue("'test.boolean' key not found", found); } } ././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestMapConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestMapConfiguration.j100644 12410 12232154104 33533 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.junit.Test; /** * Tests for MapConfiguration. * * @author Emmanuel Bourg * @version $Id: TestMapConfiguration.java 1222465 2011-12-22 21:32:56Z oheger $ */ public class TestMapConfiguration extends TestAbstractConfiguration { /** Constant for a test key.*/ private static final String KEY = "key1"; /** Constant for a test property value with whitespace.*/ private static final String SPACE_VALUE = " Value with whitespace "; /** The trimmed test value.*/ private static final String TRIM_VALUE = SPACE_VALUE.trim(); @Override protected AbstractConfiguration getConfiguration() { Map map = new HashMap(); map.put(KEY, "value1"); map.put("key2", "value2"); map.put("list", "value1, value2"); map.put("listesc", "value1\\,value2"); return new MapConfiguration(map); } @Override protected AbstractConfiguration getEmptyConfiguration() { return new MapConfiguration(new HashMap()); } @Test public void testGetMap() { Map map = new HashMap(); MapConfiguration conf = new MapConfiguration(map); assertEquals(map, conf.getMap()); } @Test public void testClone() { MapConfiguration config = (MapConfiguration) getConfiguration(); MapConfiguration copy = (MapConfiguration) config.clone(); StrictConfigurationComparator comp = new StrictConfigurationComparator(); assertTrue("Configurations are not equal", comp.compare(config, copy)); } /** * Tests if the cloned configuration is decoupled from the original. */ @Test public void testCloneModify() { MapConfiguration config = (MapConfiguration) getConfiguration(); config.addConfigurationListener(new ConfigurationListener() { public void configurationChanged(ConfigurationEvent event) { // Just a dummy } }); MapConfiguration copy = (MapConfiguration) config.clone(); assertTrue("Event listeners were copied", copy .getConfigurationListeners().isEmpty()); config.addProperty("cloneTest", Boolean.TRUE); assertFalse("Map not decoupled", copy.containsKey("cloneTest")); copy.clearProperty("key1"); assertEquals("Map not decoupled (2)", "value1", config .getString("key1")); } /** * Tests adding another value to an existing property. */ @Test public void testAddProperty() { MapConfiguration config = (MapConfiguration) getConfiguration(); config.addProperty(KEY, TRIM_VALUE); config.addProperty(KEY, "anotherValue"); List values = config.getList(KEY); assertEquals("Wrong number of values", 3, values.size()); } /** * Tests querying a property when trimming is active. */ @Test public void testGetPropertyTrim() { MapConfiguration config = (MapConfiguration) getConfiguration(); config.getMap().put(KEY, SPACE_VALUE); assertEquals("Wrong trimmed value", TRIM_VALUE, config.getProperty(KEY)); } /** * Tests querying a property when trimming is disabled. */ @Test public void testGetPropertyTrimDisabled() { MapConfiguration config = (MapConfiguration) getConfiguration(); config.getMap().put(KEY, SPACE_VALUE); config.setTrimmingDisabled(true); assertEquals("Wrong trimmed value", SPACE_VALUE, config.getProperty(KEY)); } /** * Tests querying a property when trimming is enabled, but list splitting is * disabled. In this case no trimming is performed (trimming only works if * list splitting is enabled). */ @Test public void testGetPropertyTrimNoSplit() { MapConfiguration config = (MapConfiguration) getConfiguration(); config.getMap().put(KEY, SPACE_VALUE); config.setDelimiterParsingDisabled(true); assertEquals("Wrong trimmed value", SPACE_VALUE, config.getProperty(KEY)); } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestMapConfigurationRegression.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestMapConfigurationRe100644 2656 12232154104 33565 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import java.util.Collections; import java.util.Map; import java.util.UUID; import org.junit.Assert; import org.junit.Test; public class TestMapConfigurationRegression { @Test public void testMapConfigurationRegression() { final String key = UUID.randomUUID().toString(); final String value = UUID.randomUUID().toString(); final Map map = Collections.singletonMap(key, value); final MapConfiguration mc = new MapConfiguration(map); Assert.assertEquals(1, mc.getMap().size()); Assert.assertEquals(value, mc.getString(key)); } } ././@LongLink100644 0 0 172 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestMultiFileHierarchicalConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestMultiFileHierarchi100644 26114 12232154104 33555 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; import org.junit.Test; import org.xml.sax.SAXParseException; /** * Unit test for simple MultiConfigurationTest. * * @version $Id: TestMultiFileHierarchicalConfiguration.java 1224811 2011-12-26 21:04:25Z oheger $ */ public class TestMultiFileHierarchicalConfiguration { private static String PATTERN1 = "target/test-classes/testMultiConfiguration_${sys:Id}.xml"; private static final File MULTI_TENENT_FILE = new File( "conf/testMultiTenentConfigurationBuilder2.xml"); private static final File MULTI_TENENT_FILE2 = new File( "target/test-classes/testMultiTenentConfigurationBuilder2.xml"); private static final File MULTI_RELOAD_FILE = new File( "conf/testMultiTenentConfigurationBuilder3.xml"); /** * Rigourous Test :-) */ @Test public void testMultiConfiguration() { //set up a reloading strategy FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy(); strategy.setRefreshDelay(10000); MultiFileHierarchicalConfiguration config = new MultiFileHierarchicalConfiguration(PATTERN1); config.setReloadingStrategy(strategy); System.setProperty("Id", "1001"); assertTrue(config.getInt("rowsPerPage") == 15); System.setProperty("Id", "1002"); assertTrue(config.getInt("rowsPerPage") == 25); System.setProperty("Id", "1003"); assertTrue(config.getInt("rowsPerPage") == 35); } @Test public void testSchemaValidationError() throws Exception { System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_TENENT_FILE); CombinedConfiguration config = factory.getConfiguration(true); try { System.setProperty("Id", "2001"); config.getInt("rowsPerPage"); fail("No exception thrown"); } catch (Exception ex) { Throwable cause = ex.getCause(); while (cause != null && !(cause instanceof SAXParseException)) { cause = cause.getCause(); } assertTrue("SAXParseException was not thrown", cause instanceof SAXParseException); } } @Test public void testSchemaValidation() throws Exception { System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_TENENT_FILE); CombinedConfiguration config = factory.getConfiguration(true); System.setProperty("Id", "2002"); int rows = config.getInt("rowsPerPage"); assertTrue("expected: " + rows + " actual: " + "25", 25 == rows); } @Test public void testMissingFile() throws Exception { System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_TENENT_FILE); CombinedConfiguration config = factory.getConfiguration(true); System.setProperty("Id", "3099"); int rows = config.getInt("rowsPerPage"); assertTrue("expected: " + rows + " actual: " + "50", 50 == rows); } @Test public void testFileReload1() throws Exception { System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_RELOAD_FILE); CombinedConfiguration config = factory.getConfiguration(true); // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_3001.xml"); File output = new File("target/test-classes/testwrite/testMultiConfiguration_3001.xml"); output.delete(); output.getParentFile().mkdir(); copyFile(input, output); assertNotNull(config); verify("3001", config, 15); Thread.sleep(1100); XMLConfiguration x = new XMLConfiguration(); x.setFile(output); x.setAttributeSplittingDisabled(true); x.setDelimiterParsingDisabled(true); x.load(); x.setProperty("rowsPerPage", "35"); //Insure orginal timestamp and new timestamp aren't the same second. Thread.sleep(1100); x.save(); verify("3001", config, 35); output.delete(); } @Test public void testFileReload2() throws Exception { // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_3002.xml"); File output = new File("target/test-classes/testwrite/testMultiConfiguration_3002.xml"); output.delete(); System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_RELOAD_FILE); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); // The file should not exist yet. verify("3002", config, 50); output.getParentFile().mkdir(); copyFile(input, output); Thread.sleep(600); verify("3002", config, 25); output.delete(); } @Test public void testFileReload3() throws Exception { // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_3001.xml"); File output = new File("target/test-classes/testwrite/testMultiConfiguration_3001.xml"); output.delete(); output.getParentFile().mkdir(); System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_RELOAD_FILE); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); //The file does not exist yet. verify("3001", config, 50); copyFile(input, output); //Sleep so refreshDelay elapses Thread.sleep(600); verify("3001", config, 15); Thread.sleep(500); XMLConfiguration x = new XMLConfiguration(); x.setFile(output); x.setAttributeSplittingDisabled(true); x.setDelimiterParsingDisabled(true); x.load(); x.setProperty("rowsPerPage", "35"); // Insure original timestamp and new timestamp are not the same second. Thread.sleep(1100); x.save(); verify("3001", config, 35); output.delete(); } @Test public void testReloadDefault() throws Exception { // create a new configuration String defaultName = "target/test-classes/testMultiConfiguration_default.xml"; File input = new File(defaultName); System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_TENENT_FILE2); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); verify("3001", config, 15); verify("3002", config, 25); System.setProperty("Id", "3002"); config.addProperty("/ TestProp", "Test"); assertTrue("Property not added", "Test".equals(config.getString("TestProp"))); System.getProperties().remove("Id"); //Sleep so refreshDelay elapses Thread.sleep(600); long time = System.currentTimeMillis(); long original = input.lastModified(); input.setLastModified(time); File defaultFile = new File(defaultName); long newTime = defaultFile.lastModified(); assertTrue("time mismatch", original != newTime); Thread.sleep(600); verify("3001", config, 15); verify("3002", config, 25); System.setProperty("Id", "3002"); String test = config.getString("TestProp"); assertNull("Property was not cleared by reload", test); } @Test public void testFileReloadSchemaValidationError() throws Exception { System.getProperties().remove("Id"); DefaultConfigurationBuilder factory = new DefaultConfigurationBuilder(); factory.setFile(MULTI_RELOAD_FILE); CombinedConfiguration config = factory.getConfiguration(true); // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_3001.xml"); File output = new File("target/test-classes/testwrite/testMultiConfiguration_3001.xml"); output.delete(); output.getParentFile().mkdir(); copyFile(input, output); assertNotNull(config); verify("3001", config, 15); Thread.sleep(1100); XMLConfiguration x = new XMLConfiguration(); x.setFile(output); x.setAttributeSplittingDisabled(true); x.setDelimiterParsingDisabled(true); x.load(); x.setProperty("rowsPerPage", "test"); //Insure orginal timestamp and new timestamp aren't the same second. Thread.sleep(1100); x.save(); System.setProperty("Id", "3001"); try { config.getInt("rowsPerPage"); fail("No exception was thrown"); } catch (Exception ex) { } output.delete(); } private void copyFile(File input, File output) throws IOException { Reader reader = new FileReader(input); Writer writer = new FileWriter(output); char[] buffer = new char[4096]; int n = 0; while (-1 != (n = reader.read(buffer))) { writer.write(buffer, 0, n); } reader.close(); writer.close(); } private void verify(String key, CombinedConfiguration config, int rows) { if (key == null) { System.getProperties().remove("Id"); } else { System.setProperty("Id", key); } int actual = config.getInt("rowsPerPage"); assertTrue("expected: " + rows + " actual: " + actual, actual == rows); } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestNonStringProperties.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestNonStringPropertie100644 2612 12232154104 33634 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import org.junit.Before; /** * Test if non-string properties are handled correctly. * * @version $Id: TestNonStringProperties.java 1222445 2011-12-22 20:53:47Z oheger $ */ public class TestNonStringProperties extends BaseNonStringProperties { /** The File that we test with */ private String testProperties = ConfigurationAssert.getTestFile("test.properties").getAbsolutePath(); @Before public void setUp() throws Exception { conf = new PropertiesConfiguration(testProperties); nonStringTestHolder.setConfiguration(conf); } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestNullCompositeConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestNullCompositeConfi100644 35672 12232154104 33631 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.File; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.junit.Before; import org.junit.Test; /** * Test loading multiple configurations. * * @version $Id: TestNullCompositeConfiguration.java 1224814 2011-12-26 21:15:53Z oheger $ */ public class TestNullCompositeConfiguration { protected PropertiesConfiguration conf1; protected PropertiesConfiguration conf2; protected XMLConfiguration xmlConf; protected CompositeConfiguration cc; /** The File that we test with */ private String testProperties = ConfigurationAssert.getTestFile("test.properties").getAbsolutePath(); private String testProperties2 = ConfigurationAssert.getTestFile("test2.properties").getAbsolutePath(); private String testPropertiesXML = ConfigurationAssert.getTestFile("test.xml").getAbsolutePath(); @Before public void setUp() throws Exception { cc = new CompositeConfiguration(); conf1 = new PropertiesConfiguration(testProperties); conf2 = new PropertiesConfiguration(testProperties2); xmlConf = new XMLConfiguration(new File(testPropertiesXML)); cc.setThrowExceptionOnMissing(false); } @Test public void testThrowExceptionOnMissing() { assertFalse("Throw Exception Property is set!", cc.isThrowExceptionOnMissing()); } @Test public void testAddRemoveConfigurations() throws Exception { cc.addConfiguration(conf1); assertEquals(2, cc.getNumberOfConfigurations()); cc.addConfiguration(conf1); assertEquals(2, cc.getNumberOfConfigurations()); cc.addConfiguration(conf2); assertEquals(3, cc.getNumberOfConfigurations()); cc.removeConfiguration(conf1); assertEquals(2, cc.getNumberOfConfigurations()); cc.clear(); assertEquals(1, cc.getNumberOfConfigurations()); } @Test public void testGetPropertyWIncludes() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(conf2); List l = cc.getList("packages"); assertTrue(l.contains("packagea")); } @Test public void testGetProperty() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(conf2); assertEquals("Make sure we get the property from conf1 first", "test.properties", cc.getString("propertyInOrder")); cc.clear(); cc.addConfiguration(conf2); cc.addConfiguration(conf1); assertEquals("Make sure we get the property from conf2 first", "test2.properties", cc.getString("propertyInOrder")); } @Test public void testCantRemoveMemoryConfig() throws Exception { cc.clear(); assertEquals(1, cc.getNumberOfConfigurations()); Configuration internal = cc.getConfiguration(0); cc.removeConfiguration(internal); assertEquals(1, cc.getNumberOfConfigurations()); } @Test public void testGetPropertyMissing() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(conf2); assertNull("Bogus property is not null!", cc.getString("bogus.property")); assertTrue("Should be false", !cc.getBoolean("test.missing.boolean", false)); assertTrue("Should be true", cc.getBoolean("test.missing.boolean.true", true)); } @Test public void testMultipleTypesOfConfigs() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); assertEquals("Make sure we get the property from conf1 first", 1, cc.getInt("test.short")); cc.clear(); cc.addConfiguration(xmlConf); cc.addConfiguration(conf1); assertEquals("Make sure we get the property from xml", 8, cc.getInt("test.short")); } @Test public void testPropertyExistsInOnlyOneConfig() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); assertEquals("value", cc.getString("element")); } /** * Tests getting a default when the key doesn't exist */ @Test public void testDefaultValueWhenKeyMissing() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); assertEquals("default", cc.getString("bogus", "default")); assertTrue(1.4 == cc.getDouble("bogus", 1.4)); assertTrue(1.4 == cc.getDouble("bogus", 1.4)); } @Test public void testGettingConfiguration() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); assertEquals(PropertiesConfiguration.class, cc.getConfiguration(0).getClass()); assertEquals(XMLConfiguration.class, cc.getConfiguration(1).getClass()); } /** * Tests setting values. These are set in memory mode only! */ @Test public void testClearingProperty() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); cc.clearProperty("test.short"); assertTrue("Make sure test.short is gone!", !cc.containsKey("test.short")); } /** * Tests adding values. Make sure they _DON'T_ override any other properties but add to the * existing properties and keep sequence */ @Test public void testAddingProperty() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); String[] values = cc.getStringArray("test.short"); assertEquals("Number of values before add is wrong!", 1, values.length); assertEquals("First Value before add is wrong", "1", values[0]); cc.addProperty("test.short", "88"); values = cc.getStringArray("test.short"); assertEquals("Number of values is wrong!", 2, values.length); assertEquals("First Value is wrong", "1", values[0]); assertEquals("Third Value is wrong", "88", values[1]); } /** * Tests setting values. These are set in memory mode only! */ @Test public void testSettingMissingProperty() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); cc.setProperty("my.new.property", "supernew"); assertEquals("supernew", cc.getString("my.new.property")); } /** * Tests retrieving subsets of configurations */ @Test public void testGettingSubset() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); Configuration subset = null; subset = cc.subset("test"); assertNotNull(subset); assertFalse("Shouldn't be empty", subset.isEmpty()); assertEquals("Make sure the initial loaded configs subset overrides any later add configs subset", "1", subset.getString("short")); cc.setProperty("test.short", "43"); subset = cc.subset("test"); assertEquals("Make sure the initial loaded configs subset overrides any later add configs subset", "43", subset.getString("short")); } /** * Tests subsets and still can resolve elements */ @Test public void testSubsetCanResolve() throws Exception { cc = new CompositeConfiguration(); final BaseConfiguration config = new BaseConfiguration(); config.addProperty("subset.tempfile", "${java.io.tmpdir}/file.tmp"); cc.addConfiguration(config); cc.addConfiguration(ConfigurationConverter.getConfiguration(System.getProperties())); Configuration subset = cc.subset("subset"); assertEquals(System.getProperty("java.io.tmpdir") + "/file.tmp", subset.getString("tempfile")); } /** * Tests {@code List} parsing. */ @Test public void testList() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); List packages = cc.getList("packages"); // we should get 3 packages here assertEquals(3, packages.size()); List defaultList = new ArrayList(); defaultList.add("1"); defaultList.add("2"); packages = cc.getList("packages.which.dont.exist", defaultList); // we should get 2 packages here assertEquals(2, packages.size()); } /** * Tests {@code String} array parsing. */ @Test public void testStringArray() throws Exception { cc.addConfiguration(conf1); cc.addConfiguration(xmlConf); String[] packages = cc.getStringArray("packages"); // we should get 3 packages here assertEquals(3, packages.length); packages = cc.getStringArray("packages.which.dont.exist"); // we should get 0 packages here assertEquals(0, packages.length); } @Test public void testGetList() { Configuration conf1 = new BaseConfiguration(); conf1.addProperty("array", "value1"); conf1.addProperty("array", "value2"); Configuration conf2 = new BaseConfiguration(); conf2.addProperty("array", "value3"); conf2.addProperty("array", "value4"); cc.addConfiguration(conf1); cc.addConfiguration(conf2); // check the composite 'array' property List list = cc.getList("array"); assertNotNull("null list", list); assertEquals("list size", 2, list.size()); assertTrue("'value1' not found in the list", list.contains("value1")); assertTrue("'value2' not found in the list", list.contains("value2")); // add an element to the list in the composite configuration cc.addProperty("array", "value5"); // test the new list list = cc.getList("array"); assertNotNull("null list", list); assertEquals("list size", 3, list.size()); assertTrue("'value1' not found in the list", list.contains("value1")); assertTrue("'value2' not found in the list", list.contains("value2")); assertTrue("'value5' not found in the list", list.contains("value5")); } @Test public void testGetVector() { Configuration conf1 = new BaseConfiguration(); conf1.addProperty("array", "value1"); conf1.addProperty("array", "value2"); Configuration conf2 = new BaseConfiguration(); conf2.addProperty("array", "value3"); conf2.addProperty("array", "value4"); cc.addConfiguration(conf1); cc.addConfiguration(conf2); // add an element to the vector in the composite configuration cc.addProperty("array", "value5"); List list = cc.getList("array"); assertEquals("Wrong number of elements", 3, list.size()); assertEquals("Wrong element 1", "value1", list.get(0)); assertEquals("Wrong element 2", "value2", list.get(1)); assertEquals("Wrong element 3", "value5", list.get(2)); } /** * Tests {@code getKeys()} preserves the order */ @Test public void testGetKeysPreservesOrder() throws Exception { cc.addConfiguration(conf1); List orderedList = new ArrayList(); for (Iterator keys = conf1.getKeys(); keys.hasNext();) { orderedList.add(keys.next()); } List iteratedList = new ArrayList(); for (Iterator keys = cc.getKeys(); keys.hasNext();) { iteratedList.add(keys.next()); } assertEquals(orderedList.size(), iteratedList.size()); for (int i = 0; i < orderedList.size(); i++) { assertEquals(orderedList.get(i), iteratedList.get(i)); } } /** * Tests {@code getKeys(String key)} preserves the order */ @Test public void testGetKeys2PreservesOrder() throws Exception { cc.addConfiguration(conf1); List orderedList = new ArrayList(); for (Iterator keys = conf1.getKeys("test"); keys.hasNext();) { orderedList.add(keys.next()); } List iteratedList = new ArrayList(); for (Iterator keys = cc.getKeys("test"); keys.hasNext();) { iteratedList.add(keys.next()); } assertEquals(orderedList.size(), iteratedList.size()); for (int i = 0; i < orderedList.size(); i++) { assertEquals(orderedList.get(i), iteratedList.get(i)); } } @Test public void testGetStringWithDefaults() { BaseConfiguration defaults = new BaseConfiguration(); defaults.addProperty("default", "default string"); Configuration c = new CompositeConfiguration(defaults); c.addProperty("string", "test string"); assertEquals("test string", c.getString("string")); assertNull("XXX should have been null!", c.getString("XXX")); //test defaults assertEquals( "test string", c.getString("string", "some default value")); assertEquals("default string", c.getString("default")); assertEquals( "default string", c.getString("default", "some default value")); assertEquals( "some default value", c.getString("XXX", "some default value")); } @Test public void testCheckingInMemoryConfiguration() throws Exception { String TEST_KEY = "testKey"; Configuration defaults = new PropertiesConfiguration(); defaults.setProperty(TEST_KEY, "testValue"); Configuration testConfiguration = new CompositeConfiguration(defaults); assertTrue(testConfiguration.containsKey(TEST_KEY)); assertFalse(testConfiguration.isEmpty()); boolean foundTestKey = false; Iterator i = testConfiguration.getKeys(); for (; i.hasNext();) { String key = i.next(); if (key.equals(TEST_KEY)) { foundTestKey = true; } } assertTrue(foundTestKey); testConfiguration.clearProperty(TEST_KEY); assertFalse(testConfiguration.containsKey(TEST_KEY)); } } ././@LongLink100644 0 0 161 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestNullJNDIEnvironmentValues.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestNullJNDIEnvironmen100644 10456 12232154104 33466 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Iterator; import org.junit.Before; import org.junit.Test; public class TestNullJNDIEnvironmentValues { private JNDIConfiguration conf = null; @Before public void setUp() throws Exception { System.setProperty("java.naming.factory.initial", TestJNDIConfiguration.CONTEXT_FACTORY); conf = new JNDIConfiguration(); conf.setThrowExceptionOnMissing(false); } @Test public void testThrowExceptionOnMissing() { assertFalse("Throw Exception Property is set!", conf.isThrowExceptionOnMissing()); } @Test public void testSimpleGet() throws Exception { String s = conf.getString("test.key"); assertEquals("jndivalue", s); } @Test public void testMoreGets() throws Exception { String s = conf.getString("test.key"); assertEquals("jndivalue", s); assertEquals("jndivalue2", conf.getString("test.key2")); assertEquals(1, conf.getShort("test.short")); } @Test public void testGetMissingKey() throws Exception { assertNull("Missing Key is not null!", conf.getString("test.imaginarykey")); } @Test public void testGetMissingKeyWithDefault() throws Exception { String result = conf.getString("test.imaginarykey", "bob"); assertEquals("bob", result); } @Test public void testContainsKey() throws Exception { assertTrue(conf.containsKey("test.key")); assertTrue(!conf.containsKey("test.imaginarykey")); } @Test public void testClearProperty() { assertNotNull("null short for the 'test.short' key", conf.getShort("test.short", null)); conf.clearProperty("test.short"); assertNull("'test.short' property not cleared", conf.getShort("test.short", null)); } @Test public void testIsEmpty() { assertFalse("the configuration shouldn't be empty", conf.isEmpty()); } @Test public void testGetKeys() throws Exception { boolean found = false; Iterator it = conf.getKeys(); assertTrue("no key found", it.hasNext()); while (it.hasNext() && !found) { found = "test.boolean".equals(it.next()); } assertTrue("'test.boolean' key not found", found); } @Test public void testGetKeysWithUnknownPrefix() { // test for a unknown prefix Iterator it = conf.getKeys("foo.bar"); assertFalse("no key should be found", it.hasNext()); } @Test public void testGetKeysWithExistingPrefix() { // test for an existing prefix Iterator it = conf.getKeys("test"); boolean found = false; while (it.hasNext() && !found) { found = "test.boolean".equals(it.next()); } assertTrue("'test.boolean' key not found", found); } @Test public void testGetKeysWithKeyAsPrefix() { // test for a prefix matching exactly the key of a property Iterator it = conf.getKeys("test.boolean"); boolean found = false; while (it.hasNext() && !found) { found = "test.boolean".equals(it.next()); } assertTrue("'test.boolean' key not found", found); } } ././@LongLink100644 0 0 163 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPatternSubtreeConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPatternSubtreeConf100644 4654 12232154104 33606 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertTrue; import java.io.File; import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.junit.Before; import org.junit.Test; /** * Unit test for simple MultiConfigurationTest. * * @version $Id: TestPatternSubtreeConfiguration.java 1224818 2011-12-26 21:20:17Z oheger $ */ public class TestPatternSubtreeConfiguration { private static String CONFIG_FILE = "target/test-classes/testPatternSubtreeConfig.xml"; private static String PATTERN = "BusinessClient[@name='${sys:Id}']"; private XMLConfiguration conf; @Before public void setUp() throws Exception { conf = new XMLConfiguration(); conf.setFile(new File(CONFIG_FILE)); conf.load(); } /** * Rigourous Test :-) */ @Test public void testMultiConfiguration() { //set up a reloading strategy FileChangedReloadingStrategy strategy = new FileChangedReloadingStrategy(); strategy.setRefreshDelay(10000); PatternSubtreeConfigurationWrapper config = new PatternSubtreeConfigurationWrapper(this.conf, PATTERN); config.setReloadingStrategy(strategy); config.setExpressionEngine(new XPathExpressionEngine()); System.setProperty("Id", "1001"); assertTrue(config.getInt("rowsPerPage") == 15); System.setProperty("Id", "1002"); assertTrue(config.getInt("rowsPerPage") == 25); System.setProperty("Id", "1003"); assertTrue(config.getInt("rowsPerPage") == 35); } }././@LongLink100644 0 0 157 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPropertiesConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPropertiesConfigur100644 131152 12232154104 33714 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.BufferedReader; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.PrintWriter; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.io.Writer; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.net.URLStreamHandler; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; import org.apache.commons.lang.SystemUtils; import org.junit.Before; import org.junit.Test; /** * Test for loading and saving properties files. * * @version $Id: TestPropertiesConfiguration.java 1534402 2013-10-21 22:35:52Z henning $ */ public class TestPropertiesConfiguration { /** Constant for a test property name.*/ private static final String PROP_NAME = "testProperty"; /** Constant for a test property value.*/ private static final String PROP_VALUE = "value"; /** Constant for the line break character. */ private static final String CR = System.getProperty("line.separator"); /** The configuration to be tested.*/ private PropertiesConfiguration conf; /** The File that we test with */ private static String testProperties = ConfigurationAssert.getTestFile("test.properties").getAbsolutePath(); private static String testBasePath = ConfigurationAssert.TEST_DIR.getAbsolutePath(); private static String testBasePath2 = ConfigurationAssert.TEST_DIR.getParentFile().getAbsolutePath(); private static File testSavePropertiesFile = ConfigurationAssert.getOutFile("testsave.properties"); @Before public void setUp() throws Exception { conf = new PropertiesConfiguration(testProperties); // remove the test save file if it exists if (testSavePropertiesFile.exists()) { assertTrue("Test output file could not be deleted", testSavePropertiesFile.delete()); } } @Test public void testLoad() throws Exception { String loaded = conf.getString("configuration.loaded"); assertEquals("true", loaded); } /** * Tests if properties can be appended by simply calling load() another * time. */ @Test public void testAppend() throws Exception { File file2 = ConfigurationAssert.getTestFile("threesome.properties"); conf.load(file2); assertEquals("aaa", conf.getString("test.threesome.one")); assertEquals("true", conf.getString("configuration.loaded")); } /** * Tests that empty properties are treated as the empty string * (rather than as null). */ @Test public void testEmpty() throws Exception { String empty = conf.getString("test.empty"); assertNotNull(empty); assertEquals("", empty); } /** * Tests that references to other properties work */ @Test public void testReference() throws Exception { assertEquals("baseextra", conf.getString("base.reference")); } /** * test if includes properties get loaded too */ @Test public void testLoadInclude() throws Exception { String loaded = conf.getString("include.loaded"); assertEquals("true", loaded); } /** * test if includes properties from interpolated file * name get loaded */ @Test public void testLoadIncludeInterpol() throws Exception { String loaded = conf.getString("include.interpol.loaded"); assertEquals("true", loaded); } /** * Tests whether include files can be resolved if a configuration file is * read from a reader. */ @Test public void testLoadIncludeFromReader() throws ConfigurationException, IOException { StringReader in = new StringReader(PropertiesConfiguration.getInclude() + " = " + ConfigurationAssert.getTestURL("include.properties")); conf = new PropertiesConfiguration(); conf.load(in); assertEquals("Include file not loaded", "true", conf.getString("include.loaded")); } /** * Tests whether include files can be disabled. */ @Test public void testDisableIncludes() throws ConfigurationException, IOException { String content = PropertiesConfiguration.getInclude() + " = nonExistingIncludeFile" + CR + PROP_NAME + " = " + PROP_VALUE + CR; StringReader in = new StringReader(content); conf = new PropertiesConfiguration(); conf.setIncludesAllowed(false); conf.load(in); assertEquals("Data not loaded", PROP_VALUE, conf.getString(PROP_NAME)); } @Test public void testSetInclude() throws Exception { // change the include key PropertiesConfiguration.setInclude("import"); // load the configuration PropertiesConfiguration conf = new PropertiesConfiguration(); conf.load(ConfigurationAssert.getTestFile("test.properties")); // restore the previous value for the other tests PropertiesConfiguration.setInclude("include"); assertNull(conf.getString("include.loaded")); } /** * Tests {@code List} parsing. */ @Test public void testList() throws Exception { List packages = conf.getList("packages"); // we should get 3 packages here assertEquals(3, packages.size()); } @Test public void testSave() throws Exception { // add an array of strings to the configuration conf.addProperty("string", "value1"); List list = new ArrayList(); for (int i = 1; i < 5; i++) { list.add("value" + i); } conf.addProperty("array", list); // save the configuration String filename = testSavePropertiesFile.getAbsolutePath(); conf.save(filename); assertTrue("The saved file doesn't exist", testSavePropertiesFile.exists()); // read the configuration and compare the properties PropertiesConfiguration checkConfig = new PropertiesConfiguration(filename); ConfigurationAssert.assertEquals(conf, checkConfig); // Save it again, verifying a save with a filename works. checkConfig.save(); } @Test public void testSaveToCustomURL() throws Exception { // save the configuration to a custom URL URL url = new URL("foo", "", 0, "./target/testsave-custom-url.properties", new FileURLStreamHandler()); conf.save(url); // reload the configuration Configuration config2 = new PropertiesConfiguration(url); assertEquals("true", config2.getString("configuration.loaded")); } @Test public void testInMemoryCreatedSave() throws Exception { PropertiesConfiguration pc = new PropertiesConfiguration(); // add an array of strings to the configuration pc.addProperty("string", "value1"); List list = new ArrayList(); for (int i = 1; i < 5; i++) { list.add("value" + i); } pc.addProperty("array", list); // save the configuration String filename = testSavePropertiesFile.getAbsolutePath(); pc.save(filename); assertTrue("The saved file doesn't exist", testSavePropertiesFile.exists()); // read the configuration and compare the properties PropertiesConfiguration checkConfig = new PropertiesConfiguration(filename); ConfigurationAssert.assertEquals(pc, checkConfig); // Save it again, verifying a save with a filename works. checkConfig.save(); } /** * Tests saving a configuration when delimiter parsing is disabled. */ @Test public void testSaveWithDelimiterParsingDisabled() throws ConfigurationException { conf.clear(); conf.setDelimiterParsingDisabled(true); conf.addProperty("test.list", "a,b,c"); conf.addProperty("test.dirs", "C:\\Temp\\,D:\\Data\\"); conf.save(testSavePropertiesFile); PropertiesConfiguration checkConfig = new PropertiesConfiguration(); checkConfig.setDelimiterParsingDisabled(true); checkConfig.setFile(testSavePropertiesFile); checkConfig.load(); ConfigurationAssert.assertEquals(conf, checkConfig); } @Test(expected = ConfigurationException.class) public void testSaveMissingFilename() throws ConfigurationException { PropertiesConfiguration pc = new PropertiesConfiguration(); pc.save(); } /** * Tests if the base path is taken into account by the save() method. * @throws Exception if an error occurs */ @Test public void testSaveWithBasePath() throws Exception { conf.setProperty("test", "true"); conf.setBasePath(testSavePropertiesFile.getParentFile().toURI().toURL() .toString()); conf.setFileName(testSavePropertiesFile.getName()); conf.save(); assertTrue(testSavePropertiesFile.exists()); } /** * Tests whether the escape character for list delimiters can be itself * escaped and survives a save operation. */ @Test public void testSaveEscapedEscapingCharacter() throws ConfigurationException { conf.addProperty("test.dirs", "C:\\Temp\\\\,D:\\Data\\\\,E:\\Test\\"); List dirs = conf.getList("test.dirs"); assertEquals("Wrong number of list elements", 3, dirs.size()); conf.save(testSavePropertiesFile); PropertiesConfiguration checkConfig = new PropertiesConfiguration( testSavePropertiesFile); ConfigurationAssert.assertEquals(conf, checkConfig); } @Test public void testLoadViaProperty() throws Exception { PropertiesConfiguration pc = new PropertiesConfiguration(); pc.setFileName(testProperties); pc.load(); assertTrue("Make sure we have multiple keys", pc.getBoolean("test.boolean")); } @Test public void testLoadViaPropertyWithBasePath() throws Exception { PropertiesConfiguration pc = new PropertiesConfiguration(); pc.setBasePath(testBasePath); pc.setFileName("test.properties"); pc.load(); assertTrue("Make sure we have multiple keys", pc.getBoolean("test.boolean")); } @Test public void testLoadViaPropertyWithBasePath2() throws Exception { PropertiesConfiguration pc = new PropertiesConfiguration(); pc.setBasePath(testBasePath2); pc.setFileName("test.properties"); pc.load(); assertTrue("Make sure we have multiple keys", pc.getBoolean("test.boolean")); pc = new PropertiesConfiguration(); pc.setBasePath(testBasePath2); pc.setFileName("test.properties"); pc.load(); assertTrue("Make sure we have multiple keys", pc.getBoolean("test.boolean")); } @Test public void testLoadFromFile() throws Exception { File file = ConfigurationAssert.getTestFile("test.properties"); conf = new PropertiesConfiguration(file); assertEquals("true", conf.getString("configuration.loaded")); } @Test(expected = ConfigurationException.class) public void testLoadUnexistingFile() throws ConfigurationException { conf = new PropertiesConfiguration("Unexisting file"); } /** * Tests to load a file with enabled auto save mode. */ @Test public void testLoadWithAutoSave() throws Exception { setUpSavedProperties(); } /** * Tests the auto save functionality when an existing property is modified. */ @Test public void testLoadWithAutoSaveAndSetExisting() throws Exception { setUpSavedProperties(); conf.setProperty("a", "moreThanOne"); checkSavedConfig(); } /** * Tests the auto save functionality when a new property is added using the * setProperty() method. */ @Test public void testLoadWithAutoSaveAndSetNew() throws Exception { setUpSavedProperties(); conf.setProperty("d", "four"); checkSavedConfig(); } /** * Tests the auto save functionality when a new property is added using the * addProperty() method. */ @Test public void testLoadWithAutoSaveAndAdd() throws Exception { setUpSavedProperties(); conf.addProperty("d", "four"); checkSavedConfig(); } /** * Tests the auto save functionality when a property is removed. */ @Test public void testLoadWithAutoSaveAndClear() throws Exception { setUpSavedProperties(); conf.clearProperty("c"); PropertiesConfiguration checkConfig = checkSavedConfig(); assertFalse("The saved configuration contain the key '" + "c" + "'", checkConfig.containsKey("c")); } /** * Creates a properties file on disk. Used for testing load and save * operations. * * @throws IOException if an I/O error occurs */ private void setUpSavedProperties() throws IOException, ConfigurationException { PrintWriter out = null; try { out = new PrintWriter(new FileWriter(testSavePropertiesFile)); out.println("a = one"); out.println("b = two"); out.println("c = three"); out.close(); out = null; conf = new PropertiesConfiguration(); conf.setAutoSave(true); conf.setFile(testSavePropertiesFile); conf.load(); assertEquals("one", conf.getString("a")); assertEquals("two", conf.getString("b")); assertEquals("three", conf.getString("c")); } finally { if (out != null) { out.close(); } } } /** * Helper method for testing a saved configuration. Reads in the file using * a new instance and compares this instance with the original one. * * @return the newly created configuration instance * @throws ConfigurationException if an error occurs */ private PropertiesConfiguration checkSavedConfig() throws ConfigurationException { PropertiesConfiguration checkConfig = new PropertiesConfiguration(testSavePropertiesFile); ConfigurationAssert.assertEquals(conf, checkConfig); return checkConfig; } @Test public void testGetStringWithEscapedChars() { String property = conf.getString("test.unescape"); assertEquals("String with escaped characters", "This \n string \t contains \" escaped \\ characters", property); } @Test public void testGetStringWithEscapedComma() { String property = conf.getString("test.unescape.list-separator"); assertEquals("String with an escaped list separator", "This string contains , an escaped list separator", property); } @Test public void testUnescapeJava() { assertEquals("test\\,test", PropertiesConfiguration.unescapeJava("test\\,test", ',')); } @Test public void testEscapedKey() throws Exception { PropertiesConfiguration conf = new PropertiesConfiguration(); conf.load(new StringReader("\\u0066\\u006f\\u006f=bar")); assertEquals("value of the 'foo' property", "bar", conf.getString("foo")); } @Test public void testMixedArray() { String[] array = conf.getStringArray("test.mixed.array"); assertEquals("array length", 4, array.length); assertEquals("1st element", "a", array[0]); assertEquals("2nd element", "b", array[1]); assertEquals("3rd element", "c", array[2]); assertEquals("4th element", "d", array[3]); } @Test public void testMultilines() { String property = "This is a value spread out across several adjacent " + "natural lines by escaping the line terminator with " + "a backslash character."; assertEquals("'test.multilines' property", property, conf.getString("test.multilines")); } @Test public void testChangingDefaultListDelimiter() throws Exception { PropertiesConfiguration pc = new PropertiesConfiguration(testProperties); assertEquals(4, pc.getList("test.mixed.array").size()); char delimiter = PropertiesConfiguration.getDefaultListDelimiter(); PropertiesConfiguration.setDefaultListDelimiter('^'); pc = new PropertiesConfiguration(testProperties); assertEquals(2, pc.getList("test.mixed.array").size()); PropertiesConfiguration.setDefaultListDelimiter(delimiter); } @Test public void testChangingListDelimiter() throws Exception { PropertiesConfiguration pc1 = new PropertiesConfiguration(testProperties); assertEquals(4, pc1.getList("test.mixed.array").size()); PropertiesConfiguration pc2 = new PropertiesConfiguration(); pc2.setListDelimiter('^'); pc2.setFileName(testProperties); pc2.load(); assertEquals("Should obtain the first value", "a", pc2.getString("test.mixed.array")); assertEquals(2, pc2.getList("test.mixed.array").size()); } @Test public void testDisableListDelimiter() throws Exception { PropertiesConfiguration pc1 = new PropertiesConfiguration(testProperties); assertEquals(4, pc1.getList("test.mixed.array").size()); PropertiesConfiguration pc2 = new PropertiesConfiguration(); pc2.setDelimiterParsingDisabled(true); pc2.setFileName(testProperties); pc2.load(); assertEquals(2, pc2.getList("test.mixed.array").size()); } /** * Tests escaping of an end of line with a backslash. */ @Test public void testNewLineEscaping() { List list = conf.getList("test.path"); assertEquals(3, list.size()); assertEquals("C:\\path1\\", list.get(0)); assertEquals("C:\\path2\\", list.get(1)); assertEquals("C:\\path3\\complex\\test\\", list.get(2)); } /** * Tests if included files are loaded when the source lies in the class path. */ @Test public void testLoadIncludeFromClassPath() throws ConfigurationException { conf = new PropertiesConfiguration("test.properties"); assertEquals("true", conf.getString("include.loaded")); } /** * Test if the lines starting with # or ! are properly ignored. */ @Test public void testComment() { assertFalse("comment line starting with '#' parsed as a property", conf.containsKey("#comment")); assertFalse("comment line starting with '!' parsed as a property", conf.containsKey("!comment")); } /** * Check that key/value separators can be part of a key. */ @Test public void testEscapedKeyValueSeparator() { assertEquals("Escaped separator '=' not supported in keys", "foo", conf.getProperty("test.separator=in.key")); assertEquals("Escaped separator ':' not supported in keys", "bar", conf.getProperty("test.separator:in.key")); assertEquals("Escaped separator '\\t' not supported in keys", "foo", conf.getProperty("test.separator\tin.key")); assertEquals("Escaped separator '\\f' not supported in keys", "bar", conf.getProperty("test.separator\fin.key")); assertEquals("Escaped separator ' ' not supported in keys" , "foo", conf.getProperty("test.separator in.key")); } /** * Test all acceptable key/value separators ('=', ':' or white spaces). */ @Test public void testKeyValueSeparators() { assertEquals("equal separator not properly parsed", "foo", conf.getProperty("test.separator.equal")); assertEquals("colon separator not properly parsed", "foo", conf.getProperty("test.separator.colon")); assertEquals("tab separator not properly parsed", "foo", conf.getProperty("test.separator.tab")); assertEquals("formfeed separator not properly parsed", "foo", conf.getProperty("test.separator.formfeed")); assertEquals("whitespace separator not properly parsed", "foo", conf.getProperty("test.separator.whitespace")); } /** * Tests including properties when they are loaded from a nested directory * structure. */ @SuppressWarnings("deprecation") @Test public void testIncludeInSubDir() throws ConfigurationException { ConfigurationFactory factory = new ConfigurationFactory("conf/testFactoryPropertiesInclude.xml"); Configuration config = factory.getConfiguration(); assertTrue(config.getBoolean("deeptest")); assertTrue(config.getBoolean("deepinclude")); assertFalse(config.containsKey("deeptestinvalid")); } /** * Tests whether the correct line separator is used. */ @Test public void testLineSeparator() throws ConfigurationException { final String EOL = System.getProperty("line.separator"); conf = new PropertiesConfiguration(); conf.setHeader("My header"); conf.setProperty("prop", "value"); StringWriter out = new StringWriter(); conf.save(out); String content = out.toString(); assertTrue("Header could not be found", content.indexOf("# My header" + EOL + EOL) == 0); assertTrue("Property could not be found", content.indexOf("prop = value" + EOL) > 0); } /** * Tests what happens if a reloading strategy's reloadingRequired() * implementation accesses methods of the configuration that in turn cause a reload. */ @Test public void testReentrantReload() { conf.setProperty("shouldReload", Boolean.FALSE); conf.setReloadingStrategy(new FileChangedReloadingStrategy() { @Override public boolean reloadingRequired() { return configuration.getBoolean("shouldReload"); } }); assertFalse("Property has wrong value", conf.getBoolean("shouldReload")); } /** * Tests accessing the layout object. */ @Test public void testGetLayout() { PropertiesConfigurationLayout layout = conf.getLayout(); assertNotNull("Layout is null", layout); assertSame("Different object returned", layout, conf.getLayout()); conf.setLayout(null); PropertiesConfigurationLayout layout2 = conf.getLayout(); assertNotNull("Layout 2 is null", layout2); assertNotSame("Same object returned", layout, layout2); } /** * Tests the propertyLoaded() method for a simple property. */ @Test public void testPropertyLoaded() throws ConfigurationException { DummyLayout layout = new DummyLayout(conf); conf.setLayout(layout); conf.propertyLoaded("layoutLoadedProperty", "yes"); assertEquals("Layout's load() was called", 0, layout.loadCalls); assertEquals("Property not added", "yes", conf.getString("layoutLoadedProperty")); } /** * Tests the propertyLoaded() method for an include property. */ @Test public void testPropertyLoadedInclude() throws ConfigurationException { DummyLayout layout = new DummyLayout(conf); conf.setLayout(layout); conf.propertyLoaded(PropertiesConfiguration.getInclude(), "testClasspath.properties,testEqual.properties"); assertEquals("Layout's load() was not correctly called", 2, layout.loadCalls); assertFalse("Property was added", conf.containsKey(PropertiesConfiguration.getInclude())); } /** * Tests propertyLoaded() for an include property, when includes are * disabled. */ @Test public void testPropertyLoadedIncludeNotAllowed() throws ConfigurationException { DummyLayout layout = new DummyLayout(conf); conf.setLayout(layout); conf.setIncludesAllowed(false); conf.propertyLoaded(PropertiesConfiguration.getInclude(), "testClassPath.properties,testEqual.properties"); assertEquals("Layout's load() was called", 0, layout.loadCalls); assertFalse("Property was added", conf.containsKey(PropertiesConfiguration.getInclude())); } /** * Tests whether comment lines are correctly detected. */ @Test public void testIsCommentLine() { assertTrue("Comment not detected", PropertiesConfiguration.isCommentLine("# a comment")); assertTrue("Alternative comment not detected", PropertiesConfiguration.isCommentLine("! a comment")); assertTrue("Comment with no space not detected", PropertiesConfiguration.isCommentLine("#a comment")); assertTrue("Comment with leading space not detected", PropertiesConfiguration.isCommentLine(" ! a comment")); assertFalse("Wrong comment", PropertiesConfiguration.isCommentLine(" a#comment")); } /** * Tests whether a properties configuration can be successfully cloned. It * is especially checked whether the layout object is taken into account. */ @Test public void testClone() throws ConfigurationException { PropertiesConfiguration copy = (PropertiesConfiguration) conf.clone(); assertNotSame("Copy has same layout object", conf.getLayout(), copy.getLayout()); assertEquals("Wrong number of event listeners for original", 1, conf.getConfigurationListeners().size()); assertEquals("Wrong number of event listeners for clone", 1, copy.getConfigurationListeners().size()); assertSame("Wrong event listener for original", conf.getLayout(), conf.getConfigurationListeners().iterator().next()); assertSame("Wrong event listener for clone", copy.getLayout(), copy.getConfigurationListeners().iterator().next()); StringWriter outConf = new StringWriter(); conf.save(outConf); StringWriter outCopy = new StringWriter(); copy.save(outCopy); assertEquals("Output from copy is different", outConf.toString(), outCopy.toString()); } /** * Tests the clone() method when no layout object exists yet. */ @Test public void testCloneNullLayout() { conf = new PropertiesConfiguration(); PropertiesConfiguration copy = (PropertiesConfiguration) conf.clone(); assertNotSame("Layout objects are the same", conf.getLayout(), copy.getLayout()); } /** * Tests saving a file-based configuration to a HTTP server. */ @Test public void testSaveToHTTPServerSuccess() throws Exception { MockHttpURLStreamHandler handler = new MockHttpURLStreamHandler( HttpURLConnection.HTTP_OK, testSavePropertiesFile); URL url = new URL(null, "http://jakarta.apache.org", handler); conf.save(url); MockHttpURLConnection con = handler.getMockConnection(); assertTrue("Wrong output flag", con.getDoOutput()); assertEquals("Wrong method", "PUT", con.getRequestMethod()); PropertiesConfiguration checkConfig = new PropertiesConfiguration( testSavePropertiesFile); ConfigurationAssert.assertEquals(conf, checkConfig); } /** * Tests saving a file-based configuration to a HTTP server when the server * reports a failure. This should cause an exception. */ @Test public void testSaveToHTTPServerFail() throws Exception { MockHttpURLStreamHandler handler = new MockHttpURLStreamHandler( HttpURLConnection.HTTP_BAD_REQUEST, testSavePropertiesFile); URL url = new URL(null, "http://jakarta.apache.org", handler); try { conf.save(url); fail("Response code was not checked!"); } catch (ConfigurationException cex) { assertTrue("Wrong root cause: " + cex, cex.getCause() instanceof IOException); } } /** * Test the creation of a file containing a '#' in its name. This test is * skipped on Java 1.3 as it always fails. */ @Test public void testFileWithSharpSymbol() throws Exception { if (SystemUtils.isJavaVersionAtLeast(1.4f)) { File file = new File("target/sharp#1.properties"); file.createNewFile(); PropertiesConfiguration conf = new PropertiesConfiguration(file); conf.save(); assertTrue("Missing file " + file, file.exists()); } } /** * Tests initializing a properties configuration from a non existing file. * There was a bug, which caused properties getting lost when later save() * is called. */ @Test public void testInitFromNonExistingFile() throws ConfigurationException { final String testProperty = "test.successfull"; conf = new PropertiesConfiguration(testSavePropertiesFile); conf.addProperty(testProperty, Boolean.TRUE); conf.save(); PropertiesConfiguration checkConfig = new PropertiesConfiguration( testSavePropertiesFile); assertTrue("Test property not found", checkConfig .getBoolean(testProperty)); } /** * Tests copying another configuration into the test configuration. This * test ensures that the layout object is informed about the newly added * properties. */ @Test public void testCopyAndSave() throws ConfigurationException { Configuration copyConf = setUpCopyConfig(); conf.copy(copyConf); checkCopiedConfig(copyConf); } /** * Tests appending a configuration to the test configuration. Again it has * to be ensured that the layout object is correctly updated. */ @Test public void testAppendAndSave() throws ConfigurationException { Configuration copyConf = setUpCopyConfig(); conf.append(copyConf); checkCopiedConfig(copyConf); } /** * Tests adding properties through a DataConfiguration. This is related to * CONFIGURATION-332. */ @Test public void testSaveWithDataConfig() throws ConfigurationException { conf = new PropertiesConfiguration(testSavePropertiesFile); DataConfiguration dataConfig = new DataConfiguration(conf); dataConfig.setProperty("foo", "bar"); assertEquals("Property not set", "bar", conf.getString("foo")); conf.save(); PropertiesConfiguration config2 = new PropertiesConfiguration( testSavePropertiesFile); assertEquals("Property not saved", "bar", config2.getString("foo")); } /** * Tests whether the correct default encoding is used when loading a * properties file. This test is related to CONFIGURATION-345. */ @Test public void testLoadWithDefaultEncoding() throws ConfigurationException { class PropertiesConfigurationTestImpl extends PropertiesConfiguration { String loadEncoding; public PropertiesConfigurationTestImpl(String fileName) throws ConfigurationException { super(fileName); } @Override public void load(InputStream in, String encoding) throws ConfigurationException { loadEncoding = encoding; super.load(in, encoding); } } PropertiesConfigurationTestImpl testConf = new PropertiesConfigurationTestImpl( testProperties); assertEquals("Default encoding not used", "ISO-8859-1", testConf.loadEncoding); } /** * Tests whether a default IOFactory is set. */ @Test public void testGetIOFactoryDefault() { assertNotNull("No default IO factory", conf.getIOFactory()); } /** * Tests setting the IOFactory to null. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testSetIOFactoryNull() { conf.setIOFactory(null); } /** * Tests setting an IOFactory that uses a specialized reader. */ @Test public void testSetIOFactoryReader() throws ConfigurationException { final int propertyCount = 10; conf.clear(); conf.setIOFactory(new PropertiesConfiguration.IOFactory() { public PropertiesConfiguration.PropertiesReader createPropertiesReader( Reader in, char delimiter) { return new PropertiesReaderTestImpl(in, delimiter, propertyCount); } public PropertiesConfiguration.PropertiesWriter createPropertiesWriter( Writer out, char delimiter) { throw new UnsupportedOperationException("Unexpected call!"); } }); conf.load(); for (int i = 1; i <= propertyCount; i++) { assertEquals("Wrong property value at " + i, PROP_VALUE + i, conf .getString(PROP_NAME + i)); } } /** * Tests setting an IOFactory that uses a specialized writer. */ @Test public void testSetIOFactoryWriter() throws ConfigurationException, IOException { final PropertiesWriterTestImpl testWriter = new PropertiesWriterTestImpl(','); conf.setIOFactory(new PropertiesConfiguration.IOFactory() { public PropertiesConfiguration.PropertiesReader createPropertiesReader( Reader in, char delimiter) { throw new UnsupportedOperationException("Unexpected call!"); } public PropertiesConfiguration.PropertiesWriter createPropertiesWriter( Writer out, char delimiter) { return testWriter; } }); conf.save(new StringWriter()); testWriter.close(); checkSavedConfig(); } /** * Tests that the property separators are retained when saving the * configuration. */ @Test public void testKeepSeparators() throws ConfigurationException, IOException { conf.save(testSavePropertiesFile); final String[] separatorTests = { "test.separator.equal = foo", "test.separator.colon : foo", "test.separator.tab\tfoo", "test.separator.whitespace foo", "test.separator.no.space=foo" }; Set foundLines = new HashSet(); BufferedReader in = new BufferedReader(new FileReader( testSavePropertiesFile)); try { String s; while ((s = in.readLine()) != null) { for (int i = 0; i < separatorTests.length; i++) { if (separatorTests[i].equals(s)) { foundLines.add(s); } } } } finally { in.close(); } assertEquals("No all separators were found: " + foundLines, separatorTests.length, foundLines.size()); } /** * Tests whether properties with slashes in their values can be saved. This * test is related to CONFIGURATION-408. */ @Test public void testSlashEscaping() throws ConfigurationException { conf.setProperty(PROP_NAME, "http://www.apache.org"); StringWriter writer = new StringWriter(); conf.save(writer); String s = writer.toString(); assertTrue("Value not found: " + s, s.indexOf(PROP_NAME + " = http://www.apache.org") >= 0); } /** * Tests whether backslashes are correctly handled if lists are parsed. This * test is related to CONFIGURATION-418. */ @Test public void testBackslashEscapingInLists() throws Exception { checkBackslashList("share2"); checkBackslashList("share1"); } /** * Tests whether a list property is handled correctly if delimiter parsing * is disabled. This test is related to CONFIGURATION-495. */ @Test public void testSetPropertyListWithDelimiterParsingDisabled() throws ConfigurationException { String prop = "delimiterListProp"; conf.setDelimiterParsingDisabled(true); List list = Arrays.asList("val", "val2", "val3"); conf.setProperty(prop, list); conf.setFile(testSavePropertiesFile); conf.save(); conf.clear(); conf.load(); assertEquals("Wrong list property", list, conf.getProperty(prop)); } /** * Tests whether a footer comment is correctly read. */ @Test public void testReadFooterComment() { assertEquals("Wrong footer comment", "\n# This is a foot comment\n", conf.getFooter()); assertEquals("Wrong footer comment from layout", "\nThis is a foot comment\n", conf.getLayout() .getCanonicalFooterCooment(false)); } /** * Tests whether a footer comment is correctly written out. */ @Test public void testWriteFooterComment() throws ConfigurationException, IOException { final String footer = "my footer"; conf.clear(); conf.setProperty(PROP_NAME, PROP_VALUE); conf.setFooter(footer); StringWriter out = new StringWriter(); conf.save(out); assertEquals("Wrong result", PROP_NAME + " = " + PROP_VALUE + CR + "# " + footer + CR, out.toString()); } /** * Helper method for testing the content of a list with elements that * contain backslashes. * * @param key the key */ private void checkBackslashList(String key) { Object prop = conf.getProperty("test." + key); assertTrue("Not a list", prop instanceof List); List list = (List) prop; assertEquals("Wrong number of list elements", 2, list.size()); final String prefix = "\\\\" + key; assertEquals("Wrong element 1", prefix + "a", list.get(0)); assertEquals("Wrong element 2", prefix + "b", list.get(1)); } /** * Creates a configuration that can be used for testing copy operations. * * @return the configuration to be copied */ private Configuration setUpCopyConfig() { final int count = 25; Configuration result = new BaseConfiguration(); for (int i = 1; i <= count; i++) { result.addProperty("copyKey" + i, "copyValue" + i); } return result; } /** * Tests whether the data of a configuration that was copied into the test * configuration is correctly saved. * * @param copyConf the copied configuration * @throws ConfigurationException if an error occurs */ private void checkCopiedConfig(Configuration copyConf) throws ConfigurationException { conf.save(testSavePropertiesFile); PropertiesConfiguration checkConf = new PropertiesConfiguration( testSavePropertiesFile); for (Iterator it = copyConf.getKeys(); it.hasNext();) { String key = it.next(); assertEquals("Wrong value for property " + key, checkConf .getProperty(key), copyConf.getProperty(key)); } } /** * A dummy layout implementation for checking whether certain methods are * correctly called by the configuration. */ static class DummyLayout extends PropertiesConfigurationLayout { /** Stores the number how often load() was called. */ public int loadCalls; public DummyLayout(PropertiesConfiguration config) { super(config); } @Override public void load(Reader in) throws ConfigurationException { loadCalls++; } } /** * A mock implementation of a HttpURLConnection used for testing saving to * a HTTP server. */ static class MockHttpURLConnection extends HttpURLConnection { /** The response code to return.*/ private final int returnCode; /** The output file. The output stream will point to this file.*/ private final File outputFile; protected MockHttpURLConnection(URL u, int respCode, File outFile) { super(u); returnCode = respCode; outputFile = outFile; } @Override public void disconnect() { } @Override public boolean usingProxy() { return false; } @Override public void connect() throws IOException { } @Override public int getResponseCode() throws IOException { return returnCode; } @Override public OutputStream getOutputStream() throws IOException { return new FileOutputStream(outputFile); } } /** * A mock stream handler for working with the mock HttpURLConnection. */ static class MockHttpURLStreamHandler extends URLStreamHandler { /** Stores the response code.*/ private int responseCode; /** Stores the output file.*/ private File outputFile; /** Stores the connection.*/ private MockHttpURLConnection connection; public MockHttpURLStreamHandler(int respCode, File outFile) { responseCode = respCode; outputFile = outFile; } public MockHttpURLConnection getMockConnection() { return connection; } @Override protected URLConnection openConnection(URL u) throws IOException { connection = new MockHttpURLConnection(u, responseCode, outputFile); return connection; } } /** * A test PropertiesReader for testing whether a custom reader can be * injected. This implementation creates a configurable number of synthetic * test properties. */ private static class PropertiesReaderTestImpl extends PropertiesConfiguration.PropertiesReader { /** The number of test properties to be created. */ private final int maxProperties; /** The current number of properties. */ private int propertyCount; public PropertiesReaderTestImpl(Reader reader, char listDelimiter, int maxProps) { super(reader, listDelimiter); assertEquals("Wrong list delimiter", ',', listDelimiter); maxProperties = maxProps; } @Override public String getPropertyName() { return PROP_NAME + propertyCount; } @Override public String getPropertyValue() { return PROP_VALUE + propertyCount; } @Override public boolean nextProperty() throws IOException { propertyCount++; return propertyCount <= maxProperties; } } /** * A test PropertiesWriter for testing whether a custom writer can be * injected. This implementation simply redirects all output into a test * file. */ private static class PropertiesWriterTestImpl extends PropertiesConfiguration.PropertiesWriter { public PropertiesWriterTestImpl(char delimiter) throws IOException { super(new FileWriter(testSavePropertiesFile), delimiter); } } } ././@LongLink100644 0 0 165 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPropertiesConfigurationLayout.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPropertiesConfigur100644 71470 12232154104 33702 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; import java.util.Iterator; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.junit.Before; import org.junit.Test; /** * Test class for PropertiesConfigurationLayout. * * @author Commons * Configuration team * @version $Id: TestPropertiesConfigurationLayout.java 1534402 2013-10-21 22:35:52Z henning $ */ public class TestPropertiesConfigurationLayout { /** Constant for the line break character. */ private static final String CR = System.getProperty("line.separator"); /** Constant for the normalized line break character. */ private static final String CRNORM = "\n"; /** Constant for a test property key. */ static final String TEST_KEY = "myProperty"; /** Constant for a test comment. */ static final String TEST_COMMENT = "A comment for my test property"; /** Constant for a test property value. */ static final String TEST_VALUE = "myPropertyValue"; /** The layout object under test. */ PropertiesConfigurationLayout layout; /** The associated configuration object. */ LayoutTestConfiguration config; /** A properties builder that can be used for testing. */ PropertiesBuilder builder; @Before public void setUp() throws Exception { config = new LayoutTestConfiguration(); layout = new PropertiesConfigurationLayout(config); config.setLayout(layout); builder = new PropertiesBuilder(); } /** * Tests a newly created instance. */ @Test public void testInit() { assertTrue("Object contains keys", layout.getKeys().isEmpty()); assertNull("Header comment not null", layout.getHeaderComment()); Iterator it = config.getConfigurationListeners().iterator(); assertTrue("No event listener registered", it.hasNext()); assertSame("Layout not registered as event listener", layout, it.next()); assertFalse("Multiple event listeners registered", it.hasNext()); assertSame("Configuration not stored", config, layout .getConfiguration()); assertFalse("Force single line flag set", layout.isForceSingleLine()); assertNull("Got a global separator", layout.getGlobalSeparator()); } /** * Tests creating a layout object with a null configuration. This should * cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testInitNull() { new PropertiesConfigurationLayout(null); } /** * Tests reading a simple properties file. */ @Test public void testReadSimple() throws ConfigurationException { builder.addComment(TEST_COMMENT); builder.addProperty(TEST_KEY, TEST_VALUE); layout.load(builder.getReader()); assertNull("A header comment was found", layout.getHeaderComment()); assertEquals("Wrong number of properties", 1, layout.getKeys().size()); assertTrue("Property not found", layout.getKeys().contains(TEST_KEY)); assertEquals("Comment not found", TEST_COMMENT, layout .getCanonicalComment(TEST_KEY, false)); assertEquals("Wrong number of blanc lines", 0, layout .getBlancLinesBefore(TEST_KEY)); assertTrue("Wrong single line flag", layout.isSingleLine(TEST_KEY)); assertEquals("Property not stored in config", TEST_VALUE, config .getString(TEST_KEY)); } /** * Tests whether blanc lines before a property are correctly detected. */ @Test public void testBlancLines() throws ConfigurationException { builder.addProperty("prop", "value"); builder.addComment(null); builder.addComment(null); builder.addComment(TEST_COMMENT); builder.addComment(null); builder.addProperty(TEST_KEY, TEST_VALUE); layout.load(builder.getReader()); assertEquals("Wrong number of blanc lines", 2, layout .getBlancLinesBefore(TEST_KEY)); assertEquals("Wrong comment", TEST_COMMENT + CRNORM, layout .getCanonicalComment(TEST_KEY, false)); assertEquals("Wrong property value", TEST_VALUE, config .getString(TEST_KEY)); } /** * Tests the single line flag for a simple property definition. */ @Test public void testIsSingleLine() throws ConfigurationException { builder.addProperty(TEST_KEY, TEST_VALUE + "," + TEST_VALUE + "2"); layout.load(builder.getReader()); assertTrue("Wrong single line flag", layout.isSingleLine(TEST_KEY)); assertEquals("Wrong number of values", 2, config.getList(TEST_KEY) .size()); } /** * Tests the single line flag if there are multiple property definitions. */ @Test public void testIsSingleLineMulti() throws ConfigurationException { builder.addProperty(TEST_KEY, TEST_VALUE); builder.addProperty("anotherProp", "a value"); builder.addProperty(TEST_KEY, TEST_VALUE + "2"); layout.load(builder.getReader()); assertFalse("Wrong single line flag", layout.isSingleLine(TEST_KEY)); assertEquals("Wrong number of values", 2, config.getList(TEST_KEY) .size()); } /** * Tests whether comments are combined for multiple occurrences. */ @Test public void testCombineComments() throws ConfigurationException { builder.addComment(TEST_COMMENT); builder.addProperty(TEST_KEY, TEST_VALUE); builder.addComment(null); builder.addComment(TEST_COMMENT); builder.addProperty(TEST_KEY, TEST_VALUE + "2"); layout.load(builder.getReader()); assertEquals("Wrong combined comment", TEST_COMMENT + CRNORM + TEST_COMMENT, layout.getCanonicalComment( TEST_KEY, false)); assertEquals("Wrong combined blanc numbers", 0, layout .getBlancLinesBefore(TEST_KEY)); } /** * Tests if a header comment is detected. */ @Test public void testHeaderComment() throws ConfigurationException { builder.addComment(TEST_COMMENT); builder.addComment(null); builder.addProperty(TEST_KEY, TEST_VALUE); layout.load(builder.getReader()); assertEquals("Wrong header comment", TEST_COMMENT, layout .getCanonicalHeaderComment(false)); assertNull("Wrong comment for property", layout.getCanonicalComment( TEST_KEY, false)); } /** * Tests if a header comment containing blanc lines is correctly detected. */ @Test public void testHeaderCommentWithBlancs() throws ConfigurationException { builder.addComment(TEST_COMMENT); builder.addComment(null); builder.addComment(TEST_COMMENT); builder.addComment(null); builder.addProperty(TEST_KEY, TEST_VALUE); layout.load(builder.getReader()); assertEquals("Wrong header comment", TEST_COMMENT + CRNORM + CRNORM + TEST_COMMENT, layout.getCanonicalHeaderComment(false)); assertNull("Wrong comment for property", layout.getComment(TEST_KEY)); } /** * Tests if a header comment is correctly detected when it contains blanc * lines and the first property has a comment, too. */ @Test public void testHeaderCommentWithBlancsAndPropComment() throws ConfigurationException { builder.addComment(TEST_COMMENT); builder.addComment(null); builder.addComment(TEST_COMMENT); builder.addComment(null); builder.addComment(TEST_COMMENT); builder.addProperty(TEST_KEY, TEST_VALUE); layout.load(builder.getReader()); assertEquals("Wrong header comment", TEST_COMMENT + CRNORM + CRNORM + TEST_COMMENT, layout.getCanonicalHeaderComment(false)); assertEquals("Wrong comment for property", TEST_COMMENT, layout .getCanonicalComment(TEST_KEY, false)); } /** * Tests fetching a canonical header comment when no comment is set. */ @Test public void testHeaderCommentNull() { assertNull("No null comment with comment chars", layout .getCanonicalHeaderComment(true)); assertNull("No null comment without comment chars", layout .getCanonicalHeaderComment(false)); } /** * Tests if a property add event is correctly processed. */ @Test public void testEventAdd() { ConfigurationEvent event = new ConfigurationEvent(this, AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, false); layout.configurationChanged(event); assertTrue("Property not stored", layout.getKeys().contains(TEST_KEY)); assertEquals("Blanc lines before new property", 0, layout .getBlancLinesBefore(TEST_KEY)); assertTrue("No single line property", layout.isSingleLine(TEST_KEY)); assertEquals("Wrong separator", " = ", layout.getSeparator(TEST_KEY)); } /** * Tests adding a property multiple time through an event. The property * should then be a multi-line property. */ @Test public void testEventAddMultiple() { ConfigurationEvent event = new ConfigurationEvent(this, AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, false); layout.configurationChanged(event); layout.configurationChanged(event); assertFalse("No multi-line property", layout.isSingleLine(TEST_KEY)); } /** * Tests if an add event is correctly processed if the affected property is * already stored in the layout object. */ @Test public void testEventAddExisting() throws ConfigurationException { builder.addComment(TEST_COMMENT); builder.addProperty(TEST_KEY, TEST_VALUE); layout.load(builder.getReader()); ConfigurationEvent event = new ConfigurationEvent(this, AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, false); layout.configurationChanged(event); assertFalse("No multi-line property", layout.isSingleLine(TEST_KEY)); assertEquals("Comment was modified", TEST_COMMENT, layout .getCanonicalComment(TEST_KEY, false)); } /** * Tests if a set property event for a non existing property is correctly * handled. */ @Test public void testEventSetNonExisting() { ConfigurationEvent event = new ConfigurationEvent(this, AbstractConfiguration.EVENT_SET_PROPERTY, TEST_KEY, TEST_VALUE, false); layout.configurationChanged(event); assertTrue("New property was not found", layout.getKeys().contains( TEST_KEY)); } /** * Tests if a property delete event is correctly processed. */ @Test public void testEventDelete() { ConfigurationEvent event = new ConfigurationEvent(this, AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, false); layout.configurationChanged(event); event = new ConfigurationEvent(this, AbstractConfiguration.EVENT_CLEAR_PROPERTY, TEST_KEY, null, false); layout.configurationChanged(event); assertFalse("Property still existing", layout.getKeys().contains( TEST_KEY)); } /** * Tests if a clear event is correctly processed. */ @Test public void testEventClearConfig() throws Exception { fillLayout(); ConfigurationEvent event = new ConfigurationEvent(this, AbstractConfiguration.EVENT_CLEAR, null, null, false); layout.configurationChanged(event); assertTrue("Keys not empty", layout.getKeys().isEmpty()); assertNull("Header comment was not reset", layout.getHeaderComment()); } /** * Tests if a before update event is correctly ignored. */ @Test public void testEventAddBefore() { ConfigurationEvent event = new ConfigurationEvent(this, AbstractConfiguration.EVENT_ADD_PROPERTY, TEST_KEY, TEST_VALUE, true); layout.configurationChanged(event); assertFalse("Property already stored", layout.getKeys().contains( TEST_KEY)); } /** * Tests if a reload update is correctly processed. */ @Test public void testEventReload() { fillLayout(); ConfigurationEvent event = new ConfigurationEvent(this, AbstractFileConfiguration.EVENT_RELOAD, null, null, true); layout.configurationChanged(event); assertTrue("Keys not empty", layout.getKeys().isEmpty()); assertNull("Header comment was not reset", layout.getHeaderComment()); } /** * Tests the event after a reload has been performed. This should be * ignored. */ @Test public void testEventReloadAfter() { fillLayout(); ConfigurationEvent event = new ConfigurationEvent(this, AbstractFileConfiguration.EVENT_RELOAD, null, null, false); layout.configurationChanged(event); assertFalse("Keys are empty", layout.getKeys().isEmpty()); assertNotNull("Header comment was reset", layout.getHeaderComment()); } /** * Tests a recursive load call. */ @Test public void testRecursiveLoadCall() throws ConfigurationException { PropertiesBuilder b = new PropertiesBuilder(); b.addComment("A nested header comment."); b.addComment("With multiple lines"); b.addComment(null); b.addComment("Second comment"); b.addProperty(TEST_KEY, TEST_VALUE); b.addProperty(TEST_KEY + "2", TEST_VALUE + "2"); config.builder = b; builder.addComment("Header comment"); builder.addComment(null); builder.addComment(TEST_COMMENT); builder.addProperty(TEST_KEY, TEST_VALUE); builder.addComment("Include file"); builder.addProperty(PropertiesConfiguration.getInclude(), "test"); layout.load(builder.getReader()); assertEquals("Wrong header comment", "Header comment", layout .getCanonicalHeaderComment(false)); assertFalse("Include property was stored", layout.getKeys().contains( PropertiesConfiguration.getInclude())); assertEquals("Wrong comment for property", TEST_COMMENT + CRNORM + "A nested header comment." + CRNORM + "With multiple lines" + CRNORM + CRNORM + "Second comment", layout.getCanonicalComment(TEST_KEY, false)); } /** * Tests whether the output of the layout object is identical to the source * file (at least for simple properties files). */ @Test public void testReadAndWrite() throws ConfigurationException { builder.addComment("This is my test properties file,"); builder.addComment("which contains a header comment."); builder.addComment(null); builder.addComment(TEST_COMMENT); builder.addProperty(TEST_KEY, TEST_COMMENT); builder.addComment(null); builder.addComment(null); builder.addComment("Another comment"); builder.addProperty("property", "and a value"); layout.load(builder.getReader()); checkLayoutString(builder.toString()); } /** * Tests if the content of the layout object is correctly written. */ @Test public void testSave() throws ConfigurationException { config.addProperty(TEST_KEY, TEST_VALUE); layout.setComment(TEST_KEY, TEST_COMMENT); config.addProperty(TEST_KEY, TEST_VALUE + "2"); config.addProperty("AnotherProperty", "AnotherValue"); config.addProperty("AnotherProperty", "3rdValue"); layout.setComment("AnotherProperty", "AnotherComment"); layout.setBlancLinesBefore("AnotherProperty", 2); layout.setSingleLine("AnotherProperty", true); layout.setHeaderComment("A header comment" + CRNORM + "for my properties"); checkLayoutString("# A header comment" + CR + "# for my properties" + CR + CR + "# " + TEST_COMMENT + CR + TEST_KEY + " = " + TEST_VALUE + CR + TEST_KEY + " = " + TEST_VALUE + "2" + CR + CR + CR + "# AnotherComment" + CR + "AnotherProperty = AnotherValue,3rdValue" + CR); } /** * Tests the force single line flag. */ @Test public void testSaveForceSingleLine() throws ConfigurationException { config.setListDelimiter(';'); config.addProperty(TEST_KEY, TEST_VALUE); config.addProperty(TEST_KEY, TEST_VALUE + "2"); config.addProperty("AnotherProperty", "value1;value2;value3"); layout.setComment(TEST_KEY, TEST_COMMENT); layout.setForceSingleLine(true); checkLayoutString("# " + TEST_COMMENT + CR + TEST_KEY + " = " + TEST_VALUE + ';' + TEST_VALUE + "2" + CR + "AnotherProperty = value1;value2;value3" + CR); } /** * Tests the trimComment method. */ @Test public void testTrimComment() { assertEquals("Wrong trimmed comment", "This is a comment" + CR + "that spans multiple" + CR + "lines in a" + CR + " complex way.", PropertiesConfigurationLayout.trimComment( " # This is a comment" + CR + "that spans multiple" + CR + "!lines in a" + CR + " complex way.", false)); } /** * Tests trimming a comment with trailing CRs. */ @Test public void testTrimCommentTrainlingCR() { assertEquals("Wrong trimmed comment", "Comment with" + CR + "trailing CR" + CR, PropertiesConfigurationLayout .trimComment("Comment with" + CR + "! trailing CR" + CR, false)); } /** * Tests enforcing comment characters in a comment. */ @Test public void testTrimCommentFalse() { assertEquals("Wrong trimmed comment", "# Comment with" + CR + " ! some mixed " + CR + "#comment" + CR + "# lines", PropertiesConfigurationLayout.trimComment("Comment with" + CR + " ! some mixed " + CR + "#comment" + CR + "lines", true)); } /** * Tests accessing data for a property, which is not stored. */ @Test public void testGetNonExistingLayouData() { assertNull("A comment was found", layout.getComment("unknown")); assertTrue("A multi-line property", layout.isSingleLine("unknown")); assertEquals("Leading blanc lines", 0, layout .getBlancLinesBefore("unknown")); } /** * Tests accessing a property with a null key. This should throw an * exception. */ @Test(expected = IllegalArgumentException.class) public void testGetNullLayouttData() { layout.setComment(null, TEST_COMMENT); } /** * Tests resetting a comment. */ @Test public void testSetNullComment() { fillLayout(); layout.setComment(TEST_KEY, null); assertNull("Comment was not reset", layout.getComment(TEST_KEY)); } /** * Tests saving when a comment for a non existing property is contained in * the layout object. This comment should be ignored. */ @Test public void testSaveCommentForUnexistingProperty() throws ConfigurationException { fillLayout(); layout.setComment("NonExistingKey", "NonExistingComment"); String output = getLayoutString(); assertTrue("Non existing key was found", output .indexOf("NonExistingKey") < 0); assertTrue("Non existing comment was found", output .indexOf("NonExistingComment") < 0); } /** * Tests saving an empty layout object. */ @Test public void testSaveEmptyLayout() throws ConfigurationException { checkLayoutString(""); } /** * Tests the copy constructor. */ @Test public void testInitCopy() { fillLayout(); PropertiesConfigurationLayout l2 = new PropertiesConfigurationLayout( config, layout); assertEquals("Wrong number of keys", layout.getKeys().size(), l2 .getKeys().size()); for (String key : layout.getKeys()) { assertTrue("Key was not found: " + key, l2.getKeys().contains(key)); } assertEquals("Wrong header comment", layout.getHeaderComment(), l2.getHeaderComment()); assertEquals("Wrong footer comment", layout.getFooterComment(), l2.getFooterComment()); } /** * Tests if the copy and the original are independent from each other. */ @Test public void testInitCopyModify() { fillLayout(); PropertiesConfigurationLayout l2 = new PropertiesConfigurationLayout( config, layout); assertEquals("Comments are not equal", layout.getComment(TEST_KEY), l2 .getComment(TEST_KEY)); layout.setComment(TEST_KEY, "A new comment"); assertEquals("Comment was changed", TEST_COMMENT, l2 .getCanonicalComment(TEST_KEY, false)); l2.setBlancLinesBefore(TEST_KEY, l2.getBlancLinesBefore(TEST_KEY) + 1); assertFalse("Blanc lines do not differ", layout .getBlancLinesBefore(TEST_KEY) == l2 .getBlancLinesBefore(TEST_KEY)); } /** * Tests changing the separator for a property. */ @Test public void testSetSeparator() throws ConfigurationException { config.addProperty(TEST_KEY, TEST_VALUE); layout.setSeparator(TEST_KEY, ":"); checkLayoutString(TEST_KEY + ":" + TEST_VALUE + CR); } /** * Tests setting the global separator. This separator should override the * separators for all properties. */ @Test public void testSetGlobalSeparator() throws ConfigurationException { final String sep = "="; config.addProperty(TEST_KEY, TEST_VALUE); config.addProperty("key2", "value2"); layout.setSeparator(TEST_KEY, " : "); layout.setGlobalSeparator(sep); checkLayoutString(TEST_KEY + sep + TEST_VALUE + CR + "key2" + sep + "value2" + CR); } /** * Tests setting the line separator. */ @Test public void testSetLineSeparator() throws ConfigurationException { final String lf = CR + CR; config.addProperty(TEST_KEY, TEST_VALUE); layout.setBlancLinesBefore(TEST_KEY, 2); layout.setComment(TEST_KEY, TEST_COMMENT); layout.setHeaderComment("Header comment"); layout.setLineSeparator(lf); checkLayoutString("# Header comment" + lf + lf + lf + lf + "# " + TEST_COMMENT + lf + TEST_KEY + " = " + TEST_VALUE + lf); } /** * Tests whether the line separator is also taken into account within * comments. */ @Test public void testSetLineSeparatorInComments() throws ConfigurationException { final String lf = "<-\n"; config.addProperty(TEST_KEY, TEST_VALUE); layout.setComment(TEST_KEY, TEST_COMMENT + "\nMore comment"); layout.setHeaderComment("Header\ncomment"); layout.setLineSeparator(lf); checkLayoutString("# Header" + lf + "# comment" + lf + lf + "# " + TEST_COMMENT + lf + "# More comment" + lf + TEST_KEY + " = " + TEST_VALUE + lf); } /** * Helper method for filling the layout object with some properties. */ private void fillLayout() { builder.addComment("A header comment"); builder.addComment(null); builder.addProperty("prop", "value"); builder.addComment(TEST_COMMENT); builder.addProperty(TEST_KEY, TEST_VALUE); builder.addProperty("anotherProp", "anotherValue"); builder.addComment("A footer comment"); try { layout.load(builder.getReader()); } catch (ConfigurationException cex) { // should not happen fail("Exception was thrown: " + cex); } } /** * Writes the layout's data into a string. * * @return the layout file's content as string * @throws ConfigurationException if an error occurs */ private String getLayoutString() throws ConfigurationException { StringWriter out = new StringWriter(); layout.save(out); return out.toString(); } /** * Checks if the layout's output is correct. * * @param expected the expected result * @throws ConfigurationException if an error occurs */ private void checkLayoutString(String expected) throws ConfigurationException { assertEquals("Wrong layout file content", expected, getLayoutString()); } /** * A helper class used for constructing test properties files. */ static class PropertiesBuilder { /** A buffer for storing the data. */ private StringBuilder buf = new StringBuilder(); /** A counter for varying the comment character. */ private int commentCounter; /** * Adds a property to the simulated file. * * @param key the property key * @param value the value */ public void addProperty(String key, String value) { buf.append(key).append(" = ").append(value).append(CR); } /** * Adds a comment line. * * @param s the comment (can be null, then a blanc line is * added) */ public void addComment(String s) { if (s != null) { if (commentCounter % 2 == 0) { buf.append("# "); } else { buf.append("! "); } buf.append(s); commentCounter++; } buf.append(CR); } /** * Returns a reader for the simulated properties. * * @return a reader */ public Reader getReader() { return new StringReader(buf.toString()); } /** * Returns a string representation of the buffer's content. * * @return the buffer as string */ @Override public String toString() { return buf.toString(); } } /** * A mock properties configuration implementation that is used to check * whether some expected methods are called. */ static class LayoutTestConfiguration extends PropertiesConfiguration { /** Stores a builder object. */ public PropertiesBuilder builder; /** * Simulates the propertyLoaded() callback. If a builder was set, a * load() call on the layout is invoked. */ @Override boolean propertyLoaded(String key, String value) throws ConfigurationException { if (builder == null) { return super.propertyLoaded(key, value); } else { if (PropertiesConfiguration.getInclude().equals(key)) { getLayout().load(builder.getReader()); return false; } else { return true; } } } } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPropertiesSequence.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPropertiesSequence100644 14261 12232154104 33671 0ustarhenningstaff 0 0 package org.apache.commons.configuration; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.List; import org.apache.commons.collections.IteratorUtils; import org.apache.commons.lang.StringUtils; import org.junit.Test; /** * Test that the configuration factory returns keys in the same * sequence as the properties configurator * * @version $Id: TestPropertiesSequence.java 1225011 2011-12-27 20:46:13Z oheger $ */ @SuppressWarnings("deprecation") public class TestPropertiesSequence { @Test public void testConfigurationValuesInSameOrderFromFile() throws Exception { String simpleConfigurationFile = ConfigurationAssert.getTestFile("testSequence.properties").getAbsolutePath(); String compositeConfigurationFile = ConfigurationAssert.getTestFile("testSequenceDigester.xml").getAbsolutePath(); Configuration simpleConfiguration = new PropertiesConfiguration(simpleConfigurationFile); ConfigurationFactory configurationFactory = new ConfigurationFactory(); configurationFactory.setConfigurationFileName(compositeConfigurationFile); Configuration compositeConfiguration = configurationFactory.getConfiguration(); Configuration a = simpleConfiguration.subset("prefix"); Configuration b = compositeConfiguration.subset("prefix"); List keysSimpleConfiguration = IteratorUtils.toList(a.getKeys()); List keysCompositeConfiguration = IteratorUtils.toList(b.getKeys()); assertTrue("Size:" + keysSimpleConfiguration.size(), keysSimpleConfiguration.size() > 0); assertEquals(keysSimpleConfiguration.size(), keysCompositeConfiguration.size()); for (int i = 0; i < keysSimpleConfiguration.size(); i++) { assertEquals(keysSimpleConfiguration.get(i), keysCompositeConfiguration.get(i)); } } @Test public void testConfigurationValuesInSameOrderWithManualAdd() throws Exception { String simpleConfigurationFile = ConfigurationAssert.getTestFile("testSequence.properties").getAbsolutePath(); String compositeConfigurationFile = ConfigurationAssert.getTestFile("testSequenceDigester.xml").getAbsolutePath(); Configuration simpleConfiguration = new PropertiesConfiguration(simpleConfigurationFile); ConfigurationFactory configurationFactory = new ConfigurationFactory(); configurationFactory.setConfigurationFileName(compositeConfigurationFile); Configuration compositeConfiguration = configurationFactory.getConfiguration(); simpleConfiguration.setProperty("prefix.Co.test", Boolean.TRUE); simpleConfiguration.setProperty("prefix.Av.test", Boolean.TRUE); compositeConfiguration.setProperty("prefix.Co.test", Boolean.TRUE); compositeConfiguration.setProperty("prefix.Av.test", Boolean.TRUE); Configuration a = simpleConfiguration.subset("prefix"); Configuration b = compositeConfiguration.subset("prefix"); List keysSimpleConfiguration = IteratorUtils.toList(a.getKeys()); List keysCompositeConfiguration = IteratorUtils.toList(b.getKeys()); assertTrue("Size:" + keysSimpleConfiguration.size(), keysSimpleConfiguration.size() > 0); assertEquals(keysSimpleConfiguration.size(), keysCompositeConfiguration.size()); for (int i = 0; i < keysSimpleConfiguration.size(); i++) { assertEquals(keysSimpleConfiguration.get(i), keysCompositeConfiguration.get(i)); } } @Test public void testMappingInSameOrder() throws Exception { String simpleConfigurationFile = ConfigurationAssert.getTestFile("testSequence.properties").getAbsolutePath(); String compositeConfigurationFile = ConfigurationAssert.getTestFile("testSequenceDigester.xml").getAbsolutePath(); Configuration simpleConfiguration = new PropertiesConfiguration(simpleConfigurationFile); ConfigurationFactory configurationFactory = new ConfigurationFactory(); configurationFactory.setConfigurationFileName(compositeConfigurationFile); Configuration compositeConfiguration = configurationFactory.getConfiguration(); Configuration mapping = new BaseConfiguration(); Configuration mapping2 = new BaseConfiguration(); for (Iterator keys = simpleConfiguration.getKeys(); keys.hasNext();) { String key = keys.next(); String[] keyParts = StringUtils.split(key, "."); if ((keyParts.length == 3) && keyParts[0].equals("prefix") && keyParts[2].equals("postfix")) { String serviceKey = keyParts[1]; if (!mapping.containsKey(serviceKey)) { mapping.setProperty(serviceKey, simpleConfiguration.getString(key)); } } } for (Iterator keys = compositeConfiguration.getKeys(); keys.hasNext();) { String key = keys.next(); String[] keyParts = StringUtils.split(key, "."); if ((keyParts.length == 3) && keyParts[0].equals("prefix") && keyParts[2].equals("postfix")) { String serviceKey = keyParts[1]; if (!mapping2.containsKey(serviceKey)) { mapping2.setProperty(serviceKey, compositeConfiguration.getString(key)); } } } } } ././@LongLink100644 0 0 151 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPropertyConverter.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestPropertyConverter.100644 30515 12232154104 33636 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.lang.annotation.ElementType; import java.math.BigDecimal; import java.util.Iterator; import java.util.List; import org.junit.Test; /** * Test class for PropertyConverter. * * @author Emmanuel Bourg * @version $Id: TestPropertyConverter.java 1534376 2013-10-21 21:14:18Z henning $ */ public class TestPropertyConverter { /** Constant for an enumeration class used by some tests. */ private static final Class ENUM_CLASS = ElementType.class; @Test public void testSplit() { String s = "abc, xyz , 123"; List list = PropertyConverter.split(s, ','); assertEquals("size", 3, list.size()); assertEquals("1st token for '" + s + "'", "abc", list.get(0)); assertEquals("2nd token for '" + s + "'", "xyz", list.get(1)); assertEquals("3rd token for '" + s + "'", "123", list.get(2)); } @Test public void testSplitNoTrim() { String s = "abc, xyz , 123"; List list = PropertyConverter.split(s, ',', false); assertEquals("size", 3, list.size()); assertEquals("1st token for '" + s + "'", "abc", list.get(0)); assertEquals("2nd token for '" + s + "'", " xyz ", list.get(1)); assertEquals("3rd token for '" + s + "'", " 123", list.get(2)); } @Test public void testSplitWithEscapedSeparator() { String s = "abc\\,xyz, 123"; List list = PropertyConverter.split(s, ','); assertEquals("size", 2, list.size()); assertEquals("1st token for '" + s + "'", "abc,xyz", list.get(0)); assertEquals("2nd token for '" + s + "'", "123", list.get(1)); } @Test public void testSplitEmptyValues() { String s = ",,"; List list = PropertyConverter.split(s, ','); assertEquals("size", 3, list.size()); assertEquals("1st token for '" + s + "'", "", list.get(0)); assertEquals("2nd token for '" + s + "'", "", list.get(1)); assertEquals("3rd token for '" + s + "'", "", list.get(2)); } @Test public void testSplitWithEndingSlash() { String s = "abc, xyz\\"; List list = PropertyConverter.split(s, ','); assertEquals("size", 2, list.size()); assertEquals("1st token for '" + s + "'", "abc", list.get(0)); assertEquals("2nd token for '" + s + "'", "xyz\\", list.get(1)); } @Test public void testSplitNull() { List list = PropertyConverter.split(null, ','); assertNotNull(list); assertTrue(list.isEmpty()); } /** * Tests whether an escape character can be itself escaped. */ @Test public void testSplitEscapeEscapeChar() { List list = PropertyConverter.split("C:\\Temp\\\\,xyz", ','); assertEquals("Wrong list size", 2, list.size()); assertEquals("Wrong element 1", "C:\\Temp\\", list.get(0)); assertEquals("Wrong element 2", "xyz", list.get(1)); } /** * Tests whether delimiters are correctly escaped. */ @Test public void testEscapeDelimiters() { assertEquals("Wrong escaped delimiters", "C:\\\\Temp\\\\\\,D:\\\\Data\\\\", PropertyConverter .escapeDelimiters("C:\\Temp\\,D:\\Data\\", ',')); } /** * Tests whether only the list delimiter can be escaped. */ @Test public void testEscapeListDelimiter() { assertEquals("Wrong escaped list delimiter", "C:\\Temp\\\\,D:\\Data\\", PropertyConverter.escapeListDelimiter("C:\\Temp\\,D:\\Data\\", ',')); } @Test public void testToIterator() { int[] array = new int[]{1, 2, 3}; Iterator it = PropertyConverter.toIterator(array, ','); assertEquals("1st element", new Integer(1), it.next()); assertEquals("2nd element", new Integer(2), it.next()); assertEquals("3rd element", new Integer(3), it.next()); } /** * Tests the interpolation features. */ @Test public void testInterpolateString() { PropertiesConfiguration config = new PropertiesConfiguration(); config.addProperty("animal", "quick brown fox"); config.addProperty("target", "lazy dog"); assertEquals("Wrong interpolation", "The quick brown fox jumps over the lazy dog.", PropertyConverter.interpolate("The ${animal} jumps over the ${target}.", config)); } /** * Tests interpolation of an object. Here nothing should be substituted. */ @Test public void testInterpolateObject() { assertEquals("Object was not correctly interpolated", new Integer(42), PropertyConverter.interpolate(new Integer(42), new PropertiesConfiguration())); } /** * Tests complex interpolation where the variables' values contain in turn * other variables. */ @Test public void testInterpolateRecursive() { PropertiesConfiguration config = new PropertiesConfiguration(); config.addProperty("animal", "${animal_attr} fox"); config.addProperty("target", "${target_attr} dog"); config.addProperty("animal_attr", "quick brown"); config.addProperty("target_attr", "lazy"); assertEquals("Wrong complex interpolation", "The quick brown fox jumps over the lazy dog.", PropertyConverter.interpolate("The ${animal} jumps over the ${target}.", config)); } /** * Tests an interpolation that leads to a cycle. This should throw an * exception. */ @Test(expected = IllegalStateException.class) public void testCyclicInterpolation() { PropertiesConfiguration config = new PropertiesConfiguration(); config.addProperty("animal", "${animal_attr} ${species}"); config.addProperty("animal_attr", "quick brown"); config.addProperty("species", "${animal}"); PropertyConverter.interpolate("This is a ${animal}", config); } /** * Tests interpolation if a variable is unknown. Then the variable won't be * substituted. */ @Test public void testInterpolationUnknownVariable() { PropertiesConfiguration config = new PropertiesConfiguration(); config.addProperty("animal", "quick brown fox"); assertEquals("Wrong interpolation", "The quick brown fox jumps over ${target}.", PropertyConverter.interpolate("The ${animal} jumps over ${target}.", config)); } /** * Tests conversion to numbers when the passed in objects are already * numbers. */ @Test public void testToNumberDirect() { Integer i = new Integer(42); assertSame("Wrong integer", i, PropertyConverter.toNumber(i, Integer.class)); BigDecimal d = new BigDecimal("3.1415"); assertSame("Wrong BigDecimal", d, PropertyConverter.toNumber(d, Integer.class)); } /** * Tests conversion to numbers when the passed in objects have a compatible * string representation. */ @Test public void testToNumberFromString() { assertEquals("Incorrect Integer value", new Integer(42), PropertyConverter.toNumber("42", Integer.class)); assertEquals("Incorrect Short value", new Short((short) 10), PropertyConverter.toNumber(new StringBuffer("10"), Short.class)); } /** * Tests conversion to numbers when the passed in objects are strings with * prefixes for special radices. */ @Test public void testToNumberFromHexString() { Number n = PropertyConverter.toNumber("0x10", Integer.class); assertEquals("Incorrect Integer value", 16, n.intValue()); } /** * Tests conversion to numbers when an invalid Hex value is passed in. * This should cause an exception. */ @Test(expected = ConversionException.class) public void testToNumberFromInvalidHexString() { PropertyConverter.toNumber("0xNotAHexValue", Integer.class); } /** * Tests conversion to numbers when the passed in objects are strings with * prefixes for special radices. */ @Test public void testToNumberFromBinaryString() { Number n = PropertyConverter.toNumber("0b1111", Integer.class); assertEquals("Incorrect Integer value", 15, n.intValue()); } /** * Tests conversion to numbers when an invalid binary value is passed in. * This should cause an exception. */ @Test(expected = ConversionException.class) public void testToNumberFromInvalidBinaryString() { PropertyConverter.toNumber("0bNotABinValue", Integer.class); } /** * Tests conversion to numbers when the passed in objects have no numeric * String representation. This should cause an exception. */ @Test(expected = ConversionException.class) public void testToNumberFromInvalidString() { PropertyConverter.toNumber("Not a number", Byte.class); } /** * Tests conversion to numbers when the passed in target class is invalid. * This should cause an exception. */ @Test(expected = ConversionException.class) public void testToNumberWithInvalidClass() { PropertyConverter.toNumber("42", Object.class); } @Test public void testToEnumFromEnum() { assertEquals(ElementType.METHOD, PropertyConverter.toEnum(ElementType.METHOD, ENUM_CLASS)); } @Test public void testToEnumFromString() { assertEquals(ElementType.METHOD, PropertyConverter.toEnum("METHOD", ENUM_CLASS)); } @Test(expected = ConversionException.class) public void testToEnumFromInvalidString() { PropertyConverter.toEnum("FOO", ENUM_CLASS); } @Test public void testToEnumFromNumber() { assertEquals(ElementType.METHOD, PropertyConverter.toEnum( Integer.valueOf(ElementType.METHOD.ordinal()), ENUM_CLASS)); } @Test(expected = ConversionException.class) public void testToEnumFromInvalidNumber() { PropertyConverter.toEnum(Integer.valueOf(-1), ENUM_CLASS); } /** * Tests a trivial conversion: the value has already the desired type. */ @Test public void testToNoConversionNeeded() { String value = "testValue"; assertEquals("Wrong conversion result", value, PropertyConverter.to(String.class, value, null)); } /** * Tests whether a conversion to character is possible. */ @Test public void testToCharSuccess() { assertEquals("Wrong conversion result", Character.valueOf('t'), PropertyConverter.to(Character.class, "t", null)); } /** * Tests whether other objects implementing a toString() method can be * converted to character. */ @Test public void testToCharViaToString() { Object value = new Object() { @Override public String toString() { return "X"; } }; assertEquals("Wrong conversion result", Character.valueOf('X'), PropertyConverter.to(Character.TYPE, value, null)); } /** * Tests a failed conversion to character. */ @Test(expected = ConversionException.class) public void testToCharFailed() { PropertyConverter.to(Character.TYPE, "FF", null); } } ././@LongLink100644 0 0 165 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestStrictConfigurationComparator.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestStrictConfiguratio100644 6217 12232154104 33650 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.junit.Test; /** * Tests the StrintConfigurationComparator class * * @version $Id: TestStrictConfigurationComparator.java 1225015 2011-12-27 21:01:59Z oheger $ */ public class TestStrictConfigurationComparator { /** * The comparator. */ protected ConfigurationComparator comparator = new StrictConfigurationComparator(); /** * The first configuration. */ protected Configuration configuration = new BaseConfiguration(); /** * Tests the comparator. */ @Test public void testCompare() { // Identity comparison for empty configuration assertTrue( "Compare an empty configuration with itself", comparator.compare(configuration, configuration)); configuration.setProperty("one", "1"); configuration.setProperty("two", "2"); configuration.setProperty("three", "3"); // Identify comparison for non-empty configuration assertTrue( "Compare a configuration with itself", comparator.compare(configuration, configuration)); // Create the second configuration Configuration other = new BaseConfiguration(); assertFalse( "Compare a configuration with an empty one", comparator.compare(configuration, other)); other.setProperty("one", "1"); other.setProperty("two", "2"); other.setProperty("three", "3"); // Two identical, non-empty configurations assertTrue( "Compare a configuration with an identical one", comparator.compare(configuration, other)); other.setProperty("four", "4"); assertFalse( "Compare our configuration with another that has an additional key mapping", comparator.compare(configuration, other)); configuration.setProperty("four", "4"); assertTrue( "Compare our configuration with another that is identical", comparator.compare(configuration, other)); } @Test public void testCompareNull() { assertTrue(comparator.compare(null, null)); assertFalse(comparator.compare(configuration, null)); assertFalse(comparator.compare(null, configuration)); } } ././@LongLink100644 0 0 154 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestSubnodeConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestSubnodeConfigurati100644 54226 12232154104 33643 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.apache.commons.lang.text.StrLookup; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; /** * Test case for SubnodeConfiguration. * * @author Commons * Configuration team * @version $Id: TestSubnodeConfiguration.java 1225018 2011-12-27 21:14:59Z oheger $ */ public class TestSubnodeConfiguration { /** An array with names of tables (test data). */ private static final String[] TABLE_NAMES = { "documents", "users" }; /** An array with the fields of the test tables (test data). */ private static final String[][] TABLE_FIELDS = { { "docid", "docname", "author", "dateOfCreation", "version", "size" }, { "userid", "uname", "firstName", "lastName" } }; /** Constant for an updated table name.*/ private static final String NEW_TABLE_NAME = "newTable"; /** A helper object for creating temporary files. */ @Rule public TemporaryFolder folder = new TemporaryFolder(); /** The parent configuration. */ HierarchicalConfiguration parent; /** The subnode configuration to be tested. */ SubnodeConfiguration config; /** Stores a counter for the created nodes. */ int nodeCounter; @Before public void setUp() throws Exception { parent = setUpParentConfig(); nodeCounter = 0; } /** * Tests creation of a subnode config. */ @Test public void testInitSubNodeConfig() { setUpSubnodeConfig(); assertSame("Wrong root node in subnode", getSubnodeRoot(parent), config .getRoot()); assertSame("Wrong parent config", parent, config.getParent()); } /** * Tests constructing a subnode configuration with a null parent. This * should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testInitSubNodeConfigWithNullParent() { config = new SubnodeConfiguration(null, getSubnodeRoot(parent)); } /** * Tests constructing a subnode configuration with a null root node. This * should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testInitSubNodeConfigWithNullNode() { config = new SubnodeConfiguration(parent, null); } /** * Tests if properties of the sub node can be accessed. */ @Test public void testGetProperties() { setUpSubnodeConfig(); assertEquals("Wrong table name", TABLE_NAMES[0], config .getString("name")); List fields = config.getList("fields.field.name"); assertEquals("Wrong number of fields", TABLE_FIELDS[0].length, fields .size()); for (int i = 0; i < TABLE_FIELDS[0].length; i++) { assertEquals("Wrong field at position " + i, TABLE_FIELDS[0][i], fields.get(i)); } } /** * Tests setting of properties in both the parent and the subnode * configuration and whether the changes are visible to each other. */ @Test public void testSetProperty() { setUpSubnodeConfig(); config.setProperty(null, "testTable"); config.setProperty("name", TABLE_NAMES[0] + "_tested"); assertEquals("Root value was not set", "testTable", parent .getString("tables.table(0)")); assertEquals("Table name was not changed", TABLE_NAMES[0] + "_tested", parent.getString("tables.table(0).name")); parent.setProperty("tables.table(0).fields.field(1).name", "testField"); assertEquals("Field name was not changed", "testField", config .getString("fields.field(1).name")); } /** * Tests adding of properties. */ @Test public void testAddProperty() { setUpSubnodeConfig(); config.addProperty("[@table-type]", "test"); assertEquals("parent.createNode() was not called", 1, nodeCounter); assertEquals("Attribute not set", "test", parent .getString("tables.table(0)[@table-type]")); parent.addProperty("tables.table(0).fields.field(-1).name", "newField"); List fields = config.getList("fields.field.name"); assertEquals("New field was not added", TABLE_FIELDS[0].length + 1, fields.size()); assertEquals("Wrong last field", "newField", fields .get(fields.size() - 1)); } /** * Tests listing the defined keys. */ @Test public void testGetKeys() { setUpSubnodeConfig(); Set keys = new HashSet(); CollectionUtils.addAll(keys, config.getKeys()); assertEquals("Incorrect number of keys", 2, keys.size()); assertTrue("Key 1 not contained", keys.contains("name")); assertTrue("Key 2 not contained", keys.contains("fields.field.name")); } /** * Tests setting the exception on missing flag. The subnode config obtains * this flag from its parent. */ @Test(expected = NoSuchElementException.class) public void testSetThrowExceptionOnMissing() { parent.setThrowExceptionOnMissing(true); setUpSubnodeConfig(); assertTrue("Exception flag not fetchted from parent", config .isThrowExceptionOnMissing()); config.getString("non existing key"); } /** * Tests whether the exception flag can be set independently from the parent. */ @Test public void testSetThrowExceptionOnMissingAffectsParent() { parent.setThrowExceptionOnMissing(true); setUpSubnodeConfig(); config.setThrowExceptionOnMissing(false); assertTrue("Exception flag reset on parent", parent .isThrowExceptionOnMissing()); } /** * Tests handling of the delimiter parsing disabled flag. This is shared * with the parent, too. */ @Test public void testSetDelimiterParsingDisabled() { parent.setDelimiterParsingDisabled(true); setUpSubnodeConfig(); parent.setDelimiterParsingDisabled(false); assertTrue("Delimiter parsing flag was not received from parent", config.isDelimiterParsingDisabled()); config.addProperty("newProp", "test1,test2,test3"); assertEquals("New property was splitted", "test1,test2,test3", parent .getString("tables.table(0).newProp")); parent.setDelimiterParsingDisabled(true); config.setDelimiterParsingDisabled(false); assertTrue("Delimiter parsing flag was reset on parent", parent .isDelimiterParsingDisabled()); } /** * Tests manipulating the list delimiter. This piece of data is derived from * the parent. */ @Test public void testSetListDelimiter() { parent.setListDelimiter('/'); setUpSubnodeConfig(); parent.setListDelimiter(';'); assertEquals("List delimiter not obtained from parent", '/', config .getListDelimiter()); config.addProperty("newProp", "test1,test2/test3"); assertEquals("List was incorrectly splitted", "test1,test2", parent .getString("tables.table(0).newProp")); config.setListDelimiter(','); assertEquals("List delimiter changed on parent", ';', parent .getListDelimiter()); } /** * Tests changing the expression engine. */ @Test public void testSetExpressionEngine() { parent.setExpressionEngine(new XPathExpressionEngine()); setUpSubnodeConfig(); assertEquals("Wrong field name", TABLE_FIELDS[0][1], config .getString("fields/field[2]/name")); Set keys = new HashSet(); CollectionUtils.addAll(keys, config.getKeys()); assertEquals("Wrong number of keys", 2, keys.size()); assertTrue("Key 1 not contained", keys.contains("name")); assertTrue("Key 2 not contained", keys.contains("fields/field/name")); config.setExpressionEngine(null); assertTrue("Expression engine reset on parent", parent .getExpressionEngine() instanceof XPathExpressionEngine); } /** * Tests the configurationAt() method. */ @Test public void testConfiguarationAt() { setUpSubnodeConfig(); SubnodeConfiguration sub2 = config .configurationAt("fields.field(1)"); assertEquals("Wrong value of property", TABLE_FIELDS[0][1], sub2 .getString("name")); assertEquals("Wrong parent", config.getParent(), sub2.getParent()); } /** * Tests interpolation features. The subnode config should use its parent * for interpolation. */ @Test public void testInterpolation() { parent.addProperty("tablespaces.tablespace.name", "default"); parent.addProperty("tablespaces.tablespace(-1).name", "test"); parent.addProperty("tables.table(0).tablespace", "${tablespaces.tablespace(0).name}"); assertEquals("Wrong interpolated tablespace", "default", parent .getString("tables.table(0).tablespace")); setUpSubnodeConfig(); assertEquals("Wrong interpolated tablespace in subnode", "default", config.getString("tablespace")); } /** * An additional test for interpolation when the configurationAt() method is * involved. */ @Test public void testInterpolationFromConfigurationAt() { parent.addProperty("base.dir", "/home/foo"); parent.addProperty("test.absolute.dir.dir1", "${base.dir}/path1"); parent.addProperty("test.absolute.dir.dir2", "${base.dir}/path2"); parent.addProperty("test.absolute.dir.dir3", "${base.dir}/path3"); Configuration sub = parent.configurationAt("test.absolute.dir"); for (int i = 1; i < 4; i++) { assertEquals("Wrong interpolation in parent", "/home/foo/path" + i, parent.getString("test.absolute.dir.dir" + i)); assertEquals("Wrong interpolation in subnode", "/home/foo/path" + i, sub.getString("dir" + i)); } } /** * An additional test for interpolation when the configurationAt() method is * involved for a local interpolation. */ @Test public void testLocalInterpolationFromConfigurationAt() { parent.addProperty("base.dir", "/home/foo"); parent.addProperty("test.absolute.dir.dir1", "${base.dir}/path1"); parent.addProperty("test.absolute.dir.dir2", "${dir1}"); Configuration sub = parent.configurationAt("test.absolute.dir"); assertEquals("Wrong interpolation in subnode", "/home/foo/path1", sub.getString("dir1")); assertEquals("Wrong local interpolation in subnode", "/home/foo/path1", sub.getString("dir2")); } /** * Tests manipulating the interpolator. */ @Test public void testInterpolator() { parent.addProperty("tablespaces.tablespace.name", "default"); parent.addProperty("tablespaces.tablespace(-1).name", "test"); setUpSubnodeConfig(); InterpolationTestHelper.testGetInterpolator(config); } @Test public void testLocalLookupsInInterpolatorAreInherited() { parent.addProperty("tablespaces.tablespace.name", "default"); parent.addProperty("tablespaces.tablespace(-1).name", "test"); parent.addProperty("tables.table(0).var", "${brackets:x}"); ConfigurationInterpolator interpolator = parent.getInterpolator(); interpolator.registerLookup("brackets", new StrLookup(){ @Override public String lookup(String key) { return "(" + key +")"; } }); setUpSubnodeConfig(); assertEquals("Local lookup was not inherited", "(x)", config.getString("var", "")); } /** * Tests a reload operation for the parent configuration when the subnode * configuration does not support reloads. Then the new value should not be * detected. */ @Test public void testParentReloadNotSupported() throws ConfigurationException { Configuration c = setUpReloadTest(false); assertEquals("Name changed in sub config", TABLE_NAMES[1], config .getString("name")); assertEquals("Name not changed in parent", NEW_TABLE_NAME, c .getString("tables.table(1).name")); } /** * Tests a reload operation for the parent configuration when the subnode * configuration does support reloads. The new value should be returned. */ @Test public void testParentReloadSupported() throws ConfigurationException { Configuration c = setUpReloadTest(true); assertEquals("Name not changed in sub config", NEW_TABLE_NAME, config .getString("name")); assertEquals("Name not changed in parent", NEW_TABLE_NAME, c .getString("tables.table(1).name")); } /** * Tests whether events are fired if a change of the parent is detected. */ @Test public void testParentReloadEvents() throws ConfigurationException { setUpReloadTest(true); ConfigurationListenerTestImpl l = new ConfigurationListenerTestImpl(); config.addConfigurationListener(l); config.getString("name"); assertEquals("Wrong number of events", 2, l.events.size()); boolean before = true; for (ConfigurationEvent e : l.events) { assertEquals("Wrong configuration", config, e.getSource()); assertEquals("Wrong event type", HierarchicalConfiguration.EVENT_SUBNODE_CHANGED, e .getType()); assertNull("Got a property name", e.getPropertyName()); assertNull("Got a property value", e.getPropertyValue()); assertEquals("Wrong before flag", before, e.isBeforeUpdate()); before = !before; } } /** * Tests a reload operation for the parent configuration when the subnode * configuration is aware of reloads, and the parent configuration is * accessed first. The new value should be returned. */ @Test public void testParentReloadSupportAccessParent() throws ConfigurationException { Configuration c = setUpReloadTest(true); assertEquals("Name not changed in parent", NEW_TABLE_NAME, c .getString("tables.table(1).name")); assertEquals("Name not changed in sub config", NEW_TABLE_NAME, config .getString("name")); } /** * Tests whether reloads work with sub subnode configurations. */ @Test public void testParentReloadSubSubnode() throws ConfigurationException { setUpReloadTest(true); SubnodeConfiguration sub = config.configurationAt("fields", true); assertEquals("Wrong subnode key", "tables.table(1).fields", sub .getSubnodeKey()); assertEquals("Changed field not detected", "newField", sub .getString("field(0).name")); } /** * Tests creating a sub sub config when the sub config is not aware of * changes. Then the sub sub config shouldn't be either. */ @Test public void testParentReloadSubSubnodeNoChangeSupport() throws ConfigurationException { setUpReloadTest(false); SubnodeConfiguration sub = config.configurationAt("fields", true); assertNull("Sub sub config is attached to parent", sub.getSubnodeKey()); assertEquals("Changed field name returned", TABLE_FIELDS[1][0], sub .getString("field(0).name")); } /** * Prepares a test for a reload operation. * * @param supportReload a flag whether the subnode configuration should * support reload operations * @return the parent configuration that can be used for testing * @throws ConfigurationException if an error occurs */ private XMLConfiguration setUpReloadTest(boolean supportReload) throws ConfigurationException { try { File testFile = folder.newFile(); XMLConfiguration xmlConf = new XMLConfiguration(parent); xmlConf.setFile(testFile); xmlConf.save(); config = xmlConf.configurationAt("tables.table(1)", supportReload); assertEquals("Wrong table name", TABLE_NAMES[1], config.getString("name")); xmlConf.setReloadingStrategy(new FileAlwaysReloadingStrategy()); // Now change the configuration file XMLConfiguration confUpdate = new XMLConfiguration(testFile); confUpdate.setProperty("tables.table(1).name", NEW_TABLE_NAME); confUpdate.setProperty("tables.table(1).fields.field(0).name", "newField"); confUpdate.save(); return xmlConf; } catch (IOException ioex) { throw new ConfigurationException(ioex); } } /** * Tests a manipulation of the parent configuration that causes the subnode * configuration to become invalid. In this case the sub config should be * detached and keep its old values. */ @Test public void testParentChangeDetach() { final String key = "tables.table(1)"; config = parent.configurationAt(key, true); assertEquals("Wrong subnode key", key, config.getSubnodeKey()); assertEquals("Wrong table name", TABLE_NAMES[1], config .getString("name")); parent.clearTree(key); assertEquals("Wrong table name after change", TABLE_NAMES[1], config .getString("name")); assertNull("Sub config was not detached", config.getSubnodeKey()); } /** * Tests detaching a subnode configuration when an exception is thrown * during reconstruction. This can happen e.g. if the expression engine is * changed for the parent. */ @Test public void testParentChangeDetatchException() { config = parent.configurationAt("tables.table(1)", true); parent.setExpressionEngine(new XPathExpressionEngine()); assertEquals("Wrong name of table", TABLE_NAMES[1], config .getString("name")); assertNull("Sub config was not detached", config.getSubnodeKey()); } /** * Initializes the parent configuration. This method creates the typical * structure of tables and fields nodes. * * @return the parent configuration */ protected HierarchicalConfiguration setUpParentConfig() { HierarchicalConfiguration conf = new HierarchicalConfiguration() { /** * Serial version UID. */ private static final long serialVersionUID = 1L; // Provide a special implementation of createNode() to check // if it is called by the subnode config @Override protected Node createNode(String name) { nodeCounter++; return super.createNode(name); } }; for (int i = 0; i < TABLE_NAMES.length; i++) { conf.addProperty("tables.table(-1).name", TABLE_NAMES[i]); for (int j = 0; j < TABLE_FIELDS[i].length; j++) { conf.addProperty("tables.table.fields.field(-1).name", TABLE_FIELDS[i][j]); } } return conf; } /** * Returns the root node for the subnode config. This method returns the * first table node. * * @param conf the parent config * @return the root node for the subnode config */ protected ConfigurationNode getSubnodeRoot(HierarchicalConfiguration conf) { ConfigurationNode root = conf.getRoot(); return root.getChild(0).getChild(0); } /** * Performs a standard initialization of the subnode config to test. */ protected void setUpSubnodeConfig() { config = new SubnodeConfiguration(parent, getSubnodeRoot(parent)); } /** * A specialized configuration listener for testing whether the expected * events are fired. */ private static class ConfigurationListenerTestImpl implements ConfigurationListener { /** Stores the events received.*/ final List events = new ArrayList(); public void configurationChanged(ConfigurationEvent event) { events.add(event); } } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestSubsetConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestSubsetConfiguratio100644 30366 12232154104 33667 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; import java.util.Set; import org.apache.commons.configuration.interpol.ConfigurationInterpolator; import org.apache.commons.lang.text.StrLookup; import org.junit.Test; /** * Test case for the {@link SubsetConfiguration} class. * * @author Emmanuel Bourg * @version $Id: TestSubsetConfiguration.java 1225019 2011-12-27 21:18:54Z oheger $ */ public class TestSubsetConfiguration { static final String TEST_DIR = ConfigurationAssert.TEST_DIR_NAME; static final String TEST_FILE = "testDigesterConfiguration2.xml"; @Test public void testGetProperty() { Configuration conf = new BaseConfiguration(); conf.setProperty("test.key1", "value1"); conf.setProperty("testing.key2", "value1"); Configuration subset = new SubsetConfiguration(conf, "test", "."); assertFalse("the subset is empty", subset.isEmpty()); assertTrue("'key1' not found in the subset", subset.containsKey("key1")); assertFalse("'ng.key2' found in the subset", subset.containsKey("ng.key2")); } @Test public void testSetProperty() { Configuration conf = new BaseConfiguration(); Configuration subset = new SubsetConfiguration(conf, "test", "."); // set a property in the subset and check the parent subset.setProperty("key1", "value1"); assertEquals("key1 in the subset configuration", "value1", subset.getProperty("key1")); assertEquals("test.key1 in the parent configuration", "value1", conf.getProperty("test.key1")); // set a property in the parent and check in the subset conf.setProperty("test.key2", "value2"); assertEquals("test.key2 in the parent configuration", "value2", conf.getProperty("test.key2")); assertEquals("key2 in the subset configuration", "value2", subset.getProperty("key2")); } @Test public void testGetParentKey() { // subset with delimiter SubsetConfiguration subset = new SubsetConfiguration(null, "prefix", "."); assertEquals("parent key for \"key\"", "prefix.key", subset.getParentKey("key")); assertEquals("parent key for \"\"", "prefix", subset.getParentKey("")); // subset without delimiter subset = new SubsetConfiguration(null, "prefix", null); assertEquals("parent key for \"key\"", "prefixkey", subset.getParentKey("key")); assertEquals("parent key for \"\"", "prefix", subset.getParentKey("")); } @Test public void testGetChildKey() { // subset with delimiter SubsetConfiguration subset = new SubsetConfiguration(null, "prefix", "."); assertEquals("parent key for \"prefixkey\"", "key", subset.getChildKey("prefix.key")); assertEquals("parent key for \"prefix\"", "", subset.getChildKey("prefix")); // subset without delimiter subset = new SubsetConfiguration(null, "prefix", null); assertEquals("parent key for \"prefixkey\"", "key", subset.getChildKey("prefixkey")); assertEquals("parent key for \"prefix\"", "", subset.getChildKey("prefix")); } @Test public void testGetKeys() { Configuration conf = new BaseConfiguration(); conf.setProperty("test", "value0"); conf.setProperty("test.key1", "value1"); conf.setProperty("testing.key2", "value1"); Configuration subset = new SubsetConfiguration(conf, "test", "."); Iterator it = subset.getKeys(); assertEquals("1st key", "", it.next()); assertEquals("2nd key", "key1", it.next()); assertFalse("too many elements", it.hasNext()); } @Test public void testGetKeysWithPrefix() { Configuration conf = new BaseConfiguration(); conf.setProperty("test.abc", "value0"); conf.setProperty("test.abc.key1", "value1"); conf.setProperty("test.abcdef.key2", "value1"); Configuration subset = new SubsetConfiguration(conf, "test", "."); Iterator it = subset.getKeys("abc"); assertEquals("1st key", "abc", it.next()); assertEquals("2nd key", "abc.key1", it.next()); assertFalse("too many elements", it.hasNext()); } @Test public void testGetList() { Configuration conf = new BaseConfiguration(); conf.setProperty("test.abc", "value0,value1"); conf.addProperty("test.abc", "value3"); Configuration subset = new SubsetConfiguration(conf, "test", "."); List list = subset.getList("abc", new ArrayList()); assertEquals(3, list.size()); } @Test public void testGetParent() { Configuration conf = new BaseConfiguration(); SubsetConfiguration subset = new SubsetConfiguration(conf, "prefix", "."); assertEquals("parent", conf, subset.getParent()); } @Test public void testGetPrefix() { Configuration conf = new BaseConfiguration(); SubsetConfiguration subset = new SubsetConfiguration(conf, "prefix", "."); assertEquals("prefix", "prefix", subset.getPrefix()); } @Test public void testSetPrefix() { Configuration conf = new BaseConfiguration(); SubsetConfiguration subset = new SubsetConfiguration(conf, null, "."); subset.setPrefix("prefix"); assertEquals("prefix", "prefix", subset.getPrefix()); } @Test public void testThrowExceptionOnMissing() { BaseConfiguration config = new BaseConfiguration(); config.setThrowExceptionOnMissing(true); SubsetConfiguration subset = new SubsetConfiguration(config, "prefix"); try { subset.getString("foo"); fail("NoSuchElementException expected"); } catch (NoSuchElementException e) { // expected } config.setThrowExceptionOnMissing(false); assertNull(subset.getString("foo")); subset.setThrowExceptionOnMissing(true); try { config.getString("foo"); fail("NoSuchElementException expected"); } catch (NoSuchElementException e) { // expected } } @SuppressWarnings("deprecation") @Test public void testNested() throws Exception { ConfigurationFactory factory = new ConfigurationFactory(); File src = new File(new File(TEST_DIR), TEST_FILE); factory.setConfigurationURL(src.toURL()); Configuration config = factory.getConfiguration(); Configuration subConf = config.subset("tables.table(0)"); assertTrue(subConf.getKeys().hasNext()); Configuration subSubConf = subConf.subset("fields.field(1)"); Iterator itKeys = subSubConf.getKeys(); Set keys = new HashSet(); keys.add("name"); keys.add("type"); while(itKeys.hasNext()) { String k = itKeys.next(); assertTrue(keys.contains(k)); keys.remove(k); } assertTrue(keys.isEmpty()); } @Test public void testClear() { Configuration config = new BaseConfiguration(); config.setProperty("test.key1", "value1"); config.setProperty("testing.key2", "value1"); Configuration subset = config.subset("test"); subset.clear(); assertTrue("the subset is not empty", subset.isEmpty()); assertFalse("the parent configuration is empty", config.isEmpty()); } @Test public void testSetListDelimiter() { BaseConfiguration config = new BaseConfiguration(); Configuration subset = config.subset("prefix"); config.setListDelimiter('/'); subset.addProperty("list", "a/b/c"); assertEquals("Wrong size of list", 3, config.getList("prefix.list") .size()); ((AbstractConfiguration) subset).setListDelimiter(';'); subset.addProperty("list2", "a;b;c"); assertEquals("Wrong size of list2", 3, config.getList("prefix.list2") .size()); } @Test public void testGetListDelimiter() { BaseConfiguration config = new BaseConfiguration(); AbstractConfiguration subset = (AbstractConfiguration) config .subset("prefix"); config.setListDelimiter('/'); assertEquals("Wrong list delimiter in subset", '/', subset .getListDelimiter()); subset.setListDelimiter(';'); assertEquals("Wrong list delimiter in parent", ';', config .getListDelimiter()); } @Test public void testSetDelimiterParsingDisabled() { BaseConfiguration config = new BaseConfiguration(); Configuration subset = config.subset("prefix"); config.setDelimiterParsingDisabled(true); subset.addProperty("list", "a,b,c"); assertEquals("Wrong value of property", "a,b,c", config .getString("prefix.list")); ((AbstractConfiguration) subset).setDelimiterParsingDisabled(false); subset.addProperty("list2", "a,b,c"); assertEquals("Wrong size of list2", 3, config.getList("prefix.list2") .size()); } @Test public void testIsDelimiterParsingDisabled() { BaseConfiguration config = new BaseConfiguration(); AbstractConfiguration subset = (AbstractConfiguration) config .subset("prefix"); config.setDelimiterParsingDisabled(true); assertTrue("Wrong value of list parsing flag in subset", subset .isDelimiterParsingDisabled()); subset.setDelimiterParsingDisabled(false); assertFalse("Wrong value of list parsing flag in parent", config .isDelimiterParsingDisabled()); } /** * Tests manipulating the interpolator. */ @Test public void testInterpolator() { BaseConfiguration config = new BaseConfiguration(); AbstractConfiguration subset = (AbstractConfiguration) config .subset("prefix"); InterpolationTestHelper.testGetInterpolator(subset); } @Test public void testLocalLookupsInInterpolatorAreInherited() { BaseConfiguration config = new BaseConfiguration(); ConfigurationInterpolator interpolator = config.getInterpolator(); interpolator.registerLookup("brackets", new StrLookup(){ @Override public String lookup(String key) { return "(" + key +")"; } }); config.setProperty("prefix.var", "${brackets:x}"); AbstractConfiguration subset = (AbstractConfiguration) config .subset("prefix"); assertEquals("Local lookup was not inherited", "(x)", subset .getString("var", "")); } @Test public void testInterpolationForKeysOfTheParent() { BaseConfiguration config = new BaseConfiguration(); config.setProperty("test", "junit"); config.setProperty("prefix.key", "${test}"); AbstractConfiguration subset = (AbstractConfiguration) config .subset("prefix"); assertEquals("Interpolation does not resolve parent keys", "junit", subset.getString("key", "")); } } ././@LongLink100644 0 0 153 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestSystemConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestSystemConfiguratio100644 3334 12232154104 33661 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import java.util.Properties; import org.junit.Test; /** * Tests for {@code SystemConfiguration}. * * @author Emmanuel Bourg * @version $Id: TestSystemConfiguration.java 1225020 2011-12-27 21:20:45Z oheger $ */ public class TestSystemConfiguration { @Test public void testSystemConfiguration() { Properties props = System.getProperties(); props.put("test.number", "123"); Configuration conf = new SystemConfiguration(); assertEquals("number", 123, conf.getInt("test.number")); } @Test public void testSetSystemProperties() { PropertiesConfiguration props = new PropertiesConfiguration(); props.addProperty("test.name", "Apache"); SystemConfiguration.setSystemProperties(props); assertEquals("System Properties", "Apache", System.getProperty("test.name")); } } ././@LongLink100644 0 0 165 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestSystemConfigurationRegression.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestSystemConfiguratio100644 2364 12232154104 33663 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import org.junit.Test; import org.junit.Assert; import java.util.UUID; public class TestSystemConfigurationRegression { @Test public void testSystemPropertiesRegression() { SystemConfiguration sc = new SystemConfiguration(); int oldSize = sc.getMap().size(); System.setProperty(UUID.randomUUID().toString(), "x"); Assert.assertEquals(oldSize + 1, sc.getMap().size()); } } ././@LongLink100644 0 0 156 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestThreesomeConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestThreesomeConfigura100644 4001 12232154104 33604 0ustarhenningstaff 0 0 package org.apache.commons.configuration; /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ import static org.junit.Assert.assertEquals; import java.util.List; import org.junit.Before; import org.junit.Test; /** * A base class for testing {@link * org.apache.commons.configuration.BasePropertiesConfiguration} * extensions. * * @version $Id: TestThreesomeConfiguration.java 1225021 2011-12-27 21:23:22Z oheger $ */ public class TestThreesomeConfiguration { protected Configuration conf; @Before public void setUp() throws Exception { conf = new PropertiesConfiguration("threesome.properties"); } @Test public void testList1() throws Exception { List packages = conf.getList("test.threesome.one"); // we should get 3 packages here assertEquals(3, packages.size()); } @Test public void testList2() throws Exception { List packages = conf.getList("test.threesome.two"); // we should get 3 packages here assertEquals(3, packages.size()); } @Test public void testList3() throws Exception { List packages = conf.getList("test.threesome.three"); // we should get 3 packages here assertEquals(3, packages.size()); } } ././@LongLink100644 0 0 157 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestVFSConfigurationBuilder.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestVFSConfigurationBu100644 133442 12232154104 33544 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.io.Reader; import java.io.Writer; import java.net.URL; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.commons.configuration.beanutils.BeanHelper; import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test class for VFSConfigurationBuilder. * * @author Commons * Configuration team * @version $Id: TestVFSConfigurationBuilder.java 1308148 2012-04-01 16:27:41Z rgoers $ */ public class TestVFSConfigurationBuilder { /** Test configuration definition file. */ private static final File TEST_FILE = ConfigurationAssert .getTestFile("testDigesterConfiguration.xml"); private static final File ADDITIONAL_FILE = ConfigurationAssert .getTestFile("testDigesterConfiguration2.xml"); private static final File OPTIONAL_FILE = ConfigurationAssert .getTestFile("testDigesterOptionalConfiguration.xml"); private static final File OPTIONALEX_FILE = ConfigurationAssert .getTestFile("testDigesterOptionalConfigurationEx.xml"); private static final File MULTI_FILE = ConfigurationAssert .getTestFile("testDigesterConfiguration3.xml"); private static final File INIT_FILE = ConfigurationAssert .getTestFile("testComplexInitialization.xml"); private static final File CLASS_FILE = ConfigurationAssert .getTestFile("testExtendedClass.xml"); private static final File PROVIDER_FILE = ConfigurationAssert .getTestFile("testConfigurationProvider.xml"); private static final File EXTENDED_PROVIDER_FILE = ConfigurationAssert .getTestFile("testExtendedXMLConfigurationProvider.xml"); private static final File GLOBAL_LOOKUP_FILE = ConfigurationAssert .getTestFile("testGlobalLookup.xml"); private static final File SYSTEM_PROPS_FILE = ConfigurationAssert .getTestFile("testSystemProperties.xml"); private static final File VALIDATION_FILE = ConfigurationAssert .getTestFile("testValidation.xml"); private static final File VALIDATION2_FILE = ConfigurationAssert .getTestFile("testValidation2.xml"); private static final File MULTI_TENENT_FILE = ConfigurationAssert .getTestFile("testMultiTenentConfigurationBuilder.xml"); private static final File FILESYSTEM_FILE = ConfigurationAssert .getTestFile("testFileSystem.xml"); private static final File FILERELOAD_FILE = ConfigurationAssert .getTestFile("testFileReloadConfigurationBuilder.xml"); private static final File MULTI_RELOAD_FILE1 = ConfigurationAssert .getTestFile("testVFSMultiTenentConfigurationBuilder1.xml"); private static final File MULTI_RELOAD_FILE2 = ConfigurationAssert .getTestFile("testVFSMultiTenentConfigurationBuilder2.xml"); /** Constant for the name of an optional configuration.*/ private static final String OPTIONAL_NAME = "optionalConfig"; /** Stores the object to be tested. */ DefaultConfigurationBuilder factory; @Before public void setUp() throws Exception { System .setProperty("java.naming.factory.initial", "org.apache.commons.configuration.MockInitialContextFactory"); System.setProperty("test_file_xml", "test.xml"); System.setProperty("test_file_combine", "testcombine1.xml"); System.setProperty("basePath", "file://" + System.getProperty("user.dir") + "/target/test-classes"); FileSystem.setDefaultFileSystem(new VFSFileSystem()); factory = new DefaultConfigurationBuilder(); factory.clearErrorListeners(); // avoid exception messages } @After public void tearDown() throws Exception { FileSystem.resetDefaultFileSystem(); } /** * Tests the isReservedNode() method of ConfigurationDeclaration. */ @Test public void testConfigurationDeclarationIsReserved() { DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory); DefaultConfigurationNode parent = new DefaultConfigurationNode(); DefaultConfigurationNode nd = new DefaultConfigurationNode("at"); parent.addAttribute(nd); assertTrue("Attribute at not recognized", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("optional"); parent.addAttribute(nd); assertTrue("Attribute optional not recognized", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("config-class"); parent.addAttribute(nd); assertTrue("Inherited attribute not recognized", decl .isReservedNode(nd)); nd = new DefaultConfigurationNode("different"); parent.addAttribute(nd); assertFalse("Wrong reserved attribute", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("at"); parent.addChild(nd); assertFalse("Node type not evaluated", decl.isReservedNode(nd)); } /** * Tests if the at attribute is correctly detected as reserved attribute. */ @Test public void testConfigurationDeclarationIsReservedAt() { checkOldReservedAttribute("at"); } /** * Tests if the optional attribute is correctly detected as reserved * attribute. */ @Test public void testConfigurationDeclarationIsReservedOptional() { checkOldReservedAttribute("optional"); } /** * Tests if special reserved attributes are recognized by the * isReservedNode() method. For compatibility reasons the attributes "at" * and "optional" are also treated as reserved attributes, but only if there * are no corresponding attributes with the "config-" prefix. * * @param name the attribute name */ private void checkOldReservedAttribute(String name) { DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory); DefaultConfigurationNode parent = new DefaultConfigurationNode(); DefaultConfigurationNode nd = new DefaultConfigurationNode("config-" + name); parent.addAttribute(nd); assertTrue("config-" + name + " attribute not recognized", decl .isReservedNode(nd)); DefaultConfigurationNode nd2 = new DefaultConfigurationNode(name); parent.addAttribute(nd2); assertFalse(name + " is reserved though config- exists", decl .isReservedNode(nd2)); assertTrue("config- attribute not recognized when " + name + " exists", decl.isReservedNode(nd)); } /** * Tests access to certain reserved attributes of a * ConfigurationDeclaration. */ @Test public void testConfigurationDeclarationGetAttributes() { factory.addProperty("xml.fileName", "test.xml"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("xml")); assertNull("Found an at attribute", decl.getAt()); assertFalse("Found an optional attribute", decl.isOptional()); factory.addProperty("xml[@config-at]", "test1"); assertEquals("Wrong value of at attribute", "test1", decl.getAt()); factory.addProperty("xml[@at]", "test2"); assertEquals("Wrong value of config-at attribute", "test1", decl.getAt()); factory.clearProperty("xml[@config-at]"); assertEquals("Old at attribute not detected", "test2", decl.getAt()); factory.addProperty("xml[@config-optional]", "true"); assertTrue("Wrong value of optional attribute", decl.isOptional()); factory.addProperty("xml[@optional]", "false"); assertTrue("Wrong value of config-optional attribute", decl.isOptional()); factory.clearProperty("xml[@config-optional]"); factory.setProperty("xml[@optional]", Boolean.TRUE); assertTrue("Old optional attribute not detected", decl.isOptional()); } /** * Tests whether an invalid value of an optional attribute is detected. */ @Test(expected = ConfigurationRuntimeException.class) public void testConfigurationDeclarationOptionalAttributeInvalid() { factory.addProperty("xml.fileName", "test.xml"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("xml")); factory.setProperty("xml[@optional]", "invalid value"); decl.isOptional(); } /** * Tests adding a new configuration provider. */ @Test public void testAddConfigurationProvider() { DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider(); assertNull("Provider already registered", factory .providerForTag("test")); factory.addConfigurationProvider("test", provider); assertSame("Provider not registered", provider, factory .providerForTag("test")); } /** * Tries to register a null configuration provider. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testAddConfigurationProviderNull() { factory.addConfigurationProvider("test", null); } /** * Tries to register a configuration provider for a null tag. This should * cause an exception to be thrown. */ @Test(expected = IllegalArgumentException.class) public void testAddConfigurationProviderNullTag() { factory.addConfigurationProvider(null, new DefaultConfigurationBuilder.ConfigurationProvider()); } /** * Tests removing configuration providers. */ @Test public void testRemoveConfigurationProvider() { assertNull("Removing unknown provider", factory .removeConfigurationProvider("test")); assertNull("Removing provider for null tag", factory .removeConfigurationProvider(null)); DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider(); factory.addConfigurationProvider("test", provider); assertSame("Failed to remove provider", provider, factory .removeConfigurationProvider("test")); assertNull("Provider still registered", factory.providerForTag("test")); } /** * Tests creating a configuration object from a configuration declaration. */ @Test public void testConfigurationBeanFactoryCreateBean() { factory.addConfigurationProvider("test", new DefaultConfigurationBuilder.ConfigurationProvider( PropertiesConfiguration.class)); factory.addProperty("test[@throwExceptionOnMissing]", "true"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("test")); PropertiesConfiguration conf = (PropertiesConfiguration) BeanHelper .createBean(decl); assertTrue("Property was not initialized", conf .isThrowExceptionOnMissing()); } /** * Tests creating a configuration object from an unknown tag. This should * cause an exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testConfigurationBeanFactoryCreateUnknownTag() { factory.addProperty("test[@throwExceptionOnMissing]", "true"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("test")); BeanHelper.createBean(decl); } /** * Tests loading a simple configuration definition file. */ @Test public void testLoadConfiguration() throws ConfigurationException { factory.setFile(TEST_FILE); checkConfiguration(); } /** * Tests the file constructor. */ @Test public void testLoadConfigurationFromFile() throws ConfigurationException { factory = new DefaultConfigurationBuilder(TEST_FILE); checkConfiguration(); } /** * Tests the file name constructor. */ @Test public void testLoadConfigurationFromFileName() throws ConfigurationException { factory = new DefaultConfigurationBuilder(TEST_FILE.getAbsolutePath()); checkConfiguration(); } /** * Tests the URL constructor. */ @Test public void testLoadConfigurationFromURL() throws Exception { factory = new DefaultConfigurationBuilder(TEST_FILE.toURI().toURL()); checkConfiguration(); } /** * Tests if the configuration was correctly created by the factory. */ private void checkConfiguration() throws ConfigurationException { CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory .getConfiguration(); assertEquals("Number of configurations", 3, compositeConfiguration .getNumberOfConfigurations()); assertEquals(PropertiesConfiguration.class, compositeConfiguration .getConfiguration(0).getClass()); assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration .getConfiguration(1).getClass()); assertEquals(XMLConfiguration.class, compositeConfiguration .getConfiguration(2).getClass()); // check the first configuration PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration .getConfiguration(0); assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc .getFileName()); // check some properties checkProperties(compositeConfiguration); } /** * Checks if the passed in configuration contains the expected properties. * * @param compositeConfiguration the configuration to check */ private void checkProperties(Configuration compositeConfiguration) { assertTrue("Make sure we have loaded our key", compositeConfiguration .getBoolean("test.boolean")); assertEquals("I'm complex!", compositeConfiguration .getProperty("element2.subelement.subsubelement")); assertEquals("property in the XMLPropertiesConfiguration", "value1", compositeConfiguration.getProperty("key1")); } /** * Tests loading a configuration definition file with an additional section. */ @Test public void testLoadAdditional() throws ConfigurationException { factory.setFile(ADDITIONAL_FILE); CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory .getConfiguration(); assertEquals("Verify how many configs", 2, compositeConfiguration .getNumberOfConfigurations()); // Test if union was constructed correctly Object prop = compositeConfiguration.getProperty("tables.table.name"); assertTrue(prop instanceof Collection); assertEquals(3, ((Collection) prop).size()); assertEquals("users", compositeConfiguration .getProperty("tables.table(0).name")); assertEquals("documents", compositeConfiguration .getProperty("tables.table(1).name")); assertEquals("tasks", compositeConfiguration .getProperty("tables.table(2).name")); prop = compositeConfiguration .getProperty("tables.table.fields.field.name"); assertTrue(prop instanceof Collection); assertEquals(17, ((Collection) prop).size()); assertEquals("smtp.mydomain.org", compositeConfiguration .getString("mail.host.smtp")); assertEquals("pop3.mydomain.org", compositeConfiguration .getString("mail.host.pop")); // This was overridden assertEquals("masterOfPost", compositeConfiguration .getString("mail.account.user")); assertEquals("topsecret", compositeConfiguration .getString("mail.account.psswd")); // This was overridden, too, but not in additional section assertEquals("enhanced factory", compositeConfiguration .getString("test.configuration")); } /** * Tests whether a default log error listener is registered at the builder * instance. */ @Test public void testLogErrorListener() { assertEquals("No default error listener registered", 1, new DefaultConfigurationBuilder().getErrorListeners().size()); } /** * Tests loading a definition file that contains optional configurations. */ @Test public void testLoadOptional() throws Exception { factory.setURL(OPTIONAL_FILE.toURI().toURL()); Configuration config = factory.getConfiguration(); assertTrue(config.getBoolean("test.boolean")); assertEquals("value", config.getProperty("element")); } /** * Tests whether loading a failing optional configuration causes an error * event. */ @Test public void testLoadOptionalErrorEvent() throws Exception { factory.clearErrorListeners(); ConfigurationErrorListenerImpl listener = new ConfigurationErrorListenerImpl(); factory.addErrorListener(listener); prepareOptionalTest("configuration", false); listener.verify(DefaultConfigurationBuilder.EVENT_ERR_LOAD_OPTIONAL, OPTIONAL_NAME, null); } /** * Tests loading a definition file with optional and non optional * configuration sources. One non optional does not exist, so this should * cause an exception. */ @Test(expected = ConfigurationException.class) public void testLoadOptionalWithException() throws ConfigurationException { factory.setFile(OPTIONALEX_FILE); factory.getConfiguration(); } /** * Tries to load a configuration file with an optional, non file-based * configuration. The optional attribute should work for other configuration * classes, too. */ @Test public void testLoadOptionalNonFileBased() throws ConfigurationException { CombinedConfiguration config = prepareOptionalTest("configuration", false); assertTrue("Configuration not empty", config.isEmpty()); assertEquals("Wrong number of configurations", 0, config .getNumberOfConfigurations()); } /** * Tests an optional, non existing configuration with the forceCreate * attribute. This configuration should be added to the resulting * configuration. */ @Test public void testLoadOptionalForceCreate() throws ConfigurationException { factory.setBasePath(TEST_FILE.getParent()); CombinedConfiguration config = prepareOptionalTest("xml", true); assertEquals("Wrong number of configurations", 1, config .getNumberOfConfigurations()); FileConfiguration fc = (FileConfiguration) config .getConfiguration(OPTIONAL_NAME); assertNotNull("Optional config not found", fc); assertEquals("File name was not set", "nonExisting.xml", fc .getFileName()); assertNotNull("Base path was not set", fc.getBasePath()); } /** * Tests loading an embedded optional configuration builder with the force * create attribute. */ @Test public void testLoadOptionalBuilderForceCreate() throws ConfigurationException { CombinedConfiguration config = prepareOptionalTest("configuration", true); assertEquals("Wrong number of configurations", 1, config .getNumberOfConfigurations()); assertTrue( "Wrong optional configuration type", config.getConfiguration(OPTIONAL_NAME) instanceof CombinedConfiguration); } /** * Tests loading an optional configuration with the force create attribute * set. The provider will always throw an exception. In this case the * configuration will not be added to the resulting combined configuration. */ @Test public void testLoadOptionalForceCreateWithException() throws ConfigurationException { factory.addConfigurationProvider("test", new DefaultConfigurationBuilder.ConfigurationBuilderProvider() { // Throw an exception here, too @Override public AbstractConfiguration getEmptyConfiguration( DefaultConfigurationBuilder.ConfigurationDeclaration decl) throws Exception { throw new Exception("Unable to create configuration!"); } }); CombinedConfiguration config = prepareOptionalTest("test", true); assertEquals("Optional configuration could be created", 0, config .getNumberOfConfigurations()); } /** * Prepares a test for loading a configuration definition file with an * optional configuration declaration. * * @param tag the tag name with the optional configuration * @param force the forceCreate attribute * @return the combined configuration obtained from the builder * @throws org.apache.commons.configuration.ConfigurationException if an error occurs */ private CombinedConfiguration prepareOptionalTest(String tag, boolean force) throws ConfigurationException { String prefix = "override." + tag; factory.addProperty(prefix + "[@fileName]", "nonExisting.xml"); factory.addProperty(prefix + "[@config-optional]", Boolean.TRUE); factory.addProperty(prefix + "[@config-name]", OPTIONAL_NAME); if (force) { factory.addProperty(prefix + "[@config-forceCreate]", Boolean.TRUE); } return factory.getConfiguration(false); } /** * Tests loading a definition file with multiple different sources. */ @Test public void testLoadDifferentSources() throws ConfigurationException { factory.setFile(MULTI_FILE); Configuration config = factory.getConfiguration(); assertFalse(config.isEmpty()); assertTrue(config instanceof CombinedConfiguration); CombinedConfiguration cc = (CombinedConfiguration) config; assertEquals("Wrong number of configurations", 1, cc .getNumberOfConfigurations()); assertNotNull(config .getProperty("tables.table(0).fields.field(2).name")); assertNotNull(config.getProperty("element2.subelement.subsubelement")); assertEquals("value", config.getProperty("element3")); assertEquals("foo", config.getProperty("element3[@name]")); assertNotNull(config.getProperty("mail.account.user")); // test JNDIConfiguration assertNotNull(config.getProperty("test.onlyinjndi")); assertTrue(config.getBoolean("test.onlyinjndi")); Configuration subset = config.subset("test"); assertNotNull(subset.getProperty("onlyinjndi")); assertTrue(subset.getBoolean("onlyinjndi")); // test SystemConfiguration assertNotNull(config.getProperty("java.version")); assertEquals(System.getProperty("java.version"), config .getString("java.version")); } /** * Tests if the base path is correctly evaluated. */ @Test public void testSetConfigurationBasePath() throws ConfigurationException { factory.addProperty("properties[@fileName]", "test.properties"); File deepDir = new File(ConfigurationAssert.TEST_DIR, "config/deep"); factory.setConfigurationBasePath(deepDir.getAbsolutePath()); Configuration config = factory.getConfiguration(false); assertEquals("Wrong property value", "somevalue", config .getString("somekey")); } /** * Tests reading a configuration definition file that contains complex * initialization of properties of the declared configuration sources. */ @Test public void testComplexInitialization() throws ConfigurationException { factory.setFile(INIT_FILE); CombinedConfiguration cc = (CombinedConfiguration) factory .getConfiguration(); assertEquals("System property not found", "test.xml", cc.getString("test_file_xml")); PropertiesConfiguration c1 = (PropertiesConfiguration) cc .getConfiguration(1); assertTrue( "Reloading strategy was not set", c1.getReloadingStrategy() instanceof FileChangedReloadingStrategy); assertEquals("Refresh delay was not set", 10000, ((FileChangedReloadingStrategy) c1.getReloadingStrategy()) .getRefreshDelay()); Configuration xmlConf = cc.getConfiguration("xml"); assertEquals("Property not found", "I'm complex!", xmlConf .getString("element2/subelement/subsubelement")); assertEquals("List index not found", "two", xmlConf .getString("list[0]/item[1]")); assertEquals("Property in combiner file not found", "yellow", cc .getString("/gui/selcolor")); assertTrue("Delimiter flag was not set", cc .isDelimiterParsingDisabled()); assertTrue("Expression engine was not set", cc.getExpressionEngine() instanceof XPathExpressionEngine); } /** * Tests if the returned combined configuration has the expected structure. */ @Test public void testCombinedConfiguration() throws ConfigurationException { factory.setFile(INIT_FILE); CombinedConfiguration cc = (CombinedConfiguration) factory .getConfiguration(); assertNotNull("Properties configuration not found", cc .getConfiguration("properties")); assertNotNull("XML configuration not found", cc.getConfiguration("xml")); assertEquals("Wrong number of contained configs", 4, cc .getNumberOfConfigurations()); CombinedConfiguration cc2 = (CombinedConfiguration) cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); assertNotNull("No additional configuration found", cc2); Set names = cc2.getConfigurationNames(); assertEquals("Wrong number of contained additional configs", 2, names .size()); assertTrue("Config 1 not contained", names.contains("combiner1")); assertTrue("Config 2 not contained", names.contains("combiner2")); } /** * Tests the structure of the returned combined configuration if there is no * additional section. */ @Test public void testCombinedConfigurationNoAdditional() throws ConfigurationException { factory.setFile(TEST_FILE); CombinedConfiguration cc = factory.getConfiguration(true); assertNull("Additional configuration was found", cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME)); } /** * Tests whether the list node definition was correctly processed. */ @Test public void testCombinedConfigurationListNodes() throws ConfigurationException { factory.setFile(INIT_FILE); CombinedConfiguration cc = factory.getConfiguration(true); Set listNodes = cc.getNodeCombiner().getListNodes(); assertEquals("Wrong number of list nodes", 2, listNodes.size()); assertTrue("table node not a list node", listNodes.contains("table")); assertTrue("list node not a list node", listNodes.contains("list")); CombinedConfiguration cca = (CombinedConfiguration) cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); listNodes = cca.getNodeCombiner().getListNodes(); assertTrue("Found list nodes for additional combiner", listNodes .isEmpty()); } /** * Tests whether a configuration builder can itself be declared in a * configuration definition file. */ @Test public void testConfigurationBuilderProvider() throws ConfigurationException { factory.addProperty("override.configuration[@fileName]", TEST_FILE .getAbsolutePath()); CombinedConfiguration cc = factory.getConfiguration(false); assertEquals("Wrong number of configurations", 1, cc .getNumberOfConfigurations()); checkProperties(cc); } /** * Tests whether XML settings can be inherited. */ @Test public void testLoadXMLWithSettings() throws Exception { File confDir = new File("conf"); File targetDir = new File("target"); File testXMLValidationSource = new File(confDir, "testValidateInvalid.xml"); File testSavedXML = new File(targetDir, "testSave.xml"); File testSavedFactory = new File(targetDir, "testSaveFactory.xml"); URL dtdFile = getClass().getResource("/properties.dtd"); final String publicId = "http://commons.apache.org/test.dtd"; XMLConfiguration config = new XMLConfiguration("testDtd.xml"); config.setPublicID(publicId); config.save(testSavedXML); factory.addProperty("xml[@fileName]", testSavedXML.getAbsolutePath()); factory.addProperty("xml(0)[@validating]", "true"); factory.addProperty("xml(-1)[@fileName]", testXMLValidationSource .getAbsolutePath()); factory.addProperty("xml(1)[@config-optional]", "true"); factory.addProperty("xml(1)[@validating]", "true"); factory.save(testSavedFactory); factory = new DefaultConfigurationBuilder(); factory.setFile(testSavedFactory); factory.registerEntityId(publicId, dtdFile); factory.clearErrorListeners(); Configuration c = factory.getConfiguration(); assertEquals("Wrong property value", "value1", c.getString("entry(0)")); assertFalse("Invalid XML source was loaded", c .containsKey("table.name")); testSavedXML.delete(); testSavedFactory.delete(); } /** * Tests loading a configuration definition file that defines a custom * result class. */ @Test public void testExtendedClass() throws ConfigurationException { factory.setFile(CLASS_FILE); CombinedConfiguration cc = factory.getConfiguration(true); String prop = (String)cc.getProperty("test"); assertEquals("Expected 'Extended', actual '" + prop + "'", "Extended", prop); assertTrue("Wrong result class: " + cc.getClass(), cc instanceof TestDefaultConfigurationBuilder.ExtendedCombinedConfiguration); } /** * Tests loading a configuration definition file that defines new providers. */ @Test public void testConfigurationProvider() throws ConfigurationException { factory.setFile(PROVIDER_FILE); factory.getConfiguration(true); DefaultConfigurationBuilder.ConfigurationProvider provider = factory .providerForTag("test"); assertNotNull("Provider 'test' not registered", provider); } /** * Tests loading a configuration definition file that defines new providers. */ @Test public void testExtendedXMLConfigurationProvider() throws ConfigurationException { factory.setFile(EXTENDED_PROVIDER_FILE); CombinedConfiguration cc = factory.getConfiguration(true); DefaultConfigurationBuilder.ConfigurationProvider provider = factory .providerForTag("test"); assertNotNull("Provider 'test' not registered", provider); Configuration config = cc.getConfiguration("xml"); assertNotNull("Test configuration not present", config); assertTrue("Configuration is not ExtendedXMLConfiguration, is " + config.getClass().getName(), config instanceof TestDefaultConfigurationBuilder.ExtendedXMLConfiguration); } @Test public void testGlobalLookup() throws Exception { factory.setFile(GLOBAL_LOOKUP_FILE); CombinedConfiguration cc = factory.getConfiguration(true); String value = cc.getInterpolator().lookup("test:test_key"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","test.value",value); } @Test public void testSystemProperties() throws Exception { factory.setFile(SYSTEM_PROPS_FILE); factory.getConfiguration(true); String value = System.getProperty("key1"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","value1",value); } @Test public void testValidation() throws Exception { factory.setFile(VALIDATION_FILE); CombinedConfiguration cc = factory.getConfiguration(true); String value = cc.getString("key1"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","value1",value); } @Test public void testValidation2() throws Exception { factory.setFile(VALIDATION2_FILE); CombinedConfiguration cc = factory.getConfiguration(true); String value = cc.getString("key1"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","value1",value); } @Test public void testMultiTenentConfiguration() throws Exception { factory.setFile(MULTI_TENENT_FILE); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify(null, config, 50); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testMultiTenentConfiguration2() throws Exception { factory.setFile(MULTI_TENENT_FILE); System.setProperty("Id", "1004"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testMultiTenentConfiguration3() throws Exception { factory.setFile(MULTI_TENENT_FILE); System.setProperty("Id", "1005"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testSetFileSystem() throws Exception { factory.setFile(PROVIDER_FILE); FileSystem fs = new VFSFileSystem(); factory.setFileSystem(fs); FileSystem.resetDefaultFileSystem(); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); List list = config.getConfigurations(); assertTrue("Incorrect number of configurations - " + list.size(), list.size() == 4); Iterator iter = list.iterator(); while (iter.hasNext()) { Configuration conf = iter.next(); if (conf instanceof FileSystemBased) { assertTrue("Incorrect file system for Configuration " + conf, ((FileSystemBased)conf).getFileSystem() == fs); } else if (conf instanceof CombinedConfiguration) { Iterator it = ((CombinedConfiguration)conf).getConfigurations().iterator(); while (it.hasNext()) { conf = it.next(); if (conf instanceof FileSystemBased) { assertTrue("Incorrect file system for Configuration " + conf, ((FileSystemBased)conf).getFileSystem() == fs); } } } } } @Test public void testConfiguredFileSystem() throws Exception { factory.setFile(FILESYSTEM_FILE); FileSystem.resetDefaultFileSystem(); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); FileSystem fs = factory.getFileSystem(); assertNotNull("No File System",fs); assertTrue("Incorrect File System", fs instanceof VFSFileSystem); List list = config.getConfigurations(); assertTrue("Incorrect number of configurations - " + list.size(), list.size() == 4); Iterator iter = list.iterator(); while (iter.hasNext()) { Configuration conf = iter.next(); if (conf instanceof FileSystemBased) { assertTrue("Incorrect file system for Configuration " + conf, ((FileSystemBased)conf).getFileSystem() == fs); } else if (conf instanceof CombinedConfiguration) { Iterator it = ((CombinedConfiguration)conf).getConfigurations().iterator(); while (it.hasNext()) { conf = it.next(); if (conf instanceof FileSystemBased) { assertTrue("Incorrect file system for Configuration " + conf, ((FileSystemBased)conf).getFileSystem() == fs); } } } } } @Test public void testFileReload1() throws Exception { // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_1001.xml"); File output = new File("target/test-classes/testwrite/testMultiConfiguration_1001.xml"); output.delete(); output.getParentFile().mkdir(); copyFile(input, output); // Sleep to make sure the file timestamp is not in the same second as "now". Thread.sleep(1100); factory.setFile(FILERELOAD_FILE); FileSystem.resetDefaultFileSystem(); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); verify("1001", config, 15); Thread.sleep(1100); XMLConfiguration x = new XMLConfiguration(output); x.setProperty("rowsPerPage", "50"); x.save(); verify("1001", config, 50); output.delete(); } @Test public void testFileReload2() throws Exception { // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_1002.xml"); File output = new File("target/test-classes/testwrite/testMultiConfiguration_1002.xml"); output.delete(); factory.setFile(FILERELOAD_FILE); FileSystem.resetDefaultFileSystem(); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); verify("1002", config, 50); // Sleep to make sure the file timestamp is not in the same second as "now". Thread.sleep(1100); output.getParentFile().mkdir(); copyFile(input, output); verify("1002", config, 25); output.delete(); } @Test public void testFileReload3() throws Exception { // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_1001.xml"); File output = new File("target/test-classes/testwrite/testMultiConfiguration_1001.xml"); output.delete(); output.getParentFile().mkdir(); factory.setFile(FILERELOAD_FILE); FileSystem.resetDefaultFileSystem(); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); verify("1001", config, 50); copyFile(input, output); // Sleep to make sure the file timestamp is not in the same second as "now". Thread.sleep(1100); verify("1001", config, 15); XMLConfiguration x = new XMLConfiguration(output); x.setProperty("rowsPerPage", "25"); x.save(); // Sleep to make sure the file timestamp is not in the same second as "now". Thread.sleep(1100); verify("1001", config, 25); output.delete(); } @Test public void testReloadDefault() throws Exception { // create a new configuration String defaultName = "target/test-classes/testMultiConfiguration_default.xml"; File input = new File(defaultName); System.getProperties().remove("Id"); factory.setFile(MULTI_RELOAD_FILE1); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); verify("3001", config, 15); verify("3002", config, 25); System.setProperty("Id", "3002"); config.addProperty("/ TestProp", "Test"); assertTrue("Property not added", "Test".equals(config.getString("TestProp"))); System.getProperties().remove("Id"); //Sleep so refreshDelay elapses Thread.sleep(600); long time = System.currentTimeMillis(); long original = input.lastModified(); input.setLastModified(time); File defaultFile = new File(defaultName); long newTime = defaultFile.lastModified(); assertTrue("time mismatch", original != newTime); Thread.sleep(600); verify("3001", config, 15); verify("3002", config, 25); System.setProperty("Id", "3002"); String test = config.getString("TestProp"); assertNull("Property was not cleared by reload", test); } @Test public void testFileReloadSchemaValidationError() throws Exception { System.getProperties().remove("Id"); factory.setFile(MULTI_RELOAD_FILE2); CombinedConfiguration config = factory.getConfiguration(true); // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_3001.xml"); File output = new File("target/test-classes/testwrite/testMultiConfiguration_3001.xml"); output.delete(); output.getParentFile().mkdir(); copyFile(input, output); assertNotNull(config); verify("3001", config, 15); Thread.sleep(1100); XMLConfiguration x = new XMLConfiguration(); x.setFile(output); x.setAttributeSplittingDisabled(true); x.setDelimiterParsingDisabled(true); x.load(); x.setProperty("rowsPerPage", "test"); //Insure orginal timestamp and new timestamp aren't the same second. Thread.sleep(1100); x.save(); System.setProperty("Id", "3001"); try { config.getInt("rowsPerPage"); fail("No exception was thrown"); } catch (Exception ex) { } output.delete(); } private void copyFile(File input, File output) throws IOException { Reader reader = new FileReader(input); Writer writer = new FileWriter(output); char[] buffer = new char[4096]; int n = 0; while (-1 != (n = reader.read(buffer))) { writer.write(buffer, 0, n); } reader.close(); writer.close(); } private void verify(String key, CombinedConfiguration config, int rows) { if (key == null) { System.getProperties().remove("Id"); } else { System.setProperty("Id", key); } int actual = config.getInt("rowsPerPage"); assertTrue("expected: " + rows + " actual: " + actual, actual == rows); } }././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestWebdavConfigurationBuilder.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestWebdavConfiguratio100644 117320 12232154104 33646 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.io.OutputStreamWriter; import java.io.Reader; import java.io.Writer; import java.util.Collection; import java.util.HashMap; import java.util.Map; import java.util.Set; import org.apache.commons.configuration.beanutils.BeanHelper; import org.apache.commons.configuration.event.ConfigurationEvent; import org.apache.commons.configuration.event.ConfigurationListener; import org.apache.commons.configuration.reloading.FileChangedReloadingStrategy; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.apache.commons.vfs2.FileName; import org.apache.commons.vfs2.FileObject; import org.apache.commons.vfs2.FileSystemManager; import org.apache.commons.vfs2.FileSystemOptions; import org.apache.commons.vfs2.VFS; import org.junit.After; import org.junit.Before; import org.junit.Test; /** * Test class for DefaultConfigurationBuilder. * * @author Commons * Configuration team * @version $Id: TestWebdavConfigurationBuilder.java 1225331 2011-12-28 20:55:49Z oheger $ */ public class TestWebdavConfigurationBuilder implements FileOptionsProvider, ConfigurationListener { /** Test configuration definition file. */ private static final String TEST_FILE = "testDigesterConfiguration.xml"; private static final String ADDITIONAL_FILE = "testDigesterConfiguration2.xml"; private static final String OPTIONAL_FILE = "testDigesterOptionalConfiguration.xml"; private static final String OPTIONALEX_FILE = "testDigesterOptionalConfigurationEx.xml"; private static final String MULTI_FILE = "testDigesterConfiguration3.xml"; private static final String INIT_FILE = "testComplexInitialization.xml"; private static final String CLASS_FILE = "testExtendedClass.xml"; private static final String PROVIDER_FILE = "testConfigurationProvider.xml"; private static final String EXTENDED_PROVIDER_FILE = "testExtendedXMLConfigurationProvider.xml"; private static final String GLOBAL_LOOKUP_FILE = "testGlobalLookup.xml"; private static final String SYSTEM_PROPS_FILE = "testSystemProperties.xml"; private static final String VALIDATION_FILE = "testValidation.xml"; private static final String MULTI_TENENT_FILE = "testMultiTenentConfigurationBuilder.xml"; private static final String FILERELOAD2_FILE = "testFileReloadConfigurationBuilder2.xml"; private static final String FILERELOAD_1001_FILE = "testwrite/testMultiConfiguration_1001.xml"; private static final String FILERELOAD_1002_FILE = "testwrite/testMultiConfiguration_1002.xml"; private static final String TEST_PROPERTIES = "test.properties.xml"; private static final String TEST_SAVE = "testsave.xml"; /** Constant for the name of an optional configuration.*/ private static final String OPTIONAL_NAME = "optionalConfig"; private Map options; /** true when a file is changed */ private boolean configChanged = false; /** Stores the object to be tested. */ DefaultConfigurationBuilder factory; private String getBasePath() { String path = System.getProperty("test.webdav.base"); assertNotNull("No base url provided", path); return path; } @Before public void setUp() throws Exception { System.setProperty("java.naming.factory.initial", "org.apache.commons.configuration.MockInitialContextFactory"); System.setProperty("test_file_xml", "test.xml"); System.setProperty("test_file_combine", "testcombine1.xml"); System.setProperty("basePath", getBasePath()); FileSystem fs = new VFSFileSystem(); fs.setFileOptionsProvider(this); FileSystem.setDefaultFileSystem(fs); factory = new DefaultConfigurationBuilder(); factory.setBasePath(getBasePath()); factory.clearErrorListeners(); // avoid exception messages } @After public void tearDown() throws Exception { FileSystem.resetDefaultFileSystem(); } /** * Tests the isReservedNode() method of ConfigurationDeclaration. */ @Test public void testConfigurationDeclarationIsReserved() { DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory); DefaultConfigurationNode parent = new DefaultConfigurationNode(); DefaultConfigurationNode nd = new DefaultConfigurationNode("at"); parent.addAttribute(nd); assertTrue("Attribute at not recognized", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("optional"); parent.addAttribute(nd); assertTrue("Attribute optional not recognized", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("config-class"); parent.addAttribute(nd); assertTrue("Inherited attribute not recognized", decl .isReservedNode(nd)); nd = new DefaultConfigurationNode("different"); parent.addAttribute(nd); assertFalse("Wrong reserved attribute", decl.isReservedNode(nd)); nd = new DefaultConfigurationNode("at"); parent.addChild(nd); assertFalse("Node type not evaluated", decl.isReservedNode(nd)); } /** * Tests if the at attribute is correctly detected as reserved attribute. */ @Test public void testConfigurationDeclarationIsReservedAt() { checkOldReservedAttribute("at"); } /** * Tests if the optional attribute is correctly detected as reserved * attribute. */ @Test public void testConfigurationDeclarationIsReservedOptional() { checkOldReservedAttribute("optional"); } /** * Tests if special reserved attributes are recognized by the * isReservedNode() method. For compatibility reasons the attributes "at" * and "optional" are also treated as reserved attributes, but only if there * are no corresponding attributes with the "config-" prefix. * * @param name the attribute name */ private void checkOldReservedAttribute(String name) { DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory); DefaultConfigurationNode parent = new DefaultConfigurationNode(); DefaultConfigurationNode nd = new DefaultConfigurationNode("config-" + name); parent.addAttribute(nd); assertTrue("config-" + name + " attribute not recognized", decl .isReservedNode(nd)); DefaultConfigurationNode nd2 = new DefaultConfigurationNode(name); parent.addAttribute(nd2); assertFalse(name + " is reserved though config- exists", decl .isReservedNode(nd2)); assertTrue("config- attribute not recognized when " + name + " exists", decl.isReservedNode(nd)); } /** * Tests access to certain reserved attributes of a * ConfigurationDeclaration. */ @Test public void testConfigurationDeclarationGetAttributes() { factory.addProperty("xml.fileName", "test.xml"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("xml")); assertNull("Found an at attribute", decl.getAt()); assertFalse("Found an optional attribute", decl.isOptional()); factory.addProperty("xml[@config-at]", "test1"); assertEquals("Wrong value of at attribute", "test1", decl.getAt()); factory.addProperty("xml[@at]", "test2"); assertEquals("Wrong value of config-at attribute", "test1", decl.getAt()); factory.clearProperty("xml[@config-at]"); assertEquals("Old at attribute not detected", "test2", decl.getAt()); factory.addProperty("xml[@config-optional]", "true"); assertTrue("Wrong value of optional attribute", decl.isOptional()); factory.addProperty("xml[@optional]", "false"); assertTrue("Wrong value of config-optional attribute", decl.isOptional()); factory.clearProperty("xml[@config-optional]"); factory.setProperty("xml[@optional]", Boolean.TRUE); assertTrue("Old optional attribute not detected", decl.isOptional()); } /** * Tests whether an invalid value of an optional attribute is detected. */ @Test(expected = ConfigurationRuntimeException.class) public void testConfigurationDeclarationOptionalAttributeInvalid() { factory.addProperty("xml.fileName", "test.xml"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("xml")); factory.setProperty("xml[@optional]", "invalid value"); decl.isOptional(); } /** * Tests adding a new configuration provider. */ @Test public void testAddConfigurationProvider() { DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider(); assertNull("Provider already registered", factory .providerForTag("test")); factory.addConfigurationProvider("test", provider); assertSame("Provider not registered", provider, factory .providerForTag("test")); } /** * Tries to register a null configuration provider. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testAddConfigurationProviderNull() { factory.addConfigurationProvider("test", null); } /** * Tries to register a configuration provider for a null tag. This should * cause an exception to be thrown. */ @Test(expected = IllegalArgumentException.class) public void testAddConfigurationProviderNullTag() { factory.addConfigurationProvider(null, new DefaultConfigurationBuilder.ConfigurationProvider()); } /** * Tests removing configuration providers. */ @Test public void testRemoveConfigurationProvider() { assertNull("Removing unknown provider", factory .removeConfigurationProvider("test")); assertNull("Removing provider for null tag", factory .removeConfigurationProvider(null)); DefaultConfigurationBuilder.ConfigurationProvider provider = new DefaultConfigurationBuilder.ConfigurationProvider(); factory.addConfigurationProvider("test", provider); assertSame("Failed to remove provider", provider, factory .removeConfigurationProvider("test")); assertNull("Provider still registered", factory.providerForTag("test")); } /** * Tests creating a configuration object from a configuration declaration. */ @Test public void testConfigurationBeanFactoryCreateBean() { factory.addConfigurationProvider("test", new DefaultConfigurationBuilder.ConfigurationProvider( PropertiesConfiguration.class)); factory.addProperty("test[@throwExceptionOnMissing]", "true"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("test")); PropertiesConfiguration conf = (PropertiesConfiguration) BeanHelper .createBean(decl); assertTrue("Property was not initialized", conf .isThrowExceptionOnMissing()); } /** * Tests creating a configuration object from an unknown tag. This should * cause an exception. */ @Test(expected = ConfigurationRuntimeException.class) public void testConfigurationBeanFactoryCreateUnknownTag() { factory.addProperty("test[@throwExceptionOnMissing]", "true"); DefaultConfigurationBuilder.ConfigurationDeclaration decl = new DefaultConfigurationBuilder.ConfigurationDeclaration( factory, factory.configurationAt("test")); BeanHelper.createBean(decl); } /** * Tests loading a simple configuration definition file. */ @Test public void testLoadConfiguration() throws ConfigurationException { factory.setFileName(TEST_FILE); checkConfiguration(); } /** * Tests the file constructor. */ @Test public void testLoadConfigurationFromFile() throws ConfigurationException { factory = new DefaultConfigurationBuilder(getBasePath() + TEST_FILE); checkConfiguration(); } /** * This test doesn't test DefaultConfigurationBuilder. It tests saving a file * using Webdav file options. */ @Test public void testSaveConfiguration() throws ConfigurationException { options = new HashMap(); options.put(FileOptionsProvider.VERSIONING, Boolean.TRUE); options.put(FileOptionsProvider.CURRENT_USER, "TestUser"); XMLConfiguration conf = new XMLConfiguration(); conf.setFileName(getBasePath() + TEST_PROPERTIES); conf.load(); conf.save(getBasePath() + TEST_SAVE); XMLConfiguration checkConfig = new XMLConfiguration(); checkConfig.setFileName(getBasePath() + TEST_SAVE); checkSavedConfig(conf, checkConfig); options = null; } /** * Tests if the configuration was correctly created by the factory. */ private void checkConfiguration() throws ConfigurationException { CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory .getConfiguration(); assertEquals("Number of configurations", 3, compositeConfiguration .getNumberOfConfigurations()); assertEquals(PropertiesConfiguration.class, compositeConfiguration .getConfiguration(0).getClass()); assertEquals(XMLPropertiesConfiguration.class, compositeConfiguration .getConfiguration(1).getClass()); assertEquals(XMLConfiguration.class, compositeConfiguration .getConfiguration(2).getClass()); // check the first configuration PropertiesConfiguration pc = (PropertiesConfiguration) compositeConfiguration .getConfiguration(0); assertNotNull("Make sure we have a fileName: " + pc.getFileName(), pc .getFileName()); // check some properties checkProperties(compositeConfiguration); } /** * Checks if the passed in configuration contains the expected properties. * * @param compositeConfiguration the configuration to check */ private void checkProperties(Configuration compositeConfiguration) { assertTrue("Make sure we have loaded our key", compositeConfiguration .getBoolean("test.boolean")); assertEquals("I'm complex!", compositeConfiguration .getProperty("element2.subelement.subsubelement")); assertEquals("property in the XMLPropertiesConfiguration", "value1", compositeConfiguration.getProperty("key1")); } /** * Tests loading a configuration definition file with an additional section. */ @Test public void testLoadAdditional() throws ConfigurationException { factory.setFileName(ADDITIONAL_FILE); CombinedConfiguration compositeConfiguration = (CombinedConfiguration) factory .getConfiguration(); assertEquals("Verify how many configs", 2, compositeConfiguration .getNumberOfConfigurations()); // Test if union was constructed correctly Object prop = compositeConfiguration.getProperty("tables.table.name"); assertTrue(prop instanceof Collection); assertEquals(3, ((Collection) prop).size()); assertEquals("users", compositeConfiguration .getProperty("tables.table(0).name")); assertEquals("documents", compositeConfiguration .getProperty("tables.table(1).name")); assertEquals("tasks", compositeConfiguration .getProperty("tables.table(2).name")); prop = compositeConfiguration .getProperty("tables.table.fields.field.name"); assertTrue(prop instanceof Collection); assertEquals(17, ((Collection) prop).size()); assertEquals("smtp.mydomain.org", compositeConfiguration .getString("mail.host.smtp")); assertEquals("pop3.mydomain.org", compositeConfiguration .getString("mail.host.pop")); // This was overridden assertEquals("masterOfPost", compositeConfiguration .getString("mail.account.user")); assertEquals("topsecret", compositeConfiguration .getString("mail.account.psswd")); // This was overridden, too, but not in additional section assertEquals("enhanced factory", compositeConfiguration .getString("test.configuration")); } /** * Tests whether a default log error listener is registered at the builder * instance. */ @Test public void testLogErrorListener() { assertEquals("No default error listener registered", 1, new DefaultConfigurationBuilder().getErrorListeners().size()); } /** * Tests loading a definition file that contains optional configurations. */ @Test public void testLoadOptional() throws Exception { factory.setFileName(OPTIONAL_FILE); Configuration config = factory.getConfiguration(); assertTrue(config.getBoolean("test.boolean")); assertEquals("value", config.getProperty("element")); } /** * Tests whether loading a failing optional configuration causes an error * event. */ @Test public void testLoadOptionalErrorEvent() throws Exception { factory.clearErrorListeners(); ConfigurationErrorListenerImpl listener = new ConfigurationErrorListenerImpl(); factory.addErrorListener(listener); prepareOptionalTest("configuration", false); listener.verify(DefaultConfigurationBuilder.EVENT_ERR_LOAD_OPTIONAL, OPTIONAL_NAME, null); } /** * Tests loading a definition file with optional and non optional * configuration sources. One non optional does not exist, so this should * cause an exception. */ @Test(expected = ConfigurationException.class) public void testLoadOptionalWithException() throws ConfigurationException { factory.setFileName(OPTIONALEX_FILE); factory.getConfiguration(); } /** * Tries to load a configuration file with an optional, non file-based * configuration. The optional attribute should work for other configuration * classes, too. */ @Test public void testLoadOptionalNonFileBased() throws ConfigurationException { CombinedConfiguration config = prepareOptionalTest("configuration", false); assertTrue("Configuration not empty", config.isEmpty()); assertEquals("Wrong number of configurations", 0, config .getNumberOfConfigurations()); } /** * Tests loading an embedded optional configuration builder with the force * create attribute. */ @Test public void testLoadOptionalBuilderForceCreate() throws ConfigurationException { CombinedConfiguration config = prepareOptionalTest("configuration", true); assertEquals("Wrong number of configurations", 1, config .getNumberOfConfigurations()); assertTrue( "Wrong optional configuration type", config.getConfiguration(OPTIONAL_NAME) instanceof CombinedConfiguration); } /** * Tests loading an optional configuration with the force create attribute * set. The provider will always throw an exception. In this case the * configuration will not be added to the resulting combined configuration. */ @Test public void testLoadOptionalForceCreateWithException() throws ConfigurationException { factory.addConfigurationProvider("test", new DefaultConfigurationBuilder.ConfigurationBuilderProvider() { // Throw an exception here, too @Override public AbstractConfiguration getEmptyConfiguration( DefaultConfigurationBuilder.ConfigurationDeclaration decl) throws Exception { throw new Exception("Unable to create configuration!"); } }); CombinedConfiguration config = prepareOptionalTest("test", true); assertEquals("Optional configuration could be created", 0, config .getNumberOfConfigurations()); } /** * Prepares a test for loading a configuration definition file with an * optional configuration declaration. * * @param tag the tag name with the optional configuration * @param force the forceCreate attribute * @return the combined configuration obtained from the builder * @throws ConfigurationException if an error occurs */ private CombinedConfiguration prepareOptionalTest(String tag, boolean force) throws ConfigurationException { String prefix = "override." + tag; factory.addProperty(prefix + "[@fileName]", "nonExisting.xml"); factory.addProperty(prefix + "[@config-optional]", Boolean.TRUE); factory.addProperty(prefix + "[@config-name]", OPTIONAL_NAME); if (force) { factory.addProperty(prefix + "[@config-forceCreate]", Boolean.TRUE); } return factory.getConfiguration(false); } /** * Tests loading a definition file with multiple different sources. */ @Test public void testLoadDifferentSources() throws ConfigurationException { factory.setFileName(MULTI_FILE); Configuration config = factory.getConfiguration(); assertFalse(config.isEmpty()); assertTrue(config instanceof CombinedConfiguration); CombinedConfiguration cc = (CombinedConfiguration) config; assertEquals("Wrong number of configurations", 1, cc .getNumberOfConfigurations()); assertNotNull(config .getProperty("tables.table(0).fields.field(2).name")); assertNotNull(config.getProperty("element2.subelement.subsubelement")); assertEquals("value", config.getProperty("element3")); assertEquals("foo", config.getProperty("element3[@name]")); assertNotNull(config.getProperty("mail.account.user")); // test JNDIConfiguration assertNotNull(config.getProperty("test.onlyinjndi")); assertTrue(config.getBoolean("test.onlyinjndi")); Configuration subset = config.subset("test"); assertNotNull(subset.getProperty("onlyinjndi")); assertTrue(subset.getBoolean("onlyinjndi")); // test SystemConfiguration assertNotNull(config.getProperty("java.version")); assertEquals(System.getProperty("java.version"), config .getString("java.version")); } /** * Tests if the base path is correctly evaluated. */ @Test public void testSetConfigurationBasePath() throws ConfigurationException { factory.addProperty("properties[@fileName]", "test.properties"); File deepDir = new File("conf/config/deep"); factory.setConfigurationBasePath(deepDir.getAbsolutePath()); Configuration config = factory.getConfiguration(false); assertEquals("Wrong property value", "somevalue", config .getString("somekey")); } /** * Tests reading a configuration definition file that contains complex * initialization of properties of the declared configuration sources. */ @Test public void testComplexInitialization() throws ConfigurationException { factory.setFileName(INIT_FILE); CombinedConfiguration cc = (CombinedConfiguration) factory .getConfiguration(); assertEquals("System property not found", "test.xml", cc.getString("test_file_xml")); PropertiesConfiguration c1 = (PropertiesConfiguration) cc .getConfiguration(1); assertTrue( "Reloading strategy was not set", c1.getReloadingStrategy() instanceof FileChangedReloadingStrategy); assertEquals("Refresh delay was not set", 10000, ((FileChangedReloadingStrategy) c1.getReloadingStrategy()) .getRefreshDelay()); Configuration xmlConf = cc.getConfiguration("xml"); assertEquals("Property not found", "I'm complex!", xmlConf .getString("element2/subelement/subsubelement")); assertEquals("List index not found", "two", xmlConf .getString("list[0]/item[1]")); assertEquals("Property in combiner file not found", "yellow", cc .getString("/gui/selcolor")); assertTrue("Delimiter flag was not set", cc .isDelimiterParsingDisabled()); assertTrue("Expression engine was not set", cc.getExpressionEngine() instanceof XPathExpressionEngine); } /** * Tests if the returned combined configuration has the expected structure. */ @Test public void testCombinedConfiguration() throws ConfigurationException { factory.setFileName(INIT_FILE); CombinedConfiguration cc = (CombinedConfiguration) factory .getConfiguration(); assertNotNull("Properties configuration not found", cc .getConfiguration("properties")); assertNotNull("XML configuration not found", cc.getConfiguration("xml")); assertEquals("Wrong number of contained configs", 4, cc .getNumberOfConfigurations()); CombinedConfiguration cc2 = (CombinedConfiguration) cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); assertNotNull("No additional configuration found", cc2); Set names = cc2.getConfigurationNames(); assertEquals("Wrong number of contained additional configs", 2, names .size()); assertTrue("Config 1 not contained", names.contains("combiner1")); assertTrue("Config 2 not contained", names.contains("combiner2")); } /** * Tests the structure of the returned combined configuration if there is no * additional section. */ @Test public void testCombinedConfigurationNoAdditional() throws ConfigurationException { factory.setFileName(TEST_FILE); CombinedConfiguration cc = factory.getConfiguration(true); assertNull("Additional configuration was found", cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME)); } /** * Tests whether the list node definition was correctly processed. */ @Test public void testCombinedConfigurationListNodes() throws ConfigurationException { factory.setFileName(INIT_FILE); CombinedConfiguration cc = factory.getConfiguration(true); Set listNodes = cc.getNodeCombiner().getListNodes(); assertEquals("Wrong number of list nodes", 2, listNodes.size()); assertTrue("table node not a list node", listNodes.contains("table")); assertTrue("list node not a list node", listNodes.contains("list")); CombinedConfiguration cca = (CombinedConfiguration) cc .getConfiguration(DefaultConfigurationBuilder.ADDITIONAL_NAME); listNodes = cca.getNodeCombiner().getListNodes(); assertTrue("Found list nodes for additional combiner", listNodes .isEmpty()); } /** * Tests whether XML settings can be inherited. */ @Test public void testLoadXMLWithSettings() throws ConfigurationException, IOException { File confDir = new File("conf"); File targetDir = new File("target"); File testXMLSource = new File(confDir, "testDtd.xml"); File testXMLValidationSource = new File(confDir, "testValidateInvalid.xml"); File testSavedXML = new File(targetDir, "testSave.xml"); File testSavedFactory = new File(targetDir, "testSaveFactory.xml"); File dtdFile = new File(confDir, "properties.dtd"); final String publicId = "http://commons.apache.org/test.dtd"; XMLConfiguration config = new XMLConfiguration(testXMLSource); config.setPublicID(publicId); config.save(testSavedXML); factory.addProperty("xml[@fileName]", testSavedXML.getAbsolutePath()); factory.addProperty("xml(0)[@validating]", "true"); factory.addProperty("xml(-1)[@fileName]", testXMLValidationSource .getAbsolutePath()); factory.addProperty("xml(1)[@config-optional]", "true"); factory.addProperty("xml(1)[@validating]", "true"); factory.save(testSavedFactory); factory = new DefaultConfigurationBuilder(); factory.setFile(testSavedFactory); factory.registerEntityId(publicId, dtdFile.toURI().toURL()); factory.clearErrorListeners(); Configuration c = factory.getConfiguration(); assertEquals("Wrong property value", "value1", c.getString("entry(0)")); assertFalse("Invalid XML source was loaded", c .containsKey("table.name")); testSavedXML.delete(); testSavedFactory.delete(); } /** * Tests loading a configuration definition file that defines a custom * result class. */ @Test public void testExtendedClass() throws ConfigurationException { factory.setFileName(CLASS_FILE); CombinedConfiguration cc = factory.getConfiguration(true); String prop = (String)cc.getProperty("test"); assertEquals("Expected 'Extended', actual '" + prop + "'", "Extended", prop); assertTrue("Wrong result class: " + cc.getClass(), cc instanceof TestDefaultConfigurationBuilder.ExtendedCombinedConfiguration); } /** * Tests loading a configuration definition file that defines new providers. */ @Test public void testConfigurationProvider() throws ConfigurationException { factory.setFileName(PROVIDER_FILE); factory.getConfiguration(true); DefaultConfigurationBuilder.ConfigurationProvider provider = factory .providerForTag("test"); assertNotNull("Provider 'test' not registered", provider); } /** * Tests loading a configuration definition file that defines new providers. */ @Test public void testExtendedXMLConfigurationProvider() throws ConfigurationException { factory.setFileName(EXTENDED_PROVIDER_FILE); CombinedConfiguration cc = factory.getConfiguration(true); DefaultConfigurationBuilder.ConfigurationProvider provider = factory .providerForTag("test"); assertNotNull("Provider 'test' not registered", provider); Configuration config = cc.getConfiguration("xml"); assertNotNull("Test configuration not present", config); assertTrue("Configuration is not ExtendedXMLConfiguration, is " + config.getClass().getName(), config instanceof TestDefaultConfigurationBuilder.ExtendedXMLConfiguration); } @Test public void testGlobalLookup() throws Exception { factory.setFileName(GLOBAL_LOOKUP_FILE); CombinedConfiguration cc = factory.getConfiguration(true); String value = cc.getInterpolator().lookup("test:test_key"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","test.value",value); } @Test public void testSystemProperties() throws Exception { factory.setFileName(SYSTEM_PROPS_FILE); factory.getConfiguration(true); String value = System.getProperty("key1"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","value1",value); } @Test public void testValidation() throws Exception { factory.setFileName(VALIDATION_FILE); factory.getConfiguration(true); String value = System.getProperty("key1"); assertNotNull("The test key was not located", value); assertEquals("Incorrect value retrieved","value1",value); } @Test public void testMultiTenentConfiguration() throws Exception { factory.setFileName(MULTI_TENENT_FILE); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testMultiTenentConfiguration2() throws Exception { factory.setFileName(MULTI_TENENT_FILE); System.setProperty("Id", "1004"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testMultiTenentConfiguration3() throws Exception { factory.setFileName(MULTI_TENENT_FILE); System.setProperty("Id", "1005"); CombinedConfiguration config = factory.getConfiguration(true); assertTrue("Incorrect configuration", config instanceof DynamicCombinedConfiguration); verify("1001", config, 15); verify("1002", config, 25); verify("1003", config, 35); verify("1004", config, 50); verify("1005", config, 50); } @Test public void testFileChanged() throws Exception { // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_1001.xml"); FileObject output = getFile(getBasePath() + FILERELOAD_1001_FILE); output.delete(); output.getParent().createFolder(); copyFile(input, output); factory.setFileName(getBasePath() + FILERELOAD2_FILE); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); config.addConfigurationListener(this); verify("1001", config, 15); // Allow time for FileMonitor to set up. Thread.sleep(1000); XMLConfiguration x = new XMLConfiguration(getBasePath() + FILERELOAD_1001_FILE); x.setProperty("rowsPerPage", "50"); x.save(); // Let FileMonitor detect the change. //Thread.sleep(2000); waitForChange(); verify("1001", config, 50); output.delete(); } @Test public void testFileChanged2() throws Exception { // create a new configuration File input = new File("target/test-classes/testMultiConfiguration_1002.xml"); FileObject output = getFile(getBasePath() + FILERELOAD_1002_FILE); output.delete(); factory.setFileName(getBasePath() + FILERELOAD2_FILE); System.getProperties().remove("Id"); CombinedConfiguration config = factory.getConfiguration(true); assertNotNull(config); config.addConfigurationListener(this); verify("1002", config, 50); Thread.sleep(1000); output.getParent().createFolder(); copyFile(input, output); // Allow time for the monitor to notice the change. //Thread.sleep(2000); waitForChange(); verify("1002", config, 25); output.delete(); } private void verify(String key, CombinedConfiguration config, int rows) { System.setProperty("Id", key); int actual = config.getInt("rowsPerPage"); assertTrue("expected: " + rows + " actual: " + actual, actual == rows); } public Map getOptions() { return this.options; } /** * Helper method for checking if a save operation was successful. Loads a * saved configuration and then tests against a reference configuration. * @param conf the original configuration * @param newConfig the configuration to check * @throws ConfigurationException if an error occurs */ private void checkSavedConfig(XMLConfiguration conf, FileConfiguration newConfig) throws ConfigurationException { newConfig.load(); ConfigurationAssert.assertEquals(conf, newConfig); } private FileObject getFile(String fileName) throws Exception { FileSystemManager manager = VFS.getManager(); FileName file = manager.resolveURI(fileName); FileName base = file.getParent(); FileName path = manager.resolveName(base, file.getBaseName()); FileSystemOptions opts = new FileSystemOptions(); return manager.resolveFile(path.getURI(), opts); } private void copyFile(File input, FileObject output) throws IOException { Reader reader = new FileReader(input); Writer writer = new OutputStreamWriter(output.getContent().getOutputStream()); char[] buffer = new char[4096]; int n = 0; while (-1 != (n = reader.read(buffer))) { writer.write(buffer, 0, n); } reader.close(); writer.close(); } private void waitForChange() { synchronized(this) { try { int count = 0; while (!configChanged && count++ <= 3) { this.wait(5000); } } catch (InterruptedException ie) { throw new IllegalStateException("wait timed out"); } finally { configChanged = false; } } } public void configurationChanged(ConfigurationEvent event) { if (event.getType() == AbstractFileConfiguration.EVENT_CONFIG_CHANGED) { synchronized(this) { configChanged = true; this.notify(); } } } }././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestXMLConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestXMLConfiguration.j100644 203602 12232154104 33503 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.ByteArrayInputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.PrintWriter; import java.io.StringReader; import java.io.StringWriter; import java.net.URL; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.configuration.reloading.FileAlwaysReloadingStrategy; import org.apache.commons.configuration.reloading.InvariantReloadingStrategy; import org.apache.commons.configuration.resolver.CatalogResolver; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.junit.Before; import org.junit.Test; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; import org.xml.sax.helpers.DefaultHandler; /** * test for loading and saving xml properties files * * @version $Id: TestXMLConfiguration.java 1534371 2013-10-21 21:07:12Z henning $ */ public class TestXMLConfiguration { /** XML Catalog */ private static final String CATALOG_FILES = ConfigurationAssert .getTestFile("catalog.xml").getAbsolutePath(); /** Constant for the used encoding.*/ static final String ENCODING = "ISO-8859-1"; /** Constant for the test system ID.*/ static final String SYSTEM_ID = "properties.dtd"; /** Constant for the test public ID.*/ static final String PUBLIC_ID = "-//Commons Configuration//DTD Test Configuration 1.3//EN"; /** Constant for the DOCTYPE declaration.*/ static final String DOCTYPE_DECL = " PUBLIC \"" + PUBLIC_ID + "\" \"" + SYSTEM_ID + "\">"; /** Constant for the DOCTYPE prefix.*/ static final String DOCTYPE = "", property); // test multiple sibling elements property = conf.getProperty("list.sublist.item"); assertNotNull(property); assertTrue(property instanceof List); List list = (List) property; assertEquals(2, list.size()); assertEquals("five", list.get(0)); assertEquals("six", list.get(1)); // test multiple, disjoined elements property = conf.getProperty("list.item"); assertNotNull(property); assertTrue(property instanceof List); list = (List) property; assertEquals(4, list.size()); assertEquals("one", list.get(0)); assertEquals("two", list.get(1)); assertEquals("three", list.get(2)); assertEquals("four", list.get(3)); // test multiple, disjoined attributes property = conf.getProperty("list.item[@name]"); assertNotNull(property); assertTrue(property instanceof List); list = (List) property; assertEquals(2, list.size()); assertEquals("one", list.get(0)); assertEquals("three", list.get(1)); } @Test public void testGetAttribute() { assertEquals("element3[@name]", "foo", conf.getProperty("element3[@name]")); } @Test public void testClearAttribute() throws Exception { // test non-existent attribute String key = "clear[@id]"; conf.clearProperty(key); assertNull(key, conf.getProperty(key)); assertNull(key, conf.getProperty(key)); // test single attribute conf.load(); key = "clear.element2[@id]"; conf.clearProperty(key); assertNull(key, conf.getProperty(key)); assertNull(key, conf.getProperty(key)); key = "clear.element2"; assertNotNull(key, conf.getProperty(key)); assertNotNull(key, conf.getProperty(key)); // test multiple, disjoined attributes conf.load(); key = "clear.list.item[@id]"; conf.clearProperty(key); assertNull(key, conf.getProperty(key)); assertNull(key, conf.getProperty(key)); key = "clear.list.item"; assertNotNull(key, conf.getProperty(key)); assertNotNull(key, conf.getProperty(key)); } @Test public void testSetAttribute() { // replace an existing attribute conf.setProperty("element3[@name]", "bar"); assertEquals("element3[@name]", "bar", conf.getProperty("element3[@name]")); // set a new attribute conf.setProperty("foo[@bar]", "value"); assertEquals("foo[@bar]", "value", conf.getProperty("foo[@bar]")); conf.setProperty("name1","value1"); assertEquals("value1",conf.getProperty("name1")); } @Test public void testAddAttribute() { conf.addProperty("element3[@name]", "bar"); List list = conf.getList("element3[@name]"); assertNotNull("null list", list); assertTrue("'foo' element missing", list.contains("foo")); assertTrue("'bar' element missing", list.contains("bar")); assertEquals("list size", 2, list.size()); } @Test public void testAddObjectAttribute() { conf.addProperty("test.boolean[@value]", Boolean.TRUE); assertTrue("test.boolean[@value]", conf.getBoolean("test.boolean[@value]")); } /** * Tests setting an attribute on the root element. */ @Test public void testSetRootAttribute() throws ConfigurationException { conf.setProperty("[@test]", "true"); assertEquals("Root attribute not set", "true", conf .getString("[@test]")); conf.save(testSaveConf); XMLConfiguration checkConf = new XMLConfiguration(); checkConf.setFile(testSaveConf); checkSavedConfig(checkConf); assertTrue("Attribute not found after save", checkConf .containsKey("[@test]")); checkConf.setProperty("[@test]", "newValue"); checkConf.save(); conf = checkConf; checkConf = new XMLConfiguration(); checkConf.setFile(testSaveConf); checkSavedConfig(checkConf); assertEquals("Attribute not modified after save", "newValue", checkConf .getString("[@test]")); } /** * Tests whether the configuration's root node is initialized with a * reference to the corresponding XML element. */ @Test public void testGetRootReference() { assertNotNull("Root node has no reference", conf.getRootNode() .getReference()); } @Test public void testAddList() { conf.addProperty("test.array", "value1"); conf.addProperty("test.array", "value2"); List list = conf.getList("test.array"); assertNotNull("null list", list); assertTrue("'value1' element missing", list.contains("value1")); assertTrue("'value2' element missing", list.contains("value2")); assertEquals("list size", 2, list.size()); } @Test public void testGetComplexProperty() { assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement")); } @Test public void testSettingFileNames() { conf = new XMLConfiguration(); conf.setFileName(testProperties); assertEquals(testProperties.toString(), conf.getFileName()); conf.setBasePath(testBasePath); conf.setFileName("hello.xml"); assertEquals("hello.xml", conf.getFileName()); assertEquals(testBasePath.toString(), conf.getBasePath()); assertEquals(new File(testBasePath, "hello.xml"), conf.getFile()); conf.setBasePath(testBasePath); conf.setFileName("subdir/hello.xml"); assertEquals("subdir/hello.xml", conf.getFileName()); assertEquals(testBasePath.toString(), conf.getBasePath()); assertEquals(new File(testBasePath, "subdir/hello.xml"), conf.getFile()); } @Test public void testLoad() throws Exception { conf = new XMLConfiguration(); conf.setFileName(testProperties); conf.load(); assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement")); } @Test public void testLoadWithBasePath() throws Exception { conf = new XMLConfiguration(); conf.setFileName("test.xml"); conf.setBasePath(testBasePath); conf.load(); assertEquals("I'm complex!", conf.getProperty("element2.subelement.subsubelement")); } /** * Tests constructing an XMLConfiguration from a non existing file and * later saving to this file. */ @Test public void testLoadAndSaveFromFile() throws Exception { // If the file does not exist, an empty config is created conf = new XMLConfiguration(testSaveConf); assertTrue(conf.isEmpty()); conf.addProperty("test", "yes"); conf.save(); conf = new XMLConfiguration(testSaveConf); assertEquals("yes", conf.getString("test")); } /** * Tests loading a configuration from a URL. */ @Test public void testLoadFromURL() throws Exception { URL url = new File(testProperties).toURI().toURL(); conf = new XMLConfiguration(url); assertEquals("value", conf.getProperty("element")); assertEquals(url, conf.getURL()); } /** * Tests loading from a stream. */ @Test public void testLoadFromStream() throws Exception { String xml = "1"; conf = new XMLConfiguration(); conf.load(new ByteArrayInputStream(xml.getBytes())); assertEquals(1, conf.getInt("test")); conf = new XMLConfiguration(); conf.load(new ByteArrayInputStream(xml.getBytes()), "UTF8"); assertEquals(1, conf.getInt("test")); } /** * Tests loading a non well formed XML from a string. */ @Test(expected = ConfigurationException.class) public void testLoadInvalidXML() throws Exception { String xml = "1"; conf = new XMLConfiguration(); conf.load(new StringReader(xml)); } @Test public void testSetProperty() throws Exception { conf.setProperty("element.string", "hello"); assertEquals("'element.string'", "hello", conf.getString("element.string")); assertEquals("XML value of element.string", "hello", conf.getProperty("element.string")); } @Test public void testAddProperty() { // add a property to a non initialized xml configuration XMLConfiguration config = new XMLConfiguration(); config.addProperty("test.string", "hello"); assertEquals("'test.string'", "hello", config.getString("test.string")); } @Test public void testAddObjectProperty() { // add a non string property conf.addProperty("test.boolean", Boolean.TRUE); assertTrue("'test.boolean'", conf.getBoolean("test.boolean")); } @Test public void testSave() throws Exception { // add an array of strings to the configuration conf.addProperty("string", "value1"); for (int i = 1; i < 5; i++) { conf.addProperty("test.array", "value" + i); } // add an array of strings in an attribute for (int i = 1; i < 5; i++) { conf.addProperty("test.attribute[@array]", "value" + i); } // add comma delimited lists with escaped delimiters conf.addProperty("split.list5", "a\\,b\\,c"); conf.setProperty("element3", "value\\,value1\\,value2"); conf.setProperty("element3[@name]", "foo\\,bar"); // save the configuration conf.save(testSaveConf.getAbsolutePath()); // read the configuration and compare the properties XMLConfiguration checkConfig = new XMLConfiguration(); checkConfig.setFileName(testSaveConf.getAbsolutePath()); checkSavedConfig(checkConfig); } /** * Tests saving to a URL. */ @Test public void testSaveToURL() throws Exception { conf.save(testSaveConf.toURI().toURL()); XMLConfiguration checkConfig = new XMLConfiguration(); checkConfig.setFile(testSaveConf); checkSavedConfig(checkConfig); } /** * Tests saving to a stream. */ @Test public void testSaveToStream() throws Exception { assertNull(conf.getEncoding()); conf.setEncoding("UTF8"); FileOutputStream out = null; try { out = new FileOutputStream(testSaveConf); conf.save(out); } finally { if(out != null) { out.close(); } } XMLConfiguration checkConfig = new XMLConfiguration(); checkConfig.setFile(testSaveConf); checkSavedConfig(checkConfig); try { out = new FileOutputStream(testSaveConf); conf.save(out, "UTF8"); } finally { if(out != null) { out.close(); } } checkConfig.clear(); checkSavedConfig(checkConfig); } @Test public void testAutoSave() throws Exception { conf.setFile(testSaveConf); assertFalse(conf.isAutoSave()); conf.setAutoSave(true); assertTrue(conf.isAutoSave()); conf.setProperty("autosave", "ok"); // reload the configuration XMLConfiguration conf2 = new XMLConfiguration(conf.getFile()); assertEquals("'autosave' property", "ok", conf2.getString("autosave")); conf.clearTree("clear"); conf2 = new XMLConfiguration(conf.getFile()); Configuration sub = conf2.subset("clear"); assertTrue(sub.isEmpty()); } /** * Tests if a second file can be appended to a first. */ @Test public void testAppend() throws Exception { conf = new XMLConfiguration(); conf.setFileName(testProperties); conf.load(); conf.load(testProperties2); assertEquals("value", conf.getString("element")); assertEquals("tasks", conf.getString("table.name")); conf.save(testSaveConf); conf = new XMLConfiguration(testSaveConf); assertEquals("value", conf.getString("element")); assertEquals("tasks", conf.getString("table.name")); assertEquals("application", conf.getString("table[@tableType]")); } /** * Tests saving attributes (related to issue 34442). */ @Test public void testSaveAttributes() throws Exception { conf.clear(); conf.load(); conf.save(testSaveConf); conf = new XMLConfiguration(); conf.load(testSaveConf); assertEquals("foo", conf.getString("element3[@name]")); } /** * Tests collaboration between XMLConfiguration and a reloading strategy. */ @Test public void testReloading() throws Exception { assertNotNull(conf.getReloadingStrategy()); assertTrue(conf.getReloadingStrategy() instanceof InvariantReloadingStrategy); PrintWriter out = null; try { out = new PrintWriter(new FileWriter(testSaveConf)); out.println("1"); out.close(); out = null; conf.setFile(testSaveConf); FileAlwaysReloadingStrategy strategy = new FileAlwaysReloadingStrategy(); strategy.setRefreshDelay(100); conf.setReloadingStrategy(strategy); assertEquals(strategy, conf.getReloadingStrategy()); assertEquals("Wrong file monitored", testSaveConf.getAbsolutePath(), strategy.getMonitoredFile().getAbsolutePath()); conf.load(); assertEquals(1, conf.getInt("test")); out = new PrintWriter(new FileWriter(testSaveConf)); out.println("2"); out.close(); out = null; int value = conf.getInt("test"); assertEquals("No reloading performed", 2, value); } finally { if (out != null) { out.close(); } } } @Test public void testReloadingOOM() throws Exception { assertNotNull(conf.getReloadingStrategy()); assertTrue(conf.getReloadingStrategy() instanceof InvariantReloadingStrategy); PrintWriter out = null; try { out = new PrintWriter(new FileWriter(testSaveConf)); out.println("1"); out.close(); out = null; conf.setFile(testSaveConf); FileAlwaysReloadingStrategy strategy = new FileAlwaysReloadingStrategy(); strategy.setRefreshDelay(100); conf.setReloadingStrategy(strategy); conf.load(); assertEquals(1, conf.getInt("test")); for (int i = 1; i < LOOP_COUNT; ++i) { assertEquals(1, conf.getInt("test")); } } finally { if (out != null) { out.close(); } } } /** * Tests the refresh() method. */ @Test public void testRefresh() throws ConfigurationException { conf.setProperty("element", "anotherValue"); conf.refresh(); assertEquals("Wrong property after refresh", "value", conf.getString("element")); } /** * Tries to call refresh() when the configuration is not associated with a * file. */ @Test(expected = ConfigurationException.class) public void testRefreshNoFile() throws ConfigurationException { conf = new XMLConfiguration(); conf.refresh(); } /** * Tests access to tag names with delimiter characters. */ @Test public void testComplexNames() { assertEquals("Name with dot", conf.getString("complexNames.my..elem")); assertEquals("Another dot", conf.getString("complexNames.my..elem.sub..elem")); } /** * Creates a validating document builder. * @return the document builder * @throws ParserConfigurationException if an error occurs */ private DocumentBuilder createValidatingDocBuilder() throws ParserConfigurationException { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating(true); DocumentBuilder builder = factory.newDocumentBuilder(); builder.setErrorHandler(new DefaultHandler() { @Override public void error(SAXParseException ex) throws SAXException { throw ex; } }); return builder; } /** * Tests setting a custom document builder. */ @Test public void testCustomDocBuilder() throws Exception { // Load an invalid XML file with the default (non validating) // doc builder. This should work... conf = new XMLConfiguration(); conf.load(ConfigurationAssert.getTestFile("testValidateInvalid.xml")); assertEquals("customers", conf.getString("table.name")); assertFalse(conf.containsKey("table.fields.field(1).type")); } /** * Tests whether a validating document builder detects a validation error. */ @Test(expected = ConfigurationException.class) public void testCustomDocBuilderValidationError() throws Exception { DocumentBuilder builder = createValidatingDocBuilder(); conf = new XMLConfiguration(); conf.setDocumentBuilder(builder); conf.load(new File("conf/testValidateInvalid.xml")); } /** * Tests whether a valid document can be loaded with a validating document builder. */ @Test public void testCustomDocBuilderValidationSuccess() throws Exception { DocumentBuilder builder = createValidatingDocBuilder(); conf = new XMLConfiguration(); conf.setDocumentBuilder(builder); conf.load(ConfigurationAssert.getTestFile("testValidateValid.xml")); assertTrue(conf.containsKey("table.fields.field(1).type")); } /** * Tests the clone() method. */ @Test public void testClone() { Configuration c = (Configuration) conf.clone(); assertTrue(c instanceof XMLConfiguration); XMLConfiguration copy = (XMLConfiguration) c; assertNotNull(conf.getDocument()); assertNull(copy.getDocument()); assertNotNull(conf.getFileName()); assertNull(copy.getFileName()); copy.setProperty("element3", "clonedValue"); assertEquals("value", conf.getString("element3")); conf.setProperty("element3[@name]", "originalFoo"); assertEquals("foo", copy.getString("element3[@name]")); } /** * Tests saving a configuration after cloning to ensure that the clone and * the original are completely detached. */ @Test public void testCloneWithSave() throws ConfigurationException { XMLConfiguration c = (XMLConfiguration) conf.clone(); c.addProperty("test.newProperty", Boolean.TRUE); conf.addProperty("test.orgProperty", Boolean.TRUE); c.save(testSaveConf); XMLConfiguration c2 = new XMLConfiguration(testSaveConf); assertTrue("New property after clone() was not saved", c2 .getBoolean("test.newProperty")); assertFalse("Property of original config was saved", c2 .containsKey("test.orgProperty")); } /** * Tests the subset() method. There was a bug that calling subset() had * undesired side effects. */ @Test public void testSubset() throws ConfigurationException { conf = new XMLConfiguration(); conf.load(ConfigurationAssert.getTestFile("testHierarchicalXMLConfiguration.xml")); conf.subset("tables.table(0)"); conf.save(testSaveConf); conf = new XMLConfiguration(testSaveConf); assertEquals("users", conf.getString("tables.table(0).name")); } /** * Tests string properties with list delimiters and escaped delimiters. */ @Test public void testSplitLists() { assertEquals("a", conf.getString("split.list3[@values]")); assertEquals(2, conf.getMaxIndex("split.list3[@values]")); assertEquals("a,b,c", conf.getString("split.list4[@values]")); assertEquals("a", conf.getString("split.list1")); assertEquals(2, conf.getMaxIndex("split.list1")); assertEquals("a,b,c", conf.getString("split.list2")); } /** * Tests string properties with list delimiters when delimiter parsing * is disabled */ @Test public void testDelimiterParsingDisabled() throws ConfigurationException { XMLConfiguration conf2 = new XMLConfiguration(); conf2.setDelimiterParsingDisabled(true); conf2.setFile(new File(testProperties)); conf2.load(); assertEquals("a,b,c", conf2.getString("split.list3[@values]")); assertEquals(0, conf2.getMaxIndex("split.list3[@values]")); assertEquals("a\\,b\\,c", conf2.getString("split.list4[@values]")); assertEquals("a,b,c", conf2.getString("split.list1")); assertEquals(0, conf2.getMaxIndex("split.list1")); assertEquals("a\\,b\\,c", conf2.getString("split.list2")); conf2 = new XMLConfiguration(); conf2.setExpressionEngine(new XPathExpressionEngine()); conf2.setDelimiterParsingDisabled(true); conf2.setFile(new File(testProperties)); conf2.load(); assertEquals("a,b,c", conf2.getString("split/list3/@values")); assertEquals(0, conf2.getMaxIndex("split/list3/@values")); assertEquals("a\\,b\\,c", conf2.getString("split/list4/@values")); assertEquals("a,b,c", conf2.getString("split/list1")); assertEquals(0, conf2.getMaxIndex("split/list1")); assertEquals("a\\,b\\,c", conf2.getString("split/list2")); } /** * Tests string properties with list delimiters when delimiter parsing * is disabled */ @Test public void testSaveWithDelimiterParsingDisabled() throws ConfigurationException { XMLConfiguration conf = new XMLConfiguration(); conf.setExpressionEngine(new XPathExpressionEngine()); conf.setDelimiterParsingDisabled(true); conf.setAttributeSplittingDisabled(true); conf.setFile(new File(testProperties)); conf.load(); assertEquals("a,b,c", conf.getString("split/list3/@values")); assertEquals(0, conf.getMaxIndex("split/list3/@values")); assertEquals("a\\,b\\,c", conf.getString("split/list4/@values")); assertEquals("a,b,c", conf.getString("split/list1")); assertEquals(0, conf.getMaxIndex("split/list1")); assertEquals("a\\,b\\,c", conf.getString("split/list2")); // save the configuration conf.save(testSaveConf.getAbsolutePath()); // read the configuration and compare the properties XMLConfiguration checkConfig = new XMLConfiguration(); checkConfig.setFileName(testSaveConf.getAbsolutePath()); checkSavedConfig(checkConfig); XMLConfiguration config = new XMLConfiguration(); config.setFileName(testFile2); //config.setExpressionEngine(new XPathExpressionEngine()); config.setDelimiterParsingDisabled(true); config.setAttributeSplittingDisabled(true); config.load(); config.setProperty("Employee[@attr1]", "3,2,1"); assertEquals("3,2,1", config.getString("Employee[@attr1]")); config.save(testSaveFile.getAbsolutePath()); config = new XMLConfiguration(); config.setFileName(testSaveFile.getAbsolutePath()); //config.setExpressionEngine(new XPathExpressionEngine()); config.setDelimiterParsingDisabled(true); config.setAttributeSplittingDisabled(true); config.load(); config.setProperty("Employee[@attr1]", "1,2,3"); assertEquals("1,2,3", config.getString("Employee[@attr1]")); config.setProperty("Employee[@attr2]", "one, two, three"); assertEquals("one, two, three", config.getString("Employee[@attr2]")); config.setProperty("Employee.text", "a,b,d"); assertEquals("a,b,d", config.getString("Employee.text")); config.setProperty("Employee.Salary", "100,000"); assertEquals("100,000", config.getString("Employee.Salary")); config.save(testSaveFile.getAbsolutePath()); checkConfig = new XMLConfiguration(); checkConfig.setFileName(testSaveFile.getAbsolutePath()); checkConfig.setExpressionEngine(new XPathExpressionEngine()); checkConfig.setDelimiterParsingDisabled(true); checkConfig.setAttributeSplittingDisabled(true); checkConfig.load(); assertEquals("1,2,3", checkConfig.getString("Employee/@attr1")); assertEquals("one, two, three", checkConfig.getString("Employee/@attr2")); assertEquals("a,b,d", checkConfig.getString("Employee/text")); assertEquals("100,000", checkConfig.getString("Employee/Salary")); } /** * Tests whether a DTD can be accessed. */ @Test public void testDtd() throws ConfigurationException { conf = new XMLConfiguration("testDtd.xml"); assertEquals("value1", conf.getString("entry(0)")); assertEquals("test2", conf.getString("entry(1)[@key]")); } /** * Tests DTD validation using the setValidating() method. */ @Test public void testValidating() throws ConfigurationException { File nonValidFile = ConfigurationAssert.getTestFile("testValidateInvalid.xml"); conf = new XMLConfiguration(); assertFalse(conf.isValidating()); // Load a non valid XML document. Should work for isValidating() == false conf.load(nonValidFile); assertEquals("customers", conf.getString("table.name")); assertFalse(conf.containsKey("table.fields.field(1).type")); // Now set the validating flag to true conf.setValidating(true); try { conf.load(nonValidFile); fail("Validation was not performed!"); } catch(ConfigurationException cex) { //ok } } /** * Tests handling of empty elements. */ @Test public void testEmptyElements() throws ConfigurationException { assertTrue(conf.containsKey("empty")); assertEquals("", conf.getString("empty")); conf.addProperty("empty2", ""); conf.setProperty("empty", "no more empty"); conf.save(testSaveConf); conf = new XMLConfiguration(testSaveConf); assertEquals("no more empty", conf.getString("empty")); assertEquals("", conf.getProperty("empty2")); } /** * Tests the isEmpty() method for an empty configuration that was reloaded. */ @Test public void testEmptyReload() throws ConfigurationException { XMLConfiguration config = new XMLConfiguration(); assertTrue("Newly created configuration not empty", config.isEmpty()); config.save(testSaveConf); config.load(testSaveConf); assertTrue("Reloaded configuration not empty", config.isEmpty()); } /** * Tests whether the encoding is correctly detected by the XML parser. This * is done by loading an XML file with the encoding "UTF-16". If this * encoding is not detected correctly, an exception will be thrown that * "Content is not allowed in prolog". This test case is related to issue * 34204. */ @Test public void testLoadWithEncoding() throws ConfigurationException { File file = ConfigurationAssert.getTestFile("testEncoding.xml"); conf = new XMLConfiguration(); conf.load(file); assertEquals("test3_yoge", conf.getString("yoge")); } /** * Tests whether the encoding is written to the generated XML file. */ @Test public void testSaveWithEncoding() throws ConfigurationException { conf = new XMLConfiguration(); conf.setProperty("test", "a value"); conf.setEncoding(ENCODING); StringWriter out = new StringWriter(); conf.save(out); assertTrue("Encoding was not written to file", out.toString().indexOf( "encoding=\"" + ENCODING + "\"") >= 0); } /** * Tests whether a default encoding is used if no specific encoding is set. * According to the XSLT specification (http://www.w3.org/TR/xslt#output) * this should be either UTF-8 or UTF-16. */ @Test public void testSaveWithNullEncoding() throws ConfigurationException { conf = new XMLConfiguration(); conf.setProperty("testNoEncoding", "yes"); conf.setEncoding(null); StringWriter out = new StringWriter(); conf.save(out); assertTrue("Encoding was written to file", out.toString().indexOf( "encoding=\"UTF-") >= 0); } /** * Tests whether the DOCTYPE survives a save operation. */ @Test public void testSaveWithDoctype() throws ConfigurationException { String content = "" + DOCTYPE + "properties" + DOCTYPE_DECL + "value"; StringReader in = new StringReader(content); conf = new XMLConfiguration(); conf.setFileName("testDtd.xml"); conf.load(); conf.clear(); conf.load(in); assertEquals("Wrong public ID", PUBLIC_ID, conf.getPublicID()); assertEquals("Wrong system ID", SYSTEM_ID, conf.getSystemID()); StringWriter out = new StringWriter(); conf.save(out); assertTrue("Did not find DOCTYPE", out.toString().indexOf(DOCTYPE) >= 0); } /** * Tests setting public and system IDs for the D'OCTYPE and then saving the * configuration. This should generate a DOCTYPE declaration. */ @Test public void testSaveWithDoctypeIDs() throws ConfigurationException { assertNull("A public ID was found", conf.getPublicID()); assertNull("A system ID was found", conf.getSystemID()); conf.setPublicID(PUBLIC_ID); conf.setSystemID(SYSTEM_ID); StringWriter out = new StringWriter(); conf.save(out); assertTrue("Did not find DOCTYPE", out.toString().indexOf( DOCTYPE + "testconfig" + DOCTYPE_DECL) >= 0); } /** * Tests saving a configuration when an invalid transformer factory is * specified. In this case the error thrown by the TransformerFactory class * should be caught and re-thrown as a ConfigurationException. */ @Test public void testSaveWithInvalidTransformerFactory() { System.setProperty(PROP_FACTORY, "an.invalid.Class"); try { conf.save(testSaveConf); fail("Could save with invalid TransformerFactory!"); } catch (ConfigurationException cex) { // ok } finally { System.getProperties().remove(PROP_FACTORY); } } /** * Tests if reloads are recognized by subset(). */ @Test public void testSubsetWithReload() throws ConfigurationException { XMLConfiguration c = setUpReloadTest(); Configuration sub = c.subset("test"); assertEquals("New value not read", "newValue", sub.getString("entity")); } /** * Tests if reloads are recognized by configurationAt(). */ @Test public void testConfigurationAtWithReload() throws ConfigurationException { XMLConfiguration c = setUpReloadTest(); HierarchicalConfiguration sub = c.configurationAt("test(0)"); assertEquals("New value not read", "newValue", sub.getString("entity")); } /** * Tests if reloads are recognized by configurationsAt(). */ @Test public void testConfigurationsAtWithReload() throws ConfigurationException { XMLConfiguration c = setUpReloadTest(); List configs = c.configurationsAt("test"); assertEquals("New value not read", "newValue", configs.get(0).getString("entity")); } /** * Tests whether reloads are recognized when querying the configuration's * keys. */ @Test public void testGetKeysWithReload() throws ConfigurationException { XMLConfiguration c = setUpReloadTest(); conf.addProperty("aNewKey", "aNewValue"); conf.save(testSaveConf); boolean found = false; for (Iterator it = c.getKeys(); it.hasNext();) { if ("aNewKey".equals(it.next())) { found = true; } } assertTrue("Reload not performed", found); } /** * Tests accessing properties when the XPATH expression engine is set. */ @Test public void testXPathExpressionEngine() { conf.setExpressionEngine(new XPathExpressionEngine()); assertEquals("Wrong attribute value", "foo\"bar", conf .getString("test[1]/entity/@name")); conf.clear(); assertNull(conf.getString("test[1]/entity/@name")); } /** * Tests the copy constructor. */ @Test public void testInitCopy() throws ConfigurationException { XMLConfiguration copy = new XMLConfiguration(conf); assertEquals("value", copy.getProperty("element")); assertNull("Document was copied, too", copy.getDocument()); ConfigurationNode root = copy.getRootNode(); for (ConfigurationNode node : root.getChildren()) { assertNull("Reference was not cleared", node.getReference()); } removeTestFile(); copy.setFile(testSaveConf); copy.save(); copy.clear(); checkSavedConfig(copy); } /** * Tests setting text of the root element. */ @Test public void testSetTextRootElement() throws ConfigurationException { conf.setProperty("", "Root text"); conf.save(testSaveConf); XMLConfiguration copy = new XMLConfiguration(); copy.setFile(testSaveConf); checkSavedConfig(copy); } /** * Tests removing the text of the root element. */ @Test public void testClearTextRootElement() throws ConfigurationException { final String xml = "text"; conf.clear(); StringReader in = new StringReader(xml); conf.load(in); assertEquals("Wrong text of root", "text", conf.getString("")); conf.clearProperty(""); conf.save(testSaveConf); XMLConfiguration copy = new XMLConfiguration(); copy.setFile(testSaveConf); checkSavedConfig(copy); } /** * Tests list nodes with multiple values and attributes. */ @Test public void testListWithAttributes() { assertEquals("Wrong number of elements", 6, conf.getList( "attrList.a").size()); assertEquals("Wrong value of first element", "ABC", conf .getString("attrList.a(0)")); assertEquals("Wrong value of first name attribute", "x", conf .getString("attrList.a(0)[@name]")); assertEquals("Wrong number of name attributes", 6, conf.getList( "attrList.a[@name]").size()); } /** * Tests a list node with attributes that has multiple values separated by * the list delimiter. In this scenario the attribute should be added to all * list nodes. */ @Test public void testListWithAttributesMultiValue() { assertEquals("Wrong value of 2nd element", "1", conf.getString("attrList.a(1)")); assertEquals("Wrong value of 2nd name attribute", "y", conf.getString("attrList.a(1)[@name]")); for (int i = 1; i <= 3; i++) { assertEquals("Wrong value of element " + (i + 1), i, conf.getInt("attrList.a(" + i + ")")); assertEquals("Wrong name attribute for element " + (i), "y", conf.getString("attrList.a(" + i + ")[@name]")); } } /** * Tests a list node with multiple values and multiple attributes. All * attribute values should be assigned to all list nodes. */ @Test public void testListWithMultipleAttributesMultiValue() { for (int i = 1; i <= 2; i++) { String idxStr = String.format("(%d)", Integer.valueOf(i + 3)); String nodeKey = "attrList.a" + idxStr; assertEquals("Wrong value of multi-valued node", "value" + i, conf.getString(nodeKey)); assertEquals("Wrong name attribute at " + i, "u", conf.getString(nodeKey + "[@name]")); assertEquals("Wrong test attribute at " + i, "yes", conf.getString(nodeKey + "[@test]")); } } /** * Tests whether the auto save mechanism is triggered by changes at a * subnode configuration. */ @Test public void testAutoSaveWithSubnodeConfig() throws ConfigurationException { final String newValue = "I am autosaved"; conf.setFile(testSaveConf); conf.setAutoSave(true); Configuration sub = conf.configurationAt("element2.subelement"); sub.setProperty("subsubelement", newValue); assertEquals("Change not visible to parent", newValue, conf .getString("element2.subelement.subsubelement")); XMLConfiguration conf2 = new XMLConfiguration(testSaveConf); assertEquals("Change was not saved", newValue, conf2 .getString("element2.subelement.subsubelement")); } /** * Tests whether a subnode configuration created from another subnode * configuration of a XMLConfiguration can trigger the auto save mechanism. */ @Test public void testAutoSaveWithSubSubnodeConfig() throws ConfigurationException { final String newValue = "I am autosaved"; conf.setFile(testSaveConf); conf.setAutoSave(true); SubnodeConfiguration sub1 = conf.configurationAt("element2"); SubnodeConfiguration sub2 = sub1.configurationAt("subelement"); sub2.setProperty("subsubelement", newValue); assertEquals("Change not visible to parent", newValue, conf .getString("element2.subelement.subsubelement")); XMLConfiguration conf2 = new XMLConfiguration(testSaveConf); assertEquals("Change was not saved", newValue, conf2 .getString("element2.subelement.subsubelement")); } /** * Tests saving and loading a configuration when delimiter parsing is * disabled. */ @Test public void testSaveDelimiterParsingDisabled() throws ConfigurationException { checkSaveDelimiterParsingDisabled("list.delimiter.test"); } /** * Tests saving and loading a configuration when delimiter parsing is * disabled and attributes are involved. */ @Test public void testSaveDelimiterParsingDisabledAttrs() throws ConfigurationException { checkSaveDelimiterParsingDisabled("list.delimiter.test[@attr]"); } /** * Helper method for testing saving and loading a configuration when * delimiter parsing is disabled. * * @param key the key to be checked * @throws ConfigurationException if an error occurs */ private void checkSaveDelimiterParsingDisabled(String key) throws ConfigurationException { conf.clear(); conf.setDelimiterParsingDisabled(true); conf.load(); conf.setProperty(key, "C:\\Temp\\,C:\\Data\\"); conf.addProperty(key, "a,b,c"); conf.save(testSaveConf); XMLConfiguration checkConf = new XMLConfiguration(); checkConf.setDelimiterParsingDisabled(true); checkConf.setFile(testSaveConf); checkSavedConfig(checkConf); } /** * Tests multiple attribute values in delimiter parsing disabled mode. */ @Test public void testDelimiterParsingDisabledMultiAttrValues() throws ConfigurationException { conf.clear(); conf.setDelimiterParsingDisabled(true); conf.load(); List expr = conf.getList("expressions[@value]"); assertEquals("Wrong list size", 2, expr.size()); assertEquals("Wrong element 1", "a || (b && c)", expr.get(0)); assertEquals("Wrong element 2", "!d", expr.get(1)); } /** * Tests using multiple attribute values, which are partly escaped when * delimiter parsing is not disabled. */ @Test public void testMultipleAttrValuesEscaped() throws ConfigurationException { conf.addProperty("test.dir[@name]", "C:\\Temp\\"); conf.addProperty("test.dir[@name]", "C:\\Data\\"); conf.save(testSaveConf); XMLConfiguration checkConf = new XMLConfiguration(); checkConf.setFile(testSaveConf); checkSavedConfig(checkConf); } /** * Tests a combination of auto save = true and an associated reloading * strategy. */ @Test public void testAutoSaveWithReloadingStrategy() throws ConfigurationException { conf.setFile(testSaveConf); conf.save(); conf.setReloadingStrategy(new FileAlwaysReloadingStrategy()); conf.setAutoSave(true); assertEquals("Value not found", "value", conf.getProperty("element")); } /** * Tests adding nodes from another configuration. */ @Test public void testAddNodesCopy() throws ConfigurationException { XMLConfiguration c2 = new XMLConfiguration(testProperties2); conf.addNodes("copiedProperties", c2.getRootNode().getChildren()); conf.save(testSaveConf); XMLConfiguration checkConf = new XMLConfiguration(); checkConf.setFile(testSaveConf); checkSavedConfig(checkConf); } /** * Tests whether the addNodes() method triggers an auto save. */ @Test public void testAutoSaveAddNodes() throws ConfigurationException { conf.setFile(testSaveConf); conf.setAutoSave(true); HierarchicalConfiguration.Node node = new HierarchicalConfiguration.Node( "addNodesTest", Boolean.TRUE); Collection nodes = new ArrayList(1); nodes.add(node); conf.addNodes("test.autosave", nodes); XMLConfiguration c2 = new XMLConfiguration(testSaveConf); assertTrue("Added nodes are not saved", c2 .getBoolean("test.autosave.addNodesTest")); } /** * Tests saving a configuration after a node was added. Test for * CONFIGURATION-294. */ @Test public void testAddNodesAndSave() throws ConfigurationException { ConfigurationNode node = new HierarchicalConfiguration.Node("test"); ConfigurationNode child = new HierarchicalConfiguration.Node("child"); node.addChild(child); ConfigurationNode attr = new HierarchicalConfiguration.Node("attr"); node.addAttribute(attr); ConfigurationNode node2 = conf.createNode("test2"); Collection nodes = new ArrayList(2); nodes.add(node); nodes.add(node2); conf.addNodes("add.nodes", nodes); conf.setFile(testSaveConf); conf.save(); conf.setProperty("add.nodes.test", "true"); conf.setProperty("add.nodes.test.child", "yes"); conf.setProperty("add.nodes.test[@attr]", "existing"); conf.setProperty("add.nodes.test2", "anotherValue"); conf.save(); XMLConfiguration c2 = new XMLConfiguration(testSaveConf); assertEquals("Value was not saved", "true", c2 .getString("add.nodes.test")); assertEquals("Child value was not saved", "yes", c2 .getString("add.nodes.test.child")); assertEquals("Attr value was not saved", "existing", c2 .getString("add.nodes.test[@attr]")); assertEquals("Node2 not saved", "anotherValue", c2 .getString("add.nodes.test2")); } /** * Tests registering the publicId of a DTD. */ @Test public void testRegisterEntityId() throws Exception { URL dtdURL = getClass().getResource("/properties.dtd"); final String publicId = "http://commons.apache.org/test/properties.dtd"; conf = new XMLConfiguration("testDtd.xml"); conf.setPublicID(publicId); conf.save(testSaveConf); XMLConfiguration checkConfig = new XMLConfiguration(); checkConfig.setFile(testSaveConf); checkConfig.registerEntityId(publicId, dtdURL); checkConfig.setValidating(true); checkSavedConfig(checkConfig); } /** * Tries to register a null public ID. This should cause an exception. */ @Test(expected = IllegalArgumentException.class) public void testRegisterEntityIdNull() throws IOException { conf.registerEntityId(null, new URL("http://commons.apache.org")); } /** * Tests saving a configuration that was created from a hierarchical * configuration. This test exposes bug CONFIGURATION-301. */ @Test public void testSaveAfterCreateWithCopyConstructor() throws ConfigurationException { HierarchicalConfiguration hc = conf.configurationAt("element2"); conf = new XMLConfiguration(hc); conf.save(testSaveConf); XMLConfiguration checkConfig = new XMLConfiguration(); checkConfig.setFile(testSaveConf); checkSavedConfig(checkConfig); assertEquals("Wrong name of root element", "element2", checkConfig .getRootElementName()); } /** * Tests whether the name of the root element is copied when a configuration * is created using the copy constructor. */ @Test public void testCopyRootName() throws ConfigurationException { final String rootName = "rootElement"; final String xml = "<" + rootName + ">true"; conf.clear(); conf.load(new StringReader(xml)); XMLConfiguration copy = new XMLConfiguration(conf); assertEquals("Wrong name of root element", rootName, copy .getRootElementName()); copy.save(testSaveConf); copy = new XMLConfiguration(testSaveConf); assertEquals("Wrong name of root element after save", rootName, copy .getRootElementName()); } /** * Tests whether the name of the root element is copied for a configuration * for which not yet a document exists. */ @Test public void testCopyRootNameNoDocument() throws ConfigurationException { final String rootName = "rootElement"; conf = new XMLConfiguration(); conf.setRootElementName(rootName); conf.setProperty("test", Boolean.TRUE); XMLConfiguration copy = new XMLConfiguration(conf); assertEquals("Wrong name of root element", rootName, copy .getRootElementName()); copy.save(testSaveConf); copy = new XMLConfiguration(testSaveConf); assertEquals("Wrong name of root element after save", rootName, copy .getRootElementName()); } /** * Tests adding an attribute node using the addNodes() method. */ @Test public void testAddNodesAttributeNode() { conf.addProperty("testAddNodes.property[@name]", "prop1"); conf.addProperty("testAddNodes.property(0).value", "value1"); conf.addProperty("testAddNodes.property(-1)[@name]", "prop2"); conf.addProperty("testAddNodes.property(1).value", "value2"); Collection nodes = new ArrayList(); nodes.add(new HierarchicalConfiguration.Node("property")); conf.addNodes("testAddNodes", nodes); nodes.clear(); ConfigurationNode nd = new HierarchicalConfiguration.Node("name", "prop3"); nd.setAttribute(true); nodes.add(nd); conf.addNodes("testAddNodes.property(2)", nodes); assertEquals("Attribute not added", "prop3", conf .getString("testAddNodes.property(2)[@name]")); } /** * Tests whether spaces are preserved when the xml:space attribute is set. */ @Test public void testPreserveSpace() { assertEquals("Wrong value of blanc", " ", conf.getString("space.blanc")); assertEquals("Wrong value of stars", " * * ", conf .getString("space.stars")); } /** * Tests whether the xml:space attribute works directly on the current * element. This test is related to CONFIGURATION-555. */ @Test public void testPreserveSpaceOnElement() { assertEquals("Wrong value", " preserved ", conf.getString("spaceElement")); } /** * Tests whether the xml:space attribute can be overridden in nested * elements. */ @Test public void testPreserveSpaceOverride() { assertEquals("Not trimmed", "Some text", conf .getString("space.description")); } /** * Tests an xml:space attribute with an invalid value. This will be * interpreted as default. */ @Test public void testPreserveSpaceInvalid() { assertEquals("Invalid not trimmed", "Some other text", conf .getString("space.testInvalid")); } /** * Tests whether attribute splitting can be disabled. */ @Test public void testAttributeSplittingDisabled() throws ConfigurationException { List values = conf.getList("expressions[@value2]"); assertEquals("Wrong number of attribute values", 2, values.size()); assertEquals("Wrong value 1", "a", values.get(0)); assertEquals("Wrong value 2", "b|c", values.get(1)); XMLConfiguration conf2 = new XMLConfiguration(); conf2.setAttributeSplittingDisabled(true); conf2.setFile(conf.getFile()); conf2.load(); assertEquals("Attribute was split", "a,b|c", conf2 .getString("expressions[@value2]")); } /** * Tests disabling both delimiter parsing and attribute splitting. */ @Test public void testAttributeSplittingAndDelimiterParsingDisabled() throws ConfigurationException { conf.clear(); conf.setDelimiterParsingDisabled(true); conf.load(); List values = conf.getList("expressions[@value2]"); assertEquals("Wrong number of attribute values", 2, values.size()); assertEquals("Wrong value 1", "a,b", values.get(0)); assertEquals("Wrong value 2", "c", values.get(1)); XMLConfiguration conf2 = new XMLConfiguration(); conf2.setAttributeSplittingDisabled(true); conf2.setDelimiterParsingDisabled(true); conf2.setFile(conf.getFile()); conf2.load(); assertEquals("Attribute was split", "a,b|c", conf2 .getString("expressions[@value2]")); } /** * Tests modifying an XML document and saving it with schema validation enabled. */ @Test public void testSaveWithValidation() throws Exception { CatalogResolver resolver = new CatalogResolver(); resolver.setCatalogFiles(CATALOG_FILES); conf = new XMLConfiguration(); conf.setEntityResolver(resolver); conf.setFileName(testFile2); conf.setSchemaValidation(true); conf.load(); conf.setProperty("Employee.SSN", "123456789"); conf.validate(); conf.save(testSaveConf); conf = new XMLConfiguration(testSaveConf); assertEquals("123456789", conf.getString("Employee.SSN")); } /** * Tests modifying an XML document and validating it against the schema. */ @Test public void testSaveWithValidationFailure() throws Exception { CatalogResolver resolver = new CatalogResolver(); resolver.setCatalogFiles(CATALOG_FILES); conf = new XMLConfiguration(); conf.setEntityResolver(resolver); conf.setFileName(testFile2); conf.setSchemaValidation(true); conf.load(); conf.setProperty("Employee.Email", "JohnDoe@apache.org"); try { conf.validate(); fail("No validation failure on save"); } catch (Exception e) { Throwable cause = e.getCause(); assertNotNull("No cause for exception on save", cause); assertTrue("Incorrect exception on save", cause instanceof SAXParseException); } } @Test public void testConcurrentGetAndReload() throws Exception { //final FileConfiguration config = new PropertiesConfiguration("test.properties"); final FileConfiguration config = new XMLConfiguration("test.xml"); config.setReloadingStrategy(new FileAlwaysReloadingStrategy()); assertTrue("Property not found", config.getProperty("test.short") != null); Thread testThreads[] = new Thread[THREAD_COUNT]; for (int i = 0; i < testThreads.length; ++i) { testThreads[i] = new ReloadThread(config); testThreads[i].start(); } for (int i = 0; i < LOOP_COUNT; i++) { assertTrue("Property not found", config.getProperty("test.short") != null); } for (int i = 0; i < testThreads.length; ++i) { testThreads[i].join(); } } /** * Tests whether a windows path can be saved correctly. This test is related * to CONFIGURATION-428. */ @Test public void testSaveWindowsPath() throws ConfigurationException { conf.clear(); conf.addProperty("path", "C:\\Temp"); StringWriter writer = new StringWriter(); conf.save(writer); String content = writer.toString(); assertTrue("Path not found: " + content, content.indexOf("C:\\Temp") >= 0); conf.save(testSaveFile); XMLConfiguration conf2 = new XMLConfiguration(testSaveFile); assertEquals("Wrong windows path", "C:\\Temp", conf2.getString("path")); } /** * Tests whether an attribute can be set to an empty string. This test is * related to CONFIGURATION-446. */ @Test public void testEmptyAttribute() throws ConfigurationException { String key = "element3[@value]"; conf.setProperty(key, ""); assertTrue("Key not found", conf.containsKey(key)); assertEquals("Wrong value", "", conf.getString(key)); conf.save(testSaveConf); conf = new XMLConfiguration(); conf.load(testSaveConf); assertTrue("Key not found after save", conf.containsKey(key)); assertEquals("Wrong value after save", "", conf.getString(key)); } /** * Tests whether it is possible to add nodes to a XMLConfiguration through a * SubnodeConfiguration and whether these nodes have the correct type. This * test is related to CONFIGURATION-472. */ @Test public void testAddNodesToSubnodeConfiguration() throws Exception { SubnodeConfiguration sub = conf.configurationAt("element2"); sub.addProperty("newKey", "newvalue"); ConfigurationNode root = conf.getRootNode(); ConfigurationNode elem = root.getChildren("element2").get(0); ConfigurationNode newNode = elem.getChildren("newKey").get(0); assertTrue("Wrong node type: " + newNode, newNode instanceof XMLConfiguration.XMLNode); } /** * Tests whether list properties are set correctly if delimiter * parsing is disabled. This test is related to CONFIGURATION-495. */ @Test public void testSetPropertyListWithDelimiterParsingDisabled() throws ConfigurationException { String prop = "delimiterListProp"; conf.setDelimiterParsingDisabled(true); List list = Arrays.asList("val", "val2", "val3"); conf.setProperty(prop, list); conf.setFile(testSaveFile); conf.save(); conf.clear(); conf.load(); assertEquals("Wrong list property", list, conf.getProperty(prop)); } /** * Tests whether list properties are added correctly if delimiter parsing is * disabled. This test is related to CONFIGURATION-495. */ @Test public void testAddPropertyListWithDelimiterParsingDisabled() throws ConfigurationException { String prop = "delimiterListProp"; conf.setDelimiterParsingDisabled(true); List list = Arrays.asList("val", "val2", "val3"); conf.addProperty(prop, list); conf.setFile(testSaveFile); conf.save(); conf.clear(); conf.load(); assertEquals("Wrong list property", list, conf.getProperty(prop)); } /** * Prepares a configuration object for testing a reload operation. * * @return the initialized configuration * @throws ConfigurationException if an error occurs */ private XMLConfiguration setUpReloadTest() throws ConfigurationException { removeTestFile(); conf.save(testSaveConf); XMLConfiguration c = new XMLConfiguration(testSaveConf); c.setReloadingStrategy(new FileAlwaysReloadingStrategy()); conf.setProperty("test(0).entity", "newValue"); conf.save(testSaveConf); return c; } /** * Removes the test output file if it exists. */ private void removeTestFile() { if (testSaveConf.exists()) { assertTrue(testSaveConf.delete()); } } /** * Helper method for checking if a save operation was successful. Loads a * saved configuration and then tests against a reference configuration. * @param checkConfig the configuration to check * @throws ConfigurationException if an error occurs */ private void checkSavedConfig(FileConfiguration checkConfig) throws ConfigurationException { checkConfig.load(); ConfigurationAssert.assertEquals(conf, checkConfig); } private class ReloadThread extends Thread { FileConfiguration config; ReloadThread(FileConfiguration config) { this.config = config; } @Override public void run() { for (int i = 0; i < LOOP_COUNT; i++) { config.reload(); } } } } ././@LongLink100644 0 0 162 12232154257 10255 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestXMLPropertiesConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/TestXMLPropertiesConfi100644 13336 12232154104 33542 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import java.net.URL; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.junit.Test; import org.w3c.dom.Document; /** * @author Emmanuel Bourg * @version $Id: TestXMLPropertiesConfiguration.java 1534399 2013-10-21 22:25:03Z henning $ */ public class TestXMLPropertiesConfiguration { @Test public void testLoad() throws Exception { XMLPropertiesConfiguration conf = new XMLPropertiesConfiguration("test.properties.xml"); assertEquals("header", "Description of the property list", conf.getHeader()); assertFalse("The configuration is empty", conf.isEmpty()); assertEquals("'key1' property", "value1", conf.getProperty("key1")); assertEquals("'key2' property", "value2", conf.getProperty("key2")); assertEquals("'key3' property", "value3", conf.getProperty("key3")); } @Test public void testDOMLoad() throws Exception { URL location = ConfigurationUtils.locate(FileSystem.getDefaultFileSystem(), null, "test.properties.xml"); DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); File file = new File(location.toURI()); Document doc = dBuilder.parse(file); XMLPropertiesConfiguration conf = new XMLPropertiesConfiguration(doc.getDocumentElement()); assertEquals("header", "Description of the property list", conf.getHeader()); assertFalse("The configuration is empty", conf.isEmpty()); assertEquals("'key1' property", "value1", conf.getProperty("key1")); assertEquals("'key2' property", "value2", conf.getProperty("key2")); assertEquals("'key3' property", "value3", conf.getProperty("key3")); } @Test public void testSave() throws Exception { // load the configuration XMLPropertiesConfiguration conf = new XMLPropertiesConfiguration("test.properties.xml"); // update the configuration conf.addProperty("key4", "value4"); conf.clearProperty("key2"); conf.setHeader("Description of the new property list"); // save the configuration File saveFile = new File("target/test2.properties.xml"); if (saveFile.exists()) { assertTrue(saveFile.delete()); } conf.save(saveFile); // reload the configuration XMLPropertiesConfiguration conf2 = new XMLPropertiesConfiguration(saveFile); // test the configuration assertEquals("header", "Description of the new property list", conf2.getHeader()); assertFalse("The configuration is empty", conf2.isEmpty()); assertEquals("'key1' property", "value1", conf2.getProperty("key1")); assertEquals("'key3' property", "value3", conf2.getProperty("key3")); assertEquals("'key4' property", "value4", conf2.getProperty("key4")); } @Test public void testDOMSave() throws Exception { // load the configuration XMLPropertiesConfiguration conf = new XMLPropertiesConfiguration("test.properties.xml"); // update the configuration conf.addProperty("key4", "value4"); conf.clearProperty("key2"); conf.setHeader("Description of the new property list"); // save the configuration File saveFile = new File("target/test2.properties.xml"); if (saveFile.exists()) { assertTrue(saveFile.delete()); } // save as DOM into saveFile DocumentBuilderFactory dbFactory = DocumentBuilderFactory.newInstance(); DocumentBuilder dBuilder = dbFactory.newDocumentBuilder(); Document document = dBuilder.newDocument(); conf.save(document, document); TransformerFactory tFactory = TransformerFactory.newInstance(); Transformer transformer = tFactory.newTransformer(); DOMSource source = new DOMSource(document); Result result = new StreamResult(saveFile); transformer.transform(source, result); // reload the configuration XMLPropertiesConfiguration conf2 = new XMLPropertiesConfiguration(saveFile); // test the configuration assertEquals("header", "Description of the new property list", conf2.getHeader()); assertFalse("The configuration is empty", conf2.isEmpty()); assertEquals("'key1' property", "value1", conf2.getProperty("key1")); assertEquals("'key3' property", "value3", conf2.getProperty("key3")); assertEquals("'key4' property", "value4", conf2.getProperty("key4")); } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/AbstractCombinerTest.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/AbstractCombinerT100644 6407 12232154104 33474 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.File; import org.apache.commons.configuration.ConfigurationAssert; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.XMLConfiguration; import org.junit.Before; import org.junit.Test; /** * A base class for testing combiner implementations. This base class provides * some functionality for loading the test configurations, which are to be * combined. Concrete sub classes only need to create the correct combiner * object. * * @version $Id: AbstractCombinerTest.java 1225911 2011-12-30 20:19:10Z oheger $ */ public abstract class AbstractCombinerTest { /** Constant for the first test configuration. */ static File CONF1 = ConfigurationAssert.getTestFile("testcombine1.xml"); /** Constant for the second test configuration. */ static File CONF2 = ConfigurationAssert.getTestFile("testcombine2.xml"); /** The combiner to be tested. */ protected NodeCombiner combiner; @Before public void setUp() throws Exception { combiner = createCombiner(); } /** * Creates the combiner to be tested. This method is called by * setUp(). It must be implemented in concrete sub classes. * * @return the combiner to be tested */ protected abstract NodeCombiner createCombiner(); /** * Constructs a union configuration based on the source configurations. * * @return the union configuration * @throws ConfigurationException if an error occurs */ protected HierarchicalConfiguration createCombinedConfiguration() throws ConfigurationException { XMLConfiguration conf1 = new XMLConfiguration(CONF1); XMLConfiguration conf2 = new XMLConfiguration(CONF2); ConfigurationNode cn = combiner.combine(conf1.getRootNode(), conf2 .getRootNode()); HierarchicalConfiguration result = new HierarchicalConfiguration(); result.setRootNode(cn); return result; } /** * Tests a newly created combiner. */ @Test public void testInit() { assertTrue("Combiner has list nodes", combiner.getListNodes().isEmpty()); assertFalse("Node is list node", combiner .isListNode(new DefaultConfigurationNode("test"))); } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestDefaultConfigurationKey.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestDefaultConfig100644 43102 12232154104 33511 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.NoSuchElementException; import org.junit.Before; import org.junit.Test; /** * Test class for DefaultConfigurationKey. * * @author Oliver Heger * @version $Id: TestDefaultConfigurationKey.java 1225914 2011-12-30 20:26:36Z oheger $ */ public class TestDefaultConfigurationKey { /** Constant for a test key. */ private static final String TESTPROPS = "tables.table(0).fields.field(1)"; /** Constant for a test attribute key. */ private static final String TESTATTR = "[@dataType]"; /** Constant for a complex attribute key. */ private static final String TESTKEY = TESTPROPS + TESTATTR; /** Stores the expression engine of the key to test. */ DefaultExpressionEngine expressionEngine; /** Stores the object to be tested. */ DefaultConfigurationKey key; @Before public void setUp() throws Exception { expressionEngine = new DefaultExpressionEngine(); key = new DefaultConfigurationKey(expressionEngine); } /** * Tests setting the expression engine to null. This should not be allowed. */ @Test(expected = IllegalArgumentException.class) public void testSetNullExpressionEngine() { key.setExpressionEngine(null); } /** * Tests the isAttributeKey() method with several keys. */ @Test public void testIsAttributeKey() { assertTrue("Attribute key not detected", key.isAttributeKey(TESTATTR)); assertFalse("Property key considered as attribute", key .isAttributeKey(TESTPROPS)); assertFalse("Null key considered as attribute", key .isAttributeKey(null)); } /** * Tests if attribute keys are correctly detected if no end markers are set. * (In this test case we use the same delimiter for attributes as for simple * properties.) */ @Test public void testIsAttributeKeyWithoutEndMarkers() { expressionEngine.setAttributeEnd(null); expressionEngine .setAttributeStart(DefaultExpressionEngine.DEFAULT_PROPERTY_DELIMITER); assertTrue( "Attribute key not detected", key .isAttributeKey(DefaultExpressionEngine.DEFAULT_PROPERTY_DELIMITER + "test")); assertFalse("Property key considered as attribute key", key .isAttributeKey(TESTATTR)); } /** * Tests removing leading delimiters. */ @Test public void testTrimLeft() { assertEquals("Key was not left trimmed", "test.", key .trimLeft(".test.")); assertEquals("Too much left trimming", "..test.", key .trimLeft("..test.")); } /** * Tests removing trailing delimiters. */ @Test public void testTrimRight() { assertEquals("Key was not right trimmed", ".test", key .trimRight(".test.")); assertEquals("Too much right trimming", ".test..", key .trimRight(".test..")); } /** * Tests removing delimiters. */ @Test public void testTrim() { assertEquals("Key was not trimmed", "test", key.trim(".test.")); assertEquals("Null key could not be processed", "", key.trim(null)); assertEquals("Delimiter could not be processed", "", key .trim(DefaultExpressionEngine.DEFAULT_PROPERTY_DELIMITER)); } /** * Tests appending keys. */ @Test public void testAppend() { key.append("tables").append("table(0)."); key.append("fields.").append("field(1)"); key.append(null).append(TESTATTR); assertEquals("Wrong key", TESTKEY, key.toString()); } /** * Tests appending keys that contain delimiters. */ @Test public void testAppendDelimiters() { key.append("key..").append("test").append("."); key.append(".more").append("..tests"); assertEquals("Wrong key", "key...test.more...tests", key.toString()); } /** * Tests appending keys that contain delimiters when no escpaped delimiter * is defined. */ @Test public void testAppendDelimitersWithoutEscaping() { expressionEngine.setEscapedDelimiter(null); key.append("key.......").append("test").append("."); key.append(".more").append("..tests"); assertEquals("Wrong constructed key", "key.test.more.tests", key .toString()); } /** * Tests calling append with the escape flag. */ @Test public void testAppendWithEscapeFlag() { key.append(".key.test.", true); key.append(".more").append(".tests", true); assertEquals("Wrong constructed key", "..key..test...more...tests", key .toString()); } /** * Tests constructing keys for attributes. */ @Test public void testConstructAttributeKey() { assertEquals("Wrong attribute key", TESTATTR, key .constructAttributeKey("dataType")); assertEquals("Attribute key was incorrectly converted", TESTATTR, key .constructAttributeKey(TESTATTR)); assertEquals("Null key could not be processed", "", key .constructAttributeKey(null)); } /** * Tests constructing attribute keys when no end markers are defined. In * this test case we use the property delimiter as attribute prefix. */ @Test public void testConstructAttributeKeyWithoutEndMarkers() { expressionEngine.setAttributeEnd(null); expressionEngine.setAttributeStart(expressionEngine .getPropertyDelimiter()); assertEquals("Wrong attribute key", ".test", key .constructAttributeKey("test")); assertEquals("Attribute key was incorrectly converted", ".test", key .constructAttributeKey(".test")); } /** * Tests appending attribute keys. */ @Test public void testAppendAttribute() { key.appendAttribute("dataType"); assertEquals("Attribute key not correctly appended", TESTATTR, key .toString()); } /** * Tests appending an attribute key that is already decorated- */ @Test public void testAppendDecoratedAttributeKey() { key.appendAttribute(TESTATTR); assertEquals("Decorated attribute key not correctly appended", TESTATTR, key.toString()); } /** * Tests appending a null attribute key. */ @Test public void testAppendNullAttributeKey() { key.appendAttribute(null); assertEquals("Null attribute key not correctly appended", "", key .toString()); } /** * Tests appending an index to a key. */ @Test public void testAppendIndex() { key.append("test").appendIndex(42); assertEquals("Index was not correctly appended", "test(42)", key .toString()); } /** * Tests constructing a complex key by chaining multiple append operations. */ @Test public void testAppendComplexKey() { key.append("tables").append("table.").appendIndex(0); key.append("fields.").append("field").appendIndex(1); key.appendAttribute("dataType"); assertEquals("Wrong complex key", TESTKEY, key.toString()); } /** * Tests getting and setting the key's length. */ @Test public void testLength() { key.append(TESTPROPS); assertEquals("Wrong length", TESTPROPS.length(), key.length()); key.appendAttribute("dataType"); assertEquals("Wrong length", TESTKEY.length(), key.length()); key.setLength(TESTPROPS.length()); assertEquals("Wrong length after shortening", TESTPROPS.length(), key .length()); assertEquals("Wrong resulting key", TESTPROPS, key.toString()); } /** * Tests comparing configuration keys. */ @Test public void testEquals() { DefaultConfigurationKey k1 = new DefaultConfigurationKey( expressionEngine, TESTKEY); DefaultConfigurationKey k2 = new DefaultConfigurationKey( expressionEngine, TESTKEY); assertTrue("Keys are not equal", k1.equals(k2)); assertTrue("Not reflexiv", k2.equals(k1)); assertEquals("Hash codes not equal", k1.hashCode(), k2.hashCode()); k2.append("anotherPart"); assertFalse("Keys considered equal", k1.equals(k2)); assertFalse("Keys considered equal", k2.equals(k1)); assertFalse("Key equals null key", k1.equals(null)); assertTrue("Faild comparison with string", k1.equals(TESTKEY)); } /** * Tests determining an attribute key's name. */ @Test public void testAttributeName() { assertEquals("Plain key not detected", "test", key .attributeName("test")); assertEquals("Attribute markers not stripped", "dataType", key .attributeName(TESTATTR)); assertNull("Null key not processed", key.attributeName(null)); } /** * Tests to iterate over a simple key. */ @Test public void testIterate() { key.append(TESTKEY); DefaultConfigurationKey.KeyIterator it = key.iterator(); assertTrue("No key parts", it.hasNext()); assertEquals("Wrong key part", "tables", it.nextKey()); assertEquals("Wrong key part", "table", it.nextKey()); assertTrue("No index found", it.hasIndex()); assertEquals("Wrong index", 0, it.getIndex()); assertEquals("Wrong key part", "fields", it.nextKey()); assertFalse("Found an index", it.hasIndex()); assertEquals("Wrong key part", "field", it.nextKey(true)); assertEquals("Wrong index", 1, it.getIndex()); assertFalse("Found an attribute", it.isAttribute()); assertEquals("Wrong current key", "field", it.currentKey(true)); assertEquals("Wrong key part", "dataType", it.nextKey()); assertEquals("Wrong decorated key part", "[@dataType]", it .currentKey(true)); assertTrue("Attribute not found", it.isAttribute()); assertFalse("Too many key parts", it.hasNext()); try { it.next(); fail("Could iterate over the iteration's end!"); } catch (NoSuchElementException nex) { // ok } } /** * Tests an iteration where the remove() method is called. This is not * supported. */ @Test(expected = UnsupportedOperationException.class) public void testIterateWithRemove() { assertFalse(key.iterator().hasNext()); key.append("simple"); DefaultConfigurationKey.KeyIterator it = key.iterator(); assertTrue(it.hasNext()); assertEquals("simple", it.next()); it.remove(); } /** * Tests iterating over some funny keys. */ @Test public void testIterateStrangeKeys() { key = new DefaultConfigurationKey(expressionEngine, "key."); DefaultConfigurationKey.KeyIterator it = key.iterator(); assertTrue("Too few key parts", it.hasNext()); assertEquals("Wrong key part", "key", it.next()); assertFalse("Too many key parts", it.hasNext()); key = new DefaultConfigurationKey(expressionEngine, "."); it = key.iterator(); assertFalse("Simple delimiter key has more parts", it.hasNext()); key = new DefaultConfigurationKey(expressionEngine, "key().index()undefined(0).test"); it = key.iterator(); assertEquals("Wrong first part", "key()", it.next()); assertFalse("Index detected in first part", it.hasIndex()); assertEquals("Wrong second part", "index()undefined", it.nextKey(false)); assertTrue("No index detected in second part", it.hasIndex()); assertEquals("Wrong index value", 0, it.getIndex()); } /** * Tests iterating over keys with escaped delimiters. */ @Test public void testIterateEscapedDelimiters() { key.append("my..elem"); key.append("trailing..dot.."); key.append(".strange"); assertEquals("my..elem.trailing..dot...strange", key.toString()); DefaultConfigurationKey.KeyIterator kit = key.iterator(); assertEquals("Wrong first part", "my.elem", kit.nextKey()); assertEquals("Wrong second part", "trailing.dot.", kit.nextKey()); assertEquals("Wrong third part", "strange", kit.nextKey()); assertFalse("Too many parts", kit.hasNext()); } /** * Tests iterating over keys when a different escaped delimiter is used. */ @Test public void testIterateAlternativeEscapeDelimiter() { expressionEngine.setEscapedDelimiter("\\."); key.append("\\.my\\.elem"); key.append("trailing\\.dot\\."); key.append(".strange"); assertEquals("\\.my\\.elem.trailing\\.dot\\..strange", key.toString()); DefaultConfigurationKey.KeyIterator kit = key.iterator(); assertEquals("Wrong first part", ".my.elem", kit.nextKey()); assertEquals("Wrong second part", "trailing.dot.", kit.nextKey()); assertEquals("Wrong third part", "strange", kit.nextKey()); assertFalse("Too many parts", kit.hasNext()); } /** * Tests iterating when no escape delimiter is defined. */ @Test public void testIterateWithoutEscapeDelimiter() { expressionEngine.setEscapedDelimiter(null); key.append("..my..elem.trailing..dot...strange"); assertEquals("Wrong key", "my..elem.trailing..dot...strange", key .toString()); DefaultConfigurationKey.KeyIterator kit = key.iterator(); final String[] parts = { "my", "elem", "trailing", "dot", "strange"}; for (int i = 0; i < parts.length; i++) { assertEquals("Wrong key part " + i, parts[i], kit.next()); } assertFalse("Too many parts", kit.hasNext()); } /** * Tests whether a key with brackets in it can be iterated over. */ @Test public void testIterateWithBrackets() { key.append("directory.platform(x86).path"); DefaultConfigurationKey.KeyIterator kit = key.iterator(); String part = kit.nextKey(); assertEquals("Wrong part 1", "directory", part); assertFalse("Has index 1", kit.hasIndex()); part = kit.nextKey(); assertEquals("Wrong part 2", "platform(x86)", part); assertFalse("Has index 2", kit.hasIndex()); part = kit.nextKey(); assertEquals("Wrong part 3", "path", part); assertFalse("Has index 3", kit.hasIndex()); assertFalse("Too many elements", kit.hasNext()); } /** * Tests iterating over an attribute key that has an index. */ @Test public void testAttributeKeyWithIndex() { key.append(TESTATTR); key.appendIndex(0); assertEquals("Wrong attribute key with index", TESTATTR + "(0)", key .toString()); DefaultConfigurationKey.KeyIterator it = key.iterator(); assertTrue("No first element", it.hasNext()); it.next(); assertTrue("Index not found", it.hasIndex()); assertEquals("Incorrect index", 0, it.getIndex()); assertTrue("Attribute not found", it.isAttribute()); assertEquals("Wrong plain key", "dataType", it.currentKey(false)); assertEquals("Wrong decorated key", TESTATTR, it.currentKey(true)); } /** * Tests iteration when the attribute markers equals the property delimiter. */ @Test public void testIterateAttributeEqualsPropertyDelimiter() { expressionEngine.setAttributeEnd(null); expressionEngine.setAttributeStart(expressionEngine .getPropertyDelimiter()); key.append("this.isa.key"); DefaultConfigurationKey.KeyIterator kit = key.iterator(); assertEquals("Wrong first key part", "this", kit.next()); assertFalse("First part is an attribute", kit.isAttribute()); assertTrue("First part is not a property key", kit.isPropertyKey()); assertEquals("Wrong second key part", "isa", kit.next()); assertFalse("Second part is an attribute", kit.isAttribute()); assertTrue("Second part is not a property key", kit.isPropertyKey()); assertEquals("Wrong third key part", "key", kit.next()); assertTrue("Third part is not an attribute", kit.isAttribute()); assertTrue("Third part is not a property key", kit.isPropertyKey()); assertEquals("Wrong decorated key part", "key", kit.currentKey(true)); } } ././@LongLink100644 0 0 165 12232154257 10260 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestDefaultConfigurationNode.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestDefaultConfig100644 41572 12232154104 33522 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotSame; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.List; import java.util.StringTokenizer; import org.junit.Before; import org.junit.Test; /** * Test class for DefaultConfigurationNode. * * @author Commons * Configuration team * @version $Id: TestDefaultConfigurationNode.java 1225917 2011-12-30 20:42:09Z oheger $ */ public class TestDefaultConfigurationNode { /** Constant array for the field names. */ private static final String[] FIELD_NAMES = { "UID", "NAME", "FIRSTNAME", "LASTLOGIN"}; /** Constant array for the field data types. */ private static final String[] FIELD_TYPES = { "long", "string", "string", "date"}; /** Constant array for additional field attributes. */ private static final String[] FIELD_ATTRS = { "primarykey,unique", "notnull", "notnull", null}; /** The node to be tested. */ DefaultConfigurationNode node; @Before public void setUp() throws Exception { node = new DefaultConfigurationNode(); node.setName("table"); node.setReference("TestReference"); node.addAttribute(new DefaultConfigurationNode("type", "system")); node.addChild(new DefaultConfigurationNode("name", "users")); // Add nodes for the table's fields for (int i = 0; i < FIELD_NAMES.length; i++) { DefaultConfigurationNode field = new DefaultConfigurationNode( "field"); field .addChild(new DefaultConfigurationNode("name", FIELD_NAMES[i])); field.addAttribute(new DefaultConfigurationNode("type", FIELD_TYPES[i])); if (FIELD_ATTRS[i] != null) { StringTokenizer tok = new StringTokenizer(FIELD_ATTRS[i], ", "); while (tok.hasMoreTokens()) { field.addAttribute(new DefaultConfigurationNode( "attribute", tok.nextToken())); } } node.addChild(field); } } /** * Tests a newly created, uninitialized node. */ @Test public void testNewNode() { node = new DefaultConfigurationNode(); assertNull("name is not null", node.getName()); assertNull("value is not null", node.getValue()); assertNull("reference is not null", node.getReference()); assertTrue("Children are not empty", node.getChildren().isEmpty()); assertTrue("Named children are not empty", node.getChildren("test") .isEmpty()); assertEquals("Children cound is not 0", 0, node.getChildrenCount()); assertEquals("Named children count is not 0", 0, node .getChildrenCount("test")); assertTrue("Attributes are not empty", node.getAttributes().isEmpty()); assertTrue("Named attributes are not empty", node.getAttributes("test") .isEmpty()); assertNull("Node has a parent", node.getParentNode()); assertFalse("Node is defined", node.isDefined()); } /** * Tries to access an attribute using an invalid index. */ @Test(expected = IndexOutOfBoundsException.class) public void testGetAttributeNonExisting() { node = new DefaultConfigurationNode(); node.getAttribute(0); } /** * Tests accessing a node's reference. */ @Test public void testGetReference() { assertEquals("Reference was not stored", "TestReference", node .getReference()); } /** * Tests accessing the node's children. */ @Test public void testGetChildren() { assertEquals("Number of children incorrect", FIELD_NAMES.length + 1, node.getChildrenCount()); List children = node.getChildren(); Iterator it = children.iterator(); DefaultConfigurationNode child = (DefaultConfigurationNode) it.next(); assertEquals("Wrong node", "name", child.getName()); checkFieldNodes(it); } /** * Tests accessing the node's children by name. */ @Test public void testGetChildrenByName() { List children = node.getChildren("field"); assertEquals("Incorrect number of child nodes", FIELD_NAMES.length, children.size()); assertEquals("Incorrect result of getChildrenCount()", FIELD_NAMES.length, node.getChildrenCount("field")); checkFieldNodes(children.iterator()); assertTrue("Found non existing nodes", node.getChildren("test") .isEmpty()); assertEquals("Wrong children list for null", node.getChildren(), node .getChildren(null)); } /** * Tests adding a new child node. */ @Test public void testAddChild() { int cnt = node.getChildrenCount(); DefaultConfigurationNode ndNew = new DefaultConfigurationNode("test", "xyz"); node.addChild(ndNew); assertEquals("New node was not added", cnt + 1, node.getChildrenCount()); List children = node.getChildren(); assertEquals("Incorrect number of children", node.getChildrenCount(), children.size()); assertSame("Node was not added to end", ndNew, children.get(cnt)); assertEquals("Incorrect number of named children", 1, node .getChildrenCount(ndNew.getName())); assertFalse("Child is an attribute", ndNew.isAttribute()); assertSame("Parent was not set", node, ndNew.getParentNode()); } /** * Tries to add a null child node. */ @Test(expected = IllegalArgumentException.class) public void testAddChildNull() { node.addChild(null); } /** * Tries to add a node without a name. */ @Test(expected = IllegalArgumentException.class) public void testAddUndefinedChild() { node.addChild(new DefaultConfigurationNode()); } /** * Tests removing a child node. */ @Test public void testRemoveChild() { DefaultConfigurationNode child = (DefaultConfigurationNode) node .getChildren().get(3); int cnt = node.getChildrenCount(); node.removeChild(child); assertEquals("Child was not removed", cnt - 1, node.getChildrenCount()); for (ConfigurationNode nd : node.getChildren()) { assertNotSame("Found removed node", child, nd); } assertNull("Parent reference was not removed", child.getParentNode()); } /** * Tests removing a child node that does not belong to this node. */ @Test public void testRemoveNonExistingChild() { int cnt = node.getChildrenCount(); node.removeChild(new DefaultConfigurationNode("test")); node.removeChild(new DefaultConfigurationNode()); node.removeChild((ConfigurationNode) null); node.removeChild("non existing child node"); node.removeChild((String) null); assertEquals("Children were changed", cnt, node.getChildrenCount()); } /** * Tests removing children by their name. */ @Test public void testRemoveChildByName() { int cnt = node.getChildrenCount(); node.removeChild("name"); assertEquals("Child was not removed", cnt - 1, node.getChildrenCount()); assertEquals("Still found name child", 0, node.getChildrenCount("name")); node.removeChild("field"); assertEquals("Still remaining nodes", 0, node.getChildrenCount()); } /** * Tests removing all children at once. */ @Test public void testRemoveChildren() { node.removeChildren(); assertEquals("Children count is not 0", 0, node.getChildrenCount()); assertTrue("Children are not empty", node.getChildren().isEmpty()); } /** * Tests accessing a child by its index. */ @Test public void testGetChild() { ConfigurationNode child = node.getChild(2); assertEquals("Wrong child returned", child, node.getChildren().get(2)); } /** * Tests accessing child nodes with invalid indices. */ @Test(expected = IndexOutOfBoundsException.class) public void testGetChildInvalidIndex() { node.getChild(4724); } /** * Tests accessing the node's attributes. */ @Test public void testGetAttributes() { assertEquals("Number of attributes incorrect", 1, node .getAttributeCount()); List attributes = node.getAttributes(); Iterator it = attributes.iterator(); DefaultConfigurationNode attr = (DefaultConfigurationNode) it.next(); assertEquals("Wrong node", "type", attr.getName()); assertFalse("More attributes", it.hasNext()); } /** * Tests accessing the node's attributes by name. */ @Test public void testGetAttributesByName() { assertEquals("Incorrect number of attributes", 1, node .getAttributeCount("type")); DefaultConfigurationNode field = (DefaultConfigurationNode) node .getChildren().get(1); assertEquals("Incorrect number of attributes", 2, field .getAttributeCount("attribute")); List attrs = field.getAttributes("attribute"); assertEquals("Wrong value", "primarykey", ((DefaultConfigurationNode) attrs.get(0)).getValue()); assertEquals("Wrong value", "unique", ((DefaultConfigurationNode) attrs .get(1)).getValue()); } /** * Tests adding a new attribute node. */ @Test public void testAddAttribute() { int cnt = node.getAttributeCount(); DefaultConfigurationNode ndNew = new DefaultConfigurationNode("test", "xyz"); node.addAttribute(ndNew); assertEquals("New node was not added", cnt + 1, node .getAttributeCount()); List attrs = node.getAttributes(); assertEquals("Incorrect number of attributes", node.getAttributeCount(), attrs.size()); assertSame("Node was not added to end", ndNew, attrs.get(cnt)); assertEquals("Incorrect number of named attributes", 1, node .getAttributeCount(ndNew.getName())); assertTrue("Child is no attribute", ndNew.isAttribute()); assertSame("Parent was not set", node, ndNew.getParentNode()); } /** * Tests removing an attribute node. */ @Test public void testRemoveAttribute() { DefaultConfigurationNode attr = (DefaultConfigurationNode) node .getAttributes().get(0); int cnt = node.getAttributeCount(); node.removeAttribute(attr); assertEquals("Attribute was not removed", cnt - 1, node .getAttributeCount()); for (ConfigurationNode nd : node.getAttributes()) { assertNotSame("Found removed node", attr, nd); } assertNull("Parent reference was not removed", attr.getParentNode()); } /** * Tests removing attributes by their names. */ @Test public void testRemoveAttributeByName() { ConfigurationNode field = node.getChild(1); assertEquals("Incorrect number of attributes", 3, field .getAttributeCount()); field.removeAttribute("attribute"); assertEquals("Not all nodes removed", 1, field.getAttributeCount()); assertTrue("Remaining attributes", field.getAttributes("attribute") .isEmpty()); field.removeAttribute("type"); assertEquals("Remaining attributes", 0, field.getAttributeCount()); } /** * Tests removing all attributes. */ @Test public void testRemoveAttributes() { node.removeAttributes(); assertEquals("Not all attributes removed", 0, node.getAttributeCount()); assertTrue("Attributes not empty", node.getAttributes().isEmpty()); } /** * Tests changing a node's attribute state. */ @Test(expected = IllegalStateException.class) public void testChangeAttributeState() { ConfigurationNode attr = node.getAttribute(0); attr.setAttribute(false); } /** * Tests the visit() method using a simple visitor. */ @Test public void testVisit() { CountNodeVisitor visitor = new CountNodeVisitor(); node.visit(visitor); assertEquals("Not all nodes visited", 19, visitor.beforeCalls); assertEquals("Different number of before and after calls", visitor.beforeCalls, visitor.afterCalls); } /** * Tests the visit() method with a visitor that terminates the visit * process. */ @Test public void testVisitWithTerminate() { CountNodeVisitor visitor = new CountNodeVisitor(10); node.visit(visitor); assertEquals("Incorrect number of nodes visited", visitor.maxCalls, visitor.beforeCalls); assertEquals("Different number of before and after calls", visitor.beforeCalls, visitor.afterCalls); } /** * Tests the visit() method when null is passed in. This should throw an * exception. */ @Test(expected = IllegalArgumentException.class) public void testVisitWithNullVisitor() { node.visit(null); } /** * Tests cloning a node. */ @Test public void testClone() { node.setValue("TestValue"); DefaultConfigurationNode clone = (DefaultConfigurationNode) node.clone(); assertEquals("Value not cloned", "TestValue", clone.getValue()); assertEquals("Name not cloned", "table", clone.getName()); assertEquals("Reference not cloned", "TestReference", clone.getReference()); assertEquals("Children were cloned", 0, clone.getChildrenCount()); assertEquals("Attributes were cloned", 0, clone.getAttributeCount()); } /** * Helper method for checking the child nodes of type "field". * * @param itFields the iterator with the child nodes */ private void checkFieldNodes(Iterator itFields) { for (int i = 0; i < FIELD_NAMES.length; i++) { DefaultConfigurationNode child = (DefaultConfigurationNode) itFields .next(); assertEquals("Wrong node", "field", child.getName()); List nameNodes = child.getChildren("name"); assertEquals("Wrong number of name nodes", 1, nameNodes.size()); DefaultConfigurationNode nameNode = (DefaultConfigurationNode) nameNodes .get(0); assertEquals("Wrong field name", FIELD_NAMES[i], nameNode .getValue()); } } /** * A test visitor implementation that is able to count the number of visits. * It also supports a maximum number of visits to be set; if this number is * reached, the terminate() method returns true. */ public static class CountNodeVisitor implements ConfigurationNodeVisitor { public int beforeCalls; public int afterCalls; public int maxCalls; public CountNodeVisitor() { this(Integer.MAX_VALUE); } public CountNodeVisitor(int maxNumberOfVisits) { maxCalls = maxNumberOfVisits; } public void visitBeforeChildren(ConfigurationNode node) { beforeCalls++; } public void visitAfterChildren(ConfigurationNode node) { afterCalls++; } public boolean terminate() { return beforeCalls >= maxCalls; } } } ././@LongLink100644 0 0 164 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestDefaultExpressionEngine.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestDefaultExpres100644 45353 12232154104 33564 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.List; import org.junit.Before; import org.junit.Test; /** * Test class for DefaultExpressionEngine. * * @author Commons * Configuration team * @version $Id: TestDefaultExpressionEngine.java 1225918 2011-12-30 20:54:47Z oheger $ */ public class TestDefaultExpressionEngine { /** Stores the names of the test nodes representing tables. */ private static String[] tables = { "users", "documents"}; /** Stores the types of the test table nodes. */ private static String[] tabTypes = { "system", "application"}; /** Test data fields for the node hierarchy. */ private static String[][] fields = { { "uid", "uname", "firstName", "lastName", "email"}, { "docid", "name", "creationDate", "authorID", "version"}}; /** The object to be tested. */ DefaultExpressionEngine engine; /** The root of a hierarchy with configuration nodes. */ ConfigurationNode root; @Before public void setUp() throws Exception { root = setUpNodes(); engine = new DefaultExpressionEngine(); } /** * Tests some simple queries. */ @Test public void testQueryKeys() { checkKey("tables.table.name", "name", 2); checkKey("tables.table.fields.field.name", "name", 10); checkKey("tables.table[@type]", "type", 2); checkKey("tables.table(0).fields.field.name", "name", 5); checkKey("tables.table(1).fields.field.name", "name", 5); checkKey("tables.table.fields.field(1).name", "name", 2); } /** * Performs some queries and evaluates the values of the result nodes. */ @Test public void testQueryNodes() { for (int i = 0; i < tables.length; i++) { checkKeyValue("tables.table(" + i + ").name", "name", tables[i]); checkKeyValue("tables.table(" + i + ")[@type]", "type", tabTypes[i]); for (int j = 0; j < fields[i].length; j++) { checkKeyValue("tables.table(" + i + ").fields.field(" + j + ").name", "name", fields[i][j]); } } } /** * Tests querying keys that do not exist. */ @Test public void testQueryNonExistingKeys() { checkKey("tables.tablespace.name", null, 0); checkKey("tables.table(2).name", null, 0); checkKey("a complete unknown key", null, 0); checkKey("tables.table(0).fields.field(-1).name", null, 0); checkKey("tables.table(0).fields.field(28).name", null, 0); checkKey("tables.table(0).fields.field().name", null, 0); checkKey("connection.settings.usr.name", null, 0); } /** * Tests querying nodes whose names contain a delimiter. */ @Test public void testQueryEscapedKeys() { checkKeyValue("connection..settings.usr..name", "usr.name", "scott"); checkKeyValue("connection..settings.usr..pwd", "usr.pwd", "tiger"); } /** * Tests some queries when the same delimiter is used for properties and * attributes. */ @Test public void testQueryAttributeEmulation() { engine.setAttributeEnd(null); engine.setAttributeStart(engine.getPropertyDelimiter()); checkKeyValue("tables.table(0).name", "name", tables[0]); checkKeyValue("tables.table(0).type", "type", tabTypes[0]); checkKey("tables.table.type", "type", 2); } /** * Tests accessing the root node. */ @Test public void testQueryRootNode() { List nodes = checkKey(null, null, 1); assertSame("Root node not found", root, nodes.get(0)); nodes = checkKey("", null, 1); assertSame("Root node not found", root, nodes.get(0)); checkKeyValue("[@test]", "test", "true"); } /** * Tests a different query syntax. Sets other strings for the typical tokens * used by the expression engine. */ @Test public void testQueryAlternativeSyntax() { setUpAlternativeSyntax(); checkKeyValue("tables/table[1]/name", "name", tables[1]); checkKeyValue("tables/table[0]@type", "type", tabTypes[0]); checkKeyValue("@test", "test", "true"); checkKeyValue("connection.settings/usr.name", "usr.name", "scott"); } /** * Tests obtaining keys for nodes. */ @Test public void testNodeKey() { ConfigurationNode node = root.getChild(0); assertEquals("Invalid name for descendant of root", "tables", engine .nodeKey(node, "")); assertEquals("Parent key not respected", "test.tables", engine.nodeKey( node, "test")); assertEquals("Full parent key not taken into account", "a.full.parent.key.tables", engine.nodeKey(node, "a.full.parent.key")); } /** * Tests obtaining keys when the root node is involved. */ @Test public void testNodeKeyWithRoot() { assertEquals("Wrong name for root noot", "", engine.nodeKey(root, null)); assertEquals("Null name not detected", "test", engine.nodeKey(root, "test")); } /** * Tests obtaining keys for attribute nodes. */ @Test public void testNodeKeyWithAttribute() { ConfigurationNode node = root.getChild(0).getChild(0).getAttribute(0); assertEquals("Wrong attribute node", "type", node.getName()); assertEquals("Wrong attribute key", "tables.table[@type]", engine .nodeKey(node, "tables.table")); assertEquals("Wrong key for root attribute", "[@test]", engine.nodeKey( root.getAttribute(0), "")); } /** * Tests obtaining keys for nodes that contain the delimiter character. */ @Test public void testNodeKeyWithEscapedDelimiters() { ConfigurationNode node = root.getChild(1); assertEquals("Wrong escaped key", "connection..settings", engine .nodeKey(node, "")); assertEquals("Wrong complex escaped key", "connection..settings.usr..name", engine.nodeKey(node .getChild(0), engine.nodeKey(node, ""))); } /** * Tests obtaining node keys when a different syntax is set. */ @Test public void testNodeKeyWithAlternativeSyntax() { setUpAlternativeSyntax(); assertEquals("Wrong child key", "tables/table", engine.nodeKey(root .getChild(0).getChild(0), "tables")); assertEquals("Wrong attribute key", "@test", engine.nodeKey(root .getAttribute(0), "")); engine.setAttributeStart(engine.getPropertyDelimiter()); assertEquals("Wrong attribute key", "/test", engine.nodeKey(root .getAttribute(0), "")); } /** * Tests adding direct child nodes to the existing hierarchy. */ @Test public void testPrepareAddDirectly() { NodeAddData data = engine.prepareAdd(root, "newNode"); assertSame("Wrong parent node", root, data.getParent()); assertTrue("Path nodes available", data.getPathNodes().isEmpty()); assertEquals("Wrong name of new node", "newNode", data.getNewNodeName()); assertFalse("New node is an attribute", data.isAttribute()); data = engine.prepareAdd(root, "tables.table.fields.field.name"); assertEquals("Wrong name of new node", "name", data.getNewNodeName()); assertTrue("Path nodes available", data.getPathNodes().isEmpty()); assertEquals("Wrong parent node", "field", data.getParent().getName()); ConfigurationNode nd = data.getParent().getChild(0); assertEquals("Field has no name node", "name", nd.getName()); assertEquals("Incorrect name", "version", nd.getValue()); } /** * Tests adding when indices are involved. */ @Test public void testPrepareAddWithIndex() { NodeAddData data = engine .prepareAdd(root, "tables.table(0).tableSpace"); assertEquals("Wrong name of new node", "tableSpace", data .getNewNodeName()); assertTrue("Path nodes available", data.getPathNodes().isEmpty()); assertEquals("Wrong type of parent node", "table", data.getParent() .getName()); ConfigurationNode node = data.getParent().getChild(0); assertEquals("Wrong table", tables[0], node.getValue()); data = engine.prepareAdd(root, "tables.table(1).fields.field(2).alias"); assertEquals("Wrong name of new node", "alias", data.getNewNodeName()); assertEquals("Wrong type of parent node", "field", data.getParent() .getName()); assertEquals("Wrong field node", "creationDate", data.getParent() .getChild(0).getValue()); } /** * Tests adding new attributes. */ @Test public void testPrepareAddAttribute() { NodeAddData data = engine.prepareAdd(root, "tables.table(0)[@tableSpace]"); assertEquals("Wrong table node", tables[0], data.getParent() .getChild(0).getValue()); assertEquals("Wrong name of new node", "tableSpace", data .getNewNodeName()); assertTrue("Attribute not detected", data.isAttribute()); assertTrue("Path nodes available", data.getPathNodes().isEmpty()); data = engine.prepareAdd(root, "[@newAttr]"); assertSame("Root node is not parent", root, data.getParent()); assertEquals("Wrong name of new node", "newAttr", data.getNewNodeName()); assertTrue("Attribute not detected", data.isAttribute()); } /** * Tests add operations where complete paths are added. */ @Test public void testPrepareAddWithPath() { NodeAddData data = engine.prepareAdd(root, "tables.table(1).fields.field(-1).name"); assertEquals("Wrong name of new node", "name", data.getNewNodeName()); checkNodePath(data, new String[] { "field"}); assertEquals("Wrong type of parent node", "fields", data.getParent() .getName()); data = engine.prepareAdd(root, "tables.table(-1).name"); assertEquals("Wrong name of new node", "name", data.getNewNodeName()); checkNodePath(data, new String[] { "table"}); assertEquals("Wrong type of parent node", "tables", data.getParent() .getName()); data = engine.prepareAdd(root, "a.complete.new.path"); assertEquals("Wrong name of new node", "path", data.getNewNodeName()); checkNodePath(data, new String[] { "a", "complete", "new"}); assertSame("Root is not parent", root, data.getParent()); } /** * Tests add operations when property and attribute delimiters are equal. * Then it is not possible to add new attribute nodes. */ @Test public void testPrepareAddWithSameAttributeDelimiter() { engine.setAttributeEnd(null); engine.setAttributeStart(engine.getPropertyDelimiter()); NodeAddData data = engine.prepareAdd(root, "tables.table(0).test"); assertEquals("Wrong name of new node", "test", data.getNewNodeName()); assertFalse("New node is an attribute", data.isAttribute()); assertEquals("Wrong type of parent node", "table", data.getParent() .getName()); data = engine.prepareAdd(root, "a.complete.new.path"); assertFalse("New node is an attribute", data.isAttribute()); checkNodePath(data, new String[] { "a", "complete", "new"}); } /** * Tests add operations when an alternative syntax is set. */ @Test public void testPrepareAddWithAlternativeSyntax() { setUpAlternativeSyntax(); NodeAddData data = engine.prepareAdd(root, "tables/table[0]/test"); assertEquals("Wrong name of new node", "test", data.getNewNodeName()); assertFalse("New node is attribute", data.isAttribute()); assertEquals("Wrong parent node", tables[0], data.getParent().getChild( 0).getValue()); data = engine.prepareAdd(root, "a/complete/new/path@attr"); assertEquals("Wrong name of new attribute", "attr", data .getNewNodeName()); checkNodePath(data, new String[] { "a", "complete", "new", "path"}); assertSame("Root is not parent", root, data.getParent()); } /** * Tests using invalid keys, e.g. if something should be added to * attributes. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddInvalidKey() { engine.prepareAdd(root, "tables.table(0)[@type].new"); } @Test(expected = IllegalArgumentException.class) public void testPrepareAddInvalidKeyAttribute() { engine .prepareAdd(root, "a.complete.new.path.with.an[@attribute].at.a.non.allowed[@position]"); } @Test(expected = IllegalArgumentException.class) public void testPrepareAddNullKey() { engine.prepareAdd(root, null); } @Test(expected = IllegalArgumentException.class) public void testPrepareAddEmptyKey() { engine.prepareAdd(root, ""); } /** * Creates a node hierarchy for testing that consists of tables, their * fields, and some additional data: * *
     *  tables
     *       table
     *          name
     *          fields
     *              field
     *                  name
     *              field
     *                  name
     * 
* * @return the root of the test node hierarchy */ protected ConfigurationNode setUpNodes() { DefaultConfigurationNode rootNode = new DefaultConfigurationNode(); DefaultConfigurationNode nodeTables = new DefaultConfigurationNode( "tables"); rootNode.addChild(nodeTables); for (int i = 0; i < tables.length; i++) { DefaultConfigurationNode nodeTable = new DefaultConfigurationNode( "table"); nodeTables.addChild(nodeTable); nodeTable.addChild(new DefaultConfigurationNode("name", tables[i])); nodeTable.addAttribute(new DefaultConfigurationNode("type", tabTypes[i])); DefaultConfigurationNode nodeFields = new DefaultConfigurationNode( "fields"); nodeTable.addChild(nodeFields); for (int j = 0; j < fields[i].length; j++) { nodeFields.addChild(createFieldNode(fields[i][j])); } } DefaultConfigurationNode nodeConn = new DefaultConfigurationNode( "connection.settings"); rootNode.addChild(nodeConn); nodeConn.addChild(new DefaultConfigurationNode("usr.name", "scott")); nodeConn.addChild(new DefaultConfigurationNode("usr.pwd", "tiger")); rootNode.addAttribute(new DefaultConfigurationNode("test", "true")); return rootNode; } /** * Configures the expression engine to use a different syntax. */ private void setUpAlternativeSyntax() { engine.setAttributeEnd(null); engine.setAttributeStart("@"); engine.setPropertyDelimiter("/"); engine.setEscapedDelimiter(null); engine.setIndexStart("["); engine.setIndexEnd("]"); } /** * Helper method for checking the evaluation of a key. Queries the * expression engine and tests if the expected results are returned. * * @param key the key * @param name the name of the nodes to be returned * @param count the number of expected result nodes * @return the list with the results of the query */ private List checkKey(String key, String name, int count) { List nodes = engine.query(root, key); assertEquals("Wrong number of result nodes for key " + key, count, nodes.size()); for (Iterator it = nodes.iterator(); it.hasNext();) { assertEquals("Wrong result node for key " + key, name, it.next().getName()); } return nodes; } /** * Helper method for checking the value of a node specified by the given * key. This method evaluates the key and checks whether the resulting node * has the expected value. * * @param key the key * @param name the expected name of the result node * @param value the expected value of the result node */ private void checkKeyValue(String key, String name, String value) { List nodes = checkKey(key, name, 1); assertEquals("Wrong value for key " + key, value, nodes.get(0).getValue()); } /** * Helper method for checking the path of an add operation. * * @param data the add data object * @param expected the expected path nodes */ private void checkNodePath(NodeAddData data, String[] expected) { assertEquals("Wrong number of path nodes", expected.length, data .getPathNodes().size()); Iterator it = data.getPathNodes().iterator(); for (int i = 0; i < expected.length; i++) { assertEquals("Wrong path node " + i, expected[i], it.next()); } } /** * Helper method for creating a field node with its children for the test * node hierarchy. * * @param name the name of the field * @return the field node */ private static ConfigurationNode createFieldNode(String name) { DefaultConfigurationNode nodeField = new DefaultConfigurationNode( "field"); nodeField.addChild(new DefaultConfigurationNode("name", name)); return nodeField; } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestMergeCombiner.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestMergeCombiner100644 16241 12232154104 33521 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import java.util.List; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.apache.commons.configuration.tree.xpath.XPathExpressionEngine; import org.junit.Test; /** * Test class for MergeCombiner. * * @version $Id: TestMergeCombiner.java 1225911 2011-12-30 20:19:10Z oheger $ */ public class TestMergeCombiner extends AbstractCombinerTest { /** * Creates the combiner. * * @return the combiner */ @Override protected NodeCombiner createCombiner() { return new MergeCombiner(); } /** * Tests combination of simple elements. */ @Test public void testSimpleValues() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong number of bgcolors", 0, config .getMaxIndex("gui.bgcolor")); assertEquals("Wrong bgcolor", "green", config.getString("gui.bgcolor")); assertEquals("Wrong selcolor", "yellow", config .getString("gui.selcolor")); assertEquals("Wrong fgcolor", "blue", config.getString("gui.fgcolor")); assertEquals("Wrong level", 1, config.getInt("gui.level")); } /** * Tests combination of attributes. */ @Test public void testAttributes() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong value of min attribute", 1, config .getInt("gui.level[@min]")); assertEquals("Wrong value of default attribute", 2, config .getInt("gui.level[@default]")); assertEquals("Wrong number of id attributes", 0, config .getMaxIndex("database.tables.table(0)[@id]")); assertEquals("Wrong value of table id", 1, config .getInt("database.tables.table(0)[@id]")); } /** * Tests whether property values are correctly overridden. */ @Test public void testOverrideValues() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong user", "Admin", config .getString("base.services.security.login.user")); assertEquals("Wrong user type", "default", config .getString("base.services.security.login.user[@type]")); assertNull("Wrong password", config.getString("base.services.security.login.passwd")); assertEquals("Wrong password type", "secret", config .getString("base.services.security.login.passwd[@type]")); } /** * Tests if a list from the first node structure overrides a list in the * second structure. */ @Test public void testListFromFirstStructure() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong number of services", 0, config .getMaxIndex("net.service.url")); assertEquals("Wrong service", "http://service1.org", config .getString("net.service.url")); assertFalse("Type attribute available", config .containsKey("net.service.url[@type]")); } /** * Tests if a list from the second structure is added if it is not defined * in the first structure. */ @Test public void testListFromSecondStructure() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong number of servers", 3, config .getMaxIndex("net.server.url")); assertEquals("Wrong server", "http://testsvr.com", config .getString("net.server.url(2)")); } /** * Tests the combination of the table structure. With the merge combiner * both table 1 and table 2 should be present. */ @Test public void testCombinedTable() throws ConfigurationException { checkTable(createCombinedConfiguration()); } @Test public void testMerge() throws ConfigurationException { //combiner.setDebugStream(System.out); HierarchicalConfiguration config = createCombinedConfiguration(); config.setExpressionEngine(new XPathExpressionEngine()); assertEquals("Wrong number of Channels", 3, config.getMaxIndex("Channels/Channel")); assertEquals("Bad Channel 1 Name", "My Channel", config.getString("Channels/Channel[@id='1']/Name")); assertEquals("Bad Channel Type", "half", config.getString("Channels/Channel[@id='1']/@type")); assertEquals("Bad Channel 2 Name", "Channel 2", config.getString("Channels/Channel[@id='2']/Name")); assertEquals("Bad Channel Type", "full", config.getString("Channels/Channel[@id='2']/@type")); assertEquals("Bad Channel Data", "test 1 data", config.getString("Channels/Channel[@id='1']/ChannelData")); assertEquals("Bad Channel Data", "test 2 data", config.getString("Channels/Channel[@id='2']/ChannelData")); assertEquals("Bad Channel Data", "more test 2 data", config.getString("Channels/Channel[@id='2']/MoreChannelData")); } /** * Helper method for checking the combined table structure. * * @param config the config * @return the node for the table element */ private ConfigurationNode checkTable(HierarchicalConfiguration config) { assertEquals("Wrong number of tables", 1, config .getMaxIndex("database.tables.table")); HierarchicalConfiguration c = config .configurationAt("database.tables.table(0)"); assertEquals("Wrong table name", "documents", c.getString("name")); assertEquals("Wrong number of fields", 2, c .getMaxIndex("fields.field.name")); assertEquals("Wrong field", "docname", c .getString("fields.field(1).name")); List nds = config.getExpressionEngine().query(config.getRoot(), "database.tables.table"); assertFalse("No node found", nds.isEmpty()); return nds.get(0); } }././@LongLink100644 0 0 150 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestNodeAddData.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestNodeAddData.j100644 6776 12232154104 33317 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.List; import org.junit.Before; import org.junit.Test; /** * Test class for NodeAddData. * * @author Commons * Configuration team * @version $Id: TestNodeAddData.java 1226097 2011-12-31 15:16:02Z oheger $ */ public class TestNodeAddData { /** Constant for the default parent node used for testing. */ private static final ConfigurationNode TEST_PARENT = new DefaultConfigurationNode( "parent"); /** Constant for the name of the new node. */ private static final String TEST_NODENAME = "testNewNode"; /** Constant for the name of a path node. */ private static final String PATH_NODE_NAME = "PATHNODE"; /** Constant for the number of path nodes to be added. */ private static final int PATH_NODE_COUNT = 10; /** The object to be tested. */ NodeAddData addData; @Before public void setUp() throws Exception { addData = new NodeAddData(TEST_PARENT, TEST_NODENAME); } /** * Tests the default values of an uninitialized instance. */ @Test public void testUninitialized() { addData = new NodeAddData(); assertNull("A parent is set", addData.getParent()); assertNull("Node has a name", addData.getNewNodeName()); assertFalse("Attribute flag is set", addData.isAttribute()); assertTrue("Path nodes are not empty", addData.getPathNodes().isEmpty()); } /** * Tests the constructor that initializes the most important fields. */ @Test public void testInitialized() { assertSame("Wrong parent", TEST_PARENT, addData.getParent()); assertEquals("Wrong node name", TEST_NODENAME, addData.getNewNodeName()); assertFalse("Attribute flag is set", addData.isAttribute()); assertTrue("Path nodes are not empty", addData.getPathNodes().isEmpty()); } /** * Tests adding path nodes. */ @Test public void testAddPathNode() { for (int i = 0; i < PATH_NODE_COUNT; i++) { addData.addPathNode(PATH_NODE_NAME + i); } List nodes = addData.getPathNodes(); assertEquals("Incorrect number of path nodes", PATH_NODE_COUNT, nodes .size()); for (int i = 0; i < PATH_NODE_COUNT; i++) { assertEquals("Wrong path node at position" + i, PATH_NODE_NAME + i, nodes.get(i)); } } } ././@LongLink100644 0 0 155 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestOverrideCombiner.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestOverrideCombi100644 15374 12232154104 33542 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.List; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.junit.Test; /** * Test class for OverrideCombiner. * * @version $Id: TestOverrideCombiner.java 1225911 2011-12-30 20:19:10Z oheger $ */ public class TestOverrideCombiner extends AbstractCombinerTest { /** * Creates the combiner. * * @return the combiner */ @Override protected NodeCombiner createCombiner() { return new OverrideCombiner(); } /** * Tests combination of simple elements. */ @Test public void testSimpleValues() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong number of bgcolors", 0, config .getMaxIndex("gui.bgcolor")); assertEquals("Wrong bgcolor", "green", config.getString("gui.bgcolor")); assertEquals("Wrong selcolor", "yellow", config .getString("gui.selcolor")); assertEquals("Wrong fgcolor", "blue", config.getString("gui.fgcolor")); assertEquals("Wrong level", 1, config.getInt("gui.level")); } /** * Tests combination of attributes. */ @Test public void testAttributes() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong value of min attribute", 1, config .getInt("gui.level[@min]")); assertEquals("Wrong value of default attribute", 2, config .getInt("gui.level[@default]")); assertEquals("Wrong number of id attributes", 0, config .getMaxIndex("database.tables.table(0)[@id]")); assertEquals("Wrong value of table id", 1, config .getInt("database.tables.table(0)[@id]")); } /** * Tests whether property values are correctly overridden. */ @Test public void testOverrideValues() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong user", "Admin", config .getString("base.services.security.login.user")); assertEquals("Wrong user type", "default", config .getString("base.services.security.login.user[@type]")); assertEquals("Wrong password", "BeamMeUp", config .getString("base.services.security.login.passwd")); assertEquals("Wrong password type", "secret", config .getString("base.services.security.login.passwd[@type]")); } /** * Tests if a list from the first node structure overrides a list in the * second structure. */ @Test public void testListFromFirstStructure() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong number of services", 0, config .getMaxIndex("net.service.url")); assertEquals("Wrong service", "http://service1.org", config .getString("net.service.url")); assertFalse("Type attribute available", config .containsKey("net.service.url[@type]")); } /** * Tests if a list from the second structure is added if it is not defined * in the first structure. */ @Test public void testListFromSecondStructure() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong number of servers", 3, config .getMaxIndex("net.server.url")); assertEquals("Wrong server", "http://testsvr.com", config .getString("net.server.url(2)")); } /** * Tests the combination of the table structure. Because the table node is * not declared as a list node the structures will be combined. But this * won't make any difference because the values in the first table override * the values in the second table. Only the node for the table element will * be a ViewNode. */ @Test public void testCombinedTableNoList() throws ConfigurationException { ConfigurationNode tabNode = checkTable(createCombinedConfiguration()); assertTrue("Node is not a view node", tabNode instanceof ViewNode); } /** * Tests the combination of the table structure when the table node is * declared as a list node. In this case the first table structure * completely overrides the second and will be directly added to the * resulting structure. */ @Test public void testCombinedTableList() throws ConfigurationException { combiner.addListNode("table"); ConfigurationNode tabNode = checkTable(createCombinedConfiguration()); assertFalse("Node is a view node", tabNode instanceof ViewNode); } /** * Helper method for checking the combined table structure. * * @param config the config * @return the node for the table element */ private ConfigurationNode checkTable(HierarchicalConfiguration config) { assertEquals("Wrong number of tables", 0, config .getMaxIndex("database.tables.table")); HierarchicalConfiguration c = config .configurationAt("database.tables.table"); assertEquals("Wrong table name", "documents", c.getString("name")); assertEquals("Wrong number of fields", 2, c .getMaxIndex("fields.field.name")); assertEquals("Wrong field", "docname", c .getString("fields.field(1).name")); List nds = config.getExpressionEngine().query(config.getRoot(), "database.tables.table"); assertFalse("No node found", nds.isEmpty()); return nds.get(0); } } ././@LongLink100644 0 0 152 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestUnionCombiner.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestUnionCombiner100644 12403 12232154104 33546 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import org.apache.commons.configuration.ConfigurationException; import org.apache.commons.configuration.HierarchicalConfiguration; import org.junit.Test; /** * Test class for UnionCombiner. * * @version $Id: TestUnionCombiner.java 1225911 2011-12-30 20:19:10Z oheger $ */ public class TestUnionCombiner extends AbstractCombinerTest { /** * Creates the combiner. * * @return the combiner */ @Override protected NodeCombiner createCombiner() { return new UnionCombiner(); } /** * Tests combination of simple values (no lists). */ @Test public void testSimpleValues() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Too few bgcolors", 1, config.getMaxIndex("gui.bgcolor")); assertEquals("Wrong first color", "green", config .getString("gui.bgcolor(0)")); assertEquals("Wrong second color", "black", config .getString("gui.bgcolor(1)")); assertEquals("Wrong number of selcolors", 0, config .getMaxIndex("gui.selcolor")); assertEquals("Wrong selcolor", "yellow", config .getString("gui.selcolor")); } /** * Tests combinations of elements with attributes. */ @Test public void testSimpleValuesWithAttributes() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Too few level elements", 1, config .getMaxIndex("gui.level")); assertEquals("Wrong value of first element", 1, config .getInt("gui.level(0)")); assertEquals("Wrong value of second element", 4, config .getInt("gui.level(1)")); assertEquals("Wrong value of first attribute", 2, config .getInt("gui.level(0)[@default]")); assertFalse("Found wrong attribute", config .containsKey("gui.level(0)[@min]")); assertEquals("Wrong value of second attribute", 1, config .getInt("gui.level(1)[@min]")); } /** * Tests combination of attributes. */ @Test public void testAttributes() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Too few attributes", 1, config .getMaxIndex("database.tables.table(0)[@id]")); assertEquals("Wrong value of first attribute", 1, config .getInt("database.tables.table(0)[@id](0)")); assertEquals("Wrong value of second attribute", 2, config .getInt("database.tables.table(0)[@id](1)")); } /** * Tests combination of lists. */ @Test public void testLists() throws ConfigurationException { HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Too few list elements", 2, config .getMaxIndex("net.service.url")); assertEquals("Wrong first service", "http://service1.org", config .getString("net.service.url(0)")); assertEquals("Wrong second service", "http://service2.org", config .getString("net.service.url(1)")); assertEquals("Wrong service attribute", 2, config .getInt("net.service.url(2)[@type]")); assertEquals("Wrong number of server elements", 3, config .getMaxIndex("net.server.url")); } /** * Tests combining a list of tables. Per default the table elements will be * combined. But if they are defined as list elements, the resulting tree * should contain two table nodes. */ @Test public void testTableList() throws ConfigurationException { combiner.addListNode("table"); HierarchicalConfiguration config = createCombinedConfiguration(); assertEquals("Wrong name of first table", "documents", config .getString("database.tables.table(0).name")); assertEquals("Wrong id of first table", 1, config .getInt("database.tables.table(0)[@id]")); assertEquals("Wrong name of second table", "tasks", config .getString("database.tables.table(1).name")); assertEquals("Wrong id of second table", 2, config .getInt("database.tables.table(1)[@id]")); } } ././@LongLink100644 0 0 145 12232154257 10256 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestViewNode.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/TestViewNode.java100644 10360 12232154104 33437 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree; import static org.junit.Assert.assertEquals; import org.junit.Before; import org.junit.Test; /** * Test class for ViewNode. * * @version $Id: TestViewNode.java 1226098 2011-12-31 15:18:45Z oheger $ */ public class TestViewNode { /** Stores the view node to be tested. */ ViewNode viewNode; /** Stores a regular node. */ ConfigurationNode node; /** A child node of the regular node. */ ConfigurationNode child; /** An attribute node of the regular node. */ ConfigurationNode attr; @Before public void setUp() throws Exception { node = new DefaultConfigurationNode(); child = new DefaultConfigurationNode("child"); attr = new DefaultConfigurationNode("attr"); node.addChild(child); node.addAttribute(attr); viewNode = new ViewNode(); } /** * Tests adding a child to the view node. */ @Test public void testAddChild() { viewNode.addChild(child); assertEquals("Parent was changed", node, child.getParentNode()); assertEquals("Child was not added", 1, viewNode.getChildrenCount()); } /** * Tests adding a null child to the view node. This should throw an * exception. */ @Test(expected = IllegalArgumentException.class) public void testAddNullChild() { viewNode.addChild(null); } /** * Tests adding an attribute to the view node. */ @Test public void testAddAttribute() { viewNode.addAttribute(attr); assertEquals("Parent was changed", node, attr.getParentNode()); assertEquals("Attribute was not added", 1, viewNode.getAttributeCount()); } /** * Tests adding a null attribute to the view node. This should cause an * exception. */ @Test(expected = IllegalArgumentException.class) public void testAddNullAttribute() { viewNode.addAttribute(null); } /** * Tests appending all children to a view node. */ @Test public void testAppendChildren() { viewNode.addChild(new DefaultConfigurationNode("testNode")); viewNode.appendChildren(node); assertEquals("Wrong number of children", 2, viewNode.getChildrenCount()); assertEquals("Cannot find child", child, viewNode.getChild(1)); assertEquals("Parent was changed", node, viewNode .getChild(1).getParentNode()); } /** * Tests appending children from a null source. This should be a noop. */ @Test public void testAppendNullChildren() { viewNode.appendChildren(null); assertEquals("Wrong number of children", 0, viewNode.getChildrenCount()); } /** * tests appending all attributes to a view node. */ @Test public void testAppendAttributes() { viewNode.appendAttributes(node); assertEquals("Wrong number of attributes", 1, viewNode .getAttributeCount()); assertEquals("Cannot find attribute", attr, viewNode.getAttribute(0)); assertEquals("Parent was changed", node, viewNode .getAttribute(0).getParentNode()); } /** * Tests appending attributes from a null source. This should be a noop. */ @Test public void testAppendNullAttributes() { viewNode.appendAttributes(null); assertEquals("Wrong number of attributes", 0, viewNode .getAttributeCount()); } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/AbstractXPathTest.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/AbstractXPa100644 11737 12232154104 33450 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import java.util.ArrayList; import java.util.List; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.jxpath.ri.model.NodeIterator; import org.junit.After; import org.junit.Before; /** * A base class for testing classes of the XPath package. This base class * creates a hierarchy of nodes in its setUp() method that can be used for test * cases. * * @author Commons * Configuration team * @version $Id: AbstractXPathTest.java 1226104 2011-12-31 15:37:16Z oheger $ */ public abstract class AbstractXPathTest { /** Constant for the name of the counter attribute. */ protected static final String ATTR_NAME = "counter"; /** Constant for the name of the first child. */ protected static final String CHILD_NAME1 = "subNode"; /** Constant for the name of the second child. */ protected static final String CHILD_NAME2 = "childNode"; /** Constant for the number of sub nodes. */ protected static final int CHILD_COUNT = 5; /** Constant for the number of levels in the hierarchy. */ protected static final int LEVEL_COUNT = 3; /** Stores the root node of the hierarchy. */ protected ConfigurationNode root; @Before public void setUp() throws Exception { root = constructHierarchy(LEVEL_COUNT); } /** * Clears the test environment. */ @After public void tearDown() throws Exception { root = null; } /** * Builds up a hierarchy of nodes. Each node has {@code CHILD_COUNT} * child nodes having the names {@code CHILD_NAME1} or * {@code CHILD_NAME2}. Their values are named like their parent * node with an additional index. Each node has an attribute with a counter * value. * * @param levels the number of levels in the hierarchy * @return the root node of the hierarchy */ protected ConfigurationNode constructHierarchy(int levels) { ConfigurationNode result = new DefaultConfigurationNode(); createLevel(result, levels); return result; } /** * Determines the number of elements contained in the given iterator. * * @param iterator the iterator * @return the number of elements in this iteration */ protected int iteratorSize(NodeIterator iterator) { int cnt = 0; boolean ok; do { ok = iterator.setPosition(cnt + 1); if (ok) { cnt++; } } while (ok); return cnt; } /** * Returns a list with all configuration nodes contained in the specified * iteration. It is assumed that the iteration contains only elements of * this type. * * @param iterator the iterator * @return a list with configuration nodes obtained from the iterator */ protected List iterationElements(NodeIterator iterator) { List result = new ArrayList(); for (int pos = 1; iterator.setPosition(pos); pos++) { result.add((ConfigurationNode) iterator.getNodePointer().getNode()); } return result; } /** * Recursive helper method for creating a level of the node hierarchy. * * @param parent the parent node * @param level the level counter */ private void createLevel(ConfigurationNode parent, int level) { if (level >= 0) { String prefix = (parent.getValue() == null) ? "" : parent .getValue() + "."; for (int i = 1; i <= CHILD_COUNT; i++) { ConfigurationNode child = new DefaultConfigurationNode( (i % 2 == 0) ? CHILD_NAME1 : CHILD_NAME2, prefix + i); parent.addChild(child); child.addAttribute(new DefaultConfigurationNode(ATTR_NAME, String.valueOf(i))); createLevel(child, level - 1); } } } } ././@LongLink100644 0 0 202 12232154257 10250 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestConfigurationIteratorAttributes.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestConfigu100644 7370 12232154104 33504 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import static org.junit.Assert.assertEquals; import java.util.List; import java.util.Locale; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.jxpath.ri.QName; import org.apache.commons.jxpath.ri.model.NodePointer; import org.junit.Before; import org.junit.Test; /** * Test class for ConfigurationIteratorAttributes. * * @author Commons * Configuration team * @version $Id: TestConfigurationIteratorAttributes.java 1226104 2011-12-31 15:37:16Z oheger $ */ public class TestConfigurationIteratorAttributes extends AbstractXPathTest { /** Constant for the name of another test attribute.*/ private static final String TEST_ATTR = "test"; /** Stores the node pointer of the test node.*/ NodePointer pointer; @Override @Before public void setUp() throws Exception { super.setUp(); // Adds further attributes to the test node ConfigurationNode testNode = root.getChild(1); testNode.addAttribute(new DefaultConfigurationNode(TEST_ATTR, "yes")); pointer = new ConfigurationNodePointer(testNode, Locale.getDefault()); } /** * Tests to iterate over all attributes. */ @Test public void testIterateAllAttributes() { ConfigurationNodeIteratorAttribute it = new ConfigurationNodeIteratorAttribute(pointer, new QName(null, "*")); assertEquals("Wrong number of attributes", 2, iteratorSize(it)); List attrs = iterationElements(it); assertEquals("Wrong first attribute", ATTR_NAME, attrs.get(0).getName()); assertEquals("Wrong first attribute", TEST_ATTR, attrs.get(1).getName()); } /** * Tests to iterate over attributes with a specific name. */ @Test public void testIterateSpecificAttribute() { ConfigurationNodeIteratorAttribute it = new ConfigurationNodeIteratorAttribute(pointer, new QName(null, TEST_ATTR)); assertEquals("Wrong number of attributes", 1, iteratorSize(it)); assertEquals("Wrong attribute", TEST_ATTR, iterationElements(it).get(0).getName()); } /** * Tests to iterate over non existing attributes. */ @Test public void testIterateUnknownAttribute() { ConfigurationNodeIteratorAttribute it = new ConfigurationNodeIteratorAttribute(pointer, new QName(null, "unknown")); assertEquals("Found attributes", 0, iteratorSize(it)); } /** * Tests iteration when a namespace is specified. This is not supported, so * the iteration should be empty. */ @Test public void testIterateNamespace() { ConfigurationNodeIteratorAttribute it = new ConfigurationNodeIteratorAttribute(pointer, new QName("test", "*")); assertEquals("Found attributes", 0, iteratorSize(it)); } } ././@LongLink100644 0 0 204 12232154257 10252 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestConfigurationNodeIteratorChildren.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestConfigu100644 22176 12232154104 33525 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.List; import java.util.Locale; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.jxpath.ri.Compiler; import org.apache.commons.jxpath.ri.QName; import org.apache.commons.jxpath.ri.compiler.NodeNameTest; import org.apache.commons.jxpath.ri.compiler.NodeTest; import org.apache.commons.jxpath.ri.compiler.NodeTypeTest; import org.apache.commons.jxpath.ri.compiler.ProcessingInstructionTest; import org.apache.commons.jxpath.ri.model.NodeIterator; import org.apache.commons.jxpath.ri.model.NodePointer; import org.junit.Before; import org.junit.Test; /** * Test class for ConfigurationNodeIteratorChildren. * * @author Commons * Configuration team * @version $Id: TestConfigurationNodeIteratorChildren.java 1226104 2011-12-31 15:37:16Z oheger $ */ public class TestConfigurationNodeIteratorChildren extends AbstractXPathTest { /** Stores the node pointer to the root node. */ NodePointer rootPointer; @Override @Before public void setUp() throws Exception { super.setUp(); rootPointer = new ConfigurationNodePointer(root, Locale.getDefault()); } /** * Tests to iterate over all children of the root node. */ @Test public void testIterateAllChildren() { ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, null, false, null); assertEquals("Wrong number of elements", CHILD_COUNT, iteratorSize(it)); checkValues(it, new int[] { 1, 2, 3, 4, 5 }); } /** * Tests a reverse iteration. */ @Test public void testIterateReverse() { ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, null, true, null); assertEquals("Wrong number of elements", CHILD_COUNT, iteratorSize(it)); checkValues(it, new int[] { 5, 4, 3, 2, 1 }); } /** * Tests using a node test with a wildcard name. */ @Test public void testIterateWithWildcardTest() { NodeNameTest test = new NodeNameTest(new QName(null, "*")); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, test, false, null); assertEquals("Wrong number of elements", CHILD_COUNT, iteratorSize(it)); } /** * Tests using a node test that defines a namespace prefix. Because * namespaces are not supported, no elements should be in the iteration. */ @Test public void testIterateWithPrefixTest() { NodeNameTest test = new NodeNameTest(new QName("prefix", "*")); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, test, false, null); assertNull("Undefined node pointer not returned", it.getNodePointer()); assertEquals("Prefix was not evaluated", 0, iteratorSize(it)); } /** * Tests using a node test that selects a certain sub node name. */ @Test public void testIterateWithNameTest() { NodeNameTest test = new NodeNameTest(new QName(null, CHILD_NAME2)); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, test, false, null); assertTrue("No children found", iteratorSize(it) > 0); for (ConfigurationNode nd : iterationElements(it)) { assertEquals("Wrong child element", CHILD_NAME2, nd.getName()); } } /** * Tests using a not supported test class. This should yield an empty * iteration. */ @Test public void testIterateWithUnknownTest() { NodeTest test = new ProcessingInstructionTest("test"); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, test, false, null); assertEquals("Unknown test was not evaluated", 0, iteratorSize(it)); } /** * Tests using a type test for nodes. This should return all nodes. */ @Test public void testIterateWithNodeType() { NodeTypeTest test = new NodeTypeTest(Compiler.NODE_TYPE_NODE); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, test, false, null); assertEquals("Node type not evaluated", CHILD_COUNT, iteratorSize(it)); } /** * Tests using a type test for a non supported type. This should return an * empty iteration. */ @Test public void testIterateWithUnknownType() { NodeTypeTest test = new NodeTypeTest(Compiler.NODE_TYPE_COMMENT); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, test, false, null); assertEquals("Unknown node type not evaluated", 0, iteratorSize(it)); } /** * Tests defining a start node for the iteration. */ @Test public void testIterateStartsWith() { NodePointer childPointer = new ConfigurationNodePointer(rootPointer, root.getChild(2)); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, null, false, childPointer); assertEquals("Wrong start position", 0, it.getPosition()); List nodes = iterationElements(it); assertEquals("Wrong size of iteration", CHILD_COUNT - 3, nodes.size()); int index = 4; for (Iterator it2 = nodes.iterator(); it2.hasNext(); index++) { ConfigurationNode node = it2.next(); assertEquals("Wrong node value", String.valueOf(index), node .getValue()); } } /** * Tests defining a start node for a reverse iteration. */ @Test public void testIterateStartsWithReverse() { NodePointer childPointer = new ConfigurationNodePointer(rootPointer, root.getChild(3)); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, null, true, childPointer); int value = 3; for (int index = 1; it.setPosition(index); index++, value--) { ConfigurationNode node = (ConfigurationNode) it.getNodePointer() .getNode(); assertEquals("Incorrect value at index " + index, String .valueOf(value), node.getValue()); } assertEquals("Iteration ended not at end node", 0, value); } /** * Tests iteration with an invalid start node. This should cause the * iteration to start at the first position. */ @Test public void testIterateStartsWithInvalid() { NodePointer childPointer = new ConfigurationNodePointer(rootPointer, new DefaultConfigurationNode("newNode")); ConfigurationNodeIteratorChildren it = new ConfigurationNodeIteratorChildren( rootPointer, null, false, childPointer); assertEquals("Wrong size of iteration", CHILD_COUNT, iteratorSize(it)); it.setPosition(1); ConfigurationNode node = (ConfigurationNode) it.getNodePointer() .getNode(); assertEquals("Wrong start node", "1", node.getValue()); } /** * Helper method for checking the values of the nodes returned by an * iterator. Because the values indicate the order of the child nodes with * this test it can be checked whether the nodes were returned in the * correct order. * * @param iterator the iterator * @param expectedIndices an array with the expected indices */ private void checkValues(NodeIterator iterator, int[] expectedIndices) { List nodes = iterationElements(iterator); for (int i = 0; i < expectedIndices.length; i++) { ConfigurationNode child = nodes.get(i); assertTrue("Wrong index value for child " + i, child.getValue() .toString().endsWith(String.valueOf(expectedIndices[i]))); } } } ././@LongLink100644 0 0 173 12232154257 10257 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointer.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestConfigu100644 15537 12232154104 33530 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Locale; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.jxpath.ri.QName; import org.apache.commons.jxpath.ri.model.NodeIterator; import org.apache.commons.jxpath.ri.model.NodePointer; import org.junit.Before; import org.junit.Test; /** * Test class for ConfigurationNodePointer. * * @author Commons * Configuration team * @version $Id: TestConfigurationNodePointer.java 1226104 2011-12-31 15:37:16Z oheger $ */ public class TestConfigurationNodePointer extends AbstractXPathTest { /** Stores the node pointer to be tested. */ NodePointer pointer; @Override @Before public void setUp() throws Exception { super.setUp(); pointer = new ConfigurationNodePointer(root, Locale.getDefault()); } /** * Tests comparing child node pointers for child nodes. */ @Test public void testCompareChildNodePointersChildren() { NodePointer p1 = new ConfigurationNodePointer(pointer, root.getChild(1)); NodePointer p2 = new ConfigurationNodePointer(pointer, root.getChild(3)); assertEquals("Incorrect order", -1, pointer.compareChildNodePointers( p1, p2)); assertEquals("Incorrect symmetric order", 1, pointer .compareChildNodePointers(p2, p1)); } /** * Tests comparing child node pointers for attribute nodes. */ @Test public void testCompareChildNodePointersAttributes() { root.addAttribute(new DefaultConfigurationNode("attr1", "test1")); root.addAttribute(new DefaultConfigurationNode("attr2", "test2")); NodePointer p1 = new ConfigurationNodePointer(pointer, root .getAttribute(0)); NodePointer p2 = new ConfigurationNodePointer(pointer, root .getAttribute(1)); assertEquals("Incorrect order", -1, pointer.compareChildNodePointers( p1, p2)); assertEquals("Incorrect symmetric order", 1, pointer .compareChildNodePointers(p2, p1)); } /** * tests comparing child node pointers for both child and attribute nodes. */ @Test public void testCompareChildNodePointersChildAndAttribute() { root.addAttribute(new DefaultConfigurationNode("attr1", "test1")); NodePointer p1 = new ConfigurationNodePointer(pointer, root.getChild(2)); NodePointer p2 = new ConfigurationNodePointer(pointer, root .getAttribute(0)); assertEquals("Incorrect order for attributes", 1, pointer .compareChildNodePointers(p1, p2)); assertEquals("Incorrect symmetric order for attributes", -1, pointer .compareChildNodePointers(p2, p1)); } /** * Tests comparing child node pointers for child nodes that do not belong to * the parent node. */ @Test public void testCompareChildNodePointersInvalidChildren() { ConfigurationNode node = root.getChild(1); NodePointer p1 = new ConfigurationNodePointer(pointer, node.getChild(1)); NodePointer p2 = new ConfigurationNodePointer(pointer, node.getChild(3)); assertEquals("Non child nodes could be sorted", 0, pointer .compareChildNodePointers(p1, p2)); assertEquals("Non child nodes could be sorted symmetrically", 0, pointer.compareChildNodePointers(p2, p1)); } /** * Tests the attribute flag. */ @Test public void testIsAttribute() { ConfigurationNode node = new DefaultConfigurationNode("test", "testval"); NodePointer p = new ConfigurationNodePointer(pointer, node); assertFalse("Node is an attribute", p.isAttribute()); node.setAttribute(true); assertTrue("Node is no attribute", p.isAttribute()); } /** * Tests if leaves in the tree are correctly detected. */ @Test public void testIsLeave() { assertFalse("Root node is leaf", pointer.isLeaf()); NodePointer p = pointer; while (!p.isLeaf()) { ConfigurationNode node = (ConfigurationNode) p.getNode(); assertTrue("Node has no children", node.getChildrenCount() > 0); p = new ConfigurationNodePointer(p, node.getChild(0)); } assertTrue("Node has children", ((ConfigurationNode) p.getNode()) .getChildrenCount() == 0); } /** * Tests the iterators returned by the node pointer. */ @Test public void testIterators() { checkIterators(pointer); } /** * Recursive helper method for testing the returned iterators. * * @param p the node pointer to test */ private void checkIterators(NodePointer p) { ConfigurationNode node = (ConfigurationNode) p.getNode(); NodeIterator it = p.childIterator(null, false, null); assertEquals("Iterator count differs from children count", node .getChildrenCount(), iteratorSize(it)); for (int index = 1; it.setPosition(index); index++) { NodePointer pchild = it.getNodePointer(); assertEquals("Wrong child", node.getChild(index - 1), pchild .getNode()); checkIterators(pchild); } it = p.attributeIterator(new QName(null, "*")); assertEquals("Iterator count differs from attribute count", node .getAttributeCount(), iteratorSize(it)); for (int index = 1; it.setPosition(index); index++) { NodePointer pattr = it.getNodePointer(); assertTrue("Node pointer is no attribute", pattr.isAttribute()); assertEquals("Wrong attribute", node.getAttribute(index - 1), pattr .getNode()); checkIterators(pattr); } } } ././@LongLink100644 0 0 202 12232154257 10250 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestConfigurationNodePointerFactory.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestConfigu100644 14662 12232154104 33526 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.util.Iterator; import java.util.List; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl; import org.junit.Before; import org.junit.Test; /** * Test class for ConfigurationNodePointerFactory. This class does not directly * call the factory's methods, but rather checks if it can be installed in a * {@code JXPathContext} and if XPath expressions can be evaluated. * * @author Commons * Configuration team * @version $Id: TestConfigurationNodePointerFactory.java 1226104 2011-12-31 15:37:16Z oheger $ */ public class TestConfigurationNodePointerFactory extends AbstractXPathTest { /** Stores the JXPathContext used for testing. */ JXPathContext context; @Override @Before public void setUp() throws Exception { super.setUp(); JXPathContextReferenceImpl .addNodePointerFactory(new ConfigurationNodePointerFactory()); context = JXPathContext.newContext(root); context.setLenient(true); } /** * Tests simple XPath expressions. */ @Test public void testSimpleXPath() { List nodes = context.selectNodes(CHILD_NAME1); assertEquals("Incorrect number of results", 2, nodes.size()); for (Iterator it = nodes.iterator(); it.hasNext();) { ConfigurationNode node = (ConfigurationNode) it.next(); assertEquals("Incorrect node name", CHILD_NAME1, node.getName()); assertEquals("Incorrect parent node", root, node.getParentNode()); } nodes = context.selectNodes("/" + CHILD_NAME1); assertEquals("Incorrect number of results", 2, nodes.size()); nodes = context.selectNodes(CHILD_NAME2 + "/" + CHILD_NAME1 + "/" + CHILD_NAME2); assertEquals("Incorrect number of results", 18, nodes.size()); } /** * Tests using indices to specify elements. */ @Test public void testIndices() { assertEquals("Incorrect value", "1.2.3", context.getValue("/" + CHILD_NAME2 + "[1]/" + CHILD_NAME1 + "[1]/" + CHILD_NAME2 + "[2]")); assertEquals("Incorrect value of last node", String .valueOf(CHILD_COUNT), context.getValue(CHILD_NAME2 + "[last()]")); List nodes = context.selectNodes("/" + CHILD_NAME1 + "[1]/*"); assertEquals("Wrong number of children", CHILD_COUNT, nodes.size()); int index = 1; for (Iterator it = nodes.iterator(); it.hasNext(); index++) { ConfigurationNode node = (ConfigurationNode) it.next(); assertEquals("Wrong node value for child " + index, "2." + index, node.getValue()); } } /** * Tests accessing attributes. */ @Test public void testAttributes() { root.addAttribute(new DefaultConfigurationNode("testAttr", "true")); assertEquals("Did not find attribute of root node", "true", context .getValue("@testAttr")); assertEquals("Incorrect attribute value", "1", context.getValue("/" + CHILD_NAME2 + "[1]/@" + ATTR_NAME)); assertTrue("Found elements with name attribute", context.selectNodes( "//" + CHILD_NAME2 + "[@name]").isEmpty()); ConfigurationNode node = root.getChild(2).getChild( 1).getChildren(CHILD_NAME2).get(1); node.addAttribute(new DefaultConfigurationNode("name", "testValue")); List nodes = context.selectNodes("//" + CHILD_NAME2 + "[@name]"); assertEquals("Name attribute not found", 1, nodes.size()); assertEquals("Wrong node returned", node, nodes.get(0)); } /** * Tests accessing a node's text. */ @Test public void testText() { List nodes = context.selectNodes("//" + CHILD_NAME2 + "[text()='1.1.1']"); assertEquals("Incorrect number of result nodes", 1, nodes.size()); } /** * Tests accessing the parent axis. */ @Test public void testParentAxis() { List nodes = context.selectNodes("/" + CHILD_NAME2 + "/parent::*"); assertEquals("Wrong number of parent nodes", 1, nodes.size()); } /** * Tests accessing the following sibling axis. */ @Test public void testFollowingSiblingAxis() { List nodes = context.selectNodes("/" + CHILD_NAME1 + "[2]/following-sibling::*"); assertEquals("Wrong number of following siblings", 1, nodes.size()); ConfigurationNode node = (ConfigurationNode) nodes.get(0); assertEquals("Wrong node type", CHILD_NAME2, node.getName()); assertEquals("Wrong index", String.valueOf(CHILD_COUNT), node .getValue()); } /** * Tests accessing the preceding sibling axis. */ @Test public void testPrecedingSiblingAxis() { List nodes = context.selectNodes("/" + CHILD_NAME1 + "[2]/preceding-sibling::*"); assertEquals("Wrong number of preceding siblings", 3, nodes.size()); for (int index = 0, value = 3; index < nodes.size(); index++, value--) { assertEquals("Wrong node index", String.valueOf(value), ((ConfigurationNode) nodes.get(index)).getValue()); } } } ././@LongLink100644 0 0 170 12232154257 10254 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestXPathExpressionEngine.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestXPathEx100644 32423 12232154104 33450 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.configuration.tree.ConfigurationNode; import org.apache.commons.configuration.tree.DefaultConfigurationNode; import org.apache.commons.configuration.tree.NodeAddData; import org.apache.commons.jxpath.JXPathContext; import org.apache.commons.jxpath.ri.JXPathContextReferenceImpl; import org.apache.commons.jxpath.ri.model.NodePointerFactory; import org.junit.Before; import org.junit.Test; /** * Test class for XPathExpressionEngine. * * @author Commons * Configuration team * @version $Id: TestXPathExpressionEngine.java 1226111 2011-12-31 15:44:50Z oheger $ */ public class TestXPathExpressionEngine { /** Constant for the test root node. */ static final ConfigurationNode ROOT = new DefaultConfigurationNode( "testRoot"); /** Constant for the valid test key. */ static final String TEST_KEY = "TESTKEY"; /** The expression engine to be tested. */ XPathExpressionEngine engine; @Before public void setUp() throws Exception { engine = new MockJXPathContextExpressionEngine(); } /** * Tests the query() method with a normal expression. */ @Test public void testQueryExpression() { List nodes = engine.query(ROOT, TEST_KEY); assertEquals("Incorrect number of results", 1, nodes.size()); assertSame("Wrong result node", ROOT, nodes.get(0)); checkSelectCalls(1); } /** * Tests a query that has no results. This should return an empty list. */ @Test public void testQueryWithoutResult() { List nodes = engine.query(ROOT, "a non existing key"); assertTrue("Result list is not empty", nodes.isEmpty()); checkSelectCalls(1); } /** * Tests a query with an empty key. This should directly return the root * node without invoking the JXPathContext. */ @Test public void testQueryWithEmptyKey() { checkEmptyKey(""); } /** * Tests a query with a null key. Same as an empty key. */ @Test public void testQueryWithNullKey() { checkEmptyKey(null); } /** * Helper method for testing undefined keys. * * @param key the key */ private void checkEmptyKey(String key) { List nodes = engine.query(ROOT, key); assertEquals("Incorrect number of results", 1, nodes.size()); assertSame("Wrong result node", ROOT, nodes.get(0)); checkSelectCalls(0); } /** * Tests if the used JXPathContext is correctly initialized. */ @Test public void testCreateContext() { JXPathContext ctx = new XPathExpressionEngine().createContext(ROOT, TEST_KEY); assertNotNull("Context is null", ctx); assertTrue("Lenient mode is not set", ctx.isLenient()); assertSame("Incorrect context bean set", ROOT, ctx.getContextBean()); NodePointerFactory[] factories = JXPathContextReferenceImpl .getNodePointerFactories(); boolean found = false; for (int i = 0; i < factories.length; i++) { if (factories[i] instanceof ConfigurationNodePointerFactory) { found = true; } } assertTrue("No configuration pointer factory found", found); } /** * Tests a normal call of nodeKey(). */ @Test public void testNodeKeyNormal() { assertEquals("Wrong node key", "parent/child", engine.nodeKey( new DefaultConfigurationNode("child"), "parent")); } /** * Tests nodeKey() for an attribute node. */ @Test public void testNodeKeyAttribute() { ConfigurationNode node = new DefaultConfigurationNode("attr"); node.setAttribute(true); assertEquals("Wrong attribute key", "node/@attr", engine.nodeKey(node, "node")); } /** * Tests nodeKey() for the root node. */ @Test public void testNodeKeyForRootNode() { assertEquals("Wrong key for root node", "", engine.nodeKey(ROOT, null)); assertEquals("Null name not detected", "test", engine.nodeKey( new DefaultConfigurationNode(), "test")); } /** * Tests node key() for direct children of the root node. */ @Test public void testNodeKeyForRootChild() { ConfigurationNode node = new DefaultConfigurationNode("child"); assertEquals("Wrong key for root child node", "child", engine.nodeKey( node, "")); node.setAttribute(true); assertEquals("Wrong key for root attribute", "@child", engine.nodeKey( node, "")); } /** * Tests adding a single child node. */ @Test public void testPrepareAddNode() { NodeAddData data = engine.prepareAdd(ROOT, TEST_KEY + " newNode"); checkAddPath(data, new String[] { "newNode" }, false); checkSelectCalls(1); } /** * Tests adding a new attribute node. */ @Test public void testPrepareAddAttribute() { NodeAddData data = engine.prepareAdd(ROOT, TEST_KEY + "\t@newAttr"); checkAddPath(data, new String[] { "newAttr" }, true); checkSelectCalls(1); } /** * Tests adding a complete path. */ @Test public void testPrepareAddPath() { NodeAddData data = engine.prepareAdd(ROOT, TEST_KEY + " \t a/full/path/node"); checkAddPath(data, new String[] { "a", "full", "path", "node" }, false); checkSelectCalls(1); } /** * Tests adding a complete path whose final node is an attribute. */ @Test public void testPrepareAddAttributePath() { NodeAddData data = engine.prepareAdd(ROOT, TEST_KEY + " a/full/path@attr"); checkAddPath(data, new String[] { "a", "full", "path", "attr" }, true); checkSelectCalls(1); } /** * Tests adding a new node to the root. */ @Test public void testPrepareAddRootChild() { NodeAddData data = engine.prepareAdd(ROOT, " newNode"); checkAddPath(data, new String[] { "newNode" }, false); checkSelectCalls(0); } /** * Tests adding a new attribute to the root. */ @Test public void testPrepareAddRootAttribute() { NodeAddData data = engine.prepareAdd(ROOT, " @attr"); checkAddPath(data, new String[] { "attr" }, true); checkSelectCalls(0); } /** * Tests an add operation with a query that does not return a single node. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddInvalidParent() { engine.prepareAdd(ROOT, "invalidKey newNode"); } /** * Tests an add operation with an empty path for the new node. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddEmptyPath() { engine.prepareAdd(ROOT, TEST_KEY + " "); } /** * Tests an add operation where the key is null. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddNullKey() { engine.prepareAdd(ROOT, null); } /** * Tests an add operation where the key is null. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddEmptyKey() { engine.prepareAdd(ROOT, ""); } /** * Tests an add operation with an invalid path. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddInvalidPath() { engine.prepareAdd(ROOT, TEST_KEY + " an/invalid//path"); } /** * Tests an add operation with an invalid path: the path contains an * attribute in the middle part. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddInvalidAttributePath() { engine.prepareAdd(ROOT, TEST_KEY + " a/path/with@an/attribute"); } /** * Tests an add operation with an invalid path: the path contains an * attribute after a slash. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddInvalidAttributePath2() { engine.prepareAdd(ROOT, TEST_KEY + " a/path/with/@attribute"); } /** * Tests an add operation with an invalid path that starts with a slash. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddInvalidPathWithSlash() { engine.prepareAdd(ROOT, TEST_KEY + " /a/path/node"); } /** * Tests an add operation with an invalid path that contains multiple * attribute components. */ @Test(expected = IllegalArgumentException.class) public void testPrepareAddInvalidPathMultipleAttributes() { engine.prepareAdd(ROOT, TEST_KEY + " an@attribute@path"); } /** * Helper method for testing the path nodes in the given add data object. * * @param data the data object to check * @param expected an array with the expected path elements * @param attr a flag if the new node is an attribute */ private void checkAddPath(NodeAddData data, String[] expected, boolean attr) { assertSame("Wrong parent node", ROOT, data.getParent()); List path = data.getPathNodes(); assertEquals("Incorrect number of path nodes", expected.length - 1, path.size()); Iterator it = path.iterator(); for (int idx = 0; idx < expected.length - 1; idx++) { assertEquals("Wrong node at position " + idx, expected[idx], it .next()); } assertEquals("Wrong name of new node", expected[expected.length - 1], data.getNewNodeName()); assertEquals("Incorrect attribute flag", attr, data.isAttribute()); } /** * Checks if the JXPath context's selectNodes() method was called as often * as expected. * * @param expected the number of expected calls */ protected void checkSelectCalls(int expected) { MockJXPathContext ctx = ((MockJXPathContextExpressionEngine) engine).getContext(); int calls = (ctx == null) ? 0 : ctx.selectInvocations; assertEquals("Incorrect number of select calls", expected, calls); } /** * A mock implementation of the JXPathContext class. This implementation * will overwrite the selectNodes() method that is used by * XPathExpressionEngine to count the invocations of this * method. */ static class MockJXPathContext extends JXPathContextReferenceImpl { int selectInvocations; public MockJXPathContext(Object bean) { super(null, bean); } /** * Dummy implementation of this method. If the passed in string is the * test key, the root node will be returned in the list. Otherwise the * return value is null. */ @Override public List selectNodes(String xpath) { selectInvocations++; if (TEST_KEY.equals(xpath)) { List result = new ArrayList(1); result.add(ROOT); return result; } else { return null; } } } /** * A special implementation of XPathExpressionEngine that overrides * createContext() to return a mock context object. */ static class MockJXPathContextExpressionEngine extends XPathExpressionEngine { /** Stores the context instance. */ private MockJXPathContext context; @Override protected JXPathContext createContext(ConfigurationNode root, String key) { context = new MockJXPathContext(root); return context; } /** * Returns the context created by the last newContext() call. * * @return the current context */ public MockJXPathContext getContext() { return context; } } } ././@LongLink100644 0 0 200 12232154257 10246 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestXPathExpressionEngineInConfig.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/TestXPathEx100644 7771 12232154104 33440 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.tree.xpath; import static org.junit.Assert.assertEquals; import org.apache.commons.configuration.XMLConfiguration; import org.junit.Before; import org.junit.Test; /** * A test class for XPathExpressionEngine that tests the engine integrated into * a hierarchical configuration. * * @author Commons * Configuration team * @version $Id: TestXPathExpressionEngineInConfig.java 1226113 2011-12-31 15:46:53Z oheger $ */ public class TestXPathExpressionEngineInConfig { /** Constant for a test key. */ private static final String KEY = "test/expression/xpath"; /** Constant for a value for test properties. */ private static final String VALUE = "success"; /** The test configuration. */ private XMLConfiguration config; @Before public void setUp() throws Exception { config = new XMLConfiguration(); config.setExpressionEngine(new XPathExpressionEngine()); } /** * Tests whether an already existing property can be changed using * setProperty(). */ @Test public void testSetPropertyExisting() { config.addProperty(" " + KEY, "failure"); config.setProperty(KEY, VALUE); assertEquals("Value not changed", VALUE, config.getString(KEY)); } /** * Tests setProperty() if the specified path partly exists. */ @Test public void testSetPropertyPartlyExisting() { final String testKey = KEY + "/sub"; config.addProperty(" " + KEY, "test"); config.setProperty(testKey, VALUE); assertEquals("Value not set", VALUE, config.getString(testKey)); } /** * Tests whether setProperty() can be used to add a new attribute. */ @Test public void testSetPropertyNewAttribute() { final String keyAttr = KEY + "/@attr"; config.addProperty(" " + KEY, "test"); config.setProperty(keyAttr, VALUE); assertEquals("Value not set", VALUE, config.getString(keyAttr)); } /** * Tests whether setProperty() can be used to create a completely new key. */ @Test public void testSetPropertyNewKey() { config.setProperty(KEY, VALUE); assertEquals("Value not set", VALUE, config.getString(KEY)); } /** * Tests whether addProperty() can be used to create more complex * hierarchical structures. */ @Test public void testAddPropertyComplexStructures() { config.addProperty("tables/table/name", "tasks"); config.addProperty("tables/table[last()]/@type", "system"); config.addProperty("tables/table[last()]/fields/field/name", "taskid"); config.addProperty("tables/table[last()]/fields/field[last()]/@type", "int"); config.addProperty("tables table/name", "documents"); assertEquals("Wrong table 1", "tasks", config.getString("tables/table[1]/name")); assertEquals("Wrong table 2", "documents", config.getString("tables/table[2]/name")); assertEquals("Wrong field type", "int", config.getString("tables/table[1]/fields/field[1]/@type")); } } ././@LongLink100644 0 0 157 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestAppletConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestAppletConfigur100644 10710 12232154103 33535 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import static org.junit.Assert.fail; import java.applet.Applet; import java.util.Properties; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.BaseConfiguration; import org.apache.commons.configuration.MapConfiguration; import org.apache.commons.configuration.TestAbstractConfiguration; import org.junit.Before; import org.junit.Test; /** * Test case for the {@link AppletConfiguration} class. * * @author Emmanuel Bourg * @version $Id: TestAppletConfiguration.java 1222465 2011-12-22 21:32:56Z oheger $ */ public class TestAppletConfiguration extends TestAbstractConfiguration { /** A flag whether tests with an applet can be run. */ boolean supportsApplet; /** * Initializes the tests. This implementation checks whether an applet can * be used. Some environments, which do not support a GUI, don't allow * creating an Applet instance. If we are in such an * environment, some tests need to behave differently or be completely * dropped. */ @Before public void setUp() throws Exception { try { new Applet(); supportsApplet = true; } catch (Exception ex) { // cannot use applets supportsApplet = false; } } @Override protected AbstractConfiguration getConfiguration() { final Properties parameters = new Properties(); parameters.setProperty("key1", "value1"); parameters.setProperty("key2", "value2"); parameters.setProperty("list", "value1, value2"); parameters.setProperty("listesc", "value1\\,value2"); if (supportsApplet) { Applet applet = new Applet() { /** * Serial version UID. */ private static final long serialVersionUID = 1L; @Override public String getParameter(String key) { return parameters.getProperty(key); } @Override public String[][] getParameterInfo() { return new String[][] { { "key1", "String", "" }, { "key2", "String", "" }, { "list", "String[]", "" }, { "listesc", "String", "" } }; } }; return new AppletConfiguration(applet); } else { return new MapConfiguration(parameters); } } @Override protected AbstractConfiguration getEmptyConfiguration() { if (supportsApplet) { return new AppletConfiguration(new Applet()); } else { return new BaseConfiguration(); } } @Override @Test public void testAddPropertyDirect() { if (supportsApplet) { try { super.testAddPropertyDirect(); fail("addPropertyDirect should throw an UnsupportedException"); } catch (UnsupportedOperationException e) { // ok } } } @Override @Test public void testClearProperty() { if (supportsApplet) { try { super.testClearProperty(); fail("testClearProperty should throw an UnsupportedException"); } catch (UnsupportedOperationException e) { // ok } } } } ././@LongLink100644 0 0 160 12232154257 10253 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestServletConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestServletConfigu100644 5106 12232154103 33535 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.http.HttpServlet; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.TestAbstractConfiguration; import org.junit.Test; import com.mockobjects.servlet.MockServletConfig; /** * Test case for the {@link ServletConfiguration} class. * * @author Emmanuel Bourg * @version $Id: TestServletConfiguration.java 1222465 2011-12-22 21:32:56Z oheger $ */ public class TestServletConfiguration extends TestAbstractConfiguration { @Override protected AbstractConfiguration getConfiguration() { final MockServletConfig config = new MockServletConfig(); config.setInitParameter("key1", "value1"); config.setInitParameter("key2", "value2"); config.setInitParameter("list", "value1, value2"); config.setInitParameter("listesc", "value1\\,value2"); Servlet servlet = new HttpServlet() { /** * Serial version UID. */ private static final long serialVersionUID = 1L; @Override public ServletConfig getServletConfig() { return config; } }; return new ServletConfiguration(servlet); } @Override protected AbstractConfiguration getEmptyConfiguration() { return new ServletConfiguration(new MockServletConfig()); } @Override @Test(expected = UnsupportedOperationException.class) public void testAddPropertyDirect() { super.testAddPropertyDirect(); } @Override @Test(expected = UnsupportedOperationException.class) public void testClearProperty() { super.testClearProperty(); } } ././@LongLink100644 0 0 167 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestServletContextConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestServletContext100644 7115 12232154103 33571 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import java.util.Enumeration; import java.util.Properties; import javax.servlet.Servlet; import javax.servlet.ServletConfig; import javax.servlet.ServletContext; import javax.servlet.http.HttpServlet; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.TestAbstractConfiguration; import org.junit.Test; import com.mockobjects.servlet.MockServletConfig; import com.mockobjects.servlet.MockServletContext; /** * Test case for the {@link ServletContextConfiguration} class. * * @author Emmanuel Bourg * @version $Id: TestServletContextConfiguration.java 1222465 2011-12-22 21:32:56Z oheger $ */ public class TestServletContextConfiguration extends TestAbstractConfiguration { @Override protected AbstractConfiguration getConfiguration() { final Properties parameters = new Properties(); parameters.setProperty("key1", "value1"); parameters.setProperty("key2", "value2"); parameters.setProperty("list", "value1, value2"); parameters.setProperty("listesc", "value1\\,value2"); // create a servlet context ServletContext context = new MockServletContext() { @Override public String getInitParameter(String key) { return parameters.getProperty(key); } @Override public Enumeration getInitParameterNames() { return parameters.keys(); } }; // create a servlet config final MockServletConfig config = new MockServletConfig(); config.setServletContext(context); // create a servlet Servlet servlet = new HttpServlet() { /** * Serial version UID. */ private static final long serialVersionUID = 1L; @Override public ServletConfig getServletConfig() { return config; } }; return new ServletContextConfiguration(servlet); } @Override protected AbstractConfiguration getEmptyConfiguration() { // create a servlet context ServletContext context = new MockServletContext() { @Override public Enumeration getInitParameterNames() { return new Properties().keys(); } }; return new ServletContextConfiguration(context); } @Override @Test(expected = UnsupportedOperationException.class) public void testAddPropertyDirect() { super.testAddPropertyDirect(); } @Override @Test(expected = UnsupportedOperationException.class) public void testClearProperty() { super.testClearProperty(); } } ././@LongLink100644 0 0 166 12232154257 10261 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestServletFilterConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestServletFilterC100644 5646 12232154103 33504 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import java.util.Enumeration; import java.util.Properties; import javax.servlet.FilterConfig; import javax.servlet.ServletContext; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.TestAbstractConfiguration; import org.junit.Test; /** * Test case for the {@link ServletFilterConfiguration} class. * * @author Emmanuel Bourg * @version $Id: TestServletFilterConfiguration.java 1222465 2011-12-22 21:32:56Z oheger $ */ public class TestServletFilterConfiguration extends TestAbstractConfiguration { @Override protected AbstractConfiguration getConfiguration() { MockFilterConfig config = new MockFilterConfig(); config.setInitParameter("key1", "value1"); config.setInitParameter("key2", "value2"); config.setInitParameter("list", "value1, value2"); config.setInitParameter("listesc", "value1\\,value2"); return new ServletFilterConfiguration(config); } @Override protected AbstractConfiguration getEmptyConfiguration() { return new ServletFilterConfiguration(new MockFilterConfig()); } private class MockFilterConfig implements FilterConfig { private Properties parameters = new Properties(); public String getFilterName() { return null; } public ServletContext getServletContext() { return null; } public String getInitParameter(String key) { return parameters.getProperty(key); } public Enumeration getInitParameterNames() { return parameters.keys(); } public void setInitParameter(String key, String value) { parameters.setProperty(key, value); } } @Override @Test(expected = UnsupportedOperationException.class) public void testAddPropertyDirect() { super.testAddPropertyDirect(); } @Override @Test(expected = UnsupportedOperationException.class) public void testClearProperty() { super.testClearProperty(); } } ././@LongLink100644 0 0 167 12232154257 10262 Lustar 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestServletRequestConfiguration.javacommons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/TestServletRequest100644 11127 12232154103 33613 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.configuration.web; import static org.junit.Assert.assertEquals; import java.util.HashMap; import java.util.List; import java.util.Map; import javax.servlet.ServletRequest; import org.apache.commons.configuration.AbstractConfiguration; import org.apache.commons.configuration.BaseConfiguration; import org.apache.commons.configuration.Configuration; import org.apache.commons.configuration.ConfigurationMap; import org.apache.commons.configuration.TestAbstractConfiguration; import org.junit.Test; import com.mockobjects.servlet.MockHttpServletRequest; /** * Test case for the {@link ServletRequestConfiguration} class. * * @author Emmanuel Bourg * @version $Id: TestServletRequestConfiguration.java 1222465 2011-12-22 21:32:56Z oheger $ */ public class TestServletRequestConfiguration extends TestAbstractConfiguration { @Override protected AbstractConfiguration getConfiguration() { final Configuration configuration = new BaseConfiguration(); ((BaseConfiguration) configuration).setListDelimiter('\0'); configuration.setProperty("key1", "value1"); configuration.setProperty("key2", "value2"); configuration.addProperty("list", "value1"); configuration.addProperty("list", "value2"); configuration.addProperty("listesc", "value1\\,value2"); return createConfiguration(configuration); } @Override protected AbstractConfiguration getEmptyConfiguration() { ServletRequest request = new MockHttpServletRequest() { @Override public String getParameter(String key) { return null; } @Override public Map getParameterMap() { return new HashMap(); } }; return new ServletRequestConfiguration(request); } /** * Returns a new servlet request configuration that is backed by the passed * in configuration. * * @param base the configuration with the underlying values * @return the servlet request configuration */ private ServletRequestConfiguration createConfiguration(final Configuration base) { ServletRequest request = new MockHttpServletRequest() { @Override public String[] getParameterValues(String key) { return base.getStringArray(key); } @Override public Map getParameterMap() { return new ConfigurationMap(base); } }; return new ServletRequestConfiguration(request); } @Override @Test(expected = UnsupportedOperationException.class) public void testAddPropertyDirect() { super.testAddPropertyDirect(); } @Override @Test(expected = UnsupportedOperationException.class) public void testClearProperty() { super.testClearProperty(); } /** * Tests a list with elements that contain an escaped list delimiter. */ @Test public void testListWithEscapedElements() { String[] values = { "test1", "test2\\,test3", "test4\\,test5" }; String listKey = "test.list"; BaseConfiguration config = new BaseConfiguration(); config.setListDelimiter('\0'); config.addProperty(listKey, values); assertEquals("Wrong number of list elements", values.length, config.getList(listKey).size()); Configuration c = createConfiguration(config); List v = c.getList(listKey); assertEquals("Wrong number of elements in list", values.length, v.size()); for (int i = 0; i < values.length; i++) { assertEquals("Wrong value at index " + i, values[i].replaceAll("\\\\", ""), v.get(i)); } } } commons-configuration-1.10-src/src/test/resources/01/testMultiConfiguration_1001.xml100644 2563 12232154103 30126 0ustarhenningstaff 0 0 #808080 #000000
#008000
${colors.header}
15 OK,Cancel,Help My Channel more test 2 data
commons-configuration-1.10-src/src/test/resources/catalog.xml100644 2226 12232154103 24131 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/catalog2.xml100644 2320 12232154103 24206 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/config/deep/deepinclude.properties100644 1466 12232154103 30563 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. deepinclude=true commons-configuration-1.10-src/src/test/resources/config/deep/deeptest.properties100644 1523 12232154103 30111 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. include=deepinclude.properties deeptest=true commons-configuration-1.10-src/src/test/resources/config/deep/deeptestinvalid.properties100644 1602 12232154103 31456 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Tries to include a non existing file include=nonexisting.properties deeptestinvalid=true commons-configuration-1.10-src/src/test/resources/config/deep/test.properties100644 1466 12232154103 27261 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. somekey=somevaluecommons-configuration-1.10-src/src/test/resources/config/deep/testEqualDeep.properties100644 1663 12232154103 31046 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. property.a = a property.b = b property.c = 100 # # Value set twice property.a = aa clear.property = delete me existing.property = i exist commons-configuration-1.10-src/src/test/resources/config/deep/testFileFromClasspath.xml100644 2006 12232154103 31143 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/config/test.properties100644 1654 12232154103 26343 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. boolean=true overwrite=80 key=jndivalue key2=jndivalue2 jndi=only_jndi byte=10 double=10.25 float=20.25 integer=10 long=1000000 short=1commons-configuration-1.10-src/src/test/resources/configA.xml100644 1552 12232154103 24066 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/configB.xml100644 1526 12232154103 24070 0ustarhenningstaff 0 0 test commons-configuration-1.10-src/src/test/resources/dataset.xml100644 4260 12232154103 24144 0ustarhenningstaff 0 0 keyvalue key1 value1 key2 value2 keyMulti a;b;c
namekeyvalue test key1 value1 test key2 value2
idkeyvalue 1 key3 value1 2 key3 value2 3 key3 value3
commons-configuration-1.10-src/src/test/resources/include-interpol.properties100644 1507 12232154103 27371 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. include.interpol.loaded = true commons-configuration-1.10-src/src/test/resources/include.properties100644 1534 12232154103 25537 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. include.loaded = true packages = packageb, packagec commons-configuration-1.10-src/src/test/resources/jndi.properties100644 1647 12232154103 25045 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. java.naming.factory.initial=org.osjava.jndi.PropertiesFactory org.osjava.jndi.root=classpath://config org.osjava.jndi.delimiter=/ commons-configuration-1.10-src/src/test/resources/log4j-test.xml100644 2463 12232154103 24516 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/resolver.dtd100644 1530 12232154103 24330 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/sample.xml100644 2337 12232154103 24003 0ustarhenningstaff 0 0 555121211 John Doe 1975-05-15 Exempt 100000 commons-configuration-1.10-src/src/test/resources/sample.xsd100644 3327 12232154103 24001 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/sample_1001.xml100644 2130 12232154103 24433 0ustarhenningstaff 0 0 Jane Doe commons-configuration-1.10-src/src/test/resources/test.ini100644 1567 12232154103 23464 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. ; Test ini file to be included by a configuration definition [testini] loaded=yes commons-configuration-1.10-src/src/test/resources/test.plist100644 3123 12232154103 24026 0ustarhenningstaff 0 0 /* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ { simple-string = string1; quoted-string = "string2"; quoted-string2 = "this is a string"; "complex-string" = "this is a \"complex\" string {(=,;)}"; // This is a test single-line comment array = ( "value1", "value2", "value3" ); empty-array = (); nested-arrays = ( (a , b) , (c, d) ); dictionary-array = ( { foo = bar }, { key = value } ) dictionary = { foo1 = bar1; foo2 = bar2; } empty-dictionary = { }; nested-dictionaries = { foo = { bar = { "key" = "value"; } } } date = <*D2002-03-22 11:30:00 +0100>; data = <666F6f 20 626172>; empty-data = < >; } commons-configuration-1.10-src/src/test/resources/test.plist.xml100644 5367 12232154103 24641 0ustarhenningstaff 0 0 string value1 integer 12345678900 real -123.45E-1 boolean1 boolean2 date 2005-01-01T12:00:00Z date-gnustep 2002-03-22 11:30:00 +0100 data RHJhY28gRG9ybWllbnMgTnVucXVhbSBUaXRpbGxhbmR1cw== array value1 value2 value3 nested-array a b c d dictionary-array foo bar key value dictionary key1 value1 key2 value2 key3 value3 nested node1 node2 node3 value empty-dictionary commons-configuration-1.10-src/src/test/resources/test.properties100644 6035 12232154103 25074 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. configuration.loaded = true packages = packagea propertyInOrder = test.properties include = include.properties include.file = include-interpol.properties include = ${include.file} test.unescape = This \n string \t contains \" escaped \\ character\u0073 test.unescape.list-separator = This string contains \, an escaped list separator # # Other test properties # test.equals = value=one test.empty = test.mixed.array = a test.mixed.array = b, c, d test.multilines = This is a value spread out across several adjacent \ natural lines by escaping the line terminator with \ a backslash character. # # Test a property that uses a previous property # base = base base.reference = ${base}extra base.reference.array = ${base}extra base.reference.array = ${base}extra # # Non String Properties # test.boolean = true test.boolean.array = false test.boolean.array = true test.byte = 10 test.byte.array = 20 test.byte.array = 30 test.double = 10.25 test.double.array = 20.35 test.double.array = 30.45 test.float = 20.25 test.float.array = 30.35 test.float.array = 40.45 test.integer = 10 test.integer.array = 20 test.integer.array = 30 test.long = 1000000 test.long.array = 2000000 test.long.array = 3000000 test.short = 1 test.short.array = 2 test.short.array = 3 test.overwrite = 1 # # Test complex line ending escaping # test.path = C:\\path1\\ test.path = C:\\path2\\ test.path = C:\\path3\\\ complex\\test\\ # # Test for the comment lines # #comment = this is not a property but a comment line starting with '#' !comment = this is not a property but a comment line starting with '!' # # Tests for the key/value separators ('=', ':' or white space, escaped or not) # test.separator\=in.key = foo test.separator\:in.key = bar test.separator\ in.key = foo test.separator\ in.key = bar test.separator\ in.key = foo test.separator.equal = foo test.separator.colon : foo test.separator.tab foo test.separator.formfeed foo test.separator.whitespace foo test.separator.no.space=foo # Tests for backslash escaping in lists test.share1 = \\\\\\\\share1a, \\\\\\\\share1b test.share2 = \\\\share2a test.share2 = \\\\share2b test.share3 = \\\\\\\\share3a\\\\\\\\,\\\\\\\\share3b\\ # This is a foot comment commons-configuration-1.10-src/src/test/resources/test.properties.xml100644 2066 12232154103 25673 0ustarhenningstaff 0 0 Description of the property list value1 value2 value3 commons-configuration-1.10-src/src/test/resources/test.xml100644 6472 12232154103 23505 0ustarhenningstaff 0 0 value I'm complex! value ]]> 1<2 This is really complex structure And even longer. 8 one two three four five six a,b,c a\,b\,c value value ]]> one two three four one two three four Name with dot Another dot ABC 1,2,3 value1,value2 * * Some text Some other text preserved commons-configuration-1.10-src/src/test/resources/test2.plist.xml100644 2346 12232154103 24715 0ustarhenningstaff 0 0 http://www.google.com/search?hl=en&client=safari&rls=en&q=RFC822MessageDatasPboardType&btnG=Search&aq=f&oq=&aqi= RFC822MessageDatasPboardType - Google Search commons-configuration-1.10-src/src/test/resources/test2.properties100644 2744 12232154103 25161 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. configuration.loaded = true packages = override.packages propertyInOrder=test2.properties # # Other test properties # test.equals = value=one test.empty= # # Non String Properties # test.boolean = true test.boolean.array = false test.boolean.array = true test.byte = 10 test.byte.array = 20 test.byte.array = 30 test.double = 10.25 test.double.array = 20.35 test.double.array = 30.45 test.float = 20.25 test.float.array = 30.35 test.float.array = 40.45 test.integer = 10 test.integer.array = 20 test.integer.array = 30 test.long = 1000000 test.long.array = 2000000 test.long.array = 3000000 test.short = 1 test.short.array = 2 test.short.array = 3 commons-configuration-1.10-src/src/test/resources/test_invalid_date.plist.xml100644 2303 12232154103 27327 0ustarhenningstaff 0 0 string value1 date not a valid date commons-configuration-1.10-src/src/test/resources/testClasspath.properties100644 3113 12232154103 26731 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. configuration.loaded = true packages = packagea include = include.properties # # Other test properties # test.equals = value=one test.empty= # # Test a property that uses a previous property # base=base base.reference=${base}extra # # Non String Properties # test.boolean = true test.boolean.array = false test.boolean.array = true test.byte = 10 test.byte.array = 20 test.byte.array = 30 test.double = 10.25 test.double.array = 20.35 test.double.array = 30.45 test.float = 20.25 test.float.array = 30.35 test.float.array = 40.45 test.integer = 10 test.integer.array = 20 test.integer.array = 30 test.long = 1000000 test.long.array = 2000000 test.long.array = 3000000 test.short = 1 test.short.array = 2 test.short.array = 3 test.overwrite = 1commons-configuration-1.10-src/src/test/resources/testcombine1.xml100644 4136 12232154103 25116 0ustarhenningstaff 0 0 green yellow 1 http://www.url1.org http://www.url2.org http://www.url3.org http://service1.org Admin documents docid long docname varchar authorID int
My Channel more test 2 data Test Channel
commons-configuration-1.10-src/src/test/resources/testcombine2.xml100644 4246 12232154103 25121 0ustarhenningstaff 0 0 scotty BeamMeUp black blue 4 http://appsvr1.com http://appsvr2.com http://testsvr.com http://backupsvr.com http://service2.org http://service3.org tasks taskid long taskname varchar
Channel 1 test 1 data Channel 2 test 2 data Channel 3 test 3 data
commons-configuration-1.10-src/src/test/resources/testComplexInitialization.xml100644 4174 12232154103 27742 0ustarhenningstaff 0 0
table list
-->
commons-configuration-1.10-src/src/test/resources/testConfigurationInterpolatorUpdate.xml100644 4572 12232154103 32002 0ustarhenningstaff 0 0
table list
-->
commons-configuration-1.10-src/src/test/resources/testConfigurationProvider.xml100644 4372 12232154103 27745 0ustarhenningstaff 0 0
table list
-->
commons-configuration-1.10-src/src/test/resources/testConfigurationXMLDocument.xml100644 2342 12232154103 30305 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testdb.script100644 11454 12232154103 24533 0ustarhenningstaff 0 0 ; Licensed to the Apache Software Foundation (ASF) under one or more ; contributor license agreements. See the NOTICE file distributed with ; this work for additional information regarding copyright ownership. ; The ASF licenses this file to You under the Apache License, Version 2.0 ; (the "License"); you may not use this file except in compliance with ; the License. You may obtain a copy of the License at ; ; http://www.apache.org/licenses/LICENSE-2.0 ; ; Unless required by applicable law or agreed to in writing, software ; distributed under the License is distributed on an "AS IS" BASIS, ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ; See the License for the specific language governing permissions and ; limitations under the License. DROP TABLE CONFIGURATION IF EXISTS; CREATE TABLE CONFIGURATION(KEY VARCHAR(256) NOT NULL PRIMARY KEY,VALUE VARCHAR(256)); DROP TABLE CONFIGURATIONS IF EXISTS; CREATE TABLE CONFIGURATIONS(NAME VARCHAR(256) NOT NULL,KEY VARCHAR(256) NOT NULL,VALUE VARCHAR(256),CONSTRAINT SYS_PK_CONFIGURATIONS PRIMARY KEY(NAME,KEY)); DROP TABLE CONFIGURATIONLIST IF EXISTS; CREATE TABLE CONFIGURATIONLIST(ID VARCHAR(256) NOT NULL PRIMARY KEY, KEY VARCHAR(256) NOT NULL,VALUE VARCHAR(256));; ; GRANT ALL ON CLASS "java.lang.Math" TO PUBLIC; GRANT ALL ON CLASS "org.hsqldb.Library" TO PUBLIC; CREATE USER SA PASSWORD "" ADMIN; CREATE ALIAS DAYNAME FOR "org.hsqldb.Library.dayname"; CREATE ALIAS SPACE FOR "org.hsqldb.Library.space"; CREATE ALIAS SUBSTRING FOR "org.hsqldb.Library.substring"; CREATE ALIAS HEXTORAW FOR "org.hsqldb.Library.hexToRaw"; CREATE ALIAS SQRT FOR "java.lang.Math.sqrt"; CREATE ALIAS ABS FOR "org.hsqldb.Library.abs"; CREATE ALIAS POWER FOR "java.lang.Math.pow"; CREATE ALIAS CHAR FOR "org.hsqldb.Library.character"; CREATE ALIAS CONCAT FOR "org.hsqldb.Library.concat"; CREATE ALIAS PI FOR "org.hsqldb.Library.pi"; CREATE ALIAS RAWTOHEX FOR "org.hsqldb.Library.rawToHex"; CREATE ALIAS SECOND FOR "org.hsqldb.Library.second"; CREATE ALIAS TRUNCATE FOR "org.hsqldb.Library.truncate"; CREATE ALIAS MONTH FOR "org.hsqldb.Library.month"; CREATE ALIAS LOWER FOR "org.hsqldb.Library.lcase"; CREATE ALIAS ATAN2 FOR "java.lang.Math.atan2"; CREATE ALIAS REPEAT FOR "org.hsqldb.Library.repeat"; CREATE ALIAS DAYOFMONTH FOR "org.hsqldb.Library.dayofmonth"; CREATE ALIAS TAN FOR "java.lang.Math.tan"; CREATE ALIAS RADIANS FOR "java.lang.Math.toRadians"; CREATE ALIAS FLOOR FOR "java.lang.Math.floor"; CREATE ALIAS NOW FOR "org.hsqldb.Library.now"; CREATE ALIAS ACOS FOR "java.lang.Math.acos"; CREATE ALIAS DAYOFWEEK FOR "org.hsqldb.Library.dayofweek"; CREATE ALIAS CEILING FOR "java.lang.Math.ceil"; CREATE ALIAS DAYOFYEAR FOR "org.hsqldb.Library.dayofyear"; CREATE ALIAS LCASE FOR "org.hsqldb.Library.lcase"; CREATE ALIAS WEEK FOR "org.hsqldb.Library.week"; CREATE ALIAS SOUNDEX FOR "org.hsqldb.Library.soundex"; CREATE ALIAS ASIN FOR "java.lang.Math.asin"; CREATE ALIAS LOCATE FOR "org.hsqldb.Library.locate"; CREATE ALIAS EXP FOR "java.lang.Math.exp"; CREATE ALIAS MONTHNAME FOR "org.hsqldb.Library.monthname"; CREATE ALIAS YEAR FOR "org.hsqldb.Library.year"; CREATE ALIAS LEFT FOR "org.hsqldb.Library.left"; CREATE ALIAS ROUNDMAGIC FOR "org.hsqldb.Library.roundMagic"; CREATE ALIAS BITOR FOR "org.hsqldb.Library.bitor"; CREATE ALIAS LTRIM FOR "org.hsqldb.Library.ltrim"; CREATE ALIAS COT FOR "org.hsqldb.Library.cot"; CREATE ALIAS COS FOR "java.lang.Math.cos"; CREATE ALIAS MOD FOR "org.hsqldb.Library.mod"; CREATE ALIAS SIGN FOR "org.hsqldb.Library.sign"; CREATE ALIAS DEGREES FOR "java.lang.Math.toDegrees"; CREATE ALIAS LOG FOR "java.lang.Math.log"; CREATE ALIAS SIN FOR "java.lang.Math.sin"; CREATE ALIAS CURTIME FOR "org.hsqldb.Library.curtime"; CREATE ALIAS DIFFERENCE FOR "org.hsqldb.Library.difference"; CREATE ALIAS INSERT FOR "org.hsqldb.Library.insert"; CREATE ALIAS SUBSTR FOR "org.hsqldb.Library.substring"; CREATE ALIAS DATABASE FOR "org.hsqldb.Library.database"; CREATE ALIAS MINUTE FOR "org.hsqldb.Library.minute"; CREATE ALIAS HOUR FOR "org.hsqldb.Library.hour"; CREATE ALIAS IDENTITY FOR "org.hsqldb.Library.identity"; CREATE ALIAS QUARTER FOR "org.hsqldb.Library.quarter"; CREATE ALIAS CURDATE FOR "org.hsqldb.Library.curdate"; CREATE ALIAS BITAND FOR "org.hsqldb.Library.bitand"; CREATE ALIAS USER FOR "org.hsqldb.Library.user"; CREATE ALIAS UCASE FOR "org.hsqldb.Library.ucase"; CREATE ALIAS RTRIM FOR "org.hsqldb.Library.rtrim"; CREATE ALIAS LOG10 FOR "org.hsqldb.Library.log10"; CREATE ALIAS RIGHT FOR "org.hsqldb.Library.right"; CREATE ALIAS ATAN FOR "java.lang.Math.atan"; CREATE ALIAS UPPER FOR "org.hsqldb.Library.ucase"; CREATE ALIAS ASCII FOR "org.hsqldb.Library.ascii"; CREATE ALIAS RAND FOR "java.lang.Math.random"; CREATE ALIAS LENGTH FOR "org.hsqldb.Library.length"; CREATE ALIAS ROUND FOR "org.hsqldb.Library.round"; CREATE ALIAS REPLACE FOR "org.hsqldb.Library.replace"; commons-configuration-1.10-src/src/test/resources/testDigesterBadXML.xml100644 2140 12232154103 26150 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterConfiguration.xml100644 1746 12232154103 27723 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterConfiguration2.xml100644 2501 12232154103 27773 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterConfiguration3.xml100644 2367 12232154103 30006 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterConfigurationBasePath.xml100644 1644 12232154103 31330 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterConfigurationInclude1.xml100644 3101 12232154103 31273 0ustarhenningstaff 0 0 tasks taskid long name java.lang.String description java.lang.String responsibleID long creatorID long startDate java.util.Date endDate java.util.Date
commons-configuration-1.10-src/src/test/resources/testDigesterConfigurationInclude2.properties100644 1714 12232154103 32700 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Properties for Email configuration host.smtp = smtp.mydomain.org host.pop = pop3.mydomain.org account.user = postmaster account.psswd = secret account.type = pop3 commons-configuration-1.10-src/src/test/resources/testDigesterConfigurationNamespaceAware.xml100644 2002 12232154103 32502 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterConfigurationOverwrite.properties100644 1663 12232154103 33224 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # Properties for Email configuration mail.account.user = masterOfPost mail.account.psswd = topsecret test.configuration = enhanced factory commons-configuration-1.10-src/src/test/resources/testDigesterConfigurationReverseOrder.xml100644 1667 12232154103 32255 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterConfigurationSysProps.xml100644 1763 12232154103 31445 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterConfigurationWithProps.xml100644 1654 12232154103 31601 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterCreateObject.xml100644 2153 12232154103 27437 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterOptionalConfiguration.xml100644 2750 12232154103 31425 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDigesterOptionalConfigurationEx.xml100644 2237 12232154103 31722 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testDtd.xml100644 2073 12232154103 24132 0ustarhenningstaff 0 0 value1 value2 commons-configuration-1.10-src/src/test/resources/testEncoding.xml100644 3432 12232154103 25145 0ustarhenningstaff 0 0 <?xml version="1.0" encoding="UTF-16" ?> <!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. --> <test3> <yoge>test3_yoge</yoge> </test3> commons-configuration-1.10-src/src/test/resources/testEqual.properties100644 1663 12232154103 26066 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. property.a = a property.b = b property.c = 100 # # Value set twice property.a = aa clear.property = delete me existing.property = i exist commons-configuration-1.10-src/src/test/resources/testEqualDigester.xml100644 1637 12232154103 26162 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testExpression.xml100644 5226 12232154103 25561 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testExtendedClass.xml100644 4271 12232154103 26147 0ustarhenningstaff 0 0
table list
-->
commons-configuration-1.10-src/src/test/resources/testExtendedXMLConfigurationProvider.xml100644 4572 12232154103 32011 0ustarhenningstaff 0 0
table list
-->
commons-configuration-1.10-src/src/test/resources/testFactoryPropertiesInclude.xml100644 2160 12232154103 30404 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testFileReloadConfigurationBuilder.xml100644 5124 12232154103 31464 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testFileReloadConfigurationBuilder2.xml100644 5150 12232154103 31545 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testFileSystem.xml100644 4512 12232154103 25503 0ustarhenningstaff 0 0
table list
-->
commons-configuration-1.10-src/src/test/resources/testGlobalLookup.xml100644 4364 12232154103 26016 0ustarhenningstaff 0 0
table list
-->
commons-configuration-1.10-src/src/test/resources/testHierarchicalXMLConfiguration.xml100644 3524 12232154103 31110 0ustarhenningstaff 0 0 users uid long uname java.lang.String firstName java.lang.String lastName java.lang.String email java.lang.String
documents docid long name java.lang.String creationDate java.util.Date authorID long version int
commons-configuration-1.10-src/src/test/resources/testHierarchicalXMLConfiguration2.xml100644 2766 12232154103 31201 0ustarhenningstaff 0 0 Case1Text Case2Text Case4Text commons-configuration-1.10-src/src/test/resources/testInterpolation.properties100644 2165 12232154103 27644 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. # A test configuration file for testing variable substitution across multiple # configuration sources created by a DefaultConfigurationBuilder. # This properties configuration defines a property which is referenced by # another configuration source. # $Id: testInterpolation.properties 1295276 2012-02-29 21:11:35Z oheger $ myvar=abc commons-configuration-1.10-src/src/test/resources/testInterpolation.xml100644 2363 12232154103 26250 0ustarhenningstaff 0 0 ${myvar}-product commons-configuration-1.10-src/src/test/resources/testInterpolationBuilder.xml100644 2705 12232154103 27557 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testMultiConfiguration.xsd100644 10600 12232154103 27252 0ustarhenningstaff 0 0 Comma delimited lists commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_1001.xml100644 2563 12232154103 27706 0ustarhenningstaff 0 0 #808080 #000000
#008000
${colors.header}
15 OK,Cancel,Help My Channel more test 2 data
commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_1002.xml100644 2300 12232154103 27674 0ustarhenningstaff 0 0 #2222222 #000000
#222222
${colors.header3}
25 OK-2,Cancel-2,Help-2
commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_1003.xml100644 2277 12232154103 27712 0ustarhenningstaff 0 0 #333333 #FFFFFF
#333333
${colors.header3}
35 OK-3,Cancel-3,Help-3
commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_1004.xml100644 2024 12232154103 27701 0ustarhenningstaff 0 0 ${colors.header4} OK-1,Cancel-2,Help-3 commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_2001.xml100644 2312 12232154103 27677 0ustarhenningstaff 0 0 This will throw a schema exception OK-1,Cancel-2,Help-3 commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_2002.xml100644 2540 12232154103 27703 0ustarhenningstaff 0 0 #2222222 #000000
#222222
${colors.header3}
25 OK-2,Cancel-2,Help-2
commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_3001.xml100644 3011 12232154103 27675 0ustarhenningstaff 0 0 #808080 #000000
#008000
${colors.header}
15 OK,Cancel,Help My Channel more test 2 data
commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_3002.xml100644 2526 12232154103 27710 0ustarhenningstaff 0 0 #2222222 #000000
#222222
${colors.header3}
25 OK-2,Cancel-2,Help-2
commons-configuration-1.10-src/src/test/resources/testMultiConfiguration_default.xml100644 3361 12232154103 30746 0ustarhenningstaff 0 0 #40404040 #000000
#444444
${colors.default}
50 OK-4,Cancel-4,Help-4 a,b,c a\,b\,c Channel 1 test 1 data Channel 2 test 2 data
commons-configuration-1.10-src/src/test/resources/testMultiDynamic_default.xml100644 3632 12232154103 27524 0ustarhenningstaff 0 0 #40404040 #000000
#444444
${colors.default}
ID0001 IDAUTO01 IDAUTO02 50 OK-4,Cancel-4,Help-4 a,b,c a\,b\,c Channel 1 test 1 data Channel 2 test 2 data
commons-configuration-1.10-src/src/test/resources/testMultiDynamic_default2.xml100644 3701 12232154103 27603 0ustarhenningstaff 0 0 #40404040 #000000
#444444
${colors.default}
ID0001 ID0002 IDAUTO01 IDAUTO02 25 OK-4,Cancel-4,Help-4 a,b,c a\,b\,c Channel 1 test 1 data Channel 2 test 2 data
commons-configuration-1.10-src/src/test/resources/testMultiTenentConfigurationBuilder.xml100644 4361 12232154103 31730 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testMultiTenentConfigurationBuilder2.xml100644 5131 12232154103 32006 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testMultiTenentConfigurationBuilder3.xml100644 5143 12232154103 32012 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testMultiTenentConfigurationBuilder4.xml100644 5407 12232154103 32016 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testMultiTenentConfigurationBuilder5.xml100644 5151 12232154103 32013 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testPatternSubtreeConfig.xml100644 4073 12232154103 27516 0ustarhenningstaff 0 0 #808080 #000000
#008000
${colors.header}
15 OK,Cancel,Help
#2222222 #000000
#222222
${colors.header3}
25 OK-2,Cancel-2,Help-2
#333333 #FFFFFF
#333333
${colors.header3}
35 OK-3,Cancel-3,Help-3
commons-configuration-1.10-src/src/test/resources/testResolver.xml100644 1670 12232154103 25222 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testSequence.properties100644 2030 12232154103 26554 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. prefix.Fa.postfix=value.Fa prefix.Po.postfix=value.Po prefix.Ru.postfix=value.Ru prefix.Se.postfix=value.Se prefix.As.postfix=value.As prefix.Gl.postfix=value.Gl prefix.Pu.postfix=value.Pu prefix.Te.postfix=value.Te prefix.Ve.postfix=value.Ve commons-configuration-1.10-src/src/test/resources/testSequenceDigester.xml100644 1642 12232154103 26657 0ustarhenningstaff 0 0 commons-configuration-1.10-src/src/test/resources/testSystemProperties.xml100644 3024 12232154103 26755 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testValidateInvalid.xml100644 3125 12232154103 26456 0ustarhenningstaff 0 0 ]> customers custID java.lang.Long custName
commons-configuration-1.10-src/src/test/resources/testValidateValid.xml100644 2546 12232154103 26135 0ustarhenningstaff 0 0 ]> customers custID java.lang.Long custName java.lang.String
commons-configuration-1.10-src/src/test/resources/testValidation.xml100644 2740 12232154103 25512 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testValidation2.xml100644 3063 12232154103 25573 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testValidation3.xml100644 4076 12232154103 25601 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testVFSMultiTenentConfigurationBuilder1.xml100644 5264 12232154103 32373 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/testVFSMultiTenentConfigurationBuilder2.xml100644 5271 12232154103 32372 0ustarhenningstaff 0 0
commons-configuration-1.10-src/src/test/resources/threesome.properties100644 1722 12232154103 26106 0ustarhenningstaff 0 0 # Licensed to the Apache Software Foundation (ASF) under one or more # contributor license agreements. See the NOTICE file distributed with # this work for additional information regarding copyright ownership. # The ASF licenses this file to You under the Apache License, Version 2.0 # (the "License"); you may not use this file except in compliance with # the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. test.threesome.one = aaa test.threesome.one = bbb, ccc test.threesome.two = aaa, bbb, ccc test.threesome.three = aaa test.threesome.three = bbb test.threesome.three = ccc