// Path: src/main/java/pl/exsio/nestedj/ex/InvalidNodeException.java
// public class InvalidNodeException extends RuntimeException {
// 
//     public InvalidNodeException(String msg) {
//         super(msg);
//     }
// }
// 
// Path: src/main/java/pl/exsio/nestedj/ex/InvalidParentException.java
// public class InvalidParentException extends RuntimeException {
// 
//     public InvalidParentException(String msg) {
//         super(msg);
//     }
// }
// 
// Path: src/main/java/pl/exsio/nestedj/ex/RepositoryLockedException.java
// public class RepositoryLockedException extends RuntimeException {
// 
//     public RepositoryLockedException(String msg) {
//         super(msg);
//     }
// }
// 
// Path: src/main/java/pl/exsio/nestedj/model/NestedNode.java
// public interface NestedNode<ID extends Serializable> {
// 
//     /**
//      * Standarized Field Names used internally by NestedJ.
//      * Any Java class that implements the NestedNode interface should have fields with names matching the below constants.
//      */
//     String LEFT = "treeLeft";
//     String RIGHT = "treeRight";
//     String LEVEL = "treeLevel";
//     String PARENT_ID = "parentId";
//     String ID = "id";
// 
//     /**
//      *  Should be PK if using Database.
//      *
//      * @return unique Identifier of the Entity/Object.
//      */
//     ID getId();
// 
//     /**
//      * @return Nested Set Model LEFT value
//      */
//     Long getTreeLeft();
// 
//     /**
//      * @return Nested Set Model RIGHT value
//      */
//     Long getTreeRight();
// 
//     /**
//      * @return Nested Set Model LEVEL value
//      */
//     Long getTreeLevel();
// 
//     /**
//      * Should be a FK if using Database.
//      *
//      * @return Parent Idendifier
//      */
//     ID getParentId();
// 
//     /**
//      * Sets the unique Identifier of the Entity/Object.
//      *
//      * @param id - unique Identifier of the Entity/Object.
//      */
//     void setId(ID id);
// 
//     /**
//      * Sets the Nested Set Model LEFT value
//      *
//      * @param treeLeft - Nested Set Model LEFT value
//      */
//     void setTreeLeft(Long treeLeft);
// 
//     /**
//      * Sets the Nested Set Model RIGHT value
//      *
//      * @param treeRight - Nested Set Model RIGHT value
//      */
//     void setTreeRight(Long treeRight);
// 
//     /**
//      * Sets the Nested Set Model LEVEL value
//      *
//      * @param treeLevel - Nested Set Model LEVEL value
//      */
//     void setTreeLevel(Long treeLevel);
// 
//     /**
//      * Sets the Parent Idendifier
//      *
//      * @param parent - Parent Idendifier
//      */
//     void setParentId(ID parent);
// 
// }
// 
// Path: src/main/java/pl/exsio/nestedj/model/NestedNodeInfo.java
// public class NestedNodeInfo<ID extends Serializable> {
// 
//     private final ID id;
// 
//     private final ID parentId;
// 
//     private final Long left;
// 
//     private final Long right;
// 
//     private final Long level;
// 
//     public NestedNodeInfo(ID id, ID parentId, Long left, Long right, Long level) {
//         this.id = id;
//         this.parentId = parentId;
//         this.left = left;
//         this.right = right;
//         this.level = level;
//     }
// 
//     public ID getId() {
//         return id;
//     }
// 
//     public ID getParentId() {
//         return parentId;
//     }
// 
//     public Long getLeft() {
//         return left;
//     }
// 
//     public Long getRight() {
//         return right;
//     }
// 
//     public Long getLevel() {
//         return level;
//     }
// 
//     @Override
//     public String toString() {
//         return "NestedNodeInfo{" +
//                 "id=" + id +
//                 ", parentId=" + parentId +
//                 ", left=" + left +
//                 ", right=" + right +
//                 ", level=" + level +
//                 '}';
//     }
// }
// 
// Path: src/main/java/pl/exsio/nestedj/model/Tree.java
// public interface Tree<ID extends Serializable, N extends NestedNode<ID>> {
//     
//     void setChildren(List<Tree<ID, N>> children);
//     
//     void addChild(Tree<ID, N> child);
//     
//     List<Tree<ID, N>> getChildren();
//     
//     Tree<ID, N> getParent();
//     
//     void setParent(Tree<ID, N> parent);
//     
//     N getNode();
//     
//     void setNode(N node);
//     
// }


