Add REST support for MPLS_POP, TTL_IN and DEC_TTL instructions, MPLS_BOS criterion

Change-Id: Idde10b7f25717507b7a08c11d41921f3ce39fdd3
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
index 926dc86..ebda9a9 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/CriterionCodec.java
@@ -55,6 +55,7 @@
     protected static final String ICMPV6_CODE = "icmpv6Code";
     protected static final String TARGET_ADDRESS = "targetAddress";
     protected static final String LABEL = "label";
+    protected static final String BOS = "bos";
     protected static final String EXT_HDR_FLAGS = "exthdrFlags";
     protected static final String LAMBDA = "lambda";
     protected static final String GRID_TYPE = "gridType";
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 884f6e0..d53b022 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
@@ -96,6 +96,7 @@
         decoderMap.put(Criterion.Type.IPV6_ND_SLL.name(), new V6NDSllDecoder());
         decoderMap.put(Criterion.Type.IPV6_ND_TLL.name(), new V6NDTllDecoder());
         decoderMap.put(Criterion.Type.MPLS_LABEL.name(), new MplsLabelDecoder());
+        decoderMap.put(Criterion.Type.MPLS_BOS.name(), new MplsBosDecoder());
         decoderMap.put(Criterion.Type.IPV6_EXTHDR.name(), new IpV6ExthdrDecoder());
         decoderMap.put(Criterion.Type.OCH_SIGID.name(), new OchSigIdDecoder());
         decoderMap.put(Criterion.Type.OCH_SIGTYPE.name(), new OchSigTypeDecoder());
@@ -410,6 +411,15 @@
         }
     }
 
+    private class MplsBosDecoder implements CriterionDecoder {
+        @Override
+        public Criterion decodeCriterion(ObjectNode json) {
+            boolean bos = nullIsIllegal(json.get(CriterionCodec.BOS),
+                    CriterionCodec.BOS + MISSING_MEMBER_MESSAGE).asBoolean();
+            return Criteria.matchMplsBos(bos);
+        }
+    }
+
     private class IpV6ExthdrDecoder implements CriterionDecoder {
         @Override
         public Criterion decodeCriterion(ObjectNode json) {
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 a6268bb..94fc97c 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
@@ -159,6 +159,12 @@
             int flowLabel = nullIsIllegal(json.get(InstructionCodec.FLOW_LABEL),
                     InstructionCodec.FLOW_LABEL + InstructionCodec.MISSING_MEMBER_MESSAGE).asInt();
             return Instructions.modL3IPv6FlowLabel(flowLabel);
+        } else  if (subType.equals(L3ModificationInstruction.L3SubType.TTL_IN.name())) {
+            return Instructions.copyTtlIn();
+        } else  if (subType.equals(L3ModificationInstruction.L3SubType.TTL_OUT.name())) {
+            return Instructions.copyTtlOut();
+        } else  if (subType.equals(L3ModificationInstruction.L3SubType.DEC_TTL.name())) {
+            return Instructions.decNwTtl();
         }
         throw new IllegalArgumentException("L3 Instruction subtype "
                 + subType + " is not supported");
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 0010848..4e8f8e3 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
@@ -36,6 +36,7 @@
 import org.onosproject.net.flow.criteria.Icmpv6CodeCriterion;
 import org.onosproject.net.flow.criteria.Icmpv6TypeCriterion;
 import org.onosproject.net.flow.criteria.MetadataCriterion;
+import org.onosproject.net.flow.criteria.MplsBosCriterion;
 import org.onosproject.net.flow.criteria.MplsCriterion;
 import org.onosproject.net.flow.criteria.OchSignalCriterion;
 import org.onosproject.net.flow.criteria.OchSignalTypeCriterion;
@@ -108,6 +109,7 @@
         formatMap.put(Criterion.Type.IPV6_ND_SLL, new FormatV6NDTll());
         formatMap.put(Criterion.Type.IPV6_ND_TLL, new FormatV6NDTll());
         formatMap.put(Criterion.Type.MPLS_LABEL, new FormatMplsLabel());
+        formatMap.put(Criterion.Type.MPLS_BOS, new FormatMplsBos());
         formatMap.put(Criterion.Type.IPV6_EXTHDR, new FormatIpV6Exthdr());
         formatMap.put(Criterion.Type.OCH_SIGID, new FormatOchSigId());
         formatMap.put(Criterion.Type.OCH_SIGTYPE, new FormatOchSigType());
@@ -122,7 +124,6 @@
         formatMap.put(Criterion.Type.ARP_SHA, new FormatUnknown());
         formatMap.put(Criterion.Type.ARP_THA, new FormatUnknown());
         formatMap.put(Criterion.Type.MPLS_TC, new FormatUnknown());
-        formatMap.put(Criterion.Type.MPLS_BOS, new FormatUnknown());
         formatMap.put(Criterion.Type.PBB_ISID, new FormatUnknown());
         formatMap.put(Criterion.Type.UNASSIGNED_40, new FormatUnknown());
         formatMap.put(Criterion.Type.PBB_UCA, new FormatUnknown());
@@ -357,6 +358,15 @@
         }
     }
 
