Traffic Treatements now support deferred, immediate, table, and clear instructions.

By default, treatments are all immediate. Treatments will be deferred if the builder
predicated by deferred(). Subsequent treatments will be deferred until immediate is called
on the builder again. Multiple calls to deferred and immediate are permitted.

Change-Id: I76b3a44f2219fc1e72a7fb41b72d7bd602be85b7
diff --git a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
index 75f7f7f..aa5af74 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/DefaultTrafficTreatment.java
@@ -17,7 +17,7 @@
 
 import com.google.common.base.MoreObjects;
 import com.google.common.collect.ImmutableList;
-
+import com.google.common.collect.Lists;
 import org.onlab.packet.IpAddress;
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
@@ -27,7 +27,6 @@
 import org.onosproject.net.flow.instructions.Instruction;
 import org.onosproject.net.flow.instructions.Instructions;
 
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Objects;
 
@@ -36,7 +35,11 @@
  */
 public final class DefaultTrafficTreatment implements TrafficTreatment {
 
-    private final List<Instruction> instructions;
+    private final List<Instruction> immediate;
+    private final List<Instruction> deferred;
+    private final Instructions.TableTypeTransition table;
+
+    private final boolean hasClear;
 
     /**
      * Creates a new traffic treatment from the specified list of instructions.
@@ -44,12 +47,46 @@
      * @param instructions treatment instructions
      */
     private DefaultTrafficTreatment(List<Instruction> instructions) {
-        this.instructions = ImmutableList.copyOf(instructions);
+        this.immediate = ImmutableList.copyOf(instructions);
+        this.deferred = ImmutableList.of();
+        this.hasClear = false;
+        this.table = null;
+    }
+
+    private DefaultTrafficTreatment(List<Instruction> deferred,
+                                   List<Instruction> immediate,
+                                   Instructions.TableTypeTransition table,
+                                   boolean clear) {
+        this.immediate = ImmutableList.copyOf(immediate);
+        this.deferred = ImmutableList.copyOf(deferred);
+        this.table = table;
+        this.hasClear = clear;
+
     }
 
     @Override
     public List<Instruction> instructions() {
-        return instructions;
+        return immediate;
+    }
+
+    @Override
+    public List<Instruction> deferred() {
+        return deferred;
+    }
+
+    @Override
+    public List<Instruction> immediate() {
+        return immediate;
+    }
+
+    @Override
+    public Instructions.TableTypeTransition tableTransition() {
+        return table;
+    }
+
+    @Override
+    public Boolean clearedDeferred() {
+        return hasClear;
     }
 
     /**
@@ -75,7 +112,7 @@
     //FIXME: Order of instructions may affect hashcode
     @Override
     public int hashCode() {
-        return Objects.hash(instructions);
+        return Objects.hash(immediate, deferred, table);
     }
 
     @Override
@@ -85,7 +122,9 @@
         }
         if (obj instanceof DefaultTrafficTreatment) {
             DefaultTrafficTreatment that = (DefaultTrafficTreatment) obj;
-            return Objects.equals(instructions, that.instructions);
+            return Objects.equals(immediate, that.immediate) &&
+                    Objects.equals(deferred, that.deferred) &&
+                    Objects.equals(table, that.table);
 
         }
         return false;
@@ -94,7 +133,10 @@
     @Override
     public String toString() {
         return MoreObjects.toStringHelper(getClass())
-                .add("instructions", instructions)
+                .add("immediate", immediate)
+                .add("deferred", deferred)
+                .add("transition", table == null ? "None" : table.toString())
+                .add("cleared", hasClear)
                 .toString();
     }
 
@@ -106,19 +148,22 @@
 
         boolean drop = false;
 
-        List<Instruction> outputs = new LinkedList<>();
+        boolean clear = false;
 
-        // TODO: should be a list of instructions based on group objects
-        List<Instruction> groups = new LinkedList<>();
+        Instructions.TableTypeTransition table;
 
-        // TODO: should be a list of instructions based on modification objects
-        List<Instruction> modifications = new LinkedList<>();
+        List<Instruction> deferred = Lists.newLinkedList();
+
+        List<Instruction> immediate = Lists.newLinkedList();
+
+        List<Instruction> current = immediate;
 
         // Creates a new builder
         private Builder() {
         }
 
         // Creates a new builder based off an existing treatment
+        //FIXME only works for immediate instruction sets.
         private Builder(TrafficTreatment treatment) {
             for (Instruction instruction : treatment.instructions()) {
                 add(instruction);
@@ -127,30 +172,26 @@
 
         @Override
         public Builder add(Instruction instruction) {
-            if (drop) {
-                return this;
-            }
+
             switch (instruction.type()) {
                 case DROP:
-                    drop = true;
-                    break;
-                case TABLE:
                 case OUTPUT:
-                    outputs.add(instruction);
-                    break;
+                case GROUP:
                 case L0MODIFICATION:
                 case L2MODIFICATION:
                 case L3MODIFICATION:
-                    // TODO: enforce modification order if any
-                    modifications.add(instruction);
+                    current.add(instruction);
                     break;
-                case GROUP:
-                    groups.add(instruction);
+                case TABLE:
+                    table = (Instructions.TableTypeTransition) instruction;
                     break;
                 default:
                     throw new IllegalArgumentException("Unknown instruction type: " +
                                                                instruction.type());
+
+
             }
+
             return this;
         }
 
@@ -254,27 +295,40 @@
         }
 
         @Override
-        public TrafficTreatment.Builder transition(FlowRule.Type type) {
-            return add(Instructions.transition(type));
-        }
-
-        @Override
         public Builder popVlan() {
             return add(Instructions.popVlan());
         }
 
         @Override
+        public Builder transition(FlowRule.Type type) {
+            return add(Instructions.transition(type));
+        }
+
+        @Override
+        public Builder immediate() {
+            current = immediate;
+            return this;
+        }
+
+        @Override
+        public Builder deferred() {
+            current = deferred;
+            return this;
+        }
+
+        @Override
+        public Builder wipeDeferred() {
+            clear = true;
+            return this;
+        }
+
+        @Override
         public TrafficTreatment build() {
-
-            //If we are dropping should we just return an empty list?
-            List<Instruction> instructions = new LinkedList<Instruction>();
-            instructions.addAll(modifications);
-            instructions.addAll(groups);
-            if (!drop) {
-                instructions.addAll(outputs);
+            if (deferred.size() == 0 && immediate.size() == 0
+                    && table == null && !clear) {
+                drop();
             }
-
-            return new DefaultTrafficTreatment(instructions);
+            return new DefaultTrafficTreatment(deferred, immediate, table, clear);
         }
 
     }
diff --git a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
index 1d2f7f4..b44411b 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/TrafficTreatment.java
@@ -25,6 +25,7 @@
 import org.onlab.packet.MacAddress;
 import org.onlab.packet.MplsLabel;
 import org.onlab.packet.VlanId;
+import org.onosproject.net.flow.instructions.Instructions;
 
 /**
  * Abstraction of network traffic treatment.
@@ -36,9 +37,37 @@
      *
      * @return list of treatment instructions
      */
+    @Deprecated
     List<Instruction> instructions();
 
     /**
+     * Returns the list of treatment instructions that will be applied
+     * further down the pipeline.
+     * @return list of treatment instructions
+     */
+    List<Instruction> deferred();
+
+    /**
+     * Returns the list of treatment instructions that will be applied
+     * immediately.
+     * @return list of treatment instructions
+     */
+    List<Instruction> immediate();
+
+    /**
+     * Returns the next table in the pipeline.
+     * @return a table transition; may be null.
+     */
+    Instructions.TableTypeTransition tableTransition();
+
+    /**
+     * Whether the deferred treatment instructions will be cleared
+     * by the device.
+     * @return a boolean
+     */
+    Boolean clearedDeferred();
+
+    /**
      * Builder of traffic treatment entities.
      */
     public interface Builder {
@@ -218,6 +247,25 @@
         public Builder popVlan();
 
         /**
+         * Any instructions preceded by this method call will be deferred.
+         * @return a treatment builder
+         */
+        public Builder deferred();
+
+        /**
+         * Any instructions preceded by this method call will be immediate.
+         * @return a treatment builder
+         */
+        public Builder immediate();
+
+
+        /**
+         * Instructs the device to clear the deferred instructions set.
+         * @return a treatment builder
+         */
+        public Builder wipeDeferred();
+
+        /**
          * Builds an immutable traffic treatment descriptor.
          *
          * @return traffic treatment
diff --git a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
index afbae7d..47e473f 100644
--- a/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
+++ b/core/api/src/main/java/org/onosproject/net/flow/instructions/Instructions.java
@@ -295,7 +295,7 @@
 
         @Override
         public String toString() {
-            return toStringHelper(type()).toString();
+            return toStringHelper(type().toString()).toString();
 
         }