ONOS-5775: Partial failure constraint in VPLS

Change-Id: I6a4b6e9468e6e3ae028a1d2fc2e4d51c63c50776
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/IntentInstaller.java b/apps/vpls/src/main/java/org/onosproject/vpls/IntentInstaller.java
index 2cec14a..7b4667b 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/IntentInstaller.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/IntentInstaller.java
@@ -27,6 +27,7 @@
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.intent.ConnectivityIntent;
+import org.onosproject.net.intent.Constraint;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.intent.IntentState;
@@ -34,10 +35,12 @@
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
 import org.onosproject.net.intent.SinglePointToMultiPointIntent;
 import org.onosproject.net.intent.constraint.EncapsulationConstraint;
+import org.onosproject.net.intent.constraint.PartialFailureConstraint;
 import org.onosproject.routing.IntentSynchronizationService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
@@ -76,6 +79,9 @@
     private final IntentSynchronizationService intentSynchronizer;
     private final IntentService intentService;
 
+    public static final ImmutableList<Constraint> PARTIAL_FAILURE_CONSTRAINT =
+            ImmutableList.of(new PartialFailureConstraint());
+
     /**
      * Class constructor.
      *
@@ -155,9 +161,10 @@
                 .selector(selector)
                 .filteredIngressPoint(src)
                 .filteredEgressPoints(dsts)
+                .constraints(PARTIAL_FAILURE_CONSTRAINT)
                 .priority(PRIORITY_OFFSET);
 
-        encap(intentBuilder, encap);
+        setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);
 
         return intentBuilder.build();
     }
@@ -191,9 +198,10 @@
                 .selector(selector)
                 .filteredIngressPoints(srcs)
                 .filteredEgressPoint(dst)
+                .constraints(PARTIAL_FAILURE_CONSTRAINT)
                 .priority(PRIORITY_OFFSET);
 
-        encap(intentBuilder, encap);
+        setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);
 
         return intentBuilder.build();
     }
@@ -246,17 +254,31 @@
     }
 
     /**
-     * Adds an encapsulation constraint to the builder given, if encap is not
-     * equal to NONE.
+     * Sets one or more encapsulation constraints on the intent builder given.
      *
      * @param builder the intent builder
-     * @param encap the encapsulation type
+     * @param constraints the existing intent constraints
+     * @param encap the encapsulation type to be set
      */
-    private static void encap(ConnectivityIntent.Builder builder,
-                              EncapsulationType encap) {
+    public static void setEncap(ConnectivityIntent.Builder builder,
+                                List<Constraint> constraints,
+                                EncapsulationType encap) {
+        // Constraints might be an immutable list, so a new modifiable list
+        // is created
+        List<Constraint> newConstraints = new ArrayList<>(constraints);
+
+        // Remove any encapsulation constraint if already in the list
+        constraints.stream()
+                .filter(c -> c instanceof EncapsulationConstraint)
+                .forEach(newConstraints::remove);
+
+        // if the new encapsulation is different from NONE, a new encapsulation
+        // constraint should be added to the list
         if (!encap.equals(NONE)) {
-            builder.constraints(ImmutableList.of(
-                    new EncapsulationConstraint(encap)));
+            newConstraints.add(new EncapsulationConstraint(encap));
         }
+
+        // Submit new constraint list as immutable list
+        builder.constraints(ImmutableList.copyOf(newConstraints));
     }
 }
diff --git a/apps/vpls/src/main/java/org/onosproject/vpls/Vpls.java b/apps/vpls/src/main/java/org/onosproject/vpls/Vpls.java
index 658ddad..444b5aa 100644
--- a/apps/vpls/src/main/java/org/onosproject/vpls/Vpls.java
+++ b/apps/vpls/src/main/java/org/onosproject/vpls/Vpls.java
@@ -116,7 +116,6 @@
 
     private ApplicationId appId;
 
