[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();
+ }
+}