Resolve some NPEs during collecting system metrics

Change-Id: Id018026676948d732f342d634dff6fba630c1414
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlPlaneMonitor.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlPlaneMonitor.java
index fa971b6..5821167 100644
--- a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlPlaneMonitor.java
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlPlaneMonitor.java
@@ -15,6 +15,7 @@
  */
 package org.onosproject.cpman.impl;
 
+import com.google.common.collect.ImmutableMap;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
@@ -340,6 +341,9 @@
     }
 
     private Map convertMap(Map<ControlMetricType, Double> map) {
+        if (map == null) {
+            return ImmutableMap.of();
+        }
         Map newMap = Maps.newConcurrentMap();
         map.forEach((k, v) -> newMap.putIfAbsent(k.toString(), v));
         return newMap;
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/SystemMetricsCollectorWebResource.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/SystemMetricsCollectorWebResource.java
index 6a6e50f..3e8c57b 100644
--- a/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/SystemMetricsCollectorWebResource.java
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/SystemMetricsCollectorWebResource.java
@@ -18,14 +18,18 @@
 import com.fasterxml.jackson.databind.JsonNode;
 import com.fasterxml.jackson.databind.node.ArrayNode;
 import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.apache.commons.lang3.StringUtils;
 import org.onosproject.cpman.ControlMetric;
 import org.onosproject.cpman.ControlMetricType;
 import org.onosproject.cpman.ControlPlaneMonitorService;
+import org.onosproject.cpman.ControlResource;
 import org.onosproject.cpman.MetricValue;
 import org.onosproject.cpman.SystemInfo;
 import org.onosproject.cpman.impl.DefaultSystemInfo;
 import org.onosproject.cpman.impl.SystemInfoFactory;
 import org.onosproject.rest.AbstractWebResource;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import javax.ws.rs.Consumes;
 import javax.ws.rs.POST;
@@ -35,7 +39,10 @@
 import javax.ws.rs.core.Response;
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.Iterator;
 import java.util.Optional;
+import java.util.Set;
+import java.util.stream.Collectors;
 
 import static org.onlab.util.Tools.nullIsIllegal;
 
@@ -45,11 +52,21 @@
 @Path("collector")
 public class SystemMetricsCollectorWebResource extends AbstractWebResource {
 
+    private final Logger log = LoggerFactory.getLogger(getClass());
     private final ControlPlaneMonitorService service = get(ControlPlaneMonitorService.class);
     private static final int UPDATE_INTERVAL_IN_MINUTE = 1;
     private static final String INVALID_SYSTEM_SPECS = "Invalid system specifications";
     private static final String INVALID_RESOURCE_NAME = "Invalid resource name";
     private static final String INVALID_REQUEST = "Invalid request";
+    private static final int PERCENT_CONSTANT = 100;
+
+    private static final Set<String> MEMORY_FIELD_SET = ControlResource.MEMORY_METRICS
+            .stream().map(type -> toCamelCase(type.toString(), true))
+            .collect(Collectors.toSet());
+
+    private static final Set<String> CPU_FIELD_SET = ControlResource.CPU_METRICS
+            .stream().map(type -> toCamelCase(type.toString(), true))
+            .collect(Collectors.toSet());
 
     /**
      * Collects CPU metrics.
@@ -67,7 +84,13 @@
         ControlMetric cm;
         try {
             ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
-            long cpuLoad = nullIsIllegal(jsonTree.get("cpuLoad").asLong(), INVALID_REQUEST);
+
+            if (jsonTree == null || !checkFields(jsonTree, CPU_FIELD_SET)) {
+                ok(root).build();
+            }
+
+            long cpuLoad = nullIsIllegal((long) (jsonTree.get("cpuLoad").asDouble()
+                    * PERCENT_CONSTANT), INVALID_REQUEST);
             long totalCpuTime = nullIsIllegal(jsonTree.get("totalCpuTime").asLong(), INVALID_REQUEST);
             long sysCpuTime = nullIsIllegal(jsonTree.get("sysCpuTime").asLong(), INVALID_REQUEST);
             long userCpuTime = nullIsIllegal(jsonTree.get("userCpuTime").asLong(), INVALID_REQUEST);
@@ -95,6 +118,8 @@
 
         } catch (IOException e) {
             throw new IllegalArgumentException(e.getMessage());
+        } catch (IllegalArgumentException iae) {
+            log.error("[CPU] Illegal arguments in JSON input, msg: {}", iae.getMessage());
         }
         return ok(root).build();
     }
@@ -115,10 +140,16 @@
         ControlMetric cm;
         try {
             ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
-            long memUsedRatio = nullIsIllegal(jsonTree.get("memoryUsedRatio").asLong(), INVALID_REQUEST);
-            long memFreeRatio = nullIsIllegal(jsonTree.get("memoryFreeRatio").asLong(), INVALID_REQUEST);
+
+            if (jsonTree == null || !checkFields(jsonTree, MEMORY_FIELD_SET)) {
+                ok(root).build();
+            }
+
             long memUsed = nullIsIllegal(jsonTree.get("memoryUsed").asLong(), INVALID_REQUEST);
             long memFree = nullIsIllegal(jsonTree.get("memoryFree").asLong(), INVALID_REQUEST);
+            long memTotal = memUsed + memFree;
+            long memUsedRatio = memTotal == 0L ? 0L : (memUsed * PERCENT_CONSTANT) / memTotal;
+            long memFreeRatio = memTotal == 0L ? 0L : (memFree * PERCENT_CONSTANT) / memTotal;
 
             cm = new ControlMetric(ControlMetricType.MEMORY_USED_RATIO,
                     new MetricValue.Builder().load(memUsedRatio).add());
@@ -138,6 +169,8 @@
 
         } catch (IOException e) {
             throw new IllegalArgumentException(e.getMessage());
+        } catch (IllegalArgumentException iae) {
+            log.error("[RAM] Illegal arguments in JSON input, msg: {}", iae.getMessage());
         }
         return ok(root).build();
     }
@@ -158,7 +191,9 @@
         ControlMetric cm;
         try {
             ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
-            ArrayNode diskRes = (ArrayNode) jsonTree.get("disks");
+            ArrayNode diskRes =
+                    jsonTree.get("disks") == null ? mapper().createArrayNode() : (ArrayNode) jsonTree.get("disks");
+
             for (JsonNode node : diskRes) {
                 JsonNode resourceName = node.get("resourceName");
                 nullIsIllegal(resourceName, INVALID_RESOURCE_NAME);
@@ -176,6 +211,8 @@
             }
         } catch (IOException e) {
             throw new IllegalArgumentException(e.getMessage());
+        } catch (IllegalArgumentException iae) {
+            log.error("[DISK] Illegal arguments in JSON input, msg: {}", iae.getMessage());
         }
         return ok(root).build();
     }
@@ -196,7 +233,10 @@
         ControlMetric cm;
         try {
             ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
-            ArrayNode networkRes = (ArrayNode) jsonTree.get("networks");
+
+            ArrayNode networkRes = jsonTree.get("networks") == null
+                    ? mapper().createArrayNode() : (ArrayNode) jsonTree.get("networks");
+
             for (JsonNode node : networkRes) {
                 JsonNode resourceName = node.get("resourceName");
                 nullIsIllegal(resourceName, INVALID_RESOURCE_NAME);
@@ -271,4 +311,24 @@
         }
         return ok(root).build();
     }
+
+    private boolean checkFields(ObjectNode node, Set<String> original) {
+        Iterator<String> fieldNames = node.fieldNames();
+        while (fieldNames.hasNext()) {
+            String fieldName = fieldNames.next();
+            if (!original.contains(fieldName) || node.get(fieldName) == null) {
+                log.warn("Illegal field name: {}", fieldName);
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static String toCamelCase(String value, boolean startWithLowerCase) {
+        String[] strings = StringUtils.split(value.toLowerCase(), "_");
+        for (int i = startWithLowerCase ? 1 : 0; i < strings.length; i++) {
+            strings[i] = StringUtils.capitalize(strings[i]);
+        }
+        return StringUtils.join(strings);
+    }
 }