Add bulk delete for flows

Change-Id: I77f266c75d0f9d1e99155eb48c216bff3fab2f40
diff --git a/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java b/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
index befb60e..9b62e42 100644
--- a/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
+++ b/web/api/src/main/java/org/onosproject/rest/resources/FlowsWebResource.java
@@ -19,6 +19,7 @@
 import java.io.InputStream;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.stream.StreamSupport;
 
@@ -44,6 +45,10 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+
+import static org.onlab.util.Tools.nullIsNotFound;
 
 /**
  * Query and program flow rules.
@@ -53,7 +58,10 @@
 public class FlowsWebResource extends AbstractWebResource {
 
     public static final String DEVICE_NOT_FOUND = "Device is not found";
+    public static final String FLOW_NOT_FOUND = "Flow is not found";
     public static final String FLOWS = "flows";
+    public static final String DEVICE_ID = "deviceId";
+    public static final String FLOW_ID = "flowId";
 
     final FlowRuleService service = get(FlowRuleService.class);
     final ObjectNode root = mapper().createObjectNode();
@@ -102,10 +110,16 @@
             ArrayNode flowsArray = (ArrayNode) jsonTree.get(FLOWS);
             List<FlowRule> rules = codec(FlowRule.class).decode(flowsArray, this);
             service.applyFlowRules(rules.toArray(new FlowRule[rules.size()]));
+            rules.forEach(flowRule -> {
+                ObjectNode flowNode = mapper().createObjectNode();
+                flowNode.put(DEVICE_ID, flowRule.deviceId().toString())
+                        .put(FLOW_ID, flowRule.id().value());
+                flowsNode.add(flowNode);
+            });
         } catch (IOException ex) {
             throw new IllegalArgumentException(ex);
         }
-        return Response.ok().build();
+        return Response.ok(root).build();
     }
 
     /**
@@ -224,4 +238,45 @@
                 .forEach(service::removeFlowRules);
     }
 
+    /**
+     * Removes a batch of flow rules.
+     */
+    @DELETE
+    @Produces(MediaType.APPLICATION_JSON)
+    public void deleteFlows(InputStream stream) {
+        ListMultimap<DeviceId, Long> deviceMap = ArrayListMultimap.create();
+        List<FlowEntry> rulesToRemove = new ArrayList<>();
+
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+
+            JsonNode jsonFlows = jsonTree.get("flows");
+
+            jsonFlows.forEach(node -> {
+                DeviceId deviceId =
+                        DeviceId.deviceId(
+                                nullIsNotFound(node.get(DEVICE_ID),
+                                               DEVICE_NOT_FOUND).asText());
+                long flowId = nullIsNotFound(node.get(FLOW_ID),
+                                             FLOW_NOT_FOUND).asLong();
+                deviceMap.put(deviceId, flowId);
+
+            });
+        } catch (IOException ex) {
+            throw new IllegalArgumentException(ex);
+        }
+
+        deviceMap.keySet().forEach(deviceId -> {
+            List<Long> flowIds = deviceMap.get(deviceId);
+            Iterable<FlowEntry> entries = service.getFlowEntries(deviceId);
+            flowIds.forEach(flowId -> {
+                StreamSupport.stream(entries.spliterator(), false)
+                        .filter(entry -> flowId == entry.id().value())
+                        .forEach(rulesToRemove::add);
+            });
+        });
+
+        service.removeFlowRules(rulesToRemove.toArray(new FlowEntry[0]));
+    }
+
 }