Support to encode and decode group id in InstructionCodec

Change-Id: Icd0947f494f572831e8b5c8d82d47c85eb074824
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
index 105924e..57e73ed 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
@@ -22,6 +22,8 @@
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
 import org.onlab.util.HexString;
+import org.onosproject.core.DefaultGroupId;
+import org.onosproject.core.GroupId;
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Lambda;
@@ -261,6 +263,10 @@
         } else if (type.equals(Instruction.Type.TABLE.name())) {
             return Instructions.transition(nullIsIllegal(json.get(InstructionCodec.TABLE_ID)
                     .asInt(), InstructionCodec.TABLE_ID + InstructionCodec.MISSING_MEMBER_MESSAGE));
+        } else if (type.equals(Instruction.Type.GROUP.name())) {
+            GroupId groupId = new DefaultGroupId(nullIsIllegal(json.get(InstructionCodec.GROUP_ID)
+                    .asInt(), InstructionCodec.GROUP_ID + InstructionCodec.MISSING_MEMBER_MESSAGE));
+            return Instructions.createGroup(groupId);
         } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) {
             return decodeL0();
         } else if (type.equals(Instruction.Type.L1MODIFICATION.name())) {
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
index 5db7c6d..eccbddb 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeInstructionCodecHelper.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.codec.impl;
 
+import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onlab.util.HexString;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.net.OchSignal;
@@ -29,8 +30,6 @@
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import com.fasterxml.jackson.databind.node.ObjectNode;
-
 /**
  * JSON encoding of Instructions.
  */
@@ -249,6 +248,12 @@
             case NOACTION:
                 break;
 
+            case GROUP:
+                final Instructions.GroupInstruction groupInstruction =
+                        (Instructions.GroupInstruction) instruction;
+                result.put(InstructionCodec.GROUP_ID, groupInstruction.groupId().toString());
+                break;
+
             case L0MODIFICATION:
                 encodeL0(result);
                 break;
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
index 0b5e8ad..ab60909 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/InstructionCodec.java
@@ -50,6 +50,7 @@
     protected static final String TCP_PORT = "tcpPort";
     protected static final String UDP_PORT = "udpPort";
     protected static final String TABLE_ID = "tableId";
+    protected static final String GROUP_ID = "groupId";
     protected static final String TRIBUTARY_PORT_NUMBER = "tributaryPortNumber";
     protected static final String TRIBUTARY_SLOT_LEN = "tributarySlotLength";
     protected static final String TRIBUTARY_SLOT_BITMAP = "tributarySlotBitmap";
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java b/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java
index a6871c8..2ed7a82 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/InstructionJsonMatcher.java
@@ -15,11 +15,13 @@
  */
 package org.onosproject.codec.impl;
 
+import com.fasterxml.jackson.databind.JsonNode;
 import org.hamcrest.Description;
 import org.hamcrest.TypeSafeDiagnosingMatcher;
 import org.onlab.util.HexString;
 import org.onosproject.net.OduSignalId;
 import org.onosproject.net.flow.instructions.Instruction;
+import org.onosproject.net.flow.instructions.Instructions.GroupInstruction;
 import org.onosproject.net.flow.instructions.Instructions.NoActionInstruction;
 import org.onosproject.net.flow.instructions.Instructions.OutputInstruction;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction.ModLambdaInstruction;
@@ -33,8 +35,6 @@
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction.ModIPv6FlowLabelInstruction;
 
-import com.fasterxml.jackson.databind.JsonNode;
-
 /**
  * Hamcrest matcher for instructions.
  */
@@ -123,6 +123,33 @@
     }
 
     /**
+     * Matches the contents of a group instruction.
+     *
+     * @param instructionJson JSON instruction to match
+     * @param description Description object used for recording errors
+     * @return true if contents match, false otherwise
+     */
+    private boolean matchGroupInstruction(JsonNode instructionJson,
+                                          Description description) {
+        final String jsonType = instructionJson.get("type").textValue();
+        GroupInstruction instructionToMatch = (GroupInstruction) instruction;
+        if (!instructionToMatch.type().name().equals(jsonType)) {
+            description.appendText("type was " + jsonType);
+            return false;
+        }
+
+        if (instructionJson.get("groupId").isInt()) {
+            final int jsonGroupId = instructionJson.get("groupId").asInt();
+            if (instructionToMatch.groupId().id() != jsonGroupId) {
+                description.appendText("groupId was " + jsonGroupId);
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    /**
      * Matches the contents of a mod lambda instruction.
      *
      * @param instructionJson JSON instruction to match
@@ -453,6 +480,8 @@
             return matchPushHeaderInstruction(jsonInstruction, description);
         } else if (instruction instanceof OutputInstruction) {
             return matchOutputInstruction(jsonInstruction, description);
+        } else if (instruction instanceof GroupInstruction) {
+            return matchGroupInstruction(jsonInstruction, description);
         } else if (instruction instanceof ModLambdaInstruction) {
             return matchModLambdaInstruction(jsonInstruction, description);
         } else if (instruction instanceof ModOchSignalInstruction) {