REST API related implemetations for ODU SIGID and SIGTYPE Fields in Flow Criteria and Instruction

Change-Id: I78ddc162409d377b8c55e7f8eedd9a91939ab277
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
index 4e0f2bd..69c5e79 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeCriterionCodecHelper.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.codec.impl;
 
+import static org.onlab.util.Tools.nullIsIllegal;
+
 import java.util.HashMap;
 import java.util.Map;
 
@@ -24,9 +26,13 @@
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
+import org.onlab.util.HexString;
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Lambda;
+import org.onosproject.net.OchSignalType;
+import org.onosproject.net.OduSignalId;
+import org.onosproject.net.OduSignalType;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.flow.criteria.Criteria;
 import org.onosproject.net.flow.criteria.Criterion;
@@ -34,8 +40,6 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
 
-import static org.onlab.util.Tools.nullIsIllegal;
-
 /**
  * Decode portion of the criterion codec.
  */
@@ -95,6 +99,8 @@
         decoderMap.put(Criterion.Type.OCH_SIGID.name(), new OchSigIdDecoder());
         decoderMap.put(Criterion.Type.OCH_SIGTYPE.name(), new OchSigTypeDecoder());
         decoderMap.put(Criterion.Type.TUNNEL_ID.name(), new TunnelIdDecoder());
+        decoderMap.put(Criterion.Type.ODU_SIGID.name(), new OduSigIdDecoder());
+        decoderMap.put(Criterion.Type.ODU_SIGTYPE.name(), new OduSigTypeDecoder());
     }
 
     private class EthTypeDecoder implements CriterionDecoder {
@@ -415,7 +421,9 @@
     private class OchSigTypeDecoder implements CriterionDecoder {
         @Override
         public Criterion decodeCriterion(ObjectNode json) {
-            return null;
+            OchSignalType ochSignalType = OchSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.OCH_SIGNAL_TYPE),
+                    CriterionCodec.OCH_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText());
+            return Criteria.matchOchSignalType(ochSignalType);
         }
     }
 
@@ -428,6 +436,34 @@
         }
     }
 
+    private class OduSigIdDecoder implements CriterionDecoder {
+        @Override
+        public Criterion decodeCriterion(ObjectNode json) {
+            JsonNode oduSignalId = nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_ID),
+                    CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE);
+
+            int tributaryPortNumber = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_PORT_NUMBER),
+                    CriterionCodec.TRIBUTARY_PORT_NUMBER + MISSING_MEMBER_MESSAGE).asInt();
+            int tributarySlotLen = nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_LEN),
+                    CriterionCodec.TRIBUTARY_SLOT_LEN + MISSING_MEMBER_MESSAGE).asInt();
+            byte[] tributarySlotBitmap = HexString.fromHexString(
+                    nullIsIllegal(oduSignalId.get(CriterionCodec.TRIBUTARY_SLOT_BITMAP),
+                    CriterionCodec.TRIBUTARY_SLOT_BITMAP + MISSING_MEMBER_MESSAGE).asText());
+
+            return Criteria.matchOduSignalId(
+                    OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen, tributarySlotBitmap));
+        }
+    }
+
+    private class OduSigTypeDecoder implements CriterionDecoder {
+        @Override
+        public Criterion decodeCriterion(ObjectNode json) {
+            OduSignalType oduSignalType = OduSignalType.valueOf(nullIsIllegal(json.get(CriterionCodec.ODU_SIGNAL_TYPE),
+                    CriterionCodec.ODU_SIGNAL_TYPE + MISSING_MEMBER_MESSAGE).asText());
+            return Criteria.matchOduSignalType(oduSignalType);
+        }
+    }
+
     /**
      * Decodes the JSON into a criterion object.
      *
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 6a97a07..14555b3 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
@@ -15,26 +15,29 @@
  */
 package org.onosproject.codec.impl;
 
+import static org.onlab.util.Tools.nullIsIllegal;
+
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.TpPort;
 import org.onlab.packet.VlanId;
+import org.onlab.util.HexString;
 import org.onosproject.net.ChannelSpacing;
 import org.onosproject.net.GridType;
 import org.onosproject.net.Lambda;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.PortNumber;
-
-import com.fasterxml.jackson.databind.node.ObjectNode;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
 
