[SDFAB-1100] In-order flowrule processing

Extends the FlowRuleService and its api by adding in-order processing
capabilities. This is achieved by introducing stripe key as way to
indicate how to process the flowrules. Key is an object which is used
to select a specific executor. Operations having the same key is guaranteed
that will be processed by the same executor.

Change-Id: I5ab4d42e8a2b8cb869f3dc2305dbc5084d31f08b
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperations.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperations.java
index 9c0f522..14af90d 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperations.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleOperations.java
@@ -24,7 +24,9 @@
 import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;
-import static org.onosproject.net.flow.FlowRuleOperation.Type.*;
+import static org.onosproject.net.flow.FlowRuleOperation.Type.ADD;
+import static org.onosproject.net.flow.FlowRuleOperation.Type.REMOVE;
+import static org.onosproject.net.flow.FlowRuleOperation.Type.MODIFY;
 
 /**
  * A batch of flow rule operations that are broken into stages.
@@ -34,17 +36,21 @@
 
     private final List<Set<FlowRuleOperation>> stages;
     private final FlowRuleOperationsContext callback;
+    private final Integer stripeKey;
 
     private FlowRuleOperations(List<Set<FlowRuleOperation>> stages,
-                               FlowRuleOperationsContext cb) {
+                               FlowRuleOperationsContext cb,
+                               Integer stripeKey) {
         this.stages = stages;
         this.callback = cb;
+        this.stripeKey = stripeKey;
     }
 
     // kryo-constructor
     protected FlowRuleOperations() {
         this.stages = Lists.newArrayList();
         this.callback = null;
+        this.stripeKey = null;
     }
 
     /**
@@ -67,6 +73,18 @@
     }
 
     /**
+     * Returns the stripe key. Expectation is that FlowRuleOperations with the
+     * same key will be executed sequentially in the same order as they are
+     * submitted to the FlowRuleService. Operations without a key or with
+     * different keys might be executed in parallel.
+     *
+     * @return the stripe key associated to this or null if not present
+     */
+    public Integer stripeKey() {
+        return stripeKey;
+    }
+
+    /**
      * Returns a new builder.
      *
      * @return new builder
@@ -89,6 +107,7 @@
 
         private final ImmutableList.Builder<Set<FlowRuleOperation>> listBuilder = ImmutableList.builder();
         private ImmutableSet.Builder<FlowRuleOperation> currentStage = ImmutableSet.builder();
+        private Integer stripeKey = null;
 
         // prevent use of the default constructor outside of this file; use the above method
         private Builder() {}
@@ -160,6 +179,25 @@
         }
 
         /**
+         * Provides semantics similar to lock striping. FlowRuleOperations
+         * with the same key will be executed sequentially. Operations without
+         * a key or with different keys might be executed in parallel.
+         * <p>
+         * This parameter is useful to correlate different operations with
+         * potentially conflicting writes, to guarantee that operations are
+         * executed in-order. For example, to handle the case where one operation
+         * that removes a flow rule is followed by one that adds the same flow rule.
+         * </p>
+         *
+         * @param stripeKey an integer key
+         * @return this
+         */
+        public Builder striped(int stripeKey) {
+            this.stripeKey = stripeKey;
+            return this;
+        }
+
+        /**
          * Builds the immutable flow rule operations.
          *
          * @return flow rule operations
@@ -178,7 +216,7 @@
             checkNotNull(cb);
 
             closeStage();
-            return new FlowRuleOperations(listBuilder.build(), cb);
+            return new FlowRuleOperations(listBuilder.build(), cb, stripeKey);
         }
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
index 9cada03..807d09e 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/FlowRuleService.java
@@ -196,4 +196,33 @@
     default long getActiveFlowRuleCount(DeviceId deviceId) {
         return 0;
     }
+
+    /**
+     * Applies the specified flow rules onto their respective devices. Similar
+     * to {@link FlowRuleService#applyFlowRules(FlowRule...)} but expectation is
+     * that flow rules applied by subsequent calls using the same key will be
+     * executed sequentially. Flow rules applied through {@link FlowRuleService#applyFlowRules(FlowRule...)}
+     * might be executed in parallel.
+     *
+     * @param stripeKey an integer key
+     * @param flowRules one or more flow rules
+     */
+    default void applyFlowRules(int stripeKey, FlowRule... flowRules) {
+
+    }
+
+    /**
+     * Removes the specified flow rules from their respective devices. Similar
+     * to {@link FlowRuleService#removeFlowRules(FlowRule...)} but expectation is
+     * that flow rules removed by subsequent calls using the same key will be
+     * executed sequentially. Flow rules applied through {@link FlowRuleService#removeFlowRules(FlowRule...)}
+     * might be executed in parallel.
+     *
+     * @param stripeKey an integer key
+     * @param flowRules one or more flow rules
+     */
+    default void removeFlowRules(int stripeKey, FlowRule... flowRules) {
+
+    }
+
 }