[SDFAB-90] Implement priority mechanism in the Policy framework.

Change-Id: I738956566bfcf1bd5e2d4fcd9bfef153b5fb674a
diff --git a/api/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyService.java b/api/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyService.java
index 2e188ab..9b93870 100644
--- a/api/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyService.java
+++ b/api/src/main/java/org/onosproject/segmentrouting/policy/api/PolicyService.java
@@ -23,7 +23,9 @@
 public interface PolicyService {
     /**
      * Traffic match priority.
+     * @deprecated in version 3.0.2
      */
+    @Deprecated
     int TRAFFIC_MATCH_PRIORITY = 60000;
 
     /**
diff --git a/api/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatch.java b/api/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatch.java
index 83098fe..bcad3bd 100644
--- a/api/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatch.java
+++ b/api/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatch.java
@@ -34,17 +34,34 @@
     private TrafficMatchId trafficMatchId;
     private TrafficSelector trafficSelector;
     private PolicyId policyId;
+    private TrafficMatchPriority trafficMatchPriority;
 
     /**
      * Builds a traffic match.
      *
-     * @param trafficselector the traffic selector
-     * @param policyid the associated policy id
+     * @param trafficSelector the traffic selector
+     * @param policyId the associated policy id
+     * @deprecated in version 3.0.2
      */
-    public TrafficMatch(TrafficSelector trafficselector, PolicyId policyid) {
-        trafficSelector = trafficselector;
-        trafficMatchId = TrafficMatchId.trafficMatchId(computeTrafficMatchId());
-        policyId = policyid;
+    public TrafficMatch(TrafficSelector trafficSelector, PolicyId policyId) {
+        this.trafficSelector = trafficSelector;
+        this.trafficMatchId = TrafficMatchId.trafficMatchId(computeTrafficMatchId());
+        this.policyId = policyId;
+        this.trafficMatchPriority = new TrafficMatchPriority(PolicyService.TRAFFIC_MATCH_PRIORITY);
+    }
+
+    /**
+     * Builds a traffic match.
+     *
+     * @param trafficSelector the traffic selector
+     * @param policyId the associated policy id
+     * @param trafficMatchPriority the priority
+     */
+    public TrafficMatch(TrafficSelector trafficSelector, PolicyId policyId, TrafficMatchPriority trafficMatchPriority) {
+        this.trafficSelector = trafficSelector;
+        this.trafficMatchId = TrafficMatchId.trafficMatchId(computeTrafficMatchId());
+        this.policyId = policyId;
+        this.trafficMatchPriority = trafficMatchPriority;
     }
 
     /**
@@ -74,9 +91,18 @@
         return trafficSelector;
     }
 
+    /**
+     * Returns the priority.
+     *
+     * @return the priority
+     */
+    public TrafficMatchPriority trafficMatchPriority() {
+        return trafficMatchPriority;
+    }
+
     @Override
     public int hashCode() {
-        return Objects.hash(trafficMatchId, trafficSelector, policyId);
+        return Objects.hash(trafficMatchId, trafficSelector, policyId, trafficMatchPriority);
     }
 
     @Override
@@ -88,7 +114,8 @@
             final TrafficMatch other = (TrafficMatch) obj;
             return Objects.equals(this.trafficMatchId, other.trafficMatchId) &&
                     Objects.equals(trafficSelector, other.trafficSelector) &&
-                    Objects.equals(policyId, other.policyId);
+                    Objects.equals(policyId, other.policyId) &&
+                    Objects.equals(trafficMatchPriority, other.trafficMatchPriority);
         }
         return false;
     }
@@ -99,6 +126,7 @@
                 .add("trafficMatchId", trafficMatchId)
                 .add("trafficSelector", trafficSelector)
                 .add("policyId", policyId)
+                .add("trafficMatchPriority", trafficMatchPriority)
                 .toString();
     }
 
