com.almworks.jira.structure.api.forest
Interface Forest


public interface Forest

Forest interface provides access to a data structure that stores issue hierarchy (the hierarchy is a sequence of tree structures, a forest). Forest lets you read and modify the data stored in the forest data structure.

Difference between Structure and Forest interfaces: Structure exposes properties of a structure such as name, and also lets you modify those properties and save them back to the database; while Forest is the hierarchy itself, it's just a data structure. Any modifications to the Forest are only applied to that instance in memory.

Forest of issues is represented as a sequence of pairs (long issue, int depth). The issues are identified by their issue ID, and the position in the hierarchy is identified by the position in the sequence and the associated depth. For example, the following hierarchy:

     A
        A1
        A2
     B
        B1
            B1X
   
is represented in the forest as the following sequence:
     (A, 0), (A1, 1), (A2, 1), (B, 0), (B1, 1), (B1X, 2)
   

Forest interface provides indexed access to that representation of the forest. That is, you can read issue IDs and depths given that you know the index of the pair in the sequence. There are also a number of utility methods that allow searching and browsing the forest.

Invariants

Because depth associated with an issue is an integer number, there are certain invariants about the depth that must hold true, otherwise the data does not make sense. Additionally, an issue may appear no more than once in the forest. Make sure you don't violate those invariants when creating new forest instances:

When Java assertions are enabled, these invariants are checked all the time. Due to performance impact, the invariants are not checked and assumed to hold true when running with assertions disabled. The result of creating and using a forest that violates these invariants is undefined.

Under-After Coordinates

When a specific position in the forest needs to be defined for mutating operations such as move or insert, under-after coordinates are used. (If operation addresses a specific issue, the issue ID is used instead.)

Under-after coordinates contain under value, which identifies the parent issue of the specified position (the depth and the subtree). If under is 0, the position is at the top (root issue).

The other parameter, after coordinate, defines the location of the inserted issue amongst siblings - the issues at the same depth under the same parent. If after is 0, it means that the position should be the first under the specified parent.

Note: moving an issue after itself, i.e. when the under coordinate is equal to the issue's parent issue and the after coordinate is equal to the issue itself, is allowed and does not change the position of the issue.

This class in not thread-safe.

Author:
Igor Sereda

Method Summary
 boolean addIssue(long issue, long under, long after)
          Adds a single issue at the specified position.
 boolean containsIssue(long issue)
          Can be used to check if the forest contains a specific issue.
 Forest copy()
          Creates an exact copy of this forest.
 Forest copySubtree(long issue)
          Creates a forest that contains the specified issue and all its sub-issues from this forest.
 Forest copySubtreeAtIndex(int index)
          Creates a forest that contains the specified issue and all its sub-issues from this forest.
 Forest filter(La<Long,?> filter)
          Filters this forest by hiding issues that do not pass the filter condition.
 Forest filterForIssue(long issue)
          Creates a sub-sequence forest of this forest that contains all issues "relevant" to the passed issue.
 Forest filterSoft(La<Long,?> filter)
          Filters this forest by excluding issues that do not pass the filter condition.
