Configurable Port Stats Collection interval

Change-Id: I4999338ecf1c608f93b66ba979126b2a5deda165
diff --git a/providers/openflow/device/pom.xml b/providers/openflow/device/pom.xml
index c02a33e..5f27d42 100644
--- a/providers/openflow/device/pom.xml
+++ b/providers/openflow/device/pom.xml
@@ -30,5 +30,10 @@
     <packaging>bundle</packaging>
 
     <description>ONOS OpenFlow protocol device provider</description>
-
+    <dependencies>
+        <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.compendium</artifactId>
+        </dependency>
+    </dependencies>
 </project>
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index 5f0efa5..656702b 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -19,12 +19,16 @@
 import com.google.common.collect.Lists;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
+
 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.Modified;
+import org.apache.felix.scr.annotations.Property;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
 import org.onlab.packet.ChassisId;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.net.AnnotationKeys;
 import org.onosproject.net.DefaultAnnotations;
 import org.onosproject.net.Device;
@@ -52,6 +56,7 @@
 import org.onosproject.openflow.controller.OpenFlowSwitchListener;
 import org.onosproject.openflow.controller.PortDescPropertyType;
 import org.onosproject.openflow.controller.RoleState;
+import org.osgi.service.component.ComponentContext;
 import org.projectfloodlight.openflow.protocol.OFFactory;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 import org.projectfloodlight.openflow.protocol.OFPortConfig;
@@ -73,10 +78,13 @@
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Dictionary;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.List;
 
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
 import static org.onosproject.net.DeviceId.deviceId;
 import static org.onosproject.net.Port.Type.COPPER;
 import static org.onosproject.net.Port.Type.FIBER;
@@ -100,12 +108,18 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected OpenFlowController controller;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
     private DeviceProviderService providerService;
 
     private final InternalDeviceProvider listener = new InternalDeviceProvider();
 
     // TODO: We need to make the poll interval configurable.
     static final int POLL_INTERVAL = 5;
+    @Property(name = "PortStatsPollFrequency", intValue = POLL_INTERVAL,
+    label = "Frequency (in seconds) for polling switch Port statistics")
+    private int portStatsPollFrequency = POLL_INTERVAL;
 
     private HashMap<Dpid, PortStatsCollector> collectors = Maps.newHashMap();
 
@@ -117,7 +131,8 @@
     }
 
     @Activate
-    public void activate() {
+    public void activate(ComponentContext context) {
+        cfgService.registerProperties(getClass());
         providerService = providerRegistry.register(this);
         controller.addListener(listener);
         controller.addEventListener(listener);
@@ -130,7 +145,7 @@
                 // disconnect to trigger switch-add later
                 sw.disconnectSwitch();
             }
-            PortStatsCollector psc = new PortStatsCollector(sw, POLL_INTERVAL);
+            PortStatsCollector psc = new PortStatsCollector(sw, portStatsPollFrequency);
             psc.start();
             collectors.put(new Dpid(sw.getId()), psc);
         }
@@ -138,7 +153,8 @@
     }
 
     @Deactivate
-    public void deactivate() {
+    public void deactivate(ComponentContext context) {
+        cfgService.unregisterProperties(getClass(), false);
         providerRegistry.unregister(this);
         controller.removeListener(listener);
         collectors.values().forEach(PortStatsCollector::stop);
@@ -146,6 +162,25 @@
         LOG.info("Stopped");
     }
 
+    @Modified
+    public void modified(ComponentContext context) {
+        Dictionary<?, ?> properties = context.getProperties();
+        int newPortStatsPollFrequency;
+        try {
+            String s = get(properties, "PortStatsPollFrequency");
+            newPortStatsPollFrequency = isNullOrEmpty(s) ? portStatsPollFrequency : Integer.parseInt(s.trim());
+
+        } catch (NumberFormatException | ClassCastException e) {
+            newPortStatsPollFrequency = portStatsPollFrequency;
+        }
+
+        if (newPortStatsPollFrequency != portStatsPollFrequency) {
+            portStatsPollFrequency = newPortStatsPollFrequency;
+            collectors.values().forEach(psc -> psc.adjustPollInterval(portStatsPollFrequency));
+        }
+
+        LOG.info("Settings: portStatsPollFrequency={}", portStatsPollFrequency);
+    }
 
     @Override
     public boolean isReachable(DeviceId deviceId) {
@@ -275,7 +310,7 @@
             providerService.updatePorts(did, buildPortDescriptions(sw));
 
             PortStatsCollector psc =
-                    new PortStatsCollector(controller.getSwitch(dpid), POLL_INTERVAL);
+                    new PortStatsCollector(controller.getSwitch(dpid), portStatsPollFrequency);
             psc.start();
             collectors.put(dpid, psc);
         }
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/PortStatsCollector.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/PortStatsCollector.java
index c872a82..8383fa3 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/PortStatsCollector.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/PortStatsCollector.java
@@ -41,7 +41,7 @@
     private final HashedWheelTimer timer = Timer.getTimer();
     private final OpenFlowSwitch sw;
     private final Logger log = getLogger(getClass());
-    private final int refreshInterval;
+    private int refreshInterval;
     private final AtomicLong xidAtomic = new AtomicLong(1);
 
     private Timeout timeout;
@@ -74,6 +74,13 @@
         }
     }
 
+    synchronized void adjustPollInterval(int pollInterval) {
+        this.refreshInterval = pollInterval;
+        // task.cancel();
+        // task = new InternalTimerTask();
+        // timer.scheduleAtFixedRate(task, pollInterval * SECONDS, pollInterval * 1000);
+    }
+
     private void sendPortStatistic() {
         if (sw.getRole() != RoleState.MASTER) {
             return;
diff --git a/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java b/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
index 40b1849..4f46759 100644
--- a/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
+++ b/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
@@ -18,9 +18,11 @@
 import com.google.common.collect.HashMultimap;
 import com.google.common.collect.Lists;
 import com.google.common.collect.Multimap;
+
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
+import org.onosproject.cfg.ComponentConfigAdapter;
 import org.onosproject.net.DefaultDevice;
 import org.onosproject.net.Device;
 import org.onosproject.net.DeviceId;
@@ -84,8 +86,9 @@
     public void startUp() {
         provider.providerRegistry = registry;
         provider.controller = controller;
+        provider.cfgService = new ComponentConfigAdapter();
         controller.switchMap.put(DPID1, SW1);
-        provider.activate();
+        provider.activate(null);
         assertNotNull("provider should be registered", registry.provider);
         assertNotNull("listener should be registered", controller.listener);
         assertEquals("devices not added", 1, registry.connected.size());
@@ -94,7 +97,7 @@
 
     @After
     public void tearDown() {
-        provider.deactivate();
+        provider.deactivate(null);
         assertNull("listener should be removed", controller.listener);
         provider.controller = null;
         provider.providerRegistry = null;