[ONOS-3648] Implement REST API for collecting system metrics

- Implement REST API for gathering system metrics
- Add unit test for REST API
- Add swagger doc for REST API

Change-Id: Iedd21a5f6ed14d595e4d35c1fa08270b48a5031e
diff --git a/apps/cpman/pom.xml b/apps/cpman/pom.xml
index f79b9ff..4b6a4ce 100644
--- a/apps/cpman/pom.xml
+++ b/apps/cpman/pom.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!--
-  ~ Copyright 2014-2016 Open Networking Laboratory
+  ~ Copyright 2015-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.
@@ -28,6 +28,8 @@
     <artifactId>onos-app-cpman</artifactId>
     <packaging>bundle</packaging>
 
+    <url>http://onosproject.org</url>
+
     <description>Control Plane Management Application</description>
 
     <properties>
@@ -35,25 +37,60 @@
         <onos.app.category>default</onos.app.category>
         <onos.app.url>http://onosproject.org</onos.app.url>
         <onos.app.readme>Control plane management application.</onos.app.readme>
+        <web.context>/onos/cpman</web.context>
+        <api.version>1.0.0</api.version>
+        <api.title>Control Plane Manager REST API</api.title>
+        <api.description>
+            APIs for interacting with the Control Plane Management application.
+        </api.description>
+        <api.package>org.onosproject.cpman.rest</api.package>
     </properties>
 
     <dependencies>
         <dependency>
-            <groupId>org.onosproject</groupId>
-            <artifactId>onos-api</artifactId>
-            <version>${project.version}</version>
-        </dependency>
-        <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>org.osgi.compendium</artifactId>
         </dependency>
         <dependency>
+            <groupId>org.osgi</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.scr.annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.karaf.shell</groupId>
+            <artifactId>org.apache.karaf.shell.console</artifactId>
+            <scope>compile</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-cli</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onos-core-serializers</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onlab-junit</artifactId>
             <scope>test</scope>
         </dependency>
         <dependency>
             <groupId>org.onosproject</groupId>
+            <artifactId>onos-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-rest</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
             <artifactId>onos-api</artifactId>
             <version>${project.version}</version>
             <classifier>tests</classifier>
@@ -62,6 +99,49 @@
         <dependency>
             <groupId>org.onosproject</groupId>
             <artifactId>onlab-misc</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.ws.rs</groupId>
+            <artifactId>jsr311-api</artifactId>
+            <version>1.1.1</version>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-servlet</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-annotations</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey</groupId>
+            <artifactId>jersey-client</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.easymock</groupId>
+            <artifactId>easymock</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey.jersey-test-framework</groupId>
+            <artifactId>jersey-test-framework-core</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.sun.jersey.jersey-test-framework</groupId>
+            <artifactId>jersey-test-framework-grizzly2</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.onosproject</groupId>
+            <artifactId>onlab-osgi</artifactId>
             <version>${project.version}</version>
             <classifier>tests</classifier>
             <scope>test</scope>
@@ -73,15 +153,40 @@
             <plugin>
                 <groupId>org.apache.felix</groupId>
                 <artifactId>maven-bundle-plugin</artifactId>
-            </plugin>
-
-            <plugin>
-                <groupId>org.apache.felix</groupId>
-                <artifactId>maven-scr-plugin</artifactId>
-            </plugin>
-            <plugin>
-                <groupId>org.onosproject</groupId>
-                <artifactId>onos-maven-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <_wab>src/main/webapp/</_wab>
+                        <Include-Resource>
+                            WEB-INF/classes/apidoc/swagger.json=target/swagger.json,
+                            {maven-resources}
+                        </Include-Resource>
+                        <Bundle-SymbolicName>
+                            ${project.groupId}.${project.artifactId}
+                        </Bundle-SymbolicName>
+                        <Import-Package>
+                            org.slf4j,
+                            org.osgi.framework,
+                            javax.ws.rs,
+                            javax.ws.rs.core,
+                            com.sun.jersey.api.core,
+                            com.sun.jersey.spi.container.servlet,
+                            com.sun.jersey.server.impl.container.servlet,
+                            com.fasterxml.jackson.databind,
+                            com.fasterxml.jackson.databind.node,
+                            com.fasterxml.jackson.core,
+                            org.apache.karaf.shell.commands,
+                            org.apache.karaf.shell.console,
+                            com.google.common.*,
+                            org.onlab.packet.*,
+                            org.onlab.rest.*,
+                            org.onosproject.*,
+                            org.onlab.util.*,
+                            org.jboss.netty.util.*
+                        </Import-Package>
+                        <Web-ContextPath>${web.context}</Web-ContextPath>
+                    </instructions>
+                </configuration>
             </plugin>
         </plugins>
     </build>
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/ControlMetric.java b/apps/cpman/src/main/java/org/onosproject/cpman/ControlMetric.java
index a431817..fc1640f 100644
--- a/apps/cpman/src/main/java/org/onosproject/cpman/ControlMetric.java
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/ControlMetric.java
@@ -23,7 +23,7 @@
     private final ControlMetricType metricType;
     private final MetricValue metricValue;
 
