fri.util.database.jpa.tree.closuretable
Class ClosureTableTreeDao

java.lang.Object
  extended by fri.util.database.jpa.tree.AbstractTreeDao<ClosureTableTreeNode>
      extended by fri.util.database.jpa.tree.closuretable.ClosureTableTreeDao
All Implemented Interfaces:
TreeDao<ClosureTableTreeNode>
Direct Known Subclasses:
TemporalClosureTableTreeDao

public class ClosureTableTreeDao
extends AbstractTreeDao<ClosureTableTreeNode>

Data-access-object for a hierarchical representation of records (nodes), using two database tables, having no parent reference in children. This closure-table tree will maintain child positions, meaning children lists have a defined order which can only be changed by a move(). For better performance this can be turned off by a constructor parameter.

This DAO manages the tree structure of any entity type that implements ClosureTableTreeNode. You don't need to save or delete the ClosureTableTreeNode separately, this is done here.

The "closure table" method acts on two database tables, thus it needs two entity types for its operations:

For every ClosureTableTreeNode implementation you need at least one associated TreePath implementation. As the latter references the first, they always go together. A TreePath implementation represents a tree aspect of some data. The data (nodes) do not have any information about their tree structure in them, but must expose an "id" property (like the TreeNode interface demands). You can have several tree "aspects" of the data nodes, this would require several TreePath implementations for one ClosureTableTreeNode implementation. For each TreePath implementation you must use a separate DAO instance.

Following is the path/node structure: every node is connected to every node above it (by a path), and to itself, but not to its siblings. A root has connections (paths) to all nodes in tree. Sibling order is represented by a 0-n order-index in all paths with depth 1 (all other depths have no order information). A node's self-reference path has depth 0, any other path has depth > 0.

See links in TreeDao for more information.

Note: as the temporal derivation obtains a state, all write-methods here are synchronized.

Author:
Fritz Ritzberger, 14.10.2012. Thanks to Bill Karwin for his instructions on the internet.
See Also:
ClosureTableTreeNode, TreeDao

Nested Class Summary
 
Nested classes/interfaces inherited from interface fri.util.database.jpa.tree.TreeDao
TreeDao.CopiedNodeRenamer<N extends TreeNode>
 
Field Summary
 
Fields inherited from class fri.util.database.jpa.tree.AbstractTreeDao
session
 
Fields inherited from interface fri.util.database.jpa.tree.TreeDao
UNDEFINED_POSITION
 
Constructor Summary
ClosureTableTreeDao(java.lang.Class<? extends ClosureTableTreeNode> treeNodeEntityClass, java.lang.Class<? extends TreePath> treePathsEntityClass, boolean orderIndexMatters, DbSession session)
           
ClosureTableTreeDao(java.lang.Class<? extends ClosureTableTreeNode> treeNodeEntityClass, java.lang.String treeNodeEntity, java.lang.Class<? extends TreePath> treePathEntityClass, java.lang.String treePathEntity, boolean orderIndexMatters, DbSession session)
           
 
Method Summary
 ClosureTableTreeNode addChild(ClosureTableTreeNode parent, ClosureTableTreeNode child)
          Adds to end of children of given parent.
 ClosureTableTreeNode addChildAt(ClosureTableTreeNode parent, ClosureTableTreeNode child, int position)
          Adds at specified position to children of given parent.
 ClosureTableTreeNode addChildBefore(ClosureTableTreeNode sibling, ClosureTableTreeNode child)
          Adds to children before given sibling, sibling is pushed backwards in children list.
