Refactor SystemInfo, and store SystemInfo into singleton instance

- Implement Bill Pugh singleton for ControlMetricsFactory and
  SystemInfo class

Change-Id: Ia97538d9f1be9ea900b0e87371bf50877eaf6483
diff --git a/apps/cpman/api/src/main/java/org/onosproject/cpman/SystemInfo.java b/apps/cpman/api/src/main/java/org/onosproject/cpman/SystemInfo.java
new file mode 100644
index 0000000..d8820f3
--- /dev/null
+++ b/apps/cpman/api/src/main/java/org/onosproject/cpman/SystemInfo.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cpman;
+
+/**
+ * System information interface.
+ */
+public interface SystemInfo {
+
+    /**
+     * Returns number of CPU cores.
+     *
+     * @return number of CPU cores
+     */
+    int coreCount();
+
+    /**
+     * Returns number of CPUs.
+     *
+     * @return number of CPUs
+     */
+    int cpuCount();
+
+    /**
+     * Returns CPU speed in MHz.
+     *
+     * @return CPU speed
+     */
+    int cpuSpeed();
+
+    /**
+     * Returns the total amount of memory in Mega Bytes.
+     *
+     * @return memory size
+     */
+    int totalMemory();
+
+    /**
+     * A builder of SystemInfo.
+     */
+    interface Builder {
+
+        /**
+         * Sets number of CPU cores.
+         *
+         * @param numOfCores number of CPU cores
+         * @return Builder object
+         */
+        Builder numOfCores(int numOfCores);
+
+        /**
+         * Sets number of CPUs.
+         * @param numOfCpus number of CPUs
+         * @return Builder object
+         */
+        Builder numOfCpus(int numOfCpus);
+
+        /**
+         * Sets CPU speed.
+         *
+         * @param cpuSpeedMhz CPU speed in Mhz
+         * @return Builder object
+         */
+        Builder cpuSpeed(int cpuSpeedMhz);
+
+        /**
+         * Sets total amount of memory.
+         *
+         * @param totalMemoryMbytes memory size in Mega Bytes
+         * @return Builder object
+         */
+        Builder totalMemory(int totalMemoryMbytes);
+
+        /**
+         * Builds a SystemInfo object.
+         *
+         * @return SystemInfo object
+         */
+        SystemInfo build();
+    }
+}
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsFactory.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsFactory.java
index 4fcf04f..0d50884 100644
--- a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsFactory.java
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsFactory.java
@@ -32,13 +32,9 @@
  * Singleton class to provide various control plane metrics to other components.
  */
 public final class ControlMetricsFactory {
-    private static volatile ControlMetricsFactory uniqueInstance;
-
     private MetricsService metricsService;
     private boolean enableMonitor = false;
-
-    // define a ControlMetricsSystemSpec
-    private ControlMetricsSystemSpec cmss;
+    private Boolean isInitialized = false;
 
     // define a set of MetricsAggregators
     private MetricsAggregator cpuLoad;
@@ -68,48 +64,23 @@
     private Set<String> nwInterfaces = Sets.newConcurrentHashSet();
 
     /**
-     * Constructs a control metrics factory using the given metrics and device services.
-     *
-     * @param metricsService metric service reference
-     * @param deviceService  device service reference
-     */
-    private ControlMetricsFactory(MetricsService metricsService, DeviceService deviceService) {
-        this.metricsService = metricsService;
-        registerMetrics();
-
-        deviceService.getDevices().forEach(d->deviceIds.add(d.id()));
-
-        addAllControlMessageMetrics(deviceIds);
-    }
-
-    /**
-     * Obtains the unique instance of ControlMetricsFactory.
+     * Initializes the control metrics factory instance using the given
+     * metric service and device service. Makes sure that we only initialize
+     * control metrics factory instance once.
      *
      * @param metricsService metric service
      * @param deviceService  device service
-     * @return instance of ControlMetricsFactory
      */
-    public static ControlMetricsFactory getInstance(MetricsService metricsService,
-                                                    DeviceService deviceService) {
-        if (uniqueInstance == null) {
-            synchronized (ControlMetricsFactory.class) {
-                if (uniqueInstance == null) {
-                    uniqueInstance = new ControlMetricsFactory(metricsService, deviceService);
-                }
+    public void initialization(MetricsService metricsService, DeviceService deviceService) {
+        synchronized (isInitialized) {
+            if (!isInitialized) {
+                this.metricsService = metricsService;
+                registerMetrics();
+                deviceService.getDevices().forEach(d->deviceIds.add(d.id()));
+                addAllControlMessageMetrics(deviceIds);
+                isInitialized = true;
             }
         }
-        return uniqueInstance;
-    }
-
-    /**
-     * Sets system specification.
-     *
-     * @param cmss ControlMetricsSystemSpec object
-     */
-    public void setSystemSpec(ControlMetricsSystemSpec cmss) {
-        if (this.cmss == null) {
-            this.cmss = cmss;
-        }
     }
 
     /**
@@ -119,17 +90,17 @@
      */
     public void addControlMessageMetricsByDeviceId(DeviceId deviceId) {
         MetricsAggregator inbound = new MetricsAggregator(metricsService,
-                        ControlMetricType.INBOUND_PACKET, Optional.of(deviceId));
+                ControlMetricType.INBOUND_PACKET, Optional.of(deviceId));
         MetricsAggregator outbound = new MetricsAggregator(metricsService,
-                        ControlMetricType.OUTBOUND_PACKET, Optional.of(deviceId));
+                ControlMetricType.OUTBOUND_PACKET, Optional.of(deviceId));
         MetricsAggregator flowmod = new MetricsAggregator(metricsService,
-                        ControlMetricType.FLOW_MOD_PACKET, Optional.of(deviceId));
+                ControlMetricType.FLOW_MOD_PACKET, Optional.of(deviceId));
         MetricsAggregator flowrmv = new MetricsAggregator(metricsService,
-                        ControlMetricType.FLOW_REMOVED_PACKET, Optional.of(deviceId));
+                ControlMetricType.FLOW_REMOVED_PACKET, Optional.of(deviceId));
         MetricsAggregator request = new MetricsAggregator(metricsService,
-                        ControlMetricType.REQUEST_PACKET, Optional.of(deviceId));
+                ControlMetricType.REQUEST_PACKET, Optional.of(deviceId));
         MetricsAggregator reply = new MetricsAggregator(metricsService,
-                        ControlMetricType.REPLY_PACKET, Optional.of(deviceId));
+                ControlMetricType.REPLY_PACKET, Optional.of(deviceId));
 
         inboundPacket.putIfAbsent(deviceId, inbound);
         outboundPacket.putIfAbsent(deviceId, outbound);
