YANG uses Intra file linking

Change-Id: I45936bee910ba4c81805f59daf2702bea5e60d08
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/Resolvable.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/Resolvable.java
index ab3462f..e05f4a9 100644
--- a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/Resolvable.java
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/Resolvable.java
@@ -16,6 +16,8 @@
 
 package org.onosproject.yangutils.datamodel;
 
+import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
+
 /**
  * Abstraction of YANG resolvable information. Abstracted to obtain the
  * information required for linking resolution.
@@ -44,6 +46,9 @@
 
     /**
      * Resolves the linking.
+     *
+     * @throws DataModelException data model error
      */
-    void resolve();
+    void resolve()
+            throws DataModelException;
 }
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangNode.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangNode.java
index beb8aa6..0413e653 100644
--- a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangNode.java
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangNode.java
@@ -16,11 +16,17 @@
 package org.onosproject.yangutils.datamodel;
 
 import org.onosproject.yangutils.datamodel.exceptions.DataModelException;
+import org.onosproject.yangutils.translator.tojava.TraversalType;
+
+import static org.onosproject.yangutils.translator.tojava.TraversalType.CHILD;
+import static org.onosproject.yangutils.translator.tojava.TraversalType.PARENT;
+import static org.onosproject.yangutils.translator.tojava.TraversalType.SIBILING;
 
 /**
  * Represents base class of a node in data model tree.
  */
