[ONOS-6514] Yang Compiler/Runtime: Identifty ref support

Change-Id: I05fc8140126c46ca2158b971badc01042e98cacd
diff --git a/runtime/src/main/java/org/onosproject/yang/runtime/impl/ModelConverterUtil.java b/runtime/src/main/java/org/onosproject/yang/runtime/impl/ModelConverterUtil.java
index d1c6083..9ffbedd 100644
--- a/runtime/src/main/java/org/onosproject/yang/runtime/impl/ModelConverterUtil.java
+++ b/runtime/src/main/java/org/onosproject/yang/runtime/impl/ModelConverterUtil.java
@@ -41,6 +41,7 @@
 import java.util.Arrays;
 import java.util.Base64;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Set;
 
 import static org.onosproject.yang.compiler.datamodel.TraversalType.PARENT;
@@ -355,7 +356,10 @@
     private static String getIdentityRefValue(Object fieldObj, YangIdentityRef ir,
                                               Object holderObj) {
 
-        YangIdentity id = ir.getReferredIdentity();
+        YangIdentity id = getDerivedIdentity(fieldObj, ir);
+        if (id == null) {
+            throw new ModelConvertorException("Value for identity is invalid");
+        }
         String idName = id.getJavaClassNameOrBuiltInType();
         String idPkg = id.getJavaPackage() + PERIOD + getCapitalCase(idName);
         String methodName = idName + getCapitalCase(TO_STRING);
@@ -373,6 +377,28 @@
         }
     }
 
