Adding copy builders for flow objectives.

Adding missing hashCode and equals methods.

Change-Id: I97b2d904eacf0c45a95905c0891dbc6465e18ec6
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java
index 4d9d722..593cde6 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultFilteringObjective.java
@@ -36,7 +36,6 @@
 @Beta
 public final class DefaultFilteringObjective implements FilteringObjective {
 
-
     private final Type type;
     private final boolean permanent;
     private final int timeout;
@@ -62,7 +61,7 @@
         this.meta = builder.meta;
 
         this.id = Objects.hash(type, key, conditions, permanent,
-                timeout, appId, priority);
+                               timeout, appId, priority);
     }
 
     @Override
@@ -121,6 +120,33 @@
         return context;
     }
 
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type, permanent, timeout, appId, priority, key,
+                            conditions, op, meta);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultFilteringObjective) {
+            final DefaultFilteringObjective other = (DefaultFilteringObjective) obj;
+            return Objects.equals(this.type, other.type)
+                    && Objects.equals(this.permanent, other.permanent)
+                    && Objects.equals(this.timeout, other.timeout)
+                    && Objects.equals(this.appId, other.appId)
+                    && Objects.equals(this.priority, other.priority)
+                    && Objects.equals(this.key, other.key)
+                    && Objects.equals(this.conditions, other.conditions)
+                    && Objects.equals(this.op, other.op)
+                    && Objects.equals(this.meta, other.meta);
+        }
+        return false;
+    }
+
     /**
      * Returns a new builder.
      *
@@ -130,6 +156,10 @@
         return new Builder();
     }
 
+    @Override
+    public Builder copy() {
+        return new Builder(this);
+    }
 
     public static final class Builder implements FilteringObjective.Builder {
         private final ImmutableList.Builder<Criterion> listBuilder
@@ -146,6 +176,23 @@
         private ObjectiveContext context;
         private TrafficTreatment meta;
 
+        // Creates an empty builder
+        private Builder() {
+        }
+
+        // Creates a builder set to create a copy of the specified objective.
+        private Builder(FilteringObjective objective) {
+            this.type = objective.type();
+            this.key = objective.key();
+            this.conditions = ImmutableList.copyOf(objective.conditions());
+            this.permanent = objective.permanent();
+            this.timeout = objective.timeout();
+            this.priority = objective.priority();
+            this.appId = objective.appId();
+            this.meta = objective.meta();
+            this.op = objective.op();
+        }
+
         @Override
         public Builder withKey(Criterion key) {
             this.key = key;
@@ -210,7 +257,6 @@
             checkNotNull(appId, "Must supply an application id");
 
             return new DefaultFilteringObjective(this);
-
         }
 
         @Override
@@ -222,7 +268,6 @@
             op = Operation.REMOVE;
 
             return new DefaultFilteringObjective(this);
-
         }
 
         @Override
@@ -249,7 +294,6 @@
             return new DefaultFilteringObjective(this);
         }
 
-
     }
 
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultForwardingObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultForwardingObjective.java
index af48180..7c442b2 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultForwardingObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultForwardingObjective.java
@@ -120,49 +120,28 @@
         return context;
     }
 
-    /*
-     * (non-Javadoc)
-     *
-     * @see java.lang.Object#hashCode()
-     */
     @Override
     public int hashCode() {
-        return Objects.hash(selector, flag, permanent,
-                            timeout, appId, priority, nextId,
-                            treatment, op);
+        return Objects.hash(selector, flag, permanent, timeout, appId,
+                            priority, nextId, treatment, op);
     }
 
-    /*
-     * (non-Javadoc)
-     *
-     * @see java.lang.Object#equals(java.lang.Object)
-     */
     @Override
