Initial skeleton for the flow space analyzer application.

Change-Id: I1fe9e57a6c66e80a504b98f46fc160aa34003172
diff --git a/apps/flowanalyzer/pom.xml b/apps/flowanalyzer/pom.xml
new file mode 100644
index 0000000..e068be6
--- /dev/null
+++ b/apps/flowanalyzer/pom.xml
@@ -0,0 +1,45 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Copyright 2014 Open Networking Laboratory
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~     http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.onosproject</groupId>
+        <artifactId>onos-apps</artifactId>
+        <version>1.3.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+
+    <artifactId>onos-app-flowanalyzer</artifactId>
+    <packaging>bundle</packaging>
+
+    <description>Simple flow space analyzer</description>
+
+    <properties>
+        <onos.app.name>org.onosproject.flowanalyzer</onos.app.name>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
diff --git a/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalyzer.java b/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalyzer.java
new file mode 100644
index 0000000..5d99d74
--- /dev/null
+++ b/apps/flowanalyzer/src/main/java/org/onosproject/flowanalyzer/FlowAnalyzer.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2015 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.flowanalyzer;
+
+import org.apache.felix.scr.annotations.Activate;
+import org.apache.felix.scr.annotations.Component;
+import org.apache.felix.scr.annotations.Deactivate;
+import org.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.apache.felix.scr.annotations.Service;
+import org.onosproject.net.flow.FlowRuleService;
+import org.onosproject.net.host.HostService;
+import org.onosproject.net.link.LinkService;
+import org.osgi.service.component.ComponentContext;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Simple flow space analyzer app.
+ */
+@Component(immediate = true)
+@Service(value = FlowAnalyzer.class)
+public class FlowAnalyzer {
+
+    private final Logger log = getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected FlowRuleService flowRuleService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected LinkService linkService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected HostService hostService;
+
+
+    @Activate
+    public void activate(ComponentContext context) {
+        log.info("Started");
+    }
+
+    @Deactivate
+    public void deactivate() {
+        log.info("Stopped");
+    }
+
+
+    /**
+     * ...
+     */
+    public void analyze() {
+        // TODO: implement this
+    }
+
+}
diff --git a/apps/pom.xml b/apps/pom.xml
index e08f306..7f2ac03 100644
--- a/apps/pom.xml
+++ b/apps/pom.xml
@@ -52,6 +52,7 @@
         <module>xos-integration</module>
         <module>pcep-api</module>
         <module>olt</module>
+        <module>flowanalyzer</module>
     </modules>
 
     <properties>
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 61f3552..b612b9e 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
@@ -254,6 +254,7 @@
             try {
                 // Otherwise create it and if it has pipeline behaviour, cache it
                 handler = driverService.createHandler(deviceId);
+                bTime = now();
                 if (!handler.driver().hasBehaviour(Pipeliner.class)) {
                     log.warn("Pipeline behaviour not supported for device {}",
                              deviceId);
@@ -265,13 +266,16 @@
             }
 
             driverHandlers.put(deviceId, handler);
+            cTime = now();
         }
 
         // Always (re)initialize the pipeline behaviour
         log.info("Driver {} bound to device {} ... initializing driver",
                  handler.driver().name(), deviceId);
         Pipeliner pipeliner = handler.behaviour(Pipeliner.class);
+        dTime = now();
         pipeliner.init(deviceId, context);
+        eTime = now();
         pipeliners.putIfAbsent(deviceId, pipeliner);
     }
 
@@ -282,11 +286,12 @@
             switch (event.type()) {
                 case MASTER_CHANGED:
                     log.debug("mastership changed on device {}", event.subject());
-                    long start = startWatch();
+                    start = now();
                     if (deviceService.isAvailable(event.subject())) {
+                        aTime = now();
                         setupPipelineHandler(event.subject());
                     }
-                    stopWatch(start);
+                    stopWatch();
                     break;
                 case BACKUPS_CHANGED:
                     break;
@@ -304,13 +309,14 @@
                 case DEVICE_ADDED:
                 case DEVICE_AVAILABILITY_CHANGED:
                     log.debug("Device either added or availability changed {}",
-                             event.subject().id());
-                    long start = startWatch();
+                              event.subject().id());
+                    start = now();
                     if (deviceService.isAvailable(event.subject().id())) {
+                        aTime = now();
                         log.debug("Device is now available {}", event.subject().id());
                         setupPipelineHandler(event.subject().id());
                     }
-                    stopWatch(start);
+                    stopWatch();
                     break;
                 case DEVICE_UPDATED:
                     break;
@@ -332,22 +338,29 @@
 
     // Temporary mechanism to monitor pipeliner setup time-cost; there are
     // intermittent time where this takes in excess of 2 seconds. Why?
-    private long totals = 0, count = 0;
-    private static final long LIMIT = 1;
+    private long start = 0, totals = 0, count = 0;
+    private long aTime, bTime, cTime, dTime, eTime;
+    private static final long LIMIT = 500;
 
-    private long startWatch() {
+    private long now() {
         return System.currentTimeMillis();
     }
 
-    private void stopWatch(long start) {
+    private void stopWatch() {
         long duration = System.currentTimeMillis() - start;
         totals += duration;
         count += 1;
         if (duration > LIMIT) {
-            log.info("Pipeline setup took {} ms; avg {} ms", duration, totals / count);
+            log.info("Pipeline setup took {} ms; avg {} ms; a={}, b={}, c={}, d={}, e={}",
+                     duration, totals / count, diff(aTime), diff(bTime),
+                     diff(cTime), diff(dTime), diff(eTime));
         }
     }
 
+    private long diff(long bTime) {
+        return bTime - start;
+    }
+
     // Processing context for initializing pipeline driver behaviours.
     private class InnerPipelineContext implements PipelinerContext {
         @Override