[ONOS-4636]grouping and uses
Change-Id: Ic410d03a838003ad23b2b0e8874b91503da84153
diff --git a/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/TraversalType.java b/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/TraversalType.java
new file mode 100644
index 0000000..e1a25c6
--- /dev/null
+++ b/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/TraversalType.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2016-present Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.yangutils.datamodel;
+
+/**
+ * Represents data model tree traversal types.
+ */
+public enum TraversalType {
+
+ /**
+ * Start of traversal at the tree root.
+ */
+ ROOT,
+
+ /**
+ * Child node traversal.
+ */
+ CHILD,
+
+ /**
+ * Sibling node traversal.
+ */
+ SIBILING,
+
+ /**
+ * Parent node traversal.
+ */
+ PARENT
+}
diff --git a/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/YangNode.java b/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/YangNode.java
index 820b0b4..7a963f5 100644
--- a/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/YangNode.java
+++ b/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/YangNode.java
@@ -17,6 +17,13 @@
import java.io.Serializable;
import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
+import org.onosproject.yangutils.datamodel.utils.Parsable;
+
+import static org.onosproject.yangutils.datamodel.TraversalType.CHILD;
+import static org.onosproject.yangutils.datamodel.TraversalType.PARENT;
+import static org.onosproject.yangutils.datamodel.TraversalType.SIBILING;
+import static org.onosproject.yangutils.datamodel.utils.DataModelUtils.cloneLeaves;
+import static org.onosproject.yangutils.datamodel.utils.DataModelUtils.updateClonedLeavesUnionEnumRef;
/**
* Represents base class of a node in data model tree.
@@ -226,4 +233,189 @@
newChild.setPreviousSibling(curNode);
}
}
+
+ /**
+ * Clones the current node contents and create a new node.
+ *
+ * @return cloned node
+ * @throws CloneNotSupportedException clone is not supported by the referred
+ * node
+ */
+ public YangNode clone()
+ throws CloneNotSupportedException {
+ YangNode clonedNode = (YangNode) super.clone();
+ if (clonedNode instanceof YangLeavesHolder) {
+ try {
+ cloneLeaves((YangLeavesHolder) clonedNode);
+ } catch (DataModelException e) {
+ throw new CloneNotSupportedException(e.getMessage());
+ }
+ }
+
+ clonedNode.setParent(null);
+ clonedNode.setChild(null);
+ clonedNode.setNextSibling(null);
+ clonedNode.setPreviousSibling(null);
+ return clonedNode;
+ }
+
+ /**
+ * Clones the subtree from the specified source node to the mentioned target
+ * node. The source and target root node cloning is carried out by the
+ * caller.
+ *
+ * @param srcRootNode source node for sub tree cloning
+ * @param dstRootNode destination node where the sub tree needs to be cloned
+ * @throws DataModelException data model error
+ */
+ public static void cloneSubTree(YangNode srcRootNode, YangNode dstRootNode)
+ throws DataModelException {
+
+ YangNode nextNodeToClone = srcRootNode;
+ TraversalType curTraversal;
+
+ YangNode clonedTreeCurNode = dstRootNode;
+ YangNode newNode = null;
+
+ nextNodeToClone = nextNodeToClone.getChild();
+ if (nextNodeToClone == null) {
+ return;
+ } else {
+ /**
+ * Root level cloning is taken care in the caller.
+ */
+ curTraversal = CHILD;
+ }
+
+ /**
+ * Caller ensures the cloning of the root nodes
+ */
+ try {
+ while (nextNodeToClone != srcRootNode) {
+ if (nextNodeToClone == null) {
+ throw new DataModelException("Internal error: Cloning failed, source tree null pointer reached");
+ }
+ if (curTraversal != PARENT) {
+ newNode = nextNodeToClone.clone();
+ detectCollisionWhileCloning(clonedTreeCurNode, newNode, curTraversal);
+ }
+
+ if (curTraversal == CHILD) {
+
+ /**
+ * add the new node to the cloned tree.
+ */
+ clonedTreeCurNode.addChild(newNode);
+
+ /**
+ * update the cloned tree's traversal current node as the
+ * new node.
+ */
+ clonedTreeCurNode = newNode;
+ } else if (curTraversal == SIBILING) {
+
+ clonedTreeCurNode.addNextSibling(newNode);
+ clonedTreeCurNode = newNode;
+ } else if (curTraversal == PARENT) {
+ if (clonedTreeCurNode instanceof YangLeavesHolder) {
+ updateClonedLeavesUnionEnumRef((YangLeavesHolder) clonedTreeCurNode);
+ }
+ clonedTreeCurNode = clonedTreeCurNode.getParent();
+ }
+
+ if (curTraversal != PARENT && nextNodeToClone.getChild() != null) {
+ curTraversal = CHILD;
+
+ /**
+ * update the traversal's current node.
+ */
+ nextNodeToClone = nextNodeToClone.getChild();
+
+ } else if (nextNodeToClone.getNextSibling() != null) {
+
+ curTraversal = SIBILING;
+
+ nextNodeToClone = nextNodeToClone.getNextSibling();
+ } else {
+ curTraversal = PARENT;
+ nextNodeToClone = nextNodeToClone.getParent();
+ }
+ }
+ } catch (CloneNotSupportedException e) {
+ throw new DataModelException("Failed to clone the tree");
+ }
+
+ }
+
+ /**
+ * Detects collision when the grouping is deep copied to the uses's parent.
+ *
+ * @param currentNode parent/previous sibling node for the new node
+ * @param newNode node which has to be added
+ * @param addAs traversal type of the node
+ * @throws DataModelException data model error
+ */
+ private static void detectCollisionWhileCloning(YangNode currentNode, YangNode newNode, TraversalType addAs)
+ throws DataModelException {
+ if (!(currentNode instanceof CollisionDetector)
+ || !(newNode instanceof Parsable)) {
+ throw new DataModelException("Node in data model tree does not support collision detection");
+ }
+
+ CollisionDetector collisionDetector = (CollisionDetector) currentNode;
+ Parsable parsable = (Parsable) newNode;
+ if (addAs == TraversalType.CHILD) {
+ collisionDetector.detectCollidingChild(newNode.getName(), parsable.getYangConstructType());
+ } else if (addAs == TraversalType.SIBILING) {
+ currentNode = currentNode.getParent();
+ if (!(currentNode instanceof CollisionDetector)) {
+ throw new DataModelException("Node in data model tree does not support collision detection");
+ }
+ collisionDetector = (CollisionDetector) currentNode;
+ collisionDetector.detectCollidingChild(newNode.getName(), parsable.getYangConstructType());
+ } else {
+ throw new DataModelException("Errored tree cloning");
+ }
+
+ }
+
+ /**
+ * Adds a new next sibling.
+ *
+ * @param newSibling new sibling to be added
+ * @throws DataModelException data model error
+ */
+ private void addNextSibling(YangNode newSibling)
+ throws DataModelException {
+
+ if (newSibling.getNodeType() == null) {
+ throw new DataModelException("Cloned abstract node cannot be inserted into a tree");
+ }
+
+ if (newSibling.getParent() == null) {
+ /**
+ * Since the siblings needs to have a common parent, set the parent
+ * as the current node's parent
+ */
+ newSibling.setParent(getParent());
+
+ } else {
+ throw new DataModelException("Node is already part of a tree, and cannot be added as a sibling");
+ }
+
+ if (newSibling.getPreviousSibling() == null) {
+ newSibling.setPreviousSibling(this);
+ setNextSibling(newSibling);
+ } else {
+ throw new DataModelException("New sibling to be added is not atomic, it already has a previous sibling");
+ }
+
+ if (newSibling.getChild() != null) {
+ throw new DataModelException("Sibling to be added is not atomic, it already has a child");
+ }
+
+ if (newSibling.getNextSibling() != null) {
+ throw new DataModelException("Sibling to be added is not atomic, it already has a next sibling");
+ }
+ }
}
diff --git a/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/YangUses.java b/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/YangUses.java
index 6f7137d..51cd310 100644
--- a/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/YangUses.java
+++ b/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/YangUses.java
@@ -25,6 +25,7 @@
import static org.onosproject.yangutils.datamodel.utils.DataModelUtils.detectCollidingChildUtil;
import static org.onosproject.yangutils.datamodel.utils.DataModelUtils.getParentNodeInGenCode;
+import static org.onosproject.yangutils.datamodel.utils.DataModelUtils.updateClonedLeavesUnionEnumRef;
/*-
* Reference RFC 6020.
@@ -329,42 +330,45 @@
}
YangLeavesHolder usesParentLeavesHolder = (YangLeavesHolder) usesParentNode;
- if (referredGrouping.getListOfLeaf() != null
- && referredGrouping.getListOfLeaf().size() != 0) {
- addLeavesOfGrouping(
- cloneLeavesList(referredGrouping.getListOfLeaf(),
- usesParentLeavesHolder));
- }
+ if (referredGrouping.getListOfLeaf() != null) {
+ for (YangLeaf leaf : referredGrouping.getListOfLeaf()) {
+ YangLeaf clonedLeaf = null;
+ try {
+ ((CollisionDetector) usesParentLeavesHolder).detectCollidingChild(leaf.getName(),
+ YangConstructType.LEAF_DATA);
+ clonedLeaf = leaf.clone();
- if (referredGrouping.getListOfLeafList() != null
- && referredGrouping.getListOfLeafList().size() != 0) {
- addListOfLeafListOfGrouping(
- cloneListOfLeafList(referredGrouping.getListOfLeafList(),
- usesParentLeavesHolder));
- }
+ } catch (CloneNotSupportedException | DataModelException e) {
+ throw new DataModelException(e.getMessage());
+ }
- YangNode childInGrouping = referredGrouping.getChild();
-
- while (childInGrouping != null) {
- if (childInGrouping instanceof YangEnumeration
- || childInGrouping instanceof YangUnion
- || childInGrouping instanceof YangTypeDef) {
-
- /*
- * No need to copy the leaves, union / enum class, as these will
- * be generated in the scope of grouping
- */
- childInGrouping = childInGrouping.getNextSibling();
- continue;
- } else if (childInGrouping instanceof YangUses) {
- addResolvedUsesInfoOfGrouping((YangUses) childInGrouping,
- usesParentLeavesHolder);
- } else {
- addNodeOfGrouping(childInGrouping);
+ clonedLeaf.setContainedIn(usesParentLeavesHolder);
+ usesParentLeavesHolder.addLeaf(clonedLeaf);
}
-
- childInGrouping = childInGrouping.getNextSibling();
}
+ if (referredGrouping.getListOfLeafList() != null) {
+ for (YangLeafList leafList : referredGrouping.getListOfLeafList()) {
+ YangLeafList clonedLeafList = null;
+ try {
+ ((CollisionDetector) usesParentLeavesHolder).detectCollidingChild(leafList.getName(),
+ YangConstructType.LEAF_LIST_DATA);
+ clonedLeafList = leafList.clone();
+
+ } catch (CloneNotSupportedException | DataModelException e) {
+ throw new DataModelException(e.getMessage());
+ }
+
+ clonedLeafList.setContainedIn(usesParentLeavesHolder);
+ usesParentLeavesHolder.addLeafList(clonedLeafList);
+ }
+ }
+
+ try {
+ YangNode.cloneSubTree(referredGrouping, usesParentNode);
+ } catch (DataModelException e) {
+ throw new DataModelException(e.getMessage());
+ }
+ updateClonedLeavesUnionEnumRef(usesParentLeavesHolder);
}
/**
diff --git a/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/utils/DataModelUtils.java b/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/utils/DataModelUtils.java
index 410e025..1e15d1d 100644
--- a/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/utils/DataModelUtils.java
+++ b/utils/yangutils/datamodel/src/main/java/org/onosproject/yangutils/datamodel/utils/DataModelUtils.java
@@ -20,6 +20,7 @@
import java.io.IOException;
import java.io.ObjectInputStream;
import java.util.ArrayList;
+import java.util.LinkedList;
import java.util.List;
import java.util.Set;
@@ -28,6 +29,7 @@
import org.onosproject.yangutils.datamodel.YangIfFeature;
import org.onosproject.yangutils.datamodel.YangAugment;
import org.onosproject.yangutils.datamodel.YangBase;
+import org.onosproject.yangutils.datamodel.YangEnumeration;
import org.onosproject.yangutils.datamodel.YangIdentityRef;
import org.onosproject.yangutils.datamodel.YangLeaf;
import org.onosproject.yangutils.datamodel.YangLeafList;
@@ -38,8 +40,10 @@
import org.onosproject.yangutils.datamodel.YangResolutionInfo;
import org.onosproject.yangutils.datamodel.YangRpc;
import org.onosproject.yangutils.datamodel.YangType;
+import org.onosproject.yangutils.datamodel.YangUnion;
import org.onosproject.yangutils.datamodel.YangUses;
import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
+import org.onosproject.yangutils.datamodel.utils.builtindatatype.YangDataTypes;
/**
* Represents utilities for data model tree.
@@ -307,4 +311,104 @@
}
return nodes;
}
+
+ /**
+ * Clones the list of leaves and list of leaf list in the leaves holder.
+ *
+ * @param leavesHolder YANG node potentially containing leaves or leaf lists
+ * @throws CloneNotSupportedException clone is not supported
+ * @throws DataModelException data model error
+ */
+ public static void cloneLeaves(YangLeavesHolder leavesHolder)
+ throws CloneNotSupportedException, DataModelException {
+ List<YangLeaf> currentListOfLeaves = leavesHolder.getListOfLeaf();
+ if (currentListOfLeaves != null) {
+ List<YangLeaf> clonedLeavesList = new LinkedList<YangLeaf>();
+ for (YangLeaf leaf : currentListOfLeaves) {
+ YangLeaf clonedLeaf = leaf.clone();
+ clonedLeaf.setContainedIn(leavesHolder);
+ clonedLeavesList.add(clonedLeaf);
+ }
+ leavesHolder.setListOfLeaf(clonedLeavesList);
+ }
+
+ List<YangLeafList> currentListOfLeafList = leavesHolder.getListOfLeafList();
+ if (currentListOfLeafList != null) {
+ List<YangLeafList> clonedListOfLeafList = new LinkedList<YangLeafList>();
+ for (YangLeafList leafList : currentListOfLeafList) {
+ YangLeafList clonedLeafList = leafList.clone();
+ clonedLeafList.setContainedIn(leavesHolder);
+ clonedListOfLeafList.add(clonedLeafList);
+ }
+ leavesHolder.setListOfLeafList(clonedListOfLeafList);
+ }
+ }
+
+ /**
+ * Clones the union or enum leaves. If there is any cloned leaves whose type is union/enum then the corresponding
+ * type info needs to be updated to the cloned new type node.
+ *
+ * @param leavesHolder cloned leaves holder, for whom the leaves reference needs to be updated
+ */
+ public static void updateClonedLeavesUnionEnumRef(YangLeavesHolder leavesHolder) throws DataModelException {
+ List<YangLeaf> currentListOfLeaves = leavesHolder.getListOfLeaf();
+ if (currentListOfLeaves != null) {
+ for (YangLeaf leaf : currentListOfLeaves) {
+ if (leaf.getDataType().getDataType() == YangDataTypes.ENUMERATION
+ || leaf.getDataType().getDataType() == YangDataTypes.UNION) {
+ try {
+ updateClonedTypeRef(leaf.getDataType(), leavesHolder);
+ } catch (DataModelException e) {
+ throw e;
+ }
+ }
+ }
+
+ }
+
+ List<YangLeafList> currentListOfLeafList = leavesHolder.getListOfLeafList();
+ if (currentListOfLeafList != null) {
+ for (YangLeafList leafList : currentListOfLeafList) {
+ if (leafList.getDataType().getDataType() == YangDataTypes.ENUMERATION
+ || leafList.getDataType().getDataType() == YangDataTypes.UNION) {
+ try {
+ updateClonedTypeRef(leafList.getDataType(), leavesHolder);
+ } catch (DataModelException e) {
+ throw e;
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Updates the types extended info pointer to point to the cloned type node.
+ *
+ * @param dataType data type, whose extended info needs to be pointed to the cloned type
+ * @param leavesHolder the leaves holder having the cloned type
+ */
+ private static void updateClonedTypeRef(YangType dataType, YangLeavesHolder leavesHolder)
+ throws DataModelException {
+ if (!(leavesHolder instanceof YangNode)) {
+ throw new DataModelException("Data model error: cloned leaves holder is not a node");
+ }
+ YangNode potentialTypeNode = ((YangNode) leavesHolder).getChild();
+ while (potentialTypeNode != null) {
+ String dataTypeName = null;
+ if (dataType.getDataType() == YangDataTypes.ENUMERATION) {
+ YangEnumeration enumNode = (YangEnumeration) dataType.getDataTypeExtendedInfo();
+ dataTypeName = enumNode.getName();
+ } else if (dataType.getDataType() == YangDataTypes.UNION) {
+ YangUnion unionNode = (YangUnion) dataType.getDataTypeExtendedInfo();
+ dataTypeName = unionNode.getName();
+ }
+ if (potentialTypeNode.getName().contentEquals(dataTypeName)) {
+ dataType.setDataTypeExtendedInfo((Object) potentialTypeNode);
+ return;
+ }
+ potentialTypeNode = potentialTypeNode.getNextSibling();
+ }
+
+ throw new DataModelException("Data model error: cloned leaves type is not found");
+ }
}