blob: a82eea2ccd64ee5cb62272ef605985ab094c3bf9 [file] [log] [blame]
janani b05614f12016-10-04 12:55:43 +05301/*
2 * Copyright 2016-present Open Networking Laboratory
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package org.onosproject.yms.app.ytb;
18
19import org.onosproject.yangutils.datamodel.YangAugment;
20import org.onosproject.yangutils.datamodel.YangAugmentableNode;
21import org.onosproject.yangutils.datamodel.YangCase;
22import org.onosproject.yangutils.datamodel.YangChoice;
23import org.onosproject.yangutils.datamodel.YangLeaf;
24import org.onosproject.yangutils.datamodel.YangLeafList;
25import org.onosproject.yangutils.datamodel.YangLeavesHolder;
26import org.onosproject.yangutils.datamodel.YangNode;
27import org.onosproject.yangutils.datamodel.YangSchemaNode;
28import org.onosproject.yangutils.datamodel.YangSchemaNodeIdentifier;
29import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
30import org.onosproject.yms.app.utils.TraversalType;
31import org.onosproject.yms.app.ydt.YdtExtendedBuilder;
32import org.onosproject.yms.app.ydt.YdtExtendedContext;
33import org.onosproject.yms.app.ysr.YangSchemaRegistry;
34import org.onosproject.yms.ydt.YdtContextOperationType;
35
36import java.util.HashMap;
37import java.util.HashSet;
38import java.util.Iterator;
39import java.util.List;
40import java.util.Map;
41import java.util.Set;
42
43import static org.onosproject.yms.app.utils.TraversalType.CHILD;
44import static org.onosproject.yms.app.utils.TraversalType.PARENT;
45import static org.onosproject.yms.app.utils.TraversalType.ROOT;
46import static org.onosproject.yms.app.utils.TraversalType.SIBLING;
47import static org.onosproject.yms.app.ydt.AppType.YTB;
48import static org.onosproject.yms.app.ytb.YtbUtil.PERIOD;
49import static org.onosproject.yms.app.ytb.YtbUtil.STR_NULL;
50import static org.onosproject.yms.app.ytb.YtbUtil.getAttributeFromInheritance;
51import static org.onosproject.yms.app.ytb.YtbUtil.getAttributeOfObject;
52import static org.onosproject.yms.app.ytb.YtbUtil.getCapitalCase;
53import static org.onosproject.yms.app.ytb.YtbUtil.getClassLoaderForAugment;
54import static org.onosproject.yms.app.ytb.YtbUtil.getInterfaceClassFromImplClass;
55import static org.onosproject.yms.app.ytb.YtbUtil.getJavaName;
56import static org.onosproject.yms.app.ytb.YtbUtil.getOperationTypeOfTheNode;
57import static org.onosproject.yms.app.ytb.YtbUtil.getParentObjectOfNode;
58import static org.onosproject.yms.app.ytb.YtbUtil.getStringFromDataType;
59import static org.onosproject.yms.app.ytb.YtbUtil.isAugmentNode;
60import static org.onosproject.yms.app.ytb.YtbUtil.isMultiInstanceNode;
61import static org.onosproject.yms.app.ytb.YtbUtil.isNodeProcessCompleted;
62import static org.onosproject.yms.app.ytb.YtbUtil.isNonEmpty;
63import static org.onosproject.yms.app.ytb.YtbUtil.isNonProcessableNode;
64import static org.onosproject.yms.app.ytb.YtbUtil.isTypePrimitive;
65import static org.onosproject.yms.app.ytb.YtbUtil.isValueOrSelectLeafSet;
66import static org.onosproject.yms.ydt.YdtContextOperationType.NONE;
67
68/**
69 * Implements traversal of YANG node and its corresponding object, resulting
70 * in building of the YDT tree.
71 */
72public class YdtBuilderFromYo {
73
74 private static final String STR_TYPE = "type";
75 private static final String STR_SUBJECT = "subject";
76 private static final String TRUE = "true";
77 private static final String IS_LEAF_VALUE_SET_METHOD = "isLeafValueSet";
78 private static final String IS_SELECT_LEAF_SET_METHOD = "isSelectLeaf";
79 private static final String OUTPUT = "output";
80 private static final String YANG_AUGMENTED_INFO_MAP =
81 "yangAugmentedInfoMap";
82
83 /**
84 * Application YANG schema registry.
85 */
86 private final YangSchemaRegistry registry;
87
88 /**
89 * Current instance of the YDT builder where the tree is built.
90 */
91 private final YdtExtendedBuilder extBuilder;
92
93 /**
94 * YANG root object that is required for walking along with the YANG node.
95 */
96 private Object rootObj;
97
98 /**
99 * YANG root node that is required for walking along with the YANG object.
100 */
101 private YangSchemaNode rootSchema;
102
103 /**
104 * Creates YDT builder from YANG object by assigning the mandatory values.
105 *
106 * @param rootBuilder root node builder
107 * @param rootObj root node object
108 * @param registry application schema registry
109 */
110 public YdtBuilderFromYo(YdtExtendedBuilder rootBuilder, Object rootObj,
111 YangSchemaRegistry registry) {
112 extBuilder = rootBuilder;
113 this.rootObj = rootObj;
114 this.registry = registry;
115 }
116
117 /**
118 * Returns schema root node, received from YSR, which searches based on
119 * the object received from YAB or YCH.
120 *
121 * @param object root node object
122 */
123 public void getModuleNodeFromYsr(Object object) {
124 Class interfaceClass = getInterfaceClassFromImplClass(object);
125 rootSchema = registry
126 .getYangSchemaNodeUsingGeneratedRootNodeInterfaceFileName(
127 interfaceClass.getName());
128 }
129
130 /**
131 * Returns schema root node, received from YSR, which searches based on
132 * the object received from YNH.
133 *
134 * @param object notification event object
135 */
136 public void getRootNodeWithNotificationFromYsr(Object object) {
137 rootSchema = registry.getRootYangSchemaNodeForNotification(
138 object.getClass().getName());
139 }
140
141 /**
142 * Creates the module node for in YDT before beginning with notification
143 * root node traversal. Collects sufficient information to fill YDT with
144 * notification root node in the traversal.
145 */
146 public void createModuleInYdt() {
147 extBuilder.addChild(NONE, rootSchema);
148 rootSchema = getSchemaNodeOfNotification();
149 rootObj = getObjOfNotification();
150 }
151
152 /**
153 * Creates the module and RPC node, in YDT tree, from the logical root
154 * node received from request workbench. The output schema node is taken
155 * from the child schema of RPC YANG node.
156 *
157 * @param rootNode logical root node
158 */
159 public void createModuleAndRpcInYdt(YdtExtendedContext rootNode) {
160
161 YdtExtendedContext moduleNode =
162 (YdtExtendedContext) rootNode.getFirstChild();
163 extBuilder.addChild(NONE, moduleNode.getYangSchemaNode());
164
165 YdtExtendedContext rpcNode =
166 (YdtExtendedContext) moduleNode.getFirstChild();
167 YangSchemaNode rpcSchemaNode = rpcNode.getYangSchemaNode();
168 extBuilder.addChild(NONE, rpcSchemaNode);
169
170 // Defines a schema identifier for output node.
171 YangSchemaNodeIdentifier schemaId = new YangSchemaNodeIdentifier();
172 schemaId.setName(OUTPUT);
173 schemaId.setNameSpace(rpcSchemaNode.getNameSpace());
174 try {
175 // Gets the output schema node from RPC child schema.
176 rootSchema = rpcSchemaNode.getChildSchema(schemaId).getSchemaNode();
177 } catch (DataModelException e) {
178 throw new YtbException(e);
179 }
180 }
181
182 /**
183 * Creates YDT tree from the root object, by traversing through YANG data
184 * model node, and simultaneously checking the object nodes presence and
185 * walking the object.
186 */
187 public void createYdtFromRootObject() {
188 YangNode curNode = (YangNode) rootSchema;
189 TraversalType curTraversal = ROOT;
190 YtbNodeInfo listNodeInfo = null;
191 YtbNodeInfo augmentNodeInfo = null;
192
193 while (curNode != null) {
194 /*
195 * Processes the node, if it is being visited for the first time in
196 * the schema, also if the schema node is being retraced in a multi
197 * instance node.
198 */
199 if (curTraversal != PARENT || isMultiInstanceNode(curNode)) {
200
201 if (curTraversal == PARENT && isMultiInstanceNode(curNode)) {
202 /*
203 * If the schema is being retraced for a multi-instance
204 * node, it has already entered for this multi-instance
205 * node. Now this re-processes the same schema node for
206 * any additional list object.
207 */
208 listNodeInfo = getCurNodeInfoAndTraverseBack();
209 }
210
211 if (curTraversal == ROOT && !isAugmentNode(curNode)) {
212 /*
213 * In case of RPC output, the root node is augmentative,
214 * so when the root traversal is coming for augment this
215 * flow is skipped. This adds only the root node in the YDT.
216 */
217 processApplicationRootNode();
218 } else {
219 /*
220 * Gets the object corresponding to current schema node.
221 * If object exists, this adds the corresponding YDT node
222 * to the tree and returns the object. Else returns null.
223 */
224 Object processedObject = processCurSchemaNodeAndAddToYdt(
225 curNode, listNodeInfo);
226 /*
227 * Clears the list info of processed node. The next time
228 * list info is taken newly and accordingly.
229 */
230 listNodeInfo = null;
231 if (processedObject == null && !isAugmentNode(curNode)) {
232 /*
233 * Checks the presence of next sibling of the node, by
234 * breaking the complete chain of the current node,
235 * when the object value is not present, or when the
236 * list entries are completely retraced. The augment
237 * may have sibling, so this doesn't process for
238 * augment.
239 */
240 YtbTraversalInfo traverseInfo =
241 getProcessableInfo(curNode);
242 curNode = traverseInfo.getYangNode();
243 curTraversal = traverseInfo.getTraverseType();
244 continue;
245 /*
246 * Irrespective of root or parent, sets the traversal
247 * type as parent, when augment node doesn't have any
248 * value. So, the other sibling augments can be
249 * processed, if present.
250 */
251 } else if (processedObject == null &&
252 isAugmentNode(curNode)) {
253 curTraversal = PARENT;
254 /*
255 * The second content in the list will be having
256 * parent traversal, in such case it cannot go to its
257 * child in the flow, so it is made as child
258 * traversal and proceeded to continue.
259 */
260 } else if (curTraversal == PARENT &&
261 isMultiInstanceNode(curNode)) {
262 curTraversal = CHILD;
263 }
264 }
265 }
266 /*
267 * Checks for the sibling augment when the first augment node is
268 * getting completed. From the current augment node the previous
269 * node info is taken for augment and the traversal is changed to
270 * child, so as to check for the presence of sibling augment.
271 */
272 if (curTraversal == PARENT && isAugmentNode(curNode)) {
273 curNode = ((YangAugment) curNode).getAugmentedNode();
274 augmentNodeInfo = getParentYtbInfo();
275 curTraversal = CHILD;
276 }
277 /*
278 * Creates an augment iterator for the first time or takes the
279 * previous augment iterator for more than one time, whenever an
280 * augmentative node arrives. If augment is present it goes back
281 * for processing. If its null, the augmentative nodes process is
282 * continued.
283 */
284 if (curTraversal != PARENT &&
285 curNode instanceof YangAugmentableNode) {
286 YangNode augmentNode = getAugmentInsideSchemaNode(
287 curNode, augmentNodeInfo);
288 if (augmentNode != null) {
289 curNode = augmentNode;
290 continue;
291 }
292 }
293 /*
294 * Processes the child, after processing the node. If complete
295 * child depth is over, it takes up sibling and processes it.
296 * Once child and sibling is over, it is traversed back to the
297 * parent, without processing. In multi instance case, before
298 * going to parent or schema sibling, its own list sibling is
299 * processed. Skips the processing of RPC,notification and
300 * augment, as these nodes are dealt in a different flow.
301 */
302 if (curTraversal != PARENT && curNode.getChild() != null) {
303 augmentNodeInfo = null;
304 listNodeInfo = null;
305 curTraversal = CHILD;
306 curNode = curNode.getChild();
307 if (isNonProcessableNode(curNode)) {
308 YtbTraversalInfo traverseInfo = getProcessableInfo(curNode);
309 curNode = traverseInfo.getYangNode();
310 curTraversal = traverseInfo.getTraverseType();
311 }
312 } else if (curNode.getNextSibling() != null) {
313 if (isNodeProcessCompleted(curNode, curTraversal)) {
314 break;
315 }
316 if (isMultiInstanceNode(curNode)) {
317 listNodeInfo = getCurNodeInfoAndTraverseBack();
318 augmentNodeInfo = null;
319 continue;
320 }
321 curTraversal = SIBLING;
322 traverseToParent(curNode);
323 curNode = curNode.getNextSibling();
324 if (isNonProcessableNode(curNode)) {
325 YtbTraversalInfo traverseInfo = getProcessableInfo(curNode);
326 curNode = traverseInfo.getYangNode();
327 curTraversal = traverseInfo.getTraverseType();
328 }
329 } else {
330 if (isNodeProcessCompleted(curNode, curTraversal)) {
331 break;
332 }
333 if (isMultiInstanceNode(curNode)) {
334 listNodeInfo = getCurNodeInfoAndTraverseBack();
335 augmentNodeInfo = null;
336 continue;
337 }
338 curTraversal = PARENT;
339 traverseToParent(curNode);
340 curNode = curNode.getParent();
341 }
342 }
343 }
344
345 /**
346 * Processes root YANG node and adds it as a child to the YDT
347 * extended builder which is created earlier.
348 */
349 private void processApplicationRootNode() {
350
351 YtbNodeInfo nodeInfo = new YtbNodeInfo();
352 YangNode rootYang = (YangNode) rootSchema;
353 addChildNodeInYdt(rootObj, rootYang, nodeInfo);
354 // If root node has leaf or leaf-list those will be processed.
355 processLeaves(rootYang);
356 processLeavesList(rootYang);
357 }
358
359 /**
360 * Traverses to parent, based on the schema node that requires to be
361 * traversed. Skips traversal of parent for choice and case node, as they
362 * don't get added to the YDT tree.
363 *
364 * @param curNode current YANG node
365 */
366 private void traverseToParent(YangNode curNode) {
367 if (curNode instanceof YangCase || curNode instanceof YangChoice) {
368 return;
369 }
370 extBuilder.traverseToParentWithoutValidation();
371 }
372
373 /**
374 * Returns the current YTB info of the YDT builder, and then traverses back
375 * to parent. In case of multi instance node the previous node info is
376 * used for iterating through the list.
377 *
378 * @return current YTB app info
379 */
380 private YtbNodeInfo getCurNodeInfoAndTraverseBack() {
381 YtbNodeInfo appInfo = getParentYtbInfo();
382 extBuilder.traverseToParentWithoutValidation();
383 return appInfo;
384 }
385
386 /**
387 * Returns augment node for an augmented node. From the list of augment
388 * nodes it has, one of the nodes is taken and provided linearly. If the
389 * node is not augmented or the all the augment nodes are processed, then
390 * it returns null.
391 *
392 * @param curNode current YANG node
393 * @param augmentNodeInfo previous augment node info
394 * @return YANG augment node
395 */
396 private YangNode getAugmentInsideSchemaNode(YangNode curNode,
397 YtbNodeInfo augmentNodeInfo) {
398 if (augmentNodeInfo == null) {
399 List<YangAugment> augmentList = ((YangAugmentableNode) curNode)
400 .getAugmentedInfoList();
401 if (isNonEmpty(augmentList)) {
402 YtbNodeInfo parentNodeInfo = getParentYtbInfo();
403 Iterator<YangAugment> augmentItr = augmentList.listIterator();
404 parentNodeInfo.setAugmentIterator(augmentItr);
405 return augmentItr.next();
406 }
407 } else if (augmentNodeInfo.getAugmentIterator() != null) {
408 if (augmentNodeInfo.getAugmentIterator().hasNext()) {
409 return augmentNodeInfo.getAugmentIterator().next();
410 }
411 }
412 return null;
413 }
414
415 /**
416 * Processes the current YANG node and if necessary adds it to the YDT
417 * builder tree by extracting the information from the corresponding
418 * class object.
419 *
420 * @param curNode current YANG node
421 * @param listNodeInfo previous node info for list
422 * @return object of the schema node
423 */
424 private Object processCurSchemaNodeAndAddToYdt(YangNode curNode,
425 YtbNodeInfo listNodeInfo) {
426 YtbNodeInfo curNodeInfo = new YtbNodeInfo();
427 Object nodeObj = null;
428 YtbNodeInfo parentNodeInfo = getParentYtbInfo();
429
430 switch (curNode.getYangSchemaNodeType()) {
431 case YANG_SINGLE_INSTANCE_NODE:
432 nodeObj = processSingleInstanceNode(curNode, curNodeInfo,
433 parentNodeInfo);
434 break;
435 case YANG_MULTI_INSTANCE_NODE:
436 nodeObj = processMultiInstanceNode(
437 curNode, curNodeInfo, listNodeInfo, parentNodeInfo);
438 break;
439 case YANG_CHOICE_NODE:
440 nodeObj = processChoiceNode(curNode, parentNodeInfo);
441 break;
442 case YANG_NON_DATA_NODE:
443 if (curNode instanceof YangCase) {
444 nodeObj = processCaseNode(curNode, parentNodeInfo);
445 }
446 break;
447 case YANG_AUGMENT_NODE:
448 nodeObj = processAugmentNode(curNode, parentNodeInfo);
449 break;
450 default:
451 throw new YtbException(
452 "Non processable schema node has arrived for adding " +
453 "it in YDT tree");
454 }
455 // Processes leaf/leaf-list only when object has value, else it skips.
456 if (nodeObj != null) {
457 processLeaves(curNode);
458 processLeavesList(curNode);
459 }
460 return nodeObj;
461 }
462
463 /**
464 * Processes single instance node which is added to the YDT tree.
465 *
466 * @param curNode current YANG node
467 * @param curNodeInfo current YDT node info
468 * @param parentNodeInfo parent YDT node info
469 * @return object of the current node
470 */
471 private Object processSingleInstanceNode(YangNode curNode,
472 YtbNodeInfo curNodeInfo,
473 YtbNodeInfo parentNodeInfo) {
474 Object childObj = getChildObject(curNode, parentNodeInfo);
475 if (childObj != null) {
476 addChildNodeInYdt(childObj, curNode, curNodeInfo);
477 }
478 return childObj;
479 }
480
481 /**
482 * Processes multi instance node which has to be added to the YDT tree.
483 * For the first instance in the list, iterator is created and added to
484 * the list. For second instance or more the iterator from first instance
485 * is taken and iterated through to get the object of parent.
486 *
487 * @param curNode current list node
488 * @param curNodeInfo current node info for list
489 * @param listNodeInfo previous instance node info of list
490 * @param parentNodeInfo parent node info of list
491 * @return object of the current instance
492 */
493 private Object processMultiInstanceNode(YangNode curNode,
494 YtbNodeInfo curNodeInfo,
495 YtbNodeInfo listNodeInfo,
496 YtbNodeInfo parentNodeInfo) {
497 Object childObj = null;
498 /*
499 * When YANG list comes to this flow for first time, its YTB node
500 * will be null. When it comes for the second or more content, then
501 * the list would have been already set for that node. According to
502 * set or not set this flow will be proceeded.
503 */
504 if (listNodeInfo == null) {
505 List<Object> childObjList = (List<Object>) getChildObject(
506 curNode, parentNodeInfo);
507 if (isNonEmpty(childObjList)) {
508 Iterator<Object> listItr = childObjList.iterator();
509 if (!listItr.hasNext()) {
510 return null;
511 //TODO: Handle the subtree filtering with no list entries.
512 }
513 childObj = listItr.next();
514 /*
515 * For that node the iterator is set. So the next time for
516 * the list this iterator will be taken.
517 */
518 curNodeInfo.setListIterator(listItr);
519 }
520 } else {
521 /*
522 * If the list value comes for second or more time, that list
523 * node will be having YTB node info, where iterator can be
524 * retrieved and check if any more contents are present. If
525 * present those will be processed.
526 */
527 curNodeInfo.setListIterator(listNodeInfo.getListIterator());
528 if (listNodeInfo.getListIterator().hasNext()) {
529 childObj = listNodeInfo.getListIterator().next();
530 }
531 }
532 if (childObj != null) {
533 addChildNodeInYdt(childObj, curNode, curNodeInfo);
534 }
535 return childObj;
536 }
537
538 /**
539 * Processes choice node which adds a map to the parent node info of
540 * choice name and the case object. The object taken for choice node is
541 * of case object with choice name. Also, this Skips the addition of choice
542 * to YDT.
543 *
544 * @param curNode current choice node
545 * @param parentNodeInfo parent YTB node info
546 * @return object of the choice node
547 */
548 private Object processChoiceNode(YangNode curNode,
549 YtbNodeInfo parentNodeInfo) {
550 /*
551 * Retrieves the parent YTB info, to take the object of parent, so as
552 * to check the child attribute from the object.
553 */
554 Object childObj = getChildObject(curNode, parentNodeInfo);
555 if (childObj != null) {
556 Map<String, Object> choiceCaseMap = parentNodeInfo
557 .getChoiceCaseMap();
558 if (choiceCaseMap == null) {
559 choiceCaseMap = new HashMap<>();
560 parentNodeInfo.setChoiceCaseMap(choiceCaseMap);
561 }
562 choiceCaseMap.put(curNode.getName(), childObj);
563 }
564 return childObj;
565 }
566
567 /**
568 * Processes case node from the map contents that is filled by choice
569 * nodes. Object of choice is taken when choice name and case class name
570 * matches. When the case node is not present in the map it returns null.
571 *
572 * @param curNode current case node
573 * @param parentNodeInfo choice parent node info
574 * @return object of the case node
575 */
576 private Object processCaseNode(YangNode curNode,
577 YtbNodeInfo parentNodeInfo) {
578 Object childObj = null;
579 if (parentNodeInfo.getChoiceCaseMap() != null) {
580 childObj = getCaseObjectFromChoice(parentNodeInfo,
581 curNode);
582 }
583 if (childObj != null) {
584 /*
585 * Sets the case object in parent info, so that rest of the case
586 * children can use it as parent. Case is not added in YDT.
587 */
588 parentNodeInfo.setCaseObject(childObj);
589 }
590 return childObj;
591 }
592
593 /**
594 * Processes augment node, which is not added in the YDT, but binds
595 * itself to the parent YTB info, so rest of its child nodes can use for
596 * adding themselves to the YDT tree. If there is no augment node added
597 * in map or if the augment module is not registered, then it returns null.
598 *
599 * @param curNode current augment node
600 * @param parentNodeInfo augment parent node info
601 * @return object of the augment node
602 */
603 private Object processAugmentNode(YangNode curNode,
604 YtbNodeInfo parentNodeInfo) {
605 String className = curNode.getJavaClassNameOrBuiltInType();
606 String pkgName = curNode.getJavaPackage();
607 Object parentObj = getParentObjectOfNode(parentNodeInfo,
608 curNode.getParent());
609 Map augmentMap;
610 try {
611 augmentMap = (Map) getAttributeOfObject(parentObj,
612 YANG_AUGMENTED_INFO_MAP);
613 /*
614 * Gets the registered module class. Loads the class and gets the
615 * augment class.
616 */
617 Class moduleClass = getClassLoaderForAugment(curNode, registry);
618 if (moduleClass == null) {
619 return null;
620 }
621 Class augmentClass = moduleClass.getClassLoader().loadClass(
622 pkgName + PERIOD + className);
623 Object childObj = augmentMap.get(augmentClass);
624 parentNodeInfo.setAugmentObject(childObj);
625 return childObj;
626 } catch (ClassNotFoundException | NoSuchMethodException e) {
627 throw new YtbException(e);
628 }
629 }
630
631 /**
632 * Returns the YTB info from the parent node, so that its own bounded
633 * object can be taken out.
634 *
635 * @return parent node YTB node info
636 */
637 private YtbNodeInfo getParentYtbInfo() {
638 YdtExtendedContext parentExtContext =
639 (YdtExtendedContext) extBuilder.getCurNode();
640 return (YtbNodeInfo) parentExtContext.getAppInfo(YTB);
641 }
642
643 /**
644 * Returns the child object from the parent object. Uses java name of the
645 * current node to search the attribute in the parent object.
646 *
647 * @param curNode current YANG node
648 * @param parentNodeInfo parent YTB node info
649 * @return object of the child node
650 */
651 private Object getChildObject(YangNode curNode,
652 YtbNodeInfo parentNodeInfo) {
653 String nodeJavaName = curNode.getJavaAttributeName();
654 Object parentObj = getParentObjectOfNode(parentNodeInfo,
655 curNode.getParent());
656 try {
657 return getAttributeOfObject(parentObj, nodeJavaName);
658 } catch (NoSuchMethodException e) {
659 throw new YtbException(e);
660 }
661 }
662
663 /**
664 * Adds the child node to the YDT by taking operation type from the
665 * object. Also, binds the object to the YDT node through YTB node info.
666 *
667 * @param childObj node object
668 * @param curNode current YANG node
669 * @param curNodeInfo current YTB info
670 */
671 private void addChildNodeInYdt(Object childObj, YangNode curNode,
672 YtbNodeInfo curNodeInfo) {
673 YdtContextOperationType opType = getOperationTypeOfTheNode(childObj);
674 extBuilder.addChild(opType, curNode);
675 YdtExtendedContext curExtContext = (YdtExtendedContext) extBuilder
676 .getCurNode();
677 curNodeInfo.setYangObject(childObj);
678 curExtContext.addAppInfo(YTB, curNodeInfo);
679 }
680
681 /**
682 * Processes every leaf in a YANG node. Iterates through the leaf, takes
683 * value from the leaf and adds it to the YDT with value. If value is not
684 * present, and select leaf is set, adds it to the YDT without value.
685 *
686 * @param yangNode leaves holder node
687 */
688 private void processLeaves(YangNode yangNode) {
689 if (yangNode instanceof YangLeavesHolder) {
690 List<YangLeaf> leavesList = ((YangLeavesHolder) yangNode)
691 .getListOfLeaf();
692 if (leavesList != null) {
693 for (YangLeaf yangLeaf : leavesList) {
694 YtbNodeInfo parentYtbInfo = getParentYtbInfo();
695 Object parentObj = getParentObjectOfNode(parentYtbInfo,
696 yangNode);
697 Object leafType;
698 try {
699 leafType = getAttributeOfObject(parentObj,
700 getJavaName(yangLeaf));
701 } catch (NoSuchMethodException e) {
702 throw new YtbException(e);
703 }
704
705 addLeafWithValue(yangLeaf, parentObj, leafType);
706 addLeafWithoutValue(yangLeaf, parentObj);
707 }
708 }
709 }
710 }
711
712 /**
713 * Processes every leaf-list in a YANG node. For each leaf-list, the list of
714 * objects are iterated, value from each object is put in a set of string,
715 * and is added to the YDT.
716 *
717 * @param yangNode list of leaf-list holder node
718 */
719 private void processLeavesList(YangNode yangNode) {
720 if (yangNode instanceof YangLeavesHolder) {
721 List<YangLeafList> listOfLeafList =
722 ((YangLeavesHolder) yangNode).getListOfLeafList();
723
724 if (listOfLeafList != null) {
725 for (YangLeafList yangLeafList : listOfLeafList) {
726
727 YtbNodeInfo ytbNodeInfo = getParentYtbInfo();
728 Object parentObj = getParentObjectOfNode(ytbNodeInfo,
729 yangNode);
730
731 //TODO: Let the received object list be generic collection.
732 List<Object> leafListObj;
733 try {
734 leafListObj = (List<Object>) getAttributeOfObject(
735 parentObj, getJavaName(yangLeafList));
736 } catch (NoSuchMethodException e) {
737 throw new YtbException(e);
738 }
739 Set<String> leafListValue = new HashSet<>();
740 /*
741 * If list is present, then adds each object value in set.
742 * Adds this set to the YDT, and traverse to parent.
743 */
744 if (leafListObj != null) {
745 for (Object object : leafListObj) {
746 String objValue = getStringFromDataType(
747 object, yangLeafList.getDataType());
748 leafListValue.add(objValue);
749 }
750 extBuilder.addLeafList(leafListValue, yangLeafList);
751 extBuilder.traverseToParentWithoutValidation();
752 }
753 }
754 }
755 }
756 }
757
758 /**
759 * Returns the schema node of notification from the root node. Gets the
760 * enum value from event object and gives it to the root schema node for
761 * getting back the notification schema node.
762 *
763 * @return YANG schema node of notification
764 */
765 private YangSchemaNode getSchemaNodeOfNotification() {
766 Class parentClass = rootObj.getClass().getSuperclass();
767 Object eventObjType = getAttributeFromInheritance(
768 parentClass, rootObj, STR_TYPE);
769 String opTypeValue = String.valueOf(eventObjType);
770
771 if (opTypeValue.equals(STR_NULL) || opTypeValue.isEmpty()) {
772 throw new YtbException(
773 "There is no notification present for the event. Invalid " +
774 "input for notification.");
775 }
776 try {
777 return rootSchema.getNotificationSchemaNode(opTypeValue);
778 } catch (DataModelException e) {
779 throw new YtbException(e);
780 }
781 }
782
783 /**
784 * Returns the object of the notification by retrieving the attributes
785 * from the event class object.
786 *
787 * @return notification YANG object
788 */
789 private Object getObjOfNotification() {
790 Class parentClass = rootObj.getClass().getSuperclass();
791 Object eventSubjectObj = getAttributeFromInheritance(
792 parentClass, rootObj, STR_SUBJECT);
793 String notificationName = rootSchema.getJavaAttributeName();
794 try {
795 return getAttributeOfObject(eventSubjectObj, notificationName);
796 } catch (NoSuchMethodException e) {
797 throw new YtbException(e);
798 }
799 }
800
801 /**
802 * Returns case object from the map that is bound to the parent node
803 * info. For any case node, only when the key and value is matched the
804 * object of the case is provided. If a match is not found, null is
805 * returned.
806 *
807 * @param parentNodeInfo parent YTB node info
808 * @param caseNode case schema node
809 * @return object of the case node
810 */
811 private Object getCaseObjectFromChoice(YtbNodeInfo parentNodeInfo,
812 YangSchemaNode caseNode) {
813 String javaName = getCapitalCase(
814 caseNode.getJavaClassNameOrBuiltInType());
815 String choiceName = ((YangNode) caseNode).getParent().getName();
816 Map<String, Object> mapObj = parentNodeInfo.getChoiceCaseMap();
817 Object caseObj = mapObj.get(choiceName);
818 Class<?> interfaceClass = getInterfaceClassFromImplClass(caseObj);
819 return interfaceClass.getSimpleName().equals(javaName) ? caseObj : null;
820 }
821
822 /**
823 * Adds leaf to YDT when value is present. For primitive types, in order
824 * to avoid default values, the value select is set or not is checked and
825 * then added.
826 *
827 * @param yangLeaf YANG leaf node
828 * @param parentObj leaf holder object
829 * @param leafType object of leaf type
830 */
831 private void addLeafWithValue(YangLeaf yangLeaf, Object parentObj,
832 Object leafType) {
833 String fieldValue = null;
834 if (isTypePrimitive(yangLeaf.getDataType())) {
835 fieldValue = getLeafValueFromValueSetFlag(parentObj, yangLeaf,
836 leafType);
837 /*
838 * Checks the object is present or not, when type is
839 * non-primitive. And adds the value from the respective data type.
840 */
841 } else if (leafType != null) {
842 fieldValue = getStringFromDataType(leafType,
843 yangLeaf.getDataType());
844 }
845 if (isNonEmpty(fieldValue)) {
846 extBuilder.addLeaf(fieldValue, yangLeaf);
847 extBuilder.traverseToParentWithoutValidation();
848 }
849 }
850
851 /**
852 * Adds leaf without value, when the select leaf bit is set.
853 *
854 * @param yangLeaf YANG leaf node
855 * @param parentObj leaf holder object
856 */
857 private void addLeafWithoutValue(YangLeaf yangLeaf, Object parentObj) {
858 String selectLeaf = isValueOrSelectLeafSet(
859 parentObj, getJavaName(yangLeaf), IS_SELECT_LEAF_SET_METHOD);
860 if (selectLeaf.equals(TRUE)) {
861 extBuilder.addLeaf(null, yangLeaf);
862 extBuilder.traverseToParentWithoutValidation();
863 }
864 }
865
866 /**
867 * Returns the value of type, after checking, the value leaf flag. If the
868 * flag is set, then it takes the value or returns null.
869 *
870 * @param parentObj parent object
871 * @param yangLeaf YANG leaf node
872 * @param leafType object of leaf type
873 * @return value of type
874 */
875 private String getLeafValueFromValueSetFlag(
876 Object parentObj, YangLeaf yangLeaf, Object leafType) {
877 String valueOfLeaf = isValueOrSelectLeafSet(
878 parentObj, getJavaName(yangLeaf), IS_LEAF_VALUE_SET_METHOD);
879 if (valueOfLeaf.equals(TRUE)) {
880 return getStringFromDataType(leafType, yangLeaf.getDataType());
881 }
882 return null;
883 }
884
885 /**
886 * Returns the node info which can be processed, by eliminating the nodes
887 * which need not to be processed at normal conditions such as RPC,
888 * notification and augment.
889 *
890 * @param curNode current node
891 * @return info of node which needs processing
892 */
893 private YtbTraversalInfo getProcessableInfo(YangNode curNode) {
894 if (curNode.getNextSibling() != null) {
895 YangNode sibling = curNode.getNextSibling();
896 while (isNonProcessableNode(sibling)) {
897 sibling = sibling.getNextSibling();
898 }
899 if (sibling != null) {
900 return new YtbTraversalInfo(sibling, SIBLING);
901 }
902 }
903 return new YtbTraversalInfo(curNode.getParent(), PARENT);
904 }
905
906}