[ONOS-5081] YANG tree builder.
Change-Id: Id47015d0cec1a446efcae6c4f3e2ffe87a0f0e0e
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/DefaultYangTreeBuilder.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/DefaultYangTreeBuilder.java
new file mode 100644
index 0000000..6f8df8e
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/DefaultYangTreeBuilder.java
@@ -0,0 +1,122 @@
+/*
+ * 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.ytb;
+
+import org.onosproject.yms.app.ydt.YangRequestWorkBench;
+import org.onosproject.yms.app.ydt.YdtExtendedBuilder;
+import org.onosproject.yms.app.ydt.YdtExtendedContext;
+import org.onosproject.yms.app.ysr.YangSchemaRegistry;
+import org.onosproject.yms.ydt.YdtContext;
+import org.onosproject.yms.ydt.YmsOperationType;
+
+import java.util.List;
+
+import static org.onosproject.yms.app.ytb.YtbUtil.emptyObjErrMsg;
+import static org.onosproject.yms.ydt.YmsOperationType.NOTIFICATION;
+import static org.onosproject.yms.ydt.YmsOperationType.RPC_REPLY;
+
+/**
+ * Representation of YANG tree builder which generates YANG data tree from the
+ * class objects which are provided from the applications and return it to the
+ * protocol(s).
+ */
+public class DefaultYangTreeBuilder implements YangTreeBuilder {
+
+ private static final String OBJ_LIST = "object list";
+ private static final String EVENT_OBJ = "event object";
+ private static final String OUTPUT_OBJ = "output object";
+
+ /**
+ * Creates the YANG tree builder.
+ */
+ public DefaultYangTreeBuilder() {
+ }
+
+ @Override
+ public YdtExtendedBuilder getYdtBuilderForYo(
+ List<Object> moduleObj, String rootName,
+ String rootNameSpace, YmsOperationType opType,
+ YangSchemaRegistry registry) {
+
+ if (moduleObj == null || moduleObj.isEmpty()) {
+ throw new YtbException(emptyObjErrMsg(OBJ_LIST));
+ }
+
+ YdtExtendedBuilder ydtBuilder = new YangRequestWorkBench(
+ rootName, rootNameSpace, opType, registry, false);
+
+ for (Object yangObj : moduleObj) {
+ YdtBuilderFromYo moduleBuilder = new YdtBuilderFromYo(
+ ydtBuilder, yangObj, registry);
+
+ moduleBuilder.getModuleNodeFromYsr(yangObj);
+ moduleBuilder.createYdtFromRootObject();
+ }
+ return ydtBuilder;
+ }
+
+ @Override
+ public YdtContext getYdtForNotification(Object object, String rootName,
+ YangSchemaRegistry registry) {
+
+ if (object == null) {
+ throw new YtbException(emptyObjErrMsg(EVENT_OBJ));
+ }
+
+ YdtExtendedBuilder extBuilder = new YangRequestWorkBench(
+ rootName, null, NOTIFICATION, registry, false);
+ YdtBuilderFromYo moduleBuilder = new YdtBuilderFromYo(
+ extBuilder, object, registry);
+
+ moduleBuilder.getRootNodeWithNotificationFromYsr(object);
+ /*
+ * Adds module to YDT, so that notification can further enhance the
+ * tree.
+ */
+ moduleBuilder.createModuleInYdt();
+ moduleBuilder.createYdtFromRootObject();
+ return extBuilder.getRootNode();
+ }
+
+ @Override
+ public YdtExtendedBuilder getYdtForRpcResponse(
+ Object outputObj, YangRequestWorkBench workBench) {
+
+ if (outputObj == null) {
+ throw new YtbException(emptyObjErrMsg(OUTPUT_OBJ));
+ }
+
+ // Gets the logical root node from RPC request work bench.
+ YdtExtendedContext rootNode = workBench.getRootNode();
+
+ /*
+ * Creates a new work bench for RPC reply from the contents of the
+ * request work bench
+ */
+ YdtExtendedBuilder ydtBuilder = new YangRequestWorkBench(
+ rootNode.getName(), rootNode.getNamespace(),
+ RPC_REPLY, workBench.getYangSchemaRegistry(), false);
+ YdtBuilderFromYo moduleBuilder = new YdtBuilderFromYo(
+ ydtBuilder, outputObj,
+ workBench.getYangSchemaRegistry());
+
+ // Forms YDT till RPC, so that output can further enhance the tree.
+ moduleBuilder.createModuleAndRpcInYdt(rootNode);
+ moduleBuilder.createYdtFromRootObject();
+ return ydtBuilder;
+ }
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YangTreeBuilder.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YangTreeBuilder.java
new file mode 100644
index 0000000..2c1df67
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YangTreeBuilder.java
@@ -0,0 +1,74 @@
+/*
+ * 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.ytb;
+
+import org.onosproject.yms.app.ydt.YangRequestWorkBench;
+import org.onosproject.yms.app.ydt.YdtExtendedBuilder;
+import org.onosproject.yms.app.ysr.YangSchemaRegistry;
+import org.onosproject.yms.ydt.YdtContext;
+import org.onosproject.yms.ydt.YmsOperationType;
+
+import java.util.List;
+
+/**
+ * Abstraction of an entity which provides interfaces to build YANG data tree
+ * from the object received from YNH, YAB or YCH.
+ */
+public interface YangTreeBuilder {
+
+ /**
+ * Returns the YDT builder after building the tree corresponding to the
+ * response YANG object received from any of the protocol such as YAB or
+ * YCH.
+ *
+ * @param moduleObj application module object
+ * @param rootName root node name
+ * @param rootNameSpace root node namespace
+ * @param opType root node operation type
+ * @param registry application schema registry
+ * @return YDT builder from the tree
+ */
+ YdtExtendedBuilder getYdtBuilderForYo(List<Object> moduleObj,
+ String rootName,
+ String rootNameSpace,
+ YmsOperationType opType,
+ YangSchemaRegistry registry);
+
+ /**
+ * Returns the YDT context after building the tree received from the
+ * protocol YNH.
+ *
+ * @param object application notification object
+ * @param rootName root node name
+ * @param registry application schema registry
+ * @return YDT context from the tree
+ */
+ YdtContext getYdtForNotification(Object object, String rootName,
+ YangSchemaRegistry registry);
+
+ /**
+ * Returns the YDT context after building the RPC response tree. The input
+ * for building the tree is RPC request workbench, RPC output java object.
+ * These are received from the YSB protocol.
+ *
+ * @param outputObj application output object
+ * @param workBench RPC request workbench from YDT
+ * @return YDT builder where RPC response tree is created
+ */
+ YdtExtendedBuilder getYdtForRpcResponse(Object outputObj,
+ YangRequestWorkBench workBench);
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YdtBuilderFromYo.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YdtBuilderFromYo.java
new file mode 100644
index 0000000..a82eea2
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YdtBuilderFromYo.java
@@ -0,0 +1,906 @@
+/*
+ * 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.ytb;
+
+import org.onosproject.yangutils.datamodel.YangAugment;
+import org.onosproject.yangutils.datamodel.YangAugmentableNode;
+import org.onosproject.yangutils.datamodel.YangCase;
+import org.onosproject.yangutils.datamodel.YangChoice;
+import org.onosproject.yangutils.datamodel.YangLeaf;
+import org.onosproject.yangutils.datamodel.YangLeafList;
+import org.onosproject.yangutils.datamodel.YangLeavesHolder;
+import org.onosproject.yangutils.datamodel.YangNode;
+import org.onosproject.yangutils.datamodel.YangSchemaNode;
+import org.onosproject.yangutils.datamodel.YangSchemaNodeIdentifier;
+import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
+import org.onosproject.yms.app.utils.TraversalType;
+import org.onosproject.yms.app.ydt.YdtExtendedBuilder;
+import org.onosproject.yms.app.ydt.YdtExtendedContext;
+import org.onosproject.yms.app.ysr.YangSchemaRegistry;
+import org.onosproject.yms.ydt.YdtContextOperationType;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static org.onosproject.yms.app.utils.TraversalType.CHILD;
+import static org.onosproject.yms.app.utils.TraversalType.PARENT;
+import static org.onosproject.yms.app.utils.TraversalType.ROOT;
+import static org.onosproject.yms.app.utils.TraversalType.SIBLING;
+import static org.onosproject.yms.app.ydt.AppType.YTB;
+import static org.onosproject.yms.app.ytb.YtbUtil.PERIOD;
+import static org.onosproject.yms.app.ytb.YtbUtil.STR_NULL;
+import static org.onosproject.yms.app.ytb.YtbUtil.getAttributeFromInheritance;
+import static org.onosproject.yms.app.ytb.YtbUtil.getAttributeOfObject;
+import static org.onosproject.yms.app.ytb.YtbUtil.getCapitalCase;
+import static org.onosproject.yms.app.ytb.YtbUtil.getClassLoaderForAugment;
+import static org.onosproject.yms.app.ytb.YtbUtil.getInterfaceClassFromImplClass;
+import static org.onosproject.yms.app.ytb.YtbUtil.getJavaName;
+import static org.onosproject.yms.app.ytb.YtbUtil.getOperationTypeOfTheNode;
+import static org.onosproject.yms.app.ytb.YtbUtil.getParentObjectOfNode;
+import static org.onosproject.yms.app.ytb.YtbUtil.getStringFromDataType;
+import static org.onosproject.yms.app.ytb.YtbUtil.isAugmentNode;
+import static org.onosproject.yms.app.ytb.YtbUtil.isMultiInstanceNode;
+import static org.onosproject.yms.app.ytb.YtbUtil.isNodeProcessCompleted;
+import static org.onosproject.yms.app.ytb.YtbUtil.isNonEmpty;
+import static org.onosproject.yms.app.ytb.YtbUtil.isNonProcessableNode;
+import static org.onosproject.yms.app.ytb.YtbUtil.isTypePrimitive;
+import static org.onosproject.yms.app.ytb.YtbUtil.isValueOrSelectLeafSet;
+import static org.onosproject.yms.ydt.YdtContextOperationType.NONE;
+
+/**
+ * Implements traversal of YANG node and its corresponding object, resulting
+ * in building of the YDT tree.
+ */
+public class YdtBuilderFromYo {
+
+ private static final String STR_TYPE = "type";
+ private static final String STR_SUBJECT = "subject";
+ private static final String TRUE = "true";
+ private static final String IS_LEAF_VALUE_SET_METHOD = "isLeafValueSet";
+ private static final String IS_SELECT_LEAF_SET_METHOD = "isSelectLeaf";
+ private static final String OUTPUT = "output";
+ private static final String YANG_AUGMENTED_INFO_MAP =
+ "yangAugmentedInfoMap";
+
+ /**
+ * Application YANG schema registry.
+ */
+ private final YangSchemaRegistry registry;
+
+ /**
+ * Current instance of the YDT builder where the tree is built.
+ */
+ private final YdtExtendedBuilder extBuilder;
+
+ /**
+ * YANG root object that is required for walking along with the YANG node.
+ */
+ private Object rootObj;
+
+ /**
+ * YANG root node that is required for walking along with the YANG object.
+ */
+ private YangSchemaNode rootSchema;
+
+ /**
+ * Creates YDT builder from YANG object by assigning the mandatory values.
+ *
+ * @param rootBuilder root node builder
+ * @param rootObj root node object
+ * @param registry application schema registry
+ */
+ public YdtBuilderFromYo(YdtExtendedBuilder rootBuilder, Object rootObj,
+ YangSchemaRegistry registry) {
+ extBuilder = rootBuilder;
+ this.rootObj = rootObj;
+ this.registry = registry;
+ }
+
+ /**
+ * Returns schema root node, received from YSR, which searches based on
+ * the object received from YAB or YCH.
+ *
+ * @param object root node object
+ */
+ public void getModuleNodeFromYsr(Object object) {
+ Class interfaceClass = getInterfaceClassFromImplClass(object);
+ rootSchema = registry
+ .getYangSchemaNodeUsingGeneratedRootNodeInterfaceFileName(
+ interfaceClass.getName());
+ }
+
+ /**
+ * Returns schema root node, received from YSR, which searches based on
+ * the object received from YNH.
+ *
+ * @param object notification event object
+ */
+ public void getRootNodeWithNotificationFromYsr(Object object) {
+ rootSchema = registry.getRootYangSchemaNodeForNotification(
+ object.getClass().getName());
+ }
+
+ /**
+ * Creates the module node for in YDT before beginning with notification
+ * root node traversal. Collects sufficient information to fill YDT with
+ * notification root node in the traversal.
+ */
+ public void createModuleInYdt() {
+ extBuilder.addChild(NONE, rootSchema);
+ rootSchema = getSchemaNodeOfNotification();
+ rootObj = getObjOfNotification();
+ }
+
+ /**
+ * Creates the module and RPC node, in YDT tree, from the logical root
+ * node received from request workbench. The output schema node is taken
+ * from the child schema of RPC YANG node.
+ *
+ * @param rootNode logical root node
+ */
+ public void createModuleAndRpcInYdt(YdtExtendedContext rootNode) {
+
+ YdtExtendedContext moduleNode =
+ (YdtExtendedContext) rootNode.getFirstChild();
+ extBuilder.addChild(NONE, moduleNode.getYangSchemaNode());
+
+ YdtExtendedContext rpcNode =
+ (YdtExtendedContext) moduleNode.getFirstChild();
+ YangSchemaNode rpcSchemaNode = rpcNode.getYangSchemaNode();
+ extBuilder.addChild(NONE, rpcSchemaNode);
+
+ // Defines a schema identifier for output node.
+ YangSchemaNodeIdentifier schemaId = new YangSchemaNodeIdentifier();
+ schemaId.setName(OUTPUT);
+ schemaId.setNameSpace(rpcSchemaNode.getNameSpace());
+ try {
+ // Gets the output schema node from RPC child schema.
+ rootSchema = rpcSchemaNode.getChildSchema(schemaId).getSchemaNode();
+ } catch (DataModelException e) {
+ throw new YtbException(e);
+ }
+ }
+
+ /**
+ * Creates YDT tree from the root object, by traversing through YANG data
+ * model node, and simultaneously checking the object nodes presence and
+ * walking the object.
+ */
+ public void createYdtFromRootObject() {
+ YangNode curNode = (YangNode) rootSchema;
+ TraversalType curTraversal = ROOT;
+ YtbNodeInfo listNodeInfo = null;
+ YtbNodeInfo augmentNodeInfo = null;
+
+ while (curNode != null) {
+ /*
+ * Processes the node, if it is being visited for the first time in
+ * the schema, also if the schema node is being retraced in a multi
+ * instance node.
+ */
+ if (curTraversal != PARENT || isMultiInstanceNode(curNode)) {
+
+ if (curTraversal == PARENT && isMultiInstanceNode(curNode)) {
+ /*
+ * If the schema is being retraced for a multi-instance
+ * node, it has already entered for this multi-instance
+ * node. Now this re-processes the same schema node for
+ * any additional list object.
+ */
+ listNodeInfo = getCurNodeInfoAndTraverseBack();
+ }
+
+ if (curTraversal == ROOT && !isAugmentNode(curNode)) {
+ /*
+ * In case of RPC output, the root node is augmentative,
+ * so when the root traversal is coming for augment this
+ * flow is skipped. This adds only the root node in the YDT.
+ */
+ processApplicationRootNode();
+ } else {
+ /*
+ * Gets the object corresponding to current schema node.
+ * If object exists, this adds the corresponding YDT node
+ * to the tree and returns the object. Else returns null.
+ */
+ Object processedObject = processCurSchemaNodeAndAddToYdt(
+ curNode, listNodeInfo);
+ /*
+ * Clears the list info of processed node. The next time
+ * list info is taken newly and accordingly.
+ */
+ listNodeInfo = null;
+ if (processedObject == null && !isAugmentNode(curNode)) {
+ /*
+ * Checks the presence of next sibling of the node, by
+ * breaking the complete chain of the current node,
+ * when the object value is not present, or when the
+ * list entries are completely retraced. The augment
+ * may have sibling, so this doesn't process for
+ * augment.
+ */
+ YtbTraversalInfo traverseInfo =
+ getProcessableInfo(curNode);
+ curNode = traverseInfo.getYangNode();
+ curTraversal = traverseInfo.getTraverseType();
+ continue;
+ /*
+ * Irrespective of root or parent, sets the traversal
+ * type as parent, when augment node doesn't have any
+ * value. So, the other sibling augments can be
+ * processed, if present.
+ */
+ } else if (processedObject == null &&
+ isAugmentNode(curNode)) {
+ curTraversal = PARENT;
+ /*
+ * The second content in the list will be having
+ * parent traversal, in such case it cannot go to its
+ * child in the flow, so it is made as child
+ * traversal and proceeded to continue.
+ */
+ } else if (curTraversal == PARENT &&
+ isMultiInstanceNode(curNode)) {
+ curTraversal = CHILD;
+ }
+ }
+ }
+ /*
+ * Checks for the sibling augment when the first augment node is
+ * getting completed. From the current augment node the previous
+ * node info is taken for augment and the traversal is changed to
+ * child, so as to check for the presence of sibling augment.
+ */
+ if (curTraversal == PARENT && isAugmentNode(curNode)) {
+ curNode = ((YangAugment) curNode).getAugmentedNode();
+ augmentNodeInfo = getParentYtbInfo();
+ curTraversal = CHILD;
+ }
+ /*
+ * Creates an augment iterator for the first time or takes the
+ * previous augment iterator for more than one time, whenever an
+ * augmentative node arrives. If augment is present it goes back
+ * for processing. If its null, the augmentative nodes process is
+ * continued.
+ */
+ if (curTraversal != PARENT &&
+ curNode instanceof YangAugmentableNode) {
+ YangNode augmentNode = getAugmentInsideSchemaNode(
+ curNode, augmentNodeInfo);
+ if (augmentNode != null) {
+ curNode = augmentNode;
+ continue;
+ }
+ }
+ /*
+ * Processes the child, after processing the node. If complete
+ * child depth is over, it takes up sibling and processes it.
+ * Once child and sibling is over, it is traversed back to the
+ * parent, without processing. In multi instance case, before
+ * going to parent or schema sibling, its own list sibling is
+ * processed. Skips the processing of RPC,notification and
+ * augment, as these nodes are dealt in a different flow.
+ */
+ if (curTraversal != PARENT && curNode.getChild() != null) {
+ augmentNodeInfo = null;
+ listNodeInfo = null;
+ curTraversal = CHILD;
+ curNode = curNode.getChild();
+ if (isNonProcessableNode(curNode)) {
+ YtbTraversalInfo traverseInfo = getProcessableInfo(curNode);
+ curNode = traverseInfo.getYangNode();
+ curTraversal = traverseInfo.getTraverseType();
+ }
+ } else if (curNode.getNextSibling() != null) {
+ if (isNodeProcessCompleted(curNode, curTraversal)) {
+ break;
+ }
+ if (isMultiInstanceNode(curNode)) {
+ listNodeInfo = getCurNodeInfoAndTraverseBack();
+ augmentNodeInfo = null;
+ continue;
+ }
+ curTraversal = SIBLING;
+ traverseToParent(curNode);
+ curNode = curNode.getNextSibling();
+ if (isNonProcessableNode(curNode)) {
+ YtbTraversalInfo traverseInfo = getProcessableInfo(curNode);
+ curNode = traverseInfo.getYangNode();
+ curTraversal = traverseInfo.getTraverseType();
+ }
+ } else {
+ if (isNodeProcessCompleted(curNode, curTraversal)) {
+ break;
+ }
+ if (isMultiInstanceNode(curNode)) {
+ listNodeInfo = getCurNodeInfoAndTraverseBack();
+ augmentNodeInfo = null;
+ continue;
+ }
+ curTraversal = PARENT;
+ traverseToParent(curNode);
+ curNode = curNode.getParent();
+ }
+ }
+ }
+
+ /**
+ * Processes root YANG node and adds it as a child to the YDT
+ * extended builder which is created earlier.
+ */
+ private void processApplicationRootNode() {
+
+ YtbNodeInfo nodeInfo = new YtbNodeInfo();
+ YangNode rootYang = (YangNode) rootSchema;
+ addChildNodeInYdt(rootObj, rootYang, nodeInfo);
+ // If root node has leaf or leaf-list those will be processed.
+ processLeaves(rootYang);
+ processLeavesList(rootYang);
+ }
+
+ /**
+ * Traverses to parent, based on the schema node that requires to be
+ * traversed. Skips traversal of parent for choice and case node, as they
+ * don't get added to the YDT tree.
+ *
+ * @param curNode current YANG node
+ */
+ private void traverseToParent(YangNode curNode) {
+ if (curNode instanceof YangCase || curNode instanceof YangChoice) {
+ return;
+ }
+ extBuilder.traverseToParentWithoutValidation();
+ }
+
+ /**
+ * Returns the current YTB info of the YDT builder, and then traverses back
+ * to parent. In case of multi instance node the previous node info is
+ * used for iterating through the list.
+ *
+ * @return current YTB app info
+ */
+ private YtbNodeInfo getCurNodeInfoAndTraverseBack() {
+ YtbNodeInfo appInfo = getParentYtbInfo();
+ extBuilder.traverseToParentWithoutValidation();
+ return appInfo;
+ }
+
+ /**
+ * Returns augment node for an augmented node. From the list of augment
+ * nodes it has, one of the nodes is taken and provided linearly. If the
+ * node is not augmented or the all the augment nodes are processed, then
+ * it returns null.
+ *
+ * @param curNode current YANG node
+ * @param augmentNodeInfo previous augment node info
+ * @return YANG augment node
+ */
+ private YangNode getAugmentInsideSchemaNode(YangNode curNode,
+ YtbNodeInfo augmentNodeInfo) {
+ if (augmentNodeInfo == null) {
+ List<YangAugment> augmentList = ((YangAugmentableNode) curNode)
+ .getAugmentedInfoList();
+ if (isNonEmpty(augmentList)) {
+ YtbNodeInfo parentNodeInfo = getParentYtbInfo();
+ Iterator<YangAugment> augmentItr = augmentList.listIterator();
+ parentNodeInfo.setAugmentIterator(augmentItr);
+ return augmentItr.next();
+ }
+ } else if (augmentNodeInfo.getAugmentIterator() != null) {
+ if (augmentNodeInfo.getAugmentIterator().hasNext()) {
+ return augmentNodeInfo.getAugmentIterator().next();
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Processes the current YANG node and if necessary adds it to the YDT
+ * builder tree by extracting the information from the corresponding
+ * class object.
+ *
+ * @param curNode current YANG node
+ * @param listNodeInfo previous node info for list
+ * @return object of the schema node
+ */
+ private Object processCurSchemaNodeAndAddToYdt(YangNode curNode,
+ YtbNodeInfo listNodeInfo) {
+ YtbNodeInfo curNodeInfo = new YtbNodeInfo();
+ Object nodeObj = null;
+ YtbNodeInfo parentNodeInfo = getParentYtbInfo();
+
+ switch (curNode.getYangSchemaNodeType()) {
+ case YANG_SINGLE_INSTANCE_NODE:
+ nodeObj = processSingleInstanceNode(curNode, curNodeInfo,
+ parentNodeInfo);
+ break;
+ case YANG_MULTI_INSTANCE_NODE:
+ nodeObj = processMultiInstanceNode(
+ curNode, curNodeInfo, listNodeInfo, parentNodeInfo);
+ break;
+ case YANG_CHOICE_NODE:
+ nodeObj = processChoiceNode(curNode, parentNodeInfo);
+ break;
+ case YANG_NON_DATA_NODE:
+ if (curNode instanceof YangCase) {
+ nodeObj = processCaseNode(curNode, parentNodeInfo);
+ }
+ break;
+ case YANG_AUGMENT_NODE:
+ nodeObj = processAugmentNode(curNode, parentNodeInfo);
+ break;
+ default:
+ throw new YtbException(
+ "Non processable schema node has arrived for adding " +
+ "it in YDT tree");
+ }
+ // Processes leaf/leaf-list only when object has value, else it skips.
+ if (nodeObj != null) {
+ processLeaves(curNode);
+ processLeavesList(curNode);
+ }
+ return nodeObj;
+ }
+
+ /**
+ * Processes single instance node which is added to the YDT tree.
+ *
+ * @param curNode current YANG node
+ * @param curNodeInfo current YDT node info
+ * @param parentNodeInfo parent YDT node info
+ * @return object of the current node
+ */
+ private Object processSingleInstanceNode(YangNode curNode,
+ YtbNodeInfo curNodeInfo,
+ YtbNodeInfo parentNodeInfo) {
+ Object childObj = getChildObject(curNode, parentNodeInfo);
+ if (childObj != null) {
+ addChildNodeInYdt(childObj, curNode, curNodeInfo);
+ }
+ return childObj;
+ }
+
+ /**
+ * Processes multi instance node which has to be added to the YDT tree.
+ * For the first instance in the list, iterator is created and added to
+ * the list. For second instance or more the iterator from first instance
+ * is taken and iterated through to get the object of parent.
+ *
+ * @param curNode current list node
+ * @param curNodeInfo current node info for list
+ * @param listNodeInfo previous instance node info of list
+ * @param parentNodeInfo parent node info of list
+ * @return object of the current instance
+ */
+ private Object processMultiInstanceNode(YangNode curNode,
+ YtbNodeInfo curNodeInfo,
+ YtbNodeInfo listNodeInfo,
+ YtbNodeInfo parentNodeInfo) {
+ Object childObj = null;
+ /*
+ * When YANG list comes to this flow for first time, its YTB node
+ * will be null. When it comes for the second or more content, then
+ * the list would have been already set for that node. According to
+ * set or not set this flow will be proceeded.
+ */
+ if (listNodeInfo == null) {
+ List<Object> childObjList = (List<Object>) getChildObject(
+ curNode, parentNodeInfo);
+ if (isNonEmpty(childObjList)) {
+ Iterator<Object> listItr = childObjList.iterator();
+ if (!listItr.hasNext()) {
+ return null;
+ //TODO: Handle the subtree filtering with no list entries.
+ }
+ childObj = listItr.next();
+ /*
+ * For that node the iterator is set. So the next time for
+ * the list this iterator will be taken.
+ */
+ curNodeInfo.setListIterator(listItr);
+ }
+ } else {
+ /*
+ * If the list value comes for second or more time, that list
+ * node will be having YTB node info, where iterator can be
+ * retrieved and check if any more contents are present. If
+ * present those will be processed.
+ */
+ curNodeInfo.setListIterator(listNodeInfo.getListIterator());
+ if (listNodeInfo.getListIterator().hasNext()) {
+ childObj = listNodeInfo.getListIterator().next();
+ }
+ }
+ if (childObj != null) {
+ addChildNodeInYdt(childObj, curNode, curNodeInfo);
+ }
+ return childObj;
+ }
+
+ /**
+ * Processes choice node which adds a map to the parent node info of
+ * choice name and the case object. The object taken for choice node is
+ * of case object with choice name. Also, this Skips the addition of choice
+ * to YDT.
+ *
+ * @param curNode current choice node
+ * @param parentNodeInfo parent YTB node info
+ * @return object of the choice node
+ */
+ private Object processChoiceNode(YangNode curNode,
+ YtbNodeInfo parentNodeInfo) {
+ /*
+ * Retrieves the parent YTB info, to take the object of parent, so as
+ * to check the child attribute from the object.
+ */
+ Object childObj = getChildObject(curNode, parentNodeInfo);
+ if (childObj != null) {
+ Map<String, Object> choiceCaseMap = parentNodeInfo
+ .getChoiceCaseMap();
+ if (choiceCaseMap == null) {
+ choiceCaseMap = new HashMap<>();
+ parentNodeInfo.setChoiceCaseMap(choiceCaseMap);
+ }
+ choiceCaseMap.put(curNode.getName(), childObj);
+ }
+ return childObj;
+ }
+
+ /**
+ * Processes case node from the map contents that is filled by choice
+ * nodes. Object of choice is taken when choice name and case class name
+ * matches. When the case node is not present in the map it returns null.
+ *
+ * @param curNode current case node
+ * @param parentNodeInfo choice parent node info
+ * @return object of the case node
+ */
+ private Object processCaseNode(YangNode curNode,
+ YtbNodeInfo parentNodeInfo) {
+ Object childObj = null;
+ if (parentNodeInfo.getChoiceCaseMap() != null) {
+ childObj = getCaseObjectFromChoice(parentNodeInfo,
+ curNode);
+ }
+ if (childObj != null) {
+ /*
+ * Sets the case object in parent info, so that rest of the case
+ * children can use it as parent. Case is not added in YDT.
+ */
+ parentNodeInfo.setCaseObject(childObj);
+ }
+ return childObj;
+ }
+
+ /**
+ * Processes augment node, which is not added in the YDT, but binds
+ * itself to the parent YTB info, so rest of its child nodes can use for
+ * adding themselves to the YDT tree. If there is no augment node added
+ * in map or if the augment module is not registered, then it returns null.
+ *
+ * @param curNode current augment node
+ * @param parentNodeInfo augment parent node info
+ * @return object of the augment node
+ */
+ private Object processAugmentNode(YangNode curNode,
+ YtbNodeInfo parentNodeInfo) {
+ String className = curNode.getJavaClassNameOrBuiltInType();
+ String pkgName = curNode.getJavaPackage();
+ Object parentObj = getParentObjectOfNode(parentNodeInfo,
+ curNode.getParent());
+ Map augmentMap;
+ try {
+ augmentMap = (Map) getAttributeOfObject(parentObj,
+ YANG_AUGMENTED_INFO_MAP);
+ /*
+ * Gets the registered module class. Loads the class and gets the
+ * augment class.
+ */
+ Class moduleClass = getClassLoaderForAugment(curNode, registry);
+ if (moduleClass == null) {
+ return null;
+ }
+ Class augmentClass = moduleClass.getClassLoader().loadClass(
+ pkgName + PERIOD + className);
+ Object childObj = augmentMap.get(augmentClass);
+ parentNodeInfo.setAugmentObject(childObj);
+ return childObj;
+ } catch (ClassNotFoundException | NoSuchMethodException e) {
+ throw new YtbException(e);
+ }
+ }
+
+ /**
+ * Returns the YTB info from the parent node, so that its own bounded
+ * object can be taken out.
+ *
+ * @return parent node YTB node info
+ */
+ private YtbNodeInfo getParentYtbInfo() {
+ YdtExtendedContext parentExtContext =
+ (YdtExtendedContext) extBuilder.getCurNode();
+ return (YtbNodeInfo) parentExtContext.getAppInfo(YTB);
+ }
+
+ /**
+ * Returns the child object from the parent object. Uses java name of the
+ * current node to search the attribute in the parent object.
+ *
+ * @param curNode current YANG node
+ * @param parentNodeInfo parent YTB node info
+ * @return object of the child node
+ */
+ private Object getChildObject(YangNode curNode,
+ YtbNodeInfo parentNodeInfo) {
+ String nodeJavaName = curNode.getJavaAttributeName();
+ Object parentObj = getParentObjectOfNode(parentNodeInfo,
+ curNode.getParent());
+ try {
+ return getAttributeOfObject(parentObj, nodeJavaName);
+ } catch (NoSuchMethodException e) {
+ throw new YtbException(e);
+ }
+ }
+
+ /**
+ * Adds the child node to the YDT by taking operation type from the
+ * object. Also, binds the object to the YDT node through YTB node info.
+ *
+ * @param childObj node object
+ * @param curNode current YANG node
+ * @param curNodeInfo current YTB info
+ */
+ private void addChildNodeInYdt(Object childObj, YangNode curNode,
+ YtbNodeInfo curNodeInfo) {
+ YdtContextOperationType opType = getOperationTypeOfTheNode(childObj);
+ extBuilder.addChild(opType, curNode);
+ YdtExtendedContext curExtContext = (YdtExtendedContext) extBuilder
+ .getCurNode();
+ curNodeInfo.setYangObject(childObj);
+ curExtContext.addAppInfo(YTB, curNodeInfo);
+ }
+
+ /**
+ * Processes every leaf in a YANG node. Iterates through the leaf, takes
+ * value from the leaf and adds it to the YDT with value. If value is not
+ * present, and select leaf is set, adds it to the YDT without value.
+ *
+ * @param yangNode leaves holder node
+ */
+ private void processLeaves(YangNode yangNode) {
+ if (yangNode instanceof YangLeavesHolder) {
+ List<YangLeaf> leavesList = ((YangLeavesHolder) yangNode)
+ .getListOfLeaf();
+ if (leavesList != null) {
+ for (YangLeaf yangLeaf : leavesList) {
+ YtbNodeInfo parentYtbInfo = getParentYtbInfo();
+ Object parentObj = getParentObjectOfNode(parentYtbInfo,
+ yangNode);
+ Object leafType;
+ try {
+ leafType = getAttributeOfObject(parentObj,
+ getJavaName(yangLeaf));
+ } catch (NoSuchMethodException e) {
+ throw new YtbException(e);
+ }
+
+ addLeafWithValue(yangLeaf, parentObj, leafType);
+ addLeafWithoutValue(yangLeaf, parentObj);
+ }
+ }
+ }
+ }
+
+ /**
+ * Processes every leaf-list in a YANG node. For each leaf-list, the list of
+ * objects are iterated, value from each object is put in a set of string,
+ * and is added to the YDT.
+ *
+ * @param yangNode list of leaf-list holder node
+ */
+ private void processLeavesList(YangNode yangNode) {
+ if (yangNode instanceof YangLeavesHolder) {
+ List<YangLeafList> listOfLeafList =
+ ((YangLeavesHolder) yangNode).getListOfLeafList();
+
+ if (listOfLeafList != null) {
+ for (YangLeafList yangLeafList : listOfLeafList) {
+
+ YtbNodeInfo ytbNodeInfo = getParentYtbInfo();
+ Object parentObj = getParentObjectOfNode(ytbNodeInfo,
+ yangNode);
+
+ //TODO: Let the received object list be generic collection.
+ List<Object> leafListObj;
+ try {
+ leafListObj = (List<Object>) getAttributeOfObject(
+ parentObj, getJavaName(yangLeafList));
+ } catch (NoSuchMethodException e) {
+ throw new YtbException(e);
+ }
+ Set<String> leafListValue = new HashSet<>();
+ /*
+ * If list is present, then adds each object value in set.
+ * Adds this set to the YDT, and traverse to parent.
+ */
+ if (leafListObj != null) {
+ for (Object object : leafListObj) {
+ String objValue = getStringFromDataType(
+ object, yangLeafList.getDataType());
+ leafListValue.add(objValue);
+ }
+ extBuilder.addLeafList(leafListValue, yangLeafList);
+ extBuilder.traverseToParentWithoutValidation();
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Returns the schema node of notification from the root node. Gets the
+ * enum value from event object and gives it to the root schema node for
+ * getting back the notification schema node.
+ *
+ * @return YANG schema node of notification
+ */
+ private YangSchemaNode getSchemaNodeOfNotification() {
+ Class parentClass = rootObj.getClass().getSuperclass();
+ Object eventObjType = getAttributeFromInheritance(
+ parentClass, rootObj, STR_TYPE);
+ String opTypeValue = String.valueOf(eventObjType);
+
+ if (opTypeValue.equals(STR_NULL) || opTypeValue.isEmpty()) {
+ throw new YtbException(
+ "There is no notification present for the event. Invalid " +
+ "input for notification.");
+ }
+ try {
+ return rootSchema.getNotificationSchemaNode(opTypeValue);
+ } catch (DataModelException e) {
+ throw new YtbException(e);
+ }
+ }
+
+ /**
+ * Returns the object of the notification by retrieving the attributes
+ * from the event class object.
+ *
+ * @return notification YANG object
+ */
+ private Object getObjOfNotification() {
+ Class parentClass = rootObj.getClass().getSuperclass();
+ Object eventSubjectObj = getAttributeFromInheritance(
+ parentClass, rootObj, STR_SUBJECT);
+ String notificationName = rootSchema.getJavaAttributeName();
+ try {
+ return getAttributeOfObject(eventSubjectObj, notificationName);
+ } catch (NoSuchMethodException e) {
+ throw new YtbException(e);
+ }
+ }
+
+ /**
+ * Returns case object from the map that is bound to the parent node
+ * info. For any case node, only when the key and value is matched the
+ * object of the case is provided. If a match is not found, null is
+ * returned.
+ *
+ * @param parentNodeInfo parent YTB node info
+ * @param caseNode case schema node
+ * @return object of the case node
+ */
+ private Object getCaseObjectFromChoice(YtbNodeInfo parentNodeInfo,
+ YangSchemaNode caseNode) {
+ String javaName = getCapitalCase(
+ caseNode.getJavaClassNameOrBuiltInType());
+ String choiceName = ((YangNode) caseNode).getParent().getName();
+ Map<String, Object> mapObj = parentNodeInfo.getChoiceCaseMap();
+ Object caseObj = mapObj.get(choiceName);
+ Class<?> interfaceClass = getInterfaceClassFromImplClass(caseObj);
+ return interfaceClass.getSimpleName().equals(javaName) ? caseObj : null;
+ }
+
+ /**
+ * Adds leaf to YDT when value is present. For primitive types, in order
+ * to avoid default values, the value select is set or not is checked and
+ * then added.
+ *
+ * @param yangLeaf YANG leaf node
+ * @param parentObj leaf holder object
+ * @param leafType object of leaf type
+ */
+ private void addLeafWithValue(YangLeaf yangLeaf, Object parentObj,
+ Object leafType) {
+ String fieldValue = null;
+ if (isTypePrimitive(yangLeaf.getDataType())) {
+ fieldValue = getLeafValueFromValueSetFlag(parentObj, yangLeaf,
+ leafType);
+ /*
+ * Checks the object is present or not, when type is
+ * non-primitive. And adds the value from the respective data type.
+ */
+ } else if (leafType != null) {
+ fieldValue = getStringFromDataType(leafType,
+ yangLeaf.getDataType());
+ }
+ if (isNonEmpty(fieldValue)) {
+ extBuilder.addLeaf(fieldValue, yangLeaf);
+ extBuilder.traverseToParentWithoutValidation();
+ }
+ }
+
+ /**
+ * Adds leaf without value, when the select leaf bit is set.
+ *
+ * @param yangLeaf YANG leaf node
+ * @param parentObj leaf holder object
+ */
+ private void addLeafWithoutValue(YangLeaf yangLeaf, Object parentObj) {
+ String selectLeaf = isValueOrSelectLeafSet(
+ parentObj, getJavaName(yangLeaf), IS_SELECT_LEAF_SET_METHOD);
+ if (selectLeaf.equals(TRUE)) {
+ extBuilder.addLeaf(null, yangLeaf);
+ extBuilder.traverseToParentWithoutValidation();
+ }
+ }
+
+ /**
+ * Returns the value of type, after checking, the value leaf flag. If the
+ * flag is set, then it takes the value or returns null.
+ *
+ * @param parentObj parent object
+ * @param yangLeaf YANG leaf node
+ * @param leafType object of leaf type
+ * @return value of type
+ */
+ private String getLeafValueFromValueSetFlag(
+ Object parentObj, YangLeaf yangLeaf, Object leafType) {
+ String valueOfLeaf = isValueOrSelectLeafSet(
+ parentObj, getJavaName(yangLeaf), IS_LEAF_VALUE_SET_METHOD);
+ if (valueOfLeaf.equals(TRUE)) {
+ return getStringFromDataType(leafType, yangLeaf.getDataType());
+ }
+ return null;
+ }
+
+ /**
+ * Returns the node info which can be processed, by eliminating the nodes
+ * which need not to be processed at normal conditions such as RPC,
+ * notification and augment.
+ *
+ * @param curNode current node
+ * @return info of node which needs processing
+ */
+ private YtbTraversalInfo getProcessableInfo(YangNode curNode) {
+ if (curNode.getNextSibling() != null) {
+ YangNode sibling = curNode.getNextSibling();
+ while (isNonProcessableNode(sibling)) {
+ sibling = sibling.getNextSibling();
+ }
+ if (sibling != null) {
+ return new YtbTraversalInfo(sibling, SIBLING);
+ }
+ }
+ return new YtbTraversalInfo(curNode.getParent(), PARENT);
+ }
+
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbException.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbException.java
new file mode 100644
index 0000000..98f141a
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbException.java
@@ -0,0 +1,41 @@
+/*
+ * 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.ytb;
+
+/**
+ * Represents exception that needs to be handled by YTB.
+ */
+public class YtbException extends RuntimeException {
+
+ /**
+ * Creates YTB exception with an exception message.
+ *
+ * @param exceptionMessage message with which exception must be thrown
+ */
+ public YtbException(String exceptionMessage) {
+ super(exceptionMessage);
+ }
+
+ /**
+ * Creates YTB exception with the cause for it.
+ *
+ * @param cause cause of the exception
+ */
+ public YtbException(Throwable cause) {
+ super(cause);
+ }
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbNodeInfo.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbNodeInfo.java
new file mode 100644
index 0000000..6815bca
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbNodeInfo.java
@@ -0,0 +1,186 @@
+/*
+ * 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.ytb;
+
+import org.onosproject.yangutils.datamodel.YangAugment;
+
+import java.util.Iterator;
+import java.util.Map;
+
+/**
+ * Represents YTB node info for all the nodes that are added to the YDT
+ * builder tree.Contains the information which can be attached and retrieved
+ * back from YDT while walking.
+ */
+public class YtbNodeInfo {
+
+ /**
+ * Object of the corresponding YANG construct. This object is bound to
+ * each and every YDT node. So, whenever walk of parent and sibling
+ * happens, object can be retrieved from its YDT node.
+ */
+ private Object yangObject;
+
+ /**
+ * The list iterator since first content of the multi instance node is
+ * faced. With this iterator the node can be walked multiple times till
+ * it becomes empty.
+ */
+ private Iterator<Object> listIterator;
+
+ /**
+ * The current YTB node's, list of augments are iterated through this
+ * iterator. Every time an augment is built completely, this iterator
+ * gives the next augment node until it becomes empty.
+ */
+ private Iterator<YangAugment> augmentNodeItr;
+
+ /**
+ * The map with case object as value and choice node name as key is added
+ * for the current YTB info. Every time a case schema node comes, it takes
+ * this map and checks if it is present.
+ */
+ private Map<String, Object> choiceCaseMap;
+
+ /**
+ * When the case finds its object in map, it assigns it to case object of
+ * the YTB info, so when its child wants to take the parent object, they
+ * can take from the YTB info's case object.
+ */
+ private Object caseObject;
+
+ /**
+ * When the augment object is present, it assigns it to augment object of
+ * the YTB info, so when its child wants to take the parent object, they
+ * can take from the YTB info's augment object.
+ */
+ private Object augmentObject;
+
+ /**
+ * Constructs a default YTB node info.
+ */
+ public YtbNodeInfo() {
+ }
+
+ /**
+ * Returns the object of the YANG schema node.
+ *
+ * @return YANG node object
+ */
+ public Object getYangObject() {
+ return yangObject;
+ }
+
+ /**
+ * Sets the object of the YANG schema node.
+ *
+ * @param yangObject YANG node object
+ */
+ public void setYangObject(Object yangObject) {
+ this.yangObject = yangObject;
+ }
+
+ /**
+ * Returns the current list iterator of the YANG schema node.
+ *
+ * @return current list iterator for the schema node
+ */
+ public Iterator<Object> getListIterator() {
+ return listIterator;
+ }
+
+ /**
+ * Sets the current list iterator of the YANG schema node.
+ *
+ * @param listIterator current list iterator for the schema node
+ */
+ public void setListIterator(Iterator<Object> listIterator) {
+ this.listIterator = listIterator;
+ }
+
+ /**
+ * Returns the map of choice schema name and case object.
+ *
+ * @return choice name and case object map
+ */
+ public Map<String, Object> getChoiceCaseMap() {
+ return choiceCaseMap;
+ }
+
+ /**
+ * Sets the map of choice schema name and case object.
+ *
+ * @param choiceCaseMap choice name and case object map
+ */
+ public void setChoiceCaseMap(Map<String, Object> choiceCaseMap) {
+ this.choiceCaseMap = choiceCaseMap;
+ }
+
+ /**
+ * Returns the case object.
+ *
+ * @return case object
+ */
+ public Object getCaseObject() {
+ return caseObject;
+ }
+
+ /**
+ * Sets the case node object.
+ *
+ * @param caseObject case node object
+ */
+ public void setCaseObject(Object caseObject) {
+ this.caseObject = caseObject;
+ }
+
+ /**
+ * Returns the augment node object.
+ *
+ * @return augment node object
+ */
+ public Object getAugmentObject() {
+ return augmentObject;
+ }
+
+ /**
+ * Sets the augment node object.
+ *
+ * @param augmentObject augment node object
+ */
+ public void setAugmentObject(Object augmentObject) {
+ this.augmentObject = augmentObject;
+ }
+
+ /**
+ * Returns the current list iterator of the YANG augment node.
+ *
+ * @return augment node iterator
+ */
+ public Iterator<YangAugment> getAugmentIterator() {
+ return augmentNodeItr;
+ }
+
+ /**
+ * Sets the current list iterator of the YANG augment node.
+ *
+ * @param augmentNodeItr augment node iterator
+ */
+ public void setAugmentIterator(Iterator<YangAugment> augmentNodeItr) {
+ this.augmentNodeItr = augmentNodeItr;
+ }
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbTraversalInfo.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbTraversalInfo.java
new file mode 100644
index 0000000..4435c0a
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbTraversalInfo.java
@@ -0,0 +1,68 @@
+/*
+ * 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.ytb;
+
+import org.onosproject.yangutils.datamodel.YangNode;
+import org.onosproject.yms.app.utils.TraversalType;
+
+/**
+ * Represents YTB Traversal info which is needed every time the traversal of
+ * a YANG node happens. This contains YANG node and its corresponding traversal
+ * type information.
+ */
+public class YtbTraversalInfo {
+
+ /**
+ * YANG node of the current traversal.
+ */
+ private YangNode yangNode;
+
+ /**
+ * Traverse type of the current traversal.
+ */
+ private TraversalType traverseType;
+
+ /**
+ * Creates YTB traversal info by taking the traversal type and the YANG
+ * node.
+ *
+ * @param yangNode YANG node
+ * @param traverseType traversal type
+ */
+ public YtbTraversalInfo(YangNode yangNode, TraversalType traverseType) {
+ this.yangNode = yangNode;
+ this.traverseType = traverseType;
+ }
+
+ /**
+ * Returns the YANG node of the current traversal.
+ *
+ * @return YANG node
+ */
+ public YangNode getYangNode() {
+ return yangNode;
+ }
+
+ /**
+ * Returns the traversal type of the current traversal.
+ *
+ * @return traversal type
+ */
+ public TraversalType getTraverseType() {
+ return traverseType;
+ }
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbUtil.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbUtil.java
new file mode 100644
index 0000000..8329c9f
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/YtbUtil.java
@@ -0,0 +1,449 @@
+/*
+ * 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.ytb;
+
+import org.onosproject.yangutils.datamodel.YangAugment;
+import org.onosproject.yangutils.datamodel.YangCase;
+import org.onosproject.yangutils.datamodel.YangLeafRef;
+import org.onosproject.yangutils.datamodel.YangNode;
+import org.onosproject.yangutils.datamodel.YangNotification;
+import org.onosproject.yangutils.datamodel.YangOutput;
+import org.onosproject.yangutils.datamodel.YangRpc;
+import org.onosproject.yangutils.datamodel.YangType;
+import org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes;
+import org.onosproject.yangutils.translator.tojava.javamodel.JavaLeafInfoContainer;
+import org.onosproject.yms.app.utils.TraversalType;
+import org.onosproject.yms.app.ysr.YangSchemaRegistry;
+import org.onosproject.yms.ydt.YdtContextOperationType;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.Arrays;
+import java.util.Base64;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import static org.onosproject.yangutils.datamodel.YangSchemaNodeType.YANG_AUGMENT_NODE;
+import static org.onosproject.yangutils.datamodel.YangSchemaNodeType.YANG_MULTI_INSTANCE_NODE;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.BOOLEAN;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.DECIMAL64;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.EMPTY;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.INT16;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.INT32;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.INT64;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.INT8;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.LEAFREF;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.UINT16;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.UINT32;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.UINT64;
+import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.UINT8;
+import static org.onosproject.yms.app.utils.TraversalType.PARENT;
+
+/**
+ * Representation of utility for YANG tree builder.
+ */
+public final class YtbUtil {
+
+ /**
+ * Static attribute for string value having null.
+ */
+ public static final String STR_NULL = "null";
+
+ /**
+ * Static attribute for a dot string.
+ */
+ public static final String PERIOD = ".";
+
+ private static final int ONE = 1;
+ private static final String SCHEMA_NAME_IN_ENUM = "schemaName";
+ private static final String OPERATION_TYPE = "onosYangNodeOperationType";
+ private static final String STR_NONE = "NONE";
+ private static final String EQUALS = "=";
+ private static final String ENUM_LEAF_IDENTIFIER = "$LeafIdentifier";
+ private static final char CLOSE_BRACE = '}';
+ private static final Set<YangDataTypes> PRIMITIVE_TYPES =
+ new HashSet<>(Arrays.asList(INT8, INT16, INT32, INT64, UINT8,
+ UINT16, UINT32, UINT64, DECIMAL64,
+ BOOLEAN, EMPTY));
+
+ // No instantiation.
+ private YtbUtil() {
+ }
+
+ /**
+ * Returns the object of the node from the node info. Getting object for
+ * augment and case differs from other node.
+ *
+ * @param nodeInfo node info of the holder
+ * @param yangNode YANG node of the holder
+ * @return object of the parent
+ */
+ public static Object getParentObjectOfNode(YtbNodeInfo nodeInfo,
+ YangNode yangNode) {
+ Object object;
+ if (yangNode instanceof YangCase) {
+ object = nodeInfo.getCaseObject();
+ } else if (yangNode instanceof YangAugment) {
+ object = nodeInfo.getAugmentObject();
+ } else {
+ object = nodeInfo.getYangObject();
+ }
+ return object;
+ }
+
+ /**
+ * Returns the capital cased first letter of the given string.
+ *
+ * @param name string to be capital cased
+ * @return capital cased string
+ */
+ public static String getCapitalCase(String name) {
+ // TODO: It will be removed if common util is committed.
+ return name.substring(0, 1).toUpperCase() +
+ name.substring(1);
+ }
+
+ /**
+ * Returns the value of an attribute, in a class object. The attribute
+ * name is taken from the YANG node java name.
+ *
+ * @param nodeObj object of the node
+ * @param fieldName name of the attribute
+ * @return object of the attribute
+ * @throws NoSuchMethodException method not found exception
+ */
+ public static Object getAttributeOfObject(Object nodeObj, String fieldName)
+ throws NoSuchMethodException {
+ Class<?> nodeClass = nodeObj.getClass();
+ Method getterMethod;
+ try {
+ getterMethod = nodeClass.getDeclaredMethod(fieldName);
+ return getterMethod.invoke(nodeObj);
+ } catch (InvocationTargetException | IllegalAccessException e) {
+ throw new YtbException(e);
+ }
+ }
+
+ /**
+ * Returns the object of the declared method in parent class by invoking
+ * through the child class object.
+ *
+ * @param parentClass parent class of the declared method
+ * @param childClass child class which inherits the parent class
+ * @param methodName name of the declared method
+ * @return value of the method
+ */
+ public static Object getAttributeFromInheritance(
+ Class<?> parentClass, Object childClass, String methodName) {
+ Method getterMethod;
+ try {
+ getterMethod = parentClass.getDeclaredMethod(methodName);
+ return getterMethod.invoke(childClass);
+ } catch (InvocationTargetException | NoSuchMethodException |
+ IllegalAccessException e) {
+ throw new YtbException(e);
+ }
+ }
+
+ /**
+ * Returns interface class from an implementation class object.
+ *
+ * @param implClassObj implementation class object
+ * @return interface class
+ */
+ public static Class<?> getInterfaceClassFromImplClass(Object implClassObj) {
+ Class<?> implClass = implClassObj.getClass();
+ Class<?>[] interfaces = implClass.getInterfaces();
+ if (interfaces.length > ONE) {
+ // TODO: Need to handle when impl class has more than one interface.
+ throw new YtbException("Implementation class having more than one" +
+ " interface is not handled");
+ }
+ return interfaces[0];
+ }
+
+ /**
+ * Returns the operation type value for a class object. If the operation
+ * type is not set, then none type is returned.
+ *
+ * @param nodeObj node object
+ * @return operation type of the class
+ */
+ public static YdtContextOperationType getOperationTypeOfTheNode(
+ Object nodeObj) {
+ Object opTypeObj;
+ try {
+ opTypeObj = getAttributeOfObject(nodeObj, OPERATION_TYPE);
+ } catch (NoSuchMethodException e) {
+ return YdtContextOperationType.valueOf(STR_NONE);
+ }
+ String opTypeValue = String.valueOf(opTypeObj);
+ if (opTypeValue.equals(STR_NULL)) {
+ opTypeValue = STR_NONE;
+ }
+ return YdtContextOperationType.valueOf(opTypeValue);
+ }
+
+ /**
+ * Returns true, if data type of leaf is primitive data type; false
+ * otherwise.
+ *
+ * @param yangType leaf type
+ * @return true if data type is primitive; false otherwise
+ */
+ public static boolean isTypePrimitive(YangType yangType) {
+ if (yangType.getDataType() == LEAFREF) {
+ YangLeafRef leafRef =
+ (YangLeafRef) yangType.getDataTypeExtendedInfo();
+ return isPrimitiveDataType(leafRef.getEffectiveDataType()
+ .getDataType());
+ }
+ return isPrimitiveDataType(yangType.getDataType());
+ }
+
+ /**
+ * Returns the registered class from the YSR of the module node where
+ * augment is present.
+ *
+ * @param curNode current augment node
+ * @param registry schema registry
+ * @return class loader of module
+ */
+ public static Class<?> getClassLoaderForAugment(
+ YangNode curNode, YangSchemaRegistry registry) {
+ YangNode moduleNode = curNode.getParent();
+ String moduleName = moduleNode.getJavaClassNameOrBuiltInType();
+ String modulePackage = moduleNode.getJavaPackage();
+ return registry.getRegisteredClass(moduleNode,
+ modulePackage + PERIOD + moduleName);
+ }
+
+ /**
+ * Returns the string true, if the leaf data is actually set; false
+ * otherwise.
+ *
+ * @param nodeObj object if the node
+ * @param javaName java name of the leaf
+ * @param methodName getter method name
+ * @return string value of the boolean method
+ */
+ public static String isValueOrSelectLeafSet(
+ Object nodeObj, String javaName, String methodName) {
+
+ Class<?> nodeClass = nodeObj.getClass();
+ Class<?> interfaceClass = getInterfaceClassFromImplClass(nodeObj);
+
+ // Appends the enum inner package to the interface class package.
+ String enumPackage = interfaceClass.getName() + ENUM_LEAF_IDENTIFIER;
+
+ ClassLoader classLoader = interfaceClass.getClassLoader();
+ Class leafEnum;
+ try {
+ leafEnum = classLoader.loadClass(enumPackage);
+ Method getterMethod = nodeClass.getMethod(methodName, leafEnum);
+ // Gets the value of the enum.
+ Enum<?> value = Enum.valueOf(leafEnum, javaName.toUpperCase());
+ // Invokes the method with the value of enum as param.
+ return String.valueOf(getterMethod.invoke(nodeObj, value));
+ } catch (IllegalAccessException | InvocationTargetException |
+ NoSuchMethodException | ClassNotFoundException e) {
+ throw new YtbException(e);
+ }
+ }
+
+ /**
+ * Returns the string value from the respective data types of the
+ * leaf/leaf-list.
+ * // TODO: Remove this method and append to the data model utils.
+ *
+ * @param fieldObj object of the leaf/leaf-list field
+ * @param dataType type of the leaf/leaf-list
+ * @return string value from the type
+ */
+ public static String getStringFromDataType(Object fieldObj,
+ YangType dataType) {
+ YangDataTypes type = dataType.getDataType();
+ switch (type) {
+ case INT8:
+ case INT16:
+ case INT32:
+ case INT64:
+ case UINT8:
+ case UINT16:
+ case UINT32:
+ case UINT64:
+ case EMPTY:
+ case IDENTITYREF:
+ case STRING:
+ case DECIMAL64:
+ case INSTANCE_IDENTIFIER:
+ case DERIVED:
+ case UNION:
+ //TODO: Generated code has to be changed, it must select
+ // the setting leaf and it must give back the corresponding
+ // toString of that type.
+ case BOOLEAN:
+ case BITS:
+ return getValueFromToStringHelper(String.valueOf(fieldObj));
+
+ case BINARY:
+ return Base64.getEncoder().encodeToString((byte[]) fieldObj);
+
+ case LEAFREF:
+ YangLeafRef leafRef =
+ (YangLeafRef) dataType.getDataTypeExtendedInfo();
+ return getStringFromDataType(fieldObj,
+ leafRef.getEffectiveDataType());
+
+ case ENUMERATION:
+ Object value;
+ try {
+ value = getAttributeOfObject(fieldObj, SCHEMA_NAME_IN_ENUM);
+ } catch (NoSuchMethodException e) {
+ throw new YtbException(e);
+ }
+ return getValueFromToStringHelper(String.valueOf(value));
+
+ default:
+ throw new YtbException("Unsupported data type. Cannot be " +
+ "processed.");
+ }
+ }
+
+ /**
+ * Returns the value, from the toString value which uses toStringHelper.
+ * It gives values in non-usable format(e.g., {value = 5}). But the value
+ * that has to be returned is only 5.So it parses the string and returns
+ * only the value. In certain toString, to string helper is not used, so
+ * the original value is sent without parsing.
+ *
+ * @param rawString raw string
+ * @return parsed value
+ */
+ private static String getValueFromToStringHelper(String rawString) {
+ if (rawString.contains(EQUALS)) {
+ int index = rawString.lastIndexOf(EQUALS);
+ int braceIndex = rawString.indexOf(CLOSE_BRACE);
+ if (index != -1) {
+ return rawString.substring(index + 1, braceIndex);
+ }
+ }
+ return rawString;
+ }
+
+ /**
+ * Returns true, if the data type is primitive; false otherwise.
+ *
+ * @param dataType data type
+ * @return true if the data type is primitive; false otherwise
+ */
+ private static boolean isPrimitiveDataType(YangDataTypes dataType) {
+ return PRIMITIVE_TYPES.contains(dataType);
+ }
+
+ /**
+ * Returns true, if processing of the node is not required; false otherwise.
+ * For the nodes such as notification, RPC, augment there is a different
+ * flow, so these nodes are skipped in normal conditions.
+ *
+ * @param yangNode node to be checked
+ * @return true if node processing is not required; false otherwise.
+ */
+ public static boolean isNonProcessableNode(YangNode yangNode) {
+ return yangNode != null && (yangNode instanceof YangNotification) ||
+ (yangNode instanceof YangRpc) || (yangNode instanceof YangAugment);
+ }
+
+ /**
+ * Returns true, if multi instance node; false otherwise.
+ *
+ * @param yangNode YANG node
+ * @return true, if multi instance node; false otherwise.
+ */
+ public static boolean isMultiInstanceNode(YangNode yangNode) {
+ return yangNode.getYangSchemaNodeType() == YANG_MULTI_INSTANCE_NODE;
+ }
+
+ /**
+ * Returns true, if augment node; false otherwise.
+ *
+ * @param yangNode YANG node
+ * @return true, if augment node; false otherwise.
+ */
+ public static boolean isAugmentNode(YangNode yangNode) {
+ return yangNode.getYangSchemaNodeType() == YANG_AUGMENT_NODE;
+ }
+
+ /**
+ * Returns string for throwing error when empty object is given as input
+ * to YTB.
+ *
+ * @param objName name of the object
+ * @return error message
+ */
+ public static String emptyObjErrMsg(String objName) {
+ return "The " + objName + " given for tree creation cannot be null";
+ }
+
+ /**
+ * Returns the java name for the nodes, leaf/leaf-list.
+ *
+ * @param node YANG node
+ * @return node java name
+ */
+ public static String getJavaName(Object node) {
+ return ((JavaLeafInfoContainer) node).getJavaName(null);
+ }
+
+ /**
+ * Returns true, if the list is not null and non-empty; false otherwise.
+ *
+ * @param object list object
+ * @return true, if the list is not null and non-empty; false otherwise
+ */
+ public static boolean isNonEmpty(List object) {
+ return object != null && !object.isEmpty();
+ }
+
+ /**
+ * Returns true, if the string is not null and non-empty; false otherwise.
+ *
+ * @param str string value
+ * @return true, if the string is not null and non-empty; false otherwise.
+ */
+ public static boolean isNonEmpty(String str) {
+ return str != null && !str.isEmpty();
+ }
+
+ /**
+ * Returns true when the node processing of RPC and notification is
+ * completed; false otherwise. For RPC and notification, processing of
+ * other nodes are invalid, so once node gets completed, it must be stopped.
+ *
+ * @param curNode current node
+ * @param curTraversal current traversal of the node
+ * @return true, if the node processing is completed; false otherwise.
+ */
+ public static boolean isNodeProcessCompleted(
+ YangNode curNode, TraversalType curTraversal) {
+ return (curTraversal == PARENT &&
+ curNode instanceof YangNotification) ||
+ curNode instanceof YangOutput;
+ }
+
+}
diff --git a/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/package-info.java b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/package-info.java
new file mode 100644
index 0000000..1a4a827
--- /dev/null
+++ b/apps/yms/app/src/main/java/org/onosproject/yms/app/ytb/package-info.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Provides implementation of YANG tree builder. YTB handles creation of YDT
+ * from YANG modeled objects.
+ */
+package org.onosproject.yms.app.ytb;