Class ModelTransaction


  • final class ModelTransaction
    extends java.lang.Object

    An internal helper class for a atomic updates of an InMemoryNodeModel.

    This class performs updates on the node structure of a node model consisting of ImmutableNode objects. Because the nodes themselves cannot be changed updates are achieved by replacing parts of the structure with new nodes; the new nodes are copies of original nodes with the corresponding manipulations applied. Therefore, each update of a node in the structure results in a new structure in which the affected node is replaced by a new one, and this change bubbles up to the root node (because all parent nodes have to be replaced by instances with an updated child reference).

    A single update of a model may consist of multiple changes on nodes. For instance, a remove property operation can include many nodes. There are some reasons why such updates should be handled in a single "transaction" rather than executing them on altered node structures one by one:

    • An operation is typically executed on a set of source nodes from the original node hierarchy. While manipulating nodes, nodes of this set may be replaced by new ones. The handling of these replacements complicates things a lot.
    • Performing all updates one after the other may cause more updates of nodes than necessary. Nodes near to the root node always have to be replaced when a child of them gets manipulated. If all these updates are deferred and handled in a single transaction, the resulting operation is more efficient.

    • Field Detail

      • MAX_REPLACEMENTS

        private static final int MAX_REPLACEMENTS
        Constant for the maximum number of entries in the replacement mapping. If this number is exceeded, the parent mapping is reconstructed. The number is a bit arbitrary. If it is too low, updates - especially on large node structures - are expensive because the parent mapping is often rebuild. If it is too big, read access to the model is slowed down because looking up the parent of a node is more complicated.
        See Also:
        Constant Field Values
      • LEVEL_UNKNOWN

        private static final int LEVEL_UNKNOWN
        Constant for an unknown level.
        See Also:
        Constant Field Values
      • currentData

        private final TreeData currentData
        Stores the current tree data of the calling node model.
      • queryRoot

        private final ImmutableNode queryRoot
        The root node for query operations.
      • rootNodeSelector

        private final NodeSelector rootNodeSelector
        The selector to the root node of this transaction.
      • replacedNodes

        private final java.util.Map<ImmutableNode,​ImmutableNode> replacedNodes
        The nodes replaced in this transaction.
      • addedNodes

        private final java.util.Collection<ImmutableNode> addedNodes
        A collection with nodes which have been added.
      • removedNodes

        private final java.util.Collection<ImmutableNode> removedNodes
        A collection with nodes which have been removed.
      • allRemovedNodes

        private final java.util.Collection<ImmutableNode> allRemovedNodes
        Stores all nodes which have been removed in this transaction (not only the root nodes of removed trees).
      • operations

        private final java.util.SortedMap<java.lang.Integer,​java.util.Map<ImmutableNode,​ModelTransaction.Operations>> operations
        Stores the operations to be executed during this transaction. The map is sorted by the levels of the nodes to be manipulated: Operations on nodes down in the hierarchy are executed first because they affect the nodes closer to the root.
      • newReferences

        private java.util.Map<ImmutableNode,​java.lang.Object> newReferences
        A map with reference objects to be added during this transaction.
    • Constructor Detail

      • ModelTransaction

        public ModelTransaction​(TreeData treeData,
                                NodeSelector selector,
                                NodeKeyResolver<ImmutableNode> resolver)
        Creates a new instance of ModelTransaction for the current tree data.
        Parameters:
        treeData - the current TreeData structure to operate on
        selector - an optional NodeSelector defining the target root node for this transaction; this can be used to perform operations on tracked nodes
        resolver - the NodeKeyResolver
    • Method Detail

      • append

        private static <E> java.util.Collection<E> append​(java.util.Collection<E> col,
                                                          E node)
        Appends a single element to a collection. The collection may be null, then it is created.
        Type Parameters:
        E - the type of elements involved
        Parameters:
        col - the collection
        node - the element to be added
        Returns:
        the resulting collection
      • append

        private static <K,​V> java.util.Map<K,​V> append​(java.util.Map<K,​V> map,
                                                                   K key,
                                                                   V value)
        Adds a single key-value pair to a map. The map may be null, then it is created.
        Type Parameters:
        K - the type of the key
        V - the type of the value
        Parameters:
        map - the map
        key - the key
        value - the value
        Returns:
        the resulting map
      • append

        private static <E> java.util.Set<E> append​(java.util.Set<E> col,
                                                   E elem)
        Appends a single element to a set. The set may be null then it is created.
        Type Parameters:
        E - the type of the elements involved
        Parameters:
        col - the set
        elem - the element to be added
        Returns:
        the resulting set
      • concatenate

        private static <E> java.util.Collection<E> concatenate​(java.util.Collection<E> col1,
                                                               java.util.Collection<? extends E> col2)
        Constructs the concatenation of two collections. Both can be null.
        Type Parameters:
        E - the type of the elements involved
        Parameters:
        col1 - the first collection
        col2 - the second collection
        Returns:
        the resulting collection
      • concatenate

        private static <K,​V> java.util.Map<K,​V> concatenate​(java.util.Map<K,​V> map1,
                                                                        java.util.Map<? extends K,​? extends V> map2)
        Constructs the concatenation of two maps. Both can be null.
        Type Parameters:
        K - the type of the keys
        V - the type of the values
        Parameters:
        map1 - the first map
        map2 - the second map
        Returns:
        the resulting map
      • concatenate

        private static <E> java.util.Set<E> concatenate​(java.util.Set<E> set1,
                                                        java.util.Set<? extends E> set2)
        Constructs the concatenation of two sets. Both can be null.
        Type Parameters:
        E - the type of the elements involved
        Parameters:
        set1 - the first set
        set2 - the second set
        Returns:
        the resulting set
      • addAddNodeOperation

        public void addAddNodeOperation​(ImmutableNode parent,
                                        ImmutableNode newChild)
        Adds an operation for adding a new child to a given parent node.
        Parameters:
        parent - the parent node
        newChild - the new child to be added
      • addAddNodesOperation

        public void addAddNodesOperation​(ImmutableNode parent,
                                         java.util.Collection<? extends ImmutableNode> newNodes)
        Adds an operation for adding a number of new children to a given parent node.
        Parameters:
        parent - the parent node
        newNodes - the collection of new child nodes
      • addAttributeOperation

        public void addAttributeOperation​(ImmutableNode target,
                                          java.lang.String name,
                                          java.lang.Object value)
        Adds an operation for adding an attribute to a target node.
        Parameters:
        target - the target node
        name - the name of the attribute
        value - the value of the attribute
      • addAttributesOperation

        public void addAttributesOperation​(ImmutableNode target,
                                           java.util.Map<java.lang.String,​java.lang.Object> attributes)
        Adds an operation for adding multiple attributes to a target node.
        Parameters:
        target - the target node
        attributes - the map with attributes to be set
      • addChangeNodeNameOperation

        public void addChangeNodeNameOperation​(ImmutableNode target,
                                               java.lang.String newName)
        Adds an operation for changing the name of a target node.
        Parameters:
        target - the target node
        newName - the new name for this node
      • addChangeNodeValueOperation

        public void addChangeNodeValueOperation​(ImmutableNode target,
                                                java.lang.Object newValue)
        Adds an operation for changing the value of a target node.
        Parameters:
        target - the target node
        newValue - the new value for this node
      • addClearNodeValueOperation

        public void addClearNodeValueOperation​(ImmutableNode target)
        Adds an operation for clearing the value of a target node.
        Parameters:
        target - the target node
      • addNewReference

        public void addNewReference​(ImmutableNode node,
                                    java.lang.Object ref)
        Adds a new reference object for the given node.
        Parameters:
        node - the affected node
        ref - the reference object for this node
      • addNewReferences

        public void addNewReferences​(java.util.Map<ImmutableNode,​?> refs)
        Adds a map with new reference objects. The entries in this map are passed to the ReferenceTracker during execution of this transaction.
        Parameters:
        refs - the map with new reference objects
      • addRemoveAttributeOperation

        public void addRemoveAttributeOperation​(ImmutableNode target,
                                                java.lang.String name)
        Adds an operation for removing an attribute from a target node.
        Parameters:
        target - the target node
        name - the name of the attribute
      • addRemoveNodeOperation

        public void addRemoveNodeOperation​(ImmutableNode parent,
                                           ImmutableNode node)
        Adds an operation for removing a child node of a given node.
        Parameters:
        parent - the parent node
        node - the child node to be removed
      • execute

        public TreeData execute()
        Executes this transaction resulting in a new TreeData object. The object returned by this method serves as the definition of a new node structure for the calling model.
        Returns:
        the updated TreeData
      • executeOperations

        private void executeOperations()
        Executes all operations in this transaction.
      • fetchOperations

        ModelTransaction.Operations fetchOperations​(ImmutableNode target,
                                                    int level)
        Obtains the Operations object for manipulating the specified node. If no such object exists yet, it is created. The level can be undefined, then it is determined based on the target node.
        Parameters:
        target - the target node
        level - the level of the target node (may be undefined)
        Returns:
        the Operations object for this node
      • fetchReferenceMap

        private java.util.Map<ImmutableNode,​java.lang.Object> fetchReferenceMap()
        Returns the map with new reference objects. It is created if necessary.
        Returns:
        the map with reference objects
      • getCurrentData

        public TreeData getCurrentData()
        Gets the current TreeData object this transaction operates on.
        Returns:
        the associated TreeData object
      • getParent

        ImmutableNode getParent​(ImmutableNode node)
        Gets the parent node of the given node.
        Parameters:
        node - the node in question
        Returns:
        the parent of this node
      • getQueryRoot

        public ImmutableNode getQueryRoot()
        Gets the root node to be used within queries. This is not necessarily the current root node of the model. If the operation is executed on a tracked node, this node has to be passed as root nodes to the expression engine.
        Returns:
        the root node for queries and calls to the expression engine
      • getResolver

        public NodeKeyResolver<ImmutableNode> getResolver()
        Gets the NodeKeyResolver used by this transaction.
        Returns:
        the NodeKeyResolver
      • initQueryRoot

        private ImmutableNode initQueryRoot​(TreeData treeData,
                                            NodeSelector selector)
        Initializes the root node to be used within queries. If a tracked node selector is provided, this node becomes the root node. Otherwise, the actual root node is used.
        Parameters:
        treeData - the current data of the model
        selector - an optional NodeSelector defining the target root
        Returns:
        the query root node for this transaction
      • level

        private int level​(ImmutableNode node)
        Determines the level of the specified node in the current hierarchy. The level of the root node is 0, the children of the root have level 1 and so on.
        Parameters:
        node - the node in question
        Returns:
        the level of this node
      • rebuildParentMapping

        private void rebuildParentMapping()
        Rebuilds the parent mapping from scratch. This method is called if the replacement mapping exceeds its maximum size. In this case, it is cleared, and a new parent mapping is constructed for the new root node.
      • removeNodeFromReplacementMapping

        private void removeNodeFromReplacementMapping​(ImmutableNode node)
        Removes the specified node completely from the replacement mapping. This also includes the nodes that replace the given one.
        Parameters:
        node - the node to be removed
      • removeNodesFromParentAndReplacementMapping

        private void removeNodesFromParentAndReplacementMapping​(ImmutableNode root)
        Removes a node and its children (recursively) from the parent and the replacement mappings.
        Parameters:
        root - the root of the subtree to be removed
      • updateParentMapping

        private void updateParentMapping()
        Updates the parent mapping for the resulting TreeData instance. This method is called after all update operations have been executed. It ensures that the parent mapping is updated for the changes on the nodes structure.
      • updateParentMappingForAddedNodes

        private void updateParentMappingForAddedNodes()
        Adds newly added nodes and their children to the parent mapping.
      • updateParentMappingForRemovedNodes

        private void updateParentMappingForRemovedNodes()
        Removes nodes that have been removed during this transaction from the parent and replacement mappings.
      • updateReferenceTracker

        private ReferenceTracker updateReferenceTracker()
        Returns an updated ReferenceTracker instance. The changes performed during this transaction are applied to the tracker.
        Returns:
        the updated tracker instance