Implementation of new Flow Subsystem:

The subsystem no longer returns futures for tracking completion of work.
Notifications are explicitely returned via a call back mechanism. Also, the
subsystem is now asynchronous.

Change-Id: I1a4cef931c24820f9ae9ed9a5398f163f05dfbc9

more flowservice improvements

Change-Id: I5c9c1b6be4b2ebfa523b64f6f52e7634b7d3e05f

more flowservice impl

Change-Id: I05f6774460effb53ced8c36844bcda2f8f6c096f

Manager to store functional (at least i believe it)

Change-Id: I09b04989bd1004c98fe0bafed4c76714b9155d53

flow subsystem functional: need to fix unit tests

Change-Id: I1667f25b91320f625a03e5e1d5e92823184d9de0

flow subsystem functional

Change-Id: I429b3335c16d4fc16f5d55f233dd37c4d1d6111d

finished refactor of flow subsystem

Change-Id: I1899abc6ff6a974a2018d936cc555049c70a6804

fix for null flow provider to use new api

Change-Id: If2fd9bd5baf74d9c61c5c8085cef8bc2d204cbdc
diff --git a/cli/src/main/java/org/onosproject/cli/net/AddFlowsCommand.java b/cli/src/main/java/org/onosproject/cli/net/AddFlowsCommand.java
index a5fc611..9c4700c 100644
--- a/cli/src/main/java/org/onosproject/cli/net/AddFlowsCommand.java
+++ b/cli/src/main/java/org/onosproject/cli/net/AddFlowsCommand.java
@@ -19,29 +19,30 @@
 import com.fasterxml.jackson.databind.ObjectMapper;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import com.google.common.base.Stopwatch;
 import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
+import org.apache.commons.lang.math.RandomUtils;
 import org.apache.karaf.shell.commands.Argument;
 import org.apache.karaf.shell.commands.Command;
+import org.onlab.packet.MacAddress;
 import org.onosproject.cli.AbstractShellCommand;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
 import org.onosproject.net.Device;
 import org.onosproject.net.PortNumber;
 import org.onosproject.net.device.DeviceService;
-import org.onosproject.net.flow.CompletedBatchOperation;
 import org.onosproject.net.flow.DefaultFlowRule;
 import org.onosproject.net.flow.DefaultTrafficSelector;
 import org.onosproject.net.flow.DefaultTrafficTreatment;
-import org.onosproject.net.flow.FlowRuleBatchEntry;
-import org.onosproject.net.flow.FlowRuleBatchOperation;
+import org.onosproject.net.flow.FlowRuleOperations;
+import org.onosproject.net.flow.FlowRuleOperationsContext;
 import org.onosproject.net.flow.FlowRuleService;
 import org.onosproject.net.flow.TrafficSelector;
 import org.onosproject.net.flow.TrafficTreatment;
-import org.onlab.packet.MacAddress;
 
 import java.util.ArrayList;
-import java.util.Set;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Installs many many flows.
@@ -50,6 +51,8 @@
          description = "Installs a number of test flow rules - for testing only")
 public class AddFlowsCommand extends AbstractShellCommand {
 
+    private CountDownLatch latch;
+
     @Argument(index = 0, name = "flowPerDevice", description = "Number of flows to add per device",
               required = true, multiValued = false)
     String flows = null;
@@ -63,6 +66,9 @@
 
         FlowRuleService flowService = get(FlowRuleService.class);
         DeviceService deviceService = get(DeviceService.class);
+        CoreService coreService = get(CoreService.class);
+
+        ApplicationId appId = coreService.registerApplication("onos.test.flow.installer");
 
         int flowsPerDevice = Integer.parseInt(flows);
         int num = Integer.parseInt(numOfRuns);
@@ -70,49 +76,73 @@
         ArrayList<Long> results = Lists.newArrayList();
         Iterable<Device> devices = deviceService.getDevices();
         TrafficTreatment treatment = DefaultTrafficTreatment.builder()
-                .setOutput(PortNumber.portNumber(1)).build();
+                .setOutput(PortNumber.portNumber(RandomUtils.nextInt())).build();
         TrafficSelector.Builder sbuilder;
-        Set<FlowRuleBatchEntry> rules = Sets.newHashSet();
-        Set<FlowRuleBatchEntry> remove = Sets.newHashSet();
+        FlowRuleOperations.Builder rules = FlowRuleOperations.builder();
+        FlowRuleOperations.Builder remove = FlowRuleOperations.builder();
+
         for (Device d : devices) {
             for (int i = 0; i < flowsPerDevice; i++) {
                 sbuilder = DefaultTrafficSelector.builder();
-                sbuilder.matchEthSrc(MacAddress.valueOf(i))
-                        .matchEthDst(MacAddress.valueOf(Integer.MAX_VALUE - i));
-                rules.add(new FlowRuleBatchEntry(FlowRuleBatchEntry.FlowRuleOperation.ADD,
-                                                    new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
-                                                                        100, (long) 0, 10, false)));
-                remove.add(new FlowRuleBatchEntry(FlowRuleBatchEntry.FlowRuleOperation.REMOVE,
-                                                 new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
-                                                                     100, (long) 0, 10, false)));
+
+                sbuilder.matchEthSrc(MacAddress.valueOf(RandomUtils.nextInt() * i))
+                        .matchEthDst(MacAddress.valueOf((Integer.MAX_VALUE - i) * RandomUtils.nextInt()));
+
+
+                int randomPriority = RandomUtils.nextInt();
+                rules.add(new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
+                                              randomPriority, appId, 10, false));
+                remove.remove(new DefaultFlowRule(d.id(), sbuilder.build(), treatment,
+                                                  randomPriority, appId, 10, false));
 
             }
         }
-        boolean isSuccess = true;
+
         for (int i = 0; i < num; i++) {
-            long startTime = System.currentTimeMillis();
-            Future<CompletedBatchOperation> op = flowService.applyBatch(
-                    new FlowRuleBatchOperation(rules));
+
+            latch = new CountDownLatch(2);
+            flowService.apply(rules.build(new FlowRuleOperationsContext() {
+
+                private final Stopwatch timer = Stopwatch.createStarted();
+
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+
+                    timer.stop();
+                    results.add(timer.elapsed(TimeUnit.MILLISECONDS));
+                    if (results.size() == num) {
+                        if (outputJson()) {
+                            print("%s", json(new ObjectMapper(), true, results));
+                        } else {
+                            printTime(true, results);
+                        }
+                    }
+                    latch.countDown();
+                }
+            }));
+
+
+            flowService.apply(remove.build(new FlowRuleOperationsContext() {
+                @Override
+                public void onSuccess(FlowRuleOperations ops) {
+                    latch.countDown();
+                }
+            }));
             try {
-                isSuccess &= op.get().isSuccess();
-            } catch (InterruptedException | ExecutionException e) {
+                latch.await();
+            } catch (InterruptedException e) {
                 e.printStackTrace();
             }
-            long endTime = System.currentTimeMillis();
-            results.add(endTime - startTime);
-            flowService.applyBatch(
-                    new FlowRuleBatchOperation(remove));
+
         }
-        if (outputJson()) {
-            print("%s", json(new ObjectMapper(), isSuccess, results));
-        } else {
-            printTime(isSuccess, results);
-        }
+
 
 
 
     }
 
+
+
     private Object json(ObjectMapper mapper, boolean isSuccess, ArrayList<Long> elapsed) {
         ObjectNode result = mapper.createObjectNode();
         result.put("Success", isSuccess);