protected  void beforeFindQuery(java.lang.String tableAlias, java.lang.StringBuilder queryText, java.util.List<java.lang.Object> parameters, boolean whereWasAppended)
          Does nothing.
 ClosureTableTreeNode copy(ClosureTableTreeNode node, ClosureTableTreeNode parent, ClosureTableTreeNode copiedNodeTemplate)
          Copies the given node to end of children list of parent.
 ClosureTableTreeNode copyBefore(ClosureTableTreeNode node, ClosureTableTreeNode sibling, ClosureTableTreeNode copiedNodeTemplate)
          Copies the given node to position of given sibling, pushing sibling backwards in list.
 ClosureTableTreeNode copyTo(ClosureTableTreeNode node, ClosureTableTreeNode parent, int position, ClosureTableTreeNode copiedNodeTemplate)
          Copies the given node to given position in children list of parent.
 ClosureTableTreeNode copyToBeRoot(ClosureTableTreeNode child, ClosureTableTreeNode copiedNodeTemplate)
          Copies a tree to be a root.
 ClosureTableTreeNode createRoot(ClosureTableTreeNode root)
          Creates a tree root node.
 java.util.List<ClosureTableTreeNode> find(ClosureTableTreeNode parent, java.util.Map<java.lang.String,java.lang.Object> criteria)
          Convenience finder method.
 ClosureTableTreeNode find(java.io.Serializable id)
          
 java.util.List<ClosureTableTreeNode> findDirectChildren(java.util.List<ClosureTableTreeNode> subNodes)
          Finds direct children in a cached list of tree nodes, parent is first in that cached list.
 java.util.List<ClosureTableTreeNode> findSubTree(ClosureTableTreeNode parent, java.util.List<ClosureTableTreeNode> subNodes)
          Finds a sub-tree list in a cached list of tree nodes under given parent.
 int getChildCount(ClosureTableTreeNode parent)
          
 java.util.List<ClosureTableTreeNode> getChildren(ClosureTableTreeNode parent)
          Gives the children of passed parent.
 int getLevel(ClosureTableTreeNode node)
          
 ClosureTableTreeNode getParent(ClosureTableTreeNode child)
          
 java.util.List<ClosureTableTreeNode> getPath(ClosureTableTreeNode node)
          
protected  java.util.List<? extends TreePath> getPathsToRemove(ClosureTableTreeNode node)
           
 ClosureTableTreeNode getRoot(ClosureTableTreeNode node)
          
 java.util.List<ClosureTableTreeNode> getRoots()
          
 java.util.List<ClosureTableTreeNode> getTree(ClosureTableTreeNode parent)
          Reads a tree or sub-tree, including all children.
 java.util.List<ClosureTableTreeNode> getTreeCacheable(ClosureTableTreeNode parent)
          Reads a tree or sub-tree, including all children, which can be cached and passed back into findSubTree() or findDirectChildren().
 TreePath getTreePathEntity(ClosureTableTreeNode node)
          This is for the case when the provided TreePath implementation contains additional properties concerning the node.
 boolean isChildOf(ClosureTableTreeNode child, ClosureTableTreeNode parent)
          
 boolean isEqualToOrChildOf(ClosureTableTreeNode child, ClosureTableTreeNode parent)
          
 boolean isLeaf(ClosureTableTreeNode node)
          
 boolean isRemoveReferencedNodes()
           
 boolean isRoot(ClosureTableTreeNode node)
          
 void move(ClosureTableTreeNode node, ClosureTableTreeNode parent)
          Moves the given node to end of children list of parent.
 void moveBefore(ClosureTableTreeNode node, ClosureTableTreeNode sibling)
          Moves the given node to position of given sibling, pushing sibling backwards in list.
 void moveTo(ClosureTableTreeNode node, ClosureTableTreeNode parent, int position)
          Moves the given node to given position in children list of parent.
 void moveToBeRoot(ClosureTableTreeNode child)
          Moves a sub-tree to be a root.
protected  fri.util.database.jpa.tree.closuretable.CacheableTreeList newCacheableTreeList(ClosureTableTreeNode parent, java.util.List<TreePath> breadthFirstTree)
          Factory method for new CacheableTreeList.
protected  TreePath newTreePathInstance()
          Creates a new TreePath instance from treePathEntityClass.
