Package org.apache.commons.configuration2.tree

# Class InMemoryNodeModel

java.lang.Object
org.apache.commons.configuration2.tree.InMemoryNodeModel

All Implemented Interfaces:
  `NodeModel<ImmutableNode>`

public class InMemoryNodeModel extends Object implements NodeModel<ImmutableNode>

A specialized node model implementation which operates on `ImmutableNode` structures.

This `NodeModel` implementation keeps all its data as a tree of `ImmutableNode` objects in memory. The managed structure can be manipulated in a thread-safe, non-blocking way. This is achieved by using atomic variables: The root of the tree is stored in an atomic reference variable. Each update operation causes a new structure to be constructed (which reuses as much from the original structure as possible). The old root node is then replaced by the new one using an atomic compare-and-set operation. If this fails, the manipulation has to be done anew on the updated structure.

Since:
  2.0

- ## Constructor Summary

  Constructors
  Constructor
  Description
  `InMemoryNodeModel()`
  Creates a new instance of `InMemoryNodeModel` which is initialized with an empty root node.
  `InMemoryNodeModel(ImmutableNode root)`
  Creates a new instance of `InMemoryNodeModel` and initializes it from the given root node.

- ## Method Summary

  Modifier and Type
  Method
  Description
  `void`
  `addNodes(String key, Collection<? extends ImmutableNode> nodes, NodeKeyResolver<ImmutableNode> resolver)`
  Adds a collection of new nodes to this model.
  `void`
  `addNodes(String key, NodeSelector selector, Collection<? extends ImmutableNode> nodes, NodeKeyResolver<ImmutableNode> resolver)`
  Adds new nodes using a tracked node as root node.
  `void`
  `addProperty(String key, Iterable<?> values, NodeKeyResolver<ImmutableNode> resolver)`
  Adds a new property to this node model consisting of an arbitrary number of values.
  `void`
  `addProperty(String key, NodeSelector selector, Iterable<?> values, NodeKeyResolver<ImmutableNode> resolver)`
  Adds new property values using a tracked node as root node.
  `void`
  `clear(NodeKeyResolver<ImmutableNode> resolver)`
  Removes all data from this model.
  `void`
  `clearProperty(String key, NodeKeyResolver<ImmutableNode> resolver)`
  Clears the value of a property.
  `void`
  `clearProperty(String key, NodeSelector selector, NodeKeyResolver<ImmutableNode> resolver)`
  Clears a property using a tracked node as root node.
  `List<QueryResult<ImmutableNode>>`
  `clearTree(String key, NodeKeyResolver<ImmutableNode> resolver)`
  Removes the sub trees defined by the given key from this model.
  `List<QueryResult<ImmutableNode>>`
  `clearTree(String key, NodeSelector selector, NodeKeyResolver<ImmutableNode> resolver)`
  Clears a whole sub tree using a tracked node as root node.
  `ImmutableNode`
  `getInMemoryRepresentation()`
  Gets a representation of the data stored in this model in form of a nodes hierarchy of `ImmutableNode` objects.
  `NodeHandler<ImmutableNode>`
  `getNodeHandler()`
  Gets a `NodeHandler` for dealing with the nodes managed by this model.
  `ReferenceNodeHandler`
  `getReferenceNodeHandler()`
  Gets a `ReferenceNodeHandler` object for this model.
  `ImmutableNode`
  `getRootNode()`
  Gets the root node of this mode.
  `ImmutableNode`
  `getTrackedNode(NodeSelector selector)`
  Gets the current `ImmutableNode` instance associated with the given `NodeSelector`.
  `NodeHandler<ImmutableNode>`
  `getTrackedNodeHandler(NodeSelector selector)`
  Gets a `NodeHandler` for a tracked node.
  `boolean`
  `isTrackedNodeDetached(NodeSelector selector)`
  Returns a flag whether the specified tracked node is detached.
  `void`
  `mergeRoot(ImmutableNode node, String rootName, Map<ImmutableNode,?> references, Object rootRef, NodeKeyResolver<ImmutableNode> resolver)`
  Merges the root node of this model with the specified node.
  `void`
  `replaceRoot(ImmutableNode newRoot, NodeKeyResolver<ImmutableNode> resolver)`
  Replaces the root node of this model.
  `void`
  `replaceTrackedNode(NodeSelector selector, ImmutableNode newNode)`
  Replaces a tracked node by another node.
  `Collection<NodeSelector>`
  `selectAndTrackNodes(String key, NodeKeyResolver<ImmutableNode> resolver)`
  Allows tracking all nodes selected by a key.
  `void`
  `setProperty(String key, Object value, NodeKeyResolver<ImmutableNode> resolver)`
  Changes the value of a property.
  `void`
  `setProperty(String key, NodeSelector selector, Object value, NodeKeyResolver<ImmutableNode> resolver)`
  Sets the value of a property using a tracked node as root node.
  `void`
  `setRootNode(ImmutableNode newRoot)`
  Sets a new root node for this model.
  `Collection<NodeSelector>`
  `trackChildNodes(String key, NodeKeyResolver<ImmutableNode> resolver)`
  Tracks all nodes which are children of the node selected by the passed in key.
  `NodeSelector`
  `trackChildNodeWithCreation(String key, String childName, NodeKeyResolver<ImmutableNode> resolver)`
  Tracks a node which is a child of another node selected by the passed in key.
  `void`
  `trackNode(NodeSelector selector, NodeKeyResolver<ImmutableNode> resolver)`
  Adds a node to be tracked.
  `void`
  `untrackNode(NodeSelector selector)`
  Removes a tracked node.

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

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