-    public boolean equals(final Object obj) {
+    public boolean equals(Object obj) {
         if (this == obj) {
             return true;
         }
-        if (!(obj instanceof DefaultForwardingObjective)) {
-            return false;
-        }
-        final DefaultForwardingObjective other = (DefaultForwardingObjective) obj;
-        boolean nextEq = false, treatmentEq = false;
-        if (this.selector.equals(other.selector) &&
-                this.flag == other.flag &&
-                this.permanent == other.permanent &&
-                this.timeout == other.timeout &&
-                this.appId.equals(other.appId) &&
-                this.priority == other.priority &&
-                this.op == other.op) {
-            if (this.nextId != null && other.nextId != null) {
-                nextEq = this.nextId == other.nextId;
-            }
-            if (this.treatment != null && other.treatment != null) {
-                treatmentEq = this.treatment.equals(other.treatment);
-            }
-            if (nextEq && treatmentEq) {
-                return true;
-            }
+        if (obj instanceof DefaultForwardingObjective) {
+            final DefaultForwardingObjective other = (DefaultForwardingObjective) obj;
+            return Objects.equals(this.selector, other.selector)
+                    && Objects.equals(this.flag, other.flag)
+                    && Objects.equals(this.permanent, other.permanent)
+                    && Objects.equals(this.timeout, other.timeout)
+                    && Objects.equals(this.appId, other.appId)
+                    && Objects.equals(this.priority, other.priority)
+                    && Objects.equals(this.nextId, other.nextId)
+                    && Objects.equals(this.treatment, other.treatment)
+                    && Objects.equals(this.op, other.op);
         }
         return false;
     }
@@ -176,6 +155,13 @@
         return new Builder();
     }
 
+
+    @Override
+    public Builder copy() {
+        return new Builder(this);
+    }
+
+
     public static final class Builder implements ForwardingObjective.Builder {
 
         private TrafficSelector selector;
@@ -189,6 +175,23 @@
         private Operation op;
         private ObjectiveContext context;
 
+        // Creates an empty builder
+        private Builder() {
+        }
+
+        // Creates a builder set to create a copy of the specified objective.
+        private Builder(ForwardingObjective objective) {
+            this.selector = objective.selector();
+            this.flag = objective.flag();
+            this.permanent = objective.permanent();
+            this.timeout = objective.timeout();
+            this.priority = objective.priority();
+            this.appId = objective.appId();
+            this.nextId = objective.nextId();
+            this.treatment = objective.treatment();
+            this.op = objective.op();
+        }
+
         @Override
         public Builder withSelector(TrafficSelector selector) {
             this.selector = selector;
@@ -286,4 +289,5 @@
             return new DefaultForwardingObjective(this);
         }
     }
+
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java
index bd58050..8010659 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/DefaultNextObjective.java
@@ -23,6 +23,7 @@
 
 import java.util.Collection;
 import java.util.List;
+import java.util.Objects;
 import java.util.Optional;
 
 import static com.google.common.base.Preconditions.checkArgument;
@@ -102,6 +103,28 @@
         return meta;
     }
 
+    @Override
+    public int hashCode() {
+        return Objects.hash(treatments, appId, type, id, op, meta);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultNextObjective) {
+            final DefaultNextObjective other = (DefaultNextObjective) obj;
+            return Objects.equals(this.treatments, other.treatments)
+                    && Objects.equals(this.appId, other.appId)
+                    && Objects.equals(this.type, other.type)
+                    && Objects.equals(this.id, other.id)
+                    && Objects.equals(this.op, other.op)
+                    && Objects.equals(this.meta, other.meta);
+        }
+        return false;
+    }
+
     /**
      * Returns a new builder.
      *
@@ -111,6 +134,11 @@
         return new Builder();
     }
 
+    @Override
+    public Builder copy() {
+        return new Builder(this);
+    }
+
     public static final class Builder implements NextObjective.Builder {
 
         private ApplicationId appId;
@@ -124,6 +152,20 @@
         private final ImmutableList.Builder<TrafficTreatment> listBuilder
                 = ImmutableList.builder();
 
+        // Creates an empty builder
+        private Builder() {
+        }
+
+        // Creates a builder set to create a copy of the specified objective.
+        private Builder(NextObjective objective) {
+            this.type = objective.type();
+            this.id = objective.id();
+            this.treatments = ImmutableList.copyOf(objective.next());
+            this.meta = objective.meta();
+            this.appId = objective.appId();
+            this.op = objective.op();
+        }
+
         @Override
         public Builder withId(int nextId) {
             this.id = nextId;
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java
index 8ed793d..d74b082 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/FilteringObjective.java
@@ -149,6 +149,7 @@
          *
          * @return a filtering objective
          */
+        @Override
         FilteringObjective add();
 
         /**
@@ -156,6 +157,7 @@
          *
          * @return a filtering objective.
          */
+        @Override
         FilteringObjective remove();
 
         /**
@@ -165,6 +167,7 @@
          * @param context an objective context
          * @return a filtering objective
          */
+        @Override
         FilteringObjective add(ObjectiveContext context);
 
         /**
@@ -174,6 +177,7 @@
          * @param context an objective context
          * @return a filtering objective
          */
+        @Override
         FilteringObjective remove(ObjectiveContext context);
 
 
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java b/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java
index d325415..4935990 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/FlowObjectiveService.java
@@ -28,7 +28,7 @@
     /**
      * Installs the filtering rules onto the specified device.
      *
-     * @param deviceId            device identifier
+     * @param deviceId           device identifier
      * @param filteringObjective the filtering objective
      */
     void filter(DeviceId deviceId, FilteringObjective filteringObjective);