-public abstract class YangNode {
+public abstract class YangNode
+        implements Cloneable {
 
     /**
      * Type of node.
@@ -146,7 +152,7 @@
      *
      * @param sibling YANG node
      */
-    public void setNextSibling(YangNode sibling) {
+    private void setNextSibling(YangNode sibling) {
         nextSibling = sibling;
     }
 
@@ -164,7 +170,7 @@
      *
      * @param previousSibling points to predecessor sibling
      */
-    public void setPreviousSibling(YangNode previousSibling) {
+    private void setPreviousSibling(YangNode previousSibling) {
         this.previousSibling = previousSibling;
     }
 
@@ -175,7 +181,8 @@
      * @param newChild refers to a child to be added
      * @throws DataModelException due to violation in data model rules
      */
-    public void addChild(YangNode newChild) throws DataModelException {
+    public void addChild(YangNode newChild)
+            throws DataModelException {
         if (newChild.getNodeType() == null) {
             throw new DataModelException("Abstract node cannot be inserted into a tree");
         }
@@ -207,24 +214,10 @@
         YangNode curNode;
         curNode = getChild();
 
-        /*-
-         *  If the new node needs to be the first child
-        if (newChild.getNodeType().ordinal() < curNode.getNodeType().ordinal()) {
-            newChild.setNextSibling(curNode);
-            curNode.setPreviousSibling(newChild);
-            setChild(newChild);
-            return;
-        }
-         */
-
         /*
          * Get the predecessor child of new child
          */
-        while (curNode.getNextSibling() != null
-        /*
-         * && newChild.getNodeType().ordinal() >=
-         * curNode.getNextSibling().getNodeType().ordinal()
-         */) {
+        while (curNode.getNextSibling() != null) {
 
             curNode = curNode.getNextSibling();
         }
@@ -233,16 +226,143 @@
         if (curNode.getNextSibling() == null) {
             curNode.setNextSibling(newChild);
             newChild.setPreviousSibling(curNode);
+        }
+    }
+
+    /**
+     * Clone 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();
+        clonedNode.setParent(null);
+        clonedNode.setChild(null);
+        clonedNode.setNextSibling(null);
+        clonedNode.setPreviousSibling(null);
+        return clonedNode;
+    }
+
+    /**
+     * Clone 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;
         }
 
-        /*-
-         *  Insert the new node in child node list sorted by type
-        newChild.setNextSibling(curNode.getNextSibling());
-        newChild.setPreviousSibling(curNode);
-        curNode.getNextSibling().setPreviousSibling(newChild);
-        curNode.setNextSibling(newChild);
-        return;
+        /**
+         * 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 == CHILD) {
+                    newNode = nextNodeToClone.clone();
+
+                    /**
+                     * add the new node to the cloned tree.
+                     */
+                    clonedTreeCurNode.addChild(newNode);
+
+                    /**
+                     * update the cloned tree's travesal current node as the new node.
+                     */
+                    clonedTreeCurNode = newNode;
+                } else if (curTraversal == SIBILING) {
+                    newNode = nextNodeToClone.clone();
+
+                    clonedTreeCurNode.addNextSibling(newNode);
+                    clonedTreeCurNode = newNode;
+                } else if (curTraversal == PARENT) {
+                    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");
+        }
+
+    }
+
+    /**
+     * Add 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(this.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/src/main/java/org/onosproject/yangutils/datamodel/YangResolutionInfo.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangResolutionInfo.java
index c9c0064..9f54254 100644
--- a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangResolutionInfo.java
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangResolutionInfo.java
@@ -190,7 +190,8 @@
     /**
      * Resolve the current entity in the stack.
      */
-    private void resolveTopOfStack() {
+    private void resolveTopOfStack()
+            throws DataModelException {
         ((Resolvable) getCurrentEntityToResolveFromStack()).resolve();
 
         if (((Resolvable) getCurrentEntityToResolveFromStack()).getResolvableStatus()
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangUses.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangUses.java
index 22b9700..7f9b4a3 100644
--- a/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangUses.java
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/datamodel/YangUses.java
@@ -19,6 +19,8 @@
 import org.onosproject.yangutils.parser.Parsable;
 import org.onosproject.yangutils.utils.YangConstructType;
 
+import static org.onosproject.yangutils.translator.tojava.utils.JavaIdentifierSyntax.getParentNodeInGenCode;
+
 /*-
  * Reference RFC 6020.
  *
@@ -255,8 +257,33 @@
     }
 
     @Override
-    public void resolve() {
-        //TODO: implement the method.
+    public void resolve()
+            throws DataModelException {
+
+        YangGrouping referredGrouping = getRefGroup();
+
+        if (referredGrouping == null) {
+            throw new DataModelException("YANG uses linker error, cannot resolve uses");
+        }
+
+        YangNode usesParentNode = getParentNodeInGenCode(this);
+        if (!(usesParentNode instanceof YangLeavesHolder)) {
+            throw new DataModelException("YANG uses holder construct is wrong");
+        }
+
+        YangLeavesHolder usesParentLeavesHolder = (YangLeavesHolder) usesParentNode;
+        if (referredGrouping.getListOfLeaf() != null) {
+            for (YangLeaf leaf : referredGrouping.getListOfLeaf()) {
+                usesParentLeavesHolder.addLeaf(leaf);
+            }
+        }
+        if (referredGrouping.getListOfLeafList() != null) {
+            for (YangLeafList leafList : referredGrouping.getListOfLeafList()) {
+                usesParentLeavesHolder.addLeafList(leafList);
+            }
+        }
+
+        YangNode.cloneSubTree(getRefGroup(), usesParentNode);
     }
 
     @Override
diff --git a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/listeners/ContainerListener.java b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/listeners/ContainerListener.java
index f7dbf8c..643499f 100644
--- a/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/listeners/ContainerListener.java
+++ b/utils/yangutils/src/main/java/org/onosproject/yangutils/parser/impl/listeners/ContainerListener.java
@@ -19,6 +19,7 @@
 import org.onosproject.yangutils.datamodel.YangAugment;
 import org.onosproject.yangutils.datamodel.YangCase;
 import org.onosproject.yangutils.datamodel.YangContainer;
+import org.onosproject.yangutils.datamodel.YangGrouping;
 import org.onosproject.yangutils.datamodel.YangInput;
 import org.onosproject.yangutils.datamodel.YangList;
 import org.onosproject.yangutils.datamodel.YangModule;
@@ -37,8 +38,10 @@
 import static org.onosproject.yangutils.parser.impl.parserutils.ListenerCollisionDetector.detectCollidingChildUtil;
 import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorLocation.ENTRY;
 import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorLocation.EXIT;
-import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorMessageConstruction.constructExtendedListenerErrorMessage;
-import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorMessageConstruction.constructListenerErrorMessage;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorMessageConstruction
+        .constructExtendedListenerErrorMessage;
+import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorMessageConstruction
+        .constructListenerErrorMessage;
 import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorType.INVALID_HOLDER;
 import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorType.MISSING_CURRENT_HOLDER;
 import static org.onosproject.yangutils.parser.impl.parserutils.ListenerErrorType.MISSING_HOLDER;
@@ -134,7 +137,8 @@
                 || curData instanceof YangList || curData instanceof YangCase
                 || curData instanceof YangNotification
                 || curData instanceof YangInput || curData instanceof YangOutput
-                || curData instanceof YangAugment) {
+                || curData instanceof YangAugment
+                || curData instanceof YangGrouping) {
             YangNode curNode = (YangNode) curData;
             try {
                 curNode.addChild(container);
@@ -190,6 +194,6 @@
                 ctx.identifier().getText());
         validateCardinalityMaxOne(ctx.referenceStatement(), REFERENCE_DATA, CONTAINER_DATA, ctx.identifier().getText());
         validateCardinalityMaxOne(ctx.statusStatement(), STATUS_DATA, CONTAINER_DATA, ctx.identifier().getText());
-        // TODO when, grouping, typedef.
+        // TODO validate 'when' cardinality
     }
 }