- ## Constructor Details

  - ### InMemoryNodeModel

    public InMemoryNodeModel()
    Creates a new instance of `InMemoryNodeModel` which is initialized with an empty root node.

  - ### InMemoryNodeModel

    public InMemoryNodeModel(ImmutableNode root)
    Creates a new instance of `InMemoryNodeModel` and initializes it from the given root node. If the passed in node is null, a new, empty root node is created.
    Parameters:
      `root` - the new root node for this model

- ## Method Details

  - ### addNodes

    public void addNodes(String key, Collection<? extends ImmutableNode> nodes, NodeKeyResolver<ImmutableNode> resolver)
    Description copied from interface: `NodeModel`
    Adds a collection of new nodes to this model. This operation corresponds to the `addNodes()` method of the `HierarchicalConfiguration` interface. The new nodes are either added to an existing node (if the passed in key selects exactly one node) or to a newly created node. The passed in `NodeKeyResolver` is used to interpret the given key.
    Specified by:
      `addNodes` in interface `NodeModel<ImmutableNode>`
    Parameters:
      `key` - the key
      `nodes` - the collection of nodes to be added (may be null)
      `resolver` - the `NodeKeyResolver`

  - ### addNodes

    public void addNodes(String key, NodeSelector selector, Collection<? extends ImmutableNode> nodes, NodeKeyResolver<ImmutableNode> resolver)
    Adds new nodes using a tracked node as root node. This method works like the normal `addNodes()` method, but the origin of the operation (also for the interpretation of the passed in key) is a tracked node identified by the passed in `NodeSelector`. The selector can be null, then the root node is assumed.
    Parameters:
      `key` - the key
      `selector` - the `NodeSelector` defining the root node (or null)
      `nodes` - the collection of new nodes to be added
      `resolver` - the `NodeKeyResolver`
    Throws:
      `ConfigurationRuntimeException` - if the selector cannot be resolved

  - ### addProperty

    public void addProperty(String key, Iterable<?> values, NodeKeyResolver<ImmutableNode> resolver)
    Description copied from interface: `NodeModel`
    Adds a new property to this node model consisting of an arbitrary number of values. The key for the add operation is provided. For each value a new node has to be added. The passed in resolver is queried for a `NodeAddData` object defining the add operation to be performed.
    Specified by:
      `addProperty` in interface `NodeModel<ImmutableNode>`
    Parameters:
      `key` - the key
      `values` - the values to be added at the position defined by the key
      `resolver` - the `NodeKeyResolver`

  - ### addProperty

    public void addProperty(String key, NodeSelector selector, Iterable<?> values, NodeKeyResolver<ImmutableNode> resolver)
    Adds new property values using a tracked node as root node. This method works like the normal `addProperty()` method, but the origin of the operation (also for the interpretation of the passed in key) is a tracked node identified by the passed in `NodeSelector`. The selector can be null, then the root node is assumed.
    Parameters:
      `key` - the key
      `selector` - the `NodeSelector` defining the root node (or null)
      `values` - the values to be added
      `resolver` - the `NodeKeyResolver`
    Throws:
      `ConfigurationRuntimeException` - if the selector cannot be resolved

  - ### clear

    public void clear(NodeKeyResolver<ImmutableNode> resolver)
    Removes all data from this model. A new empty root node is created with the same name as the current root node. Implementation note: Because this is a hard reset the usual dance for dealing with concurrent updates is not required here.
    Specified by:
      `clear` in interface `NodeModel<ImmutableNode>`
    Parameters:
      `resolver` - the `NodeKeyResolver`

  - ### clearProperty

    public void clearProperty(String key, NodeKeyResolver<ImmutableNode> resolver)
    Clears the value of a property. This method is similar to `NodeModel.clearTree(String, NodeKeyResolver)`: However, the nodes referenced by the passed in key are not removed completely, but only their value is set to null. If this operation leaves an affected node in an undefined state, it is removed from the model.
    Specified by:
      `clearProperty` in interface `NodeModel<ImmutableNode>`
    Parameters:
      `key` - the key selecting the properties to be cleared
      `resolver` - the `NodeKeyResolver`

  - ### clearProperty

    public void clearProperty(String key, NodeSelector selector, NodeKeyResolver<ImmutableNode> resolver)
    Clears a property using a tracked node as root node. This method works like the normal `clearProperty()` method, but the origin of the operation (also for the interpretation of the passed in key) is a tracked node identified by the passed in `NodeSelector`. The selector can be null, then the root node is assumed.
    Parameters:
      `key` - the key
      `selector` - the `NodeSelector` defining the root node (or null)
      `resolver` - the `NodeKeyResolver`
    Throws:
      `ConfigurationRuntimeException` - if the selector cannot be resolved

  - ### clearTree

    public List<QueryResult<ImmutableNode>> clearTree(String key, NodeKeyResolver<ImmutableNode> resolver)
    Removes the sub trees defined by the given key from this model. All nodes selected by this key are retrieved from the specified `NodeKeyResolver` and removed from the model. This implementation checks whether nodes become undefined after subtrees have been removed. If this is the case, such nodes are removed, too. Return value is a collection with `QueryResult` objects for the elements to be removed from the model.
    Specified by:
      `clearTree` in interface `NodeModel<ImmutableNode>`
    Parameters:
      `key` - the key selecting the properties to be removed
      `resolver` - the `NodeKeyResolver`
    Returns:
      an object with information about the data removed

  - ### clearTree

    public List<QueryResult<ImmutableNode>> clearTree(String key, NodeSelector selector, NodeKeyResolver<ImmutableNode> resolver)
    Clears a whole sub tree using a tracked node as root node. This method works like the normal `clearTree()` method, but the origin of the operation (also for the interpretation of the passed in key) is a tracked node identified by the passed in `NodeSelector`. The selector can be null, then the root node is assumed.
    Parameters:
      `key` - the key
      `selector` - the `NodeSelector` defining the root node (or null)
      `resolver` - the `NodeKeyResolver`
    Returns:
      a list with the results to be removed
    Throws:
      `ConfigurationRuntimeException` - if the selector cannot be resolved

  - ### getInMemoryRepresentation

    public ImmutableNode getInMemoryRepresentation()
    Gets a representation of the data stored in this model in form of a nodes hierarchy of `ImmutableNode` objects. A concrete model implementation can use an arbitrary means to store its data. When a model's data is to be used together with other functionality of the Configuration library (for example when combining multiple configuration sources) it has to be transformed into a common format. This is done by this method. `ImmutableNode` is a generic representation of a hierarchical structure. Thus, it should be possible to generate a corresponding structure from arbitrary model data. This implementation simply returns the current root node of this model.
    Specified by:
      `getInMemoryRepresentation` in interface `NodeModel<ImmutableNode>`
    Returns:
      the root node of an in-memory hierarchy representing the data stored in this model

  - ### getNodeHandler

    public NodeHandler<ImmutableNode> getNodeHandler()
    Gets a `NodeHandler` for dealing with the nodes managed by this model. `InMemoryNodeModel` implements the `NodeHandler` interface itself. So this implementation just returns the this reference.
    Specified by:
      `getNodeHandler` in interface `NodeModel<ImmutableNode>`
    Returns:
      the `NodeHandler`

  - ### getReferenceNodeHandler

    public ReferenceNodeHandler getReferenceNodeHandler()
    Gets a `ReferenceNodeHandler` object for this model. This extended node handler can be used to query references objects stored for this model.
    Returns:
      the `ReferenceNodeHandler`

  - ### getRootNode

    public ImmutableNode getRootNode()
    Gets the root node of this mode. Note: This method should be used with care. The model may be updated concurrently which causes the root node to be replaced. If the root node is to be processed further (for example by executing queries on it), the model should be asked for its `NodeHandler`, and the root node should be obtained from there. The connection between a node handler and its root node remain constant because an update of the model causes the whole node handler to be replaced.
    Returns:
      the current root node

  - ### getTrackedNode

    public ImmutableNode getTrackedNode(NodeSelector selector)
    Gets the current `ImmutableNode` instance associated with the given `NodeSelector`. The node must be a tracked node, i.e. `trackNode(NodeSelector, NodeKeyResolver)` must have been called before with the given selector.
    Parameters:
      `selector` - the `NodeSelector` defining the desired node
    Returns:
      the current `ImmutableNode` associated with this selector
    Throws:
      `ConfigurationRuntimeException` - if the selector is unknown

  - ### getTrackedNodeHandler

    public NodeHandler<ImmutableNode> getTrackedNodeHandler(NodeSelector selector)
    Gets a `NodeHandler` for a tracked node. Such a handler may be required for operations on a sub tree of the model. The handler to be returned depends on the current state of the tracked node. If it is still active, a handler is used which shares some data (especially the parent mapping) with this model. Detached track nodes in contrast have their own separate model; in this case a handler associated with this model is returned.
    Parameters:
      `selector` - the `NodeSelector` defining the tracked node
    Returns:
      a `NodeHandler` for this tracked node
    Throws:
      `ConfigurationRuntimeException` - if the selector is unknown

  - ### isTrackedNodeDetached

    public boolean isTrackedNodeDetached(NodeSelector selector)
    Returns a flag whether the specified tracked node is detached. As long as the `NodeSelector` associated with that node returns a single instance, the tracked node is said to be life. If now an update of the model happens which invalidates the selector (maybe the target node was removed), the tracked node becomes detached. It is still possible to query the node; here the latest valid instance is returned. But further changes on the node model are no longer tracked for this node. So even if there are further changes which would make the `NodeSelector` valid again, the tracked node stays in detached state.
    Parameters:
      `selector` - the `NodeSelector` defining the desired node
    Returns:
      a flag whether this tracked node is in detached state
    Throws:
      `ConfigurationRuntimeException` - if the selector is unknown

  - ### mergeRoot

    public void mergeRoot(ImmutableNode node, String rootName, Map<ImmutableNode,?> references, Object rootRef, NodeKeyResolver<ImmutableNode> resolver)
    Merges the root node of this model with the specified node. This method is typically caused by configuration implementations when a configuration source is loaded, and its data has to be added to the model. It is possible to define the new name of the root node and to pass in a map with reference objects.
    Parameters:
      `node` - the node to be merged with the root node
      `rootName` - the new name of the root node; can be null, then the name of the root node is not changed unless it is null
      `references` - an optional map with reference objects
      `rootRef` - an optional reference object for the new root node
      `resolver` - the `NodeKeyResolver`

  - ### replaceRoot

    public void replaceRoot(ImmutableNode newRoot, NodeKeyResolver<ImmutableNode> resolver)
    Replaces the root node of this model. This method is similar to `setRootNode(ImmutableNode)`; however, tracked nodes will not get lost. The model applies the selectors of all tracked nodes on the new nodes hierarchy, so that corresponding nodes are selected (this may cause nodes to become detached if a select operation fails). This operation is useful if the new nodes hierarchy to be set is known to be similar to the old one. Note that reference objects are lost; there is no way to automatically match nodes between the old and the new nodes hierarchy.
    Parameters:
      `newRoot` - the new root node to be set (must not be null)
      `resolver` - the `NodeKeyResolver`
    Throws:
      `IllegalArgumentException` - if the new root node is null

  - ### replaceTrackedNode

    public void replaceTrackedNode(NodeSelector selector, ImmutableNode newNode)
    Replaces a tracked node by another node. If the tracked node is not yet detached, it becomes now detached. The passed in node (which must not be null) becomes the new root node of an independent model for this tracked node. Further updates of this model do not affect the tracked node's model and vice versa.
    Parameters:
      `selector` - the `NodeSelector` defining the tracked node
      `newNode` - the node replacing the tracked node (must not be null)
    Throws:
      `ConfigurationRuntimeException` - if the selector cannot be resolved
      `IllegalArgumentException` - if the replacement node is null

  - ### selectAndTrackNodes

    public Collection<NodeSelector> selectAndTrackNodes(String key, NodeKeyResolver<ImmutableNode> resolver)
    Allows tracking all nodes selected by a key. This method evaluates the specified key on the current nodes structure. For all selected nodes corresponding `NodeSelector` objects are created, and they are tracked. The returned collection of `NodeSelector` objects can be used for interacting with the selected nodes.
    Parameters:
      `key` - the key for selecting the nodes to track
      `resolver` - the `NodeKeyResolver`
    Returns:
      a collection with the `NodeSelector` objects for the new tracked nodes

  - ### setProperty

    public void setProperty(String key, NodeSelector selector, Object value, NodeKeyResolver<ImmutableNode> resolver)
    Sets the value of a property using a tracked node as root node. This method works like the normal `setProperty()` method, but the origin of the operation (also for the interpretation of the passed in key) is a tracked node identified by the passed in `NodeSelector`. The selector can be null, then the root node is assumed.
    Parameters:
      `key` - the key
      `selector` - the `NodeSelector` defining the root node (or null)
      `value` - the new value for this property
      `resolver` - the `NodeKeyResolver`
    Throws:
      `ConfigurationRuntimeException` - if the selector cannot be resolved

  - ### setProperty

    public void setProperty(String key, Object value, NodeKeyResolver<ImmutableNode> resolver)
    Description copied from interface: `NodeModel`
    Changes the value of a property. This is a more complex operation as it might involve adding, updating, or deleting nodes and attributes from the model. The object representing the new value is passed to the `NodeKeyResolver` which will produce a corresponding `NodeUpdateData` object. Based on the content of this object, update operations are performed.
    Specified by:
      `setProperty` in interface `NodeModel<ImmutableNode>`
    Parameters:
      `key` - the key
      `value` - the new value for this property (to be evaluated by the `NodeKeyResolver`)
      `resolver` - the `NodeKeyResolver`

  - ### setRootNode

    public void setRootNode(ImmutableNode newRoot)
    Sets a new root node for this model. The whole structure is replaced by the new node and its children. All tracked nodes and reference objects managed by this model are cleared.Care has to be taken when this method is used and the model is accessed by multiple threads. It is not deterministic which concurrent operations see the old root and which see the new root node.
    Specified by:
      `setRootNode` in interface `NodeModel<ImmutableNode>`
    Parameters:
      `newRoot` - the new root node to be set (can be null, then an empty root node is set)

  - ### trackChildNodes

    public Collection<NodeSelector> trackChildNodes(String key, NodeKeyResolver<ImmutableNode> resolver)
    Tracks all nodes which are children of the node selected by the passed in key. If the key selects exactly one node, for all children of this node `NodeSelector` objects are created, and they become tracked nodes. The returned collection of `NodeSelector` objects can be used for interacting with the selected nodes.
    Parameters:
      `key` - the key for selecting the parent node whose children are to be tracked
      `resolver` - the `NodeKeyResolver`
    Returns:
      a collection with the `NodeSelector` objects for the new tracked nodes

  - ### trackChildNodeWithCreation

    public NodeSelector trackChildNodeWithCreation(String key, String childName, NodeKeyResolver<ImmutableNode> resolver)
    Tracks a node which is a child of another node selected by the passed in key. If the selected node has a child node with this name, it is tracked and its selector is returned. Otherwise, a new child node with this name is created first.
    Parameters:
      `key` - the key for selecting the parent node
      `childName` - the name of the child node
      `resolver` - the `NodeKeyResolver`
    Returns:
      the `NodeSelector` for the tracked child node
    Throws:
      `ConfigurationRuntimeException` - if the passed in key does not select a single node

  - ### trackNode

    public void trackNode(NodeSelector selector, NodeKeyResolver<ImmutableNode> resolver)
    Adds a node to be tracked. After this method has been called with a specific `NodeSelector`, the node associated with this key can be always obtained using `getTrackedNode(NodeSelector)` with the same selector. This is useful because during updates of a model parts of the structure are replaced. Therefore, it is not a good idea to simply hold a reference to a node; this might become outdated soon. Rather, the node should be tracked. This mechanism ensures that always the correct node reference can be obtained.
    Parameters:
      `selector` - the `NodeSelector` defining the desired node
      `resolver` - the `NodeKeyResolver`
    Throws:
      `ConfigurationRuntimeException` - if the selector does not select a single node

  - ### untrackNode

    public void untrackNode(NodeSelector selector)
    Removes a tracked node. This method is the opposite of `trackNode()`. It has to be called if there is no longer the need to track a specific node. Note that for each call of `trackNode()` there has to be a corresponding `untrackNode()` call. This ensures that multiple observers can track the same node.
    Parameters:
      `selector` - the `NodeSelector` defining the desired node
    Throws:
      `ConfigurationRuntimeException` - if the specified node is not tracked