Class MemoryNodeBuilder

  • All Implemented Interfaces:
    NodeBuilder
    Direct Known Subclasses:
    SegmentNodeBuilder

    public class MemoryNodeBuilder
    extends java.lang.Object
    implements NodeBuilder
    In-memory node state builder.

    A MemoryNodeBuilder instance tracks uncommitted changes without relying on weak references or requiring hard references on the entire accessed subtree. It does this by relying on MutableNodeState instances for tracking uncommitted changes and on Head instances for tracking the connectedness of the builder. A builder keeps a reference to the parent builder and knows its own name, which is used to check for relevant changes in its parent builder and update its state accordingly.

    A builder is in one of three possible states, which is tracked within its Head instance:

    unconnected
    A child builder with no content changes starts in this state. Before each access the unconnected builder checks its parent for relevant changes.
    connected
    Once a builder is first modified, it switches to the connected state and records all modification in a shared MutableNodeState instance. Before each access the connected builder checks whether its parents base state has been reset and if so, resets its own base state accordingly.
    root
    Same as the connected state but only the root of the builder hierarchy can have this state.
    • Constructor Summary

      Constructors 
      Modifier Constructor Description
        MemoryNodeBuilder​(@NotNull NodeState base)
      Creates a new in-memory node state builder rooted at and based on the passed base state.
      protected MemoryNodeBuilder​(MemoryNodeBuilder parent, java.lang.String name)
      Creates a new in-memory child builder.
    • Method Summary

      All Methods Instance Methods Concrete Methods 
      Modifier and Type Method Description
      protected void annotateSourcePath()
      Annotate this builder with its source path if this builder has not been transiently added.
      @NotNull NodeBuilder child​(@NotNull java.lang.String name)
      Returns a builder for constructing changes to the named child node.
      Blob createBlob​(java.io.InputStream stream)  
      protected MemoryNodeBuilder createChildBuilder​(java.lang.String name)
      Factory method for creating new child state builders.
      boolean exists()
      Checks whether this builder represents a node that exists.
      @NotNull NodeState getBaseState()
      Returns the original base state that this builder is modifying.
      boolean getBoolean​(@NotNull java.lang.String name)
      Returns the boolean value of the named property.
      @NotNull NodeBuilder getChildNode​(@NotNull java.lang.String name)
      Returns a builder for constructing changes to the named child node.
      long getChildNodeCount​(long max)
      Returns the current number of child nodes.
      @NotNull java.lang.Iterable<java.lang.String> getChildNodeNames()
      Returns the names of current child nodes.
      protected java.lang.String getName()
      Accessor for name
      @Nullable java.lang.String getName​(@NotNull java.lang.String name)
      Returns the name value of the named property.
      @NotNull java.lang.Iterable<java.lang.String> getNames​(@NotNull java.lang.String name)
      Returns the name values of the named property.
      @NotNull NodeState getNodeState()
      Returns an immutable node state that matches the current state of the builder.
      protected MemoryNodeBuilder getParent()
      Accessor for parent builder
      java.lang.String getPath()  
      @NotNull java.lang.Iterable<? extends PropertyState> getProperties()
      Returns the current properties.
      PropertyState getProperty​(java.lang.String name)
      Returns the current state of the named property, or null if the property is not set.
      long getPropertyCount()
      Returns the current number of properties.
      @Nullable java.lang.String getString​(@NotNull java.lang.String name)
      Returns the name value of the named property.
      boolean hasChildNode​(@NotNull java.lang.String name)
      Checks whether the named child node currently exists.
      boolean hasProperty​(java.lang.String name)
      Checks whether the named property exists.
      boolean isModified()
      Check whether this builder represents a modified node, which has either modified properties or removed or added child nodes.
      boolean isNew()
      Check whether this builder represents a new node, which is not present in the base state.
      boolean isNew​(java.lang.String name)
      Check whether the named property is new, i.e.
      boolean isReplaced()
      Check whether this builder represents a node that used to exist but was then replaced with other content, for example as a result of a NodeBuilder.setChildNode(String) call.
      boolean isReplaced​(java.lang.String name)
      Check whether the named property exists in the base state but is replaced with other content, for example as a result of a NodeBuilder.setProperty(PropertyState) call.
      boolean isRoot()  
      boolean moveTo​(@NotNull NodeBuilder newParent, @NotNull java.lang.String newName)
      This implementation has the same semantics as adding this node with name newName as a new child of newParent followed by removing this node.
      boolean remove()
      Remove this child node from its parent.
      @NotNull NodeBuilder removeProperty​(java.lang.String name)
      Remove the named property.
      void reset​(@NotNull NodeState newBase)
      Throws away all changes in this builder and resets the base to the given node state.
      protected void set​(NodeState newState)
      Replaces the current state of this builder with the given node state.
      @NotNull NodeBuilder setChildNode​(@NotNull java.lang.String name)
      Adds the named child node and returns a builder for modifying it.
      @NotNull NodeBuilder setChildNode​(@NotNull java.lang.String name, @NotNull NodeState state)
      Adds or replaces a subtree.
      @NotNull NodeBuilder setProperty​(@NotNull PropertyState property)
      Set a property state
      <T> @NotNull NodeBuilder setProperty​(java.lang.String name, T value)
      Set a property state
      <T> @NotNull NodeBuilder setProperty​(java.lang.String name, T value, Type<T> type)
      Set a property state
      java.lang.String toString()  
      protected void updated()
      Called whenever this node is modified, i.e.
      • Methods inherited from class java.lang.Object

        clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait
    • Constructor Detail

      • MemoryNodeBuilder

        protected MemoryNodeBuilder​(MemoryNodeBuilder parent,
                                    java.lang.String name)
        Creates a new in-memory child builder.
        Parameters:
        parent - parent builder
        name - name of this node
      • MemoryNodeBuilder

        public MemoryNodeBuilder​(@NotNull
                                 @NotNull NodeState base)
        Creates a new in-memory node state builder rooted at and based on the passed base state.
        Parameters:
        base - base state of the new builder
    • Method Detail

      • isRoot

        public final boolean isRoot()
        Returns:
        true iff this is the root builder
      • createChildBuilder

        protected MemoryNodeBuilder createChildBuilder​(java.lang.String name)
        Factory method for creating new child state builders. Subclasses may override this method to control the behavior of child state builders.
        Returns:
        new builder
      • updated

        protected void updated()
        Called whenever this node is modified, i.e. a property is added, changed or removed, or a child node is added or removed. Changes inside child nodes or the subtrees below are not reported. The default implementation triggers an updated() call on the root builder (unless this is already the root builder), which subclasses can use to capture aggregate update information across the whole tree.
      • getParent

        protected final MemoryNodeBuilder getParent()
        Accessor for parent builder
      • getName

        protected final java.lang.String getName()
        Accessor for name
      • reset

        public void reset​(@NotNull
                          @NotNull NodeState newBase)
        Throws away all changes in this builder and resets the base to the given node state.
        Parameters:
        newBase - new base state
      • set

        protected void set​(NodeState newState)
        Replaces the current state of this builder with the given node state. The base state remains unchanged.
        Parameters:
        newState - new state
      • getNodeState

        @NotNull
        public @NotNull NodeState getNodeState()
        Description copied from interface: NodeBuilder
        Returns an immutable node state that matches the current state of the builder.
        Specified by:
        getNodeState in interface NodeBuilder
        Returns:
        immutable node state
      • getBaseState

        @NotNull
        public @NotNull NodeState getBaseState()
        Description copied from interface: NodeBuilder
        Returns the original base state that this builder is modifying. The return value may be non-existent (i.e. its exists method returns false) if this builder represents a new node that didn't exist in the base content tree.
        Specified by:
        getBaseState in interface NodeBuilder
        Returns:
        base node state, possibly non-existent
      • exists

        public boolean exists()
        Description copied from interface: NodeBuilder
        Checks whether this builder represents a node that exists.
        Specified by:
        exists in interface NodeBuilder
        Returns:
        true if the node exists, false otherwise
      • isNew

        public boolean isNew()
        Description copied from interface: NodeBuilder
        Check whether this builder represents a new node, which is not present in the base state.
        Specified by:
        isNew in interface NodeBuilder
        Returns:
        true for a new node
      • isNew

        public boolean isNew​(java.lang.String name)
        Description copied from interface: NodeBuilder
        Check whether the named property is new, i.e. not present in the base state.
        Specified by:
        isNew in interface NodeBuilder
        Parameters:
        name - property name
        Returns:
        true for a new property
      • isModified

        public boolean isModified()
        Description copied from interface: NodeBuilder
        Check whether this builder represents a modified node, which has either modified properties or removed or added child nodes.
        Specified by:
        isModified in interface NodeBuilder
        Returns:
        true for a modified node
      • isReplaced

        public boolean isReplaced()
        Description copied from interface: NodeBuilder
        Check whether this builder represents a node that used to exist but was then replaced with other content, for example as a result of a NodeBuilder.setChildNode(String) call.
        Specified by:
        isReplaced in interface NodeBuilder
        Returns:
        true for a replaced node
      • isReplaced

        public boolean isReplaced​(java.lang.String name)
        Description copied from interface: NodeBuilder
        Check whether the named property exists in the base state but is replaced with other content, for example as a result of a NodeBuilder.setProperty(PropertyState) call.
        Specified by:
        isReplaced in interface NodeBuilder
        Parameters:
        name - property name
        Returns:
        true for a replaced property
      • getChildNodeCount

        public long getChildNodeCount​(long max)
        Description copied from interface: NodeBuilder
        Returns the current number of child nodes.

        If an implementation does know the exact value, it returns it (even if the value is higher than max). If the implementation does not know the exact value, and the child node count is higher than max, it may return Long.MAX_VALUE. The cost of the operation is at most O(max).

        Specified by:
        getChildNodeCount in interface NodeBuilder
        Parameters:
        max - the maximum value
        Returns:
        number of child nodes
      • getChildNodeNames

        @NotNull
        public @NotNull java.lang.Iterable<java.lang.String> getChildNodeNames()
        Description copied from interface: NodeBuilder
        Returns the names of current child nodes.
        Specified by:
        getChildNodeNames in interface NodeBuilder
        Returns:
        child node names
      • hasChildNode

        public boolean hasChildNode​(@NotNull
                                    @NotNull java.lang.String name)
        Description copied from interface: NodeBuilder
        Checks whether the named child node currently exists.
        Specified by:
        hasChildNode in interface NodeBuilder
        Parameters:
        name - child node name
        Returns:
        true if the named child node exists, false otherwise
      • child

        @NotNull
        public @NotNull NodeBuilder child​(@NotNull
                                          @NotNull java.lang.String name)
        Description copied from interface: NodeBuilder
        Returns a builder for constructing changes to the named child node. If the named child node does not already exist, a new empty child node is automatically created as the base state of the returned child builder. Otherwise the existing child node state is used as the base state of the returned builder.

        All updates to the returned child builder will implicitly affect also this builder, as if a setNode(name, childBuilder.getNodeState()) method call had been made after each update. Repeated calls to this method with the same name will return the same child builder instance until an explicit NodeBuilder.setChildNode(String, NodeState) or NodeBuilder.remove() call is made, at which point the link between this builder and a previously returned child builder for that child node name will get broken.

        Specified by:
        child in interface NodeBuilder
        Parameters:
        name - name of the child node
        Returns:
        child builder
      • getChildNode

        @NotNull
        public @NotNull NodeBuilder getChildNode​(@NotNull
                                                 @NotNull java.lang.String name)
        Description copied from interface: NodeBuilder
        Returns a builder for constructing changes to the named child node. If the named child node does not already exist, the returned builder will refer to a non-existent node and trying to modify it will cause IllegalStateExceptions to be thrown.
        Specified by:
        getChildNode in interface NodeBuilder
        Parameters:
        name - name of the child node
        Returns:
        child builder, possibly non-existent
      • setChildNode

        @NotNull
        public @NotNull NodeBuilder setChildNode​(@NotNull
                                                 @NotNull java.lang.String name)
        Description copied from interface: NodeBuilder
        Adds the named child node and returns a builder for modifying it. Possible previous content in the named subtree is removed.
        Specified by:
        setChildNode in interface NodeBuilder
        Parameters:
        name - name of the child node
        Returns:
        child builder
      • setChildNode

        @NotNull
        public @NotNull NodeBuilder setChildNode​(@NotNull
                                                 @NotNull java.lang.String name,
                                                 @NotNull
                                                 @NotNull NodeState state)
        Description copied from interface: NodeBuilder
        Adds or replaces a subtree.
        Specified by:
        setChildNode in interface NodeBuilder
        Parameters:
        name - name of the child node containing the new subtree
        state - subtree
        Returns:
        child builder
      • remove

        public boolean remove()
        Description copied from interface: NodeBuilder
        Remove this child node from its parent.
        Specified by:
        remove in interface NodeBuilder
        Returns:
        true for existing nodes, false otherwise
      • moveTo

        public boolean moveTo​(@NotNull
                              @NotNull NodeBuilder newParent,
                              @NotNull
                              @NotNull java.lang.String newName)
                       throws java.lang.IllegalArgumentException
        This implementation has the same semantics as adding this node with name newName as a new child of newParent followed by removing this node. As a consequence this implementation allows moving this node into the subtree rooted here, the result of which is the same as removing this node.

        See also the general contract for MoveTo.

        Specified by:
        moveTo in interface NodeBuilder
        Parameters:
        newParent - builder for the new parent.
        newName - name of this child at the new parent
        Returns:
        true on success, false otherwise
        Throws:
        java.lang.IllegalArgumentException - if the given name string is empty or contains the forward slash character
      • annotateSourcePath

        protected final void annotateSourcePath()
        Annotate this builder with its source path if this builder has not been transiently added. The source path is written to a property with the name MoveDetector.SOURCE_PATH.

        The source path of a builder is its current path if its current source path annotation is empty and none of its parents has a source path annotation set. Otherwise it is the source path of the first parent (or self) that has its source path annotation set appended with the relative path from that parent to this builder.

        This builder has been transiently added when there exists no base node at its source path.

      • getPropertyCount

        public long getPropertyCount()
        Description copied from interface: NodeBuilder
        Returns the current number of properties.
        Specified by:
        getPropertyCount in interface NodeBuilder
        Returns:
        number of properties
      • getProperties

        @NotNull
        public @NotNull java.lang.Iterable<? extends PropertyState> getProperties()
        Description copied from interface: NodeBuilder
        Returns the current properties.
        Specified by:
        getProperties in interface NodeBuilder
        Returns:
        current properties
      • hasProperty

        public boolean hasProperty​(java.lang.String name)
        Description copied from interface: NodeBuilder
        Checks whether the named property exists. The implementation is equivalent to getProperty(name) != null, but may be optimized to avoid having to load the property value.
        Specified by:
        hasProperty in interface NodeBuilder
        Parameters:
        name - property name
        Returns:
        true if the named property exists, false otherwise
      • getProperty

        public PropertyState getProperty​(java.lang.String name)
        Description copied from interface: NodeBuilder
        Returns the current state of the named property, or null if the property is not set.
        Specified by:
        getProperty in interface NodeBuilder
        Parameters:
        name - property name
        Returns:
        property state
      • getBoolean

        public boolean getBoolean​(@NotNull
                                  @NotNull java.lang.String name)
        Description copied from interface: NodeBuilder
        Returns the boolean value of the named property. The implementation is equivalent to the following code, but may be optimized.
         
         PropertyState property = builder.getProperty(name);
         return property != null
             && property.getType() == Type.BOOLEAN
             && property.getValue(Type.BOOLEAN);
         
         
        Specified by:
        getBoolean in interface NodeBuilder
        Parameters:
        name - property name
        Returns:
        boolean value of the named property, or false
      • getString

        @Nullable
        public @Nullable java.lang.String getString​(@NotNull
                                                    @NotNull java.lang.String name)
        Description copied from interface: NodeBuilder
        Returns the name value of the named property. The implementation is equivalent to the following code, but may be optimized.
         
         PropertyState property = builder.getProperty(name);
         if (property != null && property.getType() == Type.STRING) {
             return property.getValue(Type.STRING);
         } else {
             return null;
         }
         
         
        Specified by:
        getString in interface NodeBuilder
        Parameters:
        name - property name
        Returns:
        string value of the named property, or null
      • getName

        @Nullable
        public @Nullable java.lang.String getName​(@NotNull
                                                  @NotNull java.lang.String name)
        Description copied from interface: NodeBuilder
        Returns the name value of the named property. The implementation is equivalent to the following code, but may be optimized.
         
         PropertyState property = builder.getProperty(name);
         if (property != null && property.getType() == Type.NAME) {
             return property.getValue(Type.NAME);
         } else {
             return null;
         }
         
         
        Specified by:
        getName in interface NodeBuilder
        Parameters:
        name - property name
        Returns:
        name value of the named property, or null
      • getNames

        @NotNull
        public @NotNull java.lang.Iterable<java.lang.String> getNames​(@NotNull
                                                                      @NotNull java.lang.String name)
        Description copied from interface: NodeBuilder
        Returns the name values of the named property. The implementation is equivalent to the following code, but may be optimized.
         
         PropertyState property = builder.getProperty(name);
         if (property != null && property.getType() == Type.NAMES) {
             return property.getValue(Type.NAMES);
         } else {
             return Collections.emptyList();
         }
         
         
        Specified by:
        getNames in interface NodeBuilder
        Parameters:
        name - property name
        Returns:
        name values of the named property, or an empty collection
      • setProperty

        @NotNull
        public @NotNull NodeBuilder setProperty​(@NotNull
                                                @NotNull PropertyState property)
        Description copied from interface: NodeBuilder
        Set a property state
        Specified by:
        setProperty in interface NodeBuilder
        Parameters:
        property - The property state to set
        Returns:
        this builder
      • setProperty

        @NotNull
        public <T> @NotNull NodeBuilder setProperty​(java.lang.String name,
                                                    @NotNull
                                                    T value)
        Description copied from interface: NodeBuilder
        Set a property state
        Specified by:
        setProperty in interface NodeBuilder
        Type Parameters:
        T - The type of this property. Must be one of String, Blob, byte[], Long, Integer, Double, Boolean, BigDecimal
        Parameters:
        name - The name of this property
        value - The value of this property
        Returns:
        this builder
      • setProperty

        @NotNull
        public <T> @NotNull NodeBuilder setProperty​(java.lang.String name,
                                                    @NotNull
                                                    T value,
                                                    Type<T> type)
        Description copied from interface: NodeBuilder
        Set a property state
        Specified by:
        setProperty in interface NodeBuilder
        Type Parameters:
        T - The type of this property.
        Parameters:
        name - The name of this property
        value - The value of this property
        Returns:
        this builder
      • removeProperty

        @NotNull
        public @NotNull NodeBuilder removeProperty​(java.lang.String name)
        Description copied from interface: NodeBuilder
        Remove the named property. This method has no effect if a property of the given name does not exist.
        Specified by:
        removeProperty in interface NodeBuilder
        Parameters:
        name - name of the property
      • createBlob

        public Blob createBlob​(java.io.InputStream stream)
                        throws java.io.IOException
        Specified by:
        createBlob in interface NodeBuilder
        Throws:
        java.io.IOException
      • getPath

        public final java.lang.String getPath()
        Returns:
        path of this builder.
      • toString

        public java.lang.String toString()
        Overrides:
        toString in class java.lang.Object