<T,C> C
foldUpwards(ForestParentChildrenClosure<T,C> closure)
          This is a more generic version of visitParentChildrenUpwards(com.almworks.jira.structure.api.forest.ForestParentChildrenVisitor) that allows you to effectively process the forest bottom-up, probably saving on memory allocation and search speed.
 com.almworks.integers.LongArray getChildren(long issue)
          Creates an array with all direct sub-issues of the specified issue.
 com.almworks.integers.LongArray getChildrenAtIndex(int index)
          Creates an array with all direct sub-issues of the issue at the specified index.
 int getDepth(int index)
          Gets the depth of an issue at the specified position in the forest.
 com.almworks.integers.IntList getDepths()
           
 long getIssue(int index)
          Gets the ID of an issue at the specified position in the forest.
 com.almworks.integers.LongList getIssues()
           
 long getLastChild(long parent)
          Gets the last direct sub-issue of the specified parent issue.
 long getLastChildByIndex(int parentIndex)
          Gets the last direct sub-issue of the specified parent issue.
 long getParent(long issue)
          Gets the parent issue of the specified issue.
 int getParentIndex(int index)
          Searches the forest for the index of a "parent issue".
 com.almworks.integers.LongArray getParentPathForIndex(int index)
          Returns the path to the specified issue without the issue itself.
 com.almworks.integers.LongArray getPath(long issue)
          Returns the path to the specified issue - a sequence of issues that starts with a root issue, ends with the specified issue, and where element[i] is the parent issue of element[i+1].
 com.almworks.integers.LongArray getPathForIndex(int index)
          Similar to getPath(long), returns the path to the issue specified by index.
 int getPathIndexAtDepth(int index, int depth)
          Given issue at the specified index, traverse its "path" upwards - that is, look for all parent issues up to the topmost root parent, and return an index of the parent that has the specified depth.
 long getPrecedingSibling(long issue)
          Gets the issue that immediately precedes the specified issue in the list of children of the specified issue's parent.
 long getPrecedingSiblingForIndex(int index)
          Gets the issue that immediately precedes the one with the given index in the list of children of its parent.
 int getPrecedingSiblingIndex(int index)
          Gets the index of an issue that immediately precedes the issue at the given index in the list of children of its parent.
 com.almworks.integers.LongArray getPrecedingSiblings(long issue)
          Returns the array of all issues that come before the given issue in the list of children of its parent, in the same order as they appear in the forest.
 com.almworks.integers.LongArray getPrecedingSiblingsForIndex(int index)
          Returns the array of all issues that come before the given issue in the list of children of its parent, in the same order as they appear in the forest.
 com.almworks.integers.LongArray getRoots()
           
 int getSubtreeEnd(int index)
          The method looks for the end of a subtree rooted at the specified index.
 int indexOf(long issue)
          Searches for the position of a specific issue in the forest.
 boolean isEmpty()
           
 Forest makeImmutable()
          Makes this forest immutable - all mutator operations will throw UnsupportedOperationException.
 void mergeForest(Forest forest, long under, long after)
          Convenience method to call mergeForest(Forest, long, long, ForestChangeEventHandler) without event handler.
 void mergeForest(Forest forest, long under, long after, ForestChangeEventHandler eventHandler)
          Merges another forest into this forest.
 boolean moveSubtree(long issue, long under, long after)
          Convenience method to call moveSubtree(long, long, long, ForestChangeEventHandler) without event handler.
 boolean moveSubtree(long issue, long under, long after, ForestChangeEventHandler eventHandler)
          Moves sub-tree rooted at the specified issue to a position specified by (under, after) coordinates.
 int moveSubtreeAtIndex(int index, long under, long after, ForestChangeEventHandler eventHandler)
          Moves sub-tree rooted at the specified index to a position specified by (under, after) coordinates.
 Forest removeSubtree(long issue)
          Convenience method to call removeSubtree(long, ForestChangeEventHandler) without event handler.
 Forest removeSubtree(long issue, ForestChangeEventHandler eventHandler)
          Removes a sub-tree with the specified issue as a root from this forest.
 Forest removeSubtreeAtIndex(int index, ForestChangeEventHandler eventHandler)
          Removes a sub-tree with rooted at the specified index from this forest.
 Forest set(com.almworks.integers.LongList issues, com.almworks.integers.IntList depths)
          Replaces the contents of this forest with the values passed in the parameters.
 Forest set(com.almworks.integers.WritableLongList issues, com.almworks.integers.WritableIntList depths, boolean reuseLists)
          Replaces the contents of this forest with the values passed in the parameters.
 int size()
           
 String toFullString()
          Utility method for debugging - returns full string representation of the forest, that contains all the information, unlike toString method, which may be truncated to some character number limit.
 void visitParentChildrenUpwards(ForestParentChildrenVisitor visitor)
          This method is used to efficiently traverse all pairs (parent, children) from the end of the forest upwards.
 

Method Detail

size

int size()
Returns:
the size of the forest, the number of issues in it, the number is always >= 0

isEmpty

boolean isEmpty()
Returns:
true if the size of the forest is zero

getIssues

@NotNull
com.almworks.integers.LongList getIssues()
Returns:
a non-modifiable list of issues, in the order they appear in the forest. The size of the list is equal to the value returned by size().

getDepths

