[onos-6879] Adding configuration property to node metrics app

Change-Id: I64f7a42c44be7b61ec2db291ed90a02434844041
diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeCpuUsageCommand.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeCpuUsageCommand.java
index a122791..12dd649 100644
--- a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeCpuUsageCommand.java
+++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeCpuUsageCommand.java
@@ -20,7 +20,7 @@
 import org.apache.karaf.shell.commands.Command;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.cluster.NodeId;
-import org.onosproject.nodemetrics.NodeCpu;
+import org.onosproject.nodemetrics.NodeCpuUsage;
 import org.onosproject.nodemetrics.NodeMetricsService;
 
 import java.util.Collection;
@@ -42,19 +42,19 @@
     @Override
     protected void execute() {
         if (nodeId != null) {
-            NodeCpu cpu = nodeService.cpu(NodeId.nodeId(nodeId));
+            NodeCpuUsage cpu = nodeService.cpu(NodeId.nodeId(nodeId));
             if (Objects.nonNull(cpu)) {
                 print("CPU usage : %s ", cpu);
             } else {
                 print("Node %s doesn't exists", nodeId);
             }
         } else {
-            Collection<NodeCpu> cpu = nodeService.cpu().values();
+            Collection<NodeCpuUsage> cpu = nodeService.cpu().values();
             printCpuUsage(cpu);
         }
     }
 
-    private void printCpuUsage(Collection<NodeCpu> cpuList) {
+    private void printCpuUsage(Collection<NodeCpuUsage> cpuList) {
         cpuList.forEach(cpu -> print("%s", cpu));
     }
 }
diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryCommand.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryUsageCommand.java
similarity index 81%
rename from apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryCommand.java
rename to apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryUsageCommand.java
index 3c6ec5b..2f18c43 100644
--- a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryCommand.java
+++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/cli/ShowNodeMemoryUsageCommand.java
@@ -20,7 +20,7 @@
 import org.apache.karaf.shell.commands.Command;
 import org.onosproject.cli.AbstractShellCommand;
 import org.onosproject.cluster.NodeId;
-import org.onosproject.nodemetrics.NodeMemory;
+import org.onosproject.nodemetrics.NodeMemoryUsage;
 import org.onosproject.nodemetrics.NodeMetricsService;
 
 import java.util.Collection;
@@ -31,7 +31,7 @@
  */
 @Command(scope = "onos", name = "node-memory",
         description = "Lists all node memory utilization")
