Added TierConstraint and MeteredConstraint

Change-Id: Iadc50c98dc0ba7092313f880df8055ab0e401c29
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/ConstraintCodec.java b/core/common/src/main/java/org/onosproject/codec/impl/ConstraintCodec.java
index 5c99650..d5d5a16 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/ConstraintCodec.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/ConstraintCodec.java
@@ -36,10 +36,13 @@
     static final String KEY = "key";
     static final String THRESHOLD = "threshold";
     static final String BANDWIDTH = "bandwidth";
+    static final String METERED = "metered";
     static final String LAMBDA = "lambda";
     static final String LATENCY_MILLIS = "latencyMillis";
     static final String OBSTACLES = "obstacles";
     static final String WAYPOINTS = "waypoints";
+    static final String TIERS = "tiers";
+    static final String COST_TYPE = "costType";
 
     @Override
     public ObjectNode encode(Constraint constraint, CodecContext context) {
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/DecodeConstraintCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/DecodeConstraintCodecHelper.java
index 22c50b1..1e0b35f 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/DecodeConstraintCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/DecodeConstraintCodecHelper.java
@@ -29,8 +29,10 @@
 import org.onosproject.net.intent.constraint.DomainConstraint;
 import org.onosproject.net.intent.constraint.LatencyConstraint;
 import org.onosproject.net.intent.constraint.LinkTypeConstraint;
+import org.onosproject.net.intent.constraint.MeteredConstraint;
 import org.onosproject.net.intent.constraint.NonDisruptiveConstraint;
 import org.onosproject.net.intent.constraint.ObstacleConstraint;
+import org.onosproject.net.intent.constraint.TierConstraint;
 import org.onosproject.net.intent.constraint.WaypointConstraint;
 
 import com.fasterxml.jackson.databind.JsonNode;
@@ -193,6 +195,41 @@
         return nonDisruptive();
     }
 