@NotNull
com.almworks.integers.IntList getDepths()
Returns:
a non-modifiable list of depths, in the order the issues appear in the forest. The size of the list is equal to the value returned by size() and the i-th element of this list corresponds to the issue ID at the i-th position in the list returned by getIssues().

getIssue

long getIssue(int index)
Gets the ID of an issue at the specified position in the forest.

Parameters:
index - the index of the forest entry
Returns:
issue ID at the specified index
Throws:
IndexOutOfBoundsException - if index is not within range [0 .. size() - 1].

getDepth

int getDepth(int index)
Gets the depth of an issue at the specified position in the forest.

Parameters:
index - the index of the forest entry
Returns:
depth at the specified index, value is always >= 0 and satisfies the invariants for the Forest
Throws:
IndexOutOfBoundsException - if index is not within range [0 .. size() - 1].

indexOf

int indexOf(long issue)

Searches for the position of a specific issue in the forest.

Execution of this method may take O(size()) time, however it may be optimized if the implementation maintains an index. It's better to use this method rather than using forest.getIssues().indexOf(issue) because of the possible optimizations.

Parameters:
issue - the issue ID to search for
Returns:
such index of the issue in the forest, or -1 if the issue is not found

containsIssue

boolean containsIssue(long issue)

Can be used to check if the forest contains a specific issue.

Execution of this method may take O(size()) time.

Parameters:
issue - the issue ID to search for
Returns:
true if the forest contains the specified issue

getSubtreeEnd

int getSubtreeEnd(int index)

The method looks for the end of a subtree rooted at the specified index.

A subtree rooted at index k is a sub-sequence in the forest starting at position k and containing all following elements that have depth d > depth[k].

The result of this method is the next index after the last element of this subsequence. More specifically, the result is the first element after [k] that has depth d <= depth[k].

When the subtree ends with the whole forest, the return value is equal to size().

If index is a negative number, the returned value is 0. If index is greater or equal than size(), the returned value is equal to size().

Parameters:
index - the index of the root issue of the subtree
Returns:
the index of an issue that follows the last issue of the subtree, or the size of the forest in case the subtree is at the end of it

getParentIndex

int getParentIndex(int index)

Searches the forest for the index of a "parent issue". If the issue at the specified index is a root issue (has depth of 0), returns -1.

If index is negative, returns -1.

Parameters:
index - index of a child issue
Returns:
-1 if the issue at index is a root issue, or index k of the parent issue, such as that k = MAX(k in [0, index-1] that has depth[k] == depth[index] - 1)
Throws:
IndexOutOfBoundsException - if index is equal or greater than forest size

getParent

long getParent(long issue)
Gets the parent issue of the specified issue.

Parameters:
issue - child issue
Returns:
parent issue, or 0 if the child issue is a root issue or not found in the forest

getPrecedingSibling

long getPrecedingSibling(long issue)
Gets the issue that immediately precedes the specified issue in the list of children of the specified issue's parent.

Parameters:
issue - an issue
Returns:
immediately preceding sibling (issue that has the same parent and same depth), or 0 if issue is a root issue or not found in the forest or is the first child of its parent issue

getPrecedingSiblingIndex

int getPrecedingSiblingIndex(int index)
Gets the index of an issue that immediately precedes the issue at the given index in the list of children of its parent.

Parameters:
index - issue index
Returns:
index of immediately preceding sibling, or -1 if issue at index is a root issue or not found in the forest or is the first child of its parent issue

getPrecedingSiblingForIndex

long getPrecedingSiblingForIndex(int index)
Gets the issue that immediately precedes the one with the given index in the list of children of its parent.

Parameters:
index - issue index
Returns:
immediately preceding sibling, or 0 if there is none

getPrecedingSiblings

@NotNull
com.almworks.integers.LongArray getPrecedingSiblings(long issue)
Returns the array of all issues that come before the given issue in the list of children of its parent, in the same order as they appear in the forest.

Parameters:
issue - an issue
Returns:
array of all preceding siblings, empty if issue has none or is not in the forest

getPrecedingSiblingsForIndex

@NotNull
com.almworks.integers.LongArray getPrecedingSiblingsForIndex(int index)
Returns the array of all issues that come before the given issue in the list of children of its parent, in the same order as they appear in the forest.

