[ONOS-5483] Leafref with path-predicate linking.
Change-Id: Id1f95e7b82de9d0b9b1717b8a0f96fb8d03939b1
diff --git a/generator/src/main/java/org/onosproject/yangutils/linker/impl/YangLinkerUtils.java b/generator/src/main/java/org/onosproject/yangutils/linker/impl/YangLinkerUtils.java
index 507ebf3..aa55b96 100644
--- a/generator/src/main/java/org/onosproject/yangutils/linker/impl/YangLinkerUtils.java
+++ b/generator/src/main/java/org/onosproject/yangutils/linker/impl/YangLinkerUtils.java
@@ -32,9 +32,12 @@
import org.onosproject.yangutils.datamodel.YangLeafList;
import org.onosproject.yangutils.datamodel.YangLeafRef;
import org.onosproject.yangutils.datamodel.YangLeavesHolder;
+import org.onosproject.yangutils.datamodel.YangList;
import org.onosproject.yangutils.datamodel.YangNode;
import org.onosproject.yangutils.datamodel.YangNodeIdentifier;
+import org.onosproject.yangutils.datamodel.YangPathPredicate;
import org.onosproject.yangutils.datamodel.YangReferenceResolver;
+import org.onosproject.yangutils.datamodel.YangRelativePath;
import org.onosproject.yangutils.datamodel.YangType;
import org.onosproject.yangutils.datamodel.YangTypeDef;
import org.onosproject.yangutils.datamodel.YangUses;
@@ -54,7 +57,6 @@
import static org.onosproject.yangutils.datamodel.TraversalType.PARENT;
import static org.onosproject.yangutils.datamodel.TraversalType.ROOT;
import static org.onosproject.yangutils.datamodel.TraversalType.SIBILING;
-import static org.onosproject.yangutils.datamodel.exceptions.ErrorMessages.CASE;
import static org.onosproject.yangutils.datamodel.exceptions.ErrorMessages.COLLISION_DETECTION;
import static org.onosproject.yangutils.datamodel.exceptions.ErrorMessages.FAILED_TO_ADD_CASE;
import static org.onosproject.yangutils.datamodel.exceptions.ErrorMessages.TARGET_NODE;
@@ -74,6 +76,7 @@
import static org.onosproject.yangutils.utils.UtilConstants.FEATURE_LINKER_ERROR;
import static org.onosproject.yangutils.utils.UtilConstants.GROUPING_LINKER_ERROR;
import static org.onosproject.yangutils.utils.UtilConstants.IDENTITYREF_LINKER_ERROR;
+import static org.onosproject.yangutils.utils.UtilConstants.INVALID_TREE;
import static org.onosproject.yangutils.utils.UtilConstants.IS_INVALID;
import static org.onosproject.yangutils.utils.UtilConstants.LEAFREF_ERROR;
import static org.onosproject.yangutils.utils.UtilConstants.LEAFREF_LINKER_ERROR;
@@ -85,9 +88,24 @@
public final class YangLinkerUtils {
private static final int IDENTIFIER_LENGTH = 64;
- private static final Pattern IDENTIFIER_PATTERN = Pattern.compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
+ private static final Pattern IDENTIFIER_PATTERN =
+ Pattern.compile("[a-zA-Z_][a-zA-Z0-9_.-]*");
private static final String XML = "xml";
+ private static final String INVALID_PATH_PRE =
+ "YANG file error: The path predicate of the leafref has an " +
+ "invalid path in ";
+ private static final String EMPTY_PATH_LIST_ERR =
+ "YANG file error : The atomic path list cannot be empty of the " +
+ "leafref in the path ";
+ private static final String TGT_LEAF_ERR =
+ "YANG file error: There is no leaf/leaf-list in YANG node as " +
+ "mentioned in the path predicate of the leafref path ";
+ private static final String LEAF_REF_LIST_ERR =
+ "YANG file error: Path predicates are only applicable for YANG " +
+ "list. The leafref path has path predicate for non-list " +
+ "node in the path ";
+ // No instantiation.
private YangLinkerUtils() {
}
@@ -257,33 +275,6 @@
.getFileName());
}
- //Detect collision between augment and choice children.
- private void detectCollisionForChoiceNode(YangNode choice, YangNode augment) {
- YangNode choiceChild = choice.getChild();
- YangNode augmentChild = augment.getChild();
-
- List<YangNode> choiceChildren = new ArrayList<>();
- List<YangNode> augmentChildren = new ArrayList<>();
- while (choiceChild != null) {
- choiceChildren.add(choiceChild);
- }
- while (augmentChild != null) {
- augmentChildren.add(augmentChild);
- }
-
- for (YangNode cChild : choiceChildren) {
- for (YangNode aChild : augmentChildren) {
- if (cChild.getName().equals(aChild.getName())) {
- ;
- throw new LinkerException(getErrorMsgCollision(
- COLLISION_DETECTION, cChild.getName(),
- cChild.getLineNumber(), cChild.getCharPosition(),
- CASE, cChild.getFileName()));
- }
- }
- }
- }
-
/**
* Detects collision between target nodes and its all leaf/leaf-list or child node with augmented leaf/leaf-list or
* child node.
@@ -328,25 +319,25 @@
/**
* Skips the invalid nodes which cannot have data from YANG.
*
- * @param currentParent current parent node reference
- * @param leafref instance of YANG leafref
+ * @param curParent current parent
+ * @param leafRef YANG leaf-ref
* @return parent node which can hold data
- * @throws LinkerException a violation of linker rules
+ * @throws LinkerException if linker rules are violated
*/
- static YangNode skipInvalidDataNodes(YangNode currentParent, YangLeafRef leafref)
+ public static YangNode skipInvalidDataNodes(YangNode curParent,
+ YangLeafRef leafRef)
throws LinkerException {
- while (currentParent instanceof YangChoice || currentParent instanceof YangCase) {
- if (currentParent.getParent() == null) {
- LinkerException ex = new LinkerException(
- LEAFREF_ERROR + leafref.getPath() + IS_INVALID);
- ex.setCharPosition(leafref.getCharPosition());
- ex.setLine(leafref.getLineNumber());
- ex.setFileName(leafref.getFileName());
- throw ex;
+
+ YangNode node = curParent;
+ while (node instanceof YangChoice ||
+ node instanceof YangCase) {
+
+ if (node.getParent() == null) {
+ throw new LinkerException(getLeafRefErrorInfo(leafRef));
}
- currentParent = currentParent.getParent();
+ node = node.getParent();
}
- return currentParent;
+ return node;
}
/**
@@ -610,4 +601,254 @@
}
}
+ /**
+ * Fills the path predicates of the leaf-ref with right axis node and
+ * left axis node, after linking the nodes.
+ *
+ * @param leafRef YANG leaf-ref
+ * @throws DataModelException if there is a data model error
+ */
+ public static void fillPathPredicates(YangLeafRef<?> leafRef)
+ throws DataModelException {
+
+ List<YangAtomicPath> atomics = leafRef.getAtomicPath();
+ if (atomics != null) {
+ for (YangAtomicPath atom : atomics) {
+ List<YangPathPredicate> predicates =
+ atom.getPathPredicatesList();
+
+ if (predicates != null) {
+ for (YangPathPredicate predicate : predicates) {
+ setLeftAxisNode(leafRef, atom, predicate);
+ setRightAxisNode(leafRef, predicate);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Sets the left axis node in the YANG path predicate after finding it
+ * under the YANG list node.
+ *
+ * @param leafRef YANG leaf-ref
+ * @param atom atomic path content
+ * @param predicate predicate in the atomic path
+ * @throws DataModelException if there is a data model error
+ */
+ private static void setLeftAxisNode(YangLeafRef<?> leafRef,
+ YangAtomicPath atom,
+ YangPathPredicate predicate)
+ throws DataModelException {
+ YangNode resolvedNode = atom.getResolvedNode();
+ if (!(resolvedNode instanceof YangList)) {
+ throw getDataModelExc(LEAF_REF_LIST_ERR, leafRef);
+ }
+
+ YangNodeIdentifier leftAxisName = predicate.getNodeId();
+ Object target = getTarget(leftAxisName, resolvedNode, leafRef);
+ predicate.setLeftAxisNode(target);
+ }
+
+ /**
+ * Returns the target leaf/leaf-list from the provided YANG node.
+ *
+ * @param leftAxisName name of node
+ * @param node node having target
+ * @param leafRef YANG leaf-ref
+ * @return target leaf/leaf-list
+ * @throws DataModelException if there is a data model error
+ */
+ private static Object getTarget(YangNodeIdentifier leftAxisName,
+ YangNode node, YangLeafRef leafRef)
+ throws DataModelException {
+
+ YangLeaf leaf = getLeaf(leftAxisName, (YangLeavesHolder) node);
+ if (leaf != null) {
+ return leaf;
+ }
+ YangLeafList leafList = getLeafList(leftAxisName,
+ (YangLeavesHolder) node);
+ if (leafList == null) {
+ throw getDataModelExc(TGT_LEAF_ERR, leafRef);
+ }
+ return leafList;
+ }
+
+ /**
+ * Returns the leaf by searching it in the node by the leaf name. Returns
+ * null when the name doesn't match.
+ *
+ * @param name leaf name
+ * @param holder holder of leaf
+ * @return YANG leaf
+ */
+ private static YangLeaf getLeaf(YangNodeIdentifier name,
+ YangLeavesHolder holder) {
+
+ List<YangLeaf> listOfLeaf = holder.getListOfLeaf();
+ if (listOfLeaf != null) {
+ for (YangLeaf yangLeaf : listOfLeaf) {
+ if (yangLeaf.getName().equals(name.getName())) {
+ return yangLeaf;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the leaf-list by searching it in the node by the leaf-list name.
+ * Returns null when the name doesn't match.
+ *
+ * @param name leaf-list name
+ * @param holder holder of leaf-list
+ * @return YANG leaf-list
+ */
+ private static YangLeafList getLeafList(YangNodeIdentifier name,
+ YangLeavesHolder holder) {
+
+ List<YangLeafList> listOfLeafList = holder.getListOfLeafList();
+ if (listOfLeafList != null) {
+ for (YangLeafList yangLeafList : listOfLeafList) {
+ if (yangLeafList.getName().equals(name.getName())) {
+ return yangLeafList;
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns the root node from which the path with the atomic node names
+ * has to be traversed through. With the ancestor count the nodes are
+ * moved upward.
+ *
+ * @param count ancestor count
+ * @param node current leaf-ref parent
+ * @param leafRef YANG leaf-ref
+ * @return root node from ancestor count
+ * @throws DataModelException if there is a data model error
+ */
+ private static YangNode getRootNode(int count, YangNode node,
+ YangLeafRef leafRef)
+ throws DataModelException {
+
+ YangNode curParent = node;
+ int curCount = 0;
+ while (curCount < count) {
+ curCount = curCount + 1;
+ if (curCount != 1) {
+ if (curParent.getParent() == null) {
+ throw getDataModelExc(INVALID_TREE, leafRef);
+ }
+ curParent = curParent.getParent();
+ }
+ curParent = skipInvalidDataNodes(curParent, leafRef);
+ if (curParent instanceof YangAugment) {
+ YangAugment augment = (YangAugment) curParent;
+ curParent = augment.getAugmentedNode();
+ curCount = curCount + 1;
+ }
+ }
+ return curParent;
+ }
+
+ /**
+ * Returns the last node by traversing through the atomic node id by
+ * leaving the last target leaf/leaf-list.
+ *
+ * @param curNode current node
+ * @param relPath relative path
+ * @param leafRef YANG leaf-ref
+ * @return last YANG node
+ * @throws DataModelException if there is a data model error
+ */
+ private static Object getLastNode(YangNode curNode,
+ YangRelativePath relPath,
+ YangLeafRef leafRef)
+ throws DataModelException {
+
+ YangNode node = curNode;
+ List<YangAtomicPath> atomics = new ArrayList<>();
+ atomics.addAll(relPath.getAtomicPathList());
+
+ if (atomics.isEmpty()) {
+ throw getDataModelExc(EMPTY_PATH_LIST_ERR, leafRef);
+ }
+
+ YangAtomicPath pathTgt = atomics.get(atomics.size() - 1);
+ if (atomics.size() == 1) {
+ return getTarget(pathTgt.getNodeIdentifier(), node, leafRef);
+ }
+
+ atomics.remove(atomics.size() - 1);
+ for (YangAtomicPath atomicPath : atomics) {
+ node = getNode(node.getChild(), atomicPath.getNodeIdentifier());
+ if (node == null) {
+ throw getDataModelExc(INVALID_PATH_PRE, leafRef);
+ }
+ }
+ return getTarget(pathTgt.getNodeIdentifier(), node, leafRef);
+ }
+
+ /**
+ * Returns the node from the parent node by matching it with the atomic
+ * name. If no child node matches the name then it returns null.
+ *
+ * @param curNode current node
+ * @param identifier atomic name
+ * @return node to be traversed
+ */
+ private static YangNode getNode(YangNode curNode,
+ YangNodeIdentifier identifier) {
+ YangNode node = curNode;
+ while (node != null) {
+ if (node.getName().equals(identifier.getName())) {
+ return node;
+ }
+ node = node.getNextSibling();
+ }
+ return null;
+ }
+
+ /**
+ * Sets the right axis node in the YANG path predicate after finding it
+ * from the relative path.
+ *
+ * @param leafRef YANG leaf-ref
+ * @param predicate YANG path predicate
+ * @throws DataModelException if there is a data model error
+ */
+ private static void setRightAxisNode(YangLeafRef leafRef,
+ YangPathPredicate predicate)
+ throws DataModelException {
+
+ YangNode parentNode = leafRef.getParentNode();
+ YangRelativePath relPath = predicate.getRelPath();
+ int ancestor = relPath.getAncestorNodeCount();
+
+ YangNode rootNode = getRootNode(ancestor, parentNode, leafRef);
+ Object target = getLastNode(rootNode, relPath, leafRef);
+ if (target == null) {
+ throw getDataModelExc(INVALID_PATH_PRE, leafRef);
+ }
+ predicate.setRightAxisNode(target);
+ }
+
+ /**
+ * Returns data model error messages for leaf-ref with the path.
+ *
+ * @param msg error message
+ * @param leafRef YANG leaf-ref
+ * @return data model exception
+ */
+ private static DataModelException getDataModelExc(String msg,
+ YangLeafRef leafRef) {
+ DataModelException exc = new DataModelException(
+ msg + leafRef.getPath());
+ exc.setCharPosition(leafRef.getCharPosition());
+ exc.setLine(leafRef.getLineNumber());
+ return exc;
+ }
}
diff --git a/generator/src/main/java/org/onosproject/yangutils/linker/impl/YangResolutionInfoImpl.java b/generator/src/main/java/org/onosproject/yangutils/linker/impl/YangResolutionInfoImpl.java
index 480d8c6..3400cfe 100644
--- a/generator/src/main/java/org/onosproject/yangutils/linker/impl/YangResolutionInfoImpl.java
+++ b/generator/src/main/java/org/onosproject/yangutils/linker/impl/YangResolutionInfoImpl.java
@@ -81,6 +81,7 @@
import static org.onosproject.yangutils.linker.impl.XpathLinkingTypes.AUGMENT_LINKING;
import static org.onosproject.yangutils.linker.impl.XpathLinkingTypes.LEAF_REF_LINKING;
import static org.onosproject.yangutils.linker.impl.YangLinkerUtils.detectCollisionForAugmentedNode;
+import static org.onosproject.yangutils.linker.impl.YangLinkerUtils.fillPathPredicates;
import static org.onosproject.yangutils.linker.impl.YangLinkerUtils.getErrorInfoForLinker;
import static org.onosproject.yangutils.linker.impl.YangLinkerUtils.getLeafRefErrorInfo;
import static org.onosproject.yangutils.linker.impl.YangLinkerUtils.getPathWithAugment;
@@ -294,7 +295,7 @@
YangLeafRef leafRefInTypeDef = (YangLeafRef) extendedInfo;
addRefTypeInfo(YangDataTypes.LEAFREF, LEAFREF, extendedInfo,
yangType, refNode, YANG_LEAFREF);
- leafRefInTypeDef.setParentNodeOfLeafref(refNode);
+ leafRefInTypeDef.setParentNode(refNode);
} else {
addRefTypeInfo(YangDataTypes.IDENTITYREF, IDENTITYREF, extendedInfo,
yangType, refNode, YANG_IDENTITYREF);
@@ -379,7 +380,7 @@
.getEntityToResolve();
YangNode parentNodeOfLeafref = entityToResolveInfo
.getHolderOfEntityToResolve();
- leafref.setParentNodeOfLeafref(parentNodeOfLeafref);
+ leafref.setParentNode(parentNodeOfLeafref);
if (leafref.getResolvableStatus() == UNRESOLVED) {
leafref.setResolvableStatus(INTRA_FILE_RESOLVED);
}
@@ -1018,9 +1019,11 @@
*
* @param entityToResolve entity to resolve
* @param root root node
+ * @throws DataModelException if there is a data model error
*/
private void processXPathLinking(T entityToResolve,
- YangReferenceResolver root) {
+ YangReferenceResolver root)
+ throws DataModelException {
YangXpathLinker<T> xPathLinker = new YangXpathLinker<T>();
@@ -1094,7 +1097,7 @@
addUnResolvedLeafRefTypeToStack(
(T) leafList, entityToResolveInfo.getHolderOfEntityToResolve());
}
- //TODO: add logic for leaf-ref for path predicates.
+ fillPathPredicates(leafRef);
} else {
LinkerException ex = new LinkerException(
FAILED_TO_FIND_LEAD_INFO_HOLDER + leafRef.getPath());
@@ -1266,7 +1269,7 @@
if (resolutionInfo instanceof YangLeafRef) {
YangNode leafParent = ((YangLeafRef) resolutionInfo)
- .getParentNodeOfLeafref();
+ .getParentNode();
YangLeafRef leafref = (YangLeafRef) resolutionInfo;
// Checks if the leafref has relative path in it.
diff --git a/generator/src/main/java/org/onosproject/yangutils/utils/UtilConstants.java b/generator/src/main/java/org/onosproject/yangutils/utils/UtilConstants.java
index d73a0d6..48ea81d 100644
--- a/generator/src/main/java/org/onosproject/yangutils/utils/UtilConstants.java
+++ b/generator/src/main/java/org/onosproject/yangutils/utils/UtilConstants.java
@@ -631,12 +631,12 @@
/**
* Static attribute for ancestor accessor.
*/
- public static final String ANCESTOR_ACCESSOR = "..";
+ public static final String ANCESTOR = "..";
/**
* Static attribute for ancestor accessor along with path.
*/
- public static final String ANCESTOR_ACCESSOR_IN_PATH = "../";
+ public static final String SLASH_ANCESTOR = "../";
/**
* Static attribute for add syntax.