Package org.apache.commons.configuration2

# Class AbstractHierarchicalConfiguration<T>

java.lang.Object
org.apache.commons.configuration2.event.BaseEventSource
org.apache.commons.configuration2.AbstractConfiguration
org.apache.commons.configuration2.AbstractHierarchicalConfiguration<T>

Type Parameters:
  `T` - the type of the nodes managed by this hierarchical configuration

All Implemented Interfaces:
  `Cloneable`, `Configuration`, `EventSource`, `HierarchicalConfiguration<T>`, `ImmutableConfiguration`, `ImmutableHierarchicalConfiguration`, `SynchronizerSupport`, `NodeKeyResolver<T>`, `NodeModelSupport<T>`

Direct Known Subclasses:
  `BaseHierarchicalConfiguration`

public 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:

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

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.

Since:
  2.0

- ## Constructor Summary

  Constructors
  Modifier
  Constructor
  Description
  `protected`
  `AbstractHierarchicalConfiguration(NodeModel<T> nodeModel)`
  Creates a new instance of `AbstractHierarchicalConfiguration` and sets the `NodeModel` to be used.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `final 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.
  `final 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 boolean`
  `containsValueInternal(Object value)`
  Tests whether this configuration contains one or more matches to this value.
  `protected List<QueryResult<T>>`
  `fetchNodeList(String key)`
  Helper method for resolving the specified key.
  `ExpressionEngine`
  `getExpressionEngine()`
  Gets the expression engine used by this configuration.
  `protected Iterator<String>`
  `getKeysInternal()`
  Gets an iterator with all keys defined in this configuration.
  `protected Iterator<String>`
  `getKeysInternal(String prefix)`
  Gets an iterator with all keys defined in this configuration that start with the given prefix.
  `protected Iterator<String>`
  `getKeysInternal(String prefix, String delimiter)`
  Gets an iterator with all keys defined in this configuration that start with the given prefix.
  `final int`
  `getMaxIndex(String key)`
  Gets 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()`
  Gets the `NodeModel` used by this configuration.
  `NodeModel<T>`
  `getNodeModel()`
  Gets the `NodeModel` supported by this object.
  `protected Object`
  `getPropertyInternal(String key)`
  Fetches the specified property.
  `final String`
  `getRootElementName()`
  Gets 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()`

  ### Methods inherited from class org.apache.commons.configuration2.AbstractConfiguration

  `addErrorLogListener, addProperty, append, beginRead, beginWrite, clear, clearProperty, cloneInterpolator, contains, containsKey, containsValue, 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, 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`

  ### Methods inherited from class org.apache.commons.configuration2.event.BaseEventSource

  `addEventListener, clearErrorListeners, clearEventListeners, copyEventListeners, createErrorEvent, createEvent, fireError, fireEvent, getEventListenerRegistrations, getEventListeners, isDetailEvents, removeEventListener, setDetailEvents`

  ### Methods inherited from class java.lang.Object

  `equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

  ### Methods inherited from interface org.apache.commons.configuration2.Configuration

  `addProperty, clear, clearProperty, getInterpolator, installInterpolator, setInterpolator, setProperty, subset`

  ### Methods inherited from interface org.apache.commons.configuration2.HierarchicalConfiguration

  `childConfigurationsAt, childConfigurationsAt, configurationAt, configurationAt, configurationsAt, configurationsAt`

  ### Methods inherited from interface org.apache.commons.configuration2.ImmutableConfiguration

  `containsKey, containsValue, entrySet, forEach, 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, getKeys, getList, getList, getList, getList, getLong, getLong, getLong, getProperties, getProperty, getShort, getShort, getShort, getString, getString, getStringArray, immutableSubset, isEmpty, size`

  ### Methods inherited from interface org.apache.commons.configuration2.ImmutableHierarchicalConfiguration

  `immutableChildConfigurationsAt, immutableConfigurationAt, immutableConfigurationAt, immutableConfigurationsAt`

  ### Methods inherited from interface org.apache.commons.configuration2.sync.SynchronizerSupport

  `getSynchronizer, lock, setSynchronizer, unlock`

- ## Constructor Details

  - ### AbstractHierarchicalConfiguration

    protected AbstractHierarchicalConfiguration(NodeModel<T> nodeModel)
    Creates a new instance of `AbstractHierarchicalConfiguration` and sets the `NodeModel` to be used.
    Parameters:
      `nodeModel` - the `NodeModel`

