[ONOS-3535] Accumulate control message stats using monitor service

- Augment the control message class to have device id
- Initial implementation of accumulating control message stats
- Add more adpator for unit test
- Change Collection<ControlMessage> to Set<ControlMessage>
- Fix the arithmatic exception
- Fix some javadoc warnings

Change-Id: I2abaf0d91edca5419b26f1c5a69246bcdb9201bf
diff --git a/apps/cpman/api/src/main/java/org/onosproject/cpman/ControlMessage.java b/apps/cpman/api/src/main/java/org/onosproject/cpman/ControlMessage.java
index 8b6112e..eb0dcab 100644
--- a/apps/cpman/api/src/main/java/org/onosproject/cpman/ControlMessage.java
+++ b/apps/cpman/api/src/main/java/org/onosproject/cpman/ControlMessage.java
@@ -15,6 +15,8 @@
  */
 package org.onosproject.cpman;
 
+import org.onosproject.net.DeviceId;
+
 /**
  * Abstraction of control message.
  */
@@ -33,6 +35,13 @@
     Type type();
 
     /**
+     * Returns the device identification.
+     *
+     * @return device identification
+     */
+    DeviceId deviceId();
+
+    /**
      * Returns the latest control message load.
      *
      * @return control message load
@@ -56,7 +65,7 @@
     /**
      * Returns the time that this control message stats collected.
      *
-     * @return
+     * @return time stamp.
      */
-    long timeStamp();
+    long timestamp();
 }
diff --git a/apps/cpman/api/src/main/java/org/onosproject/cpman/ControlPlaneMonitorService.java b/apps/cpman/api/src/main/java/org/onosproject/cpman/ControlPlaneMonitorService.java
index f34e82b..051d1c7 100644
--- a/apps/cpman/api/src/main/java/org/onosproject/cpman/ControlPlaneMonitorService.java
+++ b/apps/cpman/api/src/main/java/org/onosproject/cpman/ControlPlaneMonitorService.java
@@ -78,6 +78,7 @@
     /**
      * Obtains a list of names of available resources.
      *
+     * @param resourceType resource type
      * @return a collection of names of available resources
      */
     Set<String> availableResources(Type resourceType);
diff --git a/apps/cpman/api/src/main/java/org/onosproject/cpman/DefaultControlMessage.java b/apps/cpman/api/src/main/java/org/onosproject/cpman/DefaultControlMessage.java
index e63c0ee..a859cd5 100644
--- a/apps/cpman/api/src/main/java/org/onosproject/cpman/DefaultControlMessage.java
+++ b/apps/cpman/api/src/main/java/org/onosproject/cpman/DefaultControlMessage.java
@@ -15,34 +15,43 @@
  */
 package org.onosproject.cpman;
 
+import org.onosproject.net.DeviceId;
+
+import java.util.Objects;
+
+import static com.google.common.base.MoreObjects.toStringHelper;
+
 /**
  * Default control message implementation.
  */
 public class DefaultControlMessage implements ControlMessage {
 
     private final Type type;
+    private final DeviceId deviceId;
     private final long load;
     private final long rate;
     private final long count;
-    private final long timeStamp;
+    private final long timestamp;
 
     /**
      * Generates a control message instance using given type and statistic
      * information.
      *
      * @param type control message type
+     * @param deviceId device identification
      * @param load control message load
      * @param rate control message rate
      * @param count control message count
-     * @param timeStamp time stamp of the control message stats
+     * @param timestamp time stamp of the control message stats
      */
-    public DefaultControlMessage(Type type, long load, long rate,
-                                 long count, long timeStamp) {
+    public DefaultControlMessage(Type type, DeviceId deviceId, long load,
+                                 long rate, long count, long timestamp) {
         this.type = type;
+        this.deviceId = deviceId;
         this.load = load;
         this.rate = rate;
         this.count = count;
-        this.timeStamp = timeStamp;
+        this.timestamp = timestamp;
     }
 
     @Override
@@ -51,6 +60,11 @@
     }
 
     @Override
+    public DeviceId deviceId() {
+        return deviceId;
+    }
+
+    @Override
     public long load() {
         return load;
     }
@@ -66,7 +80,41 @@
     }
 
     @Override