Parameters:
index - issue index
Returns:
array of all preceding siblings, empty if issue at index has none or index is negative

getPathIndexAtDepth

int getPathIndexAtDepth(int index,
                        int depth)

Given issue at the specified index, traverse its "path" upwards - that is, look for all parent issues up to the topmost root parent, and return an index of the parent that has the specified depth.

If the required depth is equal to the depth of the issue at the specified index, returns index.

If index is a negative value, returns -1. If issue at the specified index has less depth than the required value, returns -1.

Parameters:
index - index of an issue
depth - required depth of the [grand-] parent issue
Returns:
the index of the [grand-] parent issue on the "path" to the specified issue that has the specified depth, or -1 if not found
Throws:
IndexOutOfBoundsException - if index is equal or greater than the size of the forest

getLastChild

long getLastChild(long parent)

Gets the last direct sub-issue of the specified parent issue.

Special case: when parent is 0, returns the last root issue in the forest.

If the parent issue is not in the forest, or if it does not have child issues, the return value is 0.

Parameters:
parent - parent issue
Returns:
the last issue among the parent issue's children, or 0 if the parent issue does not have children

getLastChildByIndex

long getLastChildByIndex(int parentIndex)

Gets the last direct sub-issue of the specified parent issue.

Special case: when parentIndex is less than zero, returns the last root issue in the forest.

If the parent issue does not have child issues, the return value is 0.

Parameters:
parentIndex - the index of the parent issue
Returns:
the last issue among the parent issue's children, or 0 if the parent issue does not have children

getChildren

@NotNull
com.almworks.integers.LongArray getChildren(long issue)

Creates an array with all direct sub-issues of the specified issue.

The returned array is writable and owned by the calling code.

If issue is not in the forest or does not have children, empty array is returned.

Parameters:
issue - the parent issue
Returns:
array of all sub-issues of the specified issue that have depth equal to the parent depth + 1

getChildrenAtIndex

@NotNull
com.almworks.integers.LongArray getChildrenAtIndex(int index)

Creates an array with all direct sub-issues of the issue at the specified index.

The returned array is writable and owned by the calling code.

If the specified issue does not have children, or if the index is negative, empty array is returned.

Parameters:
index - the index of the parent issue
Returns:
array of all sub-issues of the specified issue that have depth equal to the parent depth + 1
Throws:
IndexOutOfBoundsException - if the index is greater or equals the size of the forest

getRoots

@NotNull
com.almworks.integers.LongArray getRoots()
Returns:
an array of all root issues in the forest (those that have depth of 0)

getPath

@NotNull
com.almworks.integers.LongArray getPath(long issue)

Returns the path to the specified issue - a sequence of issues that starts with a root issue, ends with the specified issue, and where element[i] is the parent issue of element[i+1].

If issue is not in the forest, returns empty array.

The array is modifiable and owned by the calling code.

Parameters:
issue - issue to get the path to
Returns:
path to the specified issue, or empty array if the issue is not in the forest

getPathForIndex

@NotNull
com.almworks.integers.LongArray getPathForIndex(int index)
Similar to getPath(long), returns the path to the issue specified by index.

Parameters:
index - the index of an issue to get the path to
Returns:
path to the specified issue, or empty array if the index is negative
Throws:
NoSuchElementException - if the index is greater than or equal to forest size

getParentPathForIndex

@NotNull
com.almworks.integers.LongArray getParentPathForIndex(int index)

Returns the path to the specified issue without the issue itself. In other words, this is the path to the parent of the specified issue, if there is one.

Parameters:
index - issue index
Returns:
path to the specified issue's parent; empty array if the issue is top-level or not in the forest
See Also:
getPath(long)

filter

@NotNull
Forest filter(@Nullable
                      La<Long,?> filter)

Filters this forest by hiding issues that do not pass the filter condition. The resulting forest contains only the issues that pass the condition.

The topology of the resulting forest may differ from the original forest - that is, an issue may have a different parent in the resulting forest. This happens when an issue that has sub-issues is filtered out - in that case, its sub-tree is substituted instead of the parent issue. This is different from filterSoft(com.almworks.jira.structure.util.La) method, which preserves the topology.

This forest is not modified by this method. If all issues pass the condition, then this forest is returned as the result. If filtering has taken place, a new forest is returned.

