blob: 96d3950458b8fc703f179031a0fb5ae13464fab3 [file] [log] [blame]
/*
* Copyright 2016-present Open Networking Foundation
*
* 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.YangDerivedInfo;
import org.onosproject.yangutils.datamodel.YangLeaf;
import org.onosproject.yangutils.datamodel.YangLeafList;
import org.onosproject.yangutils.datamodel.YangLeafRef;
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.YangType;
import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
import org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes;
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.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.EMPTY;
import static org.onosproject.yangutils.utils.io.impl.YangIoUtils.getCapitalCase;
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.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.getNodeOpType;
import static org.onosproject.yms.app.ytb.YtbUtil.getOpTypeName;
import static org.onosproject.yms.app.ytb.YtbUtil.getParentObjectOfNode;
import static org.onosproject.yms.app.ytb.YtbUtil.getStringFromType;
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.isNonProcessableNode;
import static org.onosproject.yms.app.ytb.YtbUtil.isTypePrimitive;
import static org.onosproject.yms.app.ytb.YtbUtil.isValueOrSelectLeafSet;
import static org.onosproject.yms.app.ytb.YtbUtil.nonEmpty;
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";
private static final String FALSE = "false";
/**
* 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;
augmentNodeInfo = null;
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 = getParentSchemaNode(curNode);
}
}
}
/**
* 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;
}
return 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
|| curNode instanceof YangAugment) {
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 (nonEmpty(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 (nonEmpty(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 = 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 =
getNodeOpType(childObj, getOpTypeName(curNode));
extBuilder.addChild(opType, curNode);
YdtExtendedContext curExtContext = 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(yangNode, yangLeaf, parentObj, leafType);
addLeafWithoutValue(yangNode, yangLeaf, parentObj);
}
}
}
}
/**
* Processes every leaf-list in a YANG node for adding the value in 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) {
addToBuilder(yangNode, yangLeafList);
}
}
}
}
/**
* Processes the list of objects of the leaf list and adds the leaf list
* value to the builder.
*
* @param yangNode YANG node
* @param leafList YANG leaf list
*/
private void addToBuilder(YangNode yangNode, YangLeafList leafList) {
YtbNodeInfo ytbNodeInfo = getParentYtbInfo();
Object parentObj = getParentObjectOfNode(ytbNodeInfo, yangNode);
List<Object> obj;
try {
obj = (List<Object>) getAttributeOfObject(parentObj,
getJavaName(leafList));
} catch (NoSuchMethodException e) {
throw new YtbException(e);
}
if (obj != null) {
addLeafListValue(yangNode, parentObj, leafList, obj);
}
}
/**
* Adds the leaf list value to the YDT builder by taking the string value
* from the data type.
*
* @param yangNode YANG node
* @param parentObj parent object
* @param leafList YANG leaf list
* @param obj list of objects
*/
private void addLeafListValue(YangNode yangNode, Object parentObj,
YangLeafList leafList, List<Object> obj) {
Set<String> leafListVal = new LinkedHashSet<>();
boolean isEmpty = false;
for (Object object : obj) {
String val = getStringFromType(yangNode, parentObj,
getJavaName(leafList), object,
leafList.getDataType());
isEmpty = isTypeEmpty(val, leafList.getDataType());
if (isEmpty) {
if (val.equals(TRUE)) {
addLeafList(leafListVal, leafList);
}
break;
}
if (!"".equals(val)) {
leafListVal.add(val);
}
}
if (!isEmpty && !leafListVal.isEmpty()) {
addLeafList(leafListVal, leafList);
}
}
/**
* Adds set of leaf list values in the builder and traverses back to the
* holder.
*
* @param leafListVal set of values
* @param leafList YANG leaf list
*/
private void addLeafList(Set<String> leafListVal, YangLeafList leafList) {
extBuilder.addLeafList(leafListVal, leafList);
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() {
Object eventObjType = getAttributeFromInheritance(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() {
Object eventSubjectObj =
getAttributeFromInheritance(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 holder leaf holder
* @param yangLeaf YANG leaf node
* @param parentObj leaf holder object
* @param leafType object of leaf type
*/
private void addLeafWithValue(YangSchemaNode holder, YangLeaf yangLeaf,
Object parentObj, Object leafType) {
String fieldValue = null;
if (isTypePrimitive(yangLeaf.getDataType())) {
fieldValue = getLeafValueFromValueSetFlag(holder, 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 = getStringFromType(holder, parentObj,
getJavaName(yangLeaf), leafType,
yangLeaf.getDataType());
}
if (nonEmpty(fieldValue)) {
boolean isEmpty = isTypeEmpty(fieldValue,
yangLeaf.getDataType());
if (isEmpty) {
if (!fieldValue.equals(TRUE)) {
return;
}
fieldValue = null;
}
extBuilder.addLeaf(fieldValue, yangLeaf);
extBuilder.traverseToParentWithoutValidation();
}
}
/**
* Returns the value as true if direct or referred type from leafref or
* derived points to empty data type; false otherwise.
*
* @param fieldValue value of the leaf
* @param dataType type of the leaf
* @return true if type is empty; false otherwise.
*/
private boolean isTypeEmpty(String fieldValue, YangType<?> dataType) {
if (fieldValue.equals(TRUE) || fieldValue.equals(FALSE)) {
switch (dataType.getDataType()) {
case EMPTY:
return true;
case LEAFREF:
YangLeafRef leafRef =
(YangLeafRef) dataType.getDataTypeExtendedInfo();
return isTypeEmpty(fieldValue,
leafRef.getEffectiveDataType());
case DERIVED:
YangDerivedInfo info =
(YangDerivedInfo) dataType
.getDataTypeExtendedInfo();
YangDataTypes type = info.getEffectiveBuiltInType();
return type == EMPTY;
default:
return false;
}
}
return false;
}
/**
* Adds leaf without value, when the select leaf bit is set.
*
* @param holder leaf holder
* @param yangLeaf YANG leaf node
* @param parentObj leaf holder object
*/
private void addLeafWithoutValue(YangSchemaNode holder, YangLeaf yangLeaf,
Object parentObj) {
String selectLeaf;
try {
selectLeaf = isValueOrSelectLeafSet(holder, parentObj,
getJavaName(yangLeaf),
IS_SELECT_LEAF_SET_METHOD);
} catch (NoSuchMethodException e) {
selectLeaf = FALSE;
}
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 else returns null.
*
* @param holder leaf holder
* @param parentObj parent object
* @param yangLeaf YANG leaf node
* @param leafType object of leaf type
* @return value of type
*/
private String getLeafValueFromValueSetFlag(YangSchemaNode holder, Object parentObj,
YangLeaf yangLeaf, Object leafType) {
String valueOfLeaf;
try {
valueOfLeaf = isValueOrSelectLeafSet(holder, parentObj,
getJavaName(yangLeaf),
IS_LEAF_VALUE_SET_METHOD);
} catch (NoSuchMethodException e) {
throw new YtbException(e);
}
if (valueOfLeaf.equals(TRUE)) {
return getStringFromType(holder, parentObj,
getJavaName(yangLeaf), 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);
}
}