A hierarchical composite configuration class.
This class maintains a list of configuration objects, which can be added using the diverse {@code addConfiguration()} methods. After that theconfigurations 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.configuration2.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 orless 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, dependingon the current {@link NodeCombiner} and the involved properties, the resultsmay be different than expected. Some examples may illustrate this:
gui.background = blue gui.position = (10, 10, 400, 200)
gui.background = black gui.foreground = white home.dir = /data
cc.clearProperty("gui.background");Will a {@code cc.containsKey("gui.background")} now return false? No,it won't! The {@code clearProperty()} operation is executed on the node setof the combined configuration, which was constructed from the nodes of the two child configurations. It causes the value of the background node to be cleared, which is also part of the first child configuration. This modification of one of its child configurations causes the {@code CombinedConfiguration} to be re-constructed. This time the{@code OverrideCombiner} cannot find a {@code gui.background} property in thefirst child configuration, but it finds one in the second, and adds it to the resulting combined configuration. So the property is still present (with a different value now).
addProperty("database.user", "scott");would cause such a hanging property. If now one of the child configurations is changed and the {@code CombinedConfiguration} is re-constructed, thisproperty will disappear! (Add operations are not problematic if they result in a child configuration being updated. For instance an {@code addProperty("home.url", "localhost");} will alter the second childconfiguration - because the prefix home is here already present; when the {@code CombinedConfiguration} is re-constructed, this change istaken into account.)
Whenever the node structure of a {@code CombinedConfiguration} becomesinvalid (either because one of the contained configurations was modified or because the {@code invalidate()} method was directly called) an event isgenerated. So this can be detected by interested event listeners. This also makes it possible to add a combined configuration into another one.
Notes about thread-safety: This configuration implementation uses a {@code Synchronizer} object to protect instances against concurrent access.The concrete {@code Synchronizer} implementation used determines whether aninstance of this class is thread-safe or not. In contrast to other implementations derived from {@link BaseHierarchicalConfiguration}, thread-safety is an issue here because the nodes structure used by this configuration has to be constructed dynamically when a child configuration is changed. Therefore, when multiple threads are involved which also manipulate one of the child configurations, a proper {@code Synchronizer} object shouldbe set. Note that the {@code Synchronizer} objects used by the childconfigurations do not really matter. Because immutable in-memory nodes structures are used for them there is no danger that updates on child configurations could interfere with read operations on the combined configuration.
@since 1.3 @version $Id: CombinedConfiguration.java 1624601 2014-09-12 18:04:36Z oheger $
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|