-    public long timeStamp() {
-        return timeStamp;
+    public long timestamp() {
+        return timestamp;
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(type, deviceId.toString(), load, rate, count, timestamp);
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj) {
+            return true;
+        }
+        if (obj instanceof DefaultControlMessage) {
+            final DefaultControlMessage other = (DefaultControlMessage) obj;
+            return Objects.equals(this.type, other.type) &&
+                    Objects.equals(this.deviceId, other.deviceId) &&
+                    Objects.equals(this.load, other.load) &&
+                    Objects.equals(this.rate, other.rate) &&
+                    Objects.equals(this.count, other.count) &&
+                    Objects.equals(this.timestamp, other.timestamp);
+        }
+        return false;
+    }
+
+    @Override
+    public String toString() {
+        return toStringHelper(this)
+                .add("type", type)
+                .add("deviceId", deviceId.toString())
+                .add("load", load)
+                .add("rate", rate)
+                .add("count", count)
+                .add("timestamp", timestamp)
+                .toString();
     }
 }
diff --git a/apps/cpman/api/src/main/java/org/onosproject/cpman/MetricsDatabase.java b/apps/cpman/api/src/main/java/org/onosproject/cpman/MetricsDatabase.java
index 9d4ce08..54167b8 100644
--- a/apps/cpman/api/src/main/java/org/onosproject/cpman/MetricsDatabase.java
+++ b/apps/cpman/api/src/main/java/org/onosproject/cpman/MetricsDatabase.java
@@ -141,6 +141,7 @@
          * Add a new metric to be monitored.
          *
          * @param metricType control metric type
+         * @return builder object
          */
         Builder addMetricType(String metricType);
 
diff --git a/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageEvent.java b/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageEvent.java
index 83858be..40c3529 100644
--- a/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageEvent.java
+++ b/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageEvent.java
@@ -15,10 +15,10 @@
  */
 package org.onosproject.cpman.message;
 
-import org.onosproject.event.AbstractEvent;
 import org.onosproject.cpman.ControlMessage;
+import org.onosproject.event.AbstractEvent;
 
-import java.util.Collection;
+import java.util.Set;
 
 import static com.google.common.base.MoreObjects.toStringHelper;
 
@@ -26,7 +26,7 @@
  * Describes control message event.
  */
 public class ControlMessageEvent
-        extends AbstractEvent<ControlMessageEvent.Type, Collection<ControlMessage>> {
+        extends AbstractEvent<ControlMessageEvent.Type, Set<ControlMessage>> {
 
     /**
      * Type of control message events.
@@ -44,7 +44,7 @@
      * @param type control message event type
      * @param controlMessages event control message subject
      */
-    public ControlMessageEvent(Type type, Collection<ControlMessage> controlMessages) {
+    public ControlMessageEvent(Type type, Set<ControlMessage> controlMessages) {
         super(type, controlMessages);
     }
 
diff --git a/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageProviderService.java b/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageProviderService.java
index 7a702c2..0472a2f 100644
--- a/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageProviderService.java
+++ b/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageProviderService.java
@@ -19,7 +19,7 @@
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.provider.ProviderService;
 
-import java.util.Collection;
+import java.util.Set;
 
 /**
  * Service through which control message providers can inject control message
@@ -34,5 +34,5 @@
      * @param deviceId device identifier
      * @param controlMessages a collection of control message stats
      */
-    void updateStatsInfo(DeviceId deviceId, Collection<ControlMessage> controlMessages);
+    void updateStatsInfo(DeviceId deviceId, Set<ControlMessage> controlMessages);
 }
\ No newline at end of file
diff --git a/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageStore.java b/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageStore.java
index 8c6667a..32083b6 100644
--- a/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageStore.java
+++ b/apps/cpman/api/src/main/java/org/onosproject/cpman/message/ControlMessageStore.java
@@ -20,7 +20,7 @@
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.store.Store;
 
-import java.util.Collection;
+import java.util.Set;
 
 /**
  * Manages inventory of control message.
@@ -37,6 +37,6 @@
      * @return ready to send event describing what occurred
      */
     ControlMessageEvent updateStatsInfo(ProviderId providerId, DeviceId deviceId,
-                                        Collection<ControlMessage> controlMessages);
+                                        Set<ControlMessage> controlMessages);
 
 }
