Refactor the logic on collecting OpenFlow message statistics

Change-Id: I34c209c0ca90cb094ed5f82c96a8a43d3519b807
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowController.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowController.java
index c516055..df85811 100644
--- a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowController.java
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowController.java
@@ -65,13 +65,6 @@
     OpenFlowSwitch getEqualSwitch(Dpid dpid);
 
     /**
-     * If this set to be true, all incoming events are monitored.
-     * Other wise, only stats related incoming events are monitored
-     * @param monitor monitoring flag
-     */
-    void monitorAllEvents(boolean monitor);
-
-    /**
      * Register a listener for meta events that occur to OF
      * devices.
      * @param listener the listener to notify
@@ -86,6 +79,20 @@
     void removeListener(OpenFlowSwitchListener listener);
 
     /**
+     * Register a listener for all OF msg types.
+     *
+     * @param listener the listener to notify
+     */
+    void addMessageListener(OpenFlowMessageListener listener);
+
+    /**
+     * Unregister a listener for all OF msg types.
+     *
+     * @param listener the listener to notify
+     */
+    void removeMessageListener(OpenFlowMessageListener listener);
+
+    /**
      * Register a listener for packet events.
      * @param priority the importance of this listener, lower values are more important
      * @param listener the listener to notify
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowMessageListener.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowMessageListener.java
new file mode 100644
index 0000000..1442e06
--- /dev/null
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowMessageListener.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2016-present 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.openflow.controller;
+
+import org.projectfloodlight.openflow.protocol.OFMessage;
+
+import java.util.List;
+
+/**
+ * Notifies providers about all OpenFlow messages.
+ */
+public interface OpenFlowMessageListener {
+
+    /**
+     * Handles all incoming OpenFlow messages.
+     *
+     * @param dpid the switch where the message generated
+     * @param msg raw OpenFlow message
+     */
+    void handleIncomingMessage(Dpid dpid, OFMessage msg);
+
+    /**
+     * Handles all outgoing OpenFlow messages.
+     *
+     * @param dpid the switch where the message to be sent
+     * @param msgs a collection of raw OpenFlow message
+     */
+    void handleOutgoingMessage(Dpid dpid, List<OFMessage> msgs);
+}
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java
index 0b11f9c..206ffad 100644
--- a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/OpenFlowSwitch.java
@@ -157,18 +157,4 @@
      * @return string representation of the connection to the device
      */
     String channelId();
-
-    /**
-     * Registers a listener for OF msg events.
-     *
-     * @param listener the listener to notify
-     */
-    void addEventListener(OpenFlowEventListener listener);
-
-    /**
-     * Unregisters a listener.
-     *
-     * @param listener the listener to unregister
-     */
-    void removeEventListener(OpenFlowEventListener listener);
 }
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
index c3d6f44..465dd06 100644
--- a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitch.java
@@ -22,7 +22,6 @@
 import org.onosproject.net.Device;
 import org.onosproject.net.driver.AbstractHandlerBehaviour;
 import org.onosproject.openflow.controller.Dpid;
-import org.onosproject.openflow.controller.OpenFlowEventListener;
 import org.onosproject.openflow.controller.RoleState;
 import org.projectfloodlight.openflow.protocol.OFDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFErrorMsg;
@@ -37,7 +36,6 @@
 import org.projectfloodlight.openflow.protocol.OFPortStatus;
 import org.projectfloodlight.openflow.protocol.OFRoleReply;
 import org.projectfloodlight.openflow.protocol.OFRoleRequest;
-import org.projectfloodlight.openflow.protocol.OFType;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -48,16 +46,10 @@
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
-import java.util.concurrent.CopyOnWriteArraySet;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.atomic.AtomicReference;
 import java.util.stream.Collectors;
 
-import static org.onlab.util.Tools.groupedThreads;
-
 /**
  * An abstract representation of an OpenFlow switch. Can be extended by others
  * to serve as a base for their vendor specific representation of a switch.
@@ -90,11 +82,6 @@
     protected OFFeaturesReply features;
     protected OFDescStatsReply desc;
 
-    protected Set<OpenFlowEventListener> ofOutgoingMsgListener = new CopyOnWriteArraySet<>();
-
-    protected ExecutorService executorMsgs =
-            Executors.newCachedThreadPool(groupedThreads("onos/of", "event-outgoing-msg-stats-%d", log));
-
     // messagesPendingMastership is used as synchronization variable for
     // all mastership related changes. In this block, mastership (including
     // role update) will have either occurred or not.
@@ -133,9 +120,9 @@
            a synchronization primitive, because the message would have just been
            dropped anyway.
         */
+
         if (role == RoleState.MASTER) {
             // fast path send when we are master
-
             sendMsgsOnChannel(msgs);
             return;
         }
@@ -166,23 +153,10 @@
         }
     }
 