protected  java.lang.String pathEntityName()
          Overridden to return the name of TreePaths entity.
 void remove(ClosureTableTreeNode node)
          Removes the tree under given node, including the node.
 void removeAll()
          Removes all roots, including the nodes below them.
protected  void removeNode(ClosureTableTreeNode nodeToRemove)
          Called from remove() for all sub-nodes of removed tree.
protected  void removePath(TreePath path)
          Called from remove() for all sub-nodes of removed tree.
protected  void removeTree(ClosureTableTreeNode parent)
          Called from remove() after locking tree.
protected  java.lang.Object save(TreePath path)
          Saves the given path to session.
 void setRemoveReferencedNodes(boolean removeReferencedNodes)
          Set this to true when driving no more than one tree over a node table.
protected  boolean shouldCloseGapOnRemove()
          Called from remove().
 int size(ClosureTableTreeNode parent)
          
 void update(ClosureTableTreeNode node)
          Updates the given persistent object.
 
Methods inherited from class fri.util.database.jpa.tree.AbstractTreeDao
appendInvalidityCondition, appendValidityCondition, applyCopiedNodeRenamer, assertUpdate, beforeFindQuery, buildAliasedPropertyName, buildIndexedPlaceHolder, checkUniqueConstraint, checkUniqueness, copyOrMovePreconditions, equal, getUniqueTreeConstraint, getValidFromPropertyName, getValidToPropertyName, isPersistent, isValid, nodeEntityName, refresh, save, setCheckUniqueConstraintOnUpdate, setCopiedNodeRenamer, setUniqueTreeConstraint, shouldCheckUniqueConstraintOnUpdate, validFrom, validTo, validToOnRemove
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Constructor Detail

ClosureTableTreeDao

public ClosureTableTreeDao(java.lang.Class<? extends ClosureTableTreeNode> treeNodeEntityClass,
                           java.lang.Class<? extends TreePath> treePathsEntityClass,
                           boolean orderIndexMatters,
                           DbSession session)
Parameters:
treeNodeEntityClass - the persistence class representing the tree, implementing ClosureTableTreeNode. Its simpleName will be used as table name for queries.
treePathsEntityClass - the persistence class representing ancestor-child relations, implementing TreePaths. Its simpleName will be used as table name for queries.
orderIndexMatters - true when position of nodes should be managed, false if position does not matter (makes operations a little faster).

ClosureTableTreeDao

public ClosureTableTreeDao(java.lang.Class<? extends ClosureTableTreeNode> treeNodeEntityClass,
                           java.lang.String treeNodeEntity,
                           java.lang.Class<? extends TreePath> treePathEntityClass,
                           java.lang.String treePathEntity,
                           boolean orderIndexMatters,
                           DbSession session)
Parameters:
treeNodeEntityClass - the persistence class representing the tree, implementing ClosureTableTreeNode.
treeNodeEntity - the JPQL entity name of the database table to be used for node queries.
treePathEntityClass - the persistence class representing ancestor-child relations, implementing TreePaths.
treePathEntity - the JPQL entity name of the database table to be used for path queries.
orderIndexMatters - true when position of nodes should be managed, false if position does not matter (makes operations a little faster).
Method Detail

isRemoveReferencedNodes

public boolean isRemoveReferencedNodes()
Returns:
true if nodes will removed when their paths get removed.

setRemoveReferencedNodes

public void setRemoveReferencedNodes(boolean removeReferencedNodes)
Set this to true when driving no more than one tree over a node table. The consequence is that nodes will be removed when their paths get removed. Default is false, to support more than one tree on the same node table.


getTreePathEntity

public TreePath getTreePathEntity(ClosureTableTreeNode node)
This is for the case when the provided TreePath implementation contains additional properties concerning the node. Caller is expected to cast the return to an adequate type.

Parameters:
node - the node for which TreePath information is requested.
Returns:
the TreePath instance that contains the node's self-reference.

