[ONOS-5076] YANG data tree Builder

Change-Id: I25160b651c26e614d29d7fad85e63f77a262d77c
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YangRequestWorkBench.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YangRequestWorkBench.java
new file mode 100644
index 0000000..5ae1230
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ydt/YangRequestWorkBench.java
@@ -0,0 +1,758 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yms.app.ydt;
+
+import com.google.common.collect.ImmutableMap;
+import org.onosproject.yangutils.datamodel.YangList;
+import org.onosproject.yangutils.datamodel.YangSchemaNode;
+import org.onosproject.yangutils.datamodel.YangSchemaNodeContextInfo;
+import org.onosproject.yangutils.datamodel.YangSchemaNodeIdentifier;
+import org.onosproject.yms.app.ysr.YangSchemaRegistry;
+import org.onosproject.yms.ydt.YdtContext;
+import org.onosproject.yms.ydt.YdtContextOperationType;
+import org.onosproject.yms.ydt.YdtType;
+import org.onosproject.yms.ydt.YmsOperationType;
+
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.onosproject.yangutils.datamodel.YangSchemaNodeType.YANG_MULTI_INSTANCE_LEAF_NODE;
+import static org.onosproject.yms.app.ydt.AppNodeFactory.getAppContext;
+import static org.onosproject.yms.app.ydt.RequestedCallType.LEAF;
+import static org.onosproject.yms.app.ydt.RequestedCallType.OTHER;
+import static org.onosproject.yms.app.ydt.RequestedCardinality.MULTI_INSTANCE;
+import static org.onosproject.yms.app.ydt.RequestedCardinality.MULTI_INSTANCE_LEAF;
+import static org.onosproject.yms.app.ydt.RequestedCardinality.SINGLE_INSTANCE;
+import static org.onosproject.yms.app.ydt.RequestedCardinality.UNKNOWN;
+import static org.onosproject.yms.app.ydt.YdtConstants.errorMsg;
+import static org.onosproject.yms.app.ydt.YdtNodeFactory.getAppOpTypeFromYdtOpType;
+import static org.onosproject.yms.ydt.YdtContextOperationType.CREATE;
+import static org.onosproject.yms.ydt.YdtContextOperationType.DELETE;
+import static org.onosproject.yms.ydt.YdtContextOperationType.MERGE;
+import static org.onosproject.yms.ydt.YdtContextOperationType.REMOVE;
+import static org.onosproject.yms.ydt.YdtType.MULTI_INSTANCE_LEAF_VALUE_NODE;
+import static org.onosproject.yms.ydt.YdtType.MULTI_INSTANCE_NODE;
+
+/**
+ * Represents YANG request work bench which contains all parameters for
+ * request handling and methods to build and obtain YANG data tree
+ * which is data (sub)instance representation, abstract of protocol.
+ */
+public class YangRequestWorkBench implements YdtExtendedBuilder {
+
+    // ydt formatted error string
+    private static final String FMT_NOT_EXIST =
+            "Application with name \"%s\" doesn't exist.";
+    private static final String E_USE_ADDLEAF =
+            "Requested Node should be created using addLeaf interface";
+    private static final String E_MULTI_INS =
+            "Adds an instance of type list or leaf-list node only";
+    private static final String E_CREATE =
+            "Create request is not allowed under delete operation";
+    private static final String E_DEL =
+            "Delete request is not allowed under create operation";
+    private static final String E_INVOKE_PARENT =
+            "Can't invoke get parent at logical root node";
+    private static final String FMT_TOO_FEW =
+            "Too few key parameters in %s. Expected %d; actual %d.";
+    private static final String FMT_TOO_MANY =
+            "Too many key parameters in %s. Expected %d; actual %d.";
+
+    /*
+     * Current node in YANG data tree, kept to maintain the
+     * current context in YDT.
+     */
+    private YdtNode curNode;
+
+    /*
+     * Root node in YANG data tree, kept to maintain the root context in
+     * YDT.
+     */
+    private YdtNode rootNode;
+
+    /*
+     * Current node in YANG data tree, kept to maintain the current context
+     * in ydt application tree.
+     */
+    private YdtAppContext appCurNode;
+
+    /*
+     * Root node in YANG data tree, kept to maintain the root context in ydt
+     * application tree.
+     */
+    private YdtAppContext appRootNode;
+
+    /**
+     * Root Node Tag attribute in YANG data tree, kept to maintain the root
+     * tag attributes in YDT.
+     * <p>
+     * First key param of map represent tagName  name of tag attribute.
+     * Second param of map represent tagValue value of tag attribute
+     */
+    private Map<String, String> rootTagAttributeMap;
+
+    /*
+     * YANG schema registry reference.
+     */
+    private YangSchemaRegistry registry = null;
+
+    /*
+     * YMS operation type.
+     */
+    private final YmsOperationType ymsOperationType;
+
+    /*
+     * YDT default operation type.
+     */
+    private YdtContextOperationType ydtDefaultOpType;
+
+    /*
+     * Flag to identify data validation need to be done by YDT or not.
+     */
+    private final boolean validate;
+    // TODO validate need to be handle later with interaction type basis in
+    // future when it will be supported
+
+
+    /**
+     * Creates an instance of YANG request work bench which is use to initialize
+     * logical rootNode and and schema registry.
+     *
+     * @param name       name of logical container of a protocol
+     *                   which is a holder of the complete tree
+     * @param namespace  namespace of logical container
+     * @param opType     type of operation done by using YANG
+     *                   interface
+     * @param registry   Yang schema registry
+     * @param isValidate Flag to identify data validation need to be
+     *                   done by YDT or not
+     */
+    public YangRequestWorkBench(String name, String namespace,
+                                YmsOperationType opType,
+                                YangSchemaRegistry registry,
+                                boolean isValidate) {
+        YdtNode newNode;
+        YangSchemaNodeIdentifier nodeIdentifier =
+                new YangSchemaNodeIdentifier();
+        nodeIdentifier.setName(name);
+        nodeIdentifier.setNameSpace(namespace);
+        newNode = new YdtSingleInstanceNode(nodeIdentifier);
+        setRootNode(newNode);
+        this.registry = registry;
+        ymsOperationType = opType;
+        validate = isValidate;
+        // Set the logical root node for yang data app tree.
+        DefaultYdtAppContext appNode = getAppContext(true);
+
+        setAppRootNode(appNode);
+    }
+
+    /**
+     * Sets the logical root context information available in YDT node.
+     *
+     * @param node logical root node
+     */
+    private void setRootNode(YdtNode node) {
+        rootNode = node;
+        curNode = node;
+    }
+
+    /**
+     * Sets the app context tree logical root node  for ydt application tree.
+     *
+     * @param node application tree's logical root node
+     */
+    private void setAppRootNode(YdtAppContext node) {
+        appRootNode = node;
+        appCurNode = node;
+    }
+
+    /**
+     * Returns the YANG schema registry of Ydt.
+     * This method will be used by ytb.
+     *
+     * @return YANG schema registry
+     */
+    public YangSchemaRegistry getYangSchemaRegistry() {
+        return registry;
+    }
+
+    /**
+     * Returns the app context tree root node for ydt application tree.
+     * This method will be used by yab.
+     *
+     * @return YdtAppContext refers to root node of ydt application tree
+     */
+    public YdtAppContext getAppRootNode() {
+        return appRootNode;
+    }
+
+    /**
+     * Returns the data tree for given node identifier.
+     *
+     * @param id        Represents node identifier of YANG data tree node
+     * @param namespace namespace of the application requested by user
+     * @return YANG data tree node
+     */
+    private YdtNode moduleHandler(YangSchemaNodeIdentifier id,
+                                  String namespace) {
+
+        YangSchemaNode node = registry
+                .getYangSchemaNodeUsingSchemaName(id.getName());
+
+        if (node == null ||
+                namespace != null && !namespace.equals(node.getNameSpace())) {
+            curNode.errorHandler(errorMsg(
+                    FMT_NOT_EXIST, id.getName()), rootNode);
+        }
+
+        YdtNode newNode = new YdtSingleInstanceNode(id);
+        newNode.setYangSchemaNode(node);
+        id.setNameSpace(node.getNameSpace());
+        return newNode;
+    }
+
+    @Override
+    public void setRootTagAttributeMap(Map<String, String> attributeTag) {
+        rootTagAttributeMap = attributeTag;
+    }
+
+    @Override
+    public Map<String, String> getRootTagAttributeMap() {
+        if (rootTagAttributeMap != null) {
+            return ImmutableMap.copyOf(rootTagAttributeMap);
+        }
+        return null;
+    }
+
+    @Override
+    public void addChild(String name, String namespace) {
+        addChild(name, namespace, UNKNOWN, null, OTHER);
+    }
+
+    @Override
+    public void addChild(String name, String namespace, YdtType ydtType) {
+        addChild(name, namespace, ydtType, null);
+    }
+
+    @Override
+    public void addChild(String name, String namespace,
+                         YdtContextOperationType opType) {
+        addChild(name, namespace, UNKNOWN, opType, OTHER);
+    }
+
+    @Override
+    public void addChild(String name, String namespace, YdtType ydtType,
+                         YdtContextOperationType opType) {
+        RequestedCardinality cardinality = null;
+        switch (ydtType) {
+            case MULTI_INSTANCE_NODE:
+                cardinality = MULTI_INSTANCE;
+                break;
+            case SINGLE_INSTANCE_NODE:
+                cardinality = SINGLE_INSTANCE;
+                break;
+            default:
+                curNode.errorHandler(E_USE_ADDLEAF, rootNode);
+        }
+        addChild(name, namespace, cardinality, opType, OTHER);
+    }
+
+    /**
+     * Adds a last child to YANG data tree; this method is to be used by all
+     * protocols internally which are aware or unaware of the nature
+     * (single/multiple) of node.
+     *
+     * @param name        name of child to be added
+     * @param namespace   namespace of child to be added
+     * @param cardinality type of YANG data tree node operation
+     * @param opType      type of requested operation over a node
+     * @param callType    to identify the whether its a leaf or other node
+     */
+    private void addChild(String name, String namespace,
+                          RequestedCardinality cardinality,
+                          YdtContextOperationType opType,
+                          RequestedCallType callType) {
+
+        YdtNode childNode;
+        boolean isContextSwitch = false;
+        YangSchemaNode schemaNode = null;
+        YangSchemaNodeContextInfo contextInfo;
+        YangSchemaNode augmentingSchema = null;
+
+        YangSchemaNodeIdentifier id = new YangSchemaNodeIdentifier();
+        id.setName(name);
+
+        // Module/sub-module node handler.
+        if (curNode.equals(rootNode)) {
+            childNode = moduleHandler(id, namespace);
+        } else {
+
+            // If namespace given by user null, then take namespace from parent.
+            if (namespace == null) {
+                namespace = curNode.getYdtNodeIdentifier().getNameSpace();
+            }
+
+            id.setNameSpace(namespace);
+
+            /*
+             * Get the already exiting YDT node in YDT tree with same
+             * nodeIdentifier
+             */
+            childNode = curNode.getCollidingChild(id);
+
+            /*
+             * If colliding child doesn't exist ,
+             * then query yang data model for schema of given node.
+             */
+            if (childNode == null) {
+                /*
+                 * Get Yang Schema node context info which is having
+                 * YangSchemaNode and ContextSwitchedNode.
+                 */
+                contextInfo = curNode.getSchemaNodeContextInfo(id);
+
+                if (contextInfo.getContextSwitchedNode() != null) {
+                    augmentingSchema = appCurNode.getAugmentingSchemaNode(
+                            id, contextInfo);
+                    if (augmentingSchema != null) {
+                        /*
+                         * As two tree(YDT and YDT Application Tree) are getting
+                         * prepared in parallel, So  setting context switch
+                         * flag it will help ydt to keep the track whether
+                         * ydtApp tree also need to be traversed back to parent
+                         * or not with YDT tree traverse to parent call.
+                         */
+                        isContextSwitch = true;
+                    }
+                }
+                schemaNode = contextInfo.getSchemaNode();
+            } else {
+                /*
+                 * If colliding child exist , then will be leaf-list or list
+                 * If its leaf-list then return and add new requested
+                 * value/valueSet in same node else take yang data model
+                 * information from colliding child.
+                 */
+                if (childNode.getYdtType() == MULTI_INSTANCE_LEAF_VALUE_NODE) {
+                    curNode = childNode;
+                    return;
+                }
+                schemaNode = childNode.getYangSchemaNode();
+            }
+            childNode = YdtNodeFactory.getNode(id, schemaNode, cardinality,
+                                               callType);
+        }
+
+        opType = getValidOpType(opType, callType, schemaNode);
+
+        childNode.setYdtContextOperationType(opType);
+
+        curNode.addChild(childNode, true);
+
+        // Update parent ydt node map.
+        curNode.updateYdtMap(id, childNode);
+
+        processAppTree(opType, childNode, augmentingSchema, isContextSwitch);
+
+        // Updating the curNode.
+        curNode = childNode;
+    }
+
+    /**
+     * Processes application tree on the bases of requested ydt node.
+     *
+     * @param opType           user requested operation type
+     * @param childNode        requested ydt node
+     * @param augmentingSchema schema of last augmenting node
+     * @param isContextSwitch  true, for module node call; false for modules
+     *                         sub-node calls
+     */
+    private void processAppTree(
+            YdtContextOperationType opType, YdtNode childNode,
+            YangSchemaNode augmentingSchema, boolean isContextSwitch) {
+
+        if (augmentingSchema != null) {
+            if (!appCurNode.addSchemaToAppSet(augmentingSchema)) {
+                return;
+            }
+        }
+        if (opType == null) {
+            opType = curNode.getYdtContextOperationType();
+        } else {
+            // Updating operation type for parent nodes
+            appCurNode.updateAppOperationType(opType);
+        }
+
+        /*
+         * Create entry of module node in ydt app tree.
+         * Or if context switch happened then also add entry for same ydt
+         * node in the ydt application tree.
+         */
+        if (curNode.equals(rootNode) || isContextSwitch) {
+            addChildInAppTree(childNode, augmentingSchema, opType,
+                              isContextSwitch);
+
+            // Setting app tree node operation.
+            appCurNode.setOperationType(getAppOpTypeFromYdtOpType(opType));
+        }
+
+        // Updating the delete operation list in app tree.
+        if (opType == DELETE || opType == REMOVE) {
+            appCurNode.addDeleteNode(childNode);
+        }
+    }
+
+    /**
+     * Returns the valid operation type for requested ydt node after performing
+     * validation.
+     *
+     * @param opType     user requested operation type
+     * @param callType   to identify the whether its a leaf or other node
+     * @param schemaNode schema node of user requested ydt node
+     * @return operation type
+     */
+    private YdtContextOperationType getValidOpType(
+            YdtContextOperationType opType, RequestedCallType callType,
+            YangSchemaNode schemaNode) {
+
+        // Operation type not supported for leaf node.
+        if (callType == LEAF || (callType == RequestedCallType.MULTI_INSTANCE &&
+                schemaNode.getYangSchemaNodeType() ==
+                        YANG_MULTI_INSTANCE_LEAF_NODE)) {
+            return null;
+        }
+
+        // Reference for parent node operation type.
+        YdtContextOperationType parentOpType = curNode
+                .getYdtContextOperationType();
+
+        if (opType != null && parentOpType != null) {
+            validateOperationType(parentOpType, opType);
+        } else if (opType == null) {
+            opType = getOperationType(parentOpType);
+        }
+        return opType;
+    }
+
+    /**
+     * Returns the operation type for non leaf node.
+     * When "operation" attribute for current node is not specified or null,
+     * then the operation applied to the parent data node of the
+     * configuration is used. If no parent data node is available,
+     * then the default-operation'value is used.
+     * If default operation type is not set, merge will be taken as default
+     * operation type.
+     *
+     * @param parentOpType operation type of parent node
+     * @return operation type for current non leaf node
+     */
+    private YdtContextOperationType getOperationType(
+            YdtContextOperationType parentOpType) {
+
+        return parentOpType != null ? parentOpType :
+                (ydtDefaultOpType != null ? ydtDefaultOpType : MERGE);
+    }
+
+    /**
+     * Adds a last child to YANG app data tree.this method is to be used
+     * internally by other ydt interfaces.
+     *
+     * @param childNode       node to be added in tree
+     * @param schemaNode      last augmenting module node
+     * @param childOpType     operation type of node
+     * @param isContextSwitch true, for module node call; false for modules
+     *                        sub-node calls
+     */
+    private void addChildInAppTree(YdtNode childNode,
+                                   YangSchemaNode schemaNode,
+                                   YdtContextOperationType childOpType,
+                                   boolean isContextSwitch) {
+
+        YdtAppNodeOperationType opType;
+
+        DefaultYdtAppContext appContext = getAppContext(isContextSwitch);
+
+        // Add context switched child in ydt App tree.
+        appCurNode.addChild(appContext);
+        //Updating the curNode.
+        appCurNode = appContext;
+
+        // Get the app tree operation type from ydt operation type.
+        opType = getAppOpTypeFromYdtOpType(childOpType);
+
+        appCurNode.setAppData(childNode, schemaNode);
+
+        appCurNode.setOperationType(opType);
+
+        childNode.setAppContextSwitch();
+    }
+
+    /**
+     * Validates the various combination of operation type.
+     *
+     * @param parentOpType Reference for parent node operation type
+     * @param childOpType  type of YANG data tree node operation
+     */
+    private void validateOperationType(YdtContextOperationType parentOpType,
+                                       YdtContextOperationType childOpType) {
+
+        switch (parentOpType) {
+            case CREATE:
+                // Inside the create operation delete operation should not come.
+                if (childOpType == DELETE) {
+                    curNode.errorHandler(E_CREATE, rootNode);
+                }
+                break;
+            case DELETE:
+                // Inside the delete operation create operation should not come.
+                if (childOpType == CREATE) {
+                    curNode.errorHandler(E_DEL, rootNode);
+                }
+                break;
+            default:
+                //TODO check all possible scenario.
+        }
+    }
+
+    @Override
+    public void addLeaf(String name, String namespace, String value) {
+        addLeaf(name, namespace, value, null, UNKNOWN);
+    }
+
+    @Override
+    public void addLeaf(String name, String namespace, Set<String> valueSet) {
+        addLeaf(name, namespace, null, valueSet, MULTI_INSTANCE_LEAF);
+    }
+
+    /**
+     * Adds a last leaf with list of values/single value to YANG data tree.
+     * This method is used by all protocols which knows the nature
+     * (single/multiple) or not.
+     * Value of leaf can be null which indicates selection node in get
+     * operation.
+     *
+     * @param name        name of child to be added
+     * @param namespace   namespace of child to be added, if it's
+     *                    null, parent's
+     *                    namespace will be applied to child
+     * @param value       value of the child
+     * @param valueSet    list of value of the child
+     * @param cardinality type of YANG data tree node operation
+     */
+    private void addLeaf(String name, String namespace, String value,
+                         Set<String> valueSet,
+                         RequestedCardinality cardinality) {
+        addChild(name, namespace, cardinality, null, LEAF);
+
+        // After successful addition of child node updating the values in same.
+        if (value != null) {
+            curNode.addValue(value);
+        } else if (valueSet != null) {
+            curNode.addValueSet(valueSet);
+        }
+    }
+
+    @Override
+    public void traverseToParent() {
+        // If traverse back to parent for logical root node comes
+        if (curNode.equals(rootNode)) {
+            curNode.errorHandler(E_INVOKE_PARENT, rootNode);
+        }
+
+        // If node is of multiInstanceNode type then check key uniqueness.
+        if (curNode.getYdtType() == MULTI_INSTANCE_NODE) {
+            curNode.createKeyNodeList();
+        }
+
+        /*
+         * Check application switch for curNode if set,
+         * then traverseToParent in YDT application tree.
+         */
+        if (curNode.getParent().equals(rootNode) ||
+                curNode.getAppContextSwitch()) {
+            traverseToAppTreeParent();
+        }
+
+        /*
+         * Validate all multi Instance inside current context,
+         * This is not valid for leaf and leaf-list node.
+         */
+        if (curNode instanceof YdtMultiInstanceNode ||
+                curNode instanceof YdtSingleInstanceNode) {
+            curNode.validateMultiInstanceNode();
+        }
+
+        curNode = curNode.getParent();
+    }
+
+    /**
+     * Traverses up in YANG application tree to the parent node,
+     * This will be used when Ydt current context switch flag is set.
+     */
+    private void traverseToAppTreeParent() {
+        appCurNode = appCurNode.getParent();
+    }
+
+    @Override
+    public YdtContext getCurNode() {
+        return curNode;
+    }
+
+    @Override
+    public void setDefaultEditOperationType(
+            YdtContextOperationType opType) {
+        ydtDefaultOpType = opType;
+    }
+
+    @Override
+    public YdtExtendedContext getRootNode() {
+        return rootNode;
+    }
+
+    @Override
+    public YmsOperationType getYmsOperationType() {
+        return ymsOperationType;
+    }
+
+    @Override
+    public void addMultiInstanceChild(String name, String namespace,
+                                      List<String> keysValueList,
+                                      YdtContextOperationType opType) {
+        addChild(name, namespace, UNKNOWN, opType,
+                 RequestedCallType.MULTI_INSTANCE);
+        int inputCount = keysValueList.size();
+        int expectedCount;
+        if (curNode.getYdtType() == MULTI_INSTANCE_LEAF_VALUE_NODE) {
+            // After successful addition of child node updating
+            // the values in same.
+            // inputCount = curNode.getValueSet().size() + inputCount;
+            // checkElementCount(expectedCount, inputCount);
+            // TODO check the element count
+            for (String value : keysValueList) {
+                curNode.addValue(value);
+            }
+        } else if (curNode.getYdtType() == MULTI_INSTANCE_NODE) {
+            YangList yangListHolder = (YangList) curNode.getYangSchemaNode();
+            List<String> schemaKeyList = yangListHolder.getKeyList();
+            expectedCount = schemaKeyList.size();
+            checkElementCount(name, expectedCount, inputCount);
+
+            Iterator<String> sklIter = schemaKeyList.iterator();
+            Iterator<String> kvlIter = keysValueList.iterator();
+            String keyEleName;
+            while (kvlIter.hasNext()) {
+                String value = kvlIter.next();
+                keyEleName = sklIter.next();
+                addLeaf(keyEleName, namespace, value);
+                if (kvlIter.hasNext()) {
+                    traverseToParentWithoutValidation();
+                }
+            }
+            curNode = curNode.getParent();
+        } else {
+            curNode.errorHandler(E_MULTI_INS, rootNode);
+        }
+    }
+
+    /**
+     * Checks the user supplied list of argument match's the expected value
+     * or not.
+     *
+     * @param name     name of the parent list/leaf-list node
+     * @param expected count suppose to be
+     * @param actual   user supplied values count
+     */
+    private void checkElementCount(String name, int expected,
+                                   int actual) {
+        if (expected < actual) {
+            curNode.errorHandler(errorMsg(FMT_TOO_MANY, name, expected, actual),
+                                 rootNode);
+        } else if (expected > actual) {
+            curNode.errorHandler(errorMsg(FMT_TOO_FEW, name, expected, actual),
+                                 rootNode);
+        }
+    }
+
+    /**
+     * Adds a last child to YANG data tree, this method is to be used by
+     * YANG object builder sub-calls internally.
+     *
+     * @param opType type of requested operation over a node
+     * @return returns added ydt node in YDT tree
+     */
+    private YdtNode addExtendedChildNode(YdtContextOperationType opType,
+                                         YangSchemaNode schemaNode) {
+
+        YdtNode childNode;
+        YangSchemaNodeIdentifier id =
+                schemaNode.getYangSchemaNodeIdentifier();
+
+        childNode = YdtNodeFactory
+                .getYangSchemaNodeTypeSpecificContext(
+                        id, schemaNode.getYangSchemaNodeType());
+
+        childNode.setId(id);
+
+        childNode.setYangSchemaNode(schemaNode);
+
+        childNode.setYdtContextOperationType(opType);
+
+        curNode.addChild(childNode, true);
+
+        curNode = childNode;
+
+        return childNode;
+    }
+
+    @Override
+    public YdtExtendedContext addChild(YdtContextOperationType opType,
+                                       YangSchemaNode schemaNode) {
+        return addExtendedChildNode(opType, schemaNode);
+    }
+
+    @Override
+    public YdtExtendedContext addLeafList(Set<String> valueSet,
+                                          YangSchemaNode schemaNode) {
+        YdtNode childNode = addExtendedChildNode(null, schemaNode);
+
+        // After successful addition of child node updating the values in same.
+        childNode.addValueSetWithoutValidation(valueSet);
+        return childNode;
+    }
+
+    @Override
+    public YdtExtendedContext addLeaf(String value,
+                                      YangSchemaNode schemaNode) {
+        YdtNode childNode = addExtendedChildNode(null, schemaNode);
+
+        // After successful addition of child node updating the values in same.
+        childNode.addValueWithoutValidation(value);
+        return childNode;
+    }
+
+    @Override
+    public void traverseToParentWithoutValidation() {
+        // If traverse back to parent for logical root node comes
+        if (curNode.equals(rootNode)) {
+            curNode.errorHandler(E_INVOKE_PARENT, rootNode);
+        }
+        curNode = curNode.getParent();
+    }
+}