[ONOS-7831] Implement GnmiHandshaker

Change-Id: I2232a724a86955483321f9fda571907aa2cb615a
(cherry picked from commit a884274c5796e6d8e6a58743d2d7f5ef47124b78)
diff --git a/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClient.java b/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClient.java
index 7f43d1f..242bc94 100644
--- a/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClient.java
+++ b/protocols/gnmi/api/src/main/java/org/onosproject/gnmi/api/GnmiClient.java
@@ -57,5 +57,13 @@
      */
     CompletableFuture<SetResponse> set(SetRequest request);
 
+    /**
+     * Check weather the gNMI service is available or not by sending a
+     * dummy get request message.
+     *
+     * @return true if gNMI service available; false otherwise
+     */
+    CompletableFuture<Boolean> isServiceAvailable();
+
     // TODO: Support gNMI subscription
 }
diff --git a/protocols/gnmi/ctl/src/main/java/org/onosproject/gnmi/ctl/GnmiClientImpl.java b/protocols/gnmi/ctl/src/main/java/org/onosproject/gnmi/ctl/GnmiClientImpl.java
index 74a9ec0..b8179a9 100644
--- a/protocols/gnmi/ctl/src/main/java/org/onosproject/gnmi/ctl/GnmiClientImpl.java
+++ b/protocols/gnmi/ctl/src/main/java/org/onosproject/gnmi/ctl/GnmiClientImpl.java
@@ -19,10 +19,13 @@
 import gnmi.Gnmi.CapabilityResponse;
 import gnmi.Gnmi.GetRequest;
 import gnmi.Gnmi.GetResponse;
+import gnmi.Gnmi.Path;
+import gnmi.Gnmi.PathElem;
 import gnmi.Gnmi.SetRequest;
 import gnmi.Gnmi.SetResponse;
 import gnmi.gNMIGrpc;
 import io.grpc.ManagedChannel;
+import io.grpc.Status;
 import io.grpc.StatusRuntimeException;
 import org.onosproject.gnmi.api.GnmiClientKey;
 import org.onosproject.grpc.ctl.AbstractGrpcClient;
@@ -37,6 +40,9 @@
  * Implementation of gNMI client.
  */
 public class GnmiClientImpl extends AbstractGrpcClient implements GnmiClient {
+    private static final PathElem DUMMY_PATH_ELEM = PathElem.newBuilder().setName("onos-gnmi-test").build();
+    private static final Path DUMMY_PATH = Path.newBuilder().addElem(DUMMY_PATH_ELEM).build();
+    private static final GetRequest DUMMY_REQUEST = GetRequest.newBuilder().addPath(DUMMY_PATH).build();
     private final Logger log = getLogger(getClass());
     private final gNMIGrpc.gNMIBlockingStub blockingStub;
 
@@ -60,6 +66,11 @@
         return supplyInContext(() -> doSet(request), "set");
     }
 
+    @Override
+    public CompletableFuture<Boolean> isServiceAvailable() {
+        return supplyInContext(this::doServiceAvailable, "isServiceAvailable");
+    }
+
     private CapabilityResponse doCapability() {
         CapabilityRequest request = CapabilityRequest.newBuilder().build();
         try {
@@ -87,4 +98,17 @@
             return null;
         }
     }
+
+    private boolean doServiceAvailable() {
+        try {
+            blockingStub.get(DUMMY_REQUEST);
+            return true;
+        } catch (StatusRuntimeException e) {
+            // This gRPC call should throw INVALID_ARGUMENT status exception
+            // since "/onos-gnmi-test" path does not exists in any config model
+            // For other status code such as UNIMPLEMENT, means the gNMI
+            // service is not available on the device.
+            return e.getStatus().getCode().equals(Status.Code.INVALID_ARGUMENT);
+        }
+    }
 }