-public class ShowNodeMemoryCommand extends AbstractShellCommand {
+public class ShowNodeMemoryUsageCommand extends AbstractShellCommand {
 
     @Argument(index = 0, name = "nodeId", description = "Node identity",
             required = false, multiValued = false)
@@ -42,19 +42,19 @@
     @Override
     protected void execute() {
         if (nodeId != null) {
-            NodeMemory memory = nodeService.memory(NodeId.nodeId(nodeId));
+            NodeMemoryUsage memory = nodeService.memory(NodeId.nodeId(nodeId));
             if (Objects.nonNull(memory)) {
                 print("Memory usage : %s", memory.toString());
             } else {
                 print("Node %s doesn't exists");
             }
         } else {
-            Collection<NodeMemory> memory = nodeService.memory().values();
-            printMemory(memory);
+            Collection<NodeMemoryUsage> memory = nodeService.memory().values();
+            printMemoryUsage(memory);
         }
     }
 
-    private void printMemory(Collection<NodeMemory> memoryList) {
+    private void printMemoryUsage(Collection<NodeMemoryUsage> memoryList) {
         memoryList.forEach(memory -> print("%s", memory));
     }
 }
diff --git a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/NodeMetricsManager.java b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/NodeMetricsManager.java
index c91f9d8..812ebb7 100644
--- a/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/NodeMetricsManager.java
+++ b/apps/nodemetrics/mgr/src/main/java/org/onosproject/nodemetrics/impl/NodeMetricsManager.java
@@ -18,9 +18,13 @@
 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.apache.felix.scr.annotations.Service;
+import org.osgi.service.component.ComponentContext;
+import org.onosproject.cfg.ComponentConfigService;
 import org.hyperic.sigar.CpuPerc;
 import org.hyperic.sigar.FileSystemUsage;
 import org.hyperic.sigar.Mem;
@@ -32,9 +36,9 @@
 import org.onosproject.cluster.NodeId;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
-import org.onosproject.nodemetrics.NodeCpu;
+import org.onosproject.nodemetrics.NodeCpuUsage;
 import org.onosproject.nodemetrics.NodeDiskUsage;
-import org.onosproject.nodemetrics.NodeMemory;
+import org.onosproject.nodemetrics.NodeMemoryUsage;
 import org.onosproject.nodemetrics.NodeMetricsService;
 import org.onosproject.nodemetrics.Units;
 import org.onosproject.store.serializers.KryoNamespaces;
@@ -45,11 +49,15 @@
 import org.slf4j.LoggerFactory;
 
 import java.util.Map;
+import java.util.Objects;
 import java.util.concurrent.Executors;
 import java.util.concurrent.ScheduledExecutorService;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 import java.util.stream.Collectors;
+import java.util.Dictionary;
+import static org.onlab.util.Tools.getIntegerProperty;
+
 
 @Service
 @Component(immediate = true)
@@ -72,22 +80,30 @@
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected LogicalClockService clockService;
 
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ComponentConfigService cfgService;
+
     private ScheduledExecutorService metricsExecutor;
     private ScheduledFuture<?> scheduledTask;
 
     private ApplicationId appId;
     private NodeId localNodeId;
 
-    private EventuallyConsistentMap<NodeId, NodeMemory> memoryStore;
+    private EventuallyConsistentMap<NodeId, NodeMemoryUsage> memoryStore;
     private EventuallyConsistentMap<NodeId, NodeDiskUsage> diskStore;
-    private EventuallyConsistentMap<NodeId, NodeCpu> cpuStore;
+    private EventuallyConsistentMap<NodeId, NodeCpuUsage> cpuStore;
 
     private Sigar sigar;
 
+    @Property(name = "metricPollFrequencySeconds", intValue = DEFAULT_POLL_FREQUENCY_SECONDS,
+            label = "Frequency (in seconds) for polling controller metrics")
+    protected int metricPollFrequencySeconds = DEFAULT_POLL_FREQUENCY_SECONDS;
+
     @Activate
-    public void activate() {
+    public void activate(ComponentContext context) {
         appId = coreService
                 .registerApplication("org.onosproject.nodemetrics");
+        cfgService.registerProperties(getClass());
         metricsExecutor = Executors.newSingleThreadScheduledExecutor(
                 Tools.groupedThreads("nodemetrics/pollingStatics",
                         "statistics-executor-%d", log));
@@ -95,11 +111,11 @@
         localNodeId = clusterService.getLocalNode().id();
         KryoNamespace.Builder serializer = KryoNamespace.newBuilder()
                 .register(KryoNamespaces.API)
-                .register(NodeMemory.class)
+                .register(NodeMemoryUsage.class)
                 .register(NodeDiskUsage.class)
-                .register(NodeCpu.class)
+                .register(NodeCpuUsage.class)
                 .register(Units.class);
-        memoryStore = storageService.<NodeId, NodeMemory>eventuallyConsistentMapBuilder()
+        memoryStore = storageService.<NodeId, NodeMemoryUsage>eventuallyConsistentMapBuilder()
                 .withSerializer(serializer)
                 .withTimestampProvider((nodeId, memory) -> clockService.getTimestamp())
                 .withName("nodemetrics-memory")
@@ -111,26 +127,50 @@
                 .withName("nodemetrics-disk")
                 .build();
 
-        cpuStore = storageService.<NodeId, NodeCpu>eventuallyConsistentMapBuilder()
+        cpuStore = storageService.<NodeId, NodeCpuUsage>eventuallyConsistentMapBuilder()
                 .withSerializer(serializer)
                 .withTimestampProvider((nodeId, cpu) -> clockService.getTimestamp())
                 .withName("nodemetrics-cpu")
                 .build();
-
-        scheduledTask = schedulePolling();
+        modified(context);
         sigar = new Sigar();
         pollMetrics();
     }
 
     @Deactivate
     public void deactivate() {
+        cfgService.unregisterProperties(getClass(), false);
         scheduledTask.cancel(true);
         metricsExecutor.shutdown();
         sigar.close();
     }
 
+    @Modified
+    public void modified(ComponentContext context) {
+        if (context == null) {
+            log.info("No component configuration");
+            return;
+        }
+
+        Dictionary<?, ?> properties = context.getProperties();
+        int newPollFrequency = getNewPollFrequency(properties);
+        //First time call to this modified method is when app activates
+        if (Objects.isNull(scheduledTask)) {
+            metricPollFrequencySeconds = newPollFrequency;
+            scheduledTask = schedulePolling();
+        } else {
+            if (newPollFrequency != metricPollFrequencySeconds) {
+                metricPollFrequencySeconds = newPollFrequency;
+                //stops the old scheduled task
+                scheduledTask.cancel(true);
+                //schedules new task at the new polling rate
+                scheduledTask = schedulePolling();
+            }
+        }
+    }
+
     @Override
-    public Map<NodeId, NodeMemory> memory() {
+    public Map<NodeId, NodeMemoryUsage> memory() {
         return this.ecToMap(memoryStore);
     }
 
@@ -140,12 +180,12 @@
     }
 
     @Override
-    public Map<NodeId, NodeCpu> cpu() {
+    public Map<NodeId, NodeCpuUsage> cpu() {
         return this.ecToMap(cpuStore);
     }
 
     @Override
-    public NodeMemory memory(NodeId nodeid) {
+    public NodeMemoryUsage memory(NodeId nodeid) {
         return memoryStore.get(nodeid);
     }
 
@@ -155,14 +195,26 @@
     }
 
     @Override
-    public NodeCpu cpu(NodeId nodeid) {
+    public NodeCpuUsage cpu(NodeId nodeid) {
         return cpuStore.get(nodeid);
     }
 
     private ScheduledFuture schedulePolling() {
         return metricsExecutor.scheduleAtFixedRate(this::pollMetrics,
-                DEFAULT_POLL_FREQUENCY_SECONDS / 4,
-                DEFAULT_POLL_FREQUENCY_SECONDS, TimeUnit.SECONDS);
+                metricPollFrequencySeconds / 4,
+                metricPollFrequencySeconds, TimeUnit.SECONDS);
+    }
+
+    private int getNewPollFrequency(Dictionary<?, ?> properties) {
+        int newPollFrequency;
+        try {
+            newPollFrequency = getIntegerProperty(properties, "metricPollFrequencySeconds");
+            //String s = getIntegerProperty(properties, "metricPollFrequencySeconds");
+            //newPollFrequency = isNullOrEmpty(s) ? pollFrequency : Integer.parseInt(s.trim());
+        } catch (NumberFormatException | ClassCastException e) {
+            newPollFrequency = DEFAULT_POLL_FREQUENCY_SECONDS;
+        }
+        return newPollFrequency;
     }
 
     private <K, V> Map<K, V> ecToMap(EventuallyConsistentMap<K, V> ecMap) {
@@ -170,16 +222,17 @@
                 .stream()
                 .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
     }
+
     private void pollMetrics() {
         try {
             CpuPerc cpu = sigar.getCpuPerc();
             Mem mem = sigar.getMem();
             FileSystemUsage disk = sigar.getFileSystemUsage(SLASH);
 
-            NodeMemory memoryNode = new NodeMemory.Builder().free(mem.getFree())
+            NodeMemoryUsage memoryNode = new NodeMemoryUsage.Builder().free(mem.getFree())
                     .used(mem.getUsed()).total(mem.getTotal()).withUnit(Units.BYTES)
                     .withNode(localNodeId).build();
-            NodeCpu cpuNode = new NodeCpu.Builder().withNode(localNodeId)
+            NodeCpuUsage cpuNode = new NodeCpuUsage.Builder().withNode(localNodeId)
                     .usage(cpu.getCombined() * PERCENTAGE_MULTIPLIER).build();
             NodeDiskUsage diskNode = new NodeDiskUsage.Builder().withNode(localNodeId)
                     .free(disk.getFree()).used(disk.getUsed()).withUnit(Units.KBYTES)