blob: 10874f071bc45a81dcbf6dec393c2e763be7b34e [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;
janani b9069eb42016-11-24 17:50:08 +053023import org.onosproject.yangutils.datamodel.YangDerivedInfo;
janani b05614f12016-10-04 12:55:43 +053024import org.onosproject.yangutils.datamodel.YangLeaf;
25import org.onosproject.yangutils.datamodel.YangLeafList;
janani b9069eb42016-11-24 17:50:08 +053026import org.onosproject.yangutils.datamodel.YangLeafRef;
janani b05614f12016-10-04 12:55:43 +053027import org.onosproject.yangutils.datamodel.YangLeavesHolder;
28import org.onosproject.yangutils.datamodel.YangNode;
29import org.onosproject.yangutils.datamodel.YangSchemaNode;
30import org.onosproject.yangutils.datamodel.YangSchemaNodeIdentifier;
janani b9069eb42016-11-24 17:50:08 +053031import org.onosproject.yangutils.datamodel.YangType;
janani b05614f12016-10-04 12:55:43 +053032import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
janani b9069eb42016-11-24 17:50:08 +053033import org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes;
janani b05614f12016-10-04 12:55:43 +053034import org.onosproject.yms.app.utils.TraversalType;
35import org.onosproject.yms.app.ydt.YdtExtendedBuilder;
36import org.onosproject.yms.app.ydt.YdtExtendedContext;
37import org.onosproject.yms.app.ysr.YangSchemaRegistry;
38import org.onosproject.yms.ydt.YdtContextOperationType;
39
40import java.util.HashMap;
janani b05614f12016-10-04 12:55:43 +053041import java.util.Iterator;
janani b9069eb42016-11-24 17:50:08 +053042import java.util.LinkedHashSet;
janani b05614f12016-10-04 12:55:43 +053043import java.util.List;
44import java.util.Map;
45import java.util.Set;
46
janani b9069eb42016-11-24 17:50:08 +053047import static org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes.EMPTY;
48import static org.onosproject.yangutils.utils.io.impl.YangIoUtils.getCapitalCase;
janani b05614f12016-10-04 12:55:43 +053049import static org.onosproject.yms.app.utils.TraversalType.CHILD;
50import static org.onosproject.yms.app.utils.TraversalType.PARENT;
51import static org.onosproject.yms.app.utils.TraversalType.ROOT;
52import static org.onosproject.yms.app.utils.TraversalType.SIBLING;
53import static org.onosproject.yms.app.ydt.AppType.YTB;
54import static org.onosproject.yms.app.ytb.YtbUtil.PERIOD;
55import static org.onosproject.yms.app.ytb.YtbUtil.STR_NULL;
56import static org.onosproject.yms.app.ytb.YtbUtil.getAttributeFromInheritance;
57import static org.onosproject.yms.app.ytb.YtbUtil.getAttributeOfObject;
janani b05614f12016-10-04 12:55:43 +053058import static org.onosproject.yms.app.ytb.YtbUtil.getClassLoaderForAugment;
59import static org.onosproject.yms.app.ytb.YtbUtil.getInterfaceClassFromImplClass;
60import static org.onosproject.yms.app.ytb.YtbUtil.getJavaName;
janani b9069eb42016-11-24 17:50:08 +053061import static org.onosproject.yms.app.ytb.YtbUtil.getNodeOpType;
62import static org.onosproject.yms.app.ytb.YtbUtil.getOpTypeName;
janani b05614f12016-10-04 12:55:43 +053063import static org.onosproject.yms.app.ytb.YtbUtil.getParentObjectOfNode;
janani b9069eb42016-11-24 17:50:08 +053064import static org.onosproject.yms.app.ytb.YtbUtil.getStringFromType;
janani b05614f12016-10-04 12:55:43 +053065import static org.onosproject.yms.app.ytb.YtbUtil.isAugmentNode;
66import static org.onosproject.yms.app.ytb.YtbUtil.isMultiInstanceNode;
67import static org.onosproject.yms.app.ytb.YtbUtil.isNodeProcessCompleted;
janani b05614f12016-10-04 12:55:43 +053068import static org.onosproject.yms.app.ytb.YtbUtil.isNonProcessableNode;
69import static org.onosproject.yms.app.ytb.YtbUtil.isTypePrimitive;
70import static org.onosproject.yms.app.ytb.YtbUtil.isValueOrSelectLeafSet;
janani b9069eb42016-11-24 17:50:08 +053071import static org.onosproject.yms.app.ytb.YtbUtil.nonEmpty;
janani b05614f12016-10-04 12:55:43 +053072import static org.onosproject.yms.ydt.YdtContextOperationType.NONE;
73
74/**
75 * Implements traversal of YANG node and its corresponding object, resulting
76 * in building of the YDT tree.
77 */
78public class YdtBuilderFromYo {
79
80 private static final String STR_TYPE = "type";
81 private static final String STR_SUBJECT = "subject";
82 private static final String TRUE = "true";
83 private static final String IS_LEAF_VALUE_SET_METHOD = "isLeafValueSet";
84 private static final String IS_SELECT_LEAF_SET_METHOD = "isSelectLeaf";
85 private static final String OUTPUT = "output";
86 private static final String YANG_AUGMENTED_INFO_MAP =
87 "yangAugmentedInfoMap";
janani b9069eb42016-11-24 17:50:08 +053088 private static final String FALSE = "false";
janani b05614f12016-10-04 12:55:43 +053089
90 /**
91 * Application YANG schema registry.
92 */
93 private final YangSchemaRegistry registry;
94
95 /**
96 * Current instance of the YDT builder where the tree is built.
97 */
98 private final YdtExtendedBuilder extBuilder;
99
100 /**
101 * YANG root object that is required for walking along with the YANG node.
102 */
103 private Object rootObj;
104
105 /**
106 * YANG root node that is required for walking along with the YANG object.
107 */
108 private YangSchemaNode rootSchema;
109
110 /**
111 * Creates YDT builder from YANG object by assigning the mandatory values.
112 *
113 * @param rootBuilder root node builder
114 * @param rootObj root node object
115 * @param registry application schema registry
116 */
117 public YdtBuilderFromYo(YdtExtendedBuilder rootBuilder, Object rootObj,
118 YangSchemaRegistry registry) {
119 extBuilder = rootBuilder;
120 this.rootObj = rootObj;
121 this.registry = registry;
122 }
123
124 /**
125 * Returns schema root node, received from YSR, which searches based on
126 * the object received from YAB or YCH.
127 *
128 * @param object root node object
129 */
130 public void getModuleNodeFromYsr(Object object) {
131 Class interfaceClass = getInterfaceClassFromImplClass(object);
132 rootSchema = registry
133 .getYangSchemaNodeUsingGeneratedRootNodeInterfaceFileName(
134 interfaceClass.getName());
135 }
136
137 /**
138 * Returns schema root node, received from YSR, which searches based on
139 * the object received from YNH.
140 *
141 * @param object notification event object
142 */
143 public void getRootNodeWithNotificationFromYsr(Object object) {
144 rootSchema = registry.getRootYangSchemaNodeForNotification(
145 object.getClass().getName());
146 }
147
148 /**
149 * Creates the module node for in YDT before beginning with notification
150 * root node traversal. Collects sufficient information to fill YDT with
151 * notification root node in the traversal.
152 */
153 public void createModuleInYdt() {
154 extBuilder.addChild(NONE, rootSchema);
155 rootSchema = getSchemaNodeOfNotification();
156 rootObj = getObjOfNotification();
157 }
158
159 /**
160 * Creates the module and RPC node, in YDT tree, from the logical root
161 * node received from request workbench. The output schema node is taken
162 * from the child schema of RPC YANG node.
163 *
164 * @param rootNode logical root node
165 */
166 public void createModuleAndRpcInYdt(YdtExtendedContext rootNode) {
167
168 YdtExtendedContext moduleNode =
169 (YdtExtendedContext) rootNode.getFirstChild();
170 extBuilder.addChild(NONE, moduleNode.getYangSchemaNode());
171
172 YdtExtendedContext rpcNode =
173 (YdtExtendedContext) moduleNode.getFirstChild();
174 YangSchemaNode rpcSchemaNode = rpcNode.getYangSchemaNode();
175 extBuilder.addChild(NONE, rpcSchemaNode);
176
177 // Defines a schema identifier for output node.
178 YangSchemaNodeIdentifier schemaId = new YangSchemaNodeIdentifier();
179 schemaId.setName(OUTPUT);
180 schemaId.setNameSpace(rpcSchemaNode.getNameSpace());
181 try {
182 // Gets the output schema node from RPC child schema.
183 rootSchema = rpcSchemaNode.getChildSchema(schemaId).getSchemaNode();
184 } catch (DataModelException e) {
185 throw new YtbException(e);
186 }
187 }
188
189 /**
190 * Creates YDT tree from the root object, by traversing through YANG data
191 * model node, and simultaneously checking the object nodes presence and
192 * walking the object.
193 */
194 public void createYdtFromRootObject() {
195 YangNode curNode = (YangNode) rootSchema;
196 TraversalType curTraversal = ROOT;
197 YtbNodeInfo listNodeInfo = null;
198 YtbNodeInfo augmentNodeInfo = null;
199
200 while (curNode != null) {
201 /*
202 * Processes the node, if it is being visited for the first time in
203 * the schema, also if the schema node is being retraced in a multi
204 * instance node.
205 */
206 if (curTraversal != PARENT || isMultiInstanceNode(curNode)) {
207
208 if (curTraversal == PARENT && isMultiInstanceNode(curNode)) {
209 /*
210 * If the schema is being retraced for a multi-instance
211 * node, it has already entered for this multi-instance
212 * node. Now this re-processes the same schema node for
213 * any additional list object.
214 */
215 listNodeInfo = getCurNodeInfoAndTraverseBack();
216 }
217
218 if (curTraversal == ROOT && !isAugmentNode(curNode)) {
219 /*
220 * In case of RPC output, the root node is augmentative,
221 * so when the root traversal is coming for augment this
222 * flow is skipped. This adds only the root node in the YDT.
223 */
224 processApplicationRootNode();
225 } else {
226 /*
227 * Gets the object corresponding to current schema node.
228 * If object exists, this adds the corresponding YDT node
229 * to the tree and returns the object. Else returns null.
230 */
231 Object processedObject = processCurSchemaNodeAndAddToYdt(
232 curNode, listNodeInfo);
233 /*
234 * Clears the list info of processed node. The next time
235 * list info is taken newly and accordingly.
236 */
237 listNodeInfo = null;
238 if (processedObject == null && !isAugmentNode(curNode)) {
239 /*
240 * Checks the presence of next sibling of the node, by
241 * breaking the complete chain of the current node,
242 * when the object value is not present, or when the
243 * list entries are completely retraced. The augment
244 * may have sibling, so this doesn't process for
245 * augment.
246 */
247 YtbTraversalInfo traverseInfo =
248 getProcessableInfo(curNode);
249 curNode = traverseInfo.getYangNode();
250 curTraversal = traverseInfo.getTraverseType();
251 continue;
252 /*
253 * Irrespective of root or parent, sets the traversal
254 * type as parent, when augment node doesn't have any
255 * value. So, the other sibling augments can be
256 * processed, if present.
257 */
258 } else if (processedObject == null &&
259 isAugmentNode(curNode)) {
260 curTraversal = PARENT;
261 /*
262 * The second content in the list will be having
263 * parent traversal, in such case it cannot go to its
264 * child in the flow, so it is made as child
265 * traversal and proceeded to continue.
266 */
267 } else if (curTraversal == PARENT &&
268 isMultiInstanceNode(curNode)) {
269 curTraversal = CHILD;
270 }
271 }
272 }
273 /*
274 * Checks for the sibling augment when the first augment node is
275 * getting completed. From the current augment node the previous
276 * node info is taken for augment and the traversal is changed to
277 * child, so as to check for the presence of sibling augment.
278 */
279 if (curTraversal == PARENT && isAugmentNode(curNode)) {
280 curNode = ((YangAugment) curNode).getAugmentedNode();
281 augmentNodeInfo = getParentYtbInfo();
282 curTraversal = CHILD;
283 }
284 /*
285 * Creates an augment iterator for the first time or takes the
286 * previous augment iterator for more than one time, whenever an
287 * augmentative node arrives. If augment is present it goes back
288 * for processing. If its null, the augmentative nodes process is
289 * continued.
290 */
291 if (curTraversal != PARENT &&
292 curNode instanceof YangAugmentableNode) {
293 YangNode augmentNode = getAugmentInsideSchemaNode(
294 curNode, augmentNodeInfo);
295 if (augmentNode != null) {
296 curNode = augmentNode;
297 continue;
298 }
299 }
300 /*
301 * Processes the child, after processing the node. If complete
302 * child depth is over, it takes up sibling and processes it.
303 * Once child and sibling is over, it is traversed back to the
304 * parent, without processing. In multi instance case, before
305 * going to parent or schema sibling, its own list sibling is
306 * processed. Skips the processing of RPC,notification and
307 * augment, as these nodes are dealt in a different flow.
308 */
309 if (curTraversal != PARENT && curNode.getChild() != null) {
310 augmentNodeInfo = null;
311 listNodeInfo = null;
312 curTraversal = CHILD;
313 curNode = curNode.getChild();
314 if (isNonProcessableNode(curNode)) {
315 YtbTraversalInfo traverseInfo = getProcessableInfo(curNode);
316 curNode = traverseInfo.getYangNode();
317 curTraversal = traverseInfo.getTraverseType();
318 }
319 } else if (curNode.getNextSibling() != null) {
320 if (isNodeProcessCompleted(curNode, curTraversal)) {
321 break;
322 }
323 if (isMultiInstanceNode(curNode)) {
324 listNodeInfo = getCurNodeInfoAndTraverseBack();
325 augmentNodeInfo = null;
326 continue;
327 }
328 curTraversal = SIBLING;
janani b9069eb42016-11-24 17:50:08 +0530329 augmentNodeInfo = null;
janani b05614f12016-10-04 12:55:43 +0530330 traverseToParent(curNode);
331 curNode = curNode.getNextSibling();
332 if (isNonProcessableNode(curNode)) {
333 YtbTraversalInfo traverseInfo = getProcessableInfo(curNode);
334 curNode = traverseInfo.getYangNode();
335 curTraversal = traverseInfo.getTraverseType();
336 }
337 } else {
338 if (isNodeProcessCompleted(curNode, curTraversal)) {
339 break;
340 }
341 if (isMultiInstanceNode(curNode)) {
342 listNodeInfo = getCurNodeInfoAndTraverseBack();
343 augmentNodeInfo = null;
344 continue;
345 }
346 curTraversal = PARENT;
347 traverseToParent(curNode);
348 curNode = curNode.getParent();
349 }
350 }
351 }
352
353 /**
354 * Processes root YANG node and adds it as a child to the YDT
355 * extended builder which is created earlier.
356 */
357 private void processApplicationRootNode() {
358
359 YtbNodeInfo nodeInfo = new YtbNodeInfo();
360 YangNode rootYang = (YangNode) rootSchema;
361 addChildNodeInYdt(rootObj, rootYang, nodeInfo);
362 // If root node has leaf or leaf-list those will be processed.
363 processLeaves(rootYang);
364 processLeavesList(rootYang);
365 }
366
367 /**
368 * Traverses to parent, based on the schema node that requires to be
369 * traversed. Skips traversal of parent for choice and case node, as they
370 * don't get added to the YDT tree.
371 *
372 * @param curNode current YANG node
373 */
374 private void traverseToParent(YangNode curNode) {
375 if (curNode instanceof YangCase || curNode instanceof YangChoice) {
376 return;
377 }
378 extBuilder.traverseToParentWithoutValidation();
379 }
380
381 /**
382 * Returns the current YTB info of the YDT builder, and then traverses back
383 * to parent. In case of multi instance node the previous node info is
384 * used for iterating through the list.
385 *
386 * @return current YTB app info
387 */
388 private YtbNodeInfo getCurNodeInfoAndTraverseBack() {
389 YtbNodeInfo appInfo = getParentYtbInfo();
390 extBuilder.traverseToParentWithoutValidation();
391 return appInfo;
392 }
393
394 /**
395 * Returns augment node for an augmented node. From the list of augment
396 * nodes it has, one of the nodes is taken and provided linearly. If the
397 * node is not augmented or the all the augment nodes are processed, then
398 * it returns null.
399 *
400 * @param curNode current YANG node
401 * @param augmentNodeInfo previous augment node info
402 * @return YANG augment node
403 */
404 private YangNode getAugmentInsideSchemaNode(YangNode curNode,
405 YtbNodeInfo augmentNodeInfo) {
406 if (augmentNodeInfo == null) {
407 List<YangAugment> augmentList = ((YangAugmentableNode) curNode)
408 .getAugmentedInfoList();
janani b9069eb42016-11-24 17:50:08 +0530409 if (nonEmpty(augmentList)) {
janani b05614f12016-10-04 12:55:43 +0530410 YtbNodeInfo parentNodeInfo = getParentYtbInfo();
411 Iterator<YangAugment> augmentItr = augmentList.listIterator();
412 parentNodeInfo.setAugmentIterator(augmentItr);
413 return augmentItr.next();
414 }
415 } else if (augmentNodeInfo.getAugmentIterator() != null) {
416 if (augmentNodeInfo.getAugmentIterator().hasNext()) {
417 return augmentNodeInfo.getAugmentIterator().next();
418 }
419 }
420 return null;
421 }
422
423 /**
424 * Processes the current YANG node and if necessary adds it to the YDT
425 * builder tree by extracting the information from the corresponding
426 * class object.
427 *
428 * @param curNode current YANG node
429 * @param listNodeInfo previous node info for list
430 * @return object of the schema node
431 */
432 private Object processCurSchemaNodeAndAddToYdt(YangNode curNode,
433 YtbNodeInfo listNodeInfo) {
434 YtbNodeInfo curNodeInfo = new YtbNodeInfo();
435 Object nodeObj = null;
436 YtbNodeInfo parentNodeInfo = getParentYtbInfo();
437
438 switch (curNode.getYangSchemaNodeType()) {
439 case YANG_SINGLE_INSTANCE_NODE:
440 nodeObj = processSingleInstanceNode(curNode, curNodeInfo,
441 parentNodeInfo);
442 break;
443 case YANG_MULTI_INSTANCE_NODE:
444 nodeObj = processMultiInstanceNode(
445 curNode, curNodeInfo, listNodeInfo, parentNodeInfo);
446 break;
447 case YANG_CHOICE_NODE:
448 nodeObj = processChoiceNode(curNode, parentNodeInfo);
449 break;
450 case YANG_NON_DATA_NODE:
451 if (curNode instanceof YangCase) {
452 nodeObj = processCaseNode(curNode, parentNodeInfo);
453 }
454 break;
455 case YANG_AUGMENT_NODE:
456 nodeObj = processAugmentNode(curNode, parentNodeInfo);
457 break;
458 default:
459 throw new YtbException(
460 "Non processable schema node has arrived for adding " +
461 "it in YDT tree");
462 }
463 // Processes leaf/leaf-list only when object has value, else it skips.
464 if (nodeObj != null) {
465 processLeaves(curNode);
466 processLeavesList(curNode);
467 }
468 return nodeObj;
469 }
470
471 /**
472 * Processes single instance node which is added to the YDT tree.
473 *
474 * @param curNode current YANG node
475 * @param curNodeInfo current YDT node info
476 * @param parentNodeInfo parent YDT node info
477 * @return object of the current node
478 */
479 private Object processSingleInstanceNode(YangNode curNode,
480 YtbNodeInfo curNodeInfo,
481 YtbNodeInfo parentNodeInfo) {
482 Object childObj = getChildObject(curNode, parentNodeInfo);
483 if (childObj != null) {
484 addChildNodeInYdt(childObj, curNode, curNodeInfo);
485 }
486 return childObj;
487 }
488
489 /**
490 * Processes multi instance node which has to be added to the YDT tree.
491 * For the first instance in the list, iterator is created and added to
492 * the list. For second instance or more the iterator from first instance
493 * is taken and iterated through to get the object of parent.
494 *
495 * @param curNode current list node
496 * @param curNodeInfo current node info for list
497 * @param listNodeInfo previous instance node info of list
498 * @param parentNodeInfo parent node info of list
499 * @return object of the current instance
500 */
501 private Object processMultiInstanceNode(YangNode curNode,
502 YtbNodeInfo curNodeInfo,
503 YtbNodeInfo listNodeInfo,
504 YtbNodeInfo parentNodeInfo) {
505 Object childObj = null;
506 /*
507 * When YANG list comes to this flow for first time, its YTB node
508 * will be null. When it comes for the second or more content, then
509 * the list would have been already set for that node. According to
510 * set or not set this flow will be proceeded.
511 */
512 if (listNodeInfo == null) {
513 List<Object> childObjList = (List<Object>) getChildObject(
514 curNode, parentNodeInfo);
janani b9069eb42016-11-24 17:50:08 +0530515 if (nonEmpty(childObjList)) {
janani b05614f12016-10-04 12:55:43 +0530516 Iterator<Object> listItr = childObjList.iterator();
517 if (!listItr.hasNext()) {
518 return null;
519 //TODO: Handle the subtree filtering with no list entries.
520 }
521 childObj = listItr.next();
522 /*
523 * For that node the iterator is set. So the next time for
524 * the list this iterator will be taken.
525 */
526 curNodeInfo.setListIterator(listItr);
527 }
528 } else {
529 /*
530 * If the list value comes for second or more time, that list
531 * node will be having YTB node info, where iterator can be
532 * retrieved and check if any more contents are present. If
533 * present those will be processed.
534 */
535 curNodeInfo.setListIterator(listNodeInfo.getListIterator());
536 if (listNodeInfo.getListIterator().hasNext()) {
537 childObj = listNodeInfo.getListIterator().next();
538 }
539 }
540 if (childObj != null) {
541 addChildNodeInYdt(childObj, curNode, curNodeInfo);
542 }
543 return childObj;
544 }
545
546 /**
547 * Processes choice node which adds a map to the parent node info of
548 * choice name and the case object. The object taken for choice node is
549 * of case object with choice name. Also, this Skips the addition of choice
550 * to YDT.
551 *
552 * @param curNode current choice node
553 * @param parentNodeInfo parent YTB node info
554 * @return object of the choice node
555 */
556 private Object processChoiceNode(YangNode curNode,
557 YtbNodeInfo parentNodeInfo) {
558 /*
559 * Retrieves the parent YTB info, to take the object of parent, so as
560 * to check the child attribute from the object.
561 */
562 Object childObj = getChildObject(curNode, parentNodeInfo);
563 if (childObj != null) {
564 Map<String, Object> choiceCaseMap = parentNodeInfo
565 .getChoiceCaseMap();
566 if (choiceCaseMap == null) {
567 choiceCaseMap = new HashMap<>();
568 parentNodeInfo.setChoiceCaseMap(choiceCaseMap);
569 }
570 choiceCaseMap.put(curNode.getName(), childObj);
571 }
572 return childObj;
573 }
574
575 /**
576 * Processes case node from the map contents that is filled by choice
577 * nodes. Object of choice is taken when choice name and case class name
578 * matches. When the case node is not present in the map it returns null.
579 *
580 * @param curNode current case node
581 * @param parentNodeInfo choice parent node info
582 * @return object of the case node
583 */
584 private Object processCaseNode(YangNode curNode,
585 YtbNodeInfo parentNodeInfo) {
586 Object childObj = null;
587 if (parentNodeInfo.getChoiceCaseMap() != null) {
588 childObj = getCaseObjectFromChoice(parentNodeInfo,
589 curNode);
590 }
591 if (childObj != null) {
592 /*
593 * Sets the case object in parent info, so that rest of the case
594 * children can use it as parent. Case is not added in YDT.
595 */
596 parentNodeInfo.setCaseObject(childObj);
597 }
598 return childObj;
599 }
600
601 /**
602 * Processes augment node, which is not added in the YDT, but binds
603 * itself to the parent YTB info, so rest of its child nodes can use for
604 * adding themselves to the YDT tree. If there is no augment node added
605 * in map or if the augment module is not registered, then it returns null.
606 *
607 * @param curNode current augment node
608 * @param parentNodeInfo augment parent node info
609 * @return object of the augment node
610 */
611 private Object processAugmentNode(YangNode curNode,
612 YtbNodeInfo parentNodeInfo) {
613 String className = curNode.getJavaClassNameOrBuiltInType();
614 String pkgName = curNode.getJavaPackage();
615 Object parentObj = getParentObjectOfNode(parentNodeInfo,
616 curNode.getParent());
617 Map augmentMap;
618 try {
619 augmentMap = (Map) getAttributeOfObject(parentObj,
620 YANG_AUGMENTED_INFO_MAP);
621 /*
622 * Gets the registered module class. Loads the class and gets the
623 * augment class.
624 */
625 Class moduleClass = getClassLoaderForAugment(curNode, registry);
626 if (moduleClass == null) {
627 return null;
628 }
629 Class augmentClass = moduleClass.getClassLoader().loadClass(
630 pkgName + PERIOD + className);
631 Object childObj = augmentMap.get(augmentClass);
632 parentNodeInfo.setAugmentObject(childObj);
633 return childObj;
634 } catch (ClassNotFoundException | NoSuchMethodException e) {
635 throw new YtbException(e);
636 }
637 }
638
639 /**
640 * Returns the YTB info from the parent node, so that its own bounded
641 * object can be taken out.
642 *
643 * @return parent node YTB node info
644 */
645 private YtbNodeInfo getParentYtbInfo() {
janani b9069eb42016-11-24 17:50:08 +0530646 YdtExtendedContext parentExtContext = extBuilder.getCurNode();
janani b05614f12016-10-04 12:55:43 +0530647 return (YtbNodeInfo) parentExtContext.getAppInfo(YTB);
648 }
649
650 /**
651 * Returns the child object from the parent object. Uses java name of the
652 * current node to search the attribute in the parent object.
653 *
654 * @param curNode current YANG node
655 * @param parentNodeInfo parent YTB node info
656 * @return object of the child node
657 */
658 private Object getChildObject(YangNode curNode,
659 YtbNodeInfo parentNodeInfo) {
660 String nodeJavaName = curNode.getJavaAttributeName();
661 Object parentObj = getParentObjectOfNode(parentNodeInfo,
662 curNode.getParent());
663 try {
664 return getAttributeOfObject(parentObj, nodeJavaName);
665 } catch (NoSuchMethodException e) {
666 throw new YtbException(e);
667 }
668 }
669
670 /**
671 * Adds the child node to the YDT by taking operation type from the
672 * object. Also, binds the object to the YDT node through YTB node info.
673 *
674 * @param childObj node object
675 * @param curNode current YANG node
676 * @param curNodeInfo current YTB info
677 */
678 private void addChildNodeInYdt(Object childObj, YangNode curNode,
679 YtbNodeInfo curNodeInfo) {
janani b9069eb42016-11-24 17:50:08 +0530680 YdtContextOperationType opType =
681 getNodeOpType(childObj, getOpTypeName(curNode));
janani b05614f12016-10-04 12:55:43 +0530682 extBuilder.addChild(opType, curNode);
janani b9069eb42016-11-24 17:50:08 +0530683 YdtExtendedContext curExtContext = extBuilder.getCurNode();
janani b05614f12016-10-04 12:55:43 +0530684 curNodeInfo.setYangObject(childObj);
685 curExtContext.addAppInfo(YTB, curNodeInfo);
686 }
687
688 /**
689 * Processes every leaf in a YANG node. Iterates through the leaf, takes
690 * value from the leaf and adds it to the YDT with value. If value is not
691 * present, and select leaf is set, adds it to the YDT without value.
692 *
693 * @param yangNode leaves holder node
694 */
695 private void processLeaves(YangNode yangNode) {
696 if (yangNode instanceof YangLeavesHolder) {
697 List<YangLeaf> leavesList = ((YangLeavesHolder) yangNode)
698 .getListOfLeaf();
699 if (leavesList != null) {
700 for (YangLeaf yangLeaf : leavesList) {
701 YtbNodeInfo parentYtbInfo = getParentYtbInfo();
702 Object parentObj = getParentObjectOfNode(parentYtbInfo,
703 yangNode);
704 Object leafType;
705 try {
706 leafType = getAttributeOfObject(parentObj,
707 getJavaName(yangLeaf));
708 } catch (NoSuchMethodException e) {
709 throw new YtbException(e);
710 }
711
janani b9069eb42016-11-24 17:50:08 +0530712 addLeafWithValue(yangNode, yangLeaf, parentObj, leafType);
713 addLeafWithoutValue(yangNode, yangLeaf, parentObj);
janani b05614f12016-10-04 12:55:43 +0530714 }
715 }
716 }
717 }
718
719 /**
janani b9069eb42016-11-24 17:50:08 +0530720 * Processes every leaf-list in a YANG node for adding the value in YDT.
janani b05614f12016-10-04 12:55:43 +0530721 *
722 * @param yangNode list of leaf-list holder node
723 */
724 private void processLeavesList(YangNode yangNode) {
725 if (yangNode instanceof YangLeavesHolder) {
726 List<YangLeafList> listOfLeafList =
727 ((YangLeavesHolder) yangNode).getListOfLeafList();
728
729 if (listOfLeafList != null) {
730 for (YangLeafList yangLeafList : listOfLeafList) {
janani b9069eb42016-11-24 17:50:08 +0530731 addToBuilder(yangNode, yangLeafList);
janani b05614f12016-10-04 12:55:43 +0530732 }
733 }
734 }
735 }
736
737 /**
janani b9069eb42016-11-24 17:50:08 +0530738 * Processes the list of objects of the leaf list and adds the leaf list
739 * value to the builder.
740 *
741 * @param yangNode YANG node
742 * @param leafList YANG leaf list
743 */
744 private void addToBuilder(YangNode yangNode, YangLeafList leafList) {
745 YtbNodeInfo ytbNodeInfo = getParentYtbInfo();
746 Object parentObj = getParentObjectOfNode(ytbNodeInfo, yangNode);
747 List<Object> obj;
748 try {
749 obj = (List<Object>) getAttributeOfObject(parentObj,
750 getJavaName(leafList));
751 } catch (NoSuchMethodException e) {
752 throw new YtbException(e);
753 }
754 if (obj != null) {
755 addLeafListValue(yangNode, parentObj, leafList, obj);
756 }
757 }
758
759 /**
760 * Adds the leaf list value to the YDT builder by taking the string value
761 * from the data type.
762 *
763 * @param yangNode YANG node
764 * @param parentObj parent object
765 * @param leafList YANG leaf list
766 * @param obj list of objects
767 */
768 private void addLeafListValue(YangNode yangNode, Object parentObj,
769 YangLeafList leafList, List<Object> obj) {
770
771 Set<String> leafListVal = new LinkedHashSet<>();
772 boolean isEmpty = false;
773 for (Object object : obj) {
774 String val = getStringFromType(yangNode, parentObj,
775 getJavaName(leafList), object,
776 leafList.getDataType());
777 isEmpty = isTypeEmpty(val, leafList.getDataType());
778 if (isEmpty) {
779 if (val.equals(TRUE)) {
780 addLeafList(leafListVal, leafList);
781 }
782 break;
783 }
784 if (!val.equals("")) {
785 leafListVal.add(val);
786 }
787 }
788 if (!isEmpty && !leafListVal.isEmpty()) {
789 addLeafList(leafListVal, leafList);
790 }
791 }
792
793 /**
794 * Adds set of leaf list values in the builder and traverses back to the
795 * holder.
796 *
797 * @param leafListVal set of values
798 * @param leafList YANG leaf list
799 */
800 private void addLeafList(Set<String> leafListVal, YangLeafList leafList) {
801 extBuilder.addLeafList(leafListVal, leafList);
802 extBuilder.traverseToParentWithoutValidation();
803 }
804
805 /**
janani b05614f12016-10-04 12:55:43 +0530806 * Returns the schema node of notification from the root node. Gets the
807 * enum value from event object and gives it to the root schema node for
808 * getting back the notification schema node.
809 *
810 * @return YANG schema node of notification
811 */
812 private YangSchemaNode getSchemaNodeOfNotification() {
janani b9069eb42016-11-24 17:50:08 +0530813
814 Object eventObjType = getAttributeFromInheritance(rootObj, STR_TYPE);
janani b05614f12016-10-04 12:55:43 +0530815 String opTypeValue = String.valueOf(eventObjType);
816
817 if (opTypeValue.equals(STR_NULL) || opTypeValue.isEmpty()) {
818 throw new YtbException(
819 "There is no notification present for the event. Invalid " +
820 "input for notification.");
821 }
822 try {
823 return rootSchema.getNotificationSchemaNode(opTypeValue);
824 } catch (DataModelException e) {
825 throw new YtbException(e);
826 }
827 }
828
829 /**
830 * Returns the object of the notification by retrieving the attributes
831 * from the event class object.
832 *
833 * @return notification YANG object
834 */
835 private Object getObjOfNotification() {
janani b9069eb42016-11-24 17:50:08 +0530836
837 Object eventSubjectObj =
838 getAttributeFromInheritance(rootObj, STR_SUBJECT);
janani b05614f12016-10-04 12:55:43 +0530839 String notificationName = rootSchema.getJavaAttributeName();
840 try {
841 return getAttributeOfObject(eventSubjectObj, notificationName);
842 } catch (NoSuchMethodException e) {
843 throw new YtbException(e);
844 }
845 }
846
847 /**
848 * Returns case object from the map that is bound to the parent node
849 * info. For any case node, only when the key and value is matched the
850 * object of the case is provided. If a match is not found, null is
851 * returned.
852 *
853 * @param parentNodeInfo parent YTB node info
854 * @param caseNode case schema node
855 * @return object of the case node
856 */
857 private Object getCaseObjectFromChoice(YtbNodeInfo parentNodeInfo,
858 YangSchemaNode caseNode) {
859 String javaName = getCapitalCase(
860 caseNode.getJavaClassNameOrBuiltInType());
861 String choiceName = ((YangNode) caseNode).getParent().getName();
862 Map<String, Object> mapObj = parentNodeInfo.getChoiceCaseMap();
863 Object caseObj = mapObj.get(choiceName);
864 Class<?> interfaceClass = getInterfaceClassFromImplClass(caseObj);
865 return interfaceClass.getSimpleName().equals(javaName) ? caseObj : null;
866 }
867
868 /**
869 * Adds leaf to YDT when value is present. For primitive types, in order
870 * to avoid default values, the value select is set or not is checked and
871 * then added.
872 *
janani b9069eb42016-11-24 17:50:08 +0530873 * @param holder leaf holder
janani b05614f12016-10-04 12:55:43 +0530874 * @param yangLeaf YANG leaf node
875 * @param parentObj leaf holder object
876 * @param leafType object of leaf type
877 */
janani b9069eb42016-11-24 17:50:08 +0530878 private void addLeafWithValue(YangSchemaNode holder, YangLeaf yangLeaf,
879 Object parentObj, Object leafType) {
janani b05614f12016-10-04 12:55:43 +0530880 String fieldValue = null;
881 if (isTypePrimitive(yangLeaf.getDataType())) {
janani b9069eb42016-11-24 17:50:08 +0530882 fieldValue = getLeafValueFromValueSetFlag(holder, parentObj,
883 yangLeaf, leafType);
janani b05614f12016-10-04 12:55:43 +0530884 /*
885 * Checks the object is present or not, when type is
886 * non-primitive. And adds the value from the respective data type.
887 */
888 } else if (leafType != null) {
janani b9069eb42016-11-24 17:50:08 +0530889 fieldValue = getStringFromType(holder, parentObj,
890 getJavaName(yangLeaf), leafType,
891 yangLeaf.getDataType());
janani b05614f12016-10-04 12:55:43 +0530892 }
janani b9069eb42016-11-24 17:50:08 +0530893
894 if (nonEmpty(fieldValue)) {
895 boolean isEmpty = isTypeEmpty(fieldValue,
896 yangLeaf.getDataType());
897 if (isEmpty) {
898 if (!fieldValue.equals(TRUE)) {
899 return;
900 }
901 fieldValue = null;
902 }
janani b05614f12016-10-04 12:55:43 +0530903 extBuilder.addLeaf(fieldValue, yangLeaf);
904 extBuilder.traverseToParentWithoutValidation();
905 }
906 }
907
908 /**
janani b9069eb42016-11-24 17:50:08 +0530909 * Returns the value as true if direct or referred type from leafref or
910 * derived points to empty data type; false otherwise.
911 *
912 * @param fieldValue value of the leaf
913 * @param dataType type of the leaf
914 * @return true if type is empty; false otherwise.
915 */
916 private boolean isTypeEmpty(String fieldValue, YangType<?> dataType) {
917 if (fieldValue.equals(TRUE) || fieldValue.equals(FALSE)) {
918 switch (dataType.getDataType()) {
919 case EMPTY:
920 return true;
921
922 case LEAFREF:
923 YangLeafRef leafRef =
924 (YangLeafRef) dataType.getDataTypeExtendedInfo();
925 return isTypeEmpty(fieldValue,
926 leafRef.getEffectiveDataType());
927 case DERIVED:
928 YangDerivedInfo info =
929 (YangDerivedInfo) dataType
930 .getDataTypeExtendedInfo();
931 YangDataTypes type = info.getEffectiveBuiltInType();
932 return type == EMPTY;
933
934 default:
935 return false;
936 }
937 }
938 return false;
939 }
940
941 /**
janani b05614f12016-10-04 12:55:43 +0530942 * Adds leaf without value, when the select leaf bit is set.
943 *
janani b9069eb42016-11-24 17:50:08 +0530944 * @param holder leaf holder
janani b05614f12016-10-04 12:55:43 +0530945 * @param yangLeaf YANG leaf node
946 * @param parentObj leaf holder object
947 */
janani b9069eb42016-11-24 17:50:08 +0530948 private void addLeafWithoutValue(YangSchemaNode holder, YangLeaf yangLeaf,
949 Object parentObj) {
950
951 String selectLeaf;
952 try {
953 selectLeaf = isValueOrSelectLeafSet(holder, parentObj,
954 getJavaName(yangLeaf),
955 IS_SELECT_LEAF_SET_METHOD);
956 } catch (NoSuchMethodException e) {
957 selectLeaf = FALSE;
958 }
janani b05614f12016-10-04 12:55:43 +0530959 if (selectLeaf.equals(TRUE)) {
960 extBuilder.addLeaf(null, yangLeaf);
961 extBuilder.traverseToParentWithoutValidation();
962 }
963 }
964
965 /**
janani b9069eb42016-11-24 17:50:08 +0530966 * Returns the value of type, after checking the value leaf flag. If the
967 * flag is set, then it takes the value else returns null.
janani b05614f12016-10-04 12:55:43 +0530968 *
janani b9069eb42016-11-24 17:50:08 +0530969 * @param holder leaf holder
janani b05614f12016-10-04 12:55:43 +0530970 * @param parentObj parent object
971 * @param yangLeaf YANG leaf node
972 * @param leafType object of leaf type
973 * @return value of type
974 */
janani b9069eb42016-11-24 17:50:08 +0530975 private String getLeafValueFromValueSetFlag(YangSchemaNode holder, Object parentObj,
976 YangLeaf yangLeaf, Object leafType) {
977
978 String valueOfLeaf;
979 try {
980 valueOfLeaf = isValueOrSelectLeafSet(holder, parentObj,
981 getJavaName(yangLeaf),
982 IS_LEAF_VALUE_SET_METHOD);
983 } catch (NoSuchMethodException e) {
984 throw new YtbException(e);
985 }
janani b05614f12016-10-04 12:55:43 +0530986 if (valueOfLeaf.equals(TRUE)) {
janani b9069eb42016-11-24 17:50:08 +0530987 return getStringFromType(holder, parentObj,
988 getJavaName(yangLeaf), leafType,
989 yangLeaf.getDataType());
janani b05614f12016-10-04 12:55:43 +0530990 }
991 return null;
992 }
993
994 /**
995 * Returns the node info which can be processed, by eliminating the nodes
996 * which need not to be processed at normal conditions such as RPC,
997 * notification and augment.
998 *
999 * @param curNode current node
1000 * @return info of node which needs processing
1001 */
1002 private YtbTraversalInfo getProcessableInfo(YangNode curNode) {
1003 if (curNode.getNextSibling() != null) {
1004 YangNode sibling = curNode.getNextSibling();
1005 while (isNonProcessableNode(sibling)) {
1006 sibling = sibling.getNextSibling();
1007 }
1008 if (sibling != null) {
1009 return new YtbTraversalInfo(sibling, SIBLING);
1010 }
1011 }
1012 return new YtbTraversalInfo(curNode.getParent(), PARENT);
1013 }
1014
1015}