- ## Method Details

  - ### addNodes

    public final void addNodes(String key, Collection<? extends T> nodes)
    Adds a collection of nodes at the specified position of the configuration tree. This method works similar to `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()`.
    Specified by:
      `addNodes` in interface `HierarchicalConfiguration<T>`
    Parameters:
      `key` - the key where the nodes are to be added; can be null, then they are added to the root node
      `nodes` - a collection with the `Node` objects to be added

  - ### addNodesInternal

    protected void addNodesInternal(String key, Collection<? extends T> nodes)
    Actually adds a collection of new nodes to this configuration. This method is called by `addNodes()`. It can be overridden by subclasses that need to adapt this operation.
    Parameters:
      `key` - the key where the nodes are to be added; can be null, then they are added to the root node
      `nodes` - a collection with the `Node` objects to be added
    Since:
      2.0

  - ### addPropertyDirect

    protected void addPropertyDirect(String key, Object value)
    Adds a key/value pair to the Configuration. Override this method to provide write access to underlying Configuration store. This method is not called in the normal way (via `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.
    Specified by:
      `addPropertyDirect` in class `AbstractConfiguration`
    Parameters:
      `key` - key to use for mapping
      `value` - object to store

  - ### addPropertyInternal

    protected void addPropertyInternal(String key, Object obj)
    Adds the property with the specified key. This task will be delegated to the associated `ExpressionEngine`, so the passed in key must match the requirements of this implementation.
    Overrides:
      `addPropertyInternal` in class `AbstractConfiguration`
    Parameters:
      `key` - the key of the new property
      `obj` - the value of the new property

  - ### clearInternal

    protected void clearInternal()
    Clears this configuration. This is a more efficient implementation than the one inherited from the base class. It delegates to the node model.
    Overrides:
      `clearInternal` in class `AbstractConfiguration`

  - ### clearPropertyDirect

    protected void clearPropertyDirect(String key)
    Removes the property with the given key. Properties with names that start with the given key (i.e. properties below the specified key in the hierarchy) won't be affected. This implementation delegates to the node+ model.
    Specified by:
      `clearPropertyDirect` in class `AbstractConfiguration`
    Parameters:
      `key` - the key of the property to be removed

  - ### clearTree

    public final void clearTree(String key)
    Removes all values of the property with the given name and of keys that start with this name. So if there is a property with the key "foo" and a property with the key "foo.bar", a call of `clearTree("foo")` would remove both properties.
    Specified by:
      `clearTree` in interface `HierarchicalConfiguration<T>`
    Parameters:
      `key` - the key of the property to be removed

  - ### clearTreeInternal

    protected Object clearTreeInternal(String key)
    Actually clears the tree of elements referenced by the given key. This method is called by `clearTree()`. Subclasses that need to adapt this operation can override this method. This base implementation delegates to the node model.
    Parameters:
      `key` - the key of the property to be removed
    Returns:
      an object with information about the nodes that have been removed (this is needed for firing a meaningful event of type CLEAR_TREE)
    Since:
      2.0

  - ### clone

    public Object clone()
    Creates a copy of this object. This new configuration object will contain copies of all nodes in the same structure. Registered event listeners won't be cloned; so they are not registered at the returned copy.
    Overrides:
      `clone` in class `BaseEventSource`
    Returns:
      the copy
    Since:
      1.2

  - ### cloneNodeModel

    protected abstract NodeModel<T> cloneNodeModel()
    Creates a clone of the node model. This method is called by `clone()`.
    Returns:
      the clone of the `NodeModel`
    Since:
      2.0

  - ### containsKeyInternal

    protected boolean containsKeyInternal(String key)
    Checks if the specified key is contained in this configuration. Note that for this configuration the term "contained" means that the key has an associated value. If there is a node for this key that has no value but children (either defined or undefined), this method will still return false .
    Specified by:
      `containsKeyInternal` in class `AbstractConfiguration`
    Parameters:
      `key` - the key to be checked
    Returns:
      a flag if this key is contained in this configuration

  - ### containsValueInternal

    protected boolean containsValueInternal(Object value)
    Tests whether this configuration contains one or more matches to this value. This operation stops at first match but may be more expensive than the containsKey method.
    Specified by:
      `containsValueInternal` in class `AbstractConfiguration`
    Parameters:
      `value` - the value in question
    Returns:
      `true` if and only if some key maps to the `value` argument in this configuration as determined by the `equals` method; `false` otherwise.
    Since:
      2.11.0

  - ### fetchNodeList

    protected List<QueryResult<T>> fetchNodeList(String key)
    Helper method for resolving the specified key.
    Parameters:
      `key` - the key
    Returns:
      a list with all results selected by this key

  - ### getExpressionEngine

    public ExpressionEngine getExpressionEngine()
    Gets the expression engine used by this configuration. This method will never return null; if no specific expression engine was set, the default expression engine will be returned.
    Specified by:
      `getExpressionEngine` in interface `ImmutableHierarchicalConfiguration`
    Returns:
      the current expression engine
    Since:
      1.3

  - ### getKeysInternal

    protected Iterator<String> getKeysInternal()
    Gets an iterator with all keys defined in this configuration. Note that the keys returned by this method will not contain any indices. This means that some structure will be lost.
    Specified by:
      `getKeysInternal` in class `AbstractConfiguration`
    Returns:
      an iterator with the defined keys in this configuration

  - ### getKeysInternal

    protected Iterator<String> getKeysInternal(String prefix)
    Gets an iterator with all keys defined in this configuration that start with the given prefix. The returned keys will not contain any indices. This implementation tries to locate a node whose key is the same as the passed in prefix. Then the subtree of this node is traversed, and the keys of all nodes encountered (including attributes) are added to the result set.
    Overrides:
      `getKeysInternal` in class `AbstractConfiguration`
    Parameters:
      `prefix` - the prefix of the keys to start with
    Returns:
      an iterator with the found keys

  - ### getKeysInternal

    protected Iterator<String> getKeysInternal(String prefix, String delimiter)
    Gets an iterator with all keys defined in this configuration that start with the given prefix. The returned keys will not contain any indices. This implementation tries to locate a node whose key is the same as the passed in prefix. Then the subtree of this node is traversed, and the keys of all nodes encountered (including attributes) are added to the result set.
    Overrides:
      `getKeysInternal` in class `AbstractConfiguration`
    Parameters:
      `prefix` - the prefix of the keys to start with
      `delimiter` - the prefix delimiter (unused)
    Returns:
      an iterator with the found keys
    Since:
      2.12.0

  - ### getMaxIndex

    public final int getMaxIndex(String key)
    Gets the maximum defined index for the given key. This is useful if there are multiple values for this key. They can then be addressed separately by specifying indices from 0 to the return value of this method. If the passed in key is not contained in this configuration, result is -1.
    Specified by:
      `getMaxIndex` in interface `ImmutableHierarchicalConfiguration`
    Parameters:
      `key` - the key to be checked
    Returns:
      the maximum defined index for this key

  - ### getMaxIndexInternal

    protected int getMaxIndexInternal(String key)
    Actually retrieves the maximum defined index for the given key. This method is called by `getMaxIndex()`. Subclasses that need to adapt this operation have to override this method.
    Parameters:
      `key` - the key to be checked
    Returns:
      the maximum defined index for this key
    Since:
      2.0

  - ### getModel

    protected NodeModel<T> getModel()
    Gets the `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`.
    Returns:
      the node model

  - ### getNodeModel

    public NodeModel<T> getNodeModel()
    Gets the `NodeModel` supported by this object. This implementation returns the configuration's `NodeModel`. It is guarded by the current `Synchronizer`.
    Specified by:
      `getNodeModel` in interface `NodeModelSupport<T>`
    Returns:
      the `NodeModel`

  - ### getPropertyInternal

    protected Object getPropertyInternal(String key)
    Fetches the specified property. This task is delegated to the associated expression engine.
    Specified by:
      `getPropertyInternal` in class `AbstractConfiguration`
    Parameters:
      `key` - the key to be looked up
    Returns:
      the found value

  - ### getRootElementName

    public final String getRootElementName()
    Gets the name of the root element of this configuration. This information may be of use in some cases, for example for sub configurations created using the `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()`.
    Specified by:
      `getRootElementName` in interface `ImmutableHierarchicalConfiguration`
    Returns:
      the name of the root element of this configuration

  - ### getRootElementNameInternal

    protected String getRootElementNameInternal()
    Actually obtains the name of the root element. This method is called by `getRootElementName()`. It just returns the name of the root node. Subclasses that treat the root element name differently can override this method.
    Returns:
      the name of this configuration's root element

  - ### isEmptyInternal

    protected boolean isEmptyInternal()
    Checks if this configuration is empty. Empty means that there are no keys with any values, though there can be some (empty) nodes.
    Specified by:
      `isEmptyInternal` in class `AbstractConfiguration`
    Returns:
      a flag if this configuration is empty

  - ### nodeDefined

    protected boolean nodeDefined(T node)
    Checks if the specified node is defined.
    Parameters:
      `node` - the node to be checked
    Returns:
      a flag if this node is defined

  - ### nodeKey

    public String nodeKey(T node, Map<T,String> cache, NodeHandler<T> handler)
    Generates a unique key for the specified node. This method is used if keys have to be generated for nodes received as query results. An implementation must generate a canonical key which is compatible with the current expression engine. The passed in map can be used by an implementation as cache. It is created initially by the caller and then passed in subsequent calls. An implementation may use this to avoid that keys for nodes already encountered have to be generated again. This implementation uses the expression engine to generate a canonical key for the passed in node. For this purpose, the path to the root node has to be traversed. The cache is used to store and access keys for nodes encountered on the path.
    Specified by:
      `nodeKey` in interface `NodeKeyResolver<T>`
    Parameters:
      `node` - the node in question
      `cache` - a map serving as cache
      `handler` - the `NodeHandler`
    Returns:
      a key for the specified node

  - ### resolveAddKey

    public NodeAddData<T> resolveAddKey(T root, String key, NodeHandler<T> handler)
    Resolves a key of an add operation. Result is a `NodeAddData` object containing all information for actually performing the add operation at the specified key. This implementation delegates to the expression engine.
    Specified by:
      `resolveAddKey` in interface `NodeKeyResolver<T>`
    Parameters:
      `root` - the root node
      `key` - the key to be resolved
      `handler` - the `NodeHandler`
    Returns:
      a `NodeAddData` object to be used for the add operation

  - ### resolveKey

    public List<QueryResult<T>> resolveKey(T root, String key, NodeHandler<T> handler)
    Performs a query for the specified key on the given root node. This is a thin wrapper over the `query()` method of an `ExpressionEngine`. This implementation delegates to the expression engine.
    Specified by:
      `resolveKey` in interface `NodeKeyResolver<T>`
    Parameters:
      `root` - the root node
      `key` - the key to be resolved
      `handler` - the `NodeHandler`
    Returns:
      a list with query results

  - ### resolveNodeKey

    public 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. Some operations require results of type node and do not support attributes (for example for tracking nodes). This operation can be used in such cases. It works like `resolveKey()`, but filters only for results of type node. This implementation delegates to `resolveKey()` and then filters out attribute results.
    Specified by:
      `resolveNodeKey` in interface `NodeKeyResolver<T>`
    Parameters:
      `root` - the root node
      `key` - the key to be resolved
      `handler` - the `NodeHandler`
    Returns:
      a list with the resolved nodes

  - ### resolveUpdateKey

    public NodeUpdateData<T> resolveUpdateKey(T root, String key, Object newValue, NodeHandler<T> handler)
    Resolves a key for an update operation. Result is a `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.
    Specified by:
      `resolveUpdateKey` in interface `NodeKeyResolver<T>`
    Parameters:
      `root` - the root node
      `key` - the key to be resolved
      `newValue` - the new value for the key to be updated; this can be a single value or a container for multiple values
      `handler` - the `NodeHandler`
    Returns:
      a `NodeUpdateData` object to be used for this update operation

  - ### setExpressionEngine

    public void setExpressionEngine(ExpressionEngine expressionEngine)
    Sets the expression engine to be used by this configuration. All property keys this configuration has to deal with will be interpreted by this engine.
    Specified by:
      `setExpressionEngine` in interface `HierarchicalConfiguration<T>`
    Parameters:
      `expressionEngine` - the new expression engine; can be null, then the default expression engine will be used
    Since:
      1.3

  - ### setPropertyInternal

    protected void setPropertyInternal(String key, Object value)
    Sets the value of the specified property.
    Overrides:
      `setPropertyInternal` in class `AbstractConfiguration`
    Parameters:
      `key` - the key of the property to set
      `value` - the new value of this property

  - ### sizeInternal

    protected int sizeInternal()
    Actually calculates the size of this configuration. This method is called by `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.
    Overrides:
      `sizeInternal` in class `AbstractConfiguration`
    Returns:
      the size of this configuration (i.e. the number of keys)

  - ### toString

    public String toString()
    Overrides:
      `toString` in class `Object`