-    private void countOutgoingMsg(List<OFMessage> msgs) {
-        // listen to outgoing control messages only if listeners are registered
-        if (ofOutgoingMsgListener.size() != 0) {
-            msgs.forEach(m -> {
-                if (m.getType() == OFType.PACKET_OUT ||
-                        m.getType() == OFType.FLOW_MOD ||
-                        m.getType() == OFType.STATS_REQUEST) {
-                    executorMsgs.execute(new OFMessageHandler(dpid, m));
-                }
-            });
-        }
-    }
-
     private void sendMsgsOnChannel(List<OFMessage> msgs) {
         if (channel.isConnected()) {
             channel.write(msgs);
-            countOutgoingMsg(msgs);
+            agent.processDownstreamMessage(dpid, msgs);
         } else {
             log.warn("Dropping messages for switch {} because channel is not connected: {}",
                      dpid, msgs);
@@ -335,16 +309,6 @@
     }
 
     @Override
-    public void addEventListener(OpenFlowEventListener listener) {
-        ofOutgoingMsgListener.add(listener);
-    }
-
-    @Override
-    public void removeEventListener(OpenFlowEventListener listener) {
-        ofOutgoingMsgListener.remove(listener);
-    }
-
-    @Override
     public OFFactory factory() {
         return OFFactories.getFactory(ofVersion);
     }
@@ -535,25 +499,4 @@
                 ? channel.getRemoteAddress() : "?")
                 + " DPID[" + ((getStringId() != null) ? getStringId() : "?") + "]]";
     }
-
-    /**
-     * OpenFlow message handler for outgoing control messages.
-     */
-    protected final class OFMessageHandler implements Runnable {
-
-        protected final OFMessage msg;
-        protected final Dpid dpid;
-
-        public OFMessageHandler(Dpid dpid, OFMessage msg) {
-            this.msg = msg;
-            this.dpid = dpid;
-        }
-
-        @Override
-        public void run() {
-            for (OpenFlowEventListener listener : ofOutgoingMsgListener) {
-                listener.handleMessage(dpid, msg);
-            }
-        }
-    }
 }
diff --git a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowAgent.java b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowAgent.java
index 6f918e8..964c79a 100644
--- a/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowAgent.java
+++ b/protocols/openflow/api/src/main/java/org/onosproject/openflow/controller/driver/OpenFlowAgent.java
@@ -20,6 +20,8 @@
 import org.onosproject.openflow.controller.RoleState;
 import org.projectfloodlight.openflow.protocol.OFMessage;
 
