blob: 5ae123086f2ecf945441a8a889dddf547d006783 [file] [log] [blame]
sonu gupta1bb37b82016-11-11 16:51:18 +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.ydt;
18
19import com.google.common.collect.ImmutableMap;
20import org.onosproject.yangutils.datamodel.YangList;
21import org.onosproject.yangutils.datamodel.YangSchemaNode;
22import org.onosproject.yangutils.datamodel.YangSchemaNodeContextInfo;
23import org.onosproject.yangutils.datamodel.YangSchemaNodeIdentifier;
24import org.onosproject.yms.app.ysr.YangSchemaRegistry;
25import org.onosproject.yms.ydt.YdtContext;
26import org.onosproject.yms.ydt.YdtContextOperationType;
27import org.onosproject.yms.ydt.YdtType;
28import org.onosproject.yms.ydt.YmsOperationType;
29
30import java.util.Iterator;
31import java.util.List;
32import java.util.Map;
33import java.util.Set;
34
35import static org.onosproject.yangutils.datamodel.YangSchemaNodeType.YANG_MULTI_INSTANCE_LEAF_NODE;
36import static org.onosproject.yms.app.ydt.AppNodeFactory.getAppContext;
37import static org.onosproject.yms.app.ydt.RequestedCallType.LEAF;
38import static org.onosproject.yms.app.ydt.RequestedCallType.OTHER;
39import static org.onosproject.yms.app.ydt.RequestedCardinality.MULTI_INSTANCE;
40import static org.onosproject.yms.app.ydt.RequestedCardinality.MULTI_INSTANCE_LEAF;
41import static org.onosproject.yms.app.ydt.RequestedCardinality.SINGLE_INSTANCE;
42import static org.onosproject.yms.app.ydt.RequestedCardinality.UNKNOWN;
43import static org.onosproject.yms.app.ydt.YdtConstants.errorMsg;
44import static org.onosproject.yms.app.ydt.YdtNodeFactory.getAppOpTypeFromYdtOpType;
45import static org.onosproject.yms.ydt.YdtContextOperationType.CREATE;
46import static org.onosproject.yms.ydt.YdtContextOperationType.DELETE;
47import static org.onosproject.yms.ydt.YdtContextOperationType.MERGE;
48import static org.onosproject.yms.ydt.YdtContextOperationType.REMOVE;
49import static org.onosproject.yms.ydt.YdtType.MULTI_INSTANCE_LEAF_VALUE_NODE;
50import static org.onosproject.yms.ydt.YdtType.MULTI_INSTANCE_NODE;
51
52/**
53 * Represents YANG request work bench which contains all parameters for
54 * request handling and methods to build and obtain YANG data tree
55 * which is data (sub)instance representation, abstract of protocol.
56 */
57public class YangRequestWorkBench implements YdtExtendedBuilder {
58
59 // ydt formatted error string
60 private static final String FMT_NOT_EXIST =
61 "Application with name \"%s\" doesn't exist.";
62 private static final String E_USE_ADDLEAF =
63 "Requested Node should be created using addLeaf interface";
64 private static final String E_MULTI_INS =
65 "Adds an instance of type list or leaf-list node only";
66 private static final String E_CREATE =
67 "Create request is not allowed under delete operation";
68 private static final String E_DEL =
69 "Delete request is not allowed under create operation";
70 private static final String E_INVOKE_PARENT =
71 "Can't invoke get parent at logical root node";
72 private static final String FMT_TOO_FEW =
73 "Too few key parameters in %s. Expected %d; actual %d.";
74 private static final String FMT_TOO_MANY =
75 "Too many key parameters in %s. Expected %d; actual %d.";
76
77 /*
78 * Current node in YANG data tree, kept to maintain the
79 * current context in YDT.
80 */
81 private YdtNode curNode;
82
83 /*
84 * Root node in YANG data tree, kept to maintain the root context in
85 * YDT.
86 */
87 private YdtNode rootNode;
88
89 /*
90 * Current node in YANG data tree, kept to maintain the current context
91 * in ydt application tree.
92 */
93 private YdtAppContext appCurNode;
94
95 /*
96 * Root node in YANG data tree, kept to maintain the root context in ydt
97 * application tree.
98 */
99 private YdtAppContext appRootNode;
100
101 /**
102 * Root Node Tag attribute in YANG data tree, kept to maintain the root
103 * tag attributes in YDT.
104 * <p>
105 * First key param of map represent tagName name of tag attribute.
106 * Second param of map represent tagValue value of tag attribute
107 */
108 private Map<String, String> rootTagAttributeMap;
109
110 /*
111 * YANG schema registry reference.
112 */
113 private YangSchemaRegistry registry = null;
114
115 /*
116 * YMS operation type.
117 */
118 private final YmsOperationType ymsOperationType;
119
120 /*
121 * YDT default operation type.
122 */
123 private YdtContextOperationType ydtDefaultOpType;
124
125 /*
126 * Flag to identify data validation need to be done by YDT or not.
127 */
128 private final boolean validate;
129 // TODO validate need to be handle later with interaction type basis in
130 // future when it will be supported
131
132
133 /**
134 * Creates an instance of YANG request work bench which is use to initialize
135 * logical rootNode and and schema registry.
136 *
137 * @param name name of logical container of a protocol
138 * which is a holder of the complete tree
139 * @param namespace namespace of logical container
140 * @param opType type of operation done by using YANG
141 * interface
142 * @param registry Yang schema registry
143 * @param isValidate Flag to identify data validation need to be
144 * done by YDT or not
145 */
146 public YangRequestWorkBench(String name, String namespace,
147 YmsOperationType opType,
148 YangSchemaRegistry registry,
149 boolean isValidate) {
150 YdtNode newNode;
151 YangSchemaNodeIdentifier nodeIdentifier =
152 new YangSchemaNodeIdentifier();
153 nodeIdentifier.setName(name);
154 nodeIdentifier.setNameSpace(namespace);
155 newNode = new YdtSingleInstanceNode(nodeIdentifier);
156 setRootNode(newNode);
157 this.registry = registry;
158 ymsOperationType = opType;
159 validate = isValidate;
160 // Set the logical root node for yang data app tree.
161 DefaultYdtAppContext appNode = getAppContext(true);
162
163 setAppRootNode(appNode);
164 }
165
166 /**
167 * Sets the logical root context information available in YDT node.
168 *
169 * @param node logical root node
170 */
171 private void setRootNode(YdtNode node) {
172 rootNode = node;
173 curNode = node;
174 }
175
176 /**
177 * Sets the app context tree logical root node for ydt application tree.
178 *
179 * @param node application tree's logical root node
180 */
181 private void setAppRootNode(YdtAppContext node) {
182 appRootNode = node;
183 appCurNode = node;
184 }
185
186 /**
187 * Returns the YANG schema registry of Ydt.
188 * This method will be used by ytb.
189 *
190 * @return YANG schema registry
191 */
192 public YangSchemaRegistry getYangSchemaRegistry() {
193 return registry;
194 }
195
196 /**
197 * Returns the app context tree root node for ydt application tree.
198 * This method will be used by yab.
199 *
200 * @return YdtAppContext refers to root node of ydt application tree
201 */
202 public YdtAppContext getAppRootNode() {
203 return appRootNode;
204 }
205
206 /**
207 * Returns the data tree for given node identifier.
208 *
209 * @param id Represents node identifier of YANG data tree node
210 * @param namespace namespace of the application requested by user
211 * @return YANG data tree node
212 */
213 private YdtNode moduleHandler(YangSchemaNodeIdentifier id,
214 String namespace) {
215
216 YangSchemaNode node = registry
217 .getYangSchemaNodeUsingSchemaName(id.getName());
218
219 if (node == null ||
220 namespace != null && !namespace.equals(node.getNameSpace())) {
221 curNode.errorHandler(errorMsg(
222 FMT_NOT_EXIST, id.getName()), rootNode);
223 }
224
225 YdtNode newNode = new YdtSingleInstanceNode(id);
226 newNode.setYangSchemaNode(node);
227 id.setNameSpace(node.getNameSpace());
228 return newNode;
229 }
230
231 @Override
232 public void setRootTagAttributeMap(Map<String, String> attributeTag) {
233 rootTagAttributeMap = attributeTag;
234 }
235
236 @Override
237 public Map<String, String> getRootTagAttributeMap() {
238 if (rootTagAttributeMap != null) {
239 return ImmutableMap.copyOf(rootTagAttributeMap);
240 }
241 return null;
242 }
243
244 @Override
245 public void addChild(String name, String namespace) {
246 addChild(name, namespace, UNKNOWN, null, OTHER);
247 }
248
249 @Override
250 public void addChild(String name, String namespace, YdtType ydtType) {
251 addChild(name, namespace, ydtType, null);
252 }
253
254 @Override
255 public void addChild(String name, String namespace,
256 YdtContextOperationType opType) {
257 addChild(name, namespace, UNKNOWN, opType, OTHER);
258 }
259
260 @Override
261 public void addChild(String name, String namespace, YdtType ydtType,
262 YdtContextOperationType opType) {
263 RequestedCardinality cardinality = null;
264 switch (ydtType) {
265 case MULTI_INSTANCE_NODE:
266 cardinality = MULTI_INSTANCE;
267 break;
268 case SINGLE_INSTANCE_NODE:
269 cardinality = SINGLE_INSTANCE;
270 break;
271 default:
272 curNode.errorHandler(E_USE_ADDLEAF, rootNode);
273 }
274 addChild(name, namespace, cardinality, opType, OTHER);
275 }
276
277 /**
278 * Adds a last child to YANG data tree; this method is to be used by all
279 * protocols internally which are aware or unaware of the nature
280 * (single/multiple) of node.
281 *
282 * @param name name of child to be added
283 * @param namespace namespace of child to be added
284 * @param cardinality type of YANG data tree node operation
285 * @param opType type of requested operation over a node
286 * @param callType to identify the whether its a leaf or other node
287 */
288 private void addChild(String name, String namespace,
289 RequestedCardinality cardinality,
290 YdtContextOperationType opType,
291 RequestedCallType callType) {
292
293 YdtNode childNode;
294 boolean isContextSwitch = false;
295 YangSchemaNode schemaNode = null;
296 YangSchemaNodeContextInfo contextInfo;
297 YangSchemaNode augmentingSchema = null;
298
299 YangSchemaNodeIdentifier id = new YangSchemaNodeIdentifier();
300 id.setName(name);
301
302 // Module/sub-module node handler.
303 if (curNode.equals(rootNode)) {
304 childNode = moduleHandler(id, namespace);
305 } else {
306
307 // If namespace given by user null, then take namespace from parent.
308 if (namespace == null) {
309 namespace = curNode.getYdtNodeIdentifier().getNameSpace();
310 }
311
312 id.setNameSpace(namespace);
313
314 /*
315 * Get the already exiting YDT node in YDT tree with same
316 * nodeIdentifier
317 */
318 childNode = curNode.getCollidingChild(id);
319
320 /*
321 * If colliding child doesn't exist ,
322 * then query yang data model for schema of given node.
323 */
324 if (childNode == null) {
325 /*
326 * Get Yang Schema node context info which is having
327 * YangSchemaNode and ContextSwitchedNode.
328 */
329 contextInfo = curNode.getSchemaNodeContextInfo(id);
330
331 if (contextInfo.getContextSwitchedNode() != null) {
332 augmentingSchema = appCurNode.getAugmentingSchemaNode(
333 id, contextInfo);
334 if (augmentingSchema != null) {
335 /*
336 * As two tree(YDT and YDT Application Tree) are getting
337 * prepared in parallel, So setting context switch
338 * flag it will help ydt to keep the track whether
339 * ydtApp tree also need to be traversed back to parent
340 * or not with YDT tree traverse to parent call.
341 */
342 isContextSwitch = true;
343 }
344 }
345 schemaNode = contextInfo.getSchemaNode();
346 } else {
347 /*
348 * If colliding child exist , then will be leaf-list or list
349 * If its leaf-list then return and add new requested
350 * value/valueSet in same node else take yang data model
351 * information from colliding child.
352 */
353 if (childNode.getYdtType() == MULTI_INSTANCE_LEAF_VALUE_NODE) {
354 curNode = childNode;
355 return;
356 }
357 schemaNode = childNode.getYangSchemaNode();
358 }
359 childNode = YdtNodeFactory.getNode(id, schemaNode, cardinality,
360 callType);
361 }
362
363 opType = getValidOpType(opType, callType, schemaNode);
364
365 childNode.setYdtContextOperationType(opType);
366
367 curNode.addChild(childNode, true);
368
369 // Update parent ydt node map.
370 curNode.updateYdtMap(id, childNode);
371
372 processAppTree(opType, childNode, augmentingSchema, isContextSwitch);
373
374 // Updating the curNode.
375 curNode = childNode;
376 }
377
378 /**
379 * Processes application tree on the bases of requested ydt node.
380 *
381 * @param opType user requested operation type
382 * @param childNode requested ydt node
383 * @param augmentingSchema schema of last augmenting node
384 * @param isContextSwitch true, for module node call; false for modules
385 * sub-node calls
386 */
387 private void processAppTree(
388 YdtContextOperationType opType, YdtNode childNode,
389 YangSchemaNode augmentingSchema, boolean isContextSwitch) {
390
391 if (augmentingSchema != null) {
392 if (!appCurNode.addSchemaToAppSet(augmentingSchema)) {
393 return;
394 }
395 }
396 if (opType == null) {
397 opType = curNode.getYdtContextOperationType();
398 } else {
399 // Updating operation type for parent nodes
400 appCurNode.updateAppOperationType(opType);
401 }
402
403 /*
404 * Create entry of module node in ydt app tree.
405 * Or if context switch happened then also add entry for same ydt
406 * node in the ydt application tree.
407 */
408 if (curNode.equals(rootNode) || isContextSwitch) {
409 addChildInAppTree(childNode, augmentingSchema, opType,
410 isContextSwitch);
411
412 // Setting app tree node operation.
413 appCurNode.setOperationType(getAppOpTypeFromYdtOpType(opType));
414 }
415
416 // Updating the delete operation list in app tree.
417 if (opType == DELETE || opType == REMOVE) {
418 appCurNode.addDeleteNode(childNode);
419 }
420 }
421
422 /**
423 * Returns the valid operation type for requested ydt node after performing
424 * validation.
425 *
426 * @param opType user requested operation type
427 * @param callType to identify the whether its a leaf or other node
428 * @param schemaNode schema node of user requested ydt node
429 * @return operation type
430 */
431 private YdtContextOperationType getValidOpType(
432 YdtContextOperationType opType, RequestedCallType callType,
433 YangSchemaNode schemaNode) {
434
435 // Operation type not supported for leaf node.
436 if (callType == LEAF || (callType == RequestedCallType.MULTI_INSTANCE &&
437 schemaNode.getYangSchemaNodeType() ==
438 YANG_MULTI_INSTANCE_LEAF_NODE)) {
439 return null;
440 }
441
442 // Reference for parent node operation type.
443 YdtContextOperationType parentOpType = curNode
444 .getYdtContextOperationType();
445
446 if (opType != null && parentOpType != null) {
447 validateOperationType(parentOpType, opType);
448 } else if (opType == null) {
449 opType = getOperationType(parentOpType);
450 }
451 return opType;
452 }
453
454 /**
455 * Returns the operation type for non leaf node.
456 * When "operation" attribute for current node is not specified or null,
457 * then the operation applied to the parent data node of the
458 * configuration is used. If no parent data node is available,
459 * then the default-operation'value is used.
460 * If default operation type is not set, merge will be taken as default
461 * operation type.
462 *
463 * @param parentOpType operation type of parent node
464 * @return operation type for current non leaf node
465 */
466 private YdtContextOperationType getOperationType(
467 YdtContextOperationType parentOpType) {
468
469 return parentOpType != null ? parentOpType :
470 (ydtDefaultOpType != null ? ydtDefaultOpType : MERGE);
471 }
472
473 /**
474 * Adds a last child to YANG app data tree.this method is to be used
475 * internally by other ydt interfaces.
476 *
477 * @param childNode node to be added in tree
478 * @param schemaNode last augmenting module node
479 * @param childOpType operation type of node
480 * @param isContextSwitch true, for module node call; false for modules
481 * sub-node calls
482 */
483 private void addChildInAppTree(YdtNode childNode,
484 YangSchemaNode schemaNode,
485 YdtContextOperationType childOpType,
486 boolean isContextSwitch) {
487
488 YdtAppNodeOperationType opType;
489
490 DefaultYdtAppContext appContext = getAppContext(isContextSwitch);
491
492 // Add context switched child in ydt App tree.
493 appCurNode.addChild(appContext);
494 //Updating the curNode.
495 appCurNode = appContext;
496
497 // Get the app tree operation type from ydt operation type.
498 opType = getAppOpTypeFromYdtOpType(childOpType);
499
500 appCurNode.setAppData(childNode, schemaNode);
501
502 appCurNode.setOperationType(opType);
503
504 childNode.setAppContextSwitch();
505 }
506
507 /**
508 * Validates the various combination of operation type.
509 *
510 * @param parentOpType Reference for parent node operation type
511 * @param childOpType type of YANG data tree node operation
512 */
513 private void validateOperationType(YdtContextOperationType parentOpType,
514 YdtContextOperationType childOpType) {
515
516 switch (parentOpType) {
517 case CREATE:
518 // Inside the create operation delete operation should not come.
519 if (childOpType == DELETE) {
520 curNode.errorHandler(E_CREATE, rootNode);
521 }
522 break;
523 case DELETE:
524 // Inside the delete operation create operation should not come.
525 if (childOpType == CREATE) {
526 curNode.errorHandler(E_DEL, rootNode);
527 }
528 break;
529 default:
530 //TODO check all possible scenario.
531 }
532 }
533
534 @Override
535 public void addLeaf(String name, String namespace, String value) {
536 addLeaf(name, namespace, value, null, UNKNOWN);
537 }
538
539 @Override
540 public void addLeaf(String name, String namespace, Set<String> valueSet) {
541 addLeaf(name, namespace, null, valueSet, MULTI_INSTANCE_LEAF);
542 }
543
544 /**
545 * Adds a last leaf with list of values/single value to YANG data tree.
546 * This method is used by all protocols which knows the nature
547 * (single/multiple) or not.
548 * Value of leaf can be null which indicates selection node in get
549 * operation.
550 *
551 * @param name name of child to be added
552 * @param namespace namespace of child to be added, if it's
553 * null, parent's
554 * namespace will be applied to child
555 * @param value value of the child
556 * @param valueSet list of value of the child
557 * @param cardinality type of YANG data tree node operation
558 */
559 private void addLeaf(String name, String namespace, String value,
560 Set<String> valueSet,
561 RequestedCardinality cardinality) {
562 addChild(name, namespace, cardinality, null, LEAF);
563
564 // After successful addition of child node updating the values in same.
565 if (value != null) {
566 curNode.addValue(value);
567 } else if (valueSet != null) {
568 curNode.addValueSet(valueSet);
569 }
570 }
571
572 @Override
573 public void traverseToParent() {
574 // If traverse back to parent for logical root node comes
575 if (curNode.equals(rootNode)) {
576 curNode.errorHandler(E_INVOKE_PARENT, rootNode);
577 }
578
579 // If node is of multiInstanceNode type then check key uniqueness.
580 if (curNode.getYdtType() == MULTI_INSTANCE_NODE) {
581 curNode.createKeyNodeList();
582 }
583
584 /*
585 * Check application switch for curNode if set,
586 * then traverseToParent in YDT application tree.
587 */
588 if (curNode.getParent().equals(rootNode) ||
589 curNode.getAppContextSwitch()) {
590 traverseToAppTreeParent();
591 }
592
593 /*
594 * Validate all multi Instance inside current context,
595 * This is not valid for leaf and leaf-list node.
596 */
597 if (curNode instanceof YdtMultiInstanceNode ||
598 curNode instanceof YdtSingleInstanceNode) {
599 curNode.validateMultiInstanceNode();
600 }
601
602 curNode = curNode.getParent();
603 }
604
605 /**
606 * Traverses up in YANG application tree to the parent node,
607 * This will be used when Ydt current context switch flag is set.
608 */
609 private void traverseToAppTreeParent() {
610 appCurNode = appCurNode.getParent();
611 }
612
613 @Override
614 public YdtContext getCurNode() {
615 return curNode;
616 }
617
618 @Override
619 public void setDefaultEditOperationType(
620 YdtContextOperationType opType) {
621 ydtDefaultOpType = opType;
622 }
623
624 @Override
625 public YdtExtendedContext getRootNode() {
626 return rootNode;
627 }
628
629 @Override
630 public YmsOperationType getYmsOperationType() {
631 return ymsOperationType;
632 }
633
634 @Override
635 public void addMultiInstanceChild(String name, String namespace,
636 List<String> keysValueList,
637 YdtContextOperationType opType) {
638 addChild(name, namespace, UNKNOWN, opType,
639 RequestedCallType.MULTI_INSTANCE);
640 int inputCount = keysValueList.size();
641 int expectedCount;
642 if (curNode.getYdtType() == MULTI_INSTANCE_LEAF_VALUE_NODE) {
643 // After successful addition of child node updating
644 // the values in same.
645 // inputCount = curNode.getValueSet().size() + inputCount;
646 // checkElementCount(expectedCount, inputCount);
647 // TODO check the element count
648 for (String value : keysValueList) {
649 curNode.addValue(value);
650 }
651 } else if (curNode.getYdtType() == MULTI_INSTANCE_NODE) {
652 YangList yangListHolder = (YangList) curNode.getYangSchemaNode();
653 List<String> schemaKeyList = yangListHolder.getKeyList();
654 expectedCount = schemaKeyList.size();
655 checkElementCount(name, expectedCount, inputCount);
656
657 Iterator<String> sklIter = schemaKeyList.iterator();
658 Iterator<String> kvlIter = keysValueList.iterator();
659 String keyEleName;
660 while (kvlIter.hasNext()) {
661 String value = kvlIter.next();
662 keyEleName = sklIter.next();
663 addLeaf(keyEleName, namespace, value);
664 if (kvlIter.hasNext()) {
665 traverseToParentWithoutValidation();
666 }
667 }
668 curNode = curNode.getParent();
669 } else {
670 curNode.errorHandler(E_MULTI_INS, rootNode);
671 }
672 }
673
674 /**
675 * Checks the user supplied list of argument match's the expected value
676 * or not.
677 *
678 * @param name name of the parent list/leaf-list node
679 * @param expected count suppose to be
680 * @param actual user supplied values count
681 */
682 private void checkElementCount(String name, int expected,
683 int actual) {
684 if (expected < actual) {
685 curNode.errorHandler(errorMsg(FMT_TOO_MANY, name, expected, actual),
686 rootNode);
687 } else if (expected > actual) {
688 curNode.errorHandler(errorMsg(FMT_TOO_FEW, name, expected, actual),
689 rootNode);
690 }
691 }
692
693 /**
694 * Adds a last child to YANG data tree, this method is to be used by
695 * YANG object builder sub-calls internally.
696 *
697 * @param opType type of requested operation over a node
698 * @return returns added ydt node in YDT tree
699 */
700 private YdtNode addExtendedChildNode(YdtContextOperationType opType,
701 YangSchemaNode schemaNode) {
702
703 YdtNode childNode;
704 YangSchemaNodeIdentifier id =
705 schemaNode.getYangSchemaNodeIdentifier();
706
707 childNode = YdtNodeFactory
708 .getYangSchemaNodeTypeSpecificContext(
709 id, schemaNode.getYangSchemaNodeType());
710
711 childNode.setId(id);
712
713 childNode.setYangSchemaNode(schemaNode);
714
715 childNode.setYdtContextOperationType(opType);
716
717 curNode.addChild(childNode, true);
718
719 curNode = childNode;
720
721 return childNode;
722 }
723
724 @Override
725 public YdtExtendedContext addChild(YdtContextOperationType opType,
726 YangSchemaNode schemaNode) {
727 return addExtendedChildNode(opType, schemaNode);
728 }
729
730 @Override
731 public YdtExtendedContext addLeafList(Set<String> valueSet,
732 YangSchemaNode schemaNode) {
733 YdtNode childNode = addExtendedChildNode(null, schemaNode);
734
735 // After successful addition of child node updating the values in same.
736 childNode.addValueSetWithoutValidation(valueSet);
737 return childNode;
738 }
739
740 @Override
741 public YdtExtendedContext addLeaf(String value,
742 YangSchemaNode schemaNode) {
743 YdtNode childNode = addExtendedChildNode(null, schemaNode);
744
745 // After successful addition of child node updating the values in same.
746 childNode.addValueWithoutValidation(value);
747 return childNode;
748 }
749
750 @Override
751 public void traverseToParentWithoutValidation() {
752 // If traverse back to parent for logical root node comes
753 if (curNode.equals(rootNode)) {
754 curNode.errorHandler(E_INVOKE_PARENT, rootNode);
755 }
756 curNode = curNode.getParent();
757 }
758}