-
     @Activate
     public void activate() {
         appId = coreService.registerApplication(VPLS_APP);
diff --git a/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java b/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
index bc1c3f2..5f5aaec 100644
--- a/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
+++ b/apps/vpls/src/test/java/org/onosproject/vpls/VplsTest.java
@@ -15,24 +15,13 @@
  */
 package org.onosproject.vpls;
 
-import java.util.Collection;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicLong;
-import java.util.stream.Collectors;
-
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Sets;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.collect.SetMultimap;
 import com.google.common.collect.HashMultimap;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Lists;
+import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.ImmutableSetMultimap;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.SetMultimap;
+import com.google.common.collect.Sets;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -51,11 +40,11 @@
 import org.onosproject.net.DefaultHost;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.EncapsulationType;
+import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.Host;
 import org.onosproject.net.HostId;
 import org.onosproject.net.HostLocation;
 import org.onosproject.net.PortNumber;
-import org.onosproject.net.FilteredConnectPoint;
 import org.onosproject.net.config.NetworkConfigService;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.TrafficSelector;
@@ -65,7 +54,6 @@
 import org.onosproject.net.host.HostListener;
 import org.onosproject.net.host.HostService;
 import org.onosproject.net.host.HostServiceAdapter;
-import org.onosproject.net.intent.ConnectivityIntent;
 import org.onosproject.net.intent.Intent;
 import org.onosproject.net.intent.IntentService;
 import org.onosproject.net.intent.IntentServiceAdapter;
@@ -73,24 +61,27 @@
 import org.onosproject.net.intent.Key;
 import org.onosproject.net.intent.MultiPointToSinglePointIntent;
 import org.onosproject.net.intent.SinglePointToMultiPointIntent;
-import org.onosproject.net.intent.constraint.EncapsulationConstraint;
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.routing.IntentSynchronizationAdminService;
 import org.onosproject.routing.IntentSynchronizationService;
 import org.onosproject.vpls.config.VplsConfigService;
 
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.stream.Collectors;
+
 import static java.lang.String.format;
-import static org.easymock.EasyMock.anyObject;
-import static org.easymock.EasyMock.createMock;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.replay;
+import static org.easymock.EasyMock.*;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertTrue;
-
 import static org.onosproject.net.EncapsulationType.*;
-import static org.onosproject.vpls.IntentInstaller.PREFIX_BROADCAST;
-import static org.onosproject.vpls.IntentInstaller.PREFIX_UNICAST;
+import static org.onosproject.vpls.IntentInstaller.*;
 
 /**
  * Tests for the {@link Vpls} class.
@@ -503,7 +494,9 @@
                             .collect(Collectors.toSet());
 
             Key brckey = buildKey(PREFIX_BROADCAST,
-                                  point.connectPoint(), name, MacAddress.BROADCAST);
+                                  point.connectPoint(),
+                                  name,
+                                  MacAddress.BROADCAST);
 
             intents.add(buildBrcIntent(brckey, point, otherPoints, encap));
         });
@@ -594,9 +587,10 @@
                 .selector(selector)
                 .filteredIngressPoint(src)
                 .filteredEgressPoints(dsts)
+                .constraints(PARTIAL_FAILURE_CONSTRAINT)
                 .priority(PRIORITY_OFFSET);
 
-        encap(intentBuilder, encap);
+        setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);
 
         return intentBuilder.build();
     }
@@ -627,9 +621,10 @@
                 .selector(selector)
                 .filteredIngressPoints(srcs)
                 .filteredEgressPoint(dst)
+                .constraints(PARTIAL_FAILURE_CONSTRAINT)
                 .priority(PRIORITY_OFFSET);
 
-        encap(intentBuilder, encap);
+        setEncap(intentBuilder, PARTIAL_FAILURE_CONSTRAINT, encap);
 
         return intentBuilder.build();
     }
@@ -709,21 +704,6 @@
     }
 
     /**
-     * Adds an encapsulation constraint to the builder given, if encap is not
-     * equal to NONE.
-     *
-     * @param builder the intent builder
-     * @param encap the encapsulation type
-     */
-    private static void encap(ConnectivityIntent.Builder builder,
-                              EncapsulationType encap) {
-        if (!encap.equals(NONE)) {
-            builder.constraints(ImmutableList.of(
-                    new EncapsulationConstraint(encap)));
-        }
-    }
-
-    /**
      * Returns the device Id of the ith device.
      *
      * @param i the device to get the Id of
diff --git a/core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.java b/core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.java
index ec43e08..787d126 100644
--- a/core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.java
+++ b/core/api/src/main/java/org/onosproject/net/intent/constraint/PartialFailureConstraint.java
@@ -50,6 +50,22 @@
     }
 
     @Override
+    public int hashCode() {
+        return 1;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj == null || getClass() != obj.getClass()) {
+            return false;
+        }
+        return true;
+    }
+
+    @Override
     public String toString() {
         return "PartialFailureConstraint";
     }