+    private static class FormatMplsBos implements CriterionTypeFormatter {
+        @Override
+        public ObjectNode encodeCriterion(ObjectNode root, Criterion criterion) {
+            final MplsBosCriterion mplsBosCriterion =
+                    (MplsBosCriterion) criterion;
+            return root.put(CriterionCodec.BOS, mplsBosCriterion.mplsBos());
+        }
+    }
+
     private static class FormatIpV6Exthdr 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 5393eef..2727223 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
@@ -35,6 +35,7 @@
 import org.onosproject.net.flow.instructions.L4ModificationInstruction;
 import org.slf4j.Logger;
 
+import static org.onlab.util.Tools.toHexWithPrefix;
 import static org.slf4j.LoggerFactory.getLogger;
 
 /**
@@ -162,6 +163,10 @@
                         (L2ModificationInstruction.ModMplsBosInstruction) l2Instruction;
                 result.put(InstructionCodec.MPLS_BOS, modMplsBosInstruction.mplsBos());
             case MPLS_POP:
+                final L2ModificationInstruction.ModMplsHeaderInstruction popHeaderInstruction =
+                        (L2ModificationInstruction.ModMplsHeaderInstruction) l2Instruction;
+                result.put(InstructionCodec.ETHERNET_TYPE,
+                        toHexWithPrefix(popHeaderInstruction.ethernetType().toShort()));
             case DEC_MPLS_TTL:
                 break;
             default:
@@ -196,6 +201,7 @@
             case TTL_IN:
             case TTL_OUT:
             case DEC_TTL:
+                // These instructions have no values to be encoded
                 break;
             default:
                 log.info("Cannot convert L3 subtype of {}", l3Instruction.subtype());
diff --git a/utils/misc/src/main/java/org/onlab/util/Tools.java b/utils/misc/src/main/java/org/onlab/util/Tools.java
index d2aa1f5..c4fcf05 100644
--- a/utils/misc/src/main/java/org/onlab/util/Tools.java
+++ b/utils/misc/src/main/java/org/onlab/util/Tools.java
@@ -15,10 +15,12 @@
  */
 package org.onlab.util;
 
-import static java.nio.file.Files.delete;
-import static java.nio.file.Files.walkFileTree;
-import static org.onlab.util.GroupedThreadFactory.groupedThreadFactory;
-import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.base.Charsets;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import com.google.common.primitives.UnsignedLongs;
+import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import org.slf4j.Logger;
 
 import java.io.File;
 import java.io.IOException;
@@ -51,13 +53,10 @@
 import java.util.stream.Stream;
 import java.util.stream.StreamSupport;
 
-import org.slf4j.Logger;
-
-import com.google.common.base.Charsets;
-import com.google.common.base.Strings;
-import com.google.common.collect.Lists;
-import com.google.common.primitives.UnsignedLongs;
-import com.google.common.util.concurrent.ThreadFactoryBuilder;
+import static java.nio.file.Files.delete;
+import static java.nio.file.Files.walkFileTree;
+import static org.onlab.util.GroupedThreadFactory.groupedThreadFactory;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Miscellaneous utility methods.
@@ -245,6 +244,17 @@
     }
 
     /**
+     * Returns a string encoding in hex of the given long value with prefix
+     * '0x'.
+     *
+     * @param value long value to encode as hex string
+     * @return hex string
+     */
+    public static String toHexWithPrefix(long value) {
+        return "0x" + Long.toHexString(value);
+    }
+
+    /**
      * Returns the UTF-8 encoded byte[] representation of a String.
      * @param input input string
      * @return UTF-8 encoded byte array