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/stratum/BUILD b/drivers/stratum/BUILD
index 1d19c3c..a87c97e 100644
--- a/drivers/stratum/BUILD
+++ b/drivers/stratum/BUILD
@@ -4,6 +4,8 @@
     "//drivers/gnmi:onos-drivers-gnmi",
     "//drivers/gnoi:onos-drivers-gnoi",
     "//pipelines/basic:onos-pipelines-basic",
+    "//protocols/grpc/api:onos-protocols-grpc-api",
+    "//protocols/grpc/utils:onos-protocols-grpc-utils",
 ]
 
 osgi_jar(
diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDeviceDescriptionDiscovery.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDeviceDescriptionDiscovery.java
index dbcb193..fdf8173 100644
--- a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDeviceDescriptionDiscovery.java
+++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumDeviceDescriptionDiscovery.java
@@ -63,6 +63,9 @@
                 // Availability is mandated by P4Runtime.
                 p4Descr.isDefaultAvailable(),
                 DefaultAnnotations.builder()
+                        .putAll(p4Descr.annotations())
+                        .putAll(gnmiDescr.annotations())
+                        .putAll(gnoiDescr.annotations())
                         .set(AnnotationKeys.PROTOCOL, format(
                                 "%s, %s, %s",
                                 p4Descr.annotations().value(AnnotationKeys.PROTOCOL),
diff --git a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java
index d512d3b..ac9a534 100644
--- a/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java
+++ b/drivers/stratum/src/main/java/org/onosproject/drivers/stratum/StratumHandshaker.java
@@ -38,6 +38,23 @@
     }
 
     @Override
+    public boolean connect() {
+        return p4runtime.connect() && gnmi.connect() && gnoi.connect();
+    }
+
+    @Override
+    public boolean hasConnection() {
+        return p4runtime.hasConnection() && gnmi.hasConnection() && gnoi.hasConnection();
+    }
+
+    @Override
+    public void disconnect() {
+        p4runtime.disconnect();
+        gnmi.disconnect();
+        gnoi.disconnect();
+    }
+
+    @Override
     public boolean isReachable() {
         // Reachability is mainly used for mastership contests and it's a
         // prerequisite for availability. We can probably live without gNMI and
@@ -86,23 +103,4 @@
     public void removeDeviceAgentListener(ProviderId providerId) {
         p4runtime.removeDeviceAgentListener(providerId);
     }
-
-    @Override
-    public CompletableFuture<Boolean> connect() {
-        // We should execute connections in parallel.
-        return p4runtime.connect().thenCombine(gnmi.connect(), Boolean::logicalAnd)
-                .thenCombine(gnoi.connect(), Boolean::logicalAnd);
-    }
-
-    @Override
-    public boolean isConnected() {
-        return p4runtime.isConnected() && gnmi.isConnected() && gnoi.isConnected();
-    }
-
-    @Override
-    public void disconnect() {
-        p4runtime.disconnect();
-        gnmi.disconnect();
-        gnoi.disconnect();
-    }
 }