Class NodeTracker

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

final class NodeTracker extends Object

A class which can track specific nodes in an InMemoryNodeModel.

Sometimes it is necessary to keep track on a specific node, for instance when operating on a subtree of a model. For a model comprised of immutable nodes this is not trivial because each update of the model may cause the node to be replaced. So holding a direct pointer onto the target node is not an option; this instance may become outdated.

This class provides an API for selecting a specific node by using a NodeSelector. The selector is used to obtain an initial reference to the target node. It is then applied again after each update of the associated node model (which is done in the update() method). At this point of time two things can happen:

  • The NodeSelector associated with the tracked node still selects a single node. Then this node becomes the new tracked node. This may be the same instance as before or a new one.
  • The selector does no longer find the target node. This can happen for instance if it has been removed by an operation. In this case, the previous node instance is used. It is now detached from the model, but can still be used for operations on this subtree. It may even become life again after another update of the model.

Implementation note: This class is intended to work in a concurrent environment. Instances are immutable. The represented state can be updated by creating new instances which are then stored by the owning node model.

Since:
2.0
  • Field Details

  • Constructor Details

    • NodeTracker

      public NodeTracker()
      Creates a new instance of NodeTracker. This instance does not yet track any nodes.
    • NodeTracker

      private NodeTracker(Map<NodeSelector,NodeTracker.TrackedNodeData> map)
      Creates a new instance of NodeTracker and initializes it with the given map of tracked nodes. This constructor is used internally when the state of tracked nodes has changed.
      Parameters:
      map - the map with tracked nodes
  • Method Details

    • createEmptyTrackedNode

      private static ImmutableNode createEmptyTrackedNode(NodeTracker.TrackedNodeData data)
      Creates an empty node derived from the passed in TrackedNodeData object. This method is called if a tracked node got cleared by a transaction.
      Parameters:
      data - the TrackedNodeData
      Returns:
      the new node instance for this tracked node
    • detachedTrackedNodeData

      private static NodeTracker.TrackedNodeData detachedTrackedNodeData(NodeSelector txTarget, Map.Entry<NodeSelector,NodeTracker.TrackedNodeData> e)
      Creates a new TrackedNodeData object for a tracked node which becomes detached within the current transaction. This method checks whether the affected node is the root node of the current transaction. If so, it is cleared.
      Parameters:
      txTarget - the NodeSelector referencing the target node of the current transaction (may be null)
      e - the current selector and TrackedNodeData
      Returns:
      the new TrackedNodeData object to be used for this tracked node
    • determineUpdatedTrackedNodeData

      private static NodeTracker.TrackedNodeData determineUpdatedTrackedNodeData(ImmutableNode root, NodeSelector txTarget, NodeKeyResolver<ImmutableNode> resolver, NodeHandler<ImmutableNode> handler, Map.Entry<NodeSelector,NodeTracker.TrackedNodeData> e)
      Returns a TrackedNodeData object for an update operation. If the tracked node is still life, its selector is applied to the current root node. It may become detached if there is no match.
      Parameters:
      root - the root node
      txTarget - the NodeSelector referencing the target node of the current transaction (may be null)
      resolver - the NodeKeyResolver
      handler - the NodeHandler
      e - the current selector and TrackedNodeData
      Returns:
      the updated TrackedNodeData
    • trackDataForAddedObserver

      private static NodeTracker.TrackedNodeData trackDataForAddedObserver(ImmutableNode root, NodeSelector selector, NodeKeyResolver<ImmutableNode> resolver, NodeHandler<ImmutableNode> handler, NodeTracker.TrackedNodeData trackData)
      Creates a TrackedNodeData object for a newly added observer for the specified node selector.
      Parameters:
      root - the root node
      selector - the NodeSelector
      resolver - the NodeKeyResolver
      handler - the NodeHandler
      trackData - the current data for this selector
      Returns:
      the updated TrackedNodeData
      Throws:
      ConfigurationRuntimeException - if the selector does not select a single node
    • detachAllTrackedNodes

      public NodeTracker detachAllTrackedNodes()
      Marks all tracked nodes as detached. This method is called if there are some drastic changes on the underlying node structure, e.g. if the root node was replaced.
      Returns:
      the updated instance
    • getDetachedNodeModel

      public InMemoryNodeModel getDetachedNodeModel(NodeSelector selector)
      Gets the detached node model for the specified tracked node. When a node becomes detached, operations on it are independent from the original model. To implement this, a separate node model is created wrapping this tracked node. This model can be queried by this method. If the node affected is not detached, result is null.
      Parameters:
      selector - the NodeSelector
      Returns:
      the detached node model for this node or null
      Throws:
      ConfigurationRuntimeException - if no data for this selector is available
    • getTrackedNode

      public ImmutableNode getTrackedNode(NodeSelector selector)
      Gets the current ImmutableNode instance associated with the given selector.
      Parameters:
      selector - the NodeSelector
      Returns:
      the ImmutableNode selected by this selector
      Throws:
      ConfigurationRuntimeException - if no data for this selector is available
    • getTrackedNodeData

      private NodeTracker.TrackedNodeData getTrackedNodeData(NodeSelector selector)
      Obtains the TrackedNodeData object for the specified selector. If the selector cannot be resolved, an exception is thrown.
      Parameters:
      selector - the NodeSelector
      Returns:
      the TrackedNodeData object for this selector
      Throws:
      ConfigurationRuntimeException - if the selector cannot be resolved
    • isTrackedNodeDetached

      public boolean isTrackedNodeDetached(NodeSelector selector)
      Returns a flag whether the specified tracked node is detached.
      Parameters:
      selector - the NodeSelector
      Returns:
      a flag whether this node is detached
      Throws:
      ConfigurationRuntimeException - if no data for this selector is available
    • replaceAndDetachTrackedNode

      public NodeTracker replaceAndDetachTrackedNode(NodeSelector selector, ImmutableNode newNode)
      Replaces a tracked node by another one. This operation causes the tracked node to become detached.
      Parameters:
      selector - the NodeSelector
      newNode - the replacement node
      Returns:
      the updated instance
      Throws:
      ConfigurationRuntimeException - if the selector cannot be resolved
    • trackNode

      public NodeTracker trackNode(ImmutableNode root, NodeSelector selector, NodeKeyResolver<ImmutableNode> resolver, NodeHandler<ImmutableNode> handler)
      Adds a node to be tracked. The passed in selector must select exactly one target node, otherwise an exception is thrown. A new instance is created with the updated tracking state.
      Parameters:
      root - the root node
      selector - the NodeSelector
      resolver - the NodeKeyResolver
      handler - the NodeHandler
      Returns:
      the updated instance
      Throws:
      ConfigurationRuntimeException - if the selector does not select a single node
    • trackNodes

      public NodeTracker trackNodes(Collection<NodeSelector> selectors, Collection<ImmutableNode> nodes)
      Adds a number of nodes to be tracked. For each node in the passed in collection, a tracked node entry is created unless already one exists.
      Parameters:
      selectors - a collection with the NodeSelector objects
      nodes - a collection with the nodes to be tracked
      Returns:
      the updated instance
    • untrackNode

      public NodeTracker untrackNode(NodeSelector selector)
      Notifies this object that an observer was removed for the specified tracked node. If this was the last observer, the track data for this selector can be removed.
      Parameters:
      selector - the NodeSelector
      Returns:
      the updated instance
      Throws:
      ConfigurationRuntimeException - if no information about this node is available
    • update

      public NodeTracker update(ImmutableNode root, NodeSelector txTarget, NodeKeyResolver<ImmutableNode> resolver, NodeHandler<ImmutableNode> handler)
      Updates tracking information after the node structure has been changed. This method iterates over all tracked nodes. The selectors are evaluated again to update the node reference. If this fails for a selector, the previous node is reused; this tracked node is then detached. The passed in NodeSelector is the selector of the tracked node which is the target of the current transaction. (It is null if the transaction is not executed on a tracked node.) This is used to handle a special case: if the tracked node becomes detached by an operation targeting itself, this means that the node has been cleared by this operation. In this case, the previous node instance is not used, but an empty node is created.
      Parameters:
      root - the root node
      txTarget - the NodeSelector referencing the target node of the current transaction (may be null)
      resolver - the NodeKeyResolver
      handler - the NodeHandler
      Returns:
      the updated instance