diff --git a/api/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchPriority.java b/api/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchPriority.java
new file mode 100644
index 0000000..206c0b3
--- /dev/null
+++ b/api/src/main/java/org/onosproject/segmentrouting/policy/api/TrafficMatchPriority.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2021-present Open Networking Foundation
+ *
+ * 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.segmentrouting.policy.api;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
+/**
+ * Priorities for traffic match.
+ */
+public final class TrafficMatchPriority {
+    /**
+     * Priority of the TrafficMatch.
+     */
+    private final int priority;
+
+    /**
+     * Lowest allowable priority value.
+     */
+    public static final int MIN = 50000;
+
+    /**
+     * Medium priority value.
+     */
+    public static final int MEDIUM = 55000;
+
+    /**
+     * Highest allowable priority value.
+     */
+    public static final int MAX = 60000;
+
+    private static final String ILLEGAL_PRIORITY_MESSAGE = "The priority value is out of range.";
+
+    /**
+     * Using arbitrary or pre-defined value.
+     *
+     * @param priority A arbitrary or pre-defined priority value.
+     * @throws IllegalArgumentException if priority value less or greater than lower/upper bound.
+     */
+    public TrafficMatchPriority(int priority) throws IllegalArgumentException {
+        if (priority < MIN || priority > MAX) {
+            throw new IllegalArgumentException(ILLEGAL_PRIORITY_MESSAGE);
+        } else {
+            this.priority = priority;
+        }
+    }
+
+    /**
+     * Get priority value.
+     *
+     * @return the priority value.
+     */
+    public int priority() {
+        return this.priority;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(priority);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof TrafficMatchPriority) {
+            final TrafficMatchPriority other = (TrafficMatchPriority) obj;
+            return this.priority() == other.priority();
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("priority", priority)
+                .toString();
+    }
+}
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchAddCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchAddCommand.java
index ad9a432..ddab52e 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchAddCommand.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchAddCommand.java
@@ -33,6 +33,7 @@
 import org.onosproject.segmentrouting.policy.api.PolicyService;
 import org.onosproject.segmentrouting.policy.api.TrafficMatch;
 import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchPriority;
 
 /**
  * Command to add a traffic match.
@@ -47,6 +48,11 @@
             required = true, multiValued = false)
     String policyId;
 
+    @Argument(index = 1, name = "priority",
+            description = "priority",
+            required = true, multiValued = false)
+    int priority;
+
     @Option(name = "-sip", aliases = "--srcIp",
             description = "src IP",
             valueToShowInHelp = "10.0.0.1",
@@ -103,10 +109,17 @@
             print("Empty traffic selector is not allowed");
             return;
         }
+        TrafficMatchPriority trafficMatchPriority;
+        try {
+            trafficMatchPriority = new TrafficMatchPriority(priority);
+        } catch (IllegalArgumentException ex) {
+            print(ex.getMessage());
+            return;
+        }
 
         PolicyService policyService = AbstractShellCommand.get(PolicyService.class);
         TrafficMatchId trafficMatchId = policyService.addOrUpdateTrafficMatch(
-                new TrafficMatch(trafficSelector, PolicyId.of(policyId)));
+                new TrafficMatch(trafficSelector, PolicyId.of(policyId), trafficMatchPriority));
         print("Traffic match %s has been submitted", trafficMatchId);
     }
 
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchListCommand.java b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchListCommand.java
index cb5008a..3d24f50 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchListCommand.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/cli/TrafficMatchListCommand.java
@@ -31,7 +31,7 @@
 public class TrafficMatchListCommand extends AbstractShellCommand {
 
     private static final String FORMAT_MAPPING_TRAFFIC_MATCH =
-            "  id=%s, state=%s, policyId=%s";
+            "  id=%s, state=%s, policyId=%s, priority=%d";
     private static final String FORMAT_MAPPING_OPERATION =
             "    op=%s";
 
@@ -43,7 +43,8 @@
 
     private void printTrafficMatch(TrafficMatchData trafficMatchData) {
         print(FORMAT_MAPPING_TRAFFIC_MATCH, trafficMatchData.trafficMatch().trafficMatchId(),
-                trafficMatchData.trafficMatchState(), trafficMatchData.trafficMatch().policyId());
+                trafficMatchData.trafficMatchState(), trafficMatchData.trafficMatch().policyId(),
+                trafficMatchData.trafficMatch().trafficMatchPriority().priority());
         trafficMatchData.operations().forEach(operation -> print(FORMAT_MAPPING_OPERATION, operation));
     }
 }
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyManager.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyManager.java
index eaf6711..78b8600 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyManager.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/PolicyManager.java
@@ -57,6 +57,7 @@
 import org.onosproject.segmentrouting.policy.api.TrafficMatch;
 import org.onosproject.segmentrouting.policy.api.TrafficMatchData;
 import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchPriority;
 import org.onosproject.segmentrouting.policy.api.TrafficMatchState;
 import org.onosproject.segmentrouting.config.DeviceConfigNotFoundException;
 import org.onosproject.segmentrouting.policy.api.Policy.PolicyType;
@@ -144,6 +145,7 @@
             .register(PolicyRequest.class)
             .register(TrafficMatchId.class)
             .register(TrafficMatchState.class)
+            .register(TrafficMatchPriority.class)
             .register(TrafficMatch.class)
             .register(TrafficMatchRequest.class)
             .register(Operation.class);
@@ -794,7 +796,7 @@
             metaBuilder.matchMetadata(EDGE_PORT);
         }
         return DefaultForwardingObjective.builder()
-                .withPriority(PolicyService.TRAFFIC_MATCH_PRIORITY)
+                .withPriority(trafficMatch.trafficMatchPriority().priority())
                 .withSelector(trafficMatch.trafficSelector())
                 .withMeta(metaBuilder.build())
                 .fromApp(appId)
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchCodec.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchCodec.java
index fe6d464..fe834e3 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchCodec.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchCodec.java
@@ -22,6 +22,7 @@
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.segmentrouting.policy.api.PolicyId;
 import org.onosproject.segmentrouting.policy.api.TrafficMatch;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchPriority;
 
 import static org.onlab.util.Tools.nullIsIllegal;
 
@@ -34,6 +35,7 @@
     public static final String TRAFFIC_MATCH_ID = "traffic_match_id";
     public static final String TRAFFIC_SELECTOR = "selector";
     public static final String POLICY_ID = "policy_id";
+    public static final String TRAFFIC_MATCH_PRIORITY = "priority";
     public static final String MISSING_MEMBER_MESSAGE =
             " member is required in Traffic Match";
 
@@ -46,6 +48,7 @@
         final ObjectNode result = context.mapper().createObjectNode()
                 .put(TRAFFIC_MATCH_ID, trafficMatch.trafficMatchId().toString())
                 .put(POLICY_ID, trafficMatch.policyId().toString())
+                .put(TRAFFIC_MATCH_PRIORITY, trafficMatch.trafficMatchPriority().priority())
                 .set(TRAFFIC_SELECTOR, selector);
 
         return result;
@@ -63,6 +66,15 @@
         PolicyId policyId = PolicyId.of(nullIsIllegal(json.get(POLICY_ID),
                 POLICY_ID + MISSING_MEMBER_MESSAGE).asText());
 
-        return new TrafficMatch(trafficSelector, policyId);
+        int priority = nullIsIllegal(json.get(TRAFFIC_MATCH_PRIORITY),
+                TRAFFIC_MATCH_PRIORITY + MISSING_MEMBER_MESSAGE).asInt();
+        TrafficMatchPriority trafficMatchPriority;
+        try {
+            trafficMatchPriority = new TrafficMatchPriority(priority);
+        } catch (IllegalArgumentException ex) {
+            throw ex;
+        }
+
+        return new TrafficMatch(trafficSelector, policyId, trafficMatchPriority);
     }
 }
diff --git a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchRequest.java b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchRequest.java
index 6e01e01..aaddc3d 100644
--- a/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchRequest.java
+++ b/impl/src/main/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchRequest.java
@@ -19,6 +19,7 @@
 import org.onosproject.segmentrouting.policy.api.PolicyId;
 import org.onosproject.segmentrouting.policy.api.TrafficMatch;
 import org.onosproject.segmentrouting.policy.api.TrafficMatchId;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchPriority;
 import org.onosproject.segmentrouting.policy.api.TrafficMatchState;
 
 import java.util.Objects;
@@ -97,6 +98,15 @@
         return trafficMatch;
     }
 
+    /**
+     * Returns the priority.
+     *
+     * @return the priority
+     */
+    public TrafficMatchPriority priority() {
+        return trafficMatch.trafficMatchPriority();
+    }
+
     @Override
     public int hashCode() {
         return Objects.hash(trafficMatch);
diff --git a/impl/src/test/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchCodecTest.java b/impl/src/test/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchCodecTest.java
index f78fb80..10e1d07 100644
--- a/impl/src/test/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchCodecTest.java
+++ b/impl/src/test/java/org/onosproject/segmentrouting/policy/impl/TrafficMatchCodecTest.java
@@ -30,6 +30,7 @@
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.segmentrouting.policy.api.PolicyId;
 import org.onosproject.segmentrouting.policy.api.TrafficMatch;
+import org.onosproject.segmentrouting.policy.api.TrafficMatchPriority;
 
 import java.io.InputStream;
 
@@ -54,8 +55,8 @@
                 .matchTcpDst(TpPort.tpPort(81))
                 .build();
         policyId = PolicyId.of("DROP");
-
-        trafficMatch = new TrafficMatch(trafficSelector, policyId);
+        TrafficMatchPriority trafficMatchPriority = new TrafficMatchPriority(60000);
+        trafficMatch = new TrafficMatch(trafficSelector, policyId, trafficMatchPriority);
     }
 
     @Test
