ONOS-6561 BMv2 handshaker via P4Runtime

+ support fort device-specific default pipeconf
+ improvements to P4runtime and gRPC protocol stuff

Change-Id: I8986fce3959df564454ea3d31859860f61eabcae
diff --git a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
index 4ce097d..152106a 100644
--- a/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
+++ b/protocols/grpc/ctl/src/main/java/org/onosproject/grpc/ctl/GrpcControllerImpl.java
@@ -19,6 +19,8 @@
 import com.google.common.collect.ImmutableSet;
 import io.grpc.ManagedChannel;
 import io.grpc.ManagedChannelBuilder;
+import io.grpc.Status;
+import io.grpc.StatusRuntimeException;
 import org.apache.felix.scr.annotations.Activate;
 import org.apache.felix.scr.annotations.Component;
 import org.apache.felix.scr.annotations.Deactivate;
@@ -27,16 +29,20 @@
 import org.onosproject.grpc.api.GrpcController;
 import org.onosproject.grpc.api.GrpcObserverHandler;
 import org.onosproject.grpc.api.GrpcStreamObserverId;
+import org.onosproject.grpc.ctl.dummy.Dummy;
+import org.onosproject.grpc.ctl.dummy.DummyServiceGrpc;
 import org.onosproject.net.DeviceId;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.io.IOException;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Default implementation of the GrpcController.
@@ -45,6 +51,8 @@
 @Service
 public class GrpcControllerImpl implements GrpcController {
 
+    private static final int CONNECTION_TIMEOUT_SECONDS = 20;
+
     public static final Logger log = LoggerFactory
             .getLogger(GrpcControllerImpl.class);
 
@@ -87,18 +95,63 @@
     }
 
     @Override
-    public ManagedChannel connectChannel(GrpcChannelId channelId, ManagedChannelBuilder<?> channelBuilder) {
+    public ManagedChannel connectChannel(GrpcChannelId channelId, ManagedChannelBuilder<?> channelBuilder)
+            throws IOException {
         ManagedChannel channel = channelBuilder.build();
 
-        channel.getState(true);
+        // Forced connection not yet implemented. Use workaround...
+        // channel.getState(true);
+        doDummyMessage(channel);
+
         channelBuilders.put(channelId, channelBuilder);
         channels.put(channelId, channel);
         return channel;
     }
 
+    private void doDummyMessage(ManagedChannel channel) throws IOException {
+        DummyServiceGrpc.DummyServiceBlockingStub dummyStub = DummyServiceGrpc.newBlockingStub(channel)
+                .withDeadlineAfter(CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS);
+        try {
+            dummyStub.sayHello(Dummy.DummyMessageThatNoOneWouldReallyUse.getDefaultInstance());
+        } catch (StatusRuntimeException e) {
+            if (e.getStatus() != Status.UNIMPLEMENTED) {
+                // UNIMPLEMENTED means that server received our message but doesn't know how to handle it.
+                // Hence, channel is open.
+                throw new IOException(e);
+            }
+        }
+    }
+
+    @Override
+    public boolean isChannelOpen(GrpcChannelId channelId) {
+        if (!channels.containsKey(channelId)) {
+            log.warn("Can't check if channel open for unknown channel id {}", channelId);
+            return false;
+        }
+
+        try {
+            doDummyMessage(channels.get(channelId));
+            return true;
+        } catch (IOException e) {
+            return false;
+        }
+    }
+
     @Override
     public void disconnectChannel(GrpcChannelId channelId) {
-        channels.get(channelId).shutdown();
+        if (!channels.containsKey(channelId)) {
+            // Nothing to do.
+            return;
+        }
+        ManagedChannel channel = channels.get(channelId);
+
+        try {
+            channel.shutdown().awaitTermination(5, TimeUnit.SECONDS);
+        } catch (InterruptedException e) {
+            log.warn("Channel {} didn't shut down in time.");
+            channel.shutdownNow();
+        }
+
         channels.remove(channelId);
         channelBuilders.remove(channelId);
     }