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/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcClientController.java b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcClientController.java
index b47d499..3edb36d 100644
--- a/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcClientController.java
+++ b/protocols/grpc/api/src/main/java/org/onosproject/grpc/api/GrpcClientController.java
@@ -17,6 +17,7 @@
 package org.onosproject.grpc.api;
 
 import com.google.common.annotations.Beta;
+import io.grpc.ManagedChannel;
 import org.onosproject.net.DeviceId;
 import org.onosproject.net.device.DeviceAgentListener;
 import org.onosproject.net.provider.ProviderId;
@@ -24,76 +25,54 @@
 /**
  * Abstraction of controller that manages gRPC clients.
  *
- * @param <K> the gRPC client key
  * @param <C> the gRPC client type
  */
 @Beta
-public interface GrpcClientController<K extends GrpcClientKey, C extends GrpcClient> {
+public interface GrpcClientController<C extends GrpcClient> {
 
     /**
-     * Instantiates a new client to operate on a gRPC server identified by the
-     * given information. As a result of this method, a client can be later
-     * obtained by invoking {@link #getClient(DeviceId)}.
+     * Instantiates a new client to operate on the given gRPC channel. Returns
+     * true if  the client was created successfully, false otherwise. Clients
+     * are identified by device IDs and once created they can be obtained by
+     * invoking {@link #get(DeviceId)}.
      * <p>
-     * Upon creation, a connection to the server is automatically started, which
-     * blocks execution. If the connection is successful, the client is created
-     * and this method returns true, otherwise (e.g., socket error) any state
-     * associated with this client is destroyed and returns false.
-     * <p>
-     * Only one client can exist for the same device ID. Calls to this method
-     * are idempotent fot the same client key, i.e. returns true if such client
-     * already exists. Otherwise, if a client for the same device ID but
-     * different client key already exists, throws an exception.
+     * Only one client can exist for the same device ID. If a client for the
+     * given device ID already exists, throws an exception.
      *
-     * @param clientKey the client key
-     * @return true if the client was created and the channel to the server is
-     * open; false otherwise
-     * @throws IllegalArgumentException if a client for the same device ID but
-     *                                  different client key already exists.
+     * @param deviceId device ID
+     * @param channel  gRPC managed channel
+     * @return true if the client was created, false otherwise
+     * @throws IllegalArgumentException if a client for the same device ID
+     *                                  already exists.
      */
-    boolean createClient(K clientKey);
+    boolean create(DeviceId deviceId, ManagedChannel channel);
 
     /**
-     * Returns the gRPC client previously created for the given device, or null
-     * if such client does not exist.
-     *
-     * @param deviceId the device identifier
-     * @return the gRPC client of the device if exists; null otherwise
-     */
-    C getClient(DeviceId deviceId);
-
-    /**
-     * Returns the gRPC client previously created for the given client key, or
+     * Returns the gRPC client previously created for the given device ID, or
      * null if such client does not exist.
      *
-     * @param clientKey client key
+     * @param deviceId the device ID
      * @return the gRPC client of the device if exists; null otherwise
      */
-    C getClient(K clientKey);
+    C get(DeviceId deviceId);
 
     /**
      * Removes the gRPC client for the given device and any gRPC channel state
      * associated to it. If no client exists for the given device, the result is
      * a no-op.
      *
-     * @param deviceId the device identifier
+     * @param deviceId the device ID
      */
-    void removeClient(DeviceId deviceId);
+    void remove(DeviceId deviceId);
 
     /**
-     * Similar to {@link #removeClient(DeviceId)} but uses the client key to
-     * identify the client to remove.
+     * Adds a listener for device agent events for the given provider. If a
+     * listener already exists for the given device ID and provider ID, then it
+     * will be replaced by the new one.
      *
-     * @param clientKey the client key
-     */
-    void removeClient(K clientKey);
-
-    /**
-     * Adds a listener for device agent events for the given provider.
-     *
-     * @param deviceId device identifier
+     * @param deviceId   device ID
      * @param providerId provider ID
-     * @param listener the device agent listener
+     * @param listener   the device agent listener
      */
     void addDeviceAgentListener(DeviceId deviceId, ProviderId providerId,
                                 DeviceAgentListener listener);
@@ -102,7 +81,7 @@
      * Removes the listener for device agent events that was previously
      * registered for the given provider.
      *
-     * @param deviceId   device identifier
+     * @param deviceId   device ID
      * @param providerId the provider ID
      */
     void removeDeviceAgentListener(DeviceId deviceId, ProviderId providerId);