Moved validity checks inside l2TunnelHandler.

Moved every validity check for pseudowires inside the handler
itself, this simplified the usage of handler methods from within
the SegmentRoutingManager. Further, improved the api for removing
pseudowires of the l2tunnel handler.

Change-Id: Idb2607aa546b0734add29d446cbedfd3b23c46bb
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
index 79dd832..73a1c36 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/SegmentRoutingManager.java
@@ -147,7 +147,6 @@
 import static org.onlab.util.Tools.groupedThreads;
 import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_REGISTERED;
 import static org.onosproject.net.config.NetworkConfigEvent.Type.CONFIG_UNREGISTERED;
-import static org.onosproject.segmentrouting.pwaas.PwaasUtil.configurationValidity;
 
 /**
  * Segment routing manager.
@@ -595,56 +594,12 @@
 
     @Override
     public L2TunnelHandler.Result addPseudowire(L2TunnelDescription l2TunnelDescription) {
-
-        // get both added and pending pseudowires
-        List<L2TunnelDescription> newPseudowires = new ArrayList<>();
-        newPseudowires.addAll(l2TunnelHandler.getL2Descriptions(false));
-        newPseudowires.addAll(l2TunnelHandler.getL2Descriptions(true));
-
-        // add the new pseudowire to the List
-        newPseudowires.add(l2TunnelDescription);
-        // validate the new list of pseudowires
-        L2TunnelHandler.Result res = configurationValidity(newPseudowires);
-        if (res == L2TunnelHandler.Result.SUCCESS) {
-            log.debug("Pseudowire with {} deployment started, check log for any errors in this process!",
-                     l2TunnelDescription.l2Tunnel().tunnelId());
-            return l2TunnelHandler.deployPseudowire(l2TunnelDescription, false);
-        } else {
-            log.error("Pseudowire with {} can not be added, error in global validity!",
-                      l2TunnelDescription.l2Tunnel().tunnelId());
-            return res;
-        }
+        return l2TunnelHandler.deployPseudowire(l2TunnelDescription);
     }
 
     @Override
     public L2TunnelHandler.Result removePseudowire(Integer pwId) {
-
-        // get both added and pending pseudowires
-        Set<L2TunnelDescription> pseudowires = l2TunnelHandler.getL2Descriptions(false)
-                .stream()
-                .filter(pw -> pw.l2Tunnel().tunnelId() == pwId)
-                .collect(Collectors.toSet());
-        Set<L2TunnelDescription> pendingPseudowires = l2TunnelHandler.getL2Descriptions(true)
-                .stream()
-                .filter(pw -> pw.l2Tunnel().tunnelId() == pwId)
-                .collect(Collectors.toSet());
-
-        if ((pendingPseudowires.size() == 0) && (pseudowires.size() == 0)) {
-            log.error("Pseudowire with id {} does not exist", pwId);
-            return L2TunnelHandler.Result.WRONG_PARAMETERS
-                    .appendError("Pseudowire does not exist.");
-        }
-        if (pendingPseudowires.size() != 0) {
-            log.info("Remove pseudowire from pending store!");
-            // will fill when we implement failure mechanism detection.
-        }
-        if (pseudowires.size() != 0) {
-            log.info("Removal of pseudowire with {} started, check log for any errors in this process!",
-                     pwId);
-            return l2TunnelHandler.tearDownPseudowire(pwId);
-        }
-
-        return L2TunnelHandler.Result.SUCCESS;
+        return l2TunnelHandler.tearDownPseudowire(pwId);
     }
 
     @Override
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
index faabdfe..dc8500d 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/DefaultL2TunnelHandler.java
@@ -68,6 +68,7 @@
 import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Result.*;
 import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.FWD;
 import static org.onosproject.segmentrouting.pwaas.L2TunnelHandler.Direction.REV;
+import static org.onosproject.segmentrouting.pwaas.PwaasUtil.*;
 
 /**
  * Handles pwaas related events.
@@ -176,7 +177,6 @@
                 .withSerializer(Serializer.using(l2TunnelKryo.build()))
                 .build();
 
-
         vlanStore = srManager.storageService.<VlanId>setBuilder()
                 .withName("onos-transport-vlan-store")
                 .withSerializer(Serializer.using(
@@ -200,10 +200,9 @@
 
     @Override
     public Set<L2TunnelDescription> getL2Descriptions(boolean pending) {
-        if (!pending) {
-            List<L2Tunnel> tunnels = getL2Tunnels();
-            List<L2TunnelPolicy> policies = getL2Policies();
-
+            // get pending tunnels/policies OR installed tunnels/policies
+            List<L2Tunnel> tunnels = pending ? getL2PendingTunnels() : getL2Tunnels();
+            List<L2TunnelPolicy> policies = pending ? getL2PendingPolicies() : getL2Policies();
             return tunnels.stream()
                 .map(l2Tunnel -> {
                     L2TunnelPolicy policy = null;
@@ -217,29 +216,10 @@
                     return new DefaultL2TunnelDescription(l2Tunnel, policy);
                 })
                 .collect(Collectors.toSet());
-        } else {
-            List<L2Tunnel> tunnels = getL2PendingTunnels();
-            List<L2TunnelPolicy> policies = getL2PendingPolicies();
-
-            return tunnels.stream()
-                    .map(l2Tunnel -> {
-                        L2TunnelPolicy policy = null;
-                        for (L2TunnelPolicy l2Policy : policies) {
-                            if (l2Policy.tunnelId() == l2Tunnel.tunnelId()) {
-                                policy = l2Policy;
-                                break;
-                            }
-                        }
-
-                        return new DefaultL2TunnelDescription(l2Tunnel, policy);
-                    })
-                    .collect(Collectors.toSet());
-        }
     }
 
     @Override
     public List<L2TunnelPolicy> getL2Policies() {
-
         return new ArrayList<>(l2PolicyStore
                 .values()
                 .stream()
@@ -249,7 +229,6 @@
 
     @Override
     public List<L2Tunnel> getL2Tunnels() {
-
         return new ArrayList<>(l2TunnelStore
                 .values()
                 .stream()
@@ -259,7 +238,6 @@
 
     @Override
     public List<L2TunnelPolicy> getL2PendingPolicies() {
-
         return new ArrayList<>(pendingL2PolicyStore
                                        .values()
                                        .stream()
@@ -269,7 +247,6 @@
 
     @Override
     public List<L2Tunnel> getL2PendingTunnels() {
-
         return new ArrayList<>(pendingL2TunnelStore
                                        .values()
                                        .stream()
@@ -277,6 +254,19 @@
                                        .collect(Collectors.toList()));
     }
 
+    @Override
+    public Result verifyGlobalValidity(L2TunnelDescription pwToAdd) {
+
+        // get both added and pending pseudowires
+        List<L2TunnelDescription> newPseudowires = new ArrayList<>();
+        newPseudowires.addAll(getL2Descriptions(false));
+        newPseudowires.addAll(getL2Descriptions(true));
+        // add the new one
+        newPseudowires.add(pwToAdd);
+
+        return configurationValidity(newPseudowires);
+    }
+
     /**
      * Manages intermediate filtering rules.
      *
@@ -531,14 +521,16 @@
      * Adds a single pseudowire.
      *
      * @param pw The pseudowire to deploy
-     * @param removeFromPending if to remove the pseudowire from the pending store
      * @return result of pseudowire deployment
      */
