RestDeviceProvider has configurable port stats frequency

Change-Id: I79fdde88f0cfd62a2d8ed58a1b621252161c975e
Signed-off-by: Georgios Katsikas <katsikas.gp@gmail.com>
diff --git a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
index 037f31a..9a279b9 100644
--- a/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
+++ b/providers/rest/device/src/main/java/org/onosproject/provider/rest/device/impl/RestDeviceProvider.java
@@ -21,12 +21,16 @@
 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.onlab.util.SharedExecutors;
 import org.onlab.util.SharedScheduledExecutorService;
 import org.onlab.util.SharedScheduledExecutors;
+import org.onlab.util.Tools;
+import org.onosproject.cfg.ComponentConfigService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.AnnotationKeys;
@@ -63,11 +67,13 @@
 import org.onosproject.protocol.rest.DefaultRestSBDevice;
 import org.onosproject.protocol.rest.RestSBController;
 import org.onosproject.protocol.rest.RestSBDevice;
+import org.osgi.service.component.ComponentContext;
 import org.slf4j.Logger;
 
 import javax.ws.rs.ProcessingException;
 import javax.ws.rs.core.MediaType;
 import java.util.Collection;
+import java.util.Dictionary;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -101,8 +107,8 @@
     private static final String IPADDRESS = "ipaddress";
     private static final String ISNOTNULL = "Rest device is not null";
     private static final String UNKNOWN = "unknown";
+    private static final String POLL_FREQUENCY = "pollFrequency";
     private static final int REST_TIMEOUT_SEC = 5;
-    private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30;
     private static final int EXECUTOR_THREAD_POOL_SIZE = 8;
     private final Logger log = getLogger(getClass());
 
@@ -113,7 +119,10 @@
     protected RestSBController controller;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected NetworkConfigRegistry cfgService;
+    protected NetworkConfigRegistry netCfgService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService compCfgService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
@@ -124,6 +133,12 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected DriverService driverService;
 
+    private static final int DEFAULT_POLL_FREQUENCY_SECONDS = 30;
+    @Property(name = POLL_FREQUENCY, intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
+            label = "Configure poll frequency for port status and statistics; " +
+                    "default is 30 seconds")
+    private int pollFrequency = DEFAULT_POLL_FREQUENCY_SECONDS;
+
     private DeviceProviderService providerService;
     private ApplicationId appId;
 
@@ -149,23 +164,44 @@
     @Activate
     public void activate() {
         appId = coreService.registerApplication(APP_NAME);
+        compCfgService.registerProperties(getClass());
         providerService = providerRegistry.register(this);
-        factories.forEach(cfgService::registerConfigFactory);
+        factories.forEach(netCfgService::registerConfigFactory);
         executor = Executors.newFixedThreadPool(
             EXECUTOR_THREAD_POOL_SIZE, groupedThreads("onos/restsbprovider", "device-installer-%d", log)
         );
-        cfgService.addListener(configListener);
+        netCfgService.addListener(configListener);
         executor.execute(RestDeviceProvider.this::createAndConnectDevices);
         scheduledTask = schedulePolling();
         log.info("Started");
     }
 
+    @Modified
+    public void modified(ComponentContext context) {
+        int previousPollFrequency = pollFrequency;
+
+        if (context != null) {
+            Dictionary<?, ?> properties = context.getProperties();
+            pollFrequency = Tools.getIntegerProperty(properties, POLL_FREQUENCY,
+                                                     DEFAULT_POLL_FREQUENCY_SECONDS);
+            log.info("Configured. Poll frequency is configured to {} seconds", pollFrequency);
+        }
+
+        // Re-schedule only if frequency has changed
+        if (!scheduledTask.isCancelled() && (previousPollFrequency != pollFrequency)) {
+            log.info("Re-scheduling port statistics task with frequency {} seconds", pollFrequency);
+            scheduledTask.cancel(true);
+            scheduledTask = schedulePolling();
+        }
+    }
+
     @Deactivate
     public void deactivate() {
-        cfgService.removeListener(configListener);
+        compCfgService.unregisterProperties(getClass(), false);
+        netCfgService.removeListener(configListener);
         providerRegistry.unregister(this);
         providerService = null;
-        factories.forEach(cfgService::unregisterConfigFactory);
+        factories.forEach(netCfgService::unregisterConfigFactory);
         scheduledTask.cancel(true);
         executor.shutdown();
         log.info("Stopped");
@@ -340,12 +376,12 @@
     //Method to connect devices provided via net-cfg under devices/ tree
     private void createAndConnectDevices() {
         Set<DeviceId> deviceSubjects =
-                cfgService.getSubjects(DeviceId.class, RestDeviceConfig.class);
+                netCfgService.getSubjects(DeviceId.class, RestDeviceConfig.class);
         connectDevices(deviceSubjects.stream()
                 .filter(deviceId -> deviceService.getDevice(deviceId) == null)
                 .map(deviceId -> {
                     RestDeviceConfig config =
-                            cfgService.getConfig(deviceId, RestDeviceConfig.class);
+                            netCfgService.getConfig(deviceId, RestDeviceConfig.class);
                     return toInactiveRestSBDevice(config);
                 }).collect(Collectors.toSet()));
     }
@@ -395,8 +431,7 @@
 
     private ScheduledFuture schedulePolling() {
         return portStatisticsExecutor.scheduleAtFixedRate(this::executePortStatisticsUpdate,
-                                                          DEFAULT_POLL_FREQUENCY_SECONDS / 2,
-                                                          DEFAULT_POLL_FREQUENCY_SECONDS,
+                                                          pollFrequency / 2, pollFrequency,
                                                           TimeUnit.SECONDS);
     }