T
- the type of the nodes managed by this hierarchical configurationpublic abstract class AbstractHierarchicalConfiguration<T> extends AbstractConfiguration implements Cloneable, NodeKeyResolver<T>, HierarchicalConfiguration<T>
A specialized configuration class that extends its base class by the ability of keeping more structure in the stored properties.
There are some sources of configuration data that cannot be stored very well in a BaseConfiguration
object
because then their structure is lost. This is for instance true for XML documents. This class can deal with such
structured configuration sources by storing the properties in a tree-like organization. The exact storage structure
of the underlying data does not matter for the configuration instance; it uses a NodeModel
object for
accessing it.
The hierarchical organization allows for a more sophisticated access to single properties. As an example consider the following XML document:
<database> <tables> <table> <name>users</name> <fields> <field> <name>lid</name> <type>long</name> </field> <field> <name>usrName</name> <type>java.lang.String</type> </field> ... </fields> </table> <table> <name>documents</name> <fields> <field> <name>docid</name> <type>long</type> </field> ... </fields> </table> ... </tables> </database>
If this document is parsed and stored in a hierarchical configuration object (which can be done by one of the sub classes), there are enhanced possibilities of accessing properties. Per default, the keys for querying information can contain indices that select a specific element if there are multiple hits.
For instance the key tables.table(0).name
can be used to find out the name of the first table. In opposite
tables.table.name
would return a collection with the names of all available tables. Similarly the key
tables.table(1).fields.field.name
returns a collection with the names of all fields of the second table. If
another index is added after the field
element, a single field can be accessed:
tables.table(1).fields.field(0).name
.
There is a getMaxIndex()
method that returns the maximum allowed index that can be added to a given property
key. This method can be used to iterate over all values defined for a certain property.
Since the 1.3 release of Commons Configuration hierarchical configurations support an expression
engine. This expression engine is responsible for evaluating the passed in configuration keys and map them to
the stored properties. The examples above are valid for the default expression engine, which is used when a new
AbstractHierarchicalConfiguration
instance is created. With the setExpressionEngine()
method a
different expression engine can be set. For instance with
XPathExpressionEngine
there is an expression engine available
that supports configuration keys in XPATH syntax.
In addition to the events common for all configuration classes, hierarchical configurations support some more events
that correspond to some specific methods and features. For those events specific event type constants in
ConfigurationEvent
exist:
addNodes()
method was called; the event object contains the key, to which the nodes were added, and a
collection with the new nodes as value.clearTree()
method was called; the event object stores the key of the removed sub tree.SubnodeConfiguration
that was created from this configuration has been changed. The value property of
the event object contains the original event object as it was sent by the subnode configuration.
Whether an AbstractHierarchicalConfiguration
object is thread-safe or not depends on the underlying
NodeModel
and the Synchronizer
it is associated
with. Some NodeModel
implementations are inherently thread-safe; they do not require a special
Synchronizer
. (Per default, a dummy Synchronizer
is used which is not thread-safe!) The methods for
querying or updating configuration data invoke this Synchronizer
accordingly. When accessing the
configuration's root node directly, the client application is responsible for proper synchronization. This is
achieved by calling the methods lock()
, and
unlock()
with a proper
LockMode
argument. In any case, it is recommended to not
access the root node directly, but to use corresponding methods for querying or updating configuration data instead.
Direct manipulations of a configuration's node structure circumvent many internal mechanisms and thus can cause
undesired effects. For concrete subclasses dealing with specific node structures, this situation may be different.
Modifier | Constructor and Description |
---|---|
protected |
AbstractHierarchicalConfiguration(NodeModel<T> nodeModel)
Creates a new instance of
AbstractHierarchicalConfiguration and sets the NodeModel to be used. |
Modifier and Type | Method and Description |
---|---|
void |
addNodes(String key,
Collection<? extends T> nodes)
Adds a collection of nodes at the specified position of the configuration tree.
|
protected void |
addNodesInternal(String key,
Collection<? extends T> nodes)
Actually adds a collection of new nodes to this configuration.
|
protected void |
addPropertyDirect(String key,
Object value)
Adds a key/value pair to the Configuration.
|
protected void |
addPropertyInternal(String key,
Object obj)
Adds the property with the specified key.
|
protected void |
clearInternal()
Clears this configuration.
|
protected void |
clearPropertyDirect(String key)
Removes the property with the given key.
|
void |
clearTree(String key)
Removes all values of the property with the given name and of keys that start with this name.
|
protected Object |
clearTreeInternal(String key)
Actually clears the tree of elements referenced by the given key.
|
Object |
clone()
Creates a copy of this object.
|
protected abstract NodeModel<T> |
cloneNodeModel()
Creates a clone of the node model.
|
protected boolean |
containsKeyInternal(String key)
Checks if the specified key is contained in this configuration.
|
protected List<QueryResult<T>> |
fetchNodeList(String key)
Helper method for resolving the specified key.
|
ExpressionEngine |
getExpressionEngine()
Returns the expression engine used by this configuration.
|
protected Iterator<String> |
getKeysInternal()
Returns an iterator with all keys defined in this configuration.
|
protected Iterator<String> |
getKeysInternal(String prefix)
Returns an iterator with all keys defined in this configuration that start with the given prefix.
|
int |
getMaxIndex(String key)
Returns the maximum defined index for the given key.
|
protected int |
getMaxIndexInternal(String key)
Actually retrieves the maximum defined index for the given key.
|
protected NodeModel<T> |
getModel()
Returns the
NodeModel used by this configuration. |
NodeModel<T> |
getNodeModel()
Returns the
NodeModel supported by this object. |
protected Object |
getPropertyInternal(String key)
Fetches the specified property.
|
String |
getRootElementName()
Returns the name of the root element of this configuration.
|
protected String |
getRootElementNameInternal()
Actually obtains the name of the root element.
|
protected boolean |
isEmptyInternal()
Checks if this configuration is empty.
|
protected boolean |
nodeDefined(T node)
Checks if the specified node is defined.
|
String |
nodeKey(T node,
Map<T,String> cache,
NodeHandler<T> handler)
Generates a unique key for the specified node.
|
NodeAddData<T> |
resolveAddKey(T root,
String key,
NodeHandler<T> handler)
Resolves a key of an add operation.
|
List<QueryResult<T>> |
resolveKey(T root,
String key,
NodeHandler<T> handler)
Performs a query for the specified key on the given root node.
|
List<T> |
resolveNodeKey(T root,
String key,
NodeHandler<T> handler)
Performs a query for the specified key on the given root node returning only node results.
|
NodeUpdateData<T> |
resolveUpdateKey(T root,
String key,
Object newValue,
NodeHandler<T> handler)
Resolves a key for an update operation.
|
void |
setExpressionEngine(ExpressionEngine expressionEngine)
Sets the expression engine to be used by this configuration.
|
protected void |
setPropertyInternal(String key,
Object value)
Sets the value of the specified property.
|
protected int |
sizeInternal()
Actually calculates the size of this configuration.
|
String |
toString() |
addErrorLogListener, addProperty, append, beginRead, beginWrite, clear, clearProperty, cloneInterpolator, containsKey, copy, endRead, endWrite, get, get, getArray, getArray, getBigDecimal, getBigDecimal, getBigInteger, getBigInteger, getBoolean, getBoolean, getBoolean, getByte, getByte, getByte, getCollection, getCollection, getConfigurationDecoder, getConversionHandler, getDouble, getDouble, getDouble, getDuration, getDuration, getEncodedString, getEncodedString, getFloat, getFloat, getFloat, getInt, getInt, getInteger, getInterpolator, getKeys, getKeys, getList, getList, getList, getList, getListDelimiterHandler, getLogger, getLong, getLong, getLong, getProperties, getProperties, getProperty, getShort, getShort, getShort, getString, getString, getStringArray, getSynchronizer, immutableSubset, initLogger, installInterpolator, interpolate, interpolate, interpolatedConfiguration, isEmpty, isScalarValue, isThrowExceptionOnMissing, lock, setConfigurationDecoder, setConversionHandler, setDefaultLookups, setInterpolator, setListDelimiterHandler, setLogger, setParentInterpolator, setPrefixLookups, setProperty, setSynchronizer, setThrowExceptionOnMissing, size, subset, unlock
addEventListener, clearErrorListeners, clearEventListeners, copyEventListeners, createErrorEvent, createEvent, fireError, fireEvent, getEventListenerRegistrations, getEventListeners, isDetailEvents, removeEventListener, setDetailEvents
equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
childConfigurationsAt, childConfigurationsAt, configurationAt, configurationAt, configurationsAt, configurationsAt
addProperty, clear, clearProperty, getInterpolator, installInterpolator, setInterpolator, setProperty, subset
getSynchronizer, lock, setSynchronizer, unlock
immutableChildConfigurationsAt, immutableConfigurationAt, immutableConfigurationAt, immutableConfigurationsAt
containsKey, get, get, getArray, getArray, getBigDecimal, getBigDecimal, getBigInteger, getBigInteger, getBoolean, getBoolean, getBoolean, getByte, getByte, getByte, getCollection, getCollection, getDouble, getDouble, getDouble, getDuration, getDuration, getEncodedString, getEncodedString, getEnum, getEnum, getFloat, getFloat, getFloat, getInt, getInt, getInteger, getKeys, getKeys, getList, getList, getList, getList, getLong, getLong, getLong, getProperties, getProperty, getShort, getShort, getShort, getString, getString, getStringArray, immutableSubset, isEmpty, size
protected AbstractHierarchicalConfiguration(NodeModel<T> nodeModel)
AbstractHierarchicalConfiguration
and sets the NodeModel
to be used.nodeModel
- the NodeModel
public final String getRootElementName()
immutableConfigurationsAt()
method. The exact meaning of the string
returned by this method is specific to a concrete implementation. For instance, an XML configuration might return the
name of the document element. This implementation handles synchronization and delegates to getRootElementNameInternal()
.getRootElementName
in interface ImmutableHierarchicalConfiguration
protected String getRootElementNameInternal()
getRootElementName()
. It just returns
the name of the root node. Subclasses that treat the root element name differently can override this method.public NodeModel<T> getNodeModel()
NodeModel
supported by this object. This implementation returns the configuration's NodeModel
. It is guarded by the current
Synchronizer
.getNodeModel
in interface NodeModelSupport<T>
NodeModel
public ExpressionEngine getExpressionEngine()
getExpressionEngine
in interface ImmutableHierarchicalConfiguration
public void setExpressionEngine(ExpressionEngine expressionEngine)
setExpressionEngine
in interface HierarchicalConfiguration<T>
expressionEngine
- the new expression engine; can be null, then the default expression engine will be
usedprotected Object getPropertyInternal(String key)
getPropertyInternal
in class AbstractConfiguration
key
- the key to be looked upprotected void addPropertyInternal(String key, Object obj)
ExpressionEngine
, so
the passed in key must match the requirements of this implementation.addPropertyInternal
in class AbstractConfiguration
key
- the key of the new propertyobj
- the value of the new propertyprotected void addPropertyDirect(String key, Object value)
addProperty()
for hierarchical configurations
because all values to be added for the property have to be passed to the model in a single step. However, to allow
derived classes to add an arbitrary value as an object, a special implementation is provided here. The passed in
object is not parsed as a list, but passed directly as only value to the model.addPropertyDirect
in class AbstractConfiguration
key
- key to use for mappingvalue
- object to storepublic final void addNodes(String key, Collection<? extends T> nodes)
addProperty()
, but instead of a single property a whole collection of nodes can be added - and thus complete
configuration sub trees. E.g. with this method it is possible to add parts of another
BaseHierarchicalConfiguration
object to this object. If the passed in key refers to an existing and unique
node, the new nodes are added to this node. Otherwise a new node will be created at the specified position in the
hierarchy. Implementation node: This method performs some book-keeping and then delegates to
addNodesInternal()
.addNodes
in interface HierarchicalConfiguration<T>
key
- the key where the nodes are to be added; can be null, then they are added to the root nodenodes
- a collection with the Node
objects to be addedprotected void addNodesInternal(String key, Collection<? extends T> nodes)
addNodes()
. It can be
overridden by subclasses that need to adapt this operation.key
- the key where the nodes are to be added; can be null, then they are added to the root nodenodes
- a collection with the Node
objects to be addedprotected boolean isEmptyInternal()
isEmptyInternal
in class AbstractConfiguration
protected boolean containsKeyInternal(String key)
containsKeyInternal
in class AbstractConfiguration
key
- the key to be checkedprotected void setPropertyInternal(String key, Object value)
setPropertyInternal
in class AbstractConfiguration
key
- the key of the property to setvalue
- the new value of this propertypublic List<QueryResult<T>> resolveKey(T root, String key, NodeHandler<T> handler)
query()
method
of an ExpressionEngine
. This implementation delegates to the expression engine.resolveKey
in interface NodeKeyResolver<T>
root
- the root nodekey
- the key to be resolvedhandler
- the NodeHandler
public List<T> resolveNodeKey(T root, String key, NodeHandler<T> handler)
resolveKey()
, but filters only for results of type node. This implementation delegates to resolveKey()
and then filters out attribute results.resolveNodeKey
in interface NodeKeyResolver<T>
root
- the root nodekey
- the key to be resolvedhandler
- the NodeHandler
public NodeAddData<T> resolveAddKey(T root, String key, NodeHandler<T> handler)
NodeAddData
object containing all information for actually
performing the add operation at the specified key. This implementation delegates to the expression engine.resolveAddKey
in interface NodeKeyResolver<T>
root
- the root nodekey
- the key to be resolvedhandler
- the NodeHandler
NodeAddData
object to be used for the add operationpublic NodeUpdateData<T> resolveUpdateKey(T root, String key, Object newValue, NodeHandler<T> handler)
NodeUpdateData
object containing all information for
actually performing the update operation at the specified key using the provided new value object. This implementation executes a query for the given key and constructs a NodeUpdateData
object
based on the results. It determines which nodes need to be changed and whether new ones need to be added or existing
ones need to be removed.resolveUpdateKey
in interface NodeKeyResolver<T>
root
- the root nodekey
- the key to be resolvednewValue
- the new value for the key to be updated; this can be a single value or a container for multiple
valueshandler
- the NodeHandler
NodeUpdateData
object to be used for this update operationpublic String nodeKey(T node, Map<T,String> cache, NodeHandler<T> handler)
nodeKey
in interface NodeKeyResolver<T>
node
- the node in questioncache
- a map serving as cachehandler
- the NodeHandler
protected void clearInternal()
clearInternal
in class AbstractConfiguration
public final void clearTree(String key)
clearTree("foo")
would remove both properties.clearTree
in interface HierarchicalConfiguration<T>
key
- the key of the property to be removedprotected Object clearTreeInternal(String key)
clearTree()
.
Subclasses that need to adapt this operation can override this method. This base implementation delegates to the node
model.key
- the key of the property to be removedprotected void clearPropertyDirect(String key)
clearPropertyDirect
in class AbstractConfiguration
key
- the key of the property to be removedprotected int sizeInternal()
size()
with a read lock held.
The base implementation provided here calculates the size based on the iterator returned by getKeys()
. Sub
classes which can determine the size in a more efficient way should override this method. This implementation is slightly more efficient than the default implementation. It does not iterate
over the key set, but directly queries its size after it has been constructed. Note that constructing the key set is
still an O(n) operation.sizeInternal
in class AbstractConfiguration
protected Iterator<String> getKeysInternal()
getKeysInternal
in class AbstractConfiguration
protected Iterator<String> getKeysInternal(String prefix)
getKeysInternal
in class AbstractConfiguration
prefix
- the prefix of the keys to start withpublic final int getMaxIndex(String key)
getMaxIndex
in interface ImmutableHierarchicalConfiguration
key
- the key to be checkedprotected int getMaxIndexInternal(String key)
getMaxIndex()
.
Subclasses that need to adapt this operation have to override this method.key
- the key to be checkedpublic Object clone()
clone
in class BaseEventSource
protected abstract NodeModel<T> cloneNodeModel()
clone()
.NodeModel
protected List<QueryResult<T>> fetchNodeList(String key)
key
- the keyprotected boolean nodeDefined(T node)
node
- the node to be checkedprotected NodeModel<T> getModel()
NodeModel
used by this configuration. This method is intended for internal use only. Access to
the model is granted without any synchronization. This is in contrast to the "official"
getNodeModel()
method which is guarded by the configuration's Synchronizer
.Copyright © 2001–2022 The Apache Software Foundation. All rights reserved.