blob: 96d3950458b8fc703f179031a0fb5ae13464fab3 [file] [log] [blame]
janani b05614f12016-10-04 12:55:43 +05301/*
Brian O'Connora09fe5b2017-08-03 21:12:30 -07002 * Copyright 2016-present Open Networking Foundation
janani b05614f12016-10-04 12:55:43 +05303 *
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);
Vidyashree Rama9f34bad2016-12-08 18:07:08 +0530348 curNode = getParentSchemaNode(curNode);
janani b05614f12016-10-04 12:55:43 +0530349 }
350 }
351 }
352
353 /**
Vidyashree Rama9f34bad2016-12-08 18:07:08 +0530354 * Returns parent schema node of current node.
355 *
356 * @param curNode current schema node
357 * @return parent schema node
358 */
359 private YangNode getParentSchemaNode(YangNode curNode) {
360 if (curNode instanceof YangAugment) {
361 /*
362 * If curNode is augment, either next augment or augmented node
363 * has to be processed. So traversal type is changed to parent,
364 * but node is not changed.
365 */
366 return curNode;
367 }
368 return curNode.getParent();
369 }
370
371 /**
janani b05614f12016-10-04 12:55:43 +0530372 * Processes root YANG node and adds it as a child to the YDT
373 * extended builder which is created earlier.
374 */
375 private void processApplicationRootNode() {
376
377 YtbNodeInfo nodeInfo = new YtbNodeInfo();
378 YangNode rootYang = (YangNode) rootSchema;
379 addChildNodeInYdt(rootObj, rootYang, nodeInfo);
380 // If root node has leaf or leaf-list those will be processed.
381 processLeaves(rootYang);
382 processLeavesList(rootYang);
383 }
384
385 /**
386 * Traverses to parent, based on the schema node that requires to be
387 * traversed. Skips traversal of parent for choice and case node, as they
388 * don't get added to the YDT tree.
389 *
390 * @param curNode current YANG node
391 */
392 private void traverseToParent(YangNode curNode) {
Vidyashree Rama9f34bad2016-12-08 18:07:08 +0530393 if (curNode instanceof YangCase || curNode instanceof YangChoice
394 || curNode instanceof YangAugment) {
janani b05614f12016-10-04 12:55:43 +0530395 return;
396 }
397 extBuilder.traverseToParentWithoutValidation();
398 }
399
400 /**
401 * Returns the current YTB info of the YDT builder, and then traverses back
402 * to parent. In case of multi instance node the previous node info is
403 * used for iterating through the list.
404 *
405 * @return current YTB app info
406 */
407 private YtbNodeInfo getCurNodeInfoAndTraverseBack() {
408 YtbNodeInfo appInfo = getParentYtbInfo();
409 extBuilder.traverseToParentWithoutValidation();
410 return appInfo;
411 }
412
413 /**
414 * Returns augment node for an augmented node. From the list of augment
415 * nodes it has, one of the nodes is taken and provided linearly. If the
416 * node is not augmented or the all the augment nodes are processed, then
417 * it returns null.
418 *
419 * @param curNode current YANG node
420 * @param augmentNodeInfo previous augment node info
421 * @return YANG augment node
422 */
423 private YangNode getAugmentInsideSchemaNode(YangNode curNode,
424 YtbNodeInfo augmentNodeInfo) {
425 if (augmentNodeInfo == null) {
426 List<YangAugment> augmentList = ((YangAugmentableNode) curNode)
427 .getAugmentedInfoList();
janani b9069eb42016-11-24 17:50:08 +0530428 if (nonEmpty(augmentList)) {
janani b05614f12016-10-04 12:55:43 +0530429 YtbNodeInfo parentNodeInfo = getParentYtbInfo();
430 Iterator<YangAugment> augmentItr = augmentList.listIterator();
431 parentNodeInfo.setAugmentIterator(augmentItr);
432 return augmentItr.next();
433 }
434 } else if (augmentNodeInfo.getAugmentIterator() != null) {
435 if (augmentNodeInfo.getAugmentIterator().hasNext()) {
436 return augmentNodeInfo.getAugmentIterator().next();
437 }
438 }
439 return null;
440 }
441
442 /**
443 * Processes the current YANG node and if necessary adds it to the YDT
444 * builder tree by extracting the information from the corresponding
445 * class object.
446 *
447 * @param curNode current YANG node
448 * @param listNodeInfo previous node info for list
449 * @return object of the schema node
450 */
451 private Object processCurSchemaNodeAndAddToYdt(YangNode curNode,
452 YtbNodeInfo listNodeInfo) {
453 YtbNodeInfo curNodeInfo = new YtbNodeInfo();
454 Object nodeObj = null;
455 YtbNodeInfo parentNodeInfo = getParentYtbInfo();
456
457 switch (curNode.getYangSchemaNodeType()) {
458 case YANG_SINGLE_INSTANCE_NODE:
459 nodeObj = processSingleInstanceNode(curNode, curNodeInfo,
460 parentNodeInfo);
461 break;
462 case YANG_MULTI_INSTANCE_NODE:
463 nodeObj = processMultiInstanceNode(
464 curNode, curNodeInfo, listNodeInfo, parentNodeInfo);
465 break;
466 case YANG_CHOICE_NODE:
467 nodeObj = processChoiceNode(curNode, parentNodeInfo);
468 break;
469 case YANG_NON_DATA_NODE:
470 if (curNode instanceof YangCase) {
471 nodeObj = processCaseNode(curNode, parentNodeInfo);
472 }
473 break;
474 case YANG_AUGMENT_NODE:
475 nodeObj = processAugmentNode(curNode, parentNodeInfo);
476 break;
477 default:
478 throw new YtbException(
479 "Non processable schema node has arrived for adding " +
480 "it in YDT tree");
481 }
482 // Processes leaf/leaf-list only when object has value, else it skips.
483 if (nodeObj != null) {
484 processLeaves(curNode);
485 processLeavesList(curNode);
486 }
487 return nodeObj;
488 }
489
490 /**
491 * Processes single instance node which is added to the YDT tree.
492 *
493 * @param curNode current YANG node
494 * @param curNodeInfo current YDT node info
495 * @param parentNodeInfo parent YDT node info
496 * @return object of the current node
497 */
498 private Object processSingleInstanceNode(YangNode curNode,
499 YtbNodeInfo curNodeInfo,
500 YtbNodeInfo parentNodeInfo) {
501 Object childObj = getChildObject(curNode, parentNodeInfo);
502 if (childObj != null) {
503 addChildNodeInYdt(childObj, curNode, curNodeInfo);
504 }
505 return childObj;
506 }
507
508 /**
509 * Processes multi instance node which has to be added to the YDT tree.
510 * For the first instance in the list, iterator is created and added to
511 * the list. For second instance or more the iterator from first instance
512 * is taken and iterated through to get the object of parent.
513 *
514 * @param curNode current list node
515 * @param curNodeInfo current node info for list
516 * @param listNodeInfo previous instance node info of list
517 * @param parentNodeInfo parent node info of list
518 * @return object of the current instance
519 */
520 private Object processMultiInstanceNode(YangNode curNode,
521 YtbNodeInfo curNodeInfo,
522 YtbNodeInfo listNodeInfo,
523 YtbNodeInfo parentNodeInfo) {
524 Object childObj = null;
525 /*
526 * When YANG list comes to this flow for first time, its YTB node
527 * will be null. When it comes for the second or more content, then
528 * the list would have been already set for that node. According to
529 * set or not set this flow will be proceeded.
530 */
531 if (listNodeInfo == null) {
532 List<Object> childObjList = (List<Object>) getChildObject(
533 curNode, parentNodeInfo);
janani b9069eb42016-11-24 17:50:08 +0530534 if (nonEmpty(childObjList)) {
janani b05614f12016-10-04 12:55:43 +0530535 Iterator<Object> listItr = childObjList.iterator();
536 if (!listItr.hasNext()) {
537 return null;
538 //TODO: Handle the subtree filtering with no list entries.
539 }
540 childObj = listItr.next();
541 /*
542 * For that node the iterator is set. So the next time for
543 * the list this iterator will be taken.
544 */
545 curNodeInfo.setListIterator(listItr);
546 }
547 } else {
548 /*
549 * If the list value comes for second or more time, that list
550 * node will be having YTB node info, where iterator can be
551 * retrieved and check if any more contents are present. If
552 * present those will be processed.
553 */
554 curNodeInfo.setListIterator(listNodeInfo.getListIterator());
555 if (listNodeInfo.getListIterator().hasNext()) {
556 childObj = listNodeInfo.getListIterator().next();
557 }
558 }
559 if (childObj != null) {
560 addChildNodeInYdt(childObj, curNode, curNodeInfo);
561 }
562 return childObj;
563 }
564
565 /**
566 * Processes choice node which adds a map to the parent node info of
567 * choice name and the case object. The object taken for choice node is
568 * of case object with choice name. Also, this Skips the addition of choice
569 * to YDT.
570 *
571 * @param curNode current choice node
572 * @param parentNodeInfo parent YTB node info
573 * @return object of the choice node
574 */
575 private Object processChoiceNode(YangNode curNode,
576 YtbNodeInfo parentNodeInfo) {
577 /*
578 * Retrieves the parent YTB info, to take the object of parent, so as
579 * to check the child attribute from the object.
580 */
581 Object childObj = getChildObject(curNode, parentNodeInfo);
582 if (childObj != null) {
583 Map<String, Object> choiceCaseMap = parentNodeInfo
584 .getChoiceCaseMap();
585 if (choiceCaseMap == null) {
586 choiceCaseMap = new HashMap<>();
587 parentNodeInfo.setChoiceCaseMap(choiceCaseMap);
588 }
589 choiceCaseMap.put(curNode.getName(), childObj);
590 }
591 return childObj;
592 }
593
594 /**
595 * Processes case node from the map contents that is filled by choice
596 * nodes. Object of choice is taken when choice name and case class name
597 * matches. When the case node is not present in the map it returns null.
598 *
599 * @param curNode current case node
600 * @param parentNodeInfo choice parent node info
601 * @return object of the case node
602 */
603 private Object processCaseNode(YangNode curNode,
604 YtbNodeInfo parentNodeInfo) {
605 Object childObj = null;
606 if (parentNodeInfo.getChoiceCaseMap() != null) {
607 childObj = getCaseObjectFromChoice(parentNodeInfo,
608 curNode);
609 }
610 if (childObj != null) {
611 /*
612 * Sets the case object in parent info, so that rest of the case
613 * children can use it as parent. Case is not added in YDT.
614 */
615 parentNodeInfo.setCaseObject(childObj);
616 }
617 return childObj;
618 }
619
620 /**
621 * Processes augment node, which is not added in the YDT, but binds
622 * itself to the parent YTB info, so rest of its child nodes can use for
623 * adding themselves to the YDT tree. If there is no augment node added
624 * in map or if the augment module is not registered, then it returns null.
625 *
626 * @param curNode current augment node
627 * @param parentNodeInfo augment parent node info
628 * @return object of the augment node
629 */
630 private Object processAugmentNode(YangNode curNode,
631 YtbNodeInfo parentNodeInfo) {
632 String className = curNode.getJavaClassNameOrBuiltInType();
633 String pkgName = curNode.getJavaPackage();
634 Object parentObj = getParentObjectOfNode(parentNodeInfo,
635 curNode.getParent());
636 Map augmentMap;
637 try {
638 augmentMap = (Map) getAttributeOfObject(parentObj,
639 YANG_AUGMENTED_INFO_MAP);
640 /*
641 * Gets the registered module class. Loads the class and gets the
642 * augment class.
643 */
644 Class moduleClass = getClassLoaderForAugment(curNode, registry);
645 if (moduleClass == null) {
646 return null;
647 }
648 Class augmentClass = moduleClass.getClassLoader().loadClass(
649 pkgName + PERIOD + className);
650 Object childObj = augmentMap.get(augmentClass);
651 parentNodeInfo.setAugmentObject(childObj);
652 return childObj;
653 } catch (ClassNotFoundException | NoSuchMethodException e) {
654 throw new YtbException(e);
655 }
656 }
657
658 /**
659 * Returns the YTB info from the parent node, so that its own bounded
660 * object can be taken out.
661 *
662 * @return parent node YTB node info
663 */
664 private YtbNodeInfo getParentYtbInfo() {
janani b9069eb42016-11-24 17:50:08 +0530665 YdtExtendedContext parentExtContext = extBuilder.getCurNode();
janani b05614f12016-10-04 12:55:43 +0530666 return (YtbNodeInfo) parentExtContext.getAppInfo(YTB);
667 }
668
669 /**
670 * Returns the child object from the parent object. Uses java name of the
671 * current node to search the attribute in the parent object.
672 *
673 * @param curNode current YANG node
674 * @param parentNodeInfo parent YTB node info
675 * @return object of the child node
676 */
677 private Object getChildObject(YangNode curNode,
678 YtbNodeInfo parentNodeInfo) {
679 String nodeJavaName = curNode.getJavaAttributeName();
680 Object parentObj = getParentObjectOfNode(parentNodeInfo,
681 curNode.getParent());
682 try {
683 return getAttributeOfObject(parentObj, nodeJavaName);
684 } catch (NoSuchMethodException e) {
685 throw new YtbException(e);
686 }
687 }
688
689 /**
690 * Adds the child node to the YDT by taking operation type from the
691 * object. Also, binds the object to the YDT node through YTB node info.
692 *
693 * @param childObj node object
694 * @param curNode current YANG node
695 * @param curNodeInfo current YTB info
696 */
697 private void addChildNodeInYdt(Object childObj, YangNode curNode,
698 YtbNodeInfo curNodeInfo) {
janani b9069eb42016-11-24 17:50:08 +0530699 YdtContextOperationType opType =
700 getNodeOpType(childObj, getOpTypeName(curNode));
janani b05614f12016-10-04 12:55:43 +0530701 extBuilder.addChild(opType, curNode);
janani b9069eb42016-11-24 17:50:08 +0530702 YdtExtendedContext curExtContext = extBuilder.getCurNode();
janani b05614f12016-10-04 12:55:43 +0530703 curNodeInfo.setYangObject(childObj);
704 curExtContext.addAppInfo(YTB, curNodeInfo);
705 }
706
707 /**
708 * Processes every leaf in a YANG node. Iterates through the leaf, takes
709 * value from the leaf and adds it to the YDT with value. If value is not
710 * present, and select leaf is set, adds it to the YDT without value.
711 *
712 * @param yangNode leaves holder node
713 */
714 private void processLeaves(YangNode yangNode) {
715 if (yangNode instanceof YangLeavesHolder) {
716 List<YangLeaf> leavesList = ((YangLeavesHolder) yangNode)
717 .getListOfLeaf();
718 if (leavesList != null) {
719 for (YangLeaf yangLeaf : leavesList) {
720 YtbNodeInfo parentYtbInfo = getParentYtbInfo();
721 Object parentObj = getParentObjectOfNode(parentYtbInfo,
722 yangNode);
723 Object leafType;
724 try {
725 leafType = getAttributeOfObject(parentObj,
726 getJavaName(yangLeaf));
727 } catch (NoSuchMethodException e) {
728 throw new YtbException(e);
729 }
730
janani b9069eb42016-11-24 17:50:08 +0530731 addLeafWithValue(yangNode, yangLeaf, parentObj, leafType);
732 addLeafWithoutValue(yangNode, yangLeaf, parentObj);
janani b05614f12016-10-04 12:55:43 +0530733 }
734 }
735 }
736 }
737
738 /**
janani b9069eb42016-11-24 17:50:08 +0530739 * Processes every leaf-list in a YANG node for adding the value in YDT.
janani b05614f12016-10-04 12:55:43 +0530740 *
741 * @param yangNode list of leaf-list holder node
742 */
743 private void processLeavesList(YangNode yangNode) {
744 if (yangNode instanceof YangLeavesHolder) {
745 List<YangLeafList> listOfLeafList =
746 ((YangLeavesHolder) yangNode).getListOfLeafList();
747
748 if (listOfLeafList != null) {
749 for (YangLeafList yangLeafList : listOfLeafList) {
janani b9069eb42016-11-24 17:50:08 +0530750 addToBuilder(yangNode, yangLeafList);
janani b05614f12016-10-04 12:55:43 +0530751 }
752 }
753 }
754 }
755
756 /**
janani b9069eb42016-11-24 17:50:08 +0530757 * Processes the list of objects of the leaf list and adds the leaf list
758 * value to the builder.
759 *
760 * @param yangNode YANG node
761 * @param leafList YANG leaf list
762 */
763 private void addToBuilder(YangNode yangNode, YangLeafList leafList) {
764 YtbNodeInfo ytbNodeInfo = getParentYtbInfo();
765 Object parentObj = getParentObjectOfNode(ytbNodeInfo, yangNode);
766 List<Object> obj;
767 try {
768 obj = (List<Object>) getAttributeOfObject(parentObj,
769 getJavaName(leafList));
770 } catch (NoSuchMethodException e) {
771 throw new YtbException(e);
772 }
773 if (obj != null) {
774 addLeafListValue(yangNode, parentObj, leafList, obj);
775 }
776 }
777
778 /**
779 * Adds the leaf list value to the YDT builder by taking the string value
780 * from the data type.
781 *
782 * @param yangNode YANG node
783 * @param parentObj parent object
784 * @param leafList YANG leaf list
785 * @param obj list of objects
786 */
787 private void addLeafListValue(YangNode yangNode, Object parentObj,
788 YangLeafList leafList, List<Object> obj) {
789
790 Set<String> leafListVal = new LinkedHashSet<>();
791 boolean isEmpty = false;
792 for (Object object : obj) {
793 String val = getStringFromType(yangNode, parentObj,
794 getJavaName(leafList), object,
795 leafList.getDataType());
796 isEmpty = isTypeEmpty(val, leafList.getDataType());
797 if (isEmpty) {
798 if (val.equals(TRUE)) {
799 addLeafList(leafListVal, leafList);
800 }
801 break;
802 }
Jon Halla3fcf672017-03-28 16:53:22 -0700803 if (!"".equals(val)) {
janani b9069eb42016-11-24 17:50:08 +0530804 leafListVal.add(val);
805 }
806 }
807 if (!isEmpty && !leafListVal.isEmpty()) {
808 addLeafList(leafListVal, leafList);
809 }
810 }
811
812 /**
813 * Adds set of leaf list values in the builder and traverses back to the
814 * holder.
815 *
816 * @param leafListVal set of values
817 * @param leafList YANG leaf list
818 */
819 private void addLeafList(Set<String> leafListVal, YangLeafList leafList) {
820 extBuilder.addLeafList(leafListVal, leafList);
821 extBuilder.traverseToParentWithoutValidation();
822 }
823
824 /**
janani b05614f12016-10-04 12:55:43 +0530825 * Returns the schema node of notification from the root node. Gets the
826 * enum value from event object and gives it to the root schema node for
827 * getting back the notification schema node.
828 *
829 * @return YANG schema node of notification
830 */
831 private YangSchemaNode getSchemaNodeOfNotification() {
janani b9069eb42016-11-24 17:50:08 +0530832
833 Object eventObjType = getAttributeFromInheritance(rootObj, STR_TYPE);
janani b05614f12016-10-04 12:55:43 +0530834 String opTypeValue = String.valueOf(eventObjType);
835
836 if (opTypeValue.equals(STR_NULL) || opTypeValue.isEmpty()) {
837 throw new YtbException(
838 "There is no notification present for the event. Invalid " +
839 "input for notification.");
840 }
841 try {
842 return rootSchema.getNotificationSchemaNode(opTypeValue);
843 } catch (DataModelException e) {
844 throw new YtbException(e);
845 }
846 }
847
848 /**
849 * Returns the object of the notification by retrieving the attributes
850 * from the event class object.
851 *
852 * @return notification YANG object
853 */
854 private Object getObjOfNotification() {
janani b9069eb42016-11-24 17:50:08 +0530855
856 Object eventSubjectObj =
857 getAttributeFromInheritance(rootObj, STR_SUBJECT);
janani b05614f12016-10-04 12:55:43 +0530858 String notificationName = rootSchema.getJavaAttributeName();
859 try {
860 return getAttributeOfObject(eventSubjectObj, notificationName);
861 } catch (NoSuchMethodException e) {
862 throw new YtbException(e);
863 }
864 }
865
866 /**
867 * Returns case object from the map that is bound to the parent node
868 * info. For any case node, only when the key and value is matched the
869 * object of the case is provided. If a match is not found, null is
870 * returned.
871 *
872 * @param parentNodeInfo parent YTB node info
873 * @param caseNode case schema node
874 * @return object of the case node
875 */
876 private Object getCaseObjectFromChoice(YtbNodeInfo parentNodeInfo,
877 YangSchemaNode caseNode) {
878 String javaName = getCapitalCase(
879 caseNode.getJavaClassNameOrBuiltInType());
880 String choiceName = ((YangNode) caseNode).getParent().getName();
881 Map<String, Object> mapObj = parentNodeInfo.getChoiceCaseMap();
882 Object caseObj = mapObj.get(choiceName);
883 Class<?> interfaceClass = getInterfaceClassFromImplClass(caseObj);
884 return interfaceClass.getSimpleName().equals(javaName) ? caseObj : null;
885 }
886
887 /**
888 * Adds leaf to YDT when value is present. For primitive types, in order
889 * to avoid default values, the value select is set or not is checked and
890 * then added.
891 *
janani b9069eb42016-11-24 17:50:08 +0530892 * @param holder leaf holder
janani b05614f12016-10-04 12:55:43 +0530893 * @param yangLeaf YANG leaf node
894 * @param parentObj leaf holder object
895 * @param leafType object of leaf type
896 */
janani b9069eb42016-11-24 17:50:08 +0530897 private void addLeafWithValue(YangSchemaNode holder, YangLeaf yangLeaf,
898 Object parentObj, Object leafType) {
janani b05614f12016-10-04 12:55:43 +0530899 String fieldValue = null;
900 if (isTypePrimitive(yangLeaf.getDataType())) {
janani b9069eb42016-11-24 17:50:08 +0530901 fieldValue = getLeafValueFromValueSetFlag(holder, parentObj,
902 yangLeaf, leafType);
janani b05614f12016-10-04 12:55:43 +0530903 /*
904 * Checks the object is present or not, when type is
905 * non-primitive. And adds the value from the respective data type.
906 */
907 } else if (leafType != null) {
janani b9069eb42016-11-24 17:50:08 +0530908 fieldValue = getStringFromType(holder, parentObj,
909 getJavaName(yangLeaf), leafType,
910 yangLeaf.getDataType());
janani b05614f12016-10-04 12:55:43 +0530911 }
janani b9069eb42016-11-24 17:50:08 +0530912
913 if (nonEmpty(fieldValue)) {
914 boolean isEmpty = isTypeEmpty(fieldValue,
915 yangLeaf.getDataType());
916 if (isEmpty) {
917 if (!fieldValue.equals(TRUE)) {
918 return;
919 }
920 fieldValue = null;
921 }
janani b05614f12016-10-04 12:55:43 +0530922 extBuilder.addLeaf(fieldValue, yangLeaf);
923 extBuilder.traverseToParentWithoutValidation();
924 }
925 }
926
927 /**
janani b9069eb42016-11-24 17:50:08 +0530928 * Returns the value as true if direct or referred type from leafref or
929 * derived points to empty data type; false otherwise.
930 *
931 * @param fieldValue value of the leaf
932 * @param dataType type of the leaf
933 * @return true if type is empty; false otherwise.
934 */
935 private boolean isTypeEmpty(String fieldValue, YangType<?> dataType) {
936 if (fieldValue.equals(TRUE) || fieldValue.equals(FALSE)) {
937 switch (dataType.getDataType()) {
938 case EMPTY:
939 return true;
940
941 case LEAFREF:
942 YangLeafRef leafRef =
943 (YangLeafRef) dataType.getDataTypeExtendedInfo();
944 return isTypeEmpty(fieldValue,
945 leafRef.getEffectiveDataType());
946 case DERIVED:
947 YangDerivedInfo info =
948 (YangDerivedInfo) dataType
949 .getDataTypeExtendedInfo();
950 YangDataTypes type = info.getEffectiveBuiltInType();
951 return type == EMPTY;
952
953 default:
954 return false;
955 }
956 }
957 return false;
958 }
959
960 /**
janani b05614f12016-10-04 12:55:43 +0530961 * Adds leaf without value, when the select leaf bit is set.
962 *
janani b9069eb42016-11-24 17:50:08 +0530963 * @param holder leaf holder
janani b05614f12016-10-04 12:55:43 +0530964 * @param yangLeaf YANG leaf node
965 * @param parentObj leaf holder object
966 */
janani b9069eb42016-11-24 17:50:08 +0530967 private void addLeafWithoutValue(YangSchemaNode holder, YangLeaf yangLeaf,
968 Object parentObj) {
969
970 String selectLeaf;
971 try {
972 selectLeaf = isValueOrSelectLeafSet(holder, parentObj,
973 getJavaName(yangLeaf),
974 IS_SELECT_LEAF_SET_METHOD);
975 } catch (NoSuchMethodException e) {
976 selectLeaf = FALSE;
977 }
janani b05614f12016-10-04 12:55:43 +0530978 if (selectLeaf.equals(TRUE)) {
979 extBuilder.addLeaf(null, yangLeaf);
980 extBuilder.traverseToParentWithoutValidation();
981 }
982 }
983
984 /**
janani b9069eb42016-11-24 17:50:08 +0530985 * Returns the value of type, after checking the value leaf flag. If the
986 * flag is set, then it takes the value else returns null.
janani b05614f12016-10-04 12:55:43 +0530987 *
janani b9069eb42016-11-24 17:50:08 +0530988 * @param holder leaf holder
janani b05614f12016-10-04 12:55:43 +0530989 * @param parentObj parent object
990 * @param yangLeaf YANG leaf node
991 * @param leafType object of leaf type
992 * @return value of type
993 */
janani b9069eb42016-11-24 17:50:08 +0530994 private String getLeafValueFromValueSetFlag(YangSchemaNode holder, Object parentObj,
995 YangLeaf yangLeaf, Object leafType) {
996
997 String valueOfLeaf;
998 try {
999 valueOfLeaf = isValueOrSelectLeafSet(holder, parentObj,
1000 getJavaName(yangLeaf),
1001 IS_LEAF_VALUE_SET_METHOD);
1002 } catch (NoSuchMethodException e) {
1003 throw new YtbException(e);
1004 }
janani b05614f12016-10-04 12:55:43 +05301005 if (valueOfLeaf.equals(TRUE)) {
janani b9069eb42016-11-24 17:50:08 +05301006 return getStringFromType(holder, parentObj,
1007 getJavaName(yangLeaf), leafType,
1008 yangLeaf.getDataType());
janani b05614f12016-10-04 12:55:43 +05301009 }
1010 return null;
1011 }
1012
1013 /**
1014 * Returns the node info which can be processed, by eliminating the nodes
1015 * which need not to be processed at normal conditions such as RPC,
1016 * notification and augment.
1017 *
1018 * @param curNode current node
1019 * @return info of node which needs processing
1020 */
1021 private YtbTraversalInfo getProcessableInfo(YangNode curNode) {
1022 if (curNode.getNextSibling() != null) {
1023 YangNode sibling = curNode.getNextSibling();
1024 while (isNonProcessableNode(sibling)) {
1025 sibling = sibling.getNextSibling();
1026 }
1027 if (sibling != null) {
1028 return new YtbTraversalInfo(sibling, SIBLING);
1029 }
1030 }
1031 return new YtbTraversalInfo(curNode.getParent(), PARENT);
1032 }
1033
1034}