The filter method is called once for every issue in the forest, and a truthy result (as defined in La.accepts(T)) indicates that the issue passes the filter.

Parameters:
filter - filter that returns a truthy value if an issue with given ID is allowed to be present in the resulting forest
Returns:
a filtered forest (or this forest if all issues satisfy the filter)
See Also:
filterSoft(com.almworks.jira.structure.util.La)

filterSoft

@NotNull
Forest filterSoft(@Nullable
                          La<Long,?> filter)

Filters this forest by excluding issues that do not pass the filter condition. All issues that contain sub-issues that have passed the filter are also preserved. The resulting forest contains sub-sequence of the original forest with issues having the same parents and depths.

Unlike filter(com.almworks.jira.structure.util.La) method, this method preserves the topology of the original forest - all issues in the resulting forest have the same root path as they do in the original forest.

This forest is not modified by this method. If all issues pass the condition, then this forest is returned as the result. If filtering has taken place, a new forest is returned.

The filter method is called once for every issue in the forest, and a truthy result (as defined in La.accepts(T)) indicates that the issue passes the filter.

Parameters:
filter - filter that returns a truthy value if an issue with given ID should be present in the resulting forest
Returns:
a filtered forest (or this forest if all issues satisfy the filter)

filterForIssue

@NotNull
Forest filterForIssue(long issue)

Creates a sub-sequence forest of this forest that contains all issues "relevant" to the passed issue.

The resulting forest contains all the parent issues of issue up to the root issue, and all the sub-issues of issue down to the deepest level.

This filter preserves the topology of the forest - all issues in the resulting forest have the same parents as in the original forest.

If issue is not in this forest, returns empty forest.

Always returns a new instance.

Parameters:
issue - the issue
Returns:
a part of the forest that is relevant to the specified issue

copy

@NotNull
Forest copy()
Creates an exact copy of this forest.

Returns:
a copy of this forest

copySubtree

@NotNull
Forest copySubtree(long issue)
Creates a forest that contains the specified issue and all its sub-issues from this forest.

Parameters:
issue - the root of the sub-tree
Returns:
a new forest that contains a copy of the sub-tree rooted at issue, or an empty forest if the issue is not in this forest

copySubtreeAtIndex

@NotNull
Forest copySubtreeAtIndex(int index)
Creates a forest that contains the specified issue and all its sub-issues from this forest.

Parameters:
index - index of the root of the sub-tree
Returns:
a new forest that contains a copy of the sub-tree rooted at issue at index, or an empty forest if the index is negative

moveSubtree

boolean moveSubtree(long issue,
                    long under,
                    long after,
                    @Nullable
                    ForestChangeEventHandler eventHandler)
                    throws StructureException

Moves sub-tree rooted at the specified issue to a position specified by (under, after) coordinates.

This method modifies the forest by removing the sub-tree with the specified issue as the root and adding it at the position specified by under-after coordinates. See Forest for the explanation of under-after coordinates.

This method does not modify the forest stored in the database for a structure. To make modifications of the structure's forest, run forest changing transaction with StructureManager.updateForest(com.atlassian.crowd.embedded.api.User, boolean, com.almworks.jira.structure.api.forest.ForestTransaction).

Parameters:
issue - the root issue of the sub-tree being moved
under - the new parent of the sub-tree, or 0 if the sub-tree should be placed at the forest root level
after - the preceding sibling of the new location for the sub-tree, or 0 to place sub-tree as the first child
eventHandler - optional handler of the move events
Returns:
true if the sub-tree has been moved, false if not (for example, if the issue is not in the forest)
Throws:
StructureException - if the move is not possible - for example, under is not in the forest or if you attempt to move a sub-tree under itself

moveSubtree

boolean moveSubtree(long issue,
                    long under,
                    long after)
                    throws StructureException
Convenience method to call moveSubtree(long, long, long, ForestChangeEventHandler) without event handler.

Parameters:
issue - the root issue of the sub-tree being moved
under - the new parent of the sub-tree, or 0 if the sub-tree should be placed at the forest root level
after - the preceding sibling of the new location for the sub-tree, or 0 to place sub-tree as the first child
Returns:
true if the sub-tree has been moved, false if not (for example, if the issue is not in the forest)
Throws:
StructureException - if the move is not possible - for example, under is not in the forest or if you attempt to move a sub-tree under itself