+import java.util.List;
+
 /**
  * Responsible for keeping track of the current set of switches
  * connected to the system. As well as whether they are in Master
@@ -84,6 +86,14 @@
     void removeConnectedSwitch(Dpid dpid);
 
     /**
+     * Notify OpenFlow message listeners on all outgoing message event.
+     *
+     * @param dpid the dpid the message sent to
+     * @param m the collection of messages to sent out
+     */
+    void processDownstreamMessage(Dpid dpid, List<OFMessage> m);
+
+    /**
      * Process a message coming from a switch.
      *
      * @param dpid the dpid the message came on.
diff --git a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/OpenflowControllerAdapter.java b/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/OpenflowControllerAdapter.java
index 8900d9d..20e2aed 100644
--- a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/OpenflowControllerAdapter.java
+++ b/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/OpenflowControllerAdapter.java
@@ -52,10 +52,6 @@
     }
 
     @Override
-    public void monitorAllEvents(boolean monitor) {
-    }
-
-    @Override
     public void addListener(OpenFlowSwitchListener listener) {
     }
 
@@ -64,6 +60,16 @@
     }
 
     @Override
+    public void addMessageListener(OpenFlowMessageListener listener) {
+
+    }
+
+    @Override
+    public void removeMessageListener(OpenFlowMessageListener listener) {
+
+    }
+
+    @Override
     public void addPacketListener(int priority, PacketListener listener) {
     }
 
diff --git a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitchTest.java b/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitchTest.java
deleted file mode 100644
index f726e50..0000000
--- a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/AbstractOpenFlowSwitchTest.java
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- * Copyright 2015-present 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.openflow.controller.driver;
-
-import org.jboss.netty.channel.Channel;
-import org.jboss.netty.channel.ChannelConfig;
-import org.jboss.netty.channel.ChannelFactory;
-import org.jboss.netty.channel.ChannelFuture;
-import org.jboss.netty.channel.ChannelPipeline;
-import org.junit.Before;
-import org.junit.Test;
-import org.onosproject.openflow.controller.Dpid;
-import org.onosproject.openflow.controller.OpenFlowEventListener;
-import org.onosproject.openflow.controller.RoleState;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-
-import java.net.SocketAddress;
-import java.util.ArrayList;
-import java.util.List;
-
-import static org.hamcrest.MatcherAssert.assertThat;
-import static org.hamcrest.Matchers.hasSize;
-import static org.hamcrest.Matchers.is;
-
-/**
- * Tests for packet processing in the abstract openflow switch class.
- */
-public class AbstractOpenFlowSwitchTest {
-
-    OpenFlowSwitchImpl ofSwitch;
-    TestExecutorService executorService;
-
-    /**
-     * Mock executor service that tracks submits.
-     */
-    static class TestExecutorService extends ExecutorServiceAdapter {
-        private List<OFMessage> submittedMessages = new ArrayList<>();
-
-        List<OFMessage> submittedMessages() {
-            return submittedMessages;
-        }
-
-        @Override
-        public void execute(Runnable task) {
-            AbstractOpenFlowSwitch.OFMessageHandler handler =
-                    (AbstractOpenFlowSwitch.OFMessageHandler) task;
-            submittedMessages.add(handler.msg);
-        }
-    }
-
-    /**
-     * Sets up switches to use as data.
-     */
-    @Before
-    public void setUp() {
-        ofSwitch = new OpenFlowSwitchImpl();
-
-        executorService = new TestExecutorService();
-        ofSwitch.executorMsgs = executorService;
-        Channel channel = new MockChannel();
-        ofSwitch.setChannel(channel);
-        ofSwitch.role = RoleState.MASTER;
-        ofSwitch.addEventListener(new OpenFlowEventListenerAdapter());
-    }
-
-    /**
-     * Tests a packet out operation.
-     */
-    @Test
-    public void testPacketOut() {
-        OFMessage ofPacketOut = new MockOfPacketOut();
-        ofSwitch.sendMsg(ofPacketOut);
-        assertThat(executorService.submittedMessages(), hasSize(1));
-        assertThat(executorService.submittedMessages().get(0), is(ofPacketOut));
-    }
-
-    /**
-     * Tests a flow mod operation.
-     */
-    @Test
-    public void testFlowMod() {
-        OFMessage ofFlowMod = new MockOfFlowMod();
-        ofSwitch.sendMsg(ofFlowMod);
-        assertThat(executorService.submittedMessages(), hasSize(1));
-        assertThat(executorService.submittedMessages().get(0), is(ofFlowMod));
-    }
-
-    /**
-     * Tests a stats request operation.
-     */
-    @Test
-    public void testStatsRequest() {
-        OFMessage ofStatsRequest = new MockOfStatsRequest();
-        ofSwitch.sendMsg(ofStatsRequest);
-        assertThat(executorService.submittedMessages(), hasSize(1));
-        assertThat(executorService.submittedMessages().get(0), is(ofStatsRequest));
-    }
-
-    protected class OpenFlowSwitchImpl extends AbstractOpenFlowSwitch {
-
-        @Override
-        public Boolean supportNxRole() {
-            return null;
-        }
-
-        @Override
-        public void startDriverHandshake() {
-        }
-
-        @Override
-        public boolean isDriverHandshakeComplete() {
-            return false;
-        }
-
-        @Override
-        public void processDriverHandshakeMessage(OFMessage m) {
-        }
-    }
-
-    private class OpenFlowEventListenerAdapter implements OpenFlowEventListener {
-
-        @Override
-        public void handleMessage(Dpid dpid, OFMessage msg) {
-        }
-    }
-
-    private class MockChannel implements Channel {
-
-        @Override
-        public Integer getId() {
-            return null;
-        }
-
-        @Override
-        public ChannelFactory getFactory() {
-            return null;
-        }
-
-        @Override
-        public Channel getParent() {
-            return null;
-        }
-
-        @Override
-        public ChannelConfig getConfig() {
-            return null;
-        }
-
-        @Override
-        public ChannelPipeline getPipeline() {
-            return null;
-        }
-
-        @Override
-        public boolean isOpen() {
-            return false;
-        }
-
-        @Override
-        public boolean isBound() {
-            return false;
-        }
-
-        @Override
-        public boolean isConnected() {
-            // we assume that the channel is connected
-            return true;
-        }
-
-        @Override
-        public SocketAddress getLocalAddress() {
-            return null;
-        }
-
-        @Override
-        public SocketAddress getRemoteAddress() {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture write(Object message) {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture write(Object message, SocketAddress remoteAddress) {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture bind(SocketAddress localAddress) {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture connect(SocketAddress remoteAddress) {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture disconnect() {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture unbind() {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture close() {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture getCloseFuture() {
-            return null;
-        }
-
-        @Override
-        public int getInterestOps() {
-            return 0;
-        }
-
-        @Override
-        public boolean isReadable() {
-            return false;
-        }
-
-        @Override
-        public boolean isWritable() {
-            return false;
-        }
-
-        @Override
-        public ChannelFuture setInterestOps(int interestOps) {
-            return null;
-        }
-
-        @Override
-        public ChannelFuture setReadable(boolean readable) {
-            return null;
-        }
-
-        @Override
-        public boolean getUserDefinedWritability(int index) {
-            return false;
-        }
-
-        @Override
-        public void setUserDefinedWritability(int index, boolean isWritable) {
-
-        }
-
-        @Override
-        public Object getAttachment() {
-            return null;
-        }
-
-        @Override
-        public void setAttachment(Object attachment) {
-
-        }
-
-        @Override
-        public int compareTo(Channel o) {
-            return 0;
-        }
-    }
-}
diff --git a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/ExecutorServiceAdapter.java b/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/ExecutorServiceAdapter.java
deleted file mode 100644
index a50db99..0000000
--- a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/ExecutorServiceAdapter.java
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * Copyright 2015-present 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.openflow.controller.driver;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Future;
-import java.util.concurrent.TimeUnit;
-import java.util.concurrent.TimeoutException;
-
-/**
- * Test harness adapter for the ExecutorService.
- */
-public class ExecutorServiceAdapter  implements ExecutorService {
-    @Override
-    public void shutdown() {
-
-    }
-
-    @Override
-    public List<Runnable> shutdownNow() {
-        return null;
-    }
-
-    @Override
-    public boolean isShutdown() {
-        return false;
-    }
-
-    @Override
-    public boolean isTerminated() {
-        return false;
-    }
-
-    @Override
-    public boolean awaitTermination(long timeout, TimeUnit unit)
-            throws InterruptedException {
-        return false;
-    }
-
-    @Override
-    public <T> Future<T> submit(Callable<T> task) {
-        return null;
-    }
-
-    @Override
-    public <T> Future<T> submit(Runnable task, T result) {
-        return null;
-    }
-
-    @Override
-    public Future<?> submit(Runnable task) {
-        return null;
-    }
-
-    @Override
-    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
-            throws InterruptedException {
-        return null;
-    }
-
-    @Override
-    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
-            throws InterruptedException {
-        return null;
-    }
-
-    @Override
-    public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws InterruptedException, ExecutionException {
-        return null;
-    }
-
-    @Override
-    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)
-            throws InterruptedException, ExecutionException, TimeoutException {
-        return null;
-    }
-
-    @Override
-    public void execute(Runnable command) {
-
-    }
-}
diff --git a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfFlowMod.java b/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfFlowMod.java
deleted file mode 100644
index 27b356f..0000000
--- a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfFlowMod.java
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright 2015-present 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.openflow.controller.driver;
-
-
-import org.projectfloodlight.openflow.protocol.OFFlowMod;
-import org.projectfloodlight.openflow.protocol.OFFlowModCommand;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.OFFlowModFlags;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.protocol.instruction.OFInstruction;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.types.OFBufferId;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.TableId;
-import org.projectfloodlight.openflow.types.U64;
-import org.projectfloodlight.openflow.types.OFGroup;
-
-import java.util.List;
-import java.util.Set;
-
-/**
- * Mock of the Open Flow flow mod message.
- */
-public class MockOfFlowMod extends OfMessageAdapter implements OFFlowMod {
-
-    public MockOfFlowMod() {
-        super(OFType.FLOW_MOD);
-    }
-
-    @Override
-    public U64 getCookie() {
-        return null;
-    }
-
-    @Override
-    public U64 getCookieMask() throws UnsupportedOperationException {
-        return null;
-    }
-
-    @Override
-    public TableId getTableId() throws UnsupportedOperationException {
-        return null;
-    }
-
-    @Override
-    public OFFlowModCommand getCommand() {
-        return null;
-    }
-
-    @Override
-    public int getIdleTimeout() {
-        return 0;
-    }
-
-    @Override
-    public int getHardTimeout() {
-        return 0;
-    }
-
-    @Override
-    public int getPriority() {
-        return 0;
-    }
-
-    @Override
-    public OFBufferId getBufferId() {
-        return null;
-    }
-
-    @Override
-    public OFPort getOutPort() {
-        return null;
-    }
-
-    @Override
-    public OFGroup getOutGroup() throws UnsupportedOperationException {
-        return null;
-    }
-
-    @Override
-    public Set<OFFlowModFlags> getFlags() {
-        return null;
-    }
-
-    @Override
-    public Match getMatch() {
-        return null;
-    }
-
-    @Override
-    public List<OFInstruction> getInstructions() throws UnsupportedOperationException {
-        return null;
-    }
-
-    @Override
-    public List<OFAction> getActions() throws UnsupportedOperationException {
-        return null;
-    }
-
-    @Override
-    public OFFlowMod.Builder createBuilder() {
-        return null;
-    }
-}
diff --git a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfPacketOut.java b/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfPacketOut.java
deleted file mode 100644
index a945950..0000000
--- a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfPacketOut.java
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2015-present 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.openflow.controller.driver;
-
-import org.projectfloodlight.openflow.protocol.OFPacketOut;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.action.OFAction;
-import org.projectfloodlight.openflow.types.OFBufferId;
-import org.projectfloodlight.openflow.types.OFPort;
-
-import java.util.List;
-
-/**
- * Mock of the Open Flow packet out message.
- */
-public class MockOfPacketOut extends OfMessageAdapter implements OFPacketOut {
-
-    public MockOfPacketOut() {
-        super(OFType.PACKET_OUT);
-    }
-
-    @Override
-    public OFBufferId getBufferId() {
-        return null;
-    }
-
-    @Override
-    public OFPort getInPort() {
-        return null;
-    }
-
-    @Override
-    public List<OFAction> getActions() {
-        return null;
-    }
-
-    @Override
-    public byte[] getData() {
-        return new byte[0];
-    }
-
-    @Override
-    public OFPacketOut.Builder createBuilder() {
-        return null;
-    }
-}
diff --git a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfStatsRequest.java b/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfStatsRequest.java
deleted file mode 100644
index 2eafec8..0000000
--- a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/MockOfStatsRequest.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2015-present 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.openflow.controller.driver;
-
-
-
-import org.projectfloodlight.openflow.protocol.OFStatsRequest;
-import org.projectfloodlight.openflow.protocol.OFStatsType;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.OFStatsReplyFlags;
-
-import java.util.Set;
-
-/**
- * Mock of the Open Flow stats request message.
- */
-public class MockOfStatsRequest extends OfMessageAdapter implements OFStatsRequest {
-
-    public MockOfStatsRequest() {
-        super(OFType.STATS_REQUEST);
-    }
-
-    @Override
-    public OFStatsType getStatsType() {
-        return null;
-    }
-
-    @Override
-    public Set<OFStatsReplyFlags> getFlags() {
-        return null;
-    }
-
-    @Override
-    public OFStatsRequest.Builder createBuilder() {
-        return null;
-    }
-}
diff --git a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/OfMessageAdapter.java b/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/OfMessageAdapter.java
deleted file mode 100644
index df6d855..0000000
--- a/protocols/openflow/api/src/test/java/org/onosproject/openflow/controller/driver/OfMessageAdapter.java
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright 2015-present 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.openflow.controller.driver;
-
-import org.jboss.netty.buffer.ChannelBuffer;
-import org.projectfloodlight.openflow.protocol.OFMessage;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.OFVersion;
-
-import com.google.common.hash.PrimitiveSink;
-
-/**
- * Adapter for testing against an OpenFlow message.
- */
-public class OfMessageAdapter implements OFMessage {
-    OFType type;
-
-    private OfMessageAdapter() {}
-
-    public OfMessageAdapter(OFType type) {
-        this.type = type;
-    }
-
-    @Override
-    public OFType getType() {
-        return type;
-    }
-
-    @Override
-    public OFVersion getVersion() {
-        return null;
-    }
-
-    @Override
-    public long getXid() {
-        return 0;
-    }
-
-    @Override
-    public void writeTo(ChannelBuffer channelBuffer) { }
-
-    @Override
-    public Builder createBuilder() {
-        return null;
-    }
-
-    @Override
-    public void putTo(PrimitiveSink sink) { }
-}
diff --git a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
index ba3eab5..43b91fd 100644
--- a/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
+++ b/protocols/openflow/ctl/src/main/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImpl.java
@@ -34,6 +34,7 @@
 import org.onosproject.openflow.controller.Dpid;
 import org.onosproject.openflow.controller.OpenFlowController;
 import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowMessageListener;
 import org.onosproject.openflow.controller.OpenFlowPacketContext;
 import org.onosproject.openflow.controller.OpenFlowSwitch;
 import org.onosproject.openflow.controller.OpenFlowSwitchListener;
@@ -134,7 +135,7 @@
 
     protected Set<OpenFlowEventListener> ofEventListener = new CopyOnWriteArraySet<>();
 
-    protected boolean monitorAllEvents = false;
+    protected Set<OpenFlowMessageListener> ofMessageListener = new CopyOnWriteArraySet<>();
 
     protected Multimap<Dpid, OFFlowStatsEntry> fullFlowStats =
             ArrayListMultimap.create();
@@ -217,11 +218,6 @@
     }
 
     @Override
-    public void monitorAllEvents(boolean monitor) {
-        this.monitorAllEvents = monitor;
-    }
-
-    @Override
     public void addListener(OpenFlowSwitchListener listener) {
         if (!ofSwitchListener.contains(listener)) {
             this.ofSwitchListener.add(listener);
@@ -234,6 +230,16 @@
     }
 
     @Override
+    public void addMessageListener(OpenFlowMessageListener listener) {
+        ofMessageListener.add(listener);
+    }
+
+    @Override
+    public void removeMessageListener(OpenFlowMessageListener listener) {
+        ofMessageListener.remove(listener);
+    }
+
+    @Override
     public void addPacketListener(int priority, PacketListener listener) {
         ofPacketListener.put(priority, listener);
     }
@@ -625,8 +631,20 @@
         }
 
         @Override
+        public void processDownstreamMessage(Dpid dpid, List<OFMessage> m) {
+            for (OpenFlowMessageListener listener : ofMessageListener) {
+                listener.handleOutgoingMessage(dpid, m);
+            }
+        }
+
+
+        @Override
         public void processMessage(Dpid dpid, OFMessage m) {
             processPacket(dpid, m);
+
+            for (OpenFlowMessageListener listener : ofMessageListener) {
+                listener.handleIncomingMessage(dpid, m);
+            }
         }
 
         @Override
diff --git a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/MockOfPacketIn.java b/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/MockOfPacketIn.java
deleted file mode 100644
index 6763819..0000000
--- a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/MockOfPacketIn.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2015-present 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.openflow;
-
-import org.projectfloodlight.openflow.protocol.OFPacketIn;
-import org.projectfloodlight.openflow.protocol.OFPacketInReason;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.types.OFBufferId;
-import org.projectfloodlight.openflow.types.OFPort;
-import org.projectfloodlight.openflow.types.TableId;
-import org.projectfloodlight.openflow.types.U64;
-
-/**
- * Mock of the Open Flow packet in message.
- */
-public class MockOfPacketIn extends OfMessageAdapter implements OFPacketIn {
-    public MockOfPacketIn() {
-        super(OFType.PACKET_IN);
-    }
-
-    @Override
-    public OFBufferId getBufferId() {
-        return null;
-    }
-
-    @Override
-    public int getTotalLen() {
-        return 0;
-    }
-
-    @Override
-    public OFPacketInReason getReason() {
-        return null;
-    }
-
-    @Override
-    public TableId getTableId() {
-        return null;
-    }
-
-    @Override
-    public Match getMatch() {
-        return null;
-    }
-
-    @Override
-    public byte[] getData() {
-        return new byte[0];
-    }
-
-    @Override
-    public OFPort getInPort() {
-        return null;
-    }
-
-    @Override
-    public OFPort getInPhyPort() {
-        return null;
-    }
-
-    @Override
-    public U64 getCookie() {
-        return null;
-    }
-
-    @Override
-    public OFPacketIn.Builder createBuilder() {
-        return null;
-    }
-}
diff --git a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/OpenflowSwitchDriverAdapter.java b/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/OpenflowSwitchDriverAdapter.java
index 0efd6fa..115c9ea 100644
--- a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/OpenflowSwitchDriverAdapter.java
+++ b/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/OpenflowSwitchDriverAdapter.java
@@ -15,14 +15,11 @@
  */
 package org.onosproject.openflow;
 
-import java.util.List;
-
 import org.jboss.netty.channel.Channel;
 import org.onosproject.net.Device;
 import org.onosproject.net.driver.DriverData;
 import org.onosproject.net.driver.DriverHandler;
 import org.onosproject.openflow.controller.Dpid;
-import org.onosproject.openflow.controller.OpenFlowEventListener;
 import org.onosproject.openflow.controller.RoleState;
 import org.onosproject.openflow.controller.driver.OpenFlowAgent;
 import org.onosproject.openflow.controller.driver.OpenFlowSwitchDriver;
@@ -38,6 +35,8 @@
 import org.projectfloodlight.openflow.protocol.OFPortDescStatsReply;
 import org.projectfloodlight.openflow.protocol.OFVersion;
 
+import java.util.List;
+
 /**
  * Testing adapter for the OpenFlow switch driver class.
  */
@@ -300,12 +299,4 @@
     public String channelId() {
         return null;
     }
-
-    @Override
-    public void addEventListener(OpenFlowEventListener listener) {
-    }
-
-    @Override
-    public void removeEventListener(OpenFlowEventListener listener) {
-    }
 }
diff --git a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/MockOfFlowRemoved.java b/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/MockOfFlowRemoved.java
deleted file mode 100644
index 9aee677..0000000
--- a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/MockOfFlowRemoved.java
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * Copyright 2015-present 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.openflow.controller.impl;
-
-import org.onosproject.openflow.OfMessageAdapter;
-import org.projectfloodlight.openflow.protocol.OFFlowRemoved;
-import org.projectfloodlight.openflow.protocol.OFType;
-import org.projectfloodlight.openflow.protocol.match.Match;
-import org.projectfloodlight.openflow.types.TableId;
-import org.projectfloodlight.openflow.types.U64;
-
-/**
- * Mock of the Open Flow packet removed message.
- */
-public class MockOfFlowRemoved extends OfMessageAdapter implements OFFlowRemoved {
-
-    public MockOfFlowRemoved() {
-        super(OFType.FLOW_REMOVED);
-    }
-
-    @Override
-    public U64 getCookie() {
-        return null;
-    }
-
-    @Override
-    public int getPriority() {
-        return 0;
-    }
-
-    @Override
-    public short getReason() {
-        return 0;
-    }
-
-    @Override
-    public TableId getTableId() throws UnsupportedOperationException {
-        return null;
-    }
-
-    @Override
-    public long getDurationSec() {
-        return 0;
-    }
-
-    @Override
-    public long getDurationNsec() {
-        return 0;
-    }
-
-    @Override
-    public int getIdleTimeout() {
-        return 0;
-    }
-
-    @Override
-    public int getHardTimeout() throws UnsupportedOperationException {
-        return 0;
-    }
-
-    @Override
-    public U64 getPacketCount() {
-        return null;
-    }
-
-    @Override
-    public U64 getByteCount() {
-        return null;
-    }
-
-    @Override
-    public Match getMatch() {
-        return null;
-    }
-
-    @Override
-    public OFFlowRemoved.Builder createBuilder() {
-        return null;
-    }
-}
diff --git a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplPacketsTest.java b/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplPacketsTest.java
index d87913a..54fae4e 100644
--- a/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplPacketsTest.java
+++ b/protocols/openflow/ctl/src/test/java/org/onosproject/openflow/controller/impl/OpenFlowControllerImplPacketsTest.java
@@ -104,7 +104,6 @@
         agent = controller.agent;
         switchListener = new OpenFlowSwitchListenerAdapter();
         controller.addListener(switchListener);
-        controller.monitorAllEvents(true);
 
         packetListener = new TestPacketListener();
         controller.addPacketListener(100, packetListener);
diff --git a/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java b/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
index 02465f1..9dd27a0 100644
--- a/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
+++ b/providers/openflow/device/src/test/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProviderTest.java
@@ -38,6 +38,7 @@
 import org.onosproject.openflow.controller.Dpid;
 import org.onosproject.openflow.controller.OpenFlowController;
 import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowMessageListener;
 import org.onosproject.openflow.controller.OpenFlowSwitch;
 import org.onosproject.openflow.controller.OpenFlowSwitchListener;
 import org.onosproject.openflow.controller.PacketListener;
@@ -275,10 +276,6 @@
         }
 
         @Override
-        public void monitorAllEvents(boolean monitor) {
-        }
-
-        @Override
         public void addListener(OpenFlowSwitchListener listener) {
             this.listener = listener;
         }
@@ -289,6 +286,16 @@
         }
 
         @Override
+        public void addMessageListener(OpenFlowMessageListener listener) {
+
+        }
+
+        @Override
+        public void removeMessageListener(OpenFlowMessageListener listener) {
+
+        }
+
+        @Override
         public void addPacketListener(int priority, PacketListener listener) {
         }
 
@@ -416,14 +423,6 @@
             return "1.2.3.4:1";
         }
 
-        @Override
-        public void addEventListener(OpenFlowEventListener listener) {
-        }
-
-        @Override
-        public void removeEventListener(OpenFlowEventListener listener) {
-        }
-
     }
 
 }
