2 * Copyright (c) 2013 Cisco Systems, Inc. and others. All rights reserved.
4 * This program and the accompanying materials are made available under the
5 * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6 * and is available at http://www.eclipse.org/legal/epl-v10.html
8 package org.opendaylight.yangtools.yang.model.util;
11 import java.util.ArrayList;
12 import java.util.Arrays;
13 import java.util.Collection;
14 import java.util.Collections;
15 import java.util.Date;
16 import java.util.LinkedList;
17 import java.util.List;
19 import org.opendaylight.yangtools.yang.common.QName;
20 import org.opendaylight.yangtools.yang.model.api.*;
22 import com.google.common.base.Preconditions;
27 * The Schema Context Util contains support methods for searching through Schema
28 * Context modules for specified schema nodes via Schema Path or Revision Aware
29 * XPath. The Schema Context Util is designed as mixin, so it is not
33 public class SchemaContextUtil {
35 private SchemaContextUtil() {
39 * Method attempts to find DataSchemaNode in Schema Context via specified
40 * Schema Path. The returned DataSchemaNode from method will be the node at
41 * the end of the SchemaPath. If the DataSchemaNode is not present in the
42 * Schema Context the method will return <code>null</code>. <br>
43 * In case that Schema Context or Schema Path are not specified correctly
44 * (i.e. contains <code>null</code> values) the method will return
45 * IllegalArgumentException.
47 * @throws IllegalArgumentException
52 * Schema Path to search for
53 * @return SchemaNode from the end of the Schema Path or <code>null</code>
54 * if the Node is not present.
56 public static SchemaNode findDataSchemaNode(SchemaContext context, SchemaPath schemaPath) {
57 Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
58 Preconditions.checkArgument(schemaPath != null, "Schema Path reference cannot be NULL");
59 List<QName> prefixedPath = (schemaPath.getPath());
60 if (prefixedPath != null) {
61 return findNodeInSchemaContext(context, prefixedPath);
67 * Method attempts to find DataSchemaNode inside of provided Schema Context
68 * and Yang Module accordingly to Non-conditional Revision Aware XPath. The
69 * specified Module MUST be present in Schema Context otherwise the
70 * operation would fail and return <code>null</code>. <br>
71 * The Revision Aware XPath MUST be specified WITHOUT the conditional
72 * statement (i.e. without [cond]) in path, because in this state the Schema
73 * Context is completely unaware of data state and will be not able to
74 * properly resolve XPath. If the XPath contains condition the method will
75 * return IllegalArgumentException. <br>
76 * In case that Schema Context or Module or Revision Aware XPath contains
77 * <code>null</code> references the method will throw
78 * IllegalArgumentException <br>
79 * If the Revision Aware XPath is correct and desired Data Schema Node is
80 * present in Yang module or in depending module in Schema Context the
81 * method will return specified Data Schema Node, otherwise the operation
82 * will fail and method will return <code>null</code>.
84 * @throws IllegalArgumentException
91 * Non Conditional Revision Aware XPath
92 * @return Returns Data Schema Node for specified Schema Context for given
93 * Non-conditional Revision Aware XPath, or <code>null</code> if the
94 * DataSchemaNode is not present in Schema Context.
96 public static SchemaNode findDataSchemaNode(SchemaContext context, Module module, RevisionAwareXPath nonCondXPath) {
97 Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
98 Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
99 Preconditions.checkArgument(nonCondXPath != null, "Non Conditional Revision Aware XPath cannot be NULL");
101 String strXPath = nonCondXPath.toString();
102 if (strXPath != null) {
103 if (strXPath.contains("[")) {
104 throw new IllegalArgumentException("Revision Aware XPath cannot contains condition");
106 if (nonCondXPath.isAbsolute()) {
107 List<QName> qnamedPath = xpathToQNamePath(context, module, strXPath);
108 if (qnamedPath != null) {
109 return findNodeInSchemaContext(context, qnamedPath);
117 * Method attempts to find DataSchemaNode inside of provided Schema Context
118 * and Yang Module accordingly to Non-conditional relative Revision Aware
119 * XPath. The specified Module MUST be present in Schema Context otherwise
120 * the operation would fail and return <code>null</code>. <br>
121 * The relative Revision Aware XPath MUST be specified WITHOUT the
122 * conditional statement (i.e. without [cond]) in path, because in this
123 * state the Schema Context is completely unaware of data state and will be
124 * not able to properly resolve XPath. If the XPath contains condition the
125 * method will return IllegalArgumentException. <br>
126 * The Actual Schema Node MUST be specified correctly because from this
127 * Schema Node will search starts. If the Actual Schema Node is not correct
128 * the operation will simply fail, because it will be unable to find desired
129 * DataSchemaNode. <br>
130 * In case that Schema Context or Module or Actual Schema Node or relative
131 * Revision Aware XPath contains <code>null</code> references the method
132 * will throw IllegalArgumentException <br>
133 * If the Revision Aware XPath doesn't have flag
134 * <code>isAbsolute == false</code> the method will throw
135 * IllegalArgumentException. <br>
136 * If the relative Revision Aware XPath is correct and desired Data Schema
137 * Node is present in Yang module or in depending module in Schema Context
138 * the method will return specified Data Schema Node, otherwise the
139 * operation will fail and method will return <code>null</code>.
141 * @throws IllegalArgumentException
147 * @param actualSchemaNode
149 * @param relativeXPath
150 * Relative Non Conditional Revision Aware XPath
151 * @return DataSchemaNode if is present in specified Schema Context for
152 * given relative Revision Aware XPath, otherwise will return
155 public static SchemaNode findDataSchemaNodeForRelativeXPath(SchemaContext context, Module module,
156 SchemaNode actualSchemaNode, RevisionAwareXPath relativeXPath) {
157 Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
158 Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
159 Preconditions.checkArgument(actualSchemaNode != null, "Actual Schema Node reference cannot be NULL");
160 Preconditions.checkArgument(relativeXPath != null, "Non Conditional Revision Aware XPath cannot be NULL");
161 Preconditions.checkState(!relativeXPath.isAbsolute(),
162 "Revision Aware XPath MUST be relative i.e. MUST contains ../, "
163 + "for non relative Revision Aware XPath use findDataSchemaNode method");
165 SchemaPath actualNodePath = actualSchemaNode.getPath();
166 if (actualNodePath != null) {
167 List<QName> qnamePath = resolveRelativeXPath(context, module, relativeXPath, actualSchemaNode);
169 if (qnamePath != null) {
170 return findNodeInSchemaContext(context, qnamePath);
177 * Returns parent Yang Module for specified Schema Context in which Schema
178 * Node is declared. If the Schema Node is not present in Schema Context the
179 * operation will return <code>null</code>. <br>
180 * If Schema Context or Schema Node contains <code>null</code> references
181 * the method will throw IllegalArgumentException
183 * @throws IllegalArgumentException
189 * @return Yang Module for specified Schema Context and Schema Node, if
190 * Schema Node is NOT present, the method will returns
193 public static Module findParentModule(SchemaContext context, SchemaNode schemaNode) {
194 Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL!");
195 Preconditions.checkArgument(schemaNode != null, "Schema Node cannot be NULL!");
196 Preconditions.checkState(schemaNode.getPath() != null, "Schema Path for Schema Node is not "
197 + "set properly (Schema Path is NULL)");
199 List<QName> qnamedPath = schemaNode.getPath().getPath();
200 if (qnamedPath == null || qnamedPath.isEmpty()) {
201 throw new IllegalStateException("Schema Path contains invalid state of path parts."
202 + "The Schema Path MUST contain at least ONE QName which defines namespace and Local name"
205 QName qname = qnamedPath.get(qnamedPath.size() - 1);
206 return context.findModuleByNamespaceAndRevision(qname.getNamespace(), qname.getRevision());
209 public static SchemaNode findNodeInSchemaContext(SchemaContext context, List<QName> path) {
210 QName current = path.get(0);
211 Module module = context.findModuleByNamespaceAndRevision(current.getNamespace(), current.getRevision());
214 return findNodeInModule(module, path);
217 public static GroupingDefinition findGrouping(SchemaContext context, Module module, List<QName> path) {
218 QName first = path.get(0);
219 Module m = context.findModuleByNamespace(first.getNamespace()).iterator().next();
220 DataNodeContainer currentParent = m;
221 for (QName qname : path) {
222 boolean found = false;
223 DataNodeContainer node = (DataNodeContainer) currentParent.getDataChildByName(qname.getLocalName());
225 Set<GroupingDefinition> groupings = currentParent.getGroupings();
226 for (GroupingDefinition gr : groupings) {
227 if (gr.getQName().getLocalName().equals(qname.getLocalName())) {
234 currentParent = node;
237 throw new IllegalArgumentException("Failed to find referenced grouping: " + path + "("
238 + qname.getLocalName() + ")");
242 return (GroupingDefinition) currentParent;
245 private static SchemaNode findNodeInModule(Module module, List<QName> path) {
246 QName current = path.get(0);
247 SchemaNode node = module.getDataChildByName(current);
249 return findNode((DataSchemaNode) node, nextLevel(path));
250 node = getRpcByName(module, current);
252 return findNodeInRpc((RpcDefinition) node, nextLevel(path));
253 node = getNotificationByName(module, current);
255 return findNodeInNotification((NotificationDefinition) node, nextLevel(path));
256 node = getGroupingByName(module, current);
258 return findNodeInGrouping((GroupingDefinition) node, nextLevel(path));
262 private static SchemaNode findNodeInGrouping(GroupingDefinition grouping, List<QName> path) {
265 QName current = path.get(0);
266 DataSchemaNode node = grouping.getDataChildByName(current);
268 return findNode(node, nextLevel(path));
272 private static SchemaNode findNodeInRpc(RpcDefinition rpc, List<QName> path) {
275 QName current = path.get(0);
276 switch (current.getLocalName()) {
278 return findNode(rpc.getInput(), nextLevel(path));
280 return findNode(rpc.getOutput(), nextLevel(path));
285 private static SchemaNode findNodeInNotification(NotificationDefinition rpc, List<QName> path) {
288 QName current = path.get(0);
289 DataSchemaNode node = rpc.getDataChildByName(current);
291 return findNode(node, nextLevel(path));
295 private static SchemaNode findNode(ChoiceNode parent, List<QName> path) {
298 QName current = path.get(0);
299 ChoiceCaseNode node = parent.getCaseNodeByName(current);
301 return findNodeInCase(node, nextLevel(path));
305 private static SchemaNode findNode(ContainerSchemaNode parent, List<QName> path) {
308 QName current = path.get(0);
309 DataSchemaNode node = parent.getDataChildByName(current);
311 return findNode(node, nextLevel(path));
315 private static SchemaNode findNode(ListSchemaNode parent, List<QName> path) {
318 QName current = path.get(0);
319 DataSchemaNode node = parent.getDataChildByName(current);
321 return findNode(node, nextLevel(path));
325 private static SchemaNode findNode(DataSchemaNode parent, List<QName> path) {
326 SchemaNode result = null;
327 if (path.isEmpty()) {
330 if (parent instanceof ContainerSchemaNode) {
331 result = findNode((ContainerSchemaNode) parent, path);
332 } else if (parent instanceof ListSchemaNode) {
333 result = findNode((ListSchemaNode) parent, path);
334 } else if (parent instanceof ChoiceNode) {
335 result = findNode((ChoiceNode) parent, path);
337 throw new IllegalArgumentException("Path nesting violation");
343 public static SchemaNode findNodeInCase(ChoiceCaseNode parent, List<QName> path) {
346 QName current = path.get(0);
347 DataSchemaNode node = parent.getDataChildByName(current);
349 return findNode(node, nextLevel(path));
353 public static RpcDefinition getRpcByName(Module module, QName name) {
354 for (RpcDefinition rpc : module.getRpcs()) {
355 if (rpc.getQName().equals(name)) {
362 private static List<QName> nextLevel(List<QName> path) {
363 return path.subList(1, path.size());
366 public static NotificationDefinition getNotificationByName(Module module, QName name) {
367 for (NotificationDefinition notification : module.getNotifications()) {
368 if (notification.getQName().equals(name)) {
375 public static GroupingDefinition getGroupingByName(Module module, QName name) {
376 for (GroupingDefinition grouping : module.getGroupings()) {
377 if (grouping.getQName().equals(name)) {
385 * Utility method which search for original node defined in grouping.
390 public static DataSchemaNode findOriginal(DataSchemaNode node, SchemaContext ctx) {
391 DataSchemaNode result = findCorrectTargetFromGrouping(node, ctx);
392 if (result == null) {
393 result = findCorrectTargetFromAugment(node, ctx);
394 if (result != null) {
395 if (result.isAddedByUses()) {
396 result = findOriginal(result, ctx);
403 private static DataSchemaNode findCorrectTargetFromGrouping(DataSchemaNode node, SchemaContext ctx) {
404 if (node.getPath().getPath().size() == 1) {
405 // uses is under module statement
406 Module m = findParentModule(ctx, node);
407 DataSchemaNode result = null;
408 for (UsesNode u : m.getUses()) {
409 SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath());
410 if (!(targetGrouping instanceof GroupingDefinition)) {
411 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
413 GroupingDefinition gr = (GroupingDefinition) targetGrouping;
414 result = gr.getDataChildByName(node.getQName().getLocalName());
416 if (result == null) {
417 throw new IllegalArgumentException("Failed to generate code for augment");
421 DataSchemaNode result = null;
422 QName currentName = node.getQName();
423 List<QName> tmpPath = new ArrayList<>();
424 Object parent = null;
426 SchemaPath sp = node.getPath();
427 List<QName> names = sp.getPath();
428 List<QName> newNames = new ArrayList<>(names);
429 newNames.remove(newNames.size() - 1);
430 SchemaPath newSp = new SchemaPath(newNames, sp.isAbsolute());
431 parent = findDataSchemaNode(ctx, newSp);
434 tmpPath.add(currentName);
435 if (parent instanceof DataNodeContainer) {
436 DataNodeContainer dataNodeParent = (DataNodeContainer) parent;
437 for (UsesNode u : dataNodeParent.getUses()) {
438 if (result == null) {
439 result = getResultFromUses(u, currentName.getLocalName(), ctx);
443 if (result == null) {
444 currentName = ((SchemaNode) parent).getQName();
445 if (parent instanceof SchemaNode) {
446 SchemaPath nodeSp = ((SchemaNode) parent).getPath();
447 List<QName> nodeNames = nodeSp.getPath();
448 List<QName> nodeNewNames = new ArrayList<>(nodeNames);
449 nodeNewNames.remove(nodeNewNames.size() - 1);
450 if (nodeNewNames.isEmpty()) {
451 parent = getParentModule((SchemaNode) parent, ctx);
453 SchemaPath nodeNewSp = new SchemaPath(nodeNewNames, nodeSp.isAbsolute());
454 parent = findDataSchemaNode(ctx, nodeNewSp);
457 throw new IllegalArgumentException("Failed to generate code for augment");
460 } while (result == null && !(parent instanceof Module));
462 if (result != null) {
463 result = getTargetNode(tmpPath, result, ctx);
469 private static DataSchemaNode findCorrectTargetFromAugment(DataSchemaNode node, SchemaContext ctx) {
470 if (!node.isAugmenting()) {
474 QName currentName = node.getQName();
475 Object currentNode = node;
476 Object parent = node;
477 List<QName> tmpPath = new ArrayList<QName>();
478 List<SchemaNode> tmpTree = new ArrayList<SchemaNode>();
480 AugmentationSchema augment = null;
482 SchemaPath sp = ((SchemaNode) parent).getPath();
483 List<QName> names = sp.getPath();
484 List<QName> newNames = new ArrayList<>(names);
485 newNames.remove(newNames.size() - 1);
486 SchemaPath newSp = new SchemaPath(newNames, sp.isAbsolute());
487 parent = findDataSchemaNode(ctx, newSp);
488 if (parent instanceof AugmentationTarget) {
489 tmpPath.add(currentName);
490 tmpTree.add((SchemaNode) currentNode);
491 augment = findNodeInAugment(((AugmentationTarget) parent).getAvailableAugmentations(), currentName);
492 if (augment == null) {
493 currentName = ((DataSchemaNode) parent).getQName();
494 currentNode = parent;
497 } while (((DataSchemaNode) parent).isAugmenting() && augment == null);
499 if (augment == null) {
502 Collections.reverse(tmpPath);
503 Collections.reverse(tmpTree);
504 Object actualParent = augment;
505 DataSchemaNode result = null;
506 for (QName name : tmpPath) {
507 if (actualParent instanceof DataNodeContainer) {
508 result = ((DataNodeContainer) actualParent).getDataChildByName(name.getLocalName());
509 actualParent = ((DataNodeContainer) actualParent).getDataChildByName(name.getLocalName());
511 if (actualParent instanceof ChoiceNode) {
512 result = ((ChoiceNode) actualParent).getCaseNodeByName(name.getLocalName());
513 actualParent = ((ChoiceNode) actualParent).getCaseNodeByName(name.getLocalName());
518 if (result.isAddedByUses()) {
519 result = findCorrectTargetFromAugmentGrouping(result, augment, tmpTree, ctx);
526 private static DataSchemaNode getResultFromUses(UsesNode u, String currentName, SchemaContext ctx) {
527 SchemaNode targetGrouping = findNodeInSchemaContext(ctx, u.getGroupingPath().getPath());
528 if (!(targetGrouping instanceof GroupingDefinition)) {
529 throw new IllegalArgumentException("Failed to generate code for augment in " + u);
531 GroupingDefinition gr = (GroupingDefinition) targetGrouping;
532 return gr.getDataChildByName(currentName);
535 private static Module getParentModule(SchemaNode node, SchemaContext ctx) {
536 QName qname = node.getPath().getPath().get(0);
537 URI namespace = qname.getNamespace();
538 Date revision = qname.getRevision();
539 return ctx.findModuleByNamespaceAndRevision(namespace, revision);
542 private static DataSchemaNode getTargetNode(List<QName> tmpPath, DataSchemaNode node, SchemaContext ctx) {
543 DataSchemaNode result = node;
544 if (tmpPath.size() == 1) {
545 if (result != null && result.isAddedByUses()) {
546 result = findOriginal(result, ctx);
550 DataSchemaNode newParent = result;
551 Collections.reverse(tmpPath);
554 for (QName name : tmpPath) {
555 // searching by local name is must, because node has different
556 // namespace in its original location
557 if (newParent == null) {
560 if (newParent instanceof DataNodeContainer) {
561 newParent = ((DataNodeContainer) newParent).getDataChildByName(name.getLocalName());
563 newParent = ((ChoiceNode) newParent).getCaseNodeByName(name.getLocalName());
566 if (newParent != null && newParent.isAddedByUses()) {
567 newParent = findOriginal(newParent, ctx);
573 private static AugmentationSchema findNodeInAugment(Collection<AugmentationSchema> augments, QName name) {
574 for (AugmentationSchema augment : augments) {
575 DataSchemaNode node = augment.getDataChildByName(name);
583 private static DataSchemaNode findCorrectTargetFromAugmentGrouping(DataSchemaNode node,
584 AugmentationSchema parentNode, List<SchemaNode> dataTree, SchemaContext ctx) {
586 DataSchemaNode result = null;
587 QName currentName = node.getQName();
588 List<QName> tmpPath = new ArrayList<>();
589 tmpPath.add(currentName);
591 Object parent = null;
594 if (dataTree.size() < 2 || dataTree.size() == i) {
597 parent = dataTree.get(dataTree.size() - (i + 1));
598 tmpPath.add(((SchemaNode) parent).getQName());
601 if (parent instanceof DataNodeContainer) {
602 DataNodeContainer dataNodeParent = (DataNodeContainer) parent;
603 for (UsesNode u : dataNodeParent.getUses()) {
604 if (result == null) {
605 result = getResultFromUses(u, currentName.getLocalName(), ctx);
610 if (result == null) {
612 currentName = ((SchemaNode) parent).getQName();
614 } while (result == null);
616 if (result != null) {
617 result = getTargetNode(tmpPath, result, ctx);
623 * Transforms string representation of XPath to Queue of QNames. The XPath
624 * is split by "/" and for each part of XPath is assigned correct module in
626 * If Schema Context, Parent Module or XPath string contains
627 * <code>null</code> values, the method will throws IllegalArgumentException
629 * @throws IllegalArgumentException
633 * @param parentModule
637 * @return return a list of QName
639 private static List<QName> xpathToQNamePath(SchemaContext context, Module parentModule, String xpath) {
640 Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
641 Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL");
642 Preconditions.checkArgument(xpath != null, "XPath string reference cannot be NULL");
644 List<QName> path = new LinkedList<QName>();
645 String[] prefixedPath = xpath.split("/");
646 for (String pathComponent : prefixedPath) {
647 if (!pathComponent.isEmpty()) {
648 path.add(stringPathPartToQName(context, parentModule, pathComponent));
655 * Transforms part of Prefixed Path as java String to QName. <br>
656 * If the string contains module prefix separated by ":" (i.e.
657 * mod:container) this module is provided from from Parent Module list of
658 * imports. If the Prefixed module is present in Schema Context the QName
659 * can be constructed. <br>
660 * If the Prefixed Path Part does not contains prefix the Parent's Module
661 * namespace is taken for construction of QName. <br>
662 * If Schema Context, Parent Module or Prefixed Path Part refers to
663 * <code>null</code> the method will throw IllegalArgumentException
665 * @throws IllegalArgumentException
669 * @param parentModule
671 * @param prefixedPathPart
672 * Prefixed Path Part string
673 * @return QName from prefixed Path Part String.
675 private static QName stringPathPartToQName(SchemaContext context, Module parentModule, String prefixedPathPart) {
676 Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
677 Preconditions.checkArgument(parentModule != null, "Parent Module reference cannot be NULL");
678 Preconditions.checkArgument(prefixedPathPart != null, "Prefixed Path Part cannot be NULL!");
680 if (prefixedPathPart.contains(":")) {
681 String[] prefixedName = prefixedPathPart.split(":");
682 Module module = resolveModuleForPrefix(context, parentModule, prefixedName[0]);
683 if (module == null) {
684 throw new IllegalArgumentException("Failed to resolve xpath: no module found for prefix "
685 + prefixedName[0] + " in module " + parentModule.getName());
687 return new QName(module.getNamespace(), module.getRevision(), prefixedName[1]);
690 return new QName(parentModule.getNamespace(), parentModule.getRevision(), prefixedPathPart);
695 * Method will attempt to resolve and provide Module reference for specified
696 * module prefix. Each Yang module could contains multiple imports which
697 * MUST be associated with corresponding module prefix. The method simply
698 * looks into module imports and returns the module that is bounded with
699 * specified prefix. If the prefix is not present in module or the prefixed
700 * module is not present in specified Schema Context, the method will return
701 * <code>null</code>. <br>
702 * If String prefix is the same as prefix of the specified Module the
703 * reference to this module is returned. <br>
704 * If Schema Context, Module or Prefix are referring to <code>null</code>
705 * the method will return IllegalArgumentException
707 * @throws IllegalArgumentException
715 * @return Module for given prefix in specified Schema Context if is
716 * present, otherwise returns <code>null</code>
718 private static Module resolveModuleForPrefix(SchemaContext context, Module module, String prefix) {
719 Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
720 Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
721 Preconditions.checkArgument(prefix != null, "Prefix string cannot be NULL");
723 if (prefix.equals(module.getPrefix())) {
727 Set<ModuleImport> imports = module.getImports();
728 for (ModuleImport mi : imports) {
729 if (prefix.equals(mi.getPrefix())) {
730 return context.findModuleByName(mi.getModuleName(), mi.getRevision());
737 * @throws IllegalArgumentException
743 * @param relativeXPath
744 * Non conditional Revision Aware Relative XPath
745 * @param leafrefSchemaPath
746 * Schema Path for Leafref
747 * @return list of QName
749 private static List<QName> resolveRelativeXPath(SchemaContext context, Module module,
750 RevisionAwareXPath relativeXPath, SchemaNode leafrefParentNode) {
751 Preconditions.checkArgument(context != null, "Schema Context reference cannot be NULL");
752 Preconditions.checkArgument(module != null, "Module reference cannot be NULL");
753 Preconditions.checkArgument(relativeXPath != null, "Non Conditional Revision Aware XPath cannot be NULL");
754 Preconditions.checkState(!relativeXPath.isAbsolute(),
755 "Revision Aware XPath MUST be relative i.e. MUST contains ../, "
756 + "for non relative Revision Aware XPath use findDataSchemaNode method");
757 Preconditions.checkState(leafrefParentNode.getPath() != null,
758 "Schema Path reference for Leafref cannot be NULL");
760 List<QName> absolutePath = new LinkedList<QName>();
761 String strXPath = relativeXPath.toString();
762 String[] xpaths = strXPath.split("/");
765 while (xpaths[colCount].contains("..")) {
766 colCount = colCount + 1;
768 List<QName> path = leafrefParentNode.getPath().getPath();
770 int lenght = path.size() - colCount;
771 absolutePath.addAll(path.subList(0, lenght));
772 List<String> xpathsList = Arrays.asList(xpaths);
773 List<String> sublistedXPath = xpathsList.subList(colCount, xpaths.length);
774 List<QName> sublist = new ArrayList<>();
775 for (String pathPart : sublistedXPath) {
776 sublist.add(stringPathPartToQName(context, module, pathPart));
778 absolutePath.addAll(sublist);