Allow sharing the same gRPC channel between clients

This change introduces a refactoring of the gRPC protocol subsystem that
allows the creation of a gRPC chanel independently of the client, while
allowing multiple clients to share the same channel (e.g. as in Stratum
where we use 3 clients).

Moreover, we refactor the P4RuntimeClient API to support multiple
P4Runtime-internal device ID using the same client. While before the
client was associated to one of such ID.

Finally, we provide an abstract implementation for gRPC-based driver
behaviors, reducing code duplication in P4Runtime, gNMI and gNOI drivers.

Change-Id: I1a46352bbbef1e0d24042f169ae8ba580202944f
diff --git a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/GnmiHandshaker.java b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/GnmiHandshaker.java
index a6d0c04..82fc40c 100644
--- a/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/GnmiHandshaker.java
+++ b/drivers/gnmi/src/main/java/org/onosproject/drivers/gnmi/GnmiHandshaker.java
@@ -17,33 +17,23 @@
 package org.onosproject.drivers.gnmi;
 
 import org.onosproject.gnmi.api.GnmiClient;
-import org.onosproject.gnmi.api.GnmiClientKey;
 import org.onosproject.gnmi.api.GnmiController;
+import org.onosproject.grpc.utils.AbstractGrpcHandshaker;
 import org.onosproject.net.MastershipRole;
 import org.onosproject.net.device.DeviceHandshaker;
 
 import java.util.concurrent.CompletableFuture;
 
-import static java.util.concurrent.CompletableFuture.completedFuture;
-
 /**
  * Implementation of DeviceHandshaker for gNMI.
  */
-public class GnmiHandshaker extends AbstractGnmiHandlerBehaviour implements DeviceHandshaker {
+public class GnmiHandshaker
+        extends AbstractGrpcHandshaker<GnmiClient, GnmiController>
+        implements DeviceHandshaker {
 
-    @Override
-    public boolean isReachable() {
-        final GnmiClient client = getClientByKey();
-        return client != null && client.isServerReachable();
-    }
 
-    @Override
-    public CompletableFuture<Boolean> probeReachability() {
-        final GnmiClient client = getClientByKey();
-        if (client == null) {
-            return completedFuture(false);
-        }
-        return client.probeService();
+    public GnmiHandshaker() {
+        super(GnmiController.class);
     }
 
     @Override
@@ -65,33 +55,4 @@
     public MastershipRole getRole() {
         throw new UnsupportedOperationException("Mastership operation not supported");
     }
-
-    @Override
-    public CompletableFuture<Boolean> connect() {
-        return CompletableFuture.supplyAsync(this::createClient);
-    }
-
-    private boolean createClient() {
-        GnmiClientKey clientKey = clientKey();
-        if (clientKey == null) {
-            return false;
-        }
-        if (!handler().get(GnmiController.class).createClient(clientKey)) {
-            log.warn("Unable to create client for {}",
-                     handler().data().deviceId());
-            return false;
-        }
-        return true;
-    }
-
-    @Override
-    public boolean isConnected() {
-        return getClientByKey() != null;
-    }
-
-    @Override
-    public void disconnect() {
-        handler().get(GnmiController.class)
-                .removeClient(handler().data().deviceId());
-    }
 }