diff --git a/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java b/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
index 0fc3287..ff08f72 100644
--- a/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
+++ b/providers/openflow/group/src/test/java/org/onosproject/provider/of/group/impl/OpenFlowGroupProviderTest.java
@@ -41,6 +41,7 @@
 import org.onosproject.openflow.controller.Dpid;
 import org.onosproject.openflow.controller.OpenFlowController;
 import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowMessageListener;
 import org.onosproject.openflow.controller.OpenFlowSwitch;
 import org.onosproject.openflow.controller.OpenFlowSwitchListener;
 import org.onosproject.openflow.controller.PacketListener;
@@ -225,6 +226,16 @@
         }
 
         @Override
+        public void addMessageListener(OpenFlowMessageListener listener) {
+
+        }
+
+        @Override
+        public void removeMessageListener(OpenFlowMessageListener listener) {
+
+        }
+
+        @Override
         public void addPacketListener(int priority, PacketListener listener) {
 
         }
@@ -288,11 +299,6 @@
         public OpenFlowSwitch getEqualSwitch(Dpid dpid) {
             return null;
         }
-
-        @Override
-        public void monitorAllEvents(boolean monitor) {
-        }
-
     }
 
     private class TestGroupProviderRegistry implements GroupProviderRegistry {
@@ -411,14 +417,5 @@
         public String channelId() {
             return null;
         }
-
-        @Override
-        public void addEventListener(OpenFlowEventListener listener) {
-        }
-
-        @Override
-        public void removeEventListener(OpenFlowEventListener listener) {
-        }
-
     }
 }