-import static org.onlab.util.Tools.nullIsIllegal;
+import com.fasterxml.jackson.databind.node.ObjectNode;
 
 /**
  * Decoding portion of the instruction codec.
@@ -174,6 +177,30 @@
     }
 
     /**
+     * Decodes a Layer 1 instruction.
+     *
+     * @return instruction object decoded from the JSON
+     * @throws IllegalArgumentException if the JSON is invalid
+     */
+    private Instruction decodeL1() {
+        String subType = json.get(InstructionCodec.SUBTYPE).asText();
+        if (subType.equals(L1ModificationInstruction.L1SubType.ODU_SIGID.name())) {
+            int tributaryPortNumber = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_PORT_NUMBER),
+                    InstructionCodec.TRIBUTARY_PORT_NUMBER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            int tributarySlotLen = nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_LEN),
+                    InstructionCodec.TRIBUTARY_SLOT_LEN + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            byte[] tributarySlotBitmap = null;
+            tributarySlotBitmap = HexString.fromHexString(
+                    nullIsIllegal(json.get(InstructionCodec.TRIBUTARY_SLOT_BITMAP),
+                    InstructionCodec.TRIBUTARY_SLOT_BITMAP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
+            return Instructions.modL1OduSignalId(OduSignalId.oduSignalId(tributaryPortNumber, tributarySlotLen,
+                    tributarySlotBitmap));
+        }
+        throw new IllegalArgumentException("L1 Instruction subtype "
+                + subType + " is not supported");
+    }
+
+    /**
      * Decodes a Layer 4 instruction.
      *
      * @return instruction object decoded from the JSON
@@ -221,6 +248,8 @@
             return Instructions.createDrop();
         } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) {
             return decodeL0();
+        } else if (type.equals(Instruction.Type.L1MODIFICATION.name())) {
+            return decodeL1();
         } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) {
             return decodeL2();
         } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) {
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
index f7af736..8fc6bbc 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeCriterionCodecHelper.java
@@ -17,8 +17,10 @@
 
 import java.util.EnumMap;
 
+import org.onlab.util.HexString;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.flow.criteria.Criterion;
 import org.onosproject.net.flow.criteria.EthCriterion;
 import org.onosproject.net.flow.criteria.EthTypeCriterion;
@@ -370,12 +372,18 @@
     private static class FormatOduSignalId implements CriterionTypeFormatter {
         @Override
         public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
-            final OduSignalIdCriterion oduSignalIdCriterion =
-                    (OduSignalIdCriterion) criterion;
-            return root.put(CriterionCodec.ODU_SIGNAL_ID, oduSignalIdCriterion.oduSignalId().toString());
+            OduSignalId oduSignalId = ((OduSignalIdCriterion) criterion).oduSignalId();
+            ObjectNode child = root.putObject(CriterionCodec.ODU_SIGNAL_ID);
+
+            child.put(CriterionCodec.TRIBUTARY_PORT_NUMBER, oduSignalId.tributaryPortNumber());
+            child.put(CriterionCodec.TRIBUTARY_SLOT_LEN, oduSignalId.tributarySlotLength());
+            child.put(CriterionCodec.TRIBUTARY_SLOT_BITMAP, HexString.toHexString(oduSignalId.tributarySlotBitmap()));
+
+            return root;
         }
     }
 
+
     private static class FormatOduSignalType implements CriterionTypeFormatter {
         @Override
         public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
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 d12e4ad..2ec301d 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,11 +15,14 @@
  */
 package org.onosproject.codec.impl;
 
+import org.onlab.util.HexString;
 import org.onosproject.codec.CodecContext;
 import org.onosproject.net.OchSignal;
+import org.onosproject.net.OduSignalId;
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 import org.onosproject.net.flow.instructions.L0ModificationInstruction;
+import org.onosproject.net.flow.instructions.L1ModificationInstruction;
 import org.onosproject.net.flow.instructions.L2ModificationInstruction;
 import org.onosproject.net.flow.instructions.L3ModificationInstruction;
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
@@ -81,6 +84,36 @@
     }
 
     /**
+     * Encode an L1 modification instruction.
+     *
+     * @param result json node that the instruction attributes are added to
+     * @param instruction The L1 instruction
+     * @param context context of the request
+     */
+    private void encodeL1(ObjectNode result) {
+        L1ModificationInstruction instruction =
+                (L1ModificationInstruction) this.instruction;
+        result.put(InstructionCodec.SUBTYPE, instruction.subtype().name());
+
+        switch (instruction.subtype()) {
+        case ODU_SIGID:
+            final L1ModificationInstruction.ModOduSignalIdInstruction oduSignalIdInstruction =
+                    (L1ModificationInstruction.ModOduSignalIdInstruction) instruction;
+            OduSignalId oduSignalId = oduSignalIdInstruction.oduSignalId();
+
+            ObjectNode child = result.putObject("oduSignalId");
+
+            child.put(InstructionCodec.TRIBUTARY_PORT_NUMBER, oduSignalId.tributaryPortNumber());
+            child.put(InstructionCodec.TRIBUTARY_SLOT_LEN, oduSignalId.tributarySlotLength());
+            child.put(InstructionCodec.TRIBUTARY_SLOT_BITMAP, HexString.toHexString(oduSignalId.tributarySlotBitmap()));
+            break;
+        default:
+            log.info("Cannot convert L1 subtype of {}", instruction.subtype());
+            break;
+        }
+    }
+
+    /**
      * Encode an L2 modification instruction.
      *
      * @param result json node that the instruction attributes are added to
@@ -222,6 +255,10 @@
                 encodeL0(result);
                 break;
 
+            case L1MODIFICATION:
+                encodeL1(result);
+                break;
+
             case L2MODIFICATION:
                 encodeL2(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 f4d5008..d7307ad 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,9 @@
     protected static final String TUNNEL_ID = "tunnelId";
     protected static final String TCP_PORT = "tcpPort";
     protected static final String UDP_PORT = "udpPort";
+    protected static final String TRIBUTARY_PORT_NUMBER = "tributaryPortNumber";
+    protected static final String TRIBUTARY_SLOT_LEN = "tributarySlotLength";
+    protected static final String TRIBUTARY_SLOT_BITMAP = "tributarySlotBitmap";
 
     protected static final String MISSING_MEMBER_MESSAGE =
             " member is required in Instruction";