+    private Constraint decodeMeteredConstraint() {
+        boolean metered = nullIsIllegal(json.get(ConstraintCodec.METERED),
+                ConstraintCodec.METERED + ConstraintCodec.MISSING_MEMBER_MESSAGE).asBoolean();
+        return new MeteredConstraint(metered);
+    }
+
+    /**
+     * Decodes a link type constraint.
+     *
+     * @return link type constraint object.
+     */
+    private Constraint decodeTierConstraint() {
+        boolean inclusive = nullIsIllegal(json.get(ConstraintCodec.INCLUSIVE),
+                ConstraintCodec.INCLUSIVE + ConstraintCodec.MISSING_MEMBER_MESSAGE).asBoolean();
+
+        TierConstraint.CostType costType = TierConstraint.CostType.valueOf(nullIsIllegal(
+                json.get(ConstraintCodec.COST_TYPE), ConstraintCodec.COST_TYPE + ConstraintCodec.MISSING_MEMBER_MESSAGE
+            ).asText());
+
+        JsonNode tiers = nullIsIllegal(json.get(ConstraintCodec.TIERS),
+                ConstraintCodec.TIERS + ConstraintCodec.MISSING_MEMBER_MESSAGE);
+        if (tiers.size() < 1) {
+            throw new IllegalArgumentException(
+                    ConstraintCodec.TIERS + " array in tier constraint must have at least one value");
+        }
+
+        ArrayList<Integer> tierEntries = new ArrayList<>(tiers.size());
+        IntStream.range(0, tiers.size())
+                .forEach(index ->
+                        tierEntries.add(new Integer(tiers.get(index).asText())));
+
+        return new TierConstraint(inclusive, costType,
+                tierEntries.toArray(new Integer[tiers.size()]));
+    }
+
     /**
      * Decodes the given constraint.
      *
@@ -221,7 +258,12 @@
             return decodeDomainConstraint();
         } else if (type.equals(NonDisruptiveConstraint.class.getSimpleName())) {
             return decodeNonDisruptiveConstraint();
+        } else if (type.equals(MeteredConstraint.class.getSimpleName())) {
+            return decodeMeteredConstraint();
+        } else if (type.equals(TierConstraint.class.getSimpleName())) {
+            return decodeTierConstraint();
         }
+
         throw new IllegalArgumentException("Instruction type "
                 + type + " is not supported");
     }
diff --git a/core/common/src/main/java/org/onosproject/codec/impl/EncodeConstraintCodecHelper.java b/core/common/src/main/java/org/onosproject/codec/impl/EncodeConstraintCodecHelper.java
index 486f4e4..6c1c846 100644
--- a/core/common/src/main/java/org/onosproject/codec/impl/EncodeConstraintCodecHelper.java
+++ b/core/common/src/main/java/org/onosproject/codec/impl/EncodeConstraintCodecHelper.java
@@ -23,7 +23,9 @@
 import org.onosproject.net.intent.constraint.BandwidthConstraint;
 import org.onosproject.net.intent.constraint.LatencyConstraint;
 import org.onosproject.net.intent.constraint.LinkTypeConstraint;
+import org.onosproject.net.intent.constraint.MeteredConstraint;
 import org.onosproject.net.intent.constraint.ObstacleConstraint;
+import org.onosproject.net.intent.constraint.TierConstraint;
 import org.onosproject.net.intent.constraint.WaypointConstraint;
 
 import com.fasterxml.jackson.databind.node.ArrayNode;
@@ -155,6 +157,38 @@
         return result;
     }
 
+    private ObjectNode encodeMeteredConstraint() {
+        checkNotNull(constraint, "Metered constraint cannot be null");
+        final MeteredConstraint meteredConstraint =
+                (MeteredConstraint) constraint;
+        return context.mapper().createObjectNode()
+                .put("metered", meteredConstraint.isUseMetered());
+    }
+
+    /**
+     * Encodes a tier constraint.
+     *
+     * @return JSON ObjectNode representing the constraint
+     */
+    private ObjectNode encodeTierConstraint() {
+        checkNotNull(constraint, "Tier constraint cannot be null");
+        final TierConstraint tierConstraint = (TierConstraint) constraint;
+
+        final ObjectNode result = context.mapper().createObjectNode()
+                .put(ConstraintCodec.INCLUSIVE, tierConstraint.isInclusive())
+                .put(ConstraintCodec.COST_TYPE, tierConstraint.costType().name());
+
+        final ArrayNode jsonTiers = result.putArray(ConstraintCodec.TIERS);
+
+        if (tierConstraint.tiers() != null) {
+            for (Integer tier : tierConstraint.tiers()) {
+                jsonTiers.add(tier);
+            }
+        }
+
+        return result;
+    }
+
     /**
      * Encodes the constraint in JSON.
      *
@@ -174,6 +208,10 @@
             result = encodeObstacleConstraint();
         } else if (constraint instanceof WaypointConstraint) {
             result = encodeWaypointConstraint();
+        } else if (constraint instanceof MeteredConstraint) {
+            result = encodeMeteredConstraint();
+        } else if (constraint instanceof TierConstraint) {
+            result = encodeTierConstraint();
         } else {
             result = context.mapper().createObjectNode();
         }
diff --git a/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java b/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java
index 569a775..2fdac58 100644
--- a/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java
+++ b/core/common/src/test/java/org/onosproject/codec/impl/ConstraintCodecTest.java
@@ -31,7 +31,9 @@
 import org.onosproject.net.intent.constraint.DomainConstraint;
 import org.onosproject.net.intent.constraint.LatencyConstraint;
 import org.onosproject.net.intent.constraint.LinkTypeConstraint;
+import org.onosproject.net.intent.constraint.MeteredConstraint;
 import org.onosproject.net.intent.constraint.ObstacleConstraint;
+import org.onosproject.net.intent.constraint.TierConstraint;
 import org.onosproject.net.intent.constraint.WaypointConstraint;
 
 import com.fasterxml.jackson.databind.JsonNode;
@@ -196,4 +198,37 @@
         Constraint constraint = getConstraint("DomainConstraint.json");
         assertThat(constraint, instanceOf(DomainConstraint.class));
     }
+
+    /**
+     * Tests metered constraint.
+     */
+    @Test
+    public void meteredConstraint() {
+        Constraint constraint = getConstraint("MeteredConstraint.json");
+        assertThat(constraint, instanceOf(MeteredConstraint.class));
+
+        MeteredConstraint meteredConstraint = (MeteredConstraint) constraint;
+
+        assertThat(meteredConstraint.isUseMetered(), is(true));
+    }
+
+    /**
+     * Tests tier constraint.
+     */
+    @Test
+    public void tierConstraint() {
+        Constraint constraint = getConstraint("TierConstraint.json");
+        assertThat(constraint, instanceOf(TierConstraint.class));
+
+        TierConstraint tierConstraint = (TierConstraint) constraint;
+
+        assertThat(tierConstraint.isInclusive(), is(true));
+        assertThat(tierConstraint.costType(), is(TierConstraint.CostType.ORDER));
+
+        assertThat(tierConstraint.tiers().get(0), is(3));
+        assertThat(tierConstraint.tiers().get(1), is(2));
+        assertThat(tierConstraint.tiers().get(2), is(1));
+    }
+
+
 }
diff --git a/core/common/src/test/resources/org/onosproject/codec/impl/MeteredConstraint.json b/core/common/src/test/resources/org/onosproject/codec/impl/MeteredConstraint.json
new file mode 100644
index 0000000..435f603
--- /dev/null
+++ b/core/common/src/test/resources/org/onosproject/codec/impl/MeteredConstraint.json
@@ -0,0 +1,4 @@
+{
+  "type":"MeteredConstraint",
+  "metered": true
+}
diff --git a/core/common/src/test/resources/org/onosproject/codec/impl/TierConstraint.json b/core/common/src/test/resources/org/onosproject/codec/impl/TierConstraint.json
new file mode 100644
index 0000000..4da785d
--- /dev/null
+++ b/core/common/src/test/resources/org/onosproject/codec/impl/TierConstraint.json
@@ -0,0 +1,6 @@
+{
+  "type":"TierConstraint",
+  "inclusive": true,
+  "costType": "ORDER",
+  "tiers": [3, 2, 1]
+}