/* * 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.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); } }