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

Change-Id: I64f7a42c44be7b61ec2db291ed90a02434844041
diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpu.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpuUsage.java
similarity index 91%
rename from apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpu.java
rename to apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpuUsage.java
index 87a79c0..7a88a2a 100644
--- a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpu.java
+++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeCpuUsage.java
@@ -25,11 +25,11 @@
 /**
  * Represents CPU usage info of Cluster controllers.
  */
-public final class NodeCpu {
+public final class NodeCpuUsage {
     private final NodeId node;
     private final double usage;
 
-    private NodeCpu(final NodeId node, final Double usage) {
+    private NodeCpuUsage(final NodeId node, final Double usage) {
         this.node = node;
         this.usage = usage;
     }
@@ -65,7 +65,7 @@
         if (getClass() != obj.getClass()) {
             return false;
         }
-        final NodeCpu other = (NodeCpu) obj;
+        final NodeCpuUsage other = (NodeCpuUsage) obj;
         return Objects.equals(this.node, other.node)
                 && Objects.equals(this.usage, other.usage);
     }
@@ -102,10 +102,10 @@
             return this;
         }
 
-        public NodeCpu build() {
+        public NodeCpuUsage build() {
             checkNotNull(node, "Must specify an node id");
             checkNotNull(usage, "Must specify a usage");
-            return new NodeCpu(node, usage);
+            return new NodeCpuUsage(node, usage);
         }
     }
 
diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemory.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemoryUsage.java
similarity index 94%
rename from apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemory.java
rename to apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemoryUsage.java
index 399bc90..4531fe1 100644
--- a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemory.java
+++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMemoryUsage.java
@@ -26,7 +26,7 @@
 /**
  * Represents Memory usage of Cluster controllers.
  */
-public final class NodeMemory {
+public final class NodeMemoryUsage {
 
     private final NodeId node;
 
@@ -42,7 +42,7 @@
 
     private static final double PERCENTAGE_MULTIPLIER = 100.0;
 
-    private NodeMemory(final NodeId node, final Units units,
+    private NodeMemoryUsage(final NodeId node, final Units units,
                       final Long free, final Long used, final Long total,
                       final Double usage) {
         this.node = node;
@@ -114,7 +114,7 @@
         if (getClass() != obj.getClass()) {
             return false;
         }
-        NodeMemory other = (NodeMemory) obj;
+        NodeMemoryUsage other = (NodeMemoryUsage) obj;
         return Objects.equals(this.node, other.node)
                 && Objects.equals(this.free, other.free)
                 && Objects.equals(this.used, other.used)
@@ -191,14 +191,14 @@
             return this;
         }
 
-        public NodeMemory build() {
+        public NodeMemoryUsage build() {
             checkNotNull(node, "Must specify an node id");
             checkNotNull(unit, "Must specify a unit");
             checkNotNull(used, "Must specify a used Diskspace");
             checkNotNull(free, "Must specify a free Diskspace");
             checkNotNull(total, "Must specify a total Diskspace");
             double usage = used * PERCENTAGE_MULTIPLIER / total;
-            return new NodeMemory(node, unit, free, used, total, usage);
+            return new NodeMemoryUsage(node, unit, free, used, total, usage);
         }
 
     }
diff --git a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMetricsService.java b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMetricsService.java
index 1228fb0..4ad0985 100644
--- a/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMetricsService.java
+++ b/apps/nodemetrics/api/src/main/java/org/onosproject/nodemetrics/NodeMetricsService.java
@@ -30,7 +30,7 @@
      * Returns may memory information of all Cluster nodes.
      * @return map
      */
-    Map<NodeId, NodeMemory> memory();
+    Map<NodeId, NodeMemoryUsage> memory();
 
     /**
      * Returns may disk information of all Cluster nodes.
@@ -42,14 +42,14 @@
      * Returns may CPU information of all Cluster nodes.
      * @return map object, NodeId as key and NodeCpu information as value.
      */
-    Map<NodeId, NodeCpu> cpu();
+    Map<NodeId, NodeCpuUsage> cpu();
 
     /**
      * Get the memory information of Specific Cluster node.
      * @param nodeid to get Memory information of that respective cluster node.
-     * @return Nodememory object.
+     * @return NodememoryUsage object.
      */
-    NodeMemory memory(NodeId nodeid);
+    NodeMemoryUsage memory(NodeId nodeid);
 
     /**
      * Get the disk information of Specific Cluster node.
@@ -61,7 +61,7 @@
     /**
      * Get the CPU information of Specific Cluster node.
      * @param nodeid to get CPU information of that respective cluster node.
-     * @return NodeCpu object.
+     * @return NodeCpuUsage object.
      */
-    NodeCpu cpu(NodeId nodeid);
+    NodeCpuUsage cpu(NodeId nodeid);
 }
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)