moveSubtreeAtIndex

int moveSubtreeAtIndex(int index,
                       long under,
                       long after,
                       @Nullable
                       ForestChangeEventHandler eventHandler)
                       throws StructureException

Moves sub-tree rooted at the specified index to a position specified by (under, after) coordinates.

This method modifies the forest by removing the sub-tree with the specified issue as the root and adding it at the position specified by under-after coordinates. See Forest for the explanation of under-after coordinates.

This method does not modify the forest stored in the database for a structure. To make modifications of the structure's forest, run forest changing transaction with StructureManager.updateForest(com.atlassian.crowd.embedded.api.User, boolean, com.almworks.jira.structure.api.forest.ForestTransaction).

Parameters:
index - the index of the root issue of the sub-tree being moved
under - the new parent of the sub-tree, or 0 if the sub-tree should be placed at the forest root level
after - the preceding sibling of the new location for the sub-tree, or 0 to place sub-tree as the first child
eventHandler - optional handler of the move events
Returns:
new index of the sub-tree if it has been moved, -1 if not (for example, if the given issue index is negative)
Throws:
StructureException - if the move is not possible - for example, under is not in the forest or if you attempt to move a sub-tree under itself

removeSubtree

@NotNull
Forest removeSubtree(long issue,
                             @Nullable
                             ForestChangeEventHandler eventHandler)

Removes a sub-tree with the specified issue as a root from this forest.

This method does not modify the forest stored in the database for a structure. To make modifications of the structure's forest, run forest changing transaction with StructureManager.updateForest(com.atlassian.crowd.embedded.api.User, boolean, com.almworks.jira.structure.api.forest.ForestTransaction).

Parameters:
issue - the root of the sub-tree to be removed
eventHandler - optional handler of the forest events
Returns:
forest with the removed issues, or empty forest if issue is not in this forest

removeSubtree

@NotNull
Forest removeSubtree(long issue)
Convenience method to call removeSubtree(long, ForestChangeEventHandler) without event handler.

Parameters:
issue - the root of the sub-tree to be removed
Returns:
forest with the removed issues, or empty forest if issue is not in this forest.

removeSubtreeAtIndex

@NotNull
Forest removeSubtreeAtIndex(int index,
                                    @Nullable
                                    ForestChangeEventHandler eventHandler)

Removes a sub-tree with rooted at the specified index from this forest.

This method does not modify the forest stored in the database for a structure. To make modifications of the structure's forest, run forest changing transaction with StructureManager.updateForest(com.atlassian.crowd.embedded.api.User, boolean, com.almworks.jira.structure.api.forest.ForestTransaction).

Parameters:
index - the index of the root of the sub-tree to be removed
eventHandler - optional handler of the forest events
Returns:
forest with the removed issues, or empty forest if index is negative

addIssue

boolean addIssue(long issue,
                 long under,
                 long after)
                 throws StructureException

Adds a single issue at the specified position.

If the issue is already in the structure, this method moves it to the specified position.

This method does not modify the forest stored in the database for a structure. To make modifications of the structure's forest, run forest changing transaction with StructureManager.updateForest(com.atlassian.crowd.embedded.api.User, boolean, com.almworks.jira.structure.api.forest.ForestTransaction).

Parameters:
issue - issue to be added
under - the parent of the issue, or 0 if the issue should be placed at the forest root level
after - the preceding sibling of the issue, or 0 to place issue as the first child
Returns:
true if the forest has been changed
Throws:
StructureException - if under is not in the forest or if a similar problem happens

mergeForest

void mergeForest(@Nullable
                 Forest forest,
                 long under,
                 long after,
                 @Nullable
                 ForestChangeEventHandler eventHandler)
                 throws StructureException

Merges another forest into this forest. After the method has executed, this forest will contain all issues from forest in the same topology under the specified positions: the root issues from forest will be positioned as defined by under-after coordinates (see Forest for the explanation of under-after coordinates), and non-root issues from forest will have the same parent issues as in forest.

This forest and the merged forest may have the same issues. In that case the issues are moved within this forest and placed at the position required by this operation.