find

public ClosureTableTreeNode find(java.io.Serializable id)

Returns:
the object by identity (primary key) from database.

update

public void update(ClosureTableTreeNode node)
            throws UniqueConstraintViolationException
Updates the given persistent object. This performs explicit constraint checking when checkUniqueConstraintsOnUpdate is true (default is false).

Throws:
UniqueConstraintViolationException - when given entity is not unique.

isRoot

public final boolean isRoot(ClosureTableTreeNode node)

Returns:
true if passed node is persistent and a root.

createRoot

public ClosureTableTreeNode createRoot(ClosureTableTreeNode root)
                                throws UniqueConstraintViolationException
Creates a tree root node.

Throws:
UniqueConstraintViolationException - when uniqueness would be violated.

getRoots

public java.util.List<ClosureTableTreeNode> getRoots()

Returns:
all tree root nodes.

removeAll

public void removeAll()
Removes all roots, including the nodes below them. Thus clears the table.


getTree

public java.util.List<ClosureTableTreeNode> getTree(ClosureTableTreeNode parent)
Reads a tree or sub-tree, including all children. The result is NOT EXPECTED to be used with findSubTree() or findDirectChildren()!

Parameters:
parent - the parent of the tree to read, can also be root of the tree.
Returns:
all tree nodes under given parent, including parent.

getTreeCacheable

public java.util.List<ClosureTableTreeNode> getTreeCacheable(ClosureTableTreeNode parent)
Reads a tree or sub-tree, including all children, which can be cached and passed back into findSubTree() or findDirectChildren(). Mind that any cached tree could be out-of-sync with database when another client performs changes.

Parameters:
parent - the parent of the tree to read, can also be root of the tree.
Returns:
all tree nodes under given parent, including parent, in depth-first order.

newCacheableTreeList

protected fri.util.database.jpa.tree.closuretable.CacheableTreeList newCacheableTreeList(ClosureTableTreeNode parent,
                                                                                         java.util.List<TreePath> breadthFirstTree)
Factory method for new CacheableTreeList. To be overridden by temporal variant.


findSubTree

public java.util.List<ClosureTableTreeNode> findSubTree(ClosureTableTreeNode parent,
                                                        java.util.List<ClosureTableTreeNode> subNodes)
Finds a sub-tree list in a cached list of tree nodes under given parent. The subNodes list was returned from a call to getTreeCacheable(). Mind that any cached tree could be out-of-sync with database when another client performs changes.

Parameters:
parent - the parent node to search a sub-tree for, contained somewhere in the given list of nodes.
subNodes - a list of nodes from which to extract a sub-tree, also containing given parent.
Returns:
a list of nodes under the passed parent node.

findDirectChildren

public java.util.List<ClosureTableTreeNode> findDirectChildren(java.util.List<ClosureTableTreeNode> subNodes)
Finds direct children in a cached list of tree nodes, parent is first in that cached list. The subNodes list was returned from a call to getTreeCacheable() or findSubTree(). Mind that any cached tree could be out-of-sync with database when another client performs changes.

Parameters:
subNodes - a list of nodes from which to extract the direct child list, parent at head of list.
Returns:
a list of direct children of the the parent which is first in list.

getChildCount

public int getChildCount(ClosureTableTreeNode parent)

Returns:
the number of direct children of given parent node.

getChildren

public java.util.List<ClosureTableTreeNode> getChildren(ClosureTableTreeNode parent)
Gives the children of passed parent. This method reads the full subtree under parent. Removing from returned list will not remove that child from tree but cause an exception.

Returns:
the ordered list of direct children under given parent.

getRoot

public ClosureTableTreeNode getRoot(ClosureTableTreeNode node)

Returns:
the root node of given node. Root has itself as root.

getParent

public ClosureTableTreeNode getParent(ClosureTableTreeNode child)

Returns:
the parent node of given node. Root has null as parent.

getPath