+    private static YangIdentity getDerivedIdentity(Object fieldObj,
+                                                   YangIdentityRef ir) {
+        YangIdentity id = ir.getReferredIdentity();
+        String idName = id.getJavaClassNameOrBuiltInType();
+        String[] objValue = fieldObj.toString().split("\\.");
+        String value = objValue[objValue.length - 1];
+        if (value.equalsIgnoreCase(idName)) {
+            return id;
+        }
+        List<YangIdentity> identities = id.getExtendList();
+        if (identities != null && !identities.isEmpty()) {
+            for (YangIdentity identity : identities) {
+                if (identity.getJavaClassNameOrBuiltInType()
+                        .equalsIgnoreCase(value)) {
+                    return identity;
+                }
+            }
+        }
+
+        return null;
+    }
+
     /**
      * Returns true, if the data type is primitive; false otherwise.
      *
diff --git a/runtime/src/test/java/org/onosproject/yang/runtime/impl/DefaultDataTreeBuilderTest.java b/runtime/src/test/java/org/onosproject/yang/runtime/impl/DefaultDataTreeBuilderTest.java
index 411556f..46f8c92 100644
--- a/runtime/src/test/java/org/onosproject/yang/runtime/impl/DefaultDataTreeBuilderTest.java
+++ b/runtime/src/test/java/org/onosproject/yang/runtime/impl/DefaultDataTreeBuilderTest.java
@@ -19,16 +19,21 @@
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.rules.ExpectedException;
-import org.onosproject.yang.gen.v1.simpledatatypes.rev20131112.simpledatatypes.DefaultCont;
-import org.onosproject.yang.gen.v1.simpledatatypes.rev20131112.simpledatatypes.Tpdfun0;
-import org.onosproject.yang.gen.v1.ytbmodulewithcontainer.rev20160826.ytbmodulewithcontainer.DefaultSched;
-import org.onosproject.yang.gen.v1.ytbietfschedule.rev20160826.YtbIetfSchedule;
-import org.onosproject.yang.gen.v1.ytbietfschedule.rev20160826.ytbietfschedule.Enum1Enum;
-import org.onosproject.yang.gen.v1.ytbietfschedule.rev20160826.ytbietfschedule.Enum2Enum;
-import org.onosproject.yang.gen.v1.ytbmodulewithleaflist.rev20160826.YtbModuleWithLeafList;
 import org.onosproject.yang.gen.v1.modulelistandkey.rev20160826.modulelistandkey.DefaultModKey;
 import org.onosproject.yang.gen.v1.modulelistandkey.rev20160826.modulelistandkey.ModKey;
 import org.onosproject.yang.gen.v1.modulelistandkey.rev20160826.modulelistandkey.ModKeyKeys;
+import org.onosproject.yang.gen.v1.simpledatatypes.rev20131112.simpledatatypes.DefaultCont;
+import org.onosproject.yang.gen.v1.simpledatatypes.rev20131112.simpledatatypes.Tpdfun0;
+import org.onosproject.yang.gen.v1.yrtietfte.rev20170310.yrtietfte.DefaultTe;
+import org.onosproject.yang.gen.v1.yrtietfte.rev20170310.yrtietfte.tunnelp2pproperties.DefaultState;
+import org.onosproject.yang.gen.v1.yrtietfte.rev20170310.yrtietfte.tunnelsgrouping.DefaultTunnels;
+import org.onosproject.yang.gen.v1.yrtietfte.rev20170310.yrtietfte.tunnelsgrouping.tunnels.DefaultTunnel;
+import org.onosproject.yang.gen.v1.yrtietftetypes.rev20160320.yrtietftetypes.TunnelP2p;
+import org.onosproject.yang.gen.v1.ytbietfschedule.rev20160826.YtbIetfSchedule;
+import org.onosproject.yang.gen.v1.ytbietfschedule.rev20160826.ytbietfschedule.Enum1Enum;
+import org.onosproject.yang.gen.v1.ytbietfschedule.rev20160826.ytbietfschedule.Enum2Enum;
+import org.onosproject.yang.gen.v1.ytbmodulewithcontainer.rev20160826.ytbmodulewithcontainer.DefaultSched;
+import org.onosproject.yang.gen.v1.ytbmodulewithleaflist.rev20160826.YtbModuleWithLeafList;
 import org.onosproject.yang.gen.v1.ytbtreebuilderforlisthavinglist.rev20160826.ytbtreebuilderforlisthavinglist.DefaultCarrier;
 import org.onosproject.yang.gen.v1.ytbtreebuilderforlisthavinglist.rev20160826.ytbtreebuilderforlisthavinglist.carrier.DefaultMultiplexes;
 import org.onosproject.yang.gen.v1.ytbtreebuilderforlisthavinglist.rev20160826.ytbtreebuilderforlisthavinglist.carrier.Multiplexes;
@@ -1145,4 +1150,39 @@
                          SINGLE_INSTANCE_LEAF_VALUE_NODE,
                          true, "successful exit");
     }
+
+    /**
+     * Unit test for identity-ref.
+     */
+    @Test
+    public void processIdentityRef() {
+        setUp();
+        DefaultState state = new DefaultState();
+        state.type(TunnelP2p.class);
+        DefaultTunnel tunnel = new DefaultTunnel();
+        tunnel.state(state);
+        DefaultTunnels tunnels = new DefaultTunnels();
+        tunnels.addToTunnel(tunnel);
+        DefaultTe te = new DefaultTe();
+        te.tunnels(tunnels);
+
+        data = new DefaultModelObjectData.Builder();
+        data.addModelObject(te);
+        DefaultDataTreeBuilder builder = new DefaultDataTreeBuilder(registry);
+        rscData = builder.getResourceData(data.build());
+
+        DataNode node = rscData.dataNodes().get(0);
+        String ns = "urn:ietf:params:xml:ns:yang:ietf-te";
+        validateDataNode(node, "te", ns, SINGLE_INSTANCE_NODE, true, null);
+        NodeKey key = NodeKey.builder().schemaId("tunnels", ns).build();
+        DataNode childNode = ((InnerNode) node).childNodes().get(key);
+        key = NodeKey.builder().schemaId("tunnel", ns).build();
+        childNode = ((InnerNode) childNode).childNodes().get(key);
+        key = NodeKey.builder().schemaId("state", ns).build();
+        childNode = ((InnerNode) childNode).childNodes().get(key);
+        key = NodeKey.builder().schemaId("type", ns).build();
+        childNode = ((InnerNode) childNode).childNodes().get(key);
+        validateDataNode(childNode, "type", ns, SINGLE_INSTANCE_LEAF_VALUE_NODE,
+                         false, "tunnel-p2p");
+    }
 }
diff --git a/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobGroupingUsesTest.java b/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobGroupingUsesTest.java
index 84c0763..f5807ab 100644
--- a/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobGroupingUsesTest.java
+++ b/runtime/src/test/java/org/onosproject/yang/runtime/impl/YobGroupingUsesTest.java
@@ -19,13 +19,15 @@
 import org.junit.Test;
 import org.onosproject.yang.gen.v1.yrtietfnetwork.rev20151208.yrtietfnetwork.DefaultNetworks;
 import org.onosproject.yang.gen.v1.yrtietfschedule.rev20160301.yrtietfschedule.schedules.schedules.Schedule;
+import org.onosproject.yang.gen.v1.yrtietfte.rev20170310.yrtietfte.DefaultTe;
+import org.onosproject.yang.gen.v1.yrtietfte.rev20170310.yrtietfte.tunnelp2pproperties.DefaultState;
 import org.onosproject.yang.gen.v1.yrtietftetopology.rev20160317.yrtietftetopology.networks.DefaultAugmentedNwNetworks;
 import org.onosproject.yang.gen.v1.yrtietftetopology.rev20160317.yrtietftetopology.tetopologiesaugment.te.templates.LinkTemplate;
 import org.onosproject.yang.model.DataNode;