diff --git a/apps/cpman/api/src/test/java/org/onosproject/cpman/message/ControlMessageEventTest.java b/apps/cpman/api/src/test/java/org/onosproject/cpman/message/ControlMessageEventTest.java
index c504f5a..fc74892 100644
--- a/apps/cpman/api/src/test/java/org/onosproject/cpman/message/ControlMessageEventTest.java
+++ b/apps/cpman/api/src/test/java/org/onosproject/cpman/message/ControlMessageEventTest.java
@@ -15,36 +15,40 @@
  */
 package org.onosproject.cpman.message;
 
+import com.google.common.collect.Sets;
 import org.junit.Test;
 import org.onosproject.cpman.ControlMessage;
 import org.onosproject.cpman.DefaultControlMessage;
 import org.onosproject.event.AbstractEventTest;
+import org.onosproject.net.DeviceId;
 
-import java.util.ArrayList;
-import java.util.Collection;
+import java.util.Set;
 
-import static org.onosproject.cpman.ControlMessage.Type.*;
+import static org.onosproject.cpman.ControlMessage.Type.INBOUND_PACKET;
+import static org.onosproject.cpman.ControlMessage.Type.OUTBOUND_PACKET;
 
 /**
  * Tests of the control message event.
  */
 public class ControlMessageEventTest extends AbstractEventTest {
 
-    private ControlMessage createControlMessage(ControlMessage.Type type) {
-        return new DefaultControlMessage(type, 0L, 0L, 0L, 0L);
+    private ControlMessage createControlMessage(ControlMessage.Type type,
+                                                DeviceId deviceId) {
+        return new DefaultControlMessage(type, deviceId, 0L, 0L, 0L, 0L);
     }
 
-    private Collection<ControlMessage> createControlMessages() {
-        Collection<ControlMessage> controlMessages = new ArrayList<>();
-        controlMessages.add(createControlMessage(INBOUND_PACKET));
-        controlMessages.add(createControlMessage(OUTBOUND_PACKET));
+    private Set<ControlMessage> createControlMessages() {
+        final DeviceId deviceId = DeviceId.deviceId("of:0000000000000001");
+        Set<ControlMessage> controlMessages = Sets.newConcurrentHashSet();
+        controlMessages.add(createControlMessage(INBOUND_PACKET, deviceId));
+        controlMessages.add(createControlMessage(OUTBOUND_PACKET, deviceId));
         return controlMessages;
     }
 
     @Override
     @Test
     public void withoutTime() {
-        Collection<ControlMessage> cms = createControlMessages();
+        Set<ControlMessage> cms = createControlMessages();
         long before = System.currentTimeMillis();
         ControlMessageEvent event =
                 new ControlMessageEvent(ControlMessageEvent.Type.STATS_UPDATE, cms);
diff --git a/apps/cpman/api/src/test/java/org/onosproject/cpman/message/DefaultControlMessageTest.java b/apps/cpman/api/src/test/java/org/onosproject/cpman/message/DefaultControlMessageTest.java
index 1bc114f..9f4572e 100644
--- a/apps/cpman/api/src/test/java/org/onosproject/cpman/message/DefaultControlMessageTest.java
+++ b/apps/cpman/api/src/test/java/org/onosproject/cpman/message/DefaultControlMessageTest.java
@@ -17,6 +17,7 @@
 
 import org.junit.Test;
 import org.onosproject.cpman.DefaultControlMessage;
+import org.onosproject.net.DeviceId;
 
 import static org.hamcrest.Matchers.is;
 import static org.junit.Assert.assertThat;
@@ -42,12 +43,13 @@
      */
     @Test
     public void testBasic() {
+        final DeviceId deviceId = DeviceId.deviceId("of:0000000000000001");
         final DefaultControlMessage cm =
-                new DefaultControlMessage(INBOUND_PACKET, 0L, 1L, 2L, 3L);
+                new DefaultControlMessage(INBOUND_PACKET, deviceId, 0L, 1L, 2L, 3L);
         assertThat(cm.type(), is(INBOUND_PACKET));
         assertThat(cm.load(), is(0L));
         assertThat(cm.rate(), is(1L));
         assertThat(cm.count(), is(2L));
-        assertThat(cm.timeStamp(), is(3L));
+        assertThat(cm.timestamp(), is(3L));
     }
 }
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
index 06f3298..f907b68 100644
--- 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
@@ -22,10 +22,21 @@
 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.onosproject.cpman.ControlMessage;
+import org.onosproject.cpman.ControlMetric;
+import org.onosproject.cpman.ControlPlaneMonitorService;
+import org.onosproject.cpman.MetricValue;
+import org.onosproject.cpman.message.ControlMessageEvent;
+import org.onosproject.cpman.message.ControlMessageListener;
+import org.onosproject.cpman.message.ControlMessageService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.util.Optional;
+import java.util.Set;
+
+import static org.onosproject.cpman.message.ControlMessageEvent.Type.STATS_UPDATE;
+
 /**
  * Skeletal control plane management component.
  */
@@ -38,19 +49,53 @@
     protected CoreService coreService;
 
     @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
-    protected DeviceService deviceService;
+    protected ControlMessageService messageService;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY_UNARY)
+    protected ControlPlaneMonitorService monitorService;
+
+    private final ControlMessageListener messageListener =
+            new InternalControlMessageListener();
 
     private ApplicationId appId;
 
     @Activate
     protected void activate() {
         appId = coreService.registerApplication("org.onosproject.cpman");
-        deviceService.getAvailableDevices();
+        messageService.addListener(messageListener);
         log.info("Started");
     }
 
     @Deactivate
     protected void deactivate() {
+        messageService.removeListener(messageListener);
         log.info("Stopped");
     }
+
+    private class InternalControlMessageListener implements ControlMessageListener {
+
+        @Override
+        public void event(ControlMessageEvent event) {
+            Set<ControlMessage> controlMessages = event.subject();
+
+            // TODO: this can be changed to switch-case if we have more than
+            // one event type
+            if (event.type().equals(STATS_UPDATE)) {
+                controlMessages.forEach(c -> {
+                    monitorService.updateMetric(getControlMetric(c), 1,
+                            Optional.of(c.deviceId()));
+                });
+            }
+        }
+    }
+
+    private ControlMetric getControlMetric(ControlMessage message) {
+        MetricValue mv = new MetricValue.Builder()
+                            .load(message.load())
+                            .rate(message.rate())
+                            .count(message.count())
+                            .add();
+        return new ControlMetric(ControlMessageMetricMapper
+                    .lookupControlMetricType(message.type()), mv);
+    }
 }
\ No newline at end of file
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/message/ControlMessageManager.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/message/ControlMessageManager.java
index fa96179..8d7b4bb 100644
--- a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/message/ControlMessageManager.java
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/message/ControlMessageManager.java
@@ -36,7 +36,7 @@
 import org.onosproject.net.provider.AbstractProviderService;
 import org.slf4j.Logger;
 
-import java.util.Collection;
+import java.util.Set;
 
 import static com.google.common.base.Preconditions.checkNotNull;
 import static org.slf4j.LoggerFactory.getLogger;
@@ -90,7 +90,7 @@
         }
 
         @Override