public java.util.List<ClosureTableTreeNode> getPath(ClosureTableTreeNode node)

Returns:
all parent nodes of given node, i.e. its path from root to (exclusive) node. Root will return an empty list.

getLevel

public int getLevel(ClosureTableTreeNode node)

Returns:
the depth of given node. Root has level 0.

size

public int size(ClosureTableTreeNode parent)

Returns:
the count of all nodes of any depth below given node, including itself.

isLeaf

public boolean isLeaf(ClosureTableTreeNode node)

Returns:
true when given node has no children, i.e. is not a container-node.

isEqualToOrChildOf

public boolean isEqualToOrChildOf(ClosureTableTreeNode child,
                                  ClosureTableTreeNode parent)

Returns:
true when child is in the tree under parent, or parent is equal to child, else false.

isChildOf

public boolean isChildOf(ClosureTableTreeNode child,
                         ClosureTableTreeNode parent)

Returns:
true when child is in the tree under parent and not parent, else false.

addChild

public ClosureTableTreeNode addChild(ClosureTableTreeNode parent,
                                     ClosureTableTreeNode child)
                              throws UniqueConstraintViolationException
Adds to end of children of given parent.

Throws:
UniqueConstraintViolationException - when uniqueness would be violated.

addChildAt

public ClosureTableTreeNode addChildAt(ClosureTableTreeNode parent,
                                       ClosureTableTreeNode child,
                                       int position)
                                throws UniqueConstraintViolationException
Adds at specified position to children of given parent.

position - -1 for append, else target position in child list.
Throws:
UniqueConstraintViolationException - when uniqueness would be violated.

addChildBefore

public ClosureTableTreeNode addChildBefore(ClosureTableTreeNode sibling,
                                           ClosureTableTreeNode child)
                                    throws UniqueConstraintViolationException
Adds to children before given sibling, sibling is pushed backwards in children list.

Throws:
UniqueConstraintViolationException - when uniqueness would be violated.

remove

public void remove(ClosureTableTreeNode node)
Removes the tree under given node, including the node. Node can also be a root.


move

public void move(ClosureTableTreeNode node,
                 ClosureTableTreeNode parent)
          throws UniqueConstraintViolationException
Moves the given node to end of children list of parent. When source is identical with target, nothing happens.

Throws:
UniqueConstraintViolationException

moveTo

public void moveTo(ClosureTableTreeNode node,
                   ClosureTableTreeNode parent,
                   int position)
            throws UniqueConstraintViolationException
Moves the given node to given position in children list of parent. When source is identical with target, nothing happens.

Throws:
UniqueConstraintViolationException

moveBefore

public void moveBefore(ClosureTableTreeNode node,
                       ClosureTableTreeNode sibling)
                throws UniqueConstraintViolationException
Moves the given node to position of given sibling, pushing sibling backwards in list. When source is identical with target, nothing happens.

Throws:
UniqueConstraintViolationException

moveToBeRoot

public void moveToBeRoot(ClosureTableTreeNode child)
                  throws UniqueConstraintViolationException
Moves a sub-tree to be a root. This means it is removed from its previous root. When child is already a root, nothing happens.

Throws:
UniqueConstraintViolationException - when unique constraint(s) for roots would be violated.

copy

public ClosureTableTreeNode copy(ClosureTableTreeNode node,
                                 ClosureTableTreeNode parent,
                                 ClosureTableTreeNode copiedNodeTemplate)
                          throws UniqueConstraintViolationException
Copies the given node to end of children list of parent. When source is identical with target, the node will be be copied to the position of its originator.

Parameters:
node - the node to be copied.
copiedNodeTemplate - a template for the copied node containing altered properties, can be null.
Throws:
UniqueConstraintViolationException - when uniqueness would be violated.

copyTo

public ClosureTableTreeNode copyTo(ClosureTableTreeNode node,
                                   ClosureTableTreeNode parent,
                                   int position,
                                   ClosureTableTreeNode copiedNodeTemplate)
                            throws UniqueConstraintViolationException
