Introduce method to write msg and get response through OpenFlow.

Change-Id: Ibc92985a98a3b9a178e474f55c117e08b05a8d44
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 df85811..43dd80b 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
@@ -17,6 +17,8 @@
 
 import org.projectfloodlight.openflow.protocol.OFMessage;
 
+import java.util.concurrent.CompletableFuture;
+
 /**
  * Abstraction of an OpenFlow controller. Serves as a one stop
  * shop for obtaining OpenFlow devices and (un)register listeners
@@ -128,6 +130,15 @@
     void write(Dpid dpid, OFMessage msg);
 
     /**
+     * Send a message to a particular switch and return the future response.
+     *
+     * @param dpid the switch to send to
+     * @param msg the message to send
+     * @return future for response message
+     */
+    CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg);
+
+    /**
      * Process a message and notify the appropriate listeners.
      *
      * @param dpid the dpid the message arrived 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 20e2aed..26122e3 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
@@ -17,6 +17,8 @@
 
 import org.projectfloodlight.openflow.protocol.OFMessage;
 
+import java.util.concurrent.CompletableFuture;
+
 /**
  * Test adapter for the OpenFlow controller interface.
  */
@@ -82,6 +84,11 @@
     }
 
     @Override
+    public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
+        return null;
+    }
+
+    @Override
     public void processPacket(Dpid dpid, OFMessage msg) {
     }
 
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 1b53bbd..cde105f 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
@@ -77,6 +77,7 @@
 import java.util.List;
 import java.util.Optional;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.ConcurrentHashMap;
 import java.util.concurrent.ConcurrentMap;
 import java.util.concurrent.CopyOnWriteArraySet;
@@ -146,6 +147,10 @@
     protected ConcurrentMap<Dpid, OpenFlowSwitch> activeEqualSwitches =
             new ConcurrentHashMap<>();
 
+    // Key: dpid, value: map with key: long (XID), value: completable future
+    protected ConcurrentMap<Dpid, ConcurrentMap<Long, CompletableFuture<OFMessage>>> responses =
+            new ConcurrentHashMap<>();
+
     protected OpenFlowSwitchAgent agent = new OpenFlowSwitchAgent();
     protected Set<OpenFlowSwitchListener> ofSwitchListener = new CopyOnWriteArraySet<>();
 
@@ -285,6 +290,19 @@
     }
 
     @Override
+    public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
+        write(dpid, msg);
+
+        ConcurrentMap<Long, CompletableFuture<OFMessage>> xids =
+                responses.computeIfAbsent(dpid, k -> new ConcurrentHashMap());
+
+        CompletableFuture<OFMessage> future = new CompletableFuture();
+        xids.put(msg.getXid(), future);
+
+        return future;
+    }
+
+    @Override
     public void processPacket(Dpid dpid, OFMessage msg) {
         Collection<OFFlowStatsEntry> flowStats;
         Collection<OFTableStatsEntry> tableStats;
@@ -294,6 +312,12 @@
 
         OpenFlowSwitch sw = this.getSwitch(dpid);
 
+        // Check if someone is waiting for this message
+        ConcurrentMap<Long, CompletableFuture<OFMessage>> xids = responses.get(dpid);
+        if (xids != null && xids.containsKey(msg.getXid())) {
+            xids.remove(msg.getXid()).complete(msg);
+        }
+
         switch (msg.getType()) {
         case PORT_STATUS:
             for (OpenFlowSwitchListener l : ofSwitchListener) {
diff --git a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
index 0acd186..7fd344d 100644
--- a/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
+++ b/providers/openflow/device/src/main/java/org/onosproject/provider/of/device/impl/OpenFlowDeviceProvider.java
@@ -15,32 +15,11 @@
  */
 package org.onosproject.provider.of.device.impl;
 
-import static com.google.common.base.Preconditions.checkArgument;
-import static com.google.common.base.Strings.isNullOrEmpty;
-import static org.onlab.util.Tools.get;
-import static org.onosproject.net.DeviceId.deviceId;
-import static org.onosproject.net.Port.Type.COPPER;
-import static org.onosproject.net.Port.Type.FIBER;
-import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
-import static org.onosproject.net.optical.device.OduCltPortHelper.oduCltPortDescription;
-import static org.onosproject.net.optical.device.OmsPortHelper.omsPortDescription;
-import static org.onosproject.net.optical.device.OtuPortHelper.otuPortDescription;
-import static org.onosproject.openflow.controller.Dpid.dpid;
-import static org.onosproject.openflow.controller.Dpid.uri;
-import static org.slf4j.LoggerFactory.getLogger;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Dictionary;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Properties;
-import java.util.Set;
-import java.util.Timer;
-
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.Lists;
+import com.google.common.collect.Maps;
+import com.google.common.collect.Sets;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -123,11 +102,31 @@
 import org.projectfloodlight.openflow.types.PortSpeed;
 import org.slf4j.Logger;
 
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableList;
-import com.google.common.collect.Lists;
-import com.google.common.collect.Maps;
-import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Dictionary;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Properties;
+import java.util.Set;
+import java.util.Timer;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onlab.util.Tools.get;
+import static org.onosproject.net.DeviceId.deviceId;
+import static org.onosproject.net.Port.Type.COPPER;
+import static org.onosproject.net.Port.Type.FIBER;
+import static org.onosproject.net.optical.device.OchPortHelper.ochPortDescription;
+import static org.onosproject.net.optical.device.OduCltPortHelper.oduCltPortDescription;
+import static org.onosproject.net.optical.device.OmsPortHelper.omsPortDescription;
+import static org.onosproject.net.optical.device.OtuPortHelper.otuPortDescription;
+import static org.onosproject.openflow.controller.Dpid.dpid;
+import static org.onosproject.openflow.controller.Dpid.uri;
+import static org.slf4j.LoggerFactory.getLogger;
 
 /**
  * Provider which uses an OpenFlow controller to detect network
@@ -744,7 +743,6 @@
                 // FIXME: use constants once loxi has full optical extensions
                 case 2:     // OMS port
                     // Assume complete optical spectrum and 50 GHz grid
-                    // LINC-OE is only supported optical OF device for now
                     Set<OchSignal> signals = null;
                     if (opsw instanceof HandlerBehaviour) {
                         DriverHandler driverHandler = ((HandlerBehaviour) opsw).handler();
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 8f5a9c1..3bf170d 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
@@ -60,6 +60,7 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 
 import static org.junit.Assert.*;
 import static org.onosproject.net.Device.Type.SWITCH;
@@ -318,6 +319,11 @@
         }
 
         @Override
+        public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
+            return null;
+        }
+
+        @Override
         public void processPacket(Dpid dpid, OFMessage msg) {
         }
 
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 ba0634a..b951ebc 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
@@ -62,6 +62,7 @@
 import java.util.Collection;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 
 import static org.junit.Assert.*;
 
@@ -265,6 +266,11 @@
         }
 
         @Override
+        public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
+            return null;
+        }
+
+        @Override
         public void processPacket(Dpid dpid, OFMessage msg) {
             eventListener.handleMessage(dpid, msg);
         }
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 c78a9fb..0c45efd 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
@@ -61,6 +61,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.CompletableFuture;
 
 import static org.junit.Assert.*;
 
@@ -328,6 +329,11 @@
         }
 
         @Override
+        public CompletableFuture<OFMessage> writeResponse(Dpid dpid, OFMessage msg) {
+            return null;
+        }
+
+        @Override
         public void processPacket(Dpid dpid, OFMessage msg) {
             OpenFlowPacketContext pktCtx =
                     DefaultOpenFlowPacketContext.