\ No newline at end of file
diff --git a/providers/openflow/message/src/main/java/org/onosproject/provider/of/message/impl/OpenFlowControlMessageProvider.java b/providers/openflow/message/src/main/java/org/onosproject/provider/of/message/impl/OpenFlowControlMessageProvider.java
index 42bed2d..a2e21dc 100644
--- a/providers/openflow/message/src/main/java/org/onosproject/provider/of/message/impl/OpenFlowControlMessageProvider.java
+++ b/providers/openflow/message/src/main/java/org/onosproject/provider/of/message/impl/OpenFlowControlMessageProvider.java
@@ -32,7 +32,7 @@
 import org.onosproject.net.provider.ProviderId;
 import org.onosproject.openflow.controller.Dpid;
 import org.onosproject.openflow.controller.OpenFlowController;
-import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowMessageListener;
 import org.onosproject.openflow.controller.OpenFlowSwitch;
 import org.onosproject.openflow.controller.OpenFlowSwitchListener;
 import org.onosproject.openflow.controller.RoleState;
@@ -42,6 +42,7 @@
 import org.slf4j.Logger;
 
 import java.util.HashMap;
+import java.util.List;
 import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.TimeUnit;
 
@@ -71,11 +72,8 @@
 
     private final InternalDeviceProvider listener = new InternalDeviceProvider();
 
