commons-configuration-1.10-src/LICENSE.txt 100644 26136 12232154104 20067 0 ustar henning staff 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.txt 100644 266 12232154104 17722 0 ustar henning staff 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.xml 100644 50354 12232154104 17560 0 ustar henning staff 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.txt 100644 10037 12232154104 20744 0 ustar henning staff 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 5 ustar 0 0 commons-configuration-1.10-src/conf/checkstyle-suppressions.xml 100644 2637 12232154102 24602 0 ustar henning staff 0 0
commons-configuration-1.10-src/conf/checkstyle.xml 100644 16426 12232154102 22050 0 ustar henning staff 0 0
commons-configuration-1.10-src/conf/CommonsConfiguration.xsd 100644 12074 12232154102 24046 0 ustar henning staff 0 0
Commons Configuration v0.1
commons-configuration-1.10-src/conf/findbugs-exclude-filter.xml 100644 2353 12232154102 24377 0 ustar henning staff 0 0
commons-configuration-1.10-src/conf/HEADER.txt 100644 1442 12232154102 20631 0 ustar henning staff 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/README 100644 160 12232154102 17774 0 ustar henning staff 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 5 ustar 0 0 commons-configuration-1.10-src/src/changes/ 40755 0 12232154103 20315 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/ 40755 0 12232154103 17631 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/assembly/ 40755 0 12232154102 21447 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/ 40755 0 12232154102 20551 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/ 40755 0 12232154102 21340 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/ 40755 0 12232154102 22561 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/ 40755 0 12232154102 24234 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ 40755 0 12232154103 27104 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/ 40755 0 12232154102 31071 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/event/ 40755 0 12232154102 30224 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/interpol/ 40755 0 12232154102 30737 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/plist/ 40755 0 12232154102 30236 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/reloading/ 40755 0 12232154102 31047 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/resolver/ 40755 0 12232154102 30744 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/ 40755 0 12232154102 30042 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/tree/xpath/ 40755 0 12232154102 31166 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/web/ 40755 0 12232154102 27660 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/javacc/ 40755 0 12232154103 21060 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/main/resources/ 40755 0 12232154103 21643 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/site/ 40755 0 12232154103 17651 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/site/resources/ 40755 0 12232154103 21663 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/site/resources/images/ 40755 0 12232154103 23130 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/site/xdoc/ 40755 0 12232154103 20606 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/site/xdoc/userguide/ 40755 0 12232154103 22602 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/ 40755 0 12232154103 17664 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/ 40755 0 12232154103 20605 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/ 40755 0 12232154103 21374 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/ 40755 0 12232154103 22615 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/ 40755 0 12232154103 24270 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/ 40755 0 12232154104 27140 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/beanutils/ 40755 0 12232154104 31126 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/event/ 40755 0 12232154103 30260 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/interpol/ 40755 0 12232154103 30773 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/plist/ 40755 0 12232154103 30272 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/reloading/ 40755 0 12232154103 31103 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/test/ 40755 0 12232154103 30116 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/ 40755 0 12232154104 30077 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/tree/xpath/ 40755 0 12232154104 31223 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/java/org/apache/commons/configuration/web/ 40755 0 12232154103 27714 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/resources/ 40755 0 12232154103 21676 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/resources/01/ 40755 0 12232154103 22116 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/resources/config/ 40755 0 12232154103 23143 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/test/resources/config/deep/ 40755 0 12232154103 24060 5 ustar henning staff 0 0 commons-configuration-1.10-src/src/changes/changes.xml 100644 275776 12232154103 22634 0 ustar henning staff 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.xml 100644 2744 12232154102 23045 0 ustar henning staff 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.xml 100644 2467 12232154102 23066 0 ustar henning staff 0 0
src
tar.gz
zip
${artifactId}-${commons.release.version}-src
LICENSE*
NOTICE*
RELEASE-NOTES*
pom.xml
conf
src
././@LongLink 100644 0 0 151 12232154257 10253 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractConfiguration.100644 117775 12232154102 33556 0 ustar henning staff 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;
}
}
././@LongLink 100644 0 0 155 12232154257 10257 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractFileConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractFileConfigurat100644 101575 12232154102 33561 0 ustar henning staff 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);
}
}
}
././@LongLink 100644 0 0 171 12232154257 10255 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractHierarchicalFileConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/AbstractHierarchicalFi100644 35415 12232154103 33475 0 ustar henning staff 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 extends ConfigurationNode> 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();
}
}
}
././@LongLink 100644 0 0 145 12232154257 10256 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/BaseConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/BaseConfiguration.java100644 14616 12232154103 33476 0 ustar henning staff 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);
}
}
}
././@LongLink 100644 0 0 156 12232154257 10260 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/BaseConfigurationXMLReader.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/BaseConfigurationXMLRe100644 7673 12232154103 33413 0 ustar henning staff 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);
}
}
}
././@LongLink 100644 0 0 155 12232154257 10257 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanDeclaration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanDeclarat100644 10311 12232154102 33432 0 ustar henning staff 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();
}
././@LongLink 100644 0 0 151 12232154257 10253 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanFactory.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanFactory.100644 6636 12232154102 33377 0 ustar henning staff 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();
}
././@LongLink 100644 0 0 150 12232154257 10252 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/BeanHelper.j100644 43722 12232154102 33376 0 ustar henning staff 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();
}
}
}
././@LongLink 100644 0 0 163 12232154257 10256 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/ConfigurationDynaBean.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/Configuratio100644 17730 12232154102 33572 0 ustar henning staff 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();
}
}
././@LongLink 100644 0 0 164 12232154257 10257 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/ConfigurationDynaClass.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/Configuratio100644 11242 12232154102 33562 0 ustar henning staff 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);
}
}
././@LongLink 100644 0 0 160 12232154257 10253 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanFactory.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/DefaultBeanF100644 7750 12232154102 33402 0 ustar henning staff 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);
}
}
././@LongLink 100644 0 0 145 12232154257 10256 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/package.html commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/package.html100644 2433 12232154102 33451 0 ustar henning staff 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 $
././@LongLink 100644 0 0 160 12232154257 10253 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/XMLBeanDeclaration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/beanutils/XMLBeanDecla100644 37233 12232154102 33320 0 ustar henning staff 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);
}
}
././@LongLink 100644 0 0 151 12232154257 10253 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/CombinedConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/CombinedConfiguration.100644 102135 12232154103 33514 0 ustar henning staff 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:
*
*
*
* 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;
}
}
}
././@LongLink 100644 0 0 152 12232154257 10254 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/CompositeConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/CompositeConfiguration100644 45165 12232154103 33651 0 ustar henning staff 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 extends Configuration> 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 extends Configuration> 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.java 100644 52536 12232154102 32705 0 ustar henning staff 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);
}
././@LongLink 100644 0 0 150 12232154257 10252 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationBuilder.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationBuilder.j100644 3523 12232154103 33475 0 ustar henning staff 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;
}
././@LongLink 100644 0 0 153 12232154257 10255 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationComparator.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationComparato100644 2632 12232154102 33603 0 ustar henning staff 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);
}
././@LongLink 100644 0 0 152 12232154257 10254 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationConverter.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationConverter100644 10342 12232154102 33642 0 ustar henning staff 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);
}
}
././@LongLink 100644 0 0 152 12232154257 10254 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationException.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationException100644 4516 12232154102 33617 0 ustar henning staff 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);
}
}
././@LongLink 100644 0 0 150 12232154257 10252 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationFactory.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationFactory.j100644 72003 12232154102 33534 0 ustar henning staff 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.java 100644 50112 12232154103 33343 0 ustar henning staff 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.java 100644 13610 12232154102 33331 0 ustar henning staff 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();
}
}
}
././@LongLink 100644 0 0 161 12232154257 10254 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationRuntimeException.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationRuntimeEx100644 4633 12232154103 33602 0 ustar henning staff 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);
}
}
././@LongLink 100644 0 0 146 12232154257 10257 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationUtils.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationUtils.jav100644 61702 12232154103 33561 0 ustar henning staff 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());
}
});
}
}
././@LongLink 100644 0 0 152 12232154257 10254 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationXMLReader.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConfigurationXMLReader100644 23655 12232154103 33472 0 ustar henning staff 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;
}
././@LongLink 100644 0 0 147 12232154257 10260 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConversionException.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/ConversionException.ja100644 4430 12232154102 33521 0 ustar henning staff 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);
}
}
././@LongLink 100644 0 0 151 12232154257 10253 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DatabaseConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DatabaseConfiguration.100644 53343 12232154102 33465 0 ustar henning staff 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();
}
}
}
././@LongLink 100644 0 0 145 12232154257 10256 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DataConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DataConfiguration.java100644 211653 12232154102 33514 0 ustar henning staff 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);
}
}
}
././@LongLink 100644 0 0 157 12232154257 10261 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DefaultConfigurationBuilder.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DefaultConfigurationBu100644 206136 12232154102 33576 0 ustar henning staff 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:
*
*
*
*
* Attribute
* Meaning
*
*
* {@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 extends HierarchicalConfiguration> 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);
}
}
}
}
././@LongLink 100644 0 0 145 12232154257 10256 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DefaultFileSystem.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DefaultFileSystem.java100644 24312 12232154103 33457 0 ustar henning staff 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());
}
}
}
}
././@LongLink 100644 0 0 160 12232154257 10253 L ustar 0 0 commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DynamicCombinedConfiguration.java commons-configuration-1.10-src/src/main/java/org/apache/commons/configuration/DynamicCombinedConfigu100644 64433 12232154102 33515 0 ustar henning staff 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