import pl.exsio.nestedj.delegate.*;
import pl.exsio.nestedj.ex.InvalidNodeException;
import pl.exsio.nestedj.ex.InvalidParentException;
import pl.exsio.nestedj.ex.RepositoryLockedException;
import pl.exsio.nestedj.model.NestedNode;
import pl.exsio.nestedj.model.NestedNodeInfo;
import pl.exsio.nestedj.model.Tree;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;
        inserter.insertAsFirstNode(node);
    }

    public boolean isAllowNullableTreeFields() {
        return allowNullableTreeFields;
    }

    public void setAllowNullableTreeFields(boolean allowNullableTreeFields) {
        this.allowNullableTreeFields = allowNullableTreeFields;
    }


    private void lockNode(N node, TreeModifier modifier) {
        if (!lock.lockNode(node)) {
            throw new RepositoryLockedException(String.format("Nested Node Repository is locked for Node %s. Try again later.", node));
        }
        try {
            modifier.modifyTree();
        } finally {
            lock.unlockNode(node);
        }
    }

    private void lockRepository(TreeModifier modifier) {
        if (!lock.lockRepository()) {
            throw new RepositoryLockedException("Nested Node Repository is locked. Try again later.");
        }
        try {
            modifier.modifyTree();
        } finally {
// Path: src/main/java/pl/exsio/nestedj/ex/InvalidNodeException.java
// public class InvalidNodeException extends RuntimeException {
// 
//     public InvalidNodeException(String msg) {
//         super(msg);
//     }
// }
// 
// Path: src/main/java/pl/exsio/nestedj/ex/InvalidParentException.java
// public class InvalidParentException extends RuntimeException {
// 
//     public InvalidParentException(String msg) {
//         super(msg);
//     }
// }
// 
// Path: src/main/java/pl/exsio/nestedj/ex/RepositoryLockedException.java
// public class RepositoryLockedException extends RuntimeException {
// 
//     public RepositoryLockedException(String msg) {
//         super(msg);
//     }
// }
// 
// Path: src/main/java/pl/exsio/nestedj/model/NestedNode.java
// public interface NestedNode<ID extends Serializable> {
// 
//     /**
//      * Standarized Field Names used internally by NestedJ.
//      * Any Java class that implements the NestedNode interface should have fields with names matching the below constants.
//      */
//     String LEFT = "treeLeft";
//     String RIGHT = "treeRight";
//     String LEVEL = "treeLevel";
//     String PARENT_ID = "parentId";
//     String ID = "id";
// 
//     /**
//      *  Should be PK if using Database.
//      *
//      * @return unique Identifier of the Entity/Object.
//      */
//     ID getId();
// 
//     /**
//      * @return Nested Set Model LEFT value
//      */
//     Long getTreeLeft();
// 
//     /**
//      * @return Nested Set Model RIGHT value
//      */
//     Long getTreeRight();
// 
//     /**
//      * @return Nested Set Model LEVEL value
//      */
//     Long getTreeLevel();
// 
//     /**
//      * Should be a FK if using Database.
//      *
//      * @return Parent Idendifier
//      */
//     ID getParentId();
// 
//     /**
//      * Sets the unique Identifier of the Entity/Object.
//      *
//      * @param id - unique Identifier of the Entity/Object.
//      */
//     void setId(ID id);
// 
//     /**
//      * Sets the Nested Set Model LEFT value
//      *
//      * @param treeLeft - Nested Set Model LEFT value
//      */
//     void setTreeLeft(Long treeLeft);
// 
//     /**
//      * Sets the Nested Set Model RIGHT value
//      *
//      * @param treeRight - Nested Set Model RIGHT value
//      */
//     void setTreeRight(Long treeRight);
// 
//     /**
//      * Sets the Nested Set Model LEVEL value
//      *
//      * @param treeLevel - Nested Set Model LEVEL value
//      */
//     void setTreeLevel(Long treeLevel);
// 
//     /**
//      * Sets the Parent Idendifier
//      *
//      * @param parent - Parent Idendifier
//      */
//     void setParentId(ID parent);
// 
// }
// 
// Path: src/main/java/pl/exsio/nestedj/model/NestedNodeInfo.java
// public class NestedNodeInfo<ID extends Serializable> {
// 
//     private final ID id;
// 
//     private final ID parentId;
// 
//     private final Long left;
// 
//     private final Long right;
// 
//     private final Long level;
// 
//     public NestedNodeInfo(ID id, ID parentId, Long left, Long right, Long level) {
//         this.id = id;
//         this.parentId = parentId;
//         this.left = left;
//         this.right = right;
//         this.level = level;
//     }
// 
//     public ID getId() {
//         return id;
//     }
// 
//     public ID getParentId() {
//         return parentId;
//     }
// 
//     public Long getLeft() {
//         return left;
//     }
// 
//     public Long getRight() {
//         return right;
//     }
// 
//     public Long getLevel() {
//         return level;
//     }
// 
//     @Override
//     public String toString() {
//         return "NestedNodeInfo{" +
//                 "id=" + id +
//                 ", parentId=" + parentId +
//                 ", left=" + left +
//                 ", right=" + right +
//                 ", level=" + level +
//                 '}';
//     }
// }
// 
// Path: src/main/java/pl/exsio/nestedj/model/Tree.java
// public interface Tree<ID extends Serializable, N extends NestedNode<ID>> {
//     
//     void setChildren(List<Tree<ID, N>> children);
//     
//     void addChild(Tree<ID, N> child);
//     
//     List<Tree<ID, N>> getChildren();
//     
//     Tree<ID, N> getParent();
//     
//     void setParent(Tree<ID, N> parent);
//     
//     N getNode();
//     
//     void setNode(N node);
//     
// }


// Path: src/main/java/pl/exsio/nestedj/DelegatingNestedNodeRepository.java
import pl.exsio.nestedj.delegate.*;
import pl.exsio.nestedj.ex.InvalidNodeException;
import pl.exsio.nestedj.ex.InvalidParentException;
import pl.exsio.nestedj.ex.RepositoryLockedException;
import pl.exsio.nestedj.model.NestedNode;
import pl.exsio.nestedj.model.NestedNodeInfo;
import pl.exsio.nestedj.model.Tree;
import java.io.Serializable;
import java.util.List;
import java.util.Optional;

        inserter.insertAsFirstNode(node);
    }

    public boolean isAllowNullableTreeFields() {
        return allowNullableTreeFields;
    }

    public void setAllowNullableTreeFields(boolean allowNullableTreeFields) {
        this.allowNullableTreeFields = allowNullableTreeFields;
    }


    private void lockNode(N node, TreeModifier modifier) {
        if (!lock.lockNode(node)) {
            throw new RepositoryLockedException(String.format("Nested Node Repository is locked for Node %s. Try again later.", node));
        }
        try {
            modifier.modifyTree();
        } finally {
            lock.unlockNode(node);
        }
    }

    private void lockRepository(TreeModifier modifier) {
        if (!lock.lockRepository()) {
            throw new RepositoryLockedException("Nested Node Repository is locked. Try again later.");
        }
        try {
            modifier.modifyTree();
        } finally {
            lock.unlockRepository();