-    private final InternalIncomingMessageProvider inMsgListener =
-                    new InternalIncomingMessageProvider();
-
-    private final InternalOutgoingMessageProvider outMsgListener =
-                    new InternalOutgoingMessageProvider();
+    private final InternalControlMessageListener messageListener =
+                    new InternalControlMessageListener();
 
     private HashMap<Dpid, OpenFlowControlMessageAggregator> aggregators = Maps.newHashMap();
     private SharedScheduledExecutorService executor;
@@ -98,12 +96,8 @@
         // listens all OpenFlow device related events
         controller.addListener(listener);
 
-        // listens all OpenFlow incoming message events
-        controller.addEventListener(inMsgListener);
-        controller.monitorAllEvents(true);
-
-        // listens all OpenFlow outgoing message events
-        controller.getSwitches().forEach(sw -> sw.addEventListener(outMsgListener));
+        // listens all OpenFlow control message
+        controller.addMessageListener(messageListener);
 
         executor = SharedScheduledExecutors.getSingleThreadExecutor();
 
@@ -117,12 +111,8 @@
         providerRegistry.unregister(this);
         providerService = null;
 
-        // stops listening all OpenFlow incoming message events
-        controller.monitorAllEvents(false);
-        controller.removeEventListener(inMsgListener);
-
-        // stops listening all OpenFlow outgoing message events
-        controller.getSwitches().forEach(sw -> sw.removeEventListener(outMsgListener));
+        // stops listening all OpenFlow control message events
+        controller.removeMessageListener(messageListener);
 
         log.info("Stopped");
     }