Copies the given node to given position in children list of parent. When source is identical with target, the node will be be copied to the position of its originator.

Parameters:
node - the node to be copied.
parent - the parent-node of the children the node should be copied into.
position - the 0-n index the node should obtain within children of parent.
copiedNodeTemplate - a template for the copied node containing altered properties, can be null.
Throws:
UniqueConstraintViolationException - when uniqueness would be violated.

copyBefore

public ClosureTableTreeNode copyBefore(ClosureTableTreeNode node,
                                       ClosureTableTreeNode sibling,
                                       ClosureTableTreeNode copiedNodeTemplate)
                                throws UniqueConstraintViolationException
Copies the given node to position of given sibling, pushing sibling backwards in list. When source is identical with target, the node will be be copied to the position of its originator.

Parameters:
node - the node to be copied.
sibling - the target node the copied node should push backwards in children list.
copiedNodeTemplate - a template for the copied node containing altered properties, can be null.
Throws:
UniqueConstraintViolationException - when uniqueness would be violated.

copyToBeRoot

public ClosureTableTreeNode copyToBeRoot(ClosureTableTreeNode child,
                                         ClosureTableTreeNode copiedNodeTemplate)
                                  throws UniqueConstraintViolationException
Copies a tree to be a root. This means it is removed from its previous root. When child is already a root, the node will be be copied to be another root.

Parameters:
child - the node to copy to be a root.
copiedNodeTemplate - a template for the copied node containing altered properties, can be null.
Throws:
UniqueConstraintViolationException - when unique constraint(s) for roots would be violated.

find

public java.util.List<ClosureTableTreeNode> find(ClosureTableTreeNode parent,
                                                 java.util.Map<java.lang.String,java.lang.Object> criteria)
Convenience finder method. All criteria will be AND'ed.

Parameters:
parent - the parent under which to search, can be null.
criteria - a name/value mapping for the nodes to be found under given tree.
Returns:
tree nodes with given criteria.

beforeFindQuery

protected void beforeFindQuery(java.lang.String tableAlias,
                               java.lang.StringBuilder queryText,
                               java.util.List<java.lang.Object> parameters,
                               boolean whereWasAppended)
Does nothing. Override to append temporal conditions. Called from all querying methods. This method is expected to first append a WHERE when whereWasAppended is false, or an AND when whereWasAppended is true.


pathEntityName

protected java.lang.String pathEntityName()
Overridden to return the name of TreePaths entity.

Overrides:
pathEntityName in class AbstractTreeDao<ClosureTableTreeNode>
Returns:
the name of the JPQL path entity, needed only in closure-table. Returns null, to be overridden.

newTreePathInstance

protected TreePath newTreePathInstance()
Creates a new TreePath instance from treePathEntityClass. To be overridden for additional actions on save.


save

protected java.lang.Object save(TreePath path)
Saves the given path to session. To be overridden for additional actions on save.


shouldCloseGapOnRemove

protected boolean shouldCloseGapOnRemove()
Called from remove(). To be overridden.

Returns:
true for closing a gap and reordering siblings after physical remove.

removeTree

protected void removeTree(ClosureTableTreeNode parent)
Called from remove() after locking tree. To be overridden.


removePath

protected void removePath(TreePath path)
Called from remove() for all sub-nodes of removed tree. Deletes physically. To be overridden for historicizing paths.


removeNode

protected void removeNode(ClosureTableTreeNode nodeToRemove)
Called from remove() for all sub-nodes of removed tree. Deletes physically. To be overridden. Here you could additionally historicize the node, which normally is not needed because paths are historicized. When using more than one DAOs on one node table, you MUST override this to NOT delete physically, because the node could be in another DAO's tree!


getPathsToRemove

protected final java.util.List<? extends TreePath> getPathsToRemove(ClosureTableTreeNode node)