Refeactor codec helper classes

Change-Id: Ic980293f5df97ed74a73fc54e3dcb197658264f5
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
new file mode 100644
index 0000000..21968c2
--- /dev/null
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeInstructionCodecHelper.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright 2015 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.codec.impl;
+
+import org.onlab.packet.IpAddress;
+import org.onlab.packet.MacAddress;
+import org.onlab.packet.MplsLabel;
+import org.onlab.packet.VlanId;
+import org.onosproject.net.ChannelSpacing;
+import org.onosproject.net.GridType;
+import org.onosproject.net.Lambda;
+import org.onosproject.net.OchSignal;
+import org.onosproject.net.PortNumber;
+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.L2ModificationInstruction;
+import org.onosproject.net.flow.instructions.L3ModificationInstruction;
+
+import com.fasterxml.jackson.databind.node.ObjectNode;
+
+import static org.onlab.util.Tools.nullIsIllegal;
+
+/**
+ * Decoding portion of the instruction codec.
+ */
+public final class DecodeInstructionCodecHelper {
+    private final ObjectNode json;
+
+    /**
+     * Creates a decode instruction codec object.
+     *
+     * @param json JSON object to decode
+     */
+    public DecodeInstructionCodecHelper(ObjectNode json) {
+        this.json = json;
+    }
+
+    /**
+     * Decodes a Layer 2 instruction.
+     *
+     * @return instruction object decoded from the JSON
+     * @throws IllegalArgumentException if the JSON is invalid
+     */
+    private Instruction decodeL2() {
+        String subType = json.get(InstructionCodec.SUBTYPE).asText();
+
+        if (subType.equals(L2ModificationInstruction.L2SubType.ETH_SRC.name())) {
+            String mac = nullIsIllegal(json.get(InstructionCodec.MAC),
+                    InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
+            return Instructions.modL2Src(MacAddress.valueOf(mac));
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.ETH_DST.name())) {
+            String mac = nullIsIllegal(json.get(InstructionCodec.MAC),
+                    InstructionCodec.MAC + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
+            return Instructions.modL2Dst(MacAddress.valueOf(mac));
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_ID.name())) {
+            short vlanId = (short) nullIsIllegal(json.get(InstructionCodec.VLAN_ID),
+                    InstructionCodec.VLAN_ID + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            return Instructions.modVlanId(VlanId.vlanId(vlanId));
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PCP.name())) {
+            byte vlanPcp = (byte) nullIsIllegal(json.get(InstructionCodec.VLAN_PCP),
+                    InstructionCodec.VLAN_PCP + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            return Instructions.modVlanPcp(vlanPcp);
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_LABEL.name())) {
+            int label = nullIsIllegal(json.get(InstructionCodec.MPLS_LABEL),
+                    InstructionCodec.MPLS_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            return Instructions.modMplsLabel(MplsLabel.mplsLabel(label));
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_PUSH.name())) {
+            return Instructions.pushMpls();
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.MPLS_POP.name())) {
+            return Instructions.popMpls();
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.DEC_MPLS_TTL.name())) {
+            return Instructions.decMplsTtl();
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_POP.name())) {
+            return Instructions.popVlan();
+        } else if (subType.equals(L2ModificationInstruction.L2SubType.VLAN_PUSH.name())) {
+            return Instructions.pushVlan();
+        }
+        throw new IllegalArgumentException("L2 Instruction subtype "
+                + subType + " is not supported");
+    }
+
+    /**
+     * Decodes a Layer 3 instruction.
+     *
+     * @return instruction object decoded from the JSON
+     * @throws IllegalArgumentException if the JSON is invalid
+     */
+    private Instruction decodeL3() {
+        String subType = json.get(InstructionCodec.SUBTYPE).asText();
+
+        if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_SRC.name())) {
+            IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
+                    InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
+            return Instructions.modL3Src(ip);
+        } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV4_DST.name())) {
+            IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
+                    InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
+            return Instructions.modL3Dst(ip);
+        } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_SRC.name())) {
+            IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
+                    InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
+            return Instructions.modL3IPv6Src(ip);
+        } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_DST.name())) {
+            IpAddress ip = IpAddress.valueOf(nullIsIllegal(json.get(InstructionCodec.IP),
+                    InstructionCodec.IP + InstructionCodec.MISSING_MEMBER_MESSAGE).asText());
+            return Instructions.modL3IPv6Dst(ip);
+        } else if (subType.equals(L3ModificationInstruction.L3SubType.IPV6_FLABEL.name())) {
+            int flowLabel = nullIsIllegal(json.get(InstructionCodec.FLOW_LABEL),
+                    InstructionCodec.FLOW_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            return Instructions.modL3IPv6FlowLabel(flowLabel);
+        }
+        throw new IllegalArgumentException("L3 Instruction subtype "
+                + subType + " is not supported");
+    }
+
+    /**
+     * Decodes a Layer 0 instruction.
+     *
+     * @return instruction object decoded from the JSON
+     * @throws IllegalArgumentException if the JSON is invalid
+     */
+    private Instruction decodeL0() {
+        String subType = json.get(InstructionCodec.SUBTYPE).asText();
+
+
+        if (subType.equals(L0ModificationInstruction.L0SubType.LAMBDA.name())) {
+            int lambda = nullIsIllegal(json.get(InstructionCodec.LAMBDA),
+                    InstructionCodec.LAMBDA + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            return Instructions.modL0Lambda(Lambda.indexedLambda(lambda));
+        } else if (subType.equals(L0ModificationInstruction.L0SubType.OCH.name())) {
+            String gridTypeString = nullIsIllegal(json.get(InstructionCodec.GRID_TYPE),
+                    InstructionCodec.GRID_TYPE + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
+            GridType gridType = GridType.valueOf(gridTypeString);
+            if (gridType == null) {
+                throw new IllegalArgumentException("Unknown grid type  "
+                        + gridTypeString);
+            }
+            String channelSpacingString = nullIsIllegal(json.get(InstructionCodec.CHANNEL_SPACING),
+                    InstructionCodec.CHANNEL_SPACING + InstructionCodec.MISSING_MEMBER_MESSAGE).asText();
+            ChannelSpacing channelSpacing = ChannelSpacing.valueOf(channelSpacingString);
+            if (channelSpacing == null) {
+                throw new IllegalArgumentException("Unknown channel spacing  "
+                        + channelSpacingString);
+            }
+            int spacingMultiplier = nullIsIllegal(json.get(InstructionCodec.SPACING_MULTIPLIER),
+                    InstructionCodec.SPACING_MULTIPLIER + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            int slotGranularity = nullIsIllegal(json.get(InstructionCodec.SLOT_GRANULARITY),
+                    InstructionCodec.SLOT_GRANULARITY + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
+            return Instructions.modL0Lambda(new OchSignal(gridType, channelSpacing,
+                    spacingMultiplier, slotGranularity));
+        }
+        throw new IllegalArgumentException("L0 Instruction subtype "
+                + subType + " is not supported");
+    }
+
+    /**
+     * Decodes the JSON into an instruction object.
+     *
+     * @return Criterion object
+     * @throws IllegalArgumentException if the JSON is invalid
+     */
+    public Instruction decode() {
+        String type = json.get(InstructionCodec.TYPE).asText();
+
+        if (type.equals(Instruction.Type.OUTPUT.name())) {
+            PortNumber portNumber =
+                    PortNumber.portNumber(nullIsIllegal(json.get(InstructionCodec.PORT),
+                            InstructionCodec.PORT + InstructionCodec.MISSING_MEMBER_MESSAGE).asLong());
+            return Instructions.createOutput(portNumber);
+        } else if (type.equals(Instruction.Type.DROP.name())) {
+            return Instructions.createDrop();
+        } else if (type.equals(Instruction.Type.L0MODIFICATION.name())) {
+            return decodeL0();
+        } else if (type.equals(Instruction.Type.L2MODIFICATION.name())) {
+            return decodeL2();
+        } else if (type.equals(Instruction.Type.L3MODIFICATION.name())) {
+            return decodeL3();
+        }
+        throw new IllegalArgumentException("Instruction type "
+                + type + " is not supported");
+    }
+
+}