blob: 681a52c57c69e878ea2229ecac1dafa91e6b70af [file] [log] [blame]
Bharat saraswalb1170bd2016-07-14 13:26: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.yangutils.linker.impl;
18
19import java.util.ArrayList;
20import java.util.HashMap;
21import java.util.Iterator;
22import java.util.List;
23import java.util.Map;
24import java.util.Stack;
25
26import org.onosproject.yangutils.datamodel.YangAtomicPath;
27import org.onosproject.yangutils.datamodel.YangAugment;
28import org.onosproject.yangutils.datamodel.YangImport;
29import org.onosproject.yangutils.datamodel.YangInclude;
30import org.onosproject.yangutils.datamodel.YangLeaf;
31import org.onosproject.yangutils.datamodel.YangLeafList;
32import org.onosproject.yangutils.datamodel.YangLeavesHolder;
33import org.onosproject.yangutils.datamodel.YangModule;
34import org.onosproject.yangutils.datamodel.YangNode;
35import org.onosproject.yangutils.datamodel.YangNodeIdentifier;
36import org.onosproject.yangutils.datamodel.YangSubModule;
37import org.onosproject.yangutils.datamodel.YangUses;
38import org.onosproject.yangutils.linker.exceptions.LinkerException;
39
40/**
41 * Represents x-path linking.
42 *
43 * @param <T> x-path linking can be done for target node or for target leaf/leaf-list
44 */
45public class YangXpathLinker<T> {
46
47 /**
48 * Enum for prefix resolver type when augment has come in path.
49 */
50 private static enum PrefixResolverType {
51
52 /**
53 * When prefix changes from inter file to intra file.
54 */
55 INTER_TO_INTRA,
56
57 /**
58 * When prefix changes from intra file to inter file.
59 */
60 INTRA_TO_INTER,
61
62 /**
63 * When prefix changes from one inter file to other inter file.
64 */
65 INTER_TO_INTER,
66
67 /**
68 * When no prefix change occurres.
69 */
70 NO_PREFIX_CHANGE_FOR_INTRA,
71
72 /**
73 * When no prefix change occurres.
74 */
75 NO_PREFIX_CHANGE_FOR_INTER
76 }
77
78 private List<YangAtomicPath> absPaths;
79 private YangNode rootNode;
80 private PrefixResolverType type;
81 private String curPrefix;
82 private Map<YangAtomicPath, YangNode> resolvedNodes;
83
84 /**
85 * Creates an instance of x-path linker.
86 */
87 public YangXpathLinker() {
88 absPaths = new ArrayList<>();
89 setResolvedNodes(new HashMap<>());
90 }
91
92 /**
93 * Returns list of target nodes paths.
94 *
95 * @return target nodes paths
96 */
97 private List<YangAtomicPath> getAbsPaths() {
98 return absPaths;
99 }
100
101 /**
102 * Sets target nodes paths.
103 *
104 * @param absPaths target nodes paths
105 */
106 private void setAbsPaths(List<YangAtomicPath> absPaths) {
107 this.absPaths = absPaths;
108 }
109
110 /**
111 * Returns current prefix.
112 *
113 * @return current prefix
114 */
115 private String getCurPrefix() {
116 return curPrefix;
117 }
118
119 /**
120 * Sets current prefix.
121 *
122 * @param curPrefix current prefix
123 */
124 private void setCurPrefix(String curPrefix) {
125 this.curPrefix = curPrefix;
126 }
127
128 /**
129 * Return root node.
130 *
131 * @return root Node
132 */
133 private YangNode getRootNode() {
134 return rootNode;
135 }
136
137 /**
138 * Sets root node.
139 *
140 * @param rootNode root node
141 */
142 private void setRootNode(YangNode rootNode) {
143 this.rootNode = rootNode;
144 }
145
146 /**
147 * Returns prefix resolver type.
148 *
149 * @return prefix resolver type
150 */
151 private PrefixResolverType getPrefixResolverType() {
152 return type;
153 }
154
155 /**
156 * Sets prefix resolver type.
157 *
158 * @param type prefix resolver type
159 */
160 private void setPrefixResolverType(PrefixResolverType type) {
161 this.type = type;
162 }
163
164 /**
165 * Returns resolved nodes.
166 *
167 * @return resolved nodes
168 */
169 public Map<YangAtomicPath, YangNode> getResolvedNodes() {
170 return resolvedNodes;
171 }
172
173 /**
174 * Sets resolved nodes.
175 *
176 * @param resolvedNodes resolved nodes
177 */
178 private void setResolvedNodes(Map<YangAtomicPath, YangNode> resolvedNodes) {
179 this.resolvedNodes = resolvedNodes;
180 }
181
182 /**
183 * Adds node to resolved nodes.
184 *
185 * @param path absolute path
186 * @param node resolved node
187 */
188 private void addToResolvedNodes(YangAtomicPath path, YangNode node) {
189 getResolvedNodes().put(path, node);
190 }
191
192 /**
193 * Returns list of augment nodes.
194 *
195 * @param node root node
196 * @return list of augment nodes
197 */
198 public List<YangAugment> getListOfYangAugment(YangNode node) {
199 node = node.getChild();
200 List<YangAugment> augments = new ArrayList<>();
201 while (node != null) {
202 if (node instanceof YangAugment) {
203 augments.add((YangAugment) node);
204 }
205 node = node.getNextSibling();
206 }
207 return augments;
208 }
209
210 /**
211 * Process absolute node path for target leaf.
212 *
213 * @param absPaths absolute path node list
214 * @param root root node
215 * @return linked target node
216 */
217 public T processLeafRefXpathLinking(List<YangAtomicPath> absPaths, YangNode root) {
218
219 YangNode targetNode = null;
220 setRootNode(root);
221 YangAtomicPath leafRefPath = absPaths.get(absPaths.size() - 1);
222
223 // When leaf-ref path contains only one absolute path.
224 if (absPaths.size() == 1) {
225 targetNode = getTargetNodewhenSizeIsOne(absPaths);
226 } else {
227 absPaths.remove(absPaths.size() - 1);
228
229 setAbsPaths(absPaths);
230 targetNode = parseData(root);
231 }
232 if (targetNode == null) {
233 targetNode = parsePath(getIncludedNode(root));
234 }
235
236 if (targetNode != null) {
237 YangLeaf targetLeaf = searchReferredLeaf(targetNode, leafRefPath.getNodeIdentifier().getName());
238 if (targetLeaf == null) {
239 YangLeafList targetLeafList = searchReferredLeafList(targetNode,
240 leafRefPath.getNodeIdentifier().getName());
241 if (targetLeafList != null) {
242 return (T) targetLeafList;
243 } else {
244 throw new LinkerException(
245 "YANG file error: Unable to find base leaf/leaf-list for given leafref "
246 + leafRefPath.getNodeIdentifier().getName());
247 }
248 }
249 return (T) targetLeaf;
250 }
251 return null;
252 }
253
254 /**
255 * Returns target node when leaf-ref has only one absolute path in list.
256 *
257 * @param absPaths absolute paths
258 * @return target node
259 */
260 private YangNode getTargetNodewhenSizeIsOne(List<YangAtomicPath> absPaths) {
261 if (absPaths.get(0).getNodeIdentifier().getPrefix() != null
262 && !absPaths.get(0).getNodeIdentifier().getPrefix().equals(getRootsPrefix(getRootNode()))) {
263 return getImportedNode(getRootNode(), absPaths.get(0).getNodeIdentifier());
264 }
265 return getRootNode();
266
267 }
268
269 /**
270 * Process absolute node path linking for augment.
271 *
272 * @param absPaths absolute path node list
273 * @param root root node
274 * @return linked target node
275 */
276 public YangNode processAugmentXpathLinking(List<YangAtomicPath> absPaths, YangNode root) {
277
278 setAbsPaths(absPaths);
279 setRootNode(root);
280
281 YangNode targetNode = parseData(root);
282
283 if (targetNode == null) {
284 targetNode = parsePath(getIncludedNode(root));
285 }
286 return targetNode;
287
288 }
289
290 /**
291 * Searches for the referred leaf in target node.
292 *
293 * @param targetNode target node
294 * @param leafName leaf name
295 * @return target leaf
296 */
297 private YangLeaf searchReferredLeaf(YangNode targetNode, String leafName) {
298 if (!(targetNode instanceof YangLeavesHolder)) {
299 throw new LinkerException("Refered node " + targetNode.getName() +
300 "should be of type leaves holder ");
301 }
302 YangLeavesHolder holder = (YangLeavesHolder) targetNode;
303 List<YangLeaf> leaves = holder.getListOfLeaf();
304 for (YangLeaf leaf : leaves) {
305 if (leaf.getName().equals(leafName)) {
306 return leaf;
307 }
308 }
309 return null;
310 }
311
312 /**
313 * Searches for the referred leaf-list in target node.
314 *
315 * @param targetNode target node
316 * @param leafListName leaf-list name
317 * @return target leaf-list
318 */
319 private YangLeafList searchReferredLeafList(YangNode targetNode, String leafListName) {
320 if (!(targetNode instanceof YangLeavesHolder)) {
321 throw new LinkerException("Refered node " + targetNode.getName() +
322 "should be of type leaves holder ");
323 }
324 YangLeavesHolder holder = (YangLeavesHolder) targetNode;
325 List<YangLeafList> leavesList = holder.getListOfLeafList();
326 for (YangLeafList leafList : leavesList) {
327 if (leafList.getName().equals(leafListName)) {
328 return leafList;
329 }
330 }
331 return null;
332 }
333
334 /**
335 * Process linking using for node identifier for inter/intra file.
336 *
337 * @param root root node
338 * @return linked target node
339 */
340 private YangNode parseData(YangNode root) {
341 String rootPrefix = getRootsPrefix(root);
342 Iterator<YangAtomicPath> pathIterator = getAbsPaths().iterator();
343 YangAtomicPath path = pathIterator.next();
344 if (path.getNodeIdentifier().getPrefix() != null
345 && !path.getNodeIdentifier().getPrefix().equals(rootPrefix)) {
346 return parsePath(getImportedNode(root, path.getNodeIdentifier()));
347 } else {
348 return parsePath(root);
349 }
350 }
351
352 /**
353 * Process linking of target node in root node.
354 *
355 * @param root root node
356 * @return linked target node
357 */
358 private YangNode parsePath(YangNode root) {
359
360 YangNode tempNode = root;
361 Stack<YangNode> linkerStack = new Stack<>();
362 Iterator<YangAtomicPath> pathIterator = getAbsPaths().iterator();
363 YangAtomicPath tempPath = pathIterator.next();
364 setCurPrefix(tempPath.getNodeIdentifier().getPrefix());
365 int index = 0;
366 YangNode tempAugment = null;
367 do {
368
369 if (tempNode instanceof YangUses) {
370 tempNode = handleUsesNode(tempNode, tempPath.getNodeIdentifier());
371 if (pathIterator.hasNext()) {
372 tempPath = pathIterator.next();
373 index++;
374 } else {
375 addToResolvedNodes(tempPath, tempNode);
376 return tempNode;
377 }
378 }
379
380 if (tempPath.getNodeIdentifier().getPrefix() == null) {
381 tempAugment = resolveIntraFileAugment(tempPath, root);
382 } else {
383 tempAugment = resolveInterFileAugment(tempPath, root);
384 }
385
386 if (tempAugment != null) {
387 linkerStack.push(tempNode);
388 tempNode = tempAugment;
389 }
390
391 tempNode = searchTargetNode(tempNode, tempPath.getNodeIdentifier());
392 if (tempNode == null && linkerStack.size() != 0) {
393 tempNode = linkerStack.peek();
394 linkerStack.pop();
395 tempNode = searchTargetNode(tempNode, tempPath.getNodeIdentifier());
396 }
397
398 if (tempNode != null) {
399 addToResolvedNodes(tempPath, tempNode);
400 }
401
402 if (index == getAbsPaths().size() - 1) {
403 break;
404 }
405 tempPath = pathIterator.next();
406 index++;
407 } while (validate(tempNode, index));
408 return tempNode;
409 }
410
411 /**
412 * Resolves intra file augment linking.
413 *
414 * @param tempPath temporary absolute path
415 * @param root root node
416 * @return linked target node
417 */
418 private YangNode resolveIntraFileAugment(YangAtomicPath tempPath, YangNode root) {
419 YangNode tempAugment = null;
420 setPrefixResolverType(PrefixResolverType.NO_PREFIX_CHANGE_FOR_INTRA);
421 if (getCurPrefix() != tempPath.getNodeIdentifier().getPrefix()) {
422 setPrefixResolverType(PrefixResolverType.INTRA_TO_INTER);
423 root = getIncludedNode(getRootNode());
424 }
425
426 setCurPrefix(tempPath.getNodeIdentifier().getPrefix());
427 tempAugment = getAugment(tempPath.getNodeIdentifier(), root, getAbsPaths());
428 if (tempAugment == null) {
429 tempAugment = getAugment(tempPath.getNodeIdentifier(), getRootNode(), getAbsPaths());
430 }
431 return tempAugment;
432 }
433
434 /**
435 * Resolves inter file augment linking.
436 *
437 * @param tempPath temporary absolute path
438 * @param root root node
439 * @return linked target node
440 */
441 private YangNode resolveInterFileAugment(YangAtomicPath tempPath, YangNode root) {
442
443 YangNode tempAugment = null;
444 if (tempPath.getNodeIdentifier().getPrefix().equals(getCurPrefix())) {
445 setPrefixResolverType(PrefixResolverType.NO_PREFIX_CHANGE_FOR_INTER);
446 } else {
447 setCurPrefix(tempPath.getNodeIdentifier().getPrefix());
448 setPrefixResolverType(PrefixResolverType.INTER_TO_INTER);
449 if (getCurPrefix() == null) {
450 setPrefixResolverType(PrefixResolverType.INTER_TO_INTRA);
451 }
452 root = getImportedNode(getRootNode(), tempPath.getNodeIdentifier());
453 }
454 tempAugment = getAugment(tempPath.getNodeIdentifier(), root, getAbsPaths());
455 if (tempAugment == null && getPrefixResolverType().equals(PrefixResolverType.INTER_TO_INTER)) {
456 return resolveInterToInterFileAugment(root);
457 }
458 return tempAugment;
459 }
460
461 /**
462 * Resolves augment when prefix changed from inter file to inter file.
463 * it may be possible that the prefix used in imported module is different the
464 * given list of node identifiers.
465 *
466 * @param root root node
467 * @return target node
468 */
469 private YangNode resolveInterToInterFileAugment(YangNode root) {
470 List<YangAugment> augments = getListOfYangAugment(root);
471 int index;
472 List<YangAtomicPath> absPaths = new ArrayList<>();
473 for (YangAugment augment : augments) {
474 index = 0;
475
476 for (YangAtomicPath path : augment.getTargetNode()) {
477
478 if (!searchForAugmentInImportedNode(path.getNodeIdentifier(), index)) {
479 absPaths.clear();
480 break;
481 }
482 absPaths.add(path);
483 index++;
484 }
485 if (!absPaths.isEmpty() && absPaths.size() == getAbsPaths().size() - 1) {
486 return augment;
487 } else {
488 absPaths.clear();
489 }
490 }
491 return null;
492 }
493
494 /**
495 * Searches for the augment node in imported module when prefix has changed from
496 * inter file to inter file.
497 * @param nodeId node id
498 * @param index index
499 * @return true if found
500 */
501 private boolean searchForAugmentInImportedNode(YangNodeIdentifier nodeId, int index) {
502 YangNodeIdentifier tempNodeId = getAbsPaths().get(index).getNodeIdentifier();
503 return nodeId.getName().equals(tempNodeId.getName());
504 }
505
506 /**
507 * Returns augment node.
508 *
509 * @param tempNodeId temporary absolute path id
510 * @param root root node
511 * @return linked target node
512 */
513 private YangNode getAugment(YangNodeIdentifier tempNodeId, YangNode root, List<YangAtomicPath> absPaths) {
514 String augmentName = getAugmentNodeIdentifier(tempNodeId, absPaths);
515 if (augmentName != null) {
516 return searchAugmentNode(root, augmentName);
517 }
518 return null;
519 }
520
521 /**
522 * Process linking using import list.
523 *
524 * @param root root node
525 * @param nodeId node identifier
526 * @return linked target node
527 */
528 private YangNode getImportedNode(YangNode root, YangNodeIdentifier nodeId) {
529
530 List<YangImport> importList = new ArrayList<>();
531
532 if (root instanceof YangModule) {
533 importList = ((YangModule) root).getImportList();
534 } else {
535 importList = ((YangSubModule) root).getImportList();
536 }
537
538 for (YangImport imported : importList) {
539 if (imported.getPrefixId().equals(nodeId.getPrefix())) {
540 return imported.getImportedNode();
541 }
542 }
543
544 return root;
545 }
546
547 /**
548 * Process linking using include list.
549 *
550 * @param root root node
551 * @return linked target node
552 */
553 private YangNode getIncludedNode(YangNode root) {
554
555 List<YangInclude> includeList = new ArrayList<>();
556
557 if (root instanceof YangModule) {
558 includeList = ((YangModule) root).getIncludeList();
559 } else {
560 includeList = ((YangSubModule) root).getIncludeList();
561 }
562
563 for (YangInclude included : includeList) {
564 return included.getIncludedNode();
565 }
566
567 return root;
568 }
569
570 /**
571 * Returns augments node id.
572 *
573 * @param nodeId node identifier
574 * @return augment node id
575 */
576 private String getAugmentNodeIdentifier(YangNodeIdentifier nodeId, List<YangAtomicPath> absPaths) {
577
578 Iterator<YangAtomicPath> nodeIdIterator = absPaths.iterator();
579 YangAtomicPath tempNodeId = null;
580 StringBuilder builder = new StringBuilder();
581 while (nodeIdIterator.hasNext()) {
582 tempNodeId = nodeIdIterator.next();
583 if (!tempNodeId.getNodeIdentifier().equals(nodeId)) {
584 if (tempNodeId.getNodeIdentifier().getPrefix() != null
585 && (getPrefixResolverType().equals(PrefixResolverType.INTER_TO_INTER)
586 || getPrefixResolverType().equals(PrefixResolverType.INTRA_TO_INTER))) {
587 builder.append("/" + tempNodeId.getNodeIdentifier().getPrefix());
588 builder.append(":" + tempNodeId.getNodeIdentifier().getName());
589 } else {
590 builder.append("/" + tempNodeId.getNodeIdentifier().getName());
591 }
592 } else {
593 return builder.toString();
594 }
595 }
596 return null;
597 }
598
599 /**
600 * Searches augment node in root node.
601 *
602 * @param node root node
603 * @param tempNodeId node identifier
604 * @return target augment node
605 */
606 private YangNode searchAugmentNode(YangNode node, String tempNodeId) {
607 node = node.getChild();
608 while (node != null) {
609 if (node instanceof YangAugment) {
610 if (((YangAugment) node).getName().equals(tempNodeId)) {
611 return node;
612 }
613 }
614 node = node.getNextSibling();
615 }
616 return null;
617 }
618
619 /**
620 * Validates for target node if target node found or not.
621 *
622 * @param tempNode temporary node
623 * @param index current index of list
624 * @return false if target node found
625 */
626 private boolean validate(YangNode tempNode, int index) {
627
628 int size = getAbsPaths().size();
629 if (tempNode != null && index != size) {
630 return true;
631 } else if (tempNode != null && index == size) {
632 return false;
633 // this is your target node.
634 } else if (tempNode == null && index != size) {
635 return false;
636 // this could be in submodule as well.
637 }
638 return false;
639 }
640
641 /**
642 * Searches target node in root node.
643 *
644 * @param node root node
645 * @param curNodeId YANG node identifier
646 * @return linked target node
647 */
648 private YangNode searchTargetNode(YangNode node, YangNodeIdentifier curNodeId) {
649
650 if (node != null) {
651 node = node.getChild();
652 }
653
654 while (node != null) {
655 if (node.getName().equals(curNodeId.getName())) {
656 return node;
657 }
658 node = node.getNextSibling();
659 }
660 return null;
661 }
662
663 /**
664 * Handles linking when uses node is present.
665 *
666 * @param node uses node
667 * @param curNodeId current node id
668 * @return linked node
669 */
670 private YangNode handleUsesNode(YangNode node, YangNodeIdentifier curNodeId) {
671 YangNode tempNode = null;
672 tempNode = searchInUsesNode((YangUses) node, curNodeId);
673 if (tempNode != null) {
674 return tempNode;
675 }
676 return null;
677 }
678
679 /**
680 * Searches target node in uses resolved list.
681 *
682 * @param uses uses node
683 * @param curNodeId current node id
684 * @return linked target node
685 */
686 private YangNode searchInUsesNode(YangUses uses, YangNodeIdentifier curNodeId) {
687
688 List<YangNode> resolvedNodes = uses.getUsesResolvedNodeList();
689 for (YangNode node : resolvedNodes) {
690 if (node.getName().equals(curNodeId.getName())) {
691 return node;
692 }
693 }
694 return null;
695 }
696
697 /**
698 * Returns root prefix.
699 *
700 * @param root root node
701 * @return root prefix
702 */
703 private String getRootsPrefix(YangNode root) {
704 if (root instanceof YangModule) {
705 return ((YangModule) root).getPrefix();
706 } else {
707 return ((YangSubModule) root).getPrefix();
708 }
709 }
710
711}