@@ -36,7 +36,7 @@
     /**
      * Installs the forwarding rules onto the specified device.
      *
-     * @param deviceId             device identifier
+     * @param deviceId            device identifier
      * @param forwardingObjective the forwarding objective
      */
     void forward(DeviceId deviceId, ForwardingObjective forwardingObjective);
@@ -44,7 +44,7 @@
     /**
      * Installs the next hop elements into the specified device.
      *
-     * @param deviceId       device identifier
+     * @param deviceId      device identifier
      * @param nextObjective a next objective
      */
     void next(DeviceId deviceId, NextObjective nextObjective);
@@ -59,7 +59,25 @@
     /**
      * Installs the filtering rules onto the specified device.
      *
-     * @param policy            policy expression
+     * @param policy policy expression
      */
     void initPolicy(String policy);
+
+    /**
+     * Installs the objective onto the specified device.
+     *
+     * @param deviceId  device identifier
+     * @param objective the objective
+     */
+    default void apply(DeviceId deviceId, Objective objective) {
+        if (ForwardingObjective.class.isAssignableFrom(objective.getClass())) {
+            forward(deviceId, (ForwardingObjective) objective);
+        } else if (FilteringObjective.class.isAssignableFrom(objective.getClass())) {
+            filter(deviceId, (FilteringObjective) objective);
+        } else if (NextObjective.class.isAssignableFrom(objective.getClass())) {
+            next(deviceId, (NextObjective) objective);
+        } else {
+            throw new UnsupportedOperationException("Unsupported objective of type " + objective.getClass());
+        }
+    }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjective.java
index 9857a71..bf1bd39 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/ForwardingObjective.java
@@ -128,6 +128,7 @@
          *
          * @return a forwarding objective
          */
+        @Override
         ForwardingObjective add();
 
         /**
@@ -135,6 +136,7 @@
          *
          * @return a forwarding objective.
          */
+        @Override
         ForwardingObjective remove();
 
         /**
@@ -144,6 +146,7 @@
          * @param context an objective context
          * @return a forwarding objective
          */
+        @Override
         ForwardingObjective add(ObjectiveContext context);
 
         /**
@@ -153,6 +156,7 @@
          * @param context an objective context
          * @return a forwarding objective
          */
+        @Override
         ForwardingObjective remove(ObjectiveContext context);
     }
 }
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java
index 36098d7..cbe7ebe 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/NextObjective.java
@@ -154,6 +154,7 @@
          *
          * @return a next objective
          */
+        @Override
         NextObjective add();
 
         /**
@@ -161,6 +162,7 @@
          *
          * @return a next objective.
          */
+        @Override
         NextObjective remove();
 
         /**
@@ -170,6 +172,7 @@
          * @param context an objective context
          * @return a next objective
          */
+        @Override
         NextObjective add(ObjectiveContext context);
 
         /**
@@ -179,6 +182,7 @@
          * @param context an objective context
          * @return a next objective
          */
+        @Override
         NextObjective remove(ObjectiveContext context);
 
         /**
diff --git a/core/api/src/main/java/org/onosproject/net/flowobjective/Objective.java b/core/api/src/main/java/org/onosproject/net/flowobjective/Objective.java
index b1d73a7..eb1e106 100644
--- a/core/api/src/main/java/org/onosproject/net/flowobjective/Objective.java
+++ b/core/api/src/main/java/org/onosproject/net/flowobjective/Objective.java
@@ -112,6 +112,13 @@
     Optional<ObjectiveContext> context();
 
     /**
+     * Returns a new builder set to create a copy of this objective.
+     *
+     * @return new builder
+     */
+    Objective.Builder copy();
+
+    /**
      * An objective builder.
      */
     interface Builder {
@@ -146,6 +153,36 @@
          */
         Builder withPriority(int priority);
 
-    }
+        /**
+         * Builds the objective that will be added.
+         *
+         * @return an objective
+         */
+        Objective add();
 
+        /**
+         * Builds the objective that will be removed.
+         *
+         * @return an objective.
+         */
+        Objective remove();
+
+        /**
+         * Builds the objective that will be added.
+         * The context will be used to notify the calling application.
+         *
+         * @param context an objective context
+         * @return an objective
+         */
+        Objective add(ObjectiveContext context);
+
+        /**
+         * Builds the objective that will be removed.
+         * The context will be used to notify the calling application.
+         *
+         * @param context an objective context
+         * @return an objective
+         */
+        Objective remove(ObjectiveContext context);
+    }
 }