-    public Result deployPseudowire(L2TunnelDescription pw, boolean removeFromPending) {
+    public Result deployPseudowire(L2TunnelDescription pw) {
 
         Result result;
         long l2TunnelId;
 
+        log.debug("Pseudowire with {} deployment started, check log for any errors in this process!",
+                  pw.l2Tunnel().tunnelId());
+
         l2TunnelId = pw.l2Tunnel().tunnelId();
         // The tunnel id cannot be 0.
         if (l2TunnelId == 0) {
@@ -547,6 +539,12 @@
                     .appendError("Tunnel id id must be > 0");
         }
 
+        result = verifyGlobalValidity(pw);
+        if (result != SUCCESS) {
+            log.error("Global validity for pseudowire {} is wrong!", l2TunnelId);
+            return result;
+        }
+
         // leafSpinePw determines if this is a leaf-leaf
         // or leaf-spine pseudowire
         boolean leafSpinePw;
@@ -705,23 +703,28 @@
         // Populate stores as the final step of the process
         l2TunnelStore.put(Long.toString(l2TunnelId), pw.l2Tunnel());
         l2PolicyStore.put(Long.toString(l2TunnelId), pw.l2TunnelPolicy());
-        // if removeFromPending then remove the information from the pending stores.
-        if (removeFromPending) {
-            // check existence of tunnels/policy in the pending store, if one is missing abort!
-            Versioned<L2Tunnel> l2TunnelVersioned = pendingL2TunnelStore.get(Long.toString(l2TunnelId));
-            Versioned<L2TunnelPolicy> l2TunnelPolicyVersioned = pendingL2PolicyStore.get(Long.toString(l2TunnelId));
-            if ((l2TunnelVersioned == null) || (l2TunnelPolicyVersioned == null)) {
-                log.warn("Removal process : Policy and/or tunnel missing for tunnel id {} in pending store",
-                         l2TunnelId);
-            } else {
-                pendingL2TunnelStore.remove(Long.toString(l2TunnelId));
-                pendingL2PolicyStore.remove(Long.toString(l2TunnelId));
-            }
-        }
 
         return Result.SUCCESS;
     }
 
+    @Override
+    public Result checkIfPwExists(long tunnelId, boolean pending) {
+
+        List<L2TunnelDescription> pseudowires = getL2Descriptions(pending)
+                .stream()
+                .filter(pw -> pw.l2Tunnel().tunnelId() == tunnelId)
+                .collect(Collectors.toList());
+
+        if (pseudowires.size() == 0) {
+            String store = ((pending) ? "pending" : "installed");
+            log.error("Pseudowire {} does not exist in {} store", tunnelId, store);
+            return Result.WRONG_PARAMETERS.
+                    appendError("Pseudowire " + tunnelId + " does not exist in " + store);
+        } else {
+            return SUCCESS;
+        }
+    }
+
     /**
      * Tears down connection points of pseudowires. We can either tear down both connection points,
      * or each one of them.
@@ -729,14 +732,17 @@
      * @param l2TunnelId The tunnel id for this pseudowire.
      * @param tearDownFirst Boolean, true if we want to tear down cp1
      * @param tearDownSecond Boolean, true if we want to tear down cp2
+     * @param pending Boolean, if true remove only pseudowire from pending stores since no flows/groups
+     *                in the network, else remove flows/groups in the devices also.
      * @return Result of tearing down the pseudowire, SUCCESS if everything was ok
-     *         WRONG_PARAMETERS or INTERNAL_ERROR otherwise
+     *         a descriptive error otherwise.
      */
-    private Result tearDownConnectionPoints(long l2TunnelId, boolean tearDownFirst, boolean tearDownSecond) {
+    private Result tearDownConnectionPoints(long l2TunnelId, boolean tearDownFirst,
+                                            boolean tearDownSecond, boolean pending) {
 
+        Result res;
         CompletableFuture<ObjectiveError> fwdInitNextFuture = new CompletableFuture<>();
         CompletableFuture<ObjectiveError> fwdTermNextFuture = new CompletableFuture<>();
-
         CompletableFuture<ObjectiveError> revInitNextFuture = new CompletableFuture<>();
         CompletableFuture<ObjectiveError> revTermNextFuture = new CompletableFuture<>();
 
@@ -745,9 +751,19 @@
             return Result.WRONG_PARAMETERS.appendError("Pseudowire id can not be 0.");
         }
 
-        // check existence of tunnels/policy in the store, if one is missing abort!
-        Versioned<L2Tunnel> l2TunnelVersioned = l2TunnelStore.get(Long.toString(l2TunnelId));
-        Versioned<L2TunnelPolicy> l2TunnelPolicyVersioned = l2PolicyStore.get(Long.toString(l2TunnelId));
+        res = checkIfPwExists(l2TunnelId, pending);
+        if (res != Result.SUCCESS) {
+            return res;
+        }
+
+        // remove and get the tunnel and the policy from the appropriate store
+        // if null, return error.
+        Versioned<L2Tunnel> l2TunnelVersioned = pending ?
+                pendingL2TunnelStore.remove(Long.toString(l2TunnelId)) :
+                l2TunnelStore.remove(Long.toString(l2TunnelId));
+        Versioned<L2TunnelPolicy> l2TunnelPolicyVersioned = pending ?
+                pendingL2PolicyStore.remove(Long.toString(l2TunnelId)) :
+                l2PolicyStore.remove(Long.toString(l2TunnelId));
         if ((l2TunnelVersioned == null) || (l2TunnelPolicyVersioned == null)) {
             log.warn("Removal process : Policy and/or tunnel missing for tunnel id {}", l2TunnelId);
             return Result.INTERNAL_ERROR
@@ -757,15 +773,18 @@
         L2TunnelDescription pwToRemove = new DefaultL2TunnelDescription(l2TunnelVersioned.value(),
                                                                         l2TunnelPolicyVersioned.value());
 
-        // remove the tunnels and the policies from the store
-        l2PolicyStore.remove(Long.toString(l2TunnelId));
-        l2TunnelStore.remove(Long.toString(l2TunnelId));
-
         // remove the reserved transport vlan
         if (!pwToRemove.l2Tunnel().transportVlan().equals(UNTAGGED_TRANSPORT_VLAN)) {
             vlanStore.remove(pwToRemove.l2Tunnel().transportVlan());
         }
 
+        if (pending) {
+            // no need to remove flows / groups for a pseudowire
+            // in pending state
+            return Result.SUCCESS;
+        }
+
+        // remove flows/groups involving with this pseudowire
         if (tearDownFirst) {
             log.info("Removal process : Tearing down forward direction of pseudowire {}", l2TunnelId);
 
@@ -842,16 +861,24 @@
 
     /**
      * Helper function for removing a single pseudowire.
-     * <p>
-     * No mastership of CP1 is checked, because it can be called from
-     * the CLI for removal of pseudowires.
+     *
+     * Tries to remove pseudowire from any store it might reside (pending or installed).
      *
      * @param l2TunnelId the id of the pseudowire to tear down
      * @return Returns SUCCESS if no error is obeserved or an appropriate
      * error on a failure
      */
     public Result tearDownPseudowire(long l2TunnelId) {
-        return tearDownConnectionPoints(l2TunnelId, true, true);
+
+        if (checkIfPwExists(l2TunnelId, true) == Result.SUCCESS) {
+            return tearDownConnectionPoints(l2TunnelId, true, true, true);
+        } else if (checkIfPwExists(l2TunnelId, false) == Result.SUCCESS) {
+            return tearDownConnectionPoints(l2TunnelId, true, true, false);
+        } else {
+            return Result.WRONG_PARAMETERS.appendError("Pseudowire with "
+                                                        + l2TunnelId
+                                                        + " did not reside in any store!");
+        }
     }
 
     @Deprecated
diff --git a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
index 347d7f0..2f7fa32 100644
--- a/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
+++ b/apps/segmentrouting/app/src/main/java/org/onosproject/segmentrouting/pwaas/L2TunnelHandler.java
@@ -73,6 +73,24 @@
     List<L2Tunnel> getL2PendingTunnels();
 
     /**
+     * Verifies global validity for existing pseudowires, both ones in
+     * the pending store and the ones installed.
+     *
+     * @param pwToAdd the new pseudowire to add
+     * @return a Result describing the outcome
+     */
+    Result verifyGlobalValidity(L2TunnelDescription pwToAdd);
+
+    /**
+     * Check if pseudowire exists in the store.
+     *
+     * @param tunnelId The tunnel id to check for.
+     * @param pending Check in pending store for pseudowires.
+     * @return The result of the operation.
+     */
+    Result checkIfPwExists(long tunnelId, boolean pending);
+
+    /**
      * Pwaas pipelines.
      */
     enum Pipeline {
@@ -106,12 +124,12 @@
         INTERNAL_ERROR(3, "Internal error"),
 
         /**
-         *
+         * No path found between the connection points.
          */
         PATH_NOT_FOUND(7, "Could not find valid path between connection points!"),
 
         /**
-         *
+         * Error in global pseudowires configuration.
          */
         CONFIGURATION_ERROR(8, "Conflicting pseudowire configurations!");