@@ -149,12 +139,6 @@
                 return;
             }
 
-            OpenFlowSwitch sw = controller.getSwitch(dpid);
-            if (sw != null) {
-                // start to monitor the outgoing control messages
-                sw.addEventListener(outMsgListener);
-            }
-
             DeviceId deviceId = deviceId(uri(dpid));
             OpenFlowControlMessageAggregator ofcma =
                     new OpenFlowControlMessageAggregator(metricsService,
@@ -171,12 +155,6 @@
                 return;
             }
 
-            OpenFlowSwitch sw = controller.getSwitch(dpid);
-            if (sw != null) {
-                // stop monitoring the outgoing control messages
-                sw.removeEventListener(outMsgListener);
-            }
-
             // removes the aggregator when switch is removed
             // this also stops the aggregator from running
             OpenFlowControlMessageAggregator aggregator = aggregators.remove(dpid);
@@ -200,12 +178,12 @@
     }
 
     /**
-     * A listener for incoming OpenFlow messages.
+     * A listener for all OpenFlow control messages.
      */
-    private class InternalIncomingMessageProvider implements OpenFlowEventListener {
+    private class InternalControlMessageListener implements OpenFlowMessageListener {
 
         @Override
-        public void handleMessage(Dpid dpid, OFMessage msg) {
+        public void handleIncomingMessage(Dpid dpid, OFMessage msg) {
             if (msg.getType() == OFType.PACKET_IN ||
                     msg.getType() == OFType.FLOW_MOD ||
                     msg.getType() == OFType.STATS_REPLY) {
@@ -215,19 +193,19 @@
                 });
             }
         }
-    }
-
-    /**
-     * A listener for outgoing OpenFlow messages.
-     */
-    private class InternalOutgoingMessageProvider implements OpenFlowEventListener {
 
         @Override
-        public void handleMessage(Dpid dpid, OFMessage msg) {
-            aggregators.computeIfPresent(dpid, (k, v) -> {
-                v.increment(msg);
-                return v;
-            });
+        public void handleOutgoingMessage(Dpid dpid, List<OFMessage> msgs) {
+            for (OFMessage msg : msgs) {
+                if (msg.getType() == OFType.PACKET_OUT ||
+                        msg.getType() == OFType.FLOW_MOD ||
+                        msg.getType() == OFType.STATS_REQUEST) {
+                    aggregators.computeIfPresent(dpid, (k, v) -> {
+                        v.increment(msg);
+                        return v;
+                    });
+                }
+            }
         }
     }
 }
