Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2017-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.yang.runtime.impl;
import org.onosproject.yang.compiler.datamodel.RpcNotificationContainer;
import org.onosproject.yang.compiler.datamodel.TraversalType;
import org.onosproject.yang.compiler.datamodel.YangAugment;
import org.onosproject.yang.compiler.datamodel.YangAugmentableNode;
import org.onosproject.yang.compiler.datamodel.YangCase;
import org.onosproject.yang.compiler.datamodel.YangChoice;
import org.onosproject.yang.compiler.datamodel.YangDerivedInfo;
import org.onosproject.yang.compiler.datamodel.YangLeaf;
import org.onosproject.yang.compiler.datamodel.YangLeafList;
import org.onosproject.yang.compiler.datamodel.YangLeafRef;
import org.onosproject.yang.compiler.datamodel.YangLeavesHolder;
import org.onosproject.yang.compiler.datamodel.YangList;
import org.onosproject.yang.compiler.datamodel.YangNode;
import org.onosproject.yang.compiler.datamodel.YangSchemaNode;
import org.onosproject.yang.compiler.datamodel.YangType;
import org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes;
import org.onosproject.yang.model.DataNode;
import org.onosproject.yang.model.InnerNode;
import org.onosproject.yang.model.LeafNode;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.onosproject.yang.compiler.datamodel.TraversalType.CHILD;
import static org.onosproject.yang.compiler.datamodel.TraversalType.PARENT;
import static org.onosproject.yang.compiler.datamodel.TraversalType.ROOT;
import static org.onosproject.yang.compiler.datamodel.TraversalType.SIBLING;
import static org.onosproject.yang.compiler.datamodel.utils.DataModelUtils.nonEmpty;
import static org.onosproject.yang.compiler.datamodel.utils.builtindatatype.YangDataTypes.EMPTY;
import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_LEAF_VALUE_NODE;
import static org.onosproject.yang.model.DataNode.Type.MULTI_INSTANCE_NODE;
import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_LEAF_VALUE_NODE;
import static org.onosproject.yang.model.DataNode.Type.SINGLE_INSTANCE_NODE;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getAttributeOfObject;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getAugmentObject;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getClassLoaderForAugment;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getInterfaceClassFromImplClass;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getJavaName;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getParentObjectOfNode;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.getStringFromType;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.isAugmentNode;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.isMultiInstanceNode;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.isNodeProcessCompleted;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.isNonProcessableNode;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.isTypePrimitive;
import static org.onosproject.yang.runtime.impl.ModelConverterUtil.isValueOrSelectLeafSet;
import static org.onosproject.yang.runtime.RuntimeHelper.DEFAULT_CAPS;
import static org.onosproject.yang.runtime.RuntimeHelper.PERIOD;
import static org.onosproject.yang.runtime.RuntimeHelper.getCapitalCase;
/**
* Implements traversal of YANG node and its corresponding object, resulting
* in building of the data tree.
*/
public class DataTreeBuilderHelper {
private static final String TRUE = "true";
private static final String IS_LEAF_VALUE_SET_METHOD = "isLeafValueSet";
private static final String AUGMENTATIONS = "augmentations";
private static final String FALSE = "false";
/**
* Default YANG model registry.
*/
private final DefaultYangModelRegistry reg;
/**
* Current instance of the data node builder where the tree is built.
*/
private DataNode.Builder 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;
/**
* Yang node for which exit builder is being processed.
*/
private YangSchemaNode exitBuilderSchema;
/**
* Creates an instance of data tree builder helper.
*
* @param reg default model registry
*/
public DataTreeBuilderHelper(DefaultYangModelRegistry reg) {
this.reg = reg;
}
/**
* Sets exit builder.
*
* @param extBuilder data node builder
*/
public void setExtBuilder(DataNode.Builder extBuilder) {
this.extBuilder = extBuilder;
}
/**
* Creates data tree from the root object, by traversing through YANG data
* model node, and simultaneously checking the object nodes presence and
* walking the object.
*
* @param curSchema current root node schema
* @param builder data node builder
* @param obj current root object
*/
DataNode.Builder getDataTree(YangSchemaNode curSchema, DataNode.Builder builder,
Object obj) {
extBuilder = builder;
rootObj = obj;
rootSchema = curSchema;
YangNode curNode = (YangNode) curSchema;
TraversalType curTraversal = ROOT;
DataTreeNodeInfo listNodeInfo = null;
DataTreeNodeInfo augmentNodeInfo = null;
do {
/*
* 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(curNode);
}
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
* data tree.
*/
processApplicationRootNode();
} else {
/*
* Gets the object corresponding to current schema node.
* If object exists, this adds the corresponding data node
* to the tree and returns the object. Else returns null.
*/
Object processedObject = processCurSchemaNode(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.
*/
ModelConverterTraversalInfo 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 = getParentInfo();
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)) {
ModelConverterTraversalInfo traverseInfo = getProcessableInfo(curNode);
curNode = traverseInfo.getYangNode();
curTraversal = traverseInfo.getTraverseType();
}
} else if (curNode.getNextSibling() != null) {
if (isNodeProcessCompleted(curNode, curTraversal)) {
break;
}
if (isMultiInstanceNode(curNode)) {
listNodeInfo = getCurNodeInfoAndTraverseBack(curNode);
augmentNodeInfo = null;
continue;
}
curTraversal = SIBLING;
augmentNodeInfo = null;
traverseToParent(curNode);
//here if current node does have a sibling node but current
// node is equal to the root schema then it will fail because
// our current root object does not have info about its sibling.
if (!curNode.equals(rootSchema)) {
if (curNode instanceof YangAugment) {
curTraversal = PARENT;
continue;
}
if (isNonProcessableNode(curNode)) {
ModelConverterTraversalInfo traverseInfo = getProcessableInfo(curNode);
curNode = traverseInfo.getYangNode();
curTraversal = traverseInfo.getTraverseType();
} else {
curNode = curNode.getNextSibling();
}
}
} else {
if (isNodeProcessCompleted(curNode, curTraversal)) {
break;
}
if (isMultiInstanceNode(curNode)) {
listNodeInfo = getCurNodeInfoAndTraverseBack(curNode);
augmentNodeInfo = null;
continue;
}
curTraversal = PARENT;
traverseToParent(curNode);
curNode = getParentSchemaNode(curNode);
}
} while (curNode != null && !curNode.equals(curSchema));
return extBuilder;
}
/**
* Returns parent schema node of current node.
*
* @param curNode current schema node
* @return parent schema node
*/
private YangNode getParentSchemaNode(YangNode curNode) {
if (curNode instanceof YangAugment) {
/*
* If curNode is augment, either next augment or augmented node
* has to be processed. So traversal type is changed to parent,
* but node is not changed.
*/
return curNode;
}
if (!curNode.equals(rootSchema)) {
return curNode.getParent();
}
return curNode;
}
/**
* Processes root YANG node and adds it as a child to the data tree
* builder which is created earlier.
*/
private void processApplicationRootNode() {
DataTreeNodeInfo nodeInfo = new DataTreeNodeInfo();
nodeInfo.setYangObject(rootObj);
if (rootSchema instanceof YangList) {
nodeInfo.type(MULTI_INSTANCE_NODE);
} else {
nodeInfo.type(SINGLE_INSTANCE_NODE);
}
extBuilder.appInfo(nodeInfo);
exitBuilderSchema = rootSchema;
processLeaves((YangNode) rootSchema, nodeInfo);
processLeavesList((YangNode) rootSchema, nodeInfo);
}
/**
* 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 data tree.
*
* @param curNode current YANG node
*/
private void traverseToParent(YangNode curNode) {
if (curNode instanceof YangCase || curNode instanceof YangChoice
|| curNode instanceof YangAugment) {
return;
}
if (!curNode.equals(rootSchema)) {
extBuilder = extBuilder.exitNode();
}
}
/**
* Returns the current data tree builder info of the data node builder, and
* then traverses back to parent. In case of multi instance node the
* previous node info is used for iterating through the list.
*
* @param curNode current YANG node
* @return current data tree builder info
*/
private DataTreeNodeInfo getCurNodeInfoAndTraverseBack(YangNode curNode) {
DataTreeNodeInfo appInfo = getParentInfo();
if (!curNode.equals(rootSchema)) {
extBuilder = extBuilder.exitNode();
}
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,
DataTreeNodeInfo augmentNodeInfo) {
if (augmentNodeInfo == null) {
List augmentList = ((YangAugmentableNode) curNode)
.getAugmentedInfoList();
if (nonEmpty(augmentList)) {
DataTreeNodeInfo parentNodeInfo = getParentInfo();
Iterator 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 data tree
* builder 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 processCurSchemaNode(YangNode curNode,
DataTreeNodeInfo listNodeInfo) {
DataTreeNodeInfo curNodeInfo = new DataTreeNodeInfo();
Object nodeObj = null;
DataTreeNodeInfo parentNodeInfo = getParentInfo();
if (curNode instanceof YangAugment) {
YangNode augmented = ((YangAugment) curNode).getAugmentedNode();
String name;
if (augmented instanceof YangCase) {
name = augmented.getJavaAttributeName();
Object obj;
try {
obj = getAttributeOfObject(
parentNodeInfo.getYangObject(), name);
} catch (NoSuchMethodException e) {
throw new ModelConvertorException(
"Not processable case node with augment in " +
"data tree");
}
parentNodeInfo = new DataTreeNodeInfo();
parentNodeInfo.setYangObject(obj);
parentNodeInfo.type(SINGLE_INSTANCE_NODE);
}
}
switch (curNode.getYangSchemaNodeType()) {
case YANG_SINGLE_INSTANCE_NODE:
curNodeInfo.type(SINGLE_INSTANCE_NODE);
nodeObj = processSingleInstanceNode(curNode, curNodeInfo,
parentNodeInfo);
break;
case YANG_MULTI_INSTANCE_NODE:
curNodeInfo.type(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 ModelConvertorException(
"Non processable schema node has arrived for adding " +
"it in data tree");
}
// Processes leaf/leaf-list only when object has value, else it skips.
if (nodeObj != null) {
processLeaves(curNode, parentNodeInfo);
processLeavesList(curNode, parentNodeInfo);
}
return nodeObj;
}
/**
* Processes single instance node which is added to the data tree.
*
* @param curNode current YANG node
* @param curNodeInfo current data tree node info
* @param parentNodeInfo parent data tree node info
* @return object of the current node
*/
private Object processSingleInstanceNode(YangNode curNode,
DataTreeNodeInfo curNodeInfo,
DataTreeNodeInfo parentNodeInfo) {
Object childObj = getChildObject(curNode, parentNodeInfo);
if (childObj != null) {
curNodeInfo.setYangObject(childObj);
curNodeInfo.type(SINGLE_INSTANCE_NODE);
processChildNode(curNode, curNodeInfo);
}
return childObj;
}
/**
* Processes multi instance node which has to be added to the data 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,
DataTreeNodeInfo curNodeInfo,
DataTreeNodeInfo listNodeInfo,
DataTreeNodeInfo parentNodeInfo) {
Object childObj = null;
/*
* When YANG list comes to this flow for first time, its data 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