Split CPMan into api and app submodules

Change-Id: Iacddea67ea0f7189ab918cf9e2a7a414100fc503
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
new file mode 100644
index 0000000..3becf63
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsFactory.java
@@ -0,0 +1,432 @@
+/*
+ * 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.
+ * 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 com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.collect.Sets;
+import org.onlab.metrics.MetricsService;
+import org.onosproject.cpman.ControlMetricType;
+import org.onosproject.net.DeviceId;
+import org.onosproject.net.device.DeviceService;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 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;
+
+    // define a set of MetricsAggregators
+    private MetricsAggregator cpuLoad;
+    private MetricsAggregator totalCpuTime;
+    private MetricsAggregator sysCpuTime;
+    private MetricsAggregator userCpuTime;
+    private MetricsAggregator cpuIdleTime;
+    private MetricsAggregator memoryUsed;
+    private MetricsAggregator memoryFree;
+    private MetricsAggregator memoryUsedPercentage;
+    private MetricsAggregator memoryFreePercentage;
+    private Map<String, MetricsAggregator> diskReadBytes;
+    private Map<String, MetricsAggregator> diskWriteBytes;
+    private Map<String, MetricsAggregator> nwIncomingBytes;
+    private Map<String, MetricsAggregator> nwOutgoingBytes;
+    private Map<String, MetricsAggregator> nwIncomingPackets;
+    private Map<String, MetricsAggregator> nwOutgoingPackets;
+
+    private Map<DeviceId, MetricsAggregator> inboundPacket;
+    private Map<DeviceId, MetricsAggregator> outboundPacket;
+    private Map<DeviceId, MetricsAggregator> flowmodPacket;
+    private Map<DeviceId, MetricsAggregator> flowrmvPacket;
+    private Map<DeviceId, MetricsAggregator> requestPacket;
+    private Map<DeviceId, MetricsAggregator> replyPacket;
+    private Set<DeviceId> deviceIds = Sets.newConcurrentHashSet();
+    private Set<String> diskPartitions = Sets.newConcurrentHashSet();
+    private Set<String> nwInterfaces = Sets.newConcurrentHashSet();
+
+    private ControlMetricsFactory(MetricsService metricsService, DeviceService deviceService) {
+        this.metricsService = metricsService;
+        registerMetrics();
+
+        deviceService.getDevices().forEach(d->deviceIds.add(d.id()));
+
+        addAllControlMessageMetrics(deviceIds);
+    }
+
+    public static ControlMetricsFactory getInstance(MetricsService metricsService,
+                                                    DeviceService deviceService) {
+        if (uniqueInstance == null) {
+            synchronized (ControlMetricsFactory.class) {
+                if (uniqueInstance == null) {
+                    uniqueInstance = new ControlMetricsFactory(metricsService, deviceService);
+                }
+            }
+        }
+        return uniqueInstance;
+    }
+
+    /**
+     * Sets system specification.
+     *
+     * @param cmss ControlMetricsSystemSpec object
+     */
+    public void setSystemSpec(ControlMetricsSystemSpec cmss) {
+        if (this.cmss == null) {
+            this.cmss = cmss;
+        }
+    }
+
+    /**
+     * Adds control metrics of a new device.
+     *
+     * @param deviceId {@link org.onosproject.net.DeviceId}
+     */
+    public void addControlMessageMetricsByDeviceId(DeviceId deviceId) {
+        MetricsAggregator inbound = new MetricsAggregator(metricsService,
+                        ControlMetricType.INBOUND_PACKET, Optional.of(deviceId));
+        MetricsAggregator outbound = new MetricsAggregator(metricsService,
+                        ControlMetricType.OUTBOUND_PACKET, Optional.of(deviceId));
+        MetricsAggregator flowmod = new MetricsAggregator(metricsService,
+                        ControlMetricType.FLOW_MOD_PACKET, Optional.of(deviceId));
+        MetricsAggregator flowrmv = new MetricsAggregator(metricsService,
+                        ControlMetricType.FLOW_REMOVED_PACKET, Optional.of(deviceId));
+        MetricsAggregator request = new MetricsAggregator(metricsService,
+                        ControlMetricType.REQUEST_PACKET, Optional.of(deviceId));
+        MetricsAggregator reply = new MetricsAggregator(metricsService,
+                        ControlMetricType.REPLY_PACKET, Optional.of(deviceId));
+
+        inboundPacket.putIfAbsent(deviceId, inbound);
+        outboundPacket.putIfAbsent(deviceId, outbound);
+        flowmodPacket.putIfAbsent(deviceId, flowmod);
+        flowrmvPacket.putIfAbsent(deviceId, flowrmv);
+        requestPacket.putIfAbsent(deviceId, request);
+        replyPacket.putIfAbsent(deviceId, reply);
+
+        deviceIds.add(deviceId);
+    }
+
+    /**
+     * Adds control metrics of a disk.
+     *
+     * @param partitionName disk partition name
+     */
+    public void addDiskMetricsByPartition(String partitionName) {
+        MetricsAggregator readBytes = new MetricsAggregator(metricsService,
+                        ControlMetricType.DISK_READ_BYTES, partitionName);
+        MetricsAggregator writeBytes = new MetricsAggregator(metricsService,
+                ControlMetricType.DISK_WRITE_BYTES, partitionName);
+
+        diskReadBytes.putIfAbsent(partitionName, readBytes);
+        diskWriteBytes.putIfAbsent(partitionName, writeBytes);
+
+        diskPartitions.add(partitionName);
+    }
+
+    /**
+     * Adds control metrics of a ethernet interface.
+     *
+     * @param interfaceName network interface name
+     */
+    public void addNetworkMetricsByInterface(String interfaceName) {
+        MetricsAggregator incomingBytes = new MetricsAggregator(metricsService,
+                        ControlMetricType.NW_INCOMING_BYTES, interfaceName);
+        MetricsAggregator outgoingBytes = new MetricsAggregator(metricsService,
+                ControlMetricType.NW_OUTGOING_BYTES, interfaceName);
+        MetricsAggregator incomingPackets = new MetricsAggregator(metricsService,
+                ControlMetricType.NW_INCOMING_PACKETS, interfaceName);
+        MetricsAggregator outgoingPackets = new MetricsAggregator(metricsService,
+                ControlMetricType.NW_OUTGOING_PACKETS, interfaceName);
+
+        nwIncomingBytes.putIfAbsent(interfaceName, incomingBytes);
+        nwOutgoingBytes.putIfAbsent(interfaceName, outgoingBytes);
+        nwIncomingPackets.putIfAbsent(interfaceName, incomingPackets);
+        nwOutgoingPackets.putIfAbsent(interfaceName, outgoingPackets);
+
+        nwInterfaces.add(interfaceName);
+    }
+
+    /**
+     * Removes control metrics of an existing device.
+     *
+     * @param deviceId {@link org.onosproject.net.DeviceId}
+     */
+    public void removeControlMessageMetricsByDeviceId(DeviceId deviceId) {
+        inboundPacket.remove(deviceId);
+        outboundPacket.remove(deviceId);
+        flowmodPacket.remove(deviceId);
+        flowrmvPacket.remove(deviceId);
+        requestPacket.remove(deviceId);
+        replyPacket.remove(deviceId);
+
+        deviceIds.remove(deviceId);
+    }
+
+    /**
+     * Removes control metrics of a disk.
+     *
+     * @param partitionName disk partition name
+     */
+    public void removeDiskMetricsByResourceName(String partitionName) {
+        diskReadBytes.remove(partitionName);
+        diskWriteBytes.remove(partitionName);
+
+        diskPartitions.remove(partitionName);
+    }
+
+    /**
+     * Removes control metrics of a network interface.
+     *
+     * @param interfaceName network interface name
+     */
+    public void removeNetworkInterfacesByResourceName(String interfaceName) {
+        nwIncomingBytes.remove(interfaceName);
+        nwOutgoingBytes.remove(interfaceName);
+        nwIncomingPackets.remove(interfaceName);
+        nwOutgoingPackets.remove(interfaceName);
+
+        nwInterfaces.remove(interfaceName);
+    }
+
+    /**
+     * Returns all device ids.
+     *
+     * @return a collection of device id
+     */
+    public Set<DeviceId> getDeviceIds() {
+        return ImmutableSet.copyOf(this.deviceIds);
+    }
+
+    /**
+     * Returns all disk partition names.
+     *
+     * @return a collection of disk partition.
+     */
+    public Set<String> getDiskPartitions() {
+        return ImmutableSet.copyOf(this.diskPartitions);
+    }
+
+    /**
+     * Returns all network interface names.
+     *
+     * @return a collection of network interface.
+     */
+    public Set<String> getNetworkInterfaces() {
+        return ImmutableSet.copyOf(this.nwInterfaces);
+    }
+
+    /**
+     * Adds control metrics for all devices.
+     *
+     * @param deviceIds a set of deviceIds
+     */
+    public void addAllControlMessageMetrics(Set<DeviceId> deviceIds) {
+        deviceIds.forEach(v -> addControlMessageMetricsByDeviceId(v));
+    }
+
+    /**
+     * Returns monitoring status.
+     *
+     * @return monitoring status
+     */
+    public boolean isMonitor() {
+        return this.enableMonitor;
+    }
+
+    /**
+     * Enable control plane monitoring.
+     */
+    protected void startMonitor() {
+        this.enableMonitor = true;
+    }
+
+    /**
+     * Disable control plane monitoring.
+     */
+    protected void stopMonitor() {
+        this.enableMonitor = false;
+    }
+
+    /**
+     * Registers new control metrics.
+     */
+    protected void registerMetrics() {
+        /* CPU */
+        cpuLoad = new MetricsAggregator(metricsService, ControlMetricType.CPU_LOAD);
+        totalCpuTime = new MetricsAggregator(metricsService, ControlMetricType.TOTAL_CPU_TIME);
+        sysCpuTime = new MetricsAggregator(metricsService, ControlMetricType.SYS_CPU_TIME);
+        userCpuTime = new MetricsAggregator(metricsService, ControlMetricType.USER_CPU_TIME);
+        cpuIdleTime = new MetricsAggregator(metricsService, ControlMetricType.CPU_IDLE_TIME);
+
+        /* Memory */
+        memoryFree = new MetricsAggregator(metricsService, ControlMetricType.MEMORY_FREE);
+        memoryUsed = new MetricsAggregator(metricsService, ControlMetricType.MEMORY_USED);
+        memoryFreePercentage = new MetricsAggregator(metricsService,
+                                        ControlMetricType.MEMORY_FREE_PERCENTAGE);
+        memoryUsedPercentage = new MetricsAggregator(metricsService,
+                                        ControlMetricType.MEMORY_USED_PERCENTAGE);
+
+        /* Disk I/O */
+        diskReadBytes = new ConcurrentHashMap<>();
+        diskWriteBytes = new ConcurrentHashMap<>();
+
+        /* Network I/O */
+        nwIncomingBytes = new ConcurrentHashMap<>();
+        nwOutgoingBytes = new ConcurrentHashMap<>();
+        nwIncomingPackets = new ConcurrentHashMap<>();
+        nwOutgoingPackets = new ConcurrentHashMap<>();
+
+        /* OpenFlow Messages */
+        inboundPacket = new ConcurrentHashMap<>();
+        outboundPacket = new ConcurrentHashMap<>();
+        flowmodPacket = new ConcurrentHashMap<>();
+        flowrmvPacket = new ConcurrentHashMap<>();
+        requestPacket = new ConcurrentHashMap<>();
+        replyPacket = new ConcurrentHashMap<>();
+    }
+
+    /**
+     * Unregisters all control metrics.
+     */
+    protected void unregisterMetrics() {
+        /* Disk I/O */
+        diskReadBytes.clear();
+        diskWriteBytes.clear();
+
+        /* Network I/O */
+        nwIncomingBytes.clear();
+        nwOutgoingBytes.clear();
+        nwIncomingPackets.clear();
+        nwOutgoingPackets.clear();
+
+        /* OpenFlow Message */
+        inboundPacket.clear();
+        outboundPacket.clear();
+        flowmodPacket.clear();
+        flowrmvPacket.clear();
+        requestPacket.clear();
+        replyPacket.clear();
+    }
+
+    public MetricsAggregator cpuLoadMetric() {
+        return cpuLoad;
+    }
+
+    public MetricsAggregator totalCpuTimeMetric() {
+        return totalCpuTime;
+    }
+
+    public MetricsAggregator sysCpuTimeMetric() {
+        return sysCpuTime;
+    }
+
+    public MetricsAggregator userCpuTime() {
+        return userCpuTime;
+    }
+
+    public MetricsAggregator cpuIdleTime() {
+        return cpuIdleTime;
+    }
+
+    public MetricsAggregator memoryFreePercentage() {
+        return memoryFreePercentage;
+    }
+
+    public MetricsAggregator memoryUsedPercentage() {
+        return memoryUsedPercentage;
+    }
+
+    public MetricsAggregator diskReadBytes(String partitionName) {
+        return diskReadBytes.get(partitionName);
+    }
+
+    public MetricsAggregator diskWriteBytes(String partitionName) {
+        return diskWriteBytes.get(partitionName);
+    }
+
+    public MetricsAggregator nwIncomingBytes(String interfaceName) {
+        return nwIncomingBytes.get(interfaceName);
+    }
+
+    public MetricsAggregator nwOutgoingBytes(String interfaceName) {
+        return nwOutgoingBytes.get(interfaceName);
+    }
+
+    public MetricsAggregator nwIncomingPackets(String interfaceName) {
+        return nwIncomingPackets.get(interfaceName);
+    }
+
+    public MetricsAggregator nwOutgoingPackets(String interfaceName) {
+        return nwOutgoingPackets.get(interfaceName);
+    }
+
+    public Map<DeviceId, MetricsAggregator> inboundPacket() {
+        return ImmutableMap.copyOf(inboundPacket);
+    }
+
+    public Map<DeviceId, MetricsAggregator> outboundPacket() {
+        return ImmutableMap.copyOf(outboundPacket);
+    }
+
+    public Map<DeviceId, MetricsAggregator> flowmodPacket() {
+        return ImmutableMap.copyOf(flowmodPacket);
+    }
+
+    public Map<DeviceId, MetricsAggregator> flowrmvPacket() {
+        return ImmutableMap.copyOf(flowrmvPacket);
+    }
+
+    public Map<DeviceId, MetricsAggregator> requestPacket() {
+        return ImmutableMap.copyOf(requestPacket);
+    }
+
+    public Map<DeviceId, MetricsAggregator> replyPacket() {
+        return ImmutableMap.copyOf(replyPacket);
+    }
+
+    public MetricsAggregator inboundPacket(DeviceId deviceId) {
+        return inboundPacket.get(deviceId);
+    }
+
+    public MetricsAggregator outboundPacket(DeviceId deviceId) {
+        return outboundPacket.get(deviceId);
+    }
+
+    public MetricsAggregator flowmodPacket(DeviceId deviceId) {
+        return flowmodPacket.get(deviceId);
+    }
+
+    public MetricsAggregator flowrmvPacket(DeviceId deviceId) {
+        return flowrmvPacket.get(deviceId);
+    }
+
+    public MetricsAggregator requestPacket(DeviceId deviceId) {
+        return requestPacket.get(deviceId);
+    }
+
+    public MetricsAggregator replyPacket(DeviceId deviceId) {
+        return replyPacket.get(deviceId);
+    }
+}
\ No newline at end of file
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsObserver.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsObserver.java
new file mode 100644
index 0000000..fb0bf8b
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsObserver.java
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ * 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.net.DeviceId;
+
+import java.util.Optional;
+
+/**
+ * Control metrics observer interface.
+ */
+public interface ControlMetricsObserver {
+
+    /**
+     * Feeds the extracted value from MetricAggregator to back-end storage.
+     *
+     * @param metricsAggregator metric aggregator
+     * @param deviceId          device id {@link org.onosproject.net.DeviceId}
+     */
+    void feedMetrics(MetricsAggregator metricsAggregator, Optional<DeviceId> deviceId);
+
+    /**
+     * Feeds the extracted value from MetricAggregator to back-end storage.
+     *
+     * @param metricsAggregator metric aggregator
+     * @param resourceName      resource name
+     */
+    void feedMetrics(MetricsAggregator metricsAggregator, String resourceName);
+}
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
new file mode 100644
index 0000000..a80f43c
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlMetricsSystemSpec.java
@@ -0,0 +1,132 @@
+/*
+ * 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/ControlPlaneManager.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlPlaneManager.java
new file mode 100644
index 0000000..ef11466
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlPlaneManager.java
@@ -0,0 +1,57 @@
+/*
+ * 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.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.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.core.ApplicationId;
+import org.onosproject.core.CoreService;
+import org.onosproject.net.device.DeviceService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Skeletal control plane management component.
+ */
+@Component(immediate = true)
+public class ControlPlaneManager {
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected CoreService coreService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected DeviceService deviceService;
+
+    private ApplicationId appId;
+
+    @Activate
+    protected void activate() {
+        appId = coreService.registerApplication("org.onosproject.cpman");
+        deviceService.getAvailableDevices();
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        log.info("Stopped");
+    }
+
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..e1cbdad
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/ControlPlaneMonitor.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ * 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.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.Service;
+import org.onosproject.cluster.NodeId;
+import org.onosproject.cpman.ControlLoad;
+import org.onosproject.cpman.ControlMetric;
+import org.onosproject.cpman.ControlMetricType;
+import org.onosproject.cpman.ControlPlaneMonitorService;
+import org.onosproject.net.DeviceId;
+import org.slf4j.Logger;
+
+import java.util.Optional;
+import java.util.concurrent.TimeUnit;
+
+import static org.slf4j.LoggerFactory.getLogger;
+
+/**
+ * Control plane monitoring service class.
+ */
+@Component(immediate = true)
+@Service
+public class ControlPlaneMonitor implements ControlPlaneMonitorService {
+
+    private final Logger log = getLogger(getClass());
+
+    @Activate
+    public void activate() {
+
+    }
+
+    @Deactivate
+    public void deactivate() {
+    }
+
+    @Override
+    public void updateMetric(ControlMetric cpm, Integer updateInterval,
+                             Optional<DeviceId> deviceId) {
+    }
+
+    @Override
+    public void updateMetric(ControlMetric controlMetric, Integer updateInterval,
+                             String resourceName) {
+
+    }
+
+    @Override
+    public ControlLoad getLoad(NodeId nodeId, ControlMetricType type,
+                               Optional<DeviceId> deviceId) {
+        return null;
+    }
+
+    @Override
+    public ControlLoad getLoad(NodeId nodeId, ControlMetricType type,
+                               Optional<DeviceId> deviceId, int duration, TimeUnit unit) {
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/DefaultControlMetricsObserver.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/DefaultControlMetricsObserver.java
new file mode 100644
index 0000000..9af5ded
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/DefaultControlMetricsObserver.java
@@ -0,0 +1,56 @@
+/*
+ * 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.
+ * 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.apache.felix.scr.annotations.Reference;
+import org.apache.felix.scr.annotations.ReferenceCardinality;
+import org.onosproject.cpman.ControlMetric;
+import org.onosproject.cpman.ControlPlaneMonitorService;
+import org.onosproject.cpman.MetricValue;
+import org.onosproject.net.DeviceId;
+
+import java.util.Optional;
+
+/**
+ * Default ControlMetricsObserver.
+ */
+public class DefaultControlMetricsObserver implements ControlMetricsObserver {
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ControlPlaneMonitorService controlPlaneMonitorService;
+
+    @Override
+    public void feedMetrics(MetricsAggregator ma, Optional<DeviceId> deviceId) {
+        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.Builder()
+                        .rate(ma.getRate())
+                        .count(ma.getCount())
+                        .load(ma.getLoad())
+                        .add();
+        ControlMetric cm = new ControlMetric(ma.getMetricsType(), mv);
+        controlPlaneMonitorService.updateMetric(cm, 1, resourceName);
+    }
+}
\ No newline at end of file
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/MetricsAggregator.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/MetricsAggregator.java
new file mode 100644
index 0000000..8426cb7
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/MetricsAggregator.java
@@ -0,0 +1,159 @@
+/*
+ * 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.
+ * 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 com.codahale.metrics.Meter;
+import org.apache.commons.lang3.StringUtils;
+import org.onlab.metrics.MetricsComponent;
+import org.onlab.metrics.MetricsFeature;
+import org.onlab.metrics.MetricsService;
+import org.onosproject.cpman.ControlMetricType;
+import org.onosproject.net.DeviceId;
+
+import java.util.Optional;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+/**
+ * An aggregator that aggregates a specific network or performance metrics via the metrics service.
+ */
+public class MetricsAggregator {
+
+    private Meter rateMeter;
+    private Meter countMeter;
+    private MetricsService metricsService;
+    private MetricsComponent metricsComponent;
+    private MetricsFeature metricsFeature;
+    private ControlMetricType metricsType;
+    private static final int EXECUTE_PERIOD_IN_SECOND = 60;
+    private static final String RATE_NAME = "rate";
+    private static final String COUNT_NAME = "count";
+
+    /**
+     * Constructs a new MetricsAggregator for aggregating a metric.
+     * Instantiates the metrics service
+     * Initializes all the general metrics for that object
+     *
+     * @param metricsService MetricsService reference
+     * @param type           Control metric type
+     * @param deviceId       DeviceId
+     */
+    MetricsAggregator(MetricsService metricsService, ControlMetricType type,
+                      Optional<DeviceId> deviceId) {
+        init(metricsService, type, deviceId, null);
+    }
+
+    /**
+     * Constructs a new MetricAggregator for aggregating a metric.
+     * Instantiates the metrics service
+     * Initializes all the general metrics for that object
+     *
+     * @param metricsService MetricsService reference
+     * @param type           Control metric type
+     * @param resourceName   resource name (e.g., ethernet interface name)
+     */
+    MetricsAggregator(MetricsService metricsService, ControlMetricType type,
+                      String resourceName) {
+        init(metricsService, type, Optional.ofNullable(null), resourceName);
+
+    }
+
+    /**
+     * Constructs a new MetricAggregator for aggregating a metric.
+     * Instantiates the metrics service
+     * Initializes all the general metrics for that object
+     *
+     * @param metricsService MetricsService reference
+     * @param type           Control metric type
+     */
+    MetricsAggregator(MetricsService metricsService, ControlMetricType type) {
+        init(metricsService, type, Optional.ofNullable(null), null);
+    }
+
+    /**
+     * Base method of the constructor of this class.
+     *
+     * @param metricsService MetricsService reference
+     * @param type           Control metric type
+     * @param deviceId       DeviceId
+     * @param resourceName   resource name
+     */
+    private void init(MetricsService metricsService, ControlMetricType type,
+                      Optional<DeviceId> deviceId, String resourceName) {
+        String primitiveName = type.toString();
+        String objName = "all";
+        if (deviceId.isPresent()) {
+            objName = deviceId.toString();
+        }
+
+        if (StringUtils.isNotEmpty(resourceName)) {
+            objName = resourceName;
+        }
+
+        checkNotNull(primitiveName, "Component name cannot be null");
+        checkNotNull(objName, "Feature name cannot be null");
+
+        this.metricsType = type;
+
+        this.metricsService = metricsService;
+        this.metricsComponent = metricsService.registerComponent(primitiveName);
+        this.metricsFeature = metricsComponent.registerFeature(objName);
+
+        this.rateMeter = metricsService.createMeter(metricsComponent, metricsFeature, RATE_NAME);
+        this.countMeter = metricsService.createMeter(metricsComponent, metricsFeature, COUNT_NAME);
+    }
+
+    public ControlMetricType getMetricsType() {
+        return metricsType;
+    }
+
+    /**
+     * Increments the meter rate by {@code n}, and the meter counter by 1.
+     *
+     * @param n Increment the meter rate by {@code n}.
+     */
+    public void increment(long n) {
+        rateMeter.mark(n);
+        countMeter.mark(1);
+    }
+
+    /**
+     * Obtains the average load value.
+     *
+     * @return load value
+     */
+    public long getLoad() {
+        return (long) rateMeter.getOneMinuteRate() / (long) countMeter.getOneMinuteRate();
+    }
+
+    /**
+     * Obtains the average meter rate within recent 1 minute.
+     *
+     * @return rate value
+     */
+    public long getRate() {
+        return (long) rateMeter.getOneMinuteRate();
+    }
+
+    /**
+     * Obtains the average meter count within recent 1 minute.
+     *
+     * @return count value
+     */
+    public long getCount() {
+        return (long) countMeter.getOneMinuteRate() * EXECUTE_PERIOD_IN_SECOND;
+    }
+}
\ No newline at end of file
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/package-info.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/package-info.java
new file mode 100644
index 0000000..c71d13f
--- /dev/null
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015 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.
+ */
+
+/**
+ * Implementation for control plane management.
+ */
+package org.onosproject.cpman.impl;
\ No newline at end of file
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/CPManWebApplication.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/CPManWebApplication.java
new file mode 100644
index 0000000..26566f8
--- /dev/null
+++ b/apps/cpman/app/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/app/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/ControlMetricsCollectorWebResource.java
new file mode 100644
index 0000000..494b99f
--- /dev/null
+++ b/apps/cpman/app/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.impl.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/app/src/main/java/org/onosproject/cpman/rest/package-info.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/rest/package-info.java
new file mode 100644
index 0000000..cf3baaa
--- /dev/null
+++ b/apps/cpman/app/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/app/src/main/resources/definitions/CpuMetricsPost.json b/apps/cpman/app/src/main/resources/definitions/CpuMetricsPost.json
new file mode 100644
index 0000000..9f52429
--- /dev/null
+++ b/apps/cpman/app/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/app/src/main/resources/definitions/DiskMetricsPost.json b/apps/cpman/app/src/main/resources/definitions/DiskMetricsPost.json
new file mode 100644
index 0000000..fe0dab1
--- /dev/null
+++ b/apps/cpman/app/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/app/src/main/resources/definitions/MemoryMetricsPost.json b/apps/cpman/app/src/main/resources/definitions/MemoryMetricsPost.json
new file mode 100644
index 0000000..ab815da
--- /dev/null
+++ b/apps/cpman/app/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/app/src/main/resources/definitions/NetworkMetricsPost.json b/apps/cpman/app/src/main/resources/definitions/NetworkMetricsPost.json
new file mode 100644
index 0000000..f9ad7d3
--- /dev/null
+++ b/apps/cpman/app/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/app/src/main/resources/definitions/SystemSpecsPost.json b/apps/cpman/app/src/main/resources/definitions/SystemSpecsPost.json
new file mode 100644
index 0000000..fc4fc16
--- /dev/null
+++ b/apps/cpman/app/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/app/src/main/webapp/WEB-INF/web.xml b/apps/cpman/app/src/main/webapp/WEB-INF/web.xml
new file mode 100644
index 0000000..a1be00b
--- /dev/null
+++ b/apps/cpman/app/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>