diff --git a/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java b/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java
index ebc8cc7..1b4fe93 100644
--- a/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java
+++ b/providers/openflow/packet/src/test/java/org/onosproject/provider/of/packet/impl/OpenFlowPacketProviderTest.java
@@ -40,6 +40,7 @@
 import org.onosproject.openflow.controller.Dpid;
 import org.onosproject.openflow.controller.OpenFlowController;
 import org.onosproject.openflow.controller.OpenFlowEventListener;
+import org.onosproject.openflow.controller.OpenFlowMessageListener;
 import org.onosproject.openflow.controller.OpenFlowPacketContext;
 import org.onosproject.openflow.controller.OpenFlowSwitch;
 import org.onosproject.openflow.controller.OpenFlowSwitchListener;
@@ -287,10 +288,6 @@
         }
 
         @Override
-        public void monitorAllEvents(boolean monitor) {
-        }
-
-        @Override
         public void addListener(OpenFlowSwitchListener listener) {
         }
 
@@ -299,6 +296,16 @@
         }
 
         @Override
+        public void addMessageListener(OpenFlowMessageListener listener) {
+
+        }
+
+        @Override
+        public void removeMessageListener(OpenFlowMessageListener listener) {
+
+        }
+
+        @Override
         public void addPacketListener(int priority, PacketListener listener) {
             pktListener = listener;
         }
@@ -428,16 +435,6 @@
         public String channelId() {
             return "1.2.3.4:1";
         }
-
-        @Override
-        public void addEventListener(OpenFlowEventListener listener) {
-        }
-
-        @Override
-        public void removeEventListener(OpenFlowEventListener listener) {
-        }
-
-
     }
 
 }