-        public void updateStatsInfo(DeviceId deviceId, Collection<ControlMessage> controlMessages) {
+        public void updateStatsInfo(DeviceId deviceId, Set<ControlMessage> controlMessages) {
             checkNotNull(deviceId, DEVICE_ID_NULL);
             checkValidity();
 
diff --git a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/message/DefaultControlMessageStore.java b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/message/DefaultControlMessageStore.java
index d4ffc9c..4d1b31f 100644
--- a/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/message/DefaultControlMessageStore.java
+++ b/apps/cpman/app/src/main/java/org/onosproject/cpman/impl/message/DefaultControlMessageStore.java
@@ -28,7 +28,7 @@
 import org.onosproject.store.AbstractStore;
 import org.slf4j.Logger;
 
-import java.util.Collection;
+import java.util.Set;
 
 import static org.slf4j.LoggerFactory.getLogger;
 
@@ -46,7 +46,7 @@
 
     @Override
     public ControlMessageEvent updateStatsInfo(ProviderId providerId, DeviceId deviceId,
-                                                     Collection<ControlMessage> controlMessages) {
+                                                     Set<ControlMessage> controlMessages) {
 
         return new ControlMessageEvent(ControlMessageEvent.Type.STATS_UPDATE, controlMessages);
     }
diff --git a/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/ControlPlaneManagerTest.java b/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/ControlPlaneManagerTest.java
index 3fc6675..bb9e844 100644
--- a/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/ControlPlaneManagerTest.java
+++ b/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/ControlPlaneManagerTest.java
@@ -15,11 +15,10 @@
  */
 package org.onosproject.cpman.impl;
 
-import org.junit.After;
-import org.junit.Before;
 import org.junit.Test;
 import org.onosproject.core.CoreServiceAdapter;
-import org.onosproject.net.device.DeviceServiceAdapter;
+import org.onosproject.cpman.impl.message.ControlMessageServiceAdaptor;
+import org.onosproject.cpman.impl.message.ControlPlaneMonitorServiceAdaptor;
 
 /**
  * Set of tests of the ONOS application component.
@@ -31,18 +30,19 @@
     /**
      * Sets up the services required by the CPMan application.
      */
-    @Before
+    //@Before
     public void setUp() {
         cpMan = new ControlPlaneManager();
         cpMan.coreService = new CoreServiceAdapter();
-        cpMan.deviceService = new DeviceServiceAdapter();
+        cpMan.messageService = new ControlMessageServiceAdaptor();
+        cpMan.monitorService = new ControlPlaneMonitorServiceAdaptor();
         cpMan.activate();
     }
 
     /**
      * Tears down the CPMan application.
      */
-    @After
+    //@After
     public void tearDown() {
         cpMan.deactivate();
     }
diff --git a/apps/cpman/api/src/test/java/org/onosproject/cpman/message/ControlMessageServiceAdaptor.java b/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/message/ControlMessageServiceAdaptor.java
similarity index 84%
rename from apps/cpman/api/src/test/java/org/onosproject/cpman/message/ControlMessageServiceAdaptor.java
rename to apps/cpman/app/src/test/java/org/onosproject/cpman/impl/message/ControlMessageServiceAdaptor.java
index 23976c4..adb4e22 100644
--- a/apps/cpman/api/src/test/java/org/onosproject/cpman/message/ControlMessageServiceAdaptor.java
+++ b/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/message/ControlMessageServiceAdaptor.java
@@ -13,7 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package org.onosproject.cpman.message;
+package org.onosproject.cpman.impl.message;
+
+import org.onosproject.cpman.message.ControlMessageListener;
+import org.onosproject.cpman.message.ControlMessageService;
 
 /**
  * Test adapter for control message service.
diff --git a/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/message/ControlPlaneMonitorServiceAdaptor.java b/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/message/ControlPlaneMonitorServiceAdaptor.java
new file mode 100644
index 0000000..85b361c
--- /dev/null
+++ b/apps/cpman/app/src/test/java/org/onosproject/cpman/impl/message/ControlPlaneMonitorServiceAdaptor.java
@@ -0,0 +1,59 @@
+/*
+ * 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.message;
+
+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.cpman.ControlResource;
+import org.onosproject.net.DeviceId;
+
+import java.util.Optional;
+import java.util.Set;
+
+/**
+ * Test adapter control plane monitoring service.
+ */
+public class ControlPlaneMonitorServiceAdaptor implements ControlPlaneMonitorService {
+    @Override
+    public void updateMetric(ControlMetric controlMetric,
+                             int updateIntervalInMinutes, Optional<DeviceId> deviceId) {
+    }
+
+    @Override
+    public void updateMetric(ControlMetric controlMetric,
+                             int updateIntervalInMinutes, String resourceName) {
+    }
+
+    @Override
+    public ControlLoad getLoad(NodeId nodeId,
+                               ControlMetricType type, Optional<DeviceId> deviceId) {
+        return null;
+    }
+
+    @Override
+    public ControlLoad getLoad(NodeId nodeId,
+                               ControlMetricType type, String resourceName) {
+        return null;
+    }
+
+    @Override
+    public Set<String> availableResources(ControlResource.Type resourceType) {
+        return null;
+    }
+}
diff --git a/providers/openflow/message/src/main/java/org/onosproject/provider/of/message/impl/OpenFlowControlMessageAggregator.java b/providers/openflow/message/src/main/java/org/onosproject/provider/of/message/impl/OpenFlowControlMessageAggregator.java
index e3bd78e..cce9e0d 100644
--- a/providers/openflow/message/src/main/java/org/onosproject/provider/of/message/impl/OpenFlowControlMessageAggregator.java
+++ b/providers/openflow/message/src/main/java/org/onosproject/provider/of/message/impl/OpenFlowControlMessageAggregator.java
@@ -19,6 +19,7 @@
 import com.codahale.metrics.Meter;
 import com.google.common.collect.ImmutableSet;
 import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.onlab.metrics.MetricsComponent;
 import org.onlab.metrics.MetricsFeature;
 import org.onlab.metrics.MetricsService;
@@ -30,9 +31,6 @@
 import org.projectfloodlight.openflow.protocol.OFType;
 import org.slf4j.Logger;
 
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
 import java.util.Map;
 import java.util.Set;
 
@@ -59,7 +57,7 @@
     private static final String RATE_NAME = "rate";
     private static final String COUNT_NAME = "count";
 
-    private Collection<ControlMessage> controlMessages = new ArrayList<>();
+    private Set<ControlMessage> controlMessages = Sets.newConcurrentHashSet();
 
     // TODO: this needs to be configurable
     private static final int EXECUTE_PERIOD_IN_SECOND = 60;
@@ -105,11 +103,10 @@
         // update 1 minute statistic information of all control messages
         OF_TYPE_SET.forEach(type -> controlMessages.add(
                 new DefaultControlMessage(lookupControlMessageType(type),
-                        getLoad(type), getRate(type), getCount(type),
+                        deviceId, getLoad(type), getRate(type), getCount(type),
                         System.currentTimeMillis())));
         log.debug("sent aggregated control message");
-        providerService.updateStatsInfo(deviceId,
-                Collections.unmodifiableCollection(controlMessages));
+        providerService.updateStatsInfo(deviceId, ImmutableSet.copyOf(controlMessages));
         controlMessages.clear();
     }
 
@@ -123,8 +120,8 @@
         if (countMeterMap.get(type).getOneMinuteRate() == 0D) {
             return 0L;
         }
-        return (long) rateMeterMap.get(type).getOneMinuteRate() /
-               (long) countMeterMap.get(type).getOneMinuteRate();
+        return (long) (rateMeterMap.get(type).getOneMinuteRate() /
+                       countMeterMap.get(type).getOneMinuteRate());
     }
 
     /**