diff --git a/impl/src/test/resources/trafficmatch.json b/impl/src/test/resources/trafficmatch.json
index aea9585..72ed6db 100644
--- a/impl/src/test/resources/trafficmatch.json
+++ b/impl/src/test/resources/trafficmatch.json
@@ -1,6 +1,7 @@
 {
   "traffic_match_id": "-1756753738",
   "policy_id": "DROP",
+  "priority": 60000,
   "selector": {
     "criteria": [
       {
diff --git a/web/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java b/web/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java
index 5a24ca5..f876f18 100644
--- a/web/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java
+++ b/web/src/main/java/org/onosproject/segmentrouting/web/PolicyWebResource.java
@@ -252,7 +252,7 @@
             }
             policyService.addOrUpdateTrafficMatch(trafficMatch);
             root.put(TRAFFIC_MATCH_ID, trafficMatch.trafficMatchId().toString());
-        } catch (IOException ex) {
+        } catch (IOException | IllegalArgumentException ex) {
             throw new IllegalArgumentException(ex);
         }
 
diff --git a/web/src/main/resources/definitions/TrafficMatchCreate.json b/web/src/main/resources/definitions/TrafficMatchCreate.json
index 3ab1022..f901e33 100644
--- a/web/src/main/resources/definitions/TrafficMatchCreate.json
+++ b/web/src/main/resources/definitions/TrafficMatchCreate.json
@@ -3,6 +3,7 @@
   "title": "traffic-match-creation",
   "required": [
     "policy_id",
+    "priority",
     "selector"
   ],
   "properties": {
@@ -11,6 +12,11 @@
       "example": "DROP",
       "description": "ID of associated policy"
     },
+    "priority": {
+      "type": "int",
+      "example": "60000",
+      "description": "Priority of the TrafficMatch"
+    },
     "selector": {
       "type": "object",
       "title": "selector",