@@ -148,7 +119,7 @@
      */
     public void addDiskMetricsByPartition(String partitionName) {
         MetricsAggregator readBytes = new MetricsAggregator(metricsService,
-                        ControlMetricType.DISK_READ_BYTES, partitionName);
+                ControlMetricType.DISK_READ_BYTES, partitionName);
         MetricsAggregator writeBytes = new MetricsAggregator(metricsService,
                 ControlMetricType.DISK_WRITE_BYTES, partitionName);
 
@@ -165,7 +136,7 @@
      */
     public void addNetworkMetricsByInterface(String interfaceName) {
         MetricsAggregator incomingBytes = new MetricsAggregator(metricsService,
-                        ControlMetricType.NW_INCOMING_BYTES, interfaceName);
+                ControlMetricType.NW_INCOMING_BYTES, interfaceName);
         MetricsAggregator outgoingBytes = new MetricsAggregator(metricsService,
                 ControlMetricType.NW_OUTGOING_BYTES, interfaceName);
         MetricsAggregator incomingPackets = new MetricsAggregator(metricsService,
@@ -579,4 +550,17 @@
     public MetricsAggregator replyPacket(DeviceId deviceId) {
         return replyPacket.get(deviceId);
     }
+
+    /**
+     * Returns an instance of control metrics factory.
+     *
+     * @return instance of control metrics factory
+     */
+    public static ControlMetricsFactory getInstance() {
+        return SingletonHelper.INSTANCE;
+    }
+
+    private static class SingletonHelper {
+        private static final ControlMetricsFactory INSTANCE = new ControlMetricsFactory();
+    }
 }
\ No newline at end of file
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsSystemSpec.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsSystemSpec.java
deleted file mode 100644
index a80f43c..0000000
--- a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsSystemSpec.java
+++ /dev/null
@@ -1,132 +0,0 @@
-/*
- * Copyright 2016 Open Networking Laboratory
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.onosproject.cpman.impl;
-
-/**
- * Control metrics class for storing system specification.
- */
-public final class ControlMetricsSystemSpec {
-    private int numOfCores;
-    private int numOfCpus;
-    private int cpuSpeed;               // in MHz
-    private long totalMemory;           // in bytes
-
-    private ControlMetricsSystemSpec(int numOfCores, int numOfCpus,
-                                     int cpuSpeed, long totalMemory) {
-        this.numOfCores = numOfCores;
-        this.numOfCpus = numOfCpus;
-        this.cpuSpeed = cpuSpeed;
-        this.totalMemory = totalMemory;
-    }
-
-    /**
-     * Returns number of CPU cores.
-     *
-     * @return number of CPU cores
-     */
-    public int numOfCores() {
-        return this.numOfCores;
-    }
-
-    /**
-     * Returns number of CPUs.
-     *
-     * @return number of CPUs
-     */
-    public int numOfCpus() {
-        return this.numOfCpus;
-    }
-
-    /**
-     * Returns CPU speed in MHz.
-     *
-     * @return CPU speed
-     */
-    public int cpuSpeed() {
-        return this.cpuSpeed;
-    }
-
-    /**
-     * Returns the total amount of memory.
-     *
-     * @return memory size
-     */
-    public long totalMemory() {
-        return this.totalMemory;
-    }
-
-    /**
-     * ControlMetricsSystemSpec builder class.
-     */
-    public static final class Builder {
-        private int numOfCores;
-        private int numOfCpus;
-        private int cpuSpeed;               // in MHz
-        private long totalMemory;           // in bytes
-
-        /**
-         * Sets number of CPU cores.
-         *
-         * @param numOfCores number of CPU cores
-         * @return Builder object
-         */
-        public Builder numOfCores(int numOfCores) {
-            this.numOfCores = numOfCores;
-            return this;
-        }
-
-        /**
-         * Sets number of CPUs.
-         * @param numOfCpus number of CPUs
-         * @return Builder object
-         */
-        public Builder numOfCpus(int numOfCpus) {
-            this.numOfCpus = numOfCpus;
-            return this;
-        }
-
-        /**
-         * Sets CPU speed.
-         *
-         * @param cpuSpeed CPU speed
-         * @return Builder object
-         */
-        public Builder cpuSpeed(int cpuSpeed) {
-            this.cpuSpeed = cpuSpeed;
-            return this;
-        }
-
-        /**
-         * Sets total amount of memory.
-         *
-         * @param totalMemory memory size
-         * @return Builder object
-         */
-        public Builder totalMemory(long totalMemory) {
-            this.totalMemory = totalMemory;
-            return this;
-        }
-
-        /**
-         * Builds a ControlMetricsSystemSpec object.
-         *
-         * @return ControlMetricsSystemSpec object
-         */
-        public ControlMetricsSystemSpec build() {
-            return new ControlMetricsSystemSpec(numOfCores, numOfCpus, cpuSpeed, totalMemory);
-        }
-    }
-}
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/DefaultSystemInfo.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/DefaultSystemInfo.java
new file mode 100644
index 0000000..e4a301b
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/DefaultSystemInfo.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cpman.impl;
+
+import org.onosproject.cpman.SystemInfo;
+
+/**
+ * Implementation class of storing system specification.
+ */
+public final class DefaultSystemInfo implements SystemInfo {
+    private int numOfCores;
+    private int numOfCpus;
+    private int cpuSpeedMhz;
+    private int totalMemoryMbytes;
+
+    private DefaultSystemInfo(int numOfCores, int numOfCpus,
+                              int cpuSpeedMhz, int totalMemoryMbytes) {
+        this.numOfCores = numOfCores;
+        this.numOfCpus = numOfCpus;
+        this.cpuSpeedMhz = cpuSpeedMhz;
+        this.totalMemoryMbytes = totalMemoryMbytes;
+    }
+
+    @Override
+    public int coreCount() {
+        return this.numOfCores;
+    }
+
+    @Override
+    public int cpuCount() {
+        return this.numOfCpus;
+    }
+
+    @Override
+    public int cpuSpeed() {
+        return this.cpuSpeedMhz;
+    }
+
+    @Override
+    public int totalMemory() {
+        return this.totalMemoryMbytes;
+    }
+
+    /**
+     * ControlMetricsSystemSpec builder class.
+     */
+    public static final class Builder implements SystemInfo.Builder {
+        private int numOfCores;
+        private int numOfCpus;
+        private int cpuSpeedMHz;
+        private int totalMemoryBytes;
+
+        @Override
+        public SystemInfo.Builder numOfCores(int numOfCores) {
+            this.numOfCores = numOfCores;
+            return this;
+        }
+
+        @Override
+        public Builder numOfCpus(int numOfCpus) {
+            this.numOfCpus = numOfCpus;
+            return this;
+        }
+
+        @Override
+        public Builder cpuSpeed(int cpuSpeedMhz) {
+            this.cpuSpeedMHz = cpuSpeedMhz;
+            return this;
+        }
+
+        @Override
+        public Builder totalMemory(int totalMemoryBytes) {
+            this.totalMemoryBytes = totalMemoryBytes;
+            return this;
+        }
+
+        @Override
+        public DefaultSystemInfo build() {
+            return new DefaultSystemInfo(numOfCores, numOfCpus, cpuSpeedMHz, totalMemoryBytes);
+        }
+    }
+}
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/SystemInfoFactory.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/SystemInfoFactory.java
new file mode 100644
index 0000000..78f076d
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/SystemInfoFactory.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2016 Open Networking Laboratory
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.cpman.impl;
+
+import org.onosproject.cpman.SystemInfo;
+import org.slf4j.Logger;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * A factory class which instantiates a system info object.
+ */
+public final class SystemInfoFactory {
+
+    private final Logger log = getLogger(getClass());
+
+    private SystemInfo systemInfo;
+
+    // non-instantiable (except for our Singleton)
+    private SystemInfoFactory() {
+    }
+
+    /**
+     * Returns system information.
+     *
+     * @return reference object of system info
+     */
+    public SystemInfo getSystemInfo() {
+        synchronized (systemInfo) {
+            return this.systemInfo;
+        }
+    }
+
+    /**
+     * Set system information only if it is empty.
+     *
+     * @param systemInfo reference object of system info
+     */
+    public void setSystemInfo(SystemInfo systemInfo) {
+        synchronized (systemInfo) {
+            if (this.systemInfo == null) {
+                this.systemInfo = systemInfo;
+            } else {
+                log.warn("System information has already been set");
+            }
+        }
+    }
+
+    /**
+     * Returns an instance of system info factory.
+     *
+     * @return instance of system info factory
+     */
+    public static SystemInfoFactory getInstance() {
+        return SingletonHelper.INSTANCE;
+    }
+
+    private static class SingletonHelper {
+        private static final SystemInfoFactory INSTANCE = new SystemInfoFactory();
+    }
+}
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java
index ecb5764..777b89f 100644
--- a/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java
@@ -22,7 +22,9 @@
 import org.onosproject.cpman.ControlMetricType;
 import org.onosproject.cpman.ControlPlaneMonitorService;
 import org.onosproject.cpman.MetricValue;
-import org.onosproject.cpman.impl.ControlMetricsSystemSpec;
+import org.onosproject.cpman.SystemInfo;
+import org.onosproject.cpman.impl.DefaultSystemInfo;
+import org.onosproject.cpman.impl.SystemInfoFactory;
 import org.onosproject.rest.AbstractWebResource;
 
 import javax.ws.rs.Consumes;
@@ -227,19 +229,19 @@
     }
 
     /**
-     * Collects system specifications.
-     * The system specs include the various control metrics
+     * Collects system information.
+     * The system information includes the various control metrics
      * which do not require aggregation.
      *
      * @param stream JSON stream
      * @return 200 OK
-     * @onos.rsModel SystemSpecsPost
+     * @onos.rsModel SystemInfoPost
      */
     @POST
-    @Path("system_specs")
+    @Path("system_info")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces(MediaType.APPLICATION_JSON)
-    public Response systemSpecs(InputStream stream) {
+    public Response systemInfo(InputStream stream) {
         ObjectNode root = mapper().createObjectNode();
 
         try {
@@ -249,15 +251,17 @@
             JsonNode cpuSpeed = jsonTree.get("cpuSpeed");
             JsonNode totalMemory = jsonTree.get("totalMemory");
 
-            if (numOfCores != null && numOfCpus != null && cpuSpeed != null && totalMemory != null) {
-                ControlMetricsSystemSpec.Builder builder = new ControlMetricsSystemSpec.Builder();
-                ControlMetricsSystemSpec cmss = builder.numOfCores(numOfCores.asInt())
+            if (numOfCores != null && numOfCpus != null &&
+                cpuSpeed != null && totalMemory != null) {
+                SystemInfo systemInfo = new DefaultSystemInfo.Builder()
+                        .numOfCores(numOfCores.asInt())
                         .numOfCpus(numOfCpus.asInt())
                         .cpuSpeed(cpuSpeed.asInt())
-                        .totalMemory(totalMemory.asLong())
+                        .totalMemory(totalMemory.asInt())
                         .build();
-                // TODO: need to implement spec store
 
+                // try to store the system info.
+                SystemInfoFactory.getInstance().setSystemInfo(systemInfo);
             } else {
                 throw new IllegalArgumentException(INVALID_SYSTEM_SPECS);
             }
diff --git a/apps/cpman/app/src/main/resources/definitions/SystemSpecsPost.json b/apps/cpman/app/src/main/resources/definitions/SystemInfoPost.json
similarity index 100%
rename from apps/cpman/app/src/main/resources/definitions/SystemSpecsPost.json
rename to apps/cpman/app/src/main/resources/definitions/SystemInfoPost.json
diff --git a/apps/cpman/app/src/test/java/org/onosproject/cpman/rest/ControlMetricsCollectorResourceTest.java b/apps/cpman/app/src/test/java/org/onosproject/cpman/rest/ControlMetricsCollectorResourceTest.java
index 6fd8770..ac84e1d 100644
--- a/apps/cpman/app/src/test/java/org/onosproject/cpman/rest/ControlMetricsCollectorResourceTest.java
+++ b/apps/cpman/app/src/test/java/org/onosproject/cpman/rest/ControlMetricsCollectorResourceTest.java
@@ -27,6 +27,8 @@
 import org.onlab.osgi.TestServiceDirectory;
 import org.onlab.rest.BaseResource;
 import org.onosproject.cpman.ControlPlaneMonitorService;
+import org.onosproject.cpman.SystemInfo;
+import org.onosproject.cpman.impl.SystemInfoFactory;
 import org.onosproject.net.DeviceId;
 
 import javax.ws.rs.core.MediaType;
@@ -123,8 +125,14 @@
     }
 
     @Test
-    public void testSystemSpecsPost() {
-        basePostTest("system-spec-post.json", PREFIX + "/system_specs");
+    public void testSystemInfoPost() {
+        basePostTest("system-info-post.json", PREFIX + "/system_info");
+
+        SystemInfo si = SystemInfoFactory.getInstance().getSystemInfo();
+        assertThat(si.cpuSpeed(), is(2048));
+        assertThat(si.coreCount(), is(6));
+        assertThat(si.cpuCount(), is(2));
+        assertThat(si.totalMemory(), is(4096));
     }
 
     private ClientResponse baseTest(String jsonFile, String path) {
diff --git a/apps/cpman/app/src/test/resources/org/onosproject/cpman/rest/system-spec-post.json b/apps/cpman/app/src/test/resources/org/onosproject/cpman/rest/system-info-post.json
similarity index 100%
rename from apps/cpman/app/src/test/resources/org/onosproject/cpman/rest/system-spec-post.json
rename to apps/cpman/app/src/test/resources/org/onosproject/cpman/rest/system-info-post.json