+import org.onosproject.yang.model.DefaultResourceData;
 import org.onosproject.yang.model.ModelObject;
 import org.onosproject.yang.model.ModelObjectData;
 import org.onosproject.yang.model.ResourceData;
-import org.onosproject.yang.model.DefaultResourceData;
 
 import java.util.List;
 
@@ -43,6 +45,7 @@
     TestYangSerializerContext context = new TestYangSerializerContext();
     private static final String NW_NS = "urn:ietf:params:xml:ns:yang:yrt-ietf-network";
     private static final String TE_NS = "urn:ietf:params:xml:ns:yang:yrt-ietf-te-topology";
+    private static final String TE = "urn:ietf:params:xml:ns:yang:ietf-te";
     private DataNode.Builder dBlr;
     private String value;
 
@@ -103,4 +106,48 @@
         assertThat(sh.scheduleDuration(), is("schedule-duration"));
         assertThat(sh.repeatInterval(), is("repeat-interval"));
     }
+
+    private DataNode buildDataNodeWithIdentityRef() {
+        dBlr = initializeDataNode(context);
+        value = null;
+        dBlr = addDataNode(dBlr, "te", TE, value, null);
+        dBlr = addDataNode(dBlr, "tunnels", TE, value, null);
+        dBlr = addDataNode(dBlr, "tunnel", TE, value, null);
+        value = "name";
+        dBlr = addDataNode(dBlr, "name", TE, value, null);
+        dBlr = exitDataNode(dBlr);
+        value = null;
+        dBlr = addDataNode(dBlr, "state", TE, value, null);
+        value = "statename";
+        dBlr = addDataNode(dBlr, "name", TE, value, null);
+        dBlr = exitDataNode(dBlr);
+        value = "tunnel-p2p";
+        dBlr = addDataNode(dBlr, "type", TE, value, null);
+        dBlr = exitDataNode(dBlr); // tunnel-p2p
+        dBlr = exitDataNode(dBlr); // state
+        dBlr = exitDataNode(dBlr); // tunnel
+        dBlr = exitDataNode(dBlr); // tunnels
+        dBlr = exitDataNode(dBlr); // te
+        return dBlr.build();
+    }
+
+    /**
+     * Unit test for identity-ref.
+     */
+    @Test
+    public void testIdentityRef() {
+        DataNode dataNode = buildDataNodeWithIdentityRef();
+        ResourceData data = DefaultResourceData.builder().
+                addDataNode(dataNode).build();
+        DefaultYobBuilder builder = new DefaultYobBuilder(
+                (DefaultYangModelRegistry) context.getContext());
+        ModelObjectData modelObjectData = builder.getYangObject(data);
+        List<ModelObject> modelObjectList = modelObjectData.modelObjects();
+        ModelObject modelObject = modelObjectList.get(0);
+        DefaultTe te = ((DefaultTe) modelObject);
+        DefaultState state = ((DefaultState) te.tunnels()
+                .tunnel().get(0).state());
+        assertThat(state.name().toString(), is("statename"));
+        assertThat(state.type().getSimpleName().toString(), is("TunnelP2p"));
+    }
 }
diff --git a/runtime/src/test/resources/schemaProviderTestYangFiles/yrt-ietf-te.yang b/runtime/src/test/resources/schemaProviderTestYangFiles/yrt-ietf-te.yang
new file mode 100644
index 0000000..c9572be
--- /dev/null
+++ b/runtime/src/test/resources/schemaProviderTestYangFiles/yrt-ietf-te.yang
@@ -0,0 +1,52 @@
+module yrt-ietf-te {
+
+  namespace "urn:ietf:params:xml:ns:yang:ietf-te";
+  prefix "te";
+  import yrt-ietf-te-types {
+    prefix te-types;
+  }
+
+  revision "2017-03-10";
+
+  grouping tunnels-grouping {
+    container tunnels {
+      list tunnel {
+        key "name";
+        leaf name {
+          type string;
+        }
+        uses tunnel-p2p-properties;
+      }
+    }
+  }
+
+  grouping tunnel-p2p-params_config {
+    leaf name {
+      type string;
+    }
+    leaf type {
+      type identityref {
+        base te-types:tunnel-type;
+      }
+    }
+  }
+
+  grouping tunnel-p2p-params_state {
+    leaf oper-status {
+      type identityref {
+        base te-types:state-type;
+      }
+    }
+  }
+
+  grouping tunnel-p2p-properties {
+    container state {
+      config false;
+      uses tunnel-p2p-params_config;
+    }
+  }
+
+  container te {
+    uses tunnels-grouping;
+  }
+}