This method does not modify the forest stored in the database for a structure. To make modifications of the structure's forest, run forest changing transaction with StructureManager.updateForest(com.atlassian.crowd.embedded.api.User, boolean, com.almworks.jira.structure.api.forest.ForestTransaction).

When StructureException is thrown from this method, the state of this forest is unknown - due to the fact that merge splits into several atomic updates and the exception may be thrown after some of the updates have taken place.

Parameters:
forest - the merged forest
under - the parent of the merged forest, or 0 if the forest issues should be placed at the root level
after - the preceding sibling of the merged forest, or 0 to place forest as the first child
eventHandler - an optional event handler to get notifications about changes being applied - may be called several times because merge could be split into series of moves and additions.
Throws:
StructureException - if the operation cannot be completed because it requires an invalid move

mergeForest

void mergeForest(@Nullable
                 Forest forest,
                 long under,
                 long after)
                 throws StructureException
Convenience method to call mergeForest(Forest, long, long, ForestChangeEventHandler) without event handler.

Parameters:
forest - the merged forest
under - the parent of the merged forest, or 0 if the forest issues should be placed at the root level
after - the preceding sibling of the merged forest, or 0 to place forest as the first child
Throws:
StructureException - if the operation cannot be completed because it requires an invalid move

set

Forest set(com.almworks.integers.WritableLongList issues,
           com.almworks.integers.WritableIntList depths,
           boolean reuseLists)

Replaces the contents of this forest with the values passed in the parameters.

The passed lists must satisfy the invariant conditions listed in Forest, otherwise the results are undefined.

This method does not modify the forest stored in the database for a structure. To make modifications of the structure's forest, run forest changing transaction with StructureManager.updateForest(com.atlassian.crowd.embedded.api.User, boolean, com.almworks.jira.structure.api.forest.ForestTransaction).

Parameters:
issues - new issue list
depths - new depths list
reuseLists - if true, the passed arrays may be used by the forest without copying the data. In that case, the calling code must not use these lists after this method call.
Returns:
this forest

set

Forest set(com.almworks.integers.LongList issues,
           com.almworks.integers.IntList depths)

Replaces the contents of this forest with the values passed in the parameters.

The passed lists must satisfy the invariant conditions listed in Forest, otherwise the results are undefined.

This method does not modify the forest stored in the database for a structure. To make modifications of the structure's forest, run forest changing transaction with StructureManager.updateForest(com.atlassian.crowd.embedded.api.User, boolean, com.almworks.jira.structure.api.forest.ForestTransaction).

Parameters:
issues - new issue list
depths - new depths list
Returns:
this forest

visitParentChildrenUpwards

void visitParentChildrenUpwards(ForestParentChildrenVisitor visitor)

This method is used to efficiently traverse all pairs (parent, children) from the end of the forest upwards.

This method goes over the forest in the backwards direction and reports to the visitor pairs of (parent, direct children).

Invariants:

If the forest is modified during iteration, the results are undefined.

Parameters:
visitor - an instance that receives the pairs of parent and children array

foldUpwards

@Nullable
<T,C> C foldUpwards(ForestParentChildrenClosure<T,C> closure)

This is a more generic version of visitParentChildrenUpwards(com.almworks.jira.structure.api.forest.ForestParentChildrenVisitor) that allows you to effectively process the forest bottom-up, probably saving on memory allocation and search speed.

The method goes over the forest in the backwards direction and calls closure methods for each issue:

Type Parameters:
T - the type of the result of processing one issue
C - the type of the result of processing a number of sub-issues under the same parent
Parameters:
closure - the closure
Returns:
the result of processing top-level issues in the forest
See Also:
visitParentChildrenUpwards(com.almworks.jira.structure.api.forest.ForestParentChildrenVisitor), ForestParentChildrenClosure

makeImmutable

@NotNull
Forest makeImmutable()
Makes this forest immutable - all mutator operations will throw UnsupportedOperationException.

Returns:
this forest

toFullString

@NotNull
String toFullString()
Utility method for debugging - returns full string representation of the forest, that contains all the information, unlike toString method, which may be truncated to some character number limit.

Returns:
a full string containing all information about this forest


Copyright © 2013 ALMWorks. All Rights Reserved.