Interface TreeManager
This interface works by directly handling objects represented by
Element, where each one behaves similarly to a node within the tree.
So, in practical terms, this interface allows the API client to handle
business objects with tree-like behavior.
Operations here are performed on elements within other elements or on "root" elements. Root elements are those that are not inside other elements, but are at the "top" of the tree hierarchy in question. When the tree is created, its root is also created automatically, and it can be empty or have multiple children.
The operations are also done for cases where it is desirable to reallocate elements to other tree sessions. In this case, the uniqueness of each element as well as the same class type of the nodes must be respected, related to the tree in which elements will be placed.
It is important to note that there are two distinct and well-defined
contexts in the HappyTree API: the inside and outside contexts. When the API
client obtains an element and its children through the manager, the API
client is actually working with identical copies of each node (element). When
the API client makes any changes to any of the elements, a change in the
element's lifecycle is made, and this change is not immediately reflected in
the tree in question. This context is called outside the tree. An inside
context represents the client's action to perform the persist/update of the
element by using this interface, so the change is actually reflected in
the tree, but made through this manager itself. The persist/update operations
work by invoking persistElement(Element) and
updateElement(Element) respectively.
Conceptually, this interface handles trees through a transaction. This
transaction is represented by the TreeTransaction interface, and the
relation between both interfaces is 1:1. Therefore, this interface will
always be linked to a single transaction, which can contain none or many
sessions, but it is only possible to handle one session at a time.
The API client must be sure to handle elements through their respective transactions. A simple swap of a tree, by a transaction, makes this manager ready to deal with a totally different tree.
For operations to work, the following validations are made:
- The transaction must have a session bound, always.
- It is mandatory that the session be activated.
- According to the method, the elements must be in the proper state.
- For each tree session, each element inside must have a unique
@Id. - An element cannot be handled within trees that have different types of wrapped object nodes.
- It is not possible to handle root elements for the
copy(Element, Element),cut(Element, Element),persistElement(Element)andremoveElement(Element)methods.
If one of these validations fails, an exception will be thrown.
| Element State/operation | Attached | Detached | Not Existed |
|---|---|---|---|
| Cut | ✔ | X | X |
| Copy | ✔ | X | X |
| Remove | ✔ | X | X |
| Update | ✔ | ✔ | X |
| Persist | X | X | ✔ |
- Author:
- Diego Madson de Andrade Nóbrega
- See Also:
-
Method Summary
Modifier and TypeMethodDescription<T> voidApplies a function to be performed on all elements within the entire tree structure.<T> voidApplies a function to be performed on elements that satisfy a specific condition within the entire tree structure.booleancontainsElement(Element<?> element) Verifies that the current tree session has the specifiedelement.<T> booleancontainsElement(Element<T> parent, Element<T> descendant) Verifies whether theparentelement contains inside of it thedescendantelement in this current session.booleanVerifies that the current tree session has the specified element by the given@Id.booleancontainsElement(Object parent, Object descendant) Verifies whether theparentelement contains inside of it thedescendantelement in this current session.<T> Element<T> Copies the respectivefromelement into thetoelement in another tree session.<T> Element<T> createElement(Object id, Object parent, T wrappedNode) Creates an element with theid,parentand the wrapped object node.<T> Element<T> Cuts thefromelement into thetoelement, whether for the same session or not.<T> Element<T> Cuts thefromelement into thetoelement, inside of the same session.<T> Element<T> getElementById(Object id) Obtains an element by@Idin the current tree session.Returns theTreeTransactioninstance associated with this manager.<T> Element<T> persistElement(Element<T> newElement) Persists a new element into the current tree session.<T> Element<T> removeElement(Element<T> element) Removes the corresponding element from the tree session and returns the removed element itself.<T> Element<T> removeElement(Object id) Removes the element by its@Id.<T> Element<T> root()Returns the root of the tree in this current session.Searches for elements that satisfy a specific condition within the entire tree structure.<T> Element<T> updateElement(Element<T> element) Updates the state of the element to the tree.
-
Method Details
-
cut
Cuts thefromelement into thetoelement, whether for the same session or not. With this, the element to be cut can be cut into the same tree session or to another tree in another session. All children of thefromelement will be cut as well.If the
toparameter element isnull, then thefromelement with all children will be moved to the root level of the same tree.When cutting to the target element, the
fromparameter element cannot have a duplicate@Idin the tree where thetoparameter element is located. This also includes the children IDs of thefromelement.It is imperative that both trees of the
fromandtoelements be activated.- Parameters:
from- the source elementto- the target element- Returns:
- a copy of
fromelement after cut - Throws:
TreeException- when:- The transaction has no selected session to work;
-
The current session or the session which the
toelement belongs is not active; -
The
fromelement does not belong in the correct current session; -
The
fromandtoelements have different types of wrapped nodes; -
The
fromelement is represented by the root of the tree (it is not possible to handle root elements); -
The
fromortoelement or at least one of their children have a DETACHED or NOT_EXISTED state in the lifecycle; -
The
fromelement has an already existing@Idin the target tree (if thetoelement is in another tree).
IllegalArgumentException- when thefromparameter isnull
-
cut
Cuts thefromelement into thetoelement, inside of the same session. Both parameters represent the@Idof elements.If the
toparameter isnullor if its respective element is not found, then thefromelement with all children will be moved to the root level of the tree.If it is not possible to find the
fromelement id passed through the parameter, thennullis returned.Using this
cut(Object, Object)operation, an element can only be cut into the same tree. To cut elements to other trees, consider usingcut(Element, Element)where the target element is linked to another tree.- Parameters:
from- the source elementto- the target element- Returns:
- a copy of the element represented by the
fromparameter, after cut - Throws:
TreeException- when:- The transaction has no selected session to work;
- The current session is not active;
-
The
fromelement does not belong in the correct current session;
IllegalArgumentException- when thefromparameter isnull
-
copy
Copies the respectivefromelement into thetoelement in another tree session. The entire structure of the copied element will be pasted inside thetoelement. The element to be copied and all its children cannot have the same identifier as any element in thetoelement tree.Ensure that the current session is referencing the session to which the
fromelement belongs, otherwise an exception with the description "Element not defined in this session" will be thrown.Also, this method should only be used when the client desires to copy the element between different trees. It is not possible to copy elements inside the same tree, because it will throw a duplicate
@Idexception.The following steps are done internally inside the core API to copy an element:
- Validates the current session and the input;
- Copies the whole element structure with all the children;
- Invokes
TreeTransaction.sessionCheckout(String)so that the target tree can be worked on; - Pastes the elements;
- Invokes
TreeTransaction.sessionCheckout(String)back to the source tree, as before.
It is mandatory that both
fromandtoelements be attached in different trees, and both trees must be activated.- Parameters:
from- the source elementto- the target element- Returns:
- a copy of the copied element in the target tree session
- Throws:
TreeException- when:- The transaction has no selected session to work;
-
The current session (to which the
fromelement belongs) or the session which thetoelement belongs is not active; -
The
fromelement does not belong in the correct current session (it occurs when the current session is not the same to whichfromelement belongs); -
The
fromandtoelements have different types of wrapped nodes; -
The
fromelement is represented by the root of the tree (it is not possible to handle root elements); -
The
fromortoelement or at least one of their children have a DETACHED or NOT_EXISTED state in the lifecycle; -
The
fromelement has an already existing@Idin the target tree.
IllegalArgumentException- when thefromortoparameters arenull
-
removeElement
Removes the corresponding element from the tree session and returns the removed element itself. After being removed, the element and all its children will have the NOT_EXISTED state in the lifecycle. In the case of reinserting this removed element, it must be persisted again.The element to be removed must be attached (ATTACHED state) in the tree and cannot have changes. All children will be removed as well, if they are in the ATTACHED state in their lifecycle. If there is at least a single child element that is not ATTACHED, then none will be removed and this method will return
null.In the case where the
elementor its children are not attached, then it is necessary to attach them in the current tree session by invokingpersistElement(Element)if it is a new element or invokingupdateElement(Element)if it is a changed element. After that, theelementin question becomes attached again and can then be removed.If the
elementparameter isnullthen this method also will returnnull.- Parameters:
element- the element to be removed with all its children- Returns:
- the removed element itself, but now with the NOT_EXISTED state in the lifecycle
- Throws:
TreeException- when:- The transaction has no selected session to work;
- The current session is not active;
-
The
fromelement does not belong in the correct current session; -
The
elementhas a different type of wrapped node related to the current session; -
The
elementis represented by the root of the tree (it is not possible to handle root elements); -
The
elementor at least one of its children have a DETACHED or NOT_EXISTED state in the lifecycle;
-
removeElement
Removes the element by its
@Id. All children of the found element are removed as well and returns the removed element itself. Note that removing an element means that this element will be permanently eliminated from inside the tree, having its state as NOT_EXISTED in its lifecycle.If the
@Idcannot be found or isnull, then this method will returnnull.Be sure to be in the correct tree session, so as not to remove an element with the same
@Idbut in another tree.- Parameters:
id- the identifier of the element to be removed- Returns:
- the removed element itself, but with the NOT_EXISTED state in the lifecycle
- Throws:
TreeException- when:- The transaction has no selected session to work;
- The current session is not active;
-
getElementById
Obtains an element by@Idin the current tree session.If the
@Idisnullor it cannot be found in the tree, then this method will returnnull.The id corresponds to the
@Idannotated attribute of the wrapped object node in the API Transformation Process or just an ID which the API client chooses. When a tree is being built by a previous collection of objects (API Transformation Process), the core API will bind the elements by this@Idannotated attribute.Therefore:
- The
@Idcan never benull; - The
@Idis always unique in the tree.
The element and its children returned by this method represent elements with ATTACHED state in relation to the current tree session. An attached element means that the element and its children are "mirror" pieces of the tree.
If the element or its children change states, then it is necessary to attach them again in the current tree session by invoking
updateElement(Element)to be able to handle them, for operations likecut(Element, Element)orcopy(Element, Element)for example.- Parameters:
id- the element identifier- Returns:
- an identical copy of the found element
- Throws:
TreeException- when the transaction has no selected session to work or the current session is not active
- The
-
containsElement
Verifies whether theparentelement contains inside of it thedescendantelement in this current session.If both
parentanddescendantelements arenullor their (including the children) state are not ATTACHED to this tree session, thenfalseis returned.- Parameters:
parent- the element which will contain thedescendantelementdescendant- the element which is inside ofparentelement- Returns:
truevalue if theparentelement contains thedescendantelement,falseotherwise- Throws:
TreeException- when the transaction has no selected session to work or the current session is not active
-
containsElement
Verifies whether theparentelement contains inside of it thedescendantelement in this current session.The
parentanddescendantidentifiers are used to bring the respective elements. If bothparentanddescendantelements arenullor not found, thenfalseis returned.When the elements are found, then it means that they were already caught from a tree and they are automatically with the ATTACHED state, so this method returns
truewhen thedescendantelement is inside of theparentelement.- Parameters:
parent- the parent identifier which will contain thedescendantelementdescendant- the descendant identifier which will be inside of theparentelement- Returns:
truevalue if theparentelement contains thedescendantelement,falseotherwise- Throws:
TreeException- when the transaction has no selected session to work or the current session is not active
-
containsElement
Verifies that the current tree session has the specifiedelement.If the
elementisnull, not found or if theelementor at least one of its children is not in the ATTACHED state in the lifecycle thenfalseis returned.- Parameters:
element- the specified element to be searched- Returns:
truevalue if the tree contains theelement,falseotherwise- Throws:
TreeException- when the transaction has no selected session to work or the current session is not active
-
containsElement
Verifies that the current tree session has the specified element by the given@Id.If the element is not found in the tree or the
idisnullthenfalseis returned.- Parameters:
id- the identifier of the element to be searched- Returns:
truevalue if the tree contains the respective element,falseotherwise- Throws:
TreeException- when the transaction has no selected session to work or the current session is not active
-
createElement
Creates an element with theid,parentand the wrapped object node. Only theidis mandatory. When theparentis null or not found, then this element will be moved to inside of the root level (first level) of the tree, when persisted.Creating a new element does not mean that it will be automatically in the tree of the current session. When creating a new element, it is "outside" of the tree yet, having the NOT_EXISTED state in the lifecycle. The element needs to be attached in the tree right after the creation moment time, by invoking
persistElement(Element). So, after that, the element becomes attached and finally can be handled bycut(Element, Element)orcopy(Element, Element)operations for example.Ensure that the parameterized type when creating an element is the same type of the object related to the current session.
- Type Parameters:
T- the class type of wrapped object node that will be encapsulated into theElementobject- Parameters:
id- the identifier of the new elementparent- the parent identifier of this new elementwrappedNode- the object to be encapsulated in this element- Returns:
- a new element with the NOT_EXISTED state in lifecycle
- Throws:
TreeException- when the transaction has no selected session to work or the current session is not activeIllegalArgumentException- when theidparameter isnull
-
persistElement
Persists a new element into the current tree session. The new element to be persisted must have a unique identifier in the tree session. If the@Parentof this new element is defined withnullor if it is simply not found, then this new element will be persisted in root level of the tree (first level).Also, the new element must be essentially new, created using the
createElement(Object, Object, Object)method to guarantee a coherent detached state from the current tree. After creating the element, it will have the NOT_EXISTED state in the lifecycle, even its children (in case of creating children inside this element).This method also allows new chained children elements to be persisted at once. If the element has duplicate identifier or there is a descendant in this element to be created that has duplicate identifier in relation to the tree, then an exception will be thrown.
The NOT_EXISTED state represents an "outside tree session" element, which means that this element has not been inside any tree. When the element is persisted by this operation, its state changes to ATTACHED in the lifecycle. This also happens with its children when they are persisted at once.
Element States Element Status Ways persistElement() NOT_EXISTED createElement(Object, Object, Object)Yes ATTACHED getElementById(Object)No DETACHED getElementById(Object)-Element.setId(Object)No - Parameters:
newElement- the element to be persisted- Returns:
- a copy of the new persisted element with the ATTACHED state in lifecycle
- Throws:
TreeException- when:- The transaction has no selected session to work;
- The current session is not active;
-
The
newElementdoes not belong in the correct current session; -
The
newElementhas a different type of wrapped node related to the current session; -
The
newElementor at least one of its descendants have a DETACHED or ATTACHED state in the lifecycle; -
The
newElementhas an already existing identifier in this session.
IllegalArgumentException- when thenewElementor its@Idisnull
-
updateElement
Updates the state of the element to the tree. Synchronizes a previous changed element.To be updated, an element should be previously captured by invoking
getElementById(Object)for example, and its state should be as DETACHED.A DETACHED element represents an element, or one of its descendants, that has undergone some change, whether it be the
@Id, the@Parent, or the wrapped node. Make sure to avoid duplicate@Idin the current session when changing an@Id. To move the element to the root level (first level), just set the@Parentasnullor reference an inexistent parent element.This operation is for DETACHED elements. Trying to update a NOT_EXISTED element in the tree throws an exception. For ATTACHED elements, nothing happens because the element is already attached, and the same copy is returned.
Therefore, it is only possible to update an element through
persistElement(Element)or by the API Transformation Process, passing a previous list of elements to be transformed into a tree by theTreeTransaction.initializeSession(String, java.util.Collection)method.This operation also works for the root element, allowing the update when the root element adds or removes children elements directly.
When updating an element, its children list will also be automatically updated recursively. After updating, all elements have their states as ATTACHED in the lifecycle.
Element States Element Status Ways updateElement() NOT_EXISTED createElement(Object, Object, Object)No ATTACHED getElementById(Object)Yes DETACHED getElementById(Object)-Element.setId(Object)Yes - Parameters:
element- the element to be updated- Returns:
- a copy of the updated element with the ATTACHED state in the lifecycle
- Throws:
TreeException- when:- The transaction has no selected session to work;
- The current session is not active;
-
The
elementdoes not belong in the correct current session; -
The
elementhas a different type of wrapped node related to the current session; -
The
elementor at least one of its descendants have a NOT_EXISTED state in the lifecycle; -
The
elementhas an already existing@Idin this session.
IllegalArgumentException- when theelementor its@Idisnull
-
getTransaction
TreeTransaction getTransaction()Returns theTreeTransactioninstance associated with this manager.The manager is closely related to the transaction. Every operation defined in this interface needs to check the transaction and verify whether there is a session to be managed.
If there is no session to be handled or the session is not active inside the transaction, an error occurs. The API client using this method should know what session (tree) is preferred to work with. This transaction object has this objective to provide and handle the sessions.
TREEMANAGER (invokes) -> TREETRANSACTION (to store) -> TREESESSION (that contains) -> ELEMENT- Returns:
- the transaction associated to this manager
-
root
Returns the root of the tree in this current session.The root structure is also an object of
Elementtype which represents the top of the tree and encompasses all other elements.It contains a collection of children, which in turn contains a collection of children, and so on recursively. All this structure is returned in this method as
Elementtype.The root element is like a 'special' element created exclusively by the core API. All elements that the API client handles are under the root element. Thus it is not possible to create a root element. Because of that, every object node with a
null@Parentor an unknown (not found)@Parentwill be attached directly as an immediate root child (first level).Unlike regular elements, the root element has no metadata associated with it, such as
@Id,@Parentand wrapped object node. Therefore, calling theElement.getId(),Element.getParent()orElement.unwrap()methods on the root element will always returnnull.For being a special element, write operations like copy, cut or remove cannot be applied directly to the root element, otherwise an exception will be thrown and the execution aborted.
Below, an example of a tree structure with its root element and children:
ELEMENT(ROOT) /\ ELEMENT(A) ELEMENT(B) /\ /\ E(A1) E(A2) E(B1) E(B2)The creation of the root element is responsibility of the core API. It occurs at the moment of initialization of a new session when theTreeTransaction.initializeSession(String, java.util.Collection)orTreeTransaction.initializeSession(String, Class)is invoked.- Returns:
- the root element
- Throws:
TreeException- when the transaction has no selected session to work or if the current session is not active- See Also:
-
search
Searches for elements that satisfy a specific condition within the entire tree structure. The method returns a list of elements that match the provided condition.This method traverses the complete tree starting from the root element and evaluates each element against the specified condition. If an element satisfies the condition, it is included in the resulting list.
The resulting list consists of all elements that match the specified condition, including their children. Therefore, the list will include the matching elements while preserving each element's hierarchy.
Example usage:
//Find all elements which the object node has its name starting with "A" List<Element<MyNodeType>> results = manager.search( e -> e.unwrap().getName().startsWith("A") );- Parameters:
condition- the predicate function defining the search criteria- Returns:
- a list of elements that satisfy the specified condition
- Throws:
TreeException- when the transaction has no selected session to work or if the current session is not active
-
apply
Applies a function to be performed on all elements within the entire tree structure. The action applied to every element in the tree is automatically reflected on the tree session (if there are any changes), not being necessary to invoke thepersistElement(Element)norupdateElement(Element)to save the changes.This method traverses the complete tree starting from the root element and applies the given action to all elements in the tree (except for the root element itself). Unlike
apply(Consumer, Predicate), this method operates on the entire tree structure rather than just a subset of elements that match the condition.The action function receives each
Elementas a parameter and can perform any operation on it, such as modifying the wrapped object, changing element properties, or performing calculations/verifications.The action is applied to all elements in the tree, except for the root element itself, as it is a special element created by the HappyTree API itself, not having the
@Id,@Parentnor a wrapped object node.Example usage:
//Transform all directory names to uppercase in the entire tree manager.apply(e -> e.unwrap().transformNameToUpperCase()); //Log all element IDs in the tree manager.apply(e -> System.out.println("Element ID: " + e.getId()));Note: The function is applied to all elements in the entire tree (except for the root element itself). If you need conditional execution based on specific criteria, consider using
apply(Consumer, Predicate)instead.- Parameters:
action- the function to apply to each element in the tree- Throws:
TreeException- when the transaction has no selected session to work or if the current session is not active- See Also:
-
apply
Applies a function to be performed on elements that satisfy a specific condition within the entire tree structure. The action applied to every matching element in the tree is automatically reflected on the tree session (if there are any changes), not being necessary to invoke thepersistElement(Element)norupdateElement(Element)to save the changes.This method traverses the complete tree starting from the root element and applies the given action only to elements that satisfy the specified condition (not including the root element itself). Unlike
apply(Consumer), this method allows for selective application of the action based on custom criteria defined by the condition.The action function receives each
Elementthat meets the condition as a parameter and can perform any operation on it, such as modifying the wrapped object, changing element properties, or performing calculations/verifications.The condition is a predicate function that takes an
Elementas input and returns a boolean value indicating whether the action should be applied to that element. Only elements for which the condition evaluates totruewill have the action applied.Example usage:
//Transform names to uppercase for directories only manager.apply( e -> e.unwrap().transformNameToUpperCase(), e -> e.unwrap().isDirectory() ); //Log IDs of elements with names starting with "A" manager.apply( e -> System.out.println("Element ID: " + e.getId()), e -> e.unwrap().getName().startsWith("A") );Note: The function is applied only to elements that satisfy the specified condition (not including the root element). If you want to apply an action to all elements in the tree, consider using
apply(Consumer)instead.- Parameters:
action- the function to apply to each element that meets the conditioncondition- the predicate function to determine which elements should have the action applied- Throws:
TreeException- when the transaction has no selected session to work or if the current session is not active- See Also:
-