blob: c3d4b873e68a540f12ded8b33c68397e700cc59e [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 org.onosproject.yangutils.datamodel.YangList;
20import org.onosproject.yangutils.datamodel.YangSchemaNode;
21import org.onosproject.yangutils.datamodel.YangSchemaNodeContextInfo;
22import org.onosproject.yangutils.datamodel.YangSchemaNodeIdentifier;
23import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
24import org.onosproject.yms.app.ydt.exceptions.YdtException;
25import org.onosproject.yms.ydt.YdtContext;
26import org.onosproject.yms.ydt.YdtContextOperationType;
27import org.onosproject.yms.ydt.YdtExtendedInfoType;
28import org.onosproject.yms.ydt.YdtType;
29
30import java.util.ArrayList;
31import java.util.HashMap;
32import java.util.HashSet;
33import java.util.List;
34import java.util.Map;
35import java.util.Set;
36
37import static org.onosproject.yms.app.ydt.YdtConstants.errorMsg;
38
39/**
40 * Represents implementation of interfaces to build and obtain YANG data tree
41 * which is data (sub)instance representation, abstract of protocol.
42 */
43public abstract class YdtNode<T> implements YdtExtendedContext, Cloneable {
44
45 // ydt formatted error string
46 private static final String FMT_UNI_KEY =
47 "Some of the key elements are not unique in %s.";
48 private static final String FMT_KLIST_STR =
49 "List of key cannot be created for leaf and leaf-list %s node.";
50 private static final String FMT_VAL_N =
51 "Value cannot be set in non leaf %s node.";
52 private static final String FMT_VAL_NS =
53 "ValueSet cannot be set in non leaf-list %s node.";
54 private static final String FMT_VAL_IN =
55 "Value cannot be invoke from non leaf %s node.";
56 private static final String FMT_VAL_INS =
57 "ValueSet cannot be invoke from non leaf-list %s node";
58 private static final String FMT_MANY_INS =
59 "Too many instances of %s. Expected maximum instances %d.";
60 private static final String FMT_FEW_INS =
61 "Too few instances of %s. Expected minimum instances %d.";
62
63 // ydt error string
64 private static final String E_EXIST = "Node is already part of a tree";
65 private static final String E_ATOMIC =
66 "Child to be added is not atomic, it already has a child";
67 private static final String E_SIB =
68 "Child to be added is not atomic, it already has a next sibling";
69 private static final String E_PRE =
70 "Child to be added is not atomic, it already has a previous " +
71 "sibling";
72 private static final String E_SUPPORT = "Requested node type not supported";
73
74 /*
75 * Parent reference.
76 */
77 private YdtNode parent;
78
79 /*
80 * First child reference.
81 */
82 private YdtNode child;
83
84 /*
85 * Next sibling reference.
86 */
87 private YdtNode nextSibling;
88
89 /*
90 * Previous sibling reference.
91 */
92 private YdtNode previousSibling;
93
94 /*
95 * Last child reference.
96 */
97 private YdtNode lastChild;
98
99 /*
100 * Type of node.
101 */
102 private YdtType ydtType;
103
104 /*
105 * Flag to keep the track of context switch,
106 * if set then traverse back to parent in YDT app tree else no need.
107 */
108 private boolean isContextSwitch;
109
110 /*
111 * YDT extended information.
112 */
113 private T ydtExtendedInfo;
114
115 /*
116 * YDT extended information type.
117 */
118 private YdtExtendedInfoType ydtExtendedInfoType;
119
120 /*
121 * Ydt map to keep the track of node added in YDT.
122 */
123 final Map<YangSchemaNodeIdentifier, List<YdtNode<T>>> ydtNodeMap =
124 new HashMap<>();
125
126 /*
127 * Reference for data-model schema node.
128 */
129 private YangSchemaNode yangSchemaNode;
130
131 /*
132 * Reference for ydt node operation type.
133 */
134 private YdtContextOperationType ydtContextOperationType;
135
136 /*
137 * Key object for ydtNodeMap.
138 */
139 private YangSchemaNodeIdentifier id;
140
141 /*
142 * Ydt map to keep the track of application information object
143 * with respective type.
144 */
145 private final Map<AppType, Object> ydtAppInfoMap = new HashMap<>();
146
147 private YdtContext clonedNode;
148
149 /**
150 * Returns the cloned ydt node.
151 *
152 * @return clonedNode cloned ydt node
153 */
154 public YdtContext getClonedNode() {
155 return clonedNode;
156 }
157
158 /**
159 * Sets the cloned node.
160 *
161 * @param clonedNode cloned ydt node
162 */
163 public void setClonedNode(YdtContext clonedNode) {
164 this.clonedNode = clonedNode;
165 }
166
167 @Override
168 public String getName() {
169 return id.getName();
170 }
171
172 @Override
173 public String getNamespace() {
174 return id.getNameSpace();
175 }
176
177 @Override
178 public <T> T getYdtContextExtendedInfo() {
179 return (T) ydtExtendedInfo;
180 }
181
182 @Override
183 public YdtExtendedInfoType getYdtExtendedInfoType() {
184 return ydtExtendedInfoType;
185 }
186
187 @Override
188 public YdtType getYdtType() {
189 return ydtType;
190 }
191
192 @Override
193 public YdtNode getParent() {
194 return parent;
195 }
196
197 @Override
198 public YdtNode getFirstChild() {
199 return child;
200 }
201
202 @Override
203 public YdtNode getNextSibling() {
204 return nextSibling;
205 }
206
207 public YangSchemaNode getYangSchemaNode() {
208 return yangSchemaNode;
209 }
210
211 @Override
212 public YdtNode getLastChild() {
213 return lastChild;
214 }
215
216 @Override
217 public Object getAppInfo(AppType appType) {
218 return ydtAppInfoMap.get(appType);
219 }
220
221 @Override
222 public void addAppInfo(AppType appType, Object object) {
223 ydtAppInfoMap.put(appType, object);
224 }
225
226 @Override
227 public YangSchemaNodeContextInfo getSchemaNodeContextInfo(
228 YangSchemaNodeIdentifier id) {
229 try {
230 return getYangSchemaNode().getChildSchema(id);
231 } catch (DataModelException e) {
232 errorHandler(e.getLocalizedMessage(), this);
233 }
234 return null;
235 }
236
237 /**
238 * Adds the given value to the non single instance leaf node.
239 * <p>
240 * This default implementation throws an exception stating that
241 * the value cannot be added. Subclasses may override this method
242 * to provide the correct behavior for their specific implementation.
243 *
244 * @param value value in a single instance node
245 */
246 public void addValue(String value) {
247 errorHandler(
248 errorMsg(FMT_VAL_N, getYdtNodeIdentifier().getName()), this);
249 }
250
251 /**
252 * Creates the list of key element's of multi instance node.
253 * this will not be applicable on leaf and leaf-list node.
254 */
255 public void createKeyNodeList() {
256 errorHandler(errorMsg(
257 FMT_KLIST_STR, getYdtNodeIdentifier().getName()), this);
258 }
259
260 /**
261 * Adds the given value to the non single instance leaf node.
262 * <p>
263 * This default implementation throws an exception stating that
264 * the value cannot be added. Subclasses may override this method
265 * to provide the correct behavior for their specific implementation.
266 * This will be applicable in case of call from SBI so no need
267 * to validate the value.
268 *
269 * @param value value in a single instance leaf node
270 */
271 public void addValueWithoutValidation(String value) {
272 errorHandler(
273 errorMsg(FMT_VAL_N, getYdtNodeIdentifier().getName()), this);
274 }
275
276 /**
277 * Adds the given valueSet to the non multi instance leaf node.
278 * <p>
279 * This default implementation throws an exception stating that
280 * the value cannot be added. Subclasses may override this method
281 * to provide the correct behavior for their specific implementation.
282 *
283 * @param valueSet valueSet in a multi instance leaf node
284 */
285 public void addValueSet(Set<String> valueSet) {
286 errorHandler(
287 errorMsg(FMT_VAL_NS, getYdtNodeIdentifier().getName()), this);
288 }
289
290 /**
291 * Adds the given valueSet to the non multi instance leaf node.
292 * <p>
293 * This default implementation throws an exception stating that
294 * the value cannot be added. Subclasses may override this method
295 * to provide the correct behavior for their specific implementation.
296 * This will be applicable in case of call from SBI so no need
297 * to validate the value.
298 *
299 * @param valueSet valueSet in a multi instance leaf node
300 */
301 public void addValueSetWithoutValidation(Set<String> valueSet) {
302 errorHandler(
303 errorMsg(FMT_VAL_NS, getYdtNodeIdentifier().getName()), this);
304 }
305
306 /**
307 * Validates requested node allowed to have duplicate entry or not.
308 * <p>
309 * This default implementation throws an exception stating that
310 * the duplicate entry found. Subclasses may override this method
311 * to provide the correct behavior for their specific implementation.
312 */
313 public void validDuplicateEntryProcessing() {
314 }
315
316 /**
317 * Returns already existing YdtNode in Ydt tree with same nodeIdentifier.
318 *
319 * @param id represents a identifier of YANG data tree node
320 * @return YDT node
321 */
322 public YdtNode getCollidingChild(YangSchemaNodeIdentifier id) {
323
324 // Find the key in YDT map for getting the colliding node.
325 List<YdtNode<T>> collidingChild = ydtNodeMap.get(id);
326
327 /*
328 * If colliding child exist then process colliding node in respective
329 * YDT node type.
330 */
331 if (collidingChild != null) {
332 collidingChild.get(0).validDuplicateEntryProcessing();
333 return collidingChild.get(0);
334 }
335
336 return null;
337 }
338
339 /**
340 * Creates a specific type of node.
341 *
342 * @param type of YDT node
343 * @param id node identifier of the YDT node
344 */
345 YdtNode(YdtType type, YangSchemaNodeIdentifier id) {
346 ydtType = type;
347 setId(id);
348 }
349
350 /**
351 * Sets the parent of node.
352 *
353 * @param parent node
354 */
355 public void setParent(YdtNode parent) {
356 this.parent = parent;
357 }
358
359 /**
360 * Sets the first instance of a child node.
361 *
362 * @param child is only child to be set
363 */
364 public void setChild(YdtNode child) {
365 this.child = child;
366 }
367
368 /**
369 * Sets the next sibling of node.
370 *
371 * @param sibling YANG node
372 */
373 public void setNextSibling(YdtNode sibling) {
374 nextSibling = sibling;
375 }
376
377 /**
378 * Returns the previous sibling of a node.
379 *
380 * @return previous sibling of a node
381 */
382 public YdtNode getPreviousSibling() {
383 return previousSibling;
384 }
385
386 /**
387 * Sets the previous sibling.
388 *
389 * @param previousSibling points to predecessor sibling
390 */
391 public void setPreviousSibling(YdtNode previousSibling) {
392 this.previousSibling = previousSibling;
393 }
394
395 @Override
396 public String getValue() {
397 errorHandler(
398 errorMsg(FMT_VAL_IN, getYdtNodeIdentifier().getName()), this);
399 return null;
400 }
401
402 @Override
403 public Set<String> getValueSet() {
404 errorHandler(
405 errorMsg(FMT_VAL_INS, getYdtNodeIdentifier().getName()), this);
406 return null;
407 }
408
409 /**
410 * Sets the data-model node reference for of a given node.
411 *
412 * @param yangSchemaNode YANG data node
413 */
414 public void setYangSchemaNode(YangSchemaNode yangSchemaNode) {
415 this.yangSchemaNode = yangSchemaNode;
416 }
417
418 /**
419 * Sets the last instance of a child node.
420 *
421 * @param child is last child to be set
422 */
423 public void setLastChild(YdtNode child) {
424 lastChild = child;
425 }
426
427 /**
428 * Returns object node identifier.
429 *
430 * @return node identifier
431 */
432 public YangSchemaNodeIdentifier getYdtNodeIdentifier() {
433 return id;
434 }
435
436 /**
437 * Sets object node identifier.
438 *
439 * @param id node identifier
440 */
441 public void setId(YangSchemaNodeIdentifier id) {
442 this.id = id;
443 }
444
445 /**
446 * Adds a child node.
447 * The children sibling list will be sorted based on node
448 * type. This will add single child or sub-tree based on isAtomic flag.
449 *
450 * @param newChild refers to a new child to be added
451 * @param isAtomic boolean flag to maintain atomicity of the current node
452 * @throws YdtException in case of violation of any YDT rule
453 */
454 public void addChild(YdtContext newChild, boolean isAtomic)
455 throws YdtException {
456
457 if (!(newChild instanceof YdtNode)) {
458 errorHandler(errorMsg(E_SUPPORT), this);
459 }
460
461 YdtNode node = (YdtNode) newChild;
462
463 if (node.getParent() == null) {
464 node.setParent(this);
465 } else if (!node.getParent().equals(this)) {
466 errorHandler(errorMsg(E_EXIST), this);
467 }
468
469 if (node.getFirstChild() != null && isAtomic) {
470 errorHandler(errorMsg(E_ATOMIC), this);
471 }
472
473 if (node.getNextSibling() != null) {
474 errorHandler(errorMsg(E_SIB), this);
475 }
476
477 if (node.getPreviousSibling() != null) {
478 errorHandler(errorMsg(E_PRE), this);
479 }
480
481 // If new node needs to be added as first child.
482 if (getFirstChild() == null) {
483 setChild(node);
484 setLastChild(node);
485 return;
486 }
487
488 // If new node needs to be added as last child.
489 YdtNode curNode = getLastChild();
490 curNode.setNextSibling(node);
491 node.setPreviousSibling(curNode);
492 setLastChild(node);
493 }
494
495 @Override
496 public YdtContextOperationType getYdtContextOperationType() {
497 return ydtContextOperationType;
498 }
499
500 /**
501 * Sets type of yang data tree node operation.
502 *
503 * @param opType type of yang data tree node operation
504 */
505 public void setYdtContextOperationType(YdtContextOperationType opType) {
506 ydtContextOperationType = opType;
507 }
508
509 /**
510 * Updates ydt map of current context parent node.
511 *
512 * @param id object node identifier
513 * @param node ydt node for which map need to be updated
514 */
515 public void updateYdtMap(YangSchemaNodeIdentifier id, YdtNode node) {
516 List<YdtNode<T>> list = ydtNodeMap.get(id);
517 if (list == null) {
518 list = new ArrayList<>();
519 ydtNodeMap.put(id, list);
520 }
521 list.add(node);
522 }
523
524 /**
525 * Returns the flag for node if context switch.
526 *
527 * @return isContextSwitch flag of a node
528 */
529 public boolean getAppContextSwitch() {
530 return isContextSwitch;
531 }
532
533 /**
534 * Sets the flag to keep the track of context switch.
535 * If it is set then when YDT get traverToParent then
536 * traverse back to parent in YDT application tree.
537 */
538 public void setAppContextSwitch() {
539 isContextSwitch = true;
540 }
541
542 /**
543 * Validates all multi Instance inside current context.
544 */
545 public void validateMultiInstanceNode() {
546
547 // Set for checking whether input string is unique or not.
548 Set<String> keyStringSet = new HashSet<>();
549
550 // Iterating over values in map and find multi instance node list only.
551 for (List<YdtNode<T>> ydtNodeList : ydtNodeMap.values()) {
552 validateInstances(keyStringSet, ydtNodeList);
553 }
554 }
555
556 /**
557 * Checks for any duplicate list entries.
558 *
559 * @param keyStringSet set to validate the composite key of an instance
560 * @param ydtNodeList list of entries
561 */
562 private void validateInstances(Set<String> keyStringSet,
563 List<YdtNode<T>> ydtNodeList) {
564 // Clearing the set.
565 keyStringSet.clear();
566
567 if (ydtNodeList.get(0) instanceof YdtMultiInstanceNode) {
568
569 // Storing the number of multiInstance node for number
570 // if instance validation.
571 int instanceCount = ydtNodeList.size();
572
573 YangList list = (YangList) ydtNodeList.get(0).getYangSchemaNode();
574 int minElement;
575 int maxElement;
576 if (list.getMinElements() != null) {
577 minElement = list.getMinElements().getMinElement();
578 if (instanceCount < minElement) {
579 errorHandler(errorMsg(FMT_FEW_INS, list.getName(),
580 minElement), this);
581 }
582 }
583
584 if (list.getMaxElements() != null) {
585 maxElement = list.getMaxElements().getMaxElement();
586 if (instanceCount > maxElement) {
587 errorHandler(errorMsg(FMT_MANY_INS, list.getName(),
588 maxElement), this);
589 }
590 }
591
592 if (list.isConfig() && instanceCount > 1) {
593 // Iterating over values in ydtNodeList of
594 // multiInstanceNode and compare the key string.
595 for (YdtNode ydtNode : ydtNodeList) {
596 if (!keyStringSet.add(((YdtMultiInstanceNode) ydtNode)
597 .getCompositeKey())) {
598 errorHandler(errorMsg(
599 FMT_UNI_KEY, ydtNode.getYdtNodeIdentifier()
600 .getName()), this);
601 }
602 }
603 }
604 }
605 }
606
607 /**
608 * Walks in whole Ydt Tree and de-reference all the tree node.
609 * This will be called only when any exception occurs while processing
610 * the node in Ydt tree.
611 *
612 * @param node ydt node
613 */
614 public void freeRestResources(YdtNode node) {
615 // Traversing to logical rootNode.
616 YdtNode rootNode = node;
617 while (rootNode.getParent() != null) {
618 rootNode = rootNode.getParent();
619 }
620 YdtNode currentNode = rootNode;
621 while (currentNode != null) {
622
623 // Move down to first child
624 YdtNode nextNode = currentNode.getFirstChild();
625 if (nextNode != null) {
626 currentNode = nextNode;
627 continue;
628 }
629
630 // No child nodes, so walk tree
631 while (currentNode != null) {
632 // To keep the track of last sibling.
633 YdtNode lastSibling = currentNode;
634
635 // Move to sibling if possible.
636 nextNode = currentNode.getNextSibling();
637
638 // free currentNode resources
639 free(lastSibling);
640
641 lastSibling.getNamespace();
642 if (nextNode != null) {
643 currentNode = nextNode;
644 break;
645 }
646
647 // Move up
648 if (currentNode.equals(rootNode)) {
649 currentNode = null;
650 } else {
651 currentNode = currentNode.getParent();
652 lastSibling.setParent(null);
653 }
654 }
655 }
656 }
657
658 /**
659 * Free the give YDT node by de-referencing it to null.
660 *
661 * @param node node to be freed
662 */
663 private void free(YdtNode node) {
664 if (node.getParent() != null) {
665 YdtNode parent = node.getParent();
666 parent.setChild(null);
667 parent.setLastChild(null);
668 if (node.getNextSibling() != null) {
669 parent.setChild(node.getNextSibling());
670 }
671 }
672 YdtNode parentRef = node.getParent();
673 node = new YdtSingleInstanceNode(null);
674 node.ydtType = null;
675 node.setParent(parentRef);
676 }
677
678 /**
679 * Clones the current node contents and create a new node.
680 *
681 * @return cloned node
682 * @throws CloneNotSupportedException clone is not supported
683 * by the referred node
684 */
685 public YdtNode clone() throws CloneNotSupportedException {
686 YdtNode clonedNode = (YdtNode) super.clone();
687 clonedNode.setPreviousSibling(null);
688 clonedNode.setNextSibling(null);
689 clonedNode.setParent(null);
690 clonedNode.setChild(null);
691 clonedNode.setLastChild(null);
692 return clonedNode;
693 }
694
695 /**
696 * Handles an error scenario, freeing allocated resources for the given YTD
697 * node before throwing an exception with the specified error message.
698 *
699 * @param error error message
700 * @param curNode ydt node
701 * @throws YdtException with the specified error message
702 */
703 public void errorHandler(String error, YdtNode curNode) {
704 curNode.freeRestResources(curNode);
705 throw new YdtException(error);
706 }
707}