-    ControlMetric(ControlMetricType metricType, MetricValue metricValue) {
+    public ControlMetric(ControlMetricType metricType, MetricValue metricValue) {
         this.metricType = metricType;
         this.metricValue = metricValue;
     }
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneManager.java b/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneManager.java
index 3305297..941cc0f 100644
--- a/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneManager.java
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneManager.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2015-2016 Open Networking Laboratory
+ * 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.
@@ -16,117 +16,47 @@
 package org.onosproject.cpman;
 
 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.Component;
 import org.apache.felix.scr.annotations.Reference;
 import org.apache.felix.scr.annotations.ReferenceCardinality;
-import org.onlab.metrics.MetricsService;
 import org.onosproject.core.ApplicationId;
 import org.onosproject.core.CoreService;
 import org.onosproject.net.device.DeviceService;
 import org.slf4j.Logger;
-
-import java.util.HashSet;
-import java.util.Optional;
-import java.util.Set;
-
-import static org.slf4j.LoggerFactory.getLogger;
+import org.slf4j.LoggerFactory;
 
 /**
- * Control plane management application.
+ * Skeletal ONOS application component.
  */
 @Component(immediate = true)
 public class ControlPlaneManager {
 
-    private final Logger log = getLogger(getClass());
-    private Set<ControlMetricsObserver> controlMetricsObservers = new HashSet<>();
-    private ControlMetricsObserver cpObserver;
-
-    private ApplicationId appId;
-
-    private ControlMetricsFactory cmf;
-
-    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DeviceService deviceService;
+    private final Logger log = LoggerFactory.getLogger(getClass());
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected MetricsService metricsService;
+    protected DeviceService deviceService;
+
+    private ApplicationId appId;
 
     @Activate
-    public void activate() {
+    protected void activate() {
         appId = coreService.registerApplication("org.onosproject.cpman");
-
-        cmf = ControlMetricsFactory.getInstance(metricsService, deviceService);
-        // currently disable monitoring by default
-        // cmf.startMonitor();
-
-        registerObserver();
-
+        deviceService.getAvailableDevices();
         log.info("Started");
     }
 
     @Deactivate
-    public void deactivate() {
-        unregisterObserver();
-        cmf.stopMonitor();
+    protected void deactivate() {
         log.info("Stopped");
     }
 
     @Modified
-    public void modified() {
+    protected void modified() {
     }
 
-    private void registerObserver() {
-        cpObserver = new DefaultControlMetricsObserver();
-        this.addControlMetricsObserver(cpObserver);
-    }
-
-    private void unregisterObserver() {
-        this.removeControlMetricsObserver(cpObserver);
-    }
-
-    private void executeMonitorTask() {
-
-        // TODO: execute monitoring task with 1 minute period
-        if (cmf.isMonitor()) {
-            controlMetricsObservers.forEach(observer -> {
-
-                // only OpenFlow messages are spontaneously monitored with
-                // 1 minute period. Other system metrics will be pushed from
-                // external monitoring agent through REST API
-
-                // feed the control message stats
-                cmf.getDeviceIds().forEach(v -> {
-                    observer.feedMetrics(cmf.inboundPacket(v), Optional.of(v));
-                    observer.feedMetrics(cmf.outboundPacket(v), Optional.of(v));
-                    observer.feedMetrics(cmf.flowmodPacket(v), Optional.of(v));
-                    observer.feedMetrics(cmf.flowrmvPacket(v), Optional.of(v));
-                    observer.feedMetrics(cmf.requestPacket(v), Optional.of(v));
-                    observer.feedMetrics(cmf.replyPacket(v), Optional.of(v));
-                });
-            });
-        }
-    }
-
-    /**
-     * Adds a new control metrics observer.
-     *
-     * @param cmObserver control metric observer instance
-     */
-    public void addControlMetricsObserver(ControlMetricsObserver cmObserver) {
-        controlMetricsObservers.add(cmObserver);
-    }
-
-    /**
-     * Removes an existing control metrics observer.
-     *
-     * @param cmObserver control metric observer instance
-     */
-    public void removeControlMetricsObserver(ControlMetricsObserver cmObserver) {
-        controlMetricsObservers.remove(cmObserver);
-    }
 }
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneMonitor.java b/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneMonitor.java
index 2144f46..e69a915 100644
--- a/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneMonitor.java
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneMonitor.java
@@ -16,9 +16,9 @@
 package org.onosproject.cpman;
 
 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.Component;
 import org.apache.felix.scr.annotations.Service;
 import org.onosproject.cluster.NodeId;
 import org.onosproject.net.DeviceId;
@@ -41,6 +41,7 @@
 
     @Activate
     public void activate() {
+
     }
 
     @Deactivate
@@ -52,12 +53,12 @@
     }
 
     @Override
-    public void updateMetric(ControlMetric cpm, int updateInterval,
+    public void updateMetric(ControlMetric cpm, Integer updateInterval,
                              Optional<DeviceId> deviceId) {
     }
 
     @Override
-    public void updateMetric(ControlMetric controlMetric, int updateInterval,
+    public void updateMetric(ControlMetric controlMetric, Integer updateInterval,
                              String resourceName) {
 
     }
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneMonitorService.java b/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneMonitorService.java
index d35f24f..d4e6bc5 100644
--- a/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneMonitorService.java
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/ControlPlaneMonitorService.java
@@ -33,7 +33,7 @@
      * @param updateInterval value update interval (time unit will be in minute)
      * @param deviceId       {@link org.onosproject.net.DeviceId}
      */
-    void updateMetric(ControlMetric controlMetric, int updateInterval, Optional<DeviceId> deviceId);
+    void updateMetric(ControlMetric controlMetric, Integer updateInterval, Optional<DeviceId> deviceId);
 
     /**
      * Adds a new control metric value with a certain update interval.
@@ -42,7 +42,7 @@
      * @param updateInterval    value update interval (time unit will be in minute)
      * @param resourceName      resource name
      */
-    void updateMetric(ControlMetric controlMetric, int updateInterval, String resourceName);
+    void updateMetric(ControlMetric controlMetric, Integer updateInterval, String resourceName);
 
     /**
      * Obtains the control plane load of a specific device.
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/DefaultControlMetricsObserver.java b/apps/cpman/src/main/java/org/onosproject/cpman/DefaultControlMetricsObserver.java
index 434c165..145ea9f 100644
--- a/apps/cpman/src/main/java/org/onosproject/cpman/DefaultControlMetricsObserver.java
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/DefaultControlMetricsObserver.java
@@ -31,14 +31,22 @@
 
     @Override
     public void feedMetrics(MetricsAggregator ma, Optional<DeviceId> deviceId) {
-        MetricValue mv = new MetricValue((long) ma.getRate(), (long) ma.getLoad(), (long) ma.getCount());
+        MetricValue mv = new MetricValue.Builder()
+                        .rate(ma.getRate())
+                        .count(ma.getCount())
+                        .load(ma.getLoad())
+                        .add();
         ControlMetric cm = new ControlMetric(ma.getMetricsType(), mv);
         controlPlaneMonitorService.updateMetric(cm, 1, deviceId);
     }
 
     @Override
     public void feedMetrics(MetricsAggregator ma, String resourceName) {
-        MetricValue mv = new MetricValue((long) ma.getRate(), (long) ma.getLoad(), (long) ma.getCount());
+        MetricValue mv = new MetricValue.Builder()
+                        .rate(ma.getRate())
+                        .count(ma.getCount())
+                        .load(ma.getLoad())
+                        .add();
         ControlMetric cm = new ControlMetric(ma.getMetricsType(), mv);
         controlPlaneMonitorService.updateMetric(cm, 1, resourceName);
     }
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/MetricValue.java b/apps/cpman/src/main/java/org/onosproject/cpman/MetricValue.java
index 3603b3a..e0f7342 100644
--- a/apps/cpman/src/main/java/org/onosproject/cpman/MetricValue.java
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/MetricValue.java
@@ -20,7 +20,7 @@
 /**
  * Primitive Metric Value.
  */
-public class MetricValue {
+public final class MetricValue {
 
     private final long rate;
     private final long load;
@@ -33,24 +33,90 @@
      * @param load load
      * @param count count
      */
-    MetricValue(long rate, long load, long count) {
+    private MetricValue(long rate, long load, long count) {
         this.rate = rate;
         this.load = load;
         this.count = count;
     }
 
+    /**
+     * Returns rate value.
+     *
+     * @return rate
+     */
     public long getRate() {
         return rate;
     }
 
+    /**
+     * Returns load value.
+     *
+     * @return load
+     */
     public long getLoad() {
         return load;
     }
 
+    /**
+     * Returns count value.
+     *
+     * @return cound
+     */
     public long getCount() {
         return count;
     }
 
+    /**
+     * MetricValue builder class.
+     */
+    public static final class Builder {
+        private long rate;
+        private long load;
+        private long count;
+
+        /**
+         * Sets rate value.
+         *
+         * @param rate rate value
+         * @return Builder object
+         */
+        public Builder rate(long rate) {
+            this.rate = rate;
+            return this;
+        }
+
+        /**
+         * Sets load value.
+         *
+         * @param load load value
+         * @return Builder object
+         */
+        public Builder load(long load) {
+            this.load = load;
+            return this;
+        }
+
+        /**
+         * Sets count value.
+         *
+         * @param count count value
+         * @return Builder object
+         */
+        public Builder count(long count) {
+            this.count = count;
+            return this;
+        }
+
+        /**
+         * Builds a MetricValue object.
+         *
+         * @return MetricValue object
+         */
+        public MetricValue add() {
+            return new MetricValue(rate, load, count);
+        }
+    }
+
     @Override
     public boolean equals(Object obj) {
         if (this == obj) {
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/MetricsAggregator.java b/apps/cpman/src/main/java/org/onosproject/cpman/MetricsAggregator.java
index 139a9a4..3058402 100644
--- a/apps/cpman/src/main/java/org/onosproject/cpman/MetricsAggregator.java
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/MetricsAggregator.java
@@ -134,8 +134,8 @@
      *
      * @return load value
      */
-    public double getLoad() {
-        return rateMeter.getOneMinuteRate() / countMeter.getOneMinuteRate();
+    public long getLoad() {
+        return (long) rateMeter.getOneMinuteRate() / (long) countMeter.getOneMinuteRate();
     }
 
     /**
@@ -143,8 +143,8 @@
      *
      * @return rate value
      */
-    public double getRate() {
-        return rateMeter.getOneMinuteRate();
+    public long getRate() {
+        return (long) rateMeter.getOneMinuteRate();
     }
 
     /**
@@ -152,7 +152,7 @@
      *
      * @return count value
      */
-    public double getCount() {
-        return countMeter.getOneMinuteRate() * EXECUTE_PERIOD_IN_SECOND;
+    public long getCount() {
+        return (long) countMeter.getOneMinuteRate() * EXECUTE_PERIOD_IN_SECOND;
     }
 }
\ No newline at end of file
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/rest/CPManWebApplication.java b/apps/cpman/src/main/java/org/onosproject/cpman/rest/CPManWebApplication.java
new file mode 100644
index 0000000..26566f8
--- /dev/null
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/rest/CPManWebApplication.java
@@ -0,0 +1,31 @@
+/*
+ * 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.rest;
+
+import org.onlab.rest.AbstractWebApplication;
+
+import java.util.Set;
+
+/**
+ * CPMan REST APIs web application.
+ */
+public class CPManWebApplication extends AbstractWebApplication {
+    @Override
+    public Set<Class<?>> getClasses() {
+        return getClasses(ControlMetricsCollectorWebResource.class);
+    }
+}
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java b/apps/cpman/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java
new file mode 100644
index 0000000..444d3dc
--- /dev/null
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java
@@ -0,0 +1,286 @@
+/*
+ * 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.rest;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.node.ObjectNode;
+import org.onosproject.cpman.ControlMetric;
+import org.onosproject.cpman.ControlMetricType;
+import org.onosproject.cpman.ControlMetricsSystemSpec;
+import org.onosproject.cpman.ControlPlaneMonitorService;
+import org.onosproject.cpman.MetricValue;
+import org.onosproject.rest.AbstractWebResource;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.POST;
+import javax.ws.rs.Path;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Optional;
+
+/**
+ * Collect control plane metrics.
+ */
+@Path("cpman")
+public class ControlMetricsCollectorWebResource extends AbstractWebResource {
+
+    final ControlPlaneMonitorService service = get(ControlPlaneMonitorService.class);
+    public static final int UPDATE_INTERVAL = 1;           // 1 minute update interval
+    public static final String INVALID_SYSTEM_SPECS = "Invalid system specifications";
+
+    /**
+     * Collects CPU metrics.
+     *
+     * @param stream JSON stream
+     * @return 200 OK
+     * @onos.rsModel CpuMetricsPost
+     */
+    @POST
+    @Path("cpumetrics")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response cpuMetrics(InputStream stream) {
+        ObjectNode root = mapper().createObjectNode();
+        ControlMetric cm;
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+            JsonNode cpuLoadJson = jsonTree.get("cpuLoad");
+            JsonNode totalCpuTimeJson = jsonTree.get("totalCpuTime");
+            JsonNode sysCpuTimeJson = jsonTree.get("sysCpuTime");
+            JsonNode userCpuTimeJson = jsonTree.get("userCpuTime");
+            JsonNode cpuIdleTimeJson = jsonTree.get("cpuIdleTime");
+
+            if (cpuLoadJson != null) {
+                cm = new ControlMetric(ControlMetricType.CPU_LOAD,
+                     new MetricValue.Builder().load(cpuLoadJson.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (totalCpuTimeJson != null) {
+                cm = new ControlMetric(ControlMetricType.TOTAL_CPU_TIME,
+                     new MetricValue.Builder().load(totalCpuTimeJson.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (sysCpuTimeJson != null) {
+                cm = new ControlMetric(ControlMetricType.SYS_CPU_TIME,
+                        new MetricValue.Builder().load(sysCpuTimeJson.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (userCpuTimeJson != null) {
+                cm = new ControlMetric(ControlMetricType.USER_CPU_TIME,
+                        new MetricValue.Builder().load(userCpuTimeJson.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (cpuIdleTimeJson != null) {
+                cm = new ControlMetric(ControlMetricType.CPU_IDLE_TIME,
+                        new MetricValue.Builder().load(cpuIdleTimeJson.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        return ok(root).build();
+    }
+
+    /**
+     * Collects memory metrics.
+     *
+     * @param stream JSON stream
+     * @return 200 OK
+     * @onos.rsModel MemoryMetricsPost
+     */
+    @POST
+    @Path("memorymetrics")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response memoryMetrics(InputStream stream) {
+        ObjectNode root = mapper().createObjectNode();
+        ControlMetric cm;
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+            JsonNode memUsedPerc = jsonTree.get("memoryUsedPercentage");
+            JsonNode memFreePerc = jsonTree.get("memoryFreePercentage");
+            JsonNode memUsed = jsonTree.get("memoryUsed");
+            JsonNode memFree = jsonTree.get("memoryFree");
+
+            if (memUsedPerc != null) {
+                cm = new ControlMetric(ControlMetricType.MEMORY_USED_PERCENTAGE,
+                        new MetricValue.Builder().load(memUsedPerc.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (memFreePerc != null) {
+                cm = new ControlMetric(ControlMetricType.MEMORY_FREE_PERCENTAGE,
+                        new MetricValue.Builder().load(memFreePerc.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (memUsed != null) {
+                cm = new ControlMetric(ControlMetricType.MEMORY_USED,
+                        new MetricValue.Builder().load(memUsed.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (memFree != null) {
+                cm = new ControlMetric(ControlMetricType.MEMORY_FREE,
+                        new MetricValue.Builder().load(memFree.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        return ok(root).build();
+    }
+
+    /**
+     * Collects disk metrics.
+     *
+     * @param stream JSON stream
+     * @return 200 OK
+     * @onos.rsModel DiskMetricsPost
+     */
+    @POST
+    @Path("diskmetrics")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response diskMetrics(InputStream stream) {
+        ObjectNode root = mapper().createObjectNode();
+        ControlMetric cm;
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+            JsonNode readBytes = jsonTree.get("readBytes");
+            JsonNode writeBytes = jsonTree.get("writeBytes");
+
+            if (readBytes != null) {
+                cm = new ControlMetric(ControlMetricType.DISK_READ_BYTES,
+                        new MetricValue.Builder().load(readBytes.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (writeBytes != null) {
+                cm = new ControlMetric(ControlMetricType.DISK_WRITE_BYTES,
+                        new MetricValue.Builder().load(writeBytes.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        return ok(root).build();
+    }
+
+    /**
+     * Collects network metrics.
+     *
+     * @param stream JSON stream
+     * @return 200 OK
+     * @onos.rsModel NetworkMetricsPost
+     */
+    @POST
+    @Path("networkmetrics")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response networkMetrics(InputStream stream) {
+        ObjectNode root = mapper().createObjectNode();
+        ControlMetric cm;
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+            JsonNode inBytes = jsonTree.get("incomingBytes");
+            JsonNode outBytes = jsonTree.get("outgoingBytes");
+            JsonNode inPackets = jsonTree.get("incomingPackets");
+            JsonNode outPackets = jsonTree.get("outgoingPackets");
+
+            if (inBytes != null) {
+                cm = new ControlMetric(ControlMetricType.NW_INCOMING_BYTES,
+                        new MetricValue.Builder().load(inBytes.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (outBytes != null) {
+                cm = new ControlMetric(ControlMetricType.NW_OUTGOING_BYTES,
+                        new MetricValue.Builder().load(outBytes.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (inPackets != null) {
+                cm = new ControlMetric(ControlMetricType.NW_INCOMING_PACKETS,
+                        new MetricValue.Builder().load(inPackets.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+            if (outPackets != null) {
+                cm = new ControlMetric(ControlMetricType.NW_OUTGOING_PACKETS,
+                        new MetricValue.Builder().load(outPackets.asLong()).add());
+                service.updateMetric(cm, UPDATE_INTERVAL, Optional.ofNullable(null));
+            }
+
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        return ok(root).build();
+    }
+
+
+    /**
+     * Collects system specifications.
+     * The system specs include the various control metrics
+     * which do not require aggregation.
+     *
+     * @param stream JSON stream
+     * @return 200 OK
+     * @onos.rsModel SystemSpecsPost
+     */
+    @POST
+    @Path("systemspecs")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces(MediaType.APPLICATION_JSON)
+    public Response systemSpecs(InputStream stream) {
+        ObjectNode root = mapper().createObjectNode();
+
+        try {
+            ObjectNode jsonTree = (ObjectNode) mapper().readTree(stream);
+            JsonNode numOfCores = jsonTree.get("numOfCores");
+            JsonNode numOfCpus = jsonTree.get("numOfCpus");
+            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())
+                        .numOfCpus(numOfCpus.asInt())
+                        .cpuSpeed(cpuSpeed.asInt())
+                        .totalMemory(totalMemory.asLong())
+                        .build();
+                // TODO: need to implement spec store
+
+            } else {
+                throw new IllegalArgumentException(INVALID_SYSTEM_SPECS);
+            }
+
+        } catch (IOException e) {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+        return ok(root).build();
+    }
+}
diff --git a/apps/cpman/src/main/java/org/onosproject/cpman/rest/package-info.java b/apps/cpman/src/main/java/org/onosproject/cpman/rest/package-info.java
new file mode 100644
index 0000000..cf3baaa
--- /dev/null
+++ b/apps/cpman/src/main/java/org/onosproject/cpman/rest/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+
+/**
+ * REST APIs for the control plane monitor.
+ */
+package org.onosproject.cpman.rest;
\ No newline at end of file
diff --git a/apps/cpman/src/main/resources/definitions/CpuMetricsPost.json b/apps/cpman/src/main/resources/definitions/CpuMetricsPost.json
new file mode 100644
index 0000000..9f52429
--- /dev/null
+++ b/apps/cpman/src/main/resources/definitions/CpuMetricsPost.json
@@ -0,0 +1,37 @@
+{
+  "type": "object",
+  "required": [
+    "cpuLoad",
+    "totalCpuTime",
+    "sysCpuTime",
+    "userCpuTime",
+    "cpuIdleTime"
+  ],
+  "properties": {
+    "cpuLoad": {
+      "type": "integer",
+      "format": "int64",
+      "example": "50"
+    },
+    "totalCpuTime": {
+      "type": "integer",
+      "format": "int64",
+      "example": "2000"
+    },
+    "sysCpuTime": {
+      "type": "integer",
+      "format": "int64",
+      "example": "2000"
+    },
+    "userCpuTime": {
+      "type": "integer",
+      "format": "int64",
+      "example": "2000"
+    },
+    "cpuIdleTime": {
+      "type": "integer",
+      "format": "int64",
+      "example": "2000"
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/cpman/src/main/resources/definitions/DiskMetricsPost.json b/apps/cpman/src/main/resources/definitions/DiskMetricsPost.json
new file mode 100644
index 0000000..fe0dab1
--- /dev/null
+++ b/apps/cpman/src/main/resources/definitions/DiskMetricsPost.json
@@ -0,0 +1,19 @@
+{
+  "type": "object",
+  "required": [
+    "readBytes",
+    "writeBytes"
+  ],
+  "properties": {
+    "readBytes": {
+      "type": "integer",
+      "format": "int64",
+      "example": "500"
+    },
+    "writeBytes": {
+      "type": "integer",
+      "format": "int64",
+      "example": "300"
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/cpman/src/main/resources/definitions/MemoryMetricsPost.json b/apps/cpman/src/main/resources/definitions/MemoryMetricsPost.json
new file mode 100644
index 0000000..ab815da
--- /dev/null
+++ b/apps/cpman/src/main/resources/definitions/MemoryMetricsPost.json
@@ -0,0 +1,31 @@
+{
+  "type": "object",
+  "required": [
+    "memoryUsedPercentage",
+    "memoryFreePercentage",
+    "memoryUsed",
+    "memoryFree"
+  ],
+  "properties": {
+    "memoryUsedPercentage": {
+      "type": "integer",
+      "format": "int64",
+      "example": "30"
+    },
+    "memoryFreePercentage": {
+      "type": "integer",
+      "format": "int64",
+      "example": "70"
+    },
+    "memoryUsed": {
+      "type": "integer",
+      "format": "int64",
+      "example": "1024"
+    },
+    "memoryFree": {
+      "type": "integer",
+      "format": "int64",
+      "example": "2048"
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/cpman/src/main/resources/definitions/NetworkMetricsPost.json b/apps/cpman/src/main/resources/definitions/NetworkMetricsPost.json
new file mode 100644
index 0000000..f9ad7d3
--- /dev/null
+++ b/apps/cpman/src/main/resources/definitions/NetworkMetricsPost.json
@@ -0,0 +1,31 @@
+{
+  "type": "object",
+  "required": [
+    "incomingBytes",
+    "outgoingBytes",
+    "incomingPackets",
+    "outgoingPackets"
+  ],
+  "properties": {
+    "incomingBytes": {
+      "type": "integer",
+      "format": "int64",
+      "example": "1024"
+    },
+    "outgoingBytes": {
+      "type": "integer",
+      "format": "int64",
+      "example": "1024"
+    },
+    "incomingPackets": {
+      "type": "integer",
+      "format": "int64",
+      "example": "1000"
+    },
+    "outgoingPackets": {
+      "type": "integer",
+      "format": "int64",
+      "example": "2000"
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/cpman/src/main/resources/definitions/SystemSpecsPost.json b/apps/cpman/src/main/resources/definitions/SystemSpecsPost.json
new file mode 100644
index 0000000..fc4fc16
--- /dev/null
+++ b/apps/cpman/src/main/resources/definitions/SystemSpecsPost.json
@@ -0,0 +1,31 @@
+{
+  "type": "object",
+  "required": [
+    "numOfCores",
+    "numOfCpus",
+    "cpuSpeed",
+    "totalMemory"
+  ],
+  "properties": {
+    "numOfCores": {
+      "type": "integer",
+      "format": "int64",
+      "example": "6"
+    },
+    "numOfCpus": {
+      "type": "integer",
+      "format": "int64",
+      "example": "2"
+    },
+    "cpuSpeed": {
+      "type": "integer",
+      "format": "int64",
+      "example": "2048"
+    },
+    "totalMemory": {
+      "type": "integer",
+      "format": "int64",
+      "example": "4096"
+    }
+  }
+}
\ No newline at end of file
diff --git a/apps/cpman/src/main/webapp/WEB-INF/web.xml b/apps/cpman/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..a1be00b
--- /dev/null
+++ b/apps/cpman/src/main/webapp/WEB-INF/web.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ 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.
+  -->
+<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://java.sun.com/xml/ns/javaee"
+         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
+         id="ONOS" version="2.5">
+    <display-name>Control Plane REST API v1.0</display-name>
+
+    <security-constraint>
+        <web-resource-collection>
+            <web-resource-name>Secured</web-resource-name>
+            <url-pattern>/*</url-pattern>
+        </web-resource-collection>
+        <auth-constraint>
+            <role-name>admin</role-name>
+        </auth-constraint>
+    </security-constraint>
+
+    <security-role>
+        <role-name>admin</role-name>
+    </security-role>
+
+    <login-config>
+        <auth-method>BASIC</auth-method>
+        <realm-name>karaf</realm-name>
+    </login-config>
+
+    <servlet>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <servlet-class>com.sun.jersey.spi.container.servlet.ServletContainer</servlet-class>
+        <init-param>
+            <param-name>javax.ws.rs.Application</param-name>
+            <param-value>org.onosproject.cpman.rest.CPManWebApplication</param-value>
+        </init-param>
+        <load-on-startup>1</load-on-startup>
+    </servlet>
+
+    <servlet-mapping>
+        <servlet-name>JAX-RS Service</servlet-name>
+        <url-pattern>/*</url-pattern>
+    </servlet-mapping>
+</web-app>
diff --git a/apps/cpman/src/test/java/org/onosproject/cpman/ControlPlaneManagerTest.java b/apps/cpman/src/test/java/org/onosproject/cpman/ControlPlaneManagerTest.java
index ae2f3f3..c7102a5 100644
--- a/apps/cpman/src/test/java/org/onosproject/cpman/ControlPlaneManagerTest.java
+++ b/apps/cpman/src/test/java/org/onosproject/cpman/ControlPlaneManagerTest.java
@@ -18,7 +18,6 @@
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
-import org.onlab.metrics.MetricsServiceAdapter;
 import org.onosproject.core.CoreServiceAdapter;
 import org.onosproject.net.device.DeviceServiceAdapter;
 
@@ -37,7 +36,6 @@
         cpMan = new ControlPlaneManager();
         cpMan.coreService = new CoreServiceAdapter();
         cpMan.deviceService = new DeviceServiceAdapter();
-        cpMan.metricsService = new MetricsServiceAdapter();
         cpMan.activate();
     }
 
diff --git a/apps/cpman/src/test/java/org/onosproject/cpman/rest/ControlMetricsCollectorResourceTest.java b/apps/cpman/src/test/java/org/onosproject/cpman/rest/ControlMetricsCollectorResourceTest.java
new file mode 100644
index 0000000..e61873e
--- /dev/null
+++ b/apps/cpman/src/test/java/org/onosproject/cpman/rest/ControlMetricsCollectorResourceTest.java
@@ -0,0 +1,149 @@
+/*
+ * 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.rest;
+
+import com.sun.jersey.api.client.ClientResponse;
+import com.sun.jersey.api.client.WebResource;
+import com.sun.jersey.spi.container.servlet.ServletContainer;
+import com.sun.jersey.test.framework.AppDescriptor;
+import com.sun.jersey.test.framework.JerseyTest;
+import com.sun.jersey.test.framework.WebAppDescriptor;
+import org.junit.Before;
+import org.junit.Test;
+import org.onlab.osgi.ServiceDirectory;
+import org.onlab.osgi.TestServiceDirectory;
+import org.onlab.rest.BaseResource;
+import org.onosproject.cpman.ControlPlaneMonitorService;
+import org.onosproject.net.DeviceId;
+
+import javax.ws.rs.core.MediaType;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.HttpURLConnection;
+import java.net.ServerSocket;
+import java.util.Optional;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.createMock;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.replay;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.Assert.assertThat;
+
+/**
+ * Unit test for ControlMetricsCollector.
+ */
+public class ControlMetricsCollectorResourceTest extends JerseyTest {
+
+    final ControlPlaneMonitorService mockControlPlaneMonitorService =
+                                     createMock(ControlPlaneMonitorService.class);
+
+    /**
+     * Sets up the global values for all the tests.
+     */
+    @Before
+    public void setUpTest() {
+        ServiceDirectory testDirectory =
+                new TestServiceDirectory()
+                        .add(ControlPlaneMonitorService.class, mockControlPlaneMonitorService);
+        BaseResource.setServiceDirectory(testDirectory);
+    }
+
+    @Test
+    public void testCpuMetricsPost() {
+        mockControlPlaneMonitorService.updateMetric(anyObject(), anyObject(),
+                (Optional<DeviceId>) anyObject());
+        expectLastCall().times(5);
+        replay(mockControlPlaneMonitorService);
+        basePostTest("cpu-metrics-post.json", "cpman/cpumetrics");
+    }
+
+    @Test
+    public void testMemoryMetricsPost() {
+        mockControlPlaneMonitorService.updateMetric(anyObject(), anyObject(),
+                (Optional<DeviceId>) anyObject());
+        expectLastCall().times(4);
+        replay(mockControlPlaneMonitorService);
+        basePostTest("memory-metrics-post.json", "cpman/memorymetrics");
+    }
+
+    @Test
+    public void testDiskMetricsPost() {
+        mockControlPlaneMonitorService.updateMetric(anyObject(), anyObject(),
+                (Optional<DeviceId>) anyObject());
+        expectLastCall().times(2);
+        replay(mockControlPlaneMonitorService);
+        basePostTest("disk-metrics-post.json", "cpman/diskmetrics");
+    }
+
+    @Test
+    public void testNetworkMetricsPost() {
+        mockControlPlaneMonitorService.updateMetric(anyObject(), anyObject(),
+                (Optional<DeviceId>) anyObject());
+        expectLastCall().times(4);
+        replay(mockControlPlaneMonitorService);
+        basePostTest("network-metrics-post.json", "cpman/networkmetrics");
+    }
+
+    @Test
+    public void testSystemSpecsPost() {
+        basePostTest("system-spec-post.json", "cpman/systemspecs");
+    }
+
+    private void basePostTest(String jsonFile, String path) {
+        final WebResource rs = resource();
+        InputStream jsonStream = ControlMetricsCollectorResourceTest.class
+                .getResourceAsStream(jsonFile);
+
+        assertThat(jsonStream, notNullValue());
+
+        ClientResponse response = rs.path(path)
+                .type(MediaType.APPLICATION_JSON_TYPE)
+                .post(ClientResponse.class, jsonStream);
+        assertThat(response.getStatus(), is(HttpURLConnection.HTTP_OK));
+    }
+
+    public ControlMetricsCollectorResourceTest() {
+        super(new WebAppDescriptor.Builder("javax.ws.rs.Application",
+                CPManWebApplication.class.getCanonicalName())
+                .servletClass(ServletContainer.class).build());
+    }
+
+    /**
+     * Assigns an available port for the test.
+     *
+     * @param defaultPort If a port cannot be determined, this one is used.
+     * @return free port
+     */
+    @Override
+    public int getPort(int defaultPort) {
+        try {
+            ServerSocket socket = new ServerSocket(0);
+            socket.setReuseAddress(true);
+            int port = socket.getLocalPort();
+            socket.close();
+            return port;
+        } catch (IOException ioe) {
+            return defaultPort;
+        }
+    }
+
+    @Override
+    public AppDescriptor configure() {
+        return new WebAppDescriptor.Builder("org.onosproject.cpman.rest").build();
+    }
+}
diff --git a/apps/cpman/src/test/resources/org/onosproject/cpman/rest/cpu-metrics-post.json b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/cpu-metrics-post.json
new file mode 100644
index 0000000..0f6c7bc
--- /dev/null
+++ b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/cpu-metrics-post.json
@@ -0,0 +1,7 @@
+{
+  "cpuLoad": 50,
+  "totalCpuTime": 2000,
+  "sysCpuTime": 2000,
+  "userCpuTime": 2000,
+  "cpuIdleTime": 2000
+}
\ No newline at end of file
diff --git a/apps/cpman/src/test/resources/org/onosproject/cpman/rest/disk-metrics-post.json b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/disk-metrics-post.json
new file mode 100644
index 0000000..ebdf00a
--- /dev/null
+++ b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/disk-metrics-post.json
@@ -0,0 +1,4 @@
+{
+  "readBytes": 500,
+  "writeBytes": 300
+}
\ No newline at end of file
diff --git a/apps/cpman/src/test/resources/org/onosproject/cpman/rest/memory-metrics-post.json b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/memory-metrics-post.json
new file mode 100644
index 0000000..8bce870
--- /dev/null
+++ b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/memory-metrics-post.json
@@ -0,0 +1,6 @@
+{
+  "memoryUsedPercentage": 30,
+  "memoryFreePercentage": 70,
+  "memoryUsed": 1024,
+  "memoryFree": 2048
+}
\ No newline at end of file
diff --git a/apps/cpman/src/test/resources/org/onosproject/cpman/rest/network-metrics-post.json b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/network-metrics-post.json
new file mode 100644
index 0000000..bdf7c8d
--- /dev/null
+++ b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/network-metrics-post.json
@@ -0,0 +1,6 @@
+{
+  "incomingBytes": 1024,
+  "outgoingBytes": 1024,
+  "incomingPackets": 1000,
+  "outgoingPackets": 2000
+}
\ No newline at end of file
diff --git a/apps/cpman/src/test/resources/org/onosproject/cpman/rest/system-spec-post.json b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/system-spec-post.json
new file mode 100644
index 0000000..5b6f0cc
--- /dev/null
+++ b/apps/cpman/src/test/resources/org/onosproject/cpman/rest/system-spec-post.json
@@ -0,0 +1,6 @@
+{
+  "numOfCores": 6,
+  "numOfCpus": 2,
+  "cpuSpeed": 2048,
+  "totalMemory": 4096
+}
\ No newline at end of file