[SDFAB-359] Purge all objective for a given application ID

Change-Id: I51847b0be890deacec5caddc18d52bcd2993959a
(cherry picked from commit 607fd0b70e4553226d0937d36de9cde655f2eb62)
diff --git a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowObjectiveManager.java b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowObjectiveManager.java
index 0a5a509..b4c84b6 100644
--- a/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowObjectiveManager.java
+++ b/apps/virtual/app/src/main/java/org/onosproject/incubator/net/virtual/impl/VirtualNetworkFlowObjectiveManager.java
@@ -26,6 +26,7 @@
 import org.apache.commons.lang3.tuple.Pair;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.util.KryoNamespace;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.incubator.net.virtual.AbstractVnetService;
 import org.onosproject.incubator.net.virtual.NetworkId;
 import org.onosproject.incubator.net.virtual.VirtualNetworkFlowObjectiveStore;
@@ -248,6 +249,12 @@
         return pendingFlowObjectives;
     }
 
+    @Override
+    public void purgeAll(DeviceId deviceId, ApplicationId appId) {
+        // TODO: purge queued flow objectives?
+        pipeliners.get(deviceId).purgeAll(appId);
+    }
+
     private boolean queueFwdObjective(DeviceId deviceId, ForwardingObjective fwd) {
         boolean queued = false;
         synchronized (pendingForwards) {
@@ -696,6 +703,11 @@
         }
 
         @Override
+        public void purgeAll(ApplicationId appId) {
+            flowRuleService.purgeFlowRules(deviceId, appId);
+        }
+
+        @Override
         public List<String> getNextMappings(NextGroup nextGroup) {
             // Default single table pipeline does not use nextObjectives or groups
             return null;
diff --git a/core/api/src/main/java/org/onosproject/net/behaviour/Pipeliner.java b/core/api/src/main/java/org/onosproject/net/behaviour/Pipeliner.java
index 6f497e7..bd4af6c 100644
--- a/core/api/src/main/java/org/onosproject/net/behaviour/Pipeliner.java
+++ b/core/api/src/main/java/org/onosproject/net/behaviour/Pipeliner.java
@@ -17,6 +17,7 @@
 
 import java.util.List;
 
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.driver.HandlerBehaviour;
 import org.onosproject.net.flowobjective.FilteringObjective;
@@ -68,6 +69,13 @@
     void next(NextObjective nextObjective);
 
     /**
+     * Purges all objectives for the given application.
+     *
+     * @param appId application identifier
+     */
+    void purgeAll(ApplicationId appId);
+
+    /**
      *  Retrieves a mapping of the nextObjective to the groups in the dataplane,
      *  and returns it in a form that can be displayed on the CLI. Typically
      *  group-ids are returned for groups with multiple buckets, where each list element
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 11a7f5f..4def953 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
@@ -25,6 +25,7 @@
 import com.google.common.collect.Maps;
 import org.apache.commons.lang.NotImplementedException;
 import org.apache.commons.lang3.tuple.Pair;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 
 /**
@@ -129,6 +130,14 @@
     List<String> getPendingFlowObjectives();
 
     /**
+     * Purges all flow objectives on a given device and for a given application.
+     *
+     * @param deviceId device identifier
+     * @param appId application identifier
+     */
+    void purgeAll(DeviceId deviceId, ApplicationId appId);
+
+    /**
      * Returns all filtering objective that are waiting for the completion of previous objective
      * with the same FilteringObjQueueKey.
      *
diff --git a/core/api/src/test/java/org/onosproject/net/behaviour/PipelinerAdapter.java b/core/api/src/test/java/org/onosproject/net/behaviour/PipelinerAdapter.java
index c87dee2..0ff3644 100644
--- a/core/api/src/test/java/org/onosproject/net/behaviour/PipelinerAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/behaviour/PipelinerAdapter.java
@@ -17,6 +17,7 @@
 
 import java.util.List;
 
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.driver.DriverData;
 import org.onosproject.net.driver.DriverHandler;
@@ -49,6 +50,11 @@
     }
 
     @Override
+    public void purgeAll(ApplicationId appId) {
+
+    }
+
+    @Override
     public DriverHandler handler() {
         return null;
     }
diff --git a/core/api/src/test/java/org/onosproject/net/flowobjective/FlowObjectiveServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/flowobjective/FlowObjectiveServiceAdapter.java
index 0b17ce8..66ff125 100644
--- a/core/api/src/test/java/org/onosproject/net/flowobjective/FlowObjectiveServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/flowobjective/FlowObjectiveServiceAdapter.java
@@ -18,6 +18,7 @@
 
 import com.google.common.collect.ImmutableList;
 import com.google.common.collect.ImmutableMap;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 import org.apache.commons.lang3.tuple.Pair;
 import java.util.Map;
@@ -70,6 +71,11 @@
     }
 
     @Override
+    public void purgeAll(DeviceId deviceId, ApplicationId appId) {
+
+    }
+
+    @Override
     public Map<Pair<Integer, DeviceId>, List<String>> getNextMappingsChain() {
         return ImmutableMap.of();
     }
diff --git a/core/api/src/test/java/org/onosproject/net/meter/MeterServiceAdapter.java b/core/api/src/test/java/org/onosproject/net/meter/MeterServiceAdapter.java
index cc55672..7148c06 100644
--- a/core/api/src/test/java/org/onosproject/net/meter/MeterServiceAdapter.java
+++ b/core/api/src/test/java/org/onosproject/net/meter/MeterServiceAdapter.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.net.meter;
 
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 
 import java.util.Collection;
@@ -65,6 +66,11 @@
     }
 
     @Override
+    public void purgeMeters(DeviceId deviceId, ApplicationId appId) {
+
+    }
+
+    @Override
     public void addListener(MeterListener listener) {
 
     }
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
index 597e91e..a31f0b9 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/FlowObjectiveManager.java
@@ -27,6 +27,7 @@
 import org.onlab.util.Tools;
 import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.cluster.ClusterService;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.behaviour.NextGroup;
@@ -834,4 +835,34 @@
 
         return pendingFlowObjectives;
     }
+
+    @Override
+    public void purgeAll(DeviceId deviceId, ApplicationId appId) {
+        synchronized (pendingForwards) {
+            List<Integer> emptyPendingForwards = Lists.newArrayList();
+            pendingForwards.forEach((nextId, pendingObjectives) -> {
+                pendingObjectives.removeIf(pendingFlowObjective -> pendingFlowObjective.deviceId().equals(deviceId));
+                if (pendingObjectives.isEmpty()) {
+                    emptyPendingForwards.add(nextId);
+                }
+            });
+            emptyPendingForwards.forEach(pendingForwards::remove);
+        }
+        synchronized (pendingNexts) {
+            List<Integer> emptyPendingNexts = Lists.newArrayList();
+            pendingNexts.forEach((nextId, pendingObjectives) -> {
+                pendingObjectives.removeIf(pendingFlowObjective -> pendingFlowObjective.deviceId().equals(deviceId));
+                if (pendingObjectives.isEmpty()) {
+                    emptyPendingNexts.add(nextId);
+                }
+            });
+            emptyPendingNexts.forEach(pendingNexts::remove);
+        }
+        Pipeliner pipeliner = getDevicePipeliner(deviceId);
+        if (pipeliner != null) {
+            pipeliner.purgeAll(appId);
+        } else {
+            log.warn("Skip purgeAll, pipeliner not ready!");
+        }
+    }
 }
diff --git a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java
index dc5ef05..b930d6b 100644
--- a/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java
+++ b/core/net/src/main/java/org/onosproject/net/flowobjective/impl/composition/FlowObjectiveCompositionManager.java
@@ -23,6 +23,7 @@
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.util.ItemNotFoundException;
 import org.onosproject.cluster.ClusterService;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.mastership.MastershipEvent;
 import org.onosproject.mastership.MastershipListener;
 import org.onosproject.mastership.MastershipService;
@@ -441,4 +442,9 @@
         // TODO Implementation deferred as this is an experimental component.
         return ImmutableList.of();
     }
+
+    @Override
+    public void purgeAll(DeviceId deviceId, ApplicationId appId) {
+        // TODO Implementation deferred as this is an experimental component.
+    }
 }
diff --git a/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/AbstractCorsaPipeline.java b/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/AbstractCorsaPipeline.java
index b0b02be..b9fa750 100644
--- a/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/AbstractCorsaPipeline.java
+++ b/drivers/corsa/src/main/java/org/onosproject/drivers/corsa/AbstractCorsaPipeline.java
@@ -647,4 +647,10 @@
             }
         }));
     }
+
+    @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+        groupService.purgeGroupEntries(deviceId, appId);
+    }
 }
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java
index cad1a88..dedc810 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/CentecV350Pipeline.java
@@ -289,6 +289,11 @@
 
     }
 
+    @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+    }
+
     private Collection<FlowRule> processForward(ForwardingObjective fwd) {
         switch (fwd.flag()) {
             case SPECIFIC:
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java
index 1b3d310..e66adb9 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/DefaultSingleTablePipeline.java
@@ -21,6 +21,7 @@
 import com.google.common.cache.RemovalNotification;
 import org.onlab.osgi.ServiceDirectory;
 import org.onlab.util.KryoNamespace;
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.behaviour.NextGroup;
 import org.onosproject.net.behaviour.Pipeliner;
@@ -274,6 +275,11 @@
     }
 
     @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+    }
+
+    @Override
     public List<String> getNextMappings(NextGroup nextGroup) {
         // Default single table pipeline does not use nextObjectives or groups
         return Collections.emptyList();
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java
index ef79ee3..57ef6ea 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/PicaPipeline.java
@@ -216,6 +216,11 @@
 
     }
 
+    @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+    }
+
     private Collection<FlowRule> processForward(ForwardingObjective fwd) {
         switch (fwd.flag()) {
             case SPECIFIC:
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
index 9ca9420..1d0e0dd 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SoftRouterPipeline.java
@@ -186,6 +186,11 @@
         }
     }
 
+    @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+    }
+
     private void pass(Objective obj) {
         obj.context().ifPresent(context -> context.onSuccess(obj));
     }
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
index 4376295..166ba72 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/SpringOpenTTP.java
@@ -286,6 +286,12 @@
         }
     }
 
+    @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+        groupService.purgeGroupEntries(deviceId, appId);
+    }
+
     private void removeGroup(NextObjective nextObjective) {
         log.debug("removeGroup in {}: for next objective id {}",
                   deviceId, nextObjective.id());
diff --git a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
index a020a64..a22ecbe 100644
--- a/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
+++ b/drivers/default/src/main/java/org/onosproject/driver/pipeline/ofdpa/Ofdpa2Pipeline.java
@@ -477,6 +477,12 @@
         }
     }
 
+    @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+        groupService.purgeGroupEntries(deviceId, appId);
+    }
+
     //////////////////////////////////////
     //  Flow handling
     //////////////////////////////////////
diff --git a/drivers/hp/src/main/java/org/onosproject/drivers/hp/AbstractHPPipeline.java b/drivers/hp/src/main/java/org/onosproject/drivers/hp/AbstractHPPipeline.java
index 7979ab1..4d1f013 100644
--- a/drivers/hp/src/main/java/org/onosproject/drivers/hp/AbstractHPPipeline.java
+++ b/drivers/hp/src/main/java/org/onosproject/drivers/hp/AbstractHPPipeline.java
@@ -544,6 +544,13 @@
         }
     }
 
+    @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+        groupService.purgeGroupEntries(deviceId, appId);
+        meterService.purgeMeters(deviceId, appId);
+    }
+
     /**
      * Gets traffic treatment from a next objective.
      * Merge traffic treatments from next objective if the next objective is
diff --git a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicPipelinerImpl.java b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicPipelinerImpl.java
index 9fc532b..3b66f95 100644
--- a/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicPipelinerImpl.java
+++ b/pipelines/basic/src/main/java/org/onosproject/pipelines/basic/BasicPipelinerImpl.java
@@ -16,6 +16,7 @@
 
 package org.onosproject.pipelines.basic;
 
+import org.onosproject.core.ApplicationId;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.behaviour.NextGroup;
 import org.onosproject.net.behaviour.Pipeliner;
@@ -101,6 +102,11 @@
     }
 
     @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+    }
+
+    @Override
     public List<String> getNextMappings(NextGroup nextGroup) {
         // We do not use nextObjectives or groups.
         return Collections.emptyList();
diff --git a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FabricPipeliner.java b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FabricPipeliner.java
index 3105e66..e3bc567 100644
--- a/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FabricPipeliner.java
+++ b/pipelines/fabric/impl/src/main/java/org/onosproject/pipelines/fabric/impl/behaviour/pipeliner/FabricPipeliner.java
@@ -204,6 +204,13 @@
     }
 
     @Override
+    public void purgeAll(ApplicationId appId) {
+        flowRuleService.purgeFlowRules(deviceId, appId);
+        groupService.purgeGroupEntries(deviceId, appId);
+        // TODO: should we purge also the FlowObjectiveStore?
+    }
+
+    @Override
     public List<String> getNextMappings(NextGroup nextGroup) {
         final FabricNextGroup fabricNextGroup = KRYO.deserialize(nextGroup.data());
         return fabricNextGroup.nextMappings().stream()