Initial gNOI implementation added. Introduced system Time and Reboot RPC

Change-Id: I8accdcc6c1ff247408ce54490ceff3972fdf850f
diff --git a/protocols/gnoi/BUILD b/protocols/gnoi/BUILD
new file mode 100644
index 0000000..3666ea6
--- /dev/null
+++ b/protocols/gnoi/BUILD
@@ -0,0 +1,17 @@
+BUNDLES = [
+    "//protocols/gnoi/stub:onos-protocols-gnoi-stub",
+    "//protocols/gnoi/ctl:onos-protocols-gnoi-ctl",
+    "//protocols/gnoi/api:onos-protocols-gnoi-api",
+]
+
+onos_app(
+    app_name = "org.onosproject.protocols.gnoi",
+    category = "Protocol",
+    description = "gNOI protocol subsystem",
+    included_bundles = BUNDLES,
+    required_apps = [
+        "org.onosproject.protocols.grpc",
+    ],
+    title = "gNOI Protocol Subsystem",
+    url = "http://onosproject.org",
+)
diff --git a/protocols/gnoi/api/BUILD b/protocols/gnoi/api/BUILD
new file mode 100644
index 0000000..600f437
--- /dev/null
+++ b/protocols/gnoi/api/BUILD
@@ -0,0 +1,8 @@
+COMPILE_DEPS = CORE_DEPS + [
+    "//protocols/grpc/api:onos-protocols-grpc-api",
+    "//protocols/gnoi/stub:onos-protocols-gnoi-stub",
+]
+
+osgi_jar(
+    deps = COMPILE_DEPS,
+)
diff --git a/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiClient.java b/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiClient.java
new file mode 100644
index 0000000..d66c6f1
--- /dev/null
+++ b/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiClient.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.gnoi.api;
+
+import gnoi.system.SystemOuterClass.TimeResponse;
+import gnoi.system.SystemOuterClass.RebootRequest;
+import gnoi.system.SystemOuterClass.RebootResponse;
+import com.google.common.annotations.Beta;
+import org.onosproject.grpc.api.GrpcClient;
+import java.util.concurrent.CompletableFuture;
+
+/**
+ * Client to control a gNOI server.
+ */
+@Beta
+public interface GnoiClient extends GrpcClient {
+
+    /**
+     * Returns the current time on the target.
+     *
+     * @return the TimeResponse result
+     */
+    CompletableFuture<TimeResponse> time();
+
+    /**
+     * Causes the target to reboot immediately.
+     *
+     * @param request RebootRequest
+     * @return the RebootResponse result
+     */
+    CompletableFuture<RebootResponse> reboot(RebootRequest request);
+}
diff --git a/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiClientKey.java b/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiClientKey.java
new file mode 100644
index 0000000..e246d74
--- /dev/null
+++ b/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiClientKey.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.gnoi.api;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.grpc.api.GrpcClientKey;
+import org.onosproject.net.DeviceId;
+
+import java.net.URI;
+
+/**
+ * Key that uniquely identifies a gNOI client.
+ */
+@Beta
+public class GnoiClientKey extends GrpcClientKey {
+
+    private static final String GNOI = "gNOI";
+
+    /**
+     * Creates a new gNOI client key.
+     *
+     * @param deviceId  ONOS device ID
+     * @param serverUri gNOI server URI
+     */
+    public GnoiClientKey(DeviceId deviceId, URI serverUri) {
+        super(GNOI, deviceId, serverUri);
+    }
+}
diff --git a/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiController.java b/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiController.java
new file mode 100644
index 0000000..b601e21
--- /dev/null
+++ b/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/GnoiController.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.gnoi.api;
+
+import com.google.common.annotations.Beta;
+import org.onosproject.grpc.api.GrpcClientController;
+
+/**
+ * Controller of gNOI devices.
+ */
+@Beta
+public interface GnoiController
+        extends GrpcClientController<GnoiClientKey, GnoiClient> {
+}
diff --git a/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/package-info.java b/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/package-info.java
new file mode 100644
index 0000000..ff86859
--- /dev/null
+++ b/protocols/gnoi/api/src/main/java/org/onosproject/gnoi/api/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * gNOI protocol API.
+ */
+package org.onosproject.gnoi.api;
diff --git a/protocols/gnoi/ctl/BUILD b/protocols/gnoi/ctl/BUILD
new file mode 100644
index 0000000..9fdb3a8
--- /dev/null
+++ b/protocols/gnoi/ctl/BUILD
@@ -0,0 +1,23 @@
+COMPILE_DEPS = CORE_DEPS + KRYO + [
+    "//protocols/gnoi/api:onos-protocols-gnoi-api",
+    "//protocols/gnoi/stub:onos-protocols-gnoi-stub",
+    "//protocols/grpc/api:onos-protocols-grpc-api",
+    "//protocols/grpc/ctl:onos-protocols-grpc-ctl",
+    "//protocols/grpc:grpc-core",
+    "@com_google_protobuf//:protobuf_java",
+    "@io_grpc_grpc_java//netty",
+    "@io_grpc_grpc_java//protobuf-lite",
+    "@io_grpc_grpc_java//stub",
+    "@com_google_api_grpc_proto_google_common_protos//jar",
+]
+
+TEST_DEPS = TEST + [
+    "@minimal_json//jar",
+    "@io_grpc_grpc_java//core:inprocess",
+    "@io_grpc_grpc_java//protobuf-lite",
+]
+
+osgi_jar_with_tests(
+    test_deps = TEST_DEPS,
+    deps = COMPILE_DEPS,
+)
diff --git a/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/GnoiClientImpl.java b/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/GnoiClientImpl.java
new file mode 100644
index 0000000..f1f1482
--- /dev/null
+++ b/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/GnoiClientImpl.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onosproject.gnoi.ctl;
+
+import gnoi.system.SystemGrpc;
+import gnoi.system.SystemOuterClass.TimeRequest;
+import gnoi.system.SystemOuterClass.TimeResponse;
+import gnoi.system.SystemOuterClass.RebootRequest;
+import gnoi.system.SystemOuterClass.RebootResponse;
+import io.grpc.ManagedChannel;
+import io.grpc.stub.StreamObserver;
+import org.onosproject.gnoi.api.GnoiClient;
+import org.onosproject.gnoi.api.GnoiClientKey;
+import org.onosproject.grpc.ctl.AbstractGrpcClient;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Implementation of gNOI client.
+ */
+public class GnoiClientImpl extends AbstractGrpcClient implements GnoiClient {
+
+    private static final int RPC_TIMEOUT_SECONDS = 10;
+    private static final Logger log = LoggerFactory.getLogger(GnoiClientImpl.class);
+
+    GnoiClientImpl(GnoiClientKey clientKey, ManagedChannel managedChannel, GnoiControllerImpl controller) {
+        super(clientKey, managedChannel, false, controller);
+    }
+
+    @Override
+    public CompletableFuture<Boolean> probeService() {
+        return this.time().handle((response, t) -> {
+            if (t == null) {
+                log.debug("gNOI probeService succeed");
+                return true;
+            } else {
+                log.debug("gNOI probeService failed", t);
+                return false;
+            }
+        });
+    }
+
+    @Override
+    public CompletableFuture<TimeResponse> time() {
+        // The TimeRequest message is empty one so just form it
+        final TimeRequest requestMsg = TimeRequest.getDefaultInstance();
+        final CompletableFuture<TimeResponse> future = new CompletableFuture<>();
+
+        final StreamObserver<TimeResponse> observer =
+                new StreamObserver<TimeResponse>() {
+                    @Override
+                    public void onNext(TimeResponse value) {
+                        future.complete(value);
+                    }
+                    @Override
+                    public void onError(Throwable t) {
+                        handleRpcError(t, "gNOI time request");
+                        future.completeExceptionally(t);
+                    }
+                    @Override
+                    public void onCompleted() {
+                        // ignore
+                    }
+                };
+
+        execRpc(s -> s.time(requestMsg, observer));
+        return future;
+    }
+
+    @Override
+    public CompletableFuture<RebootResponse> reboot(RebootRequest request) {
+        final CompletableFuture<RebootResponse> future = new CompletableFuture<>();
+
+        final StreamObserver<RebootResponse> observer =
+                new StreamObserver<RebootResponse>() {
+                    @Override
+                    public void onNext(RebootResponse value) {
+                        future.complete(value);
+                    }
+                    @Override
+                    public void onError(Throwable t) {
+                        handleRpcError(t, "gNOI reboot request");
+                        future.completeExceptionally(t);
+                    }
+                    @Override
+                    public void onCompleted() {
+                        // ignore
+                    }
+                };
+
+        execRpc(s -> s.reboot(request, observer));
+        return future;
+    }
+
+    /**
+     * Forces execution of an RPC in a cancellable context with a timeout.
+     *
+     * @param stubConsumer SystemStub stub consumer
+     */
+    private void execRpc(Consumer<SystemGrpc.SystemStub> stubConsumer) {
+        if (log.isTraceEnabled()) {
+            log.trace("Executing RPC with timeout {} seconds (context deadline {})...",
+                    RPC_TIMEOUT_SECONDS, context().getDeadline());
+        }
+        runInCancellableContext(() -> stubConsumer.accept(
+                SystemGrpc.newStub(channel)
+                        .withDeadlineAfter(RPC_TIMEOUT_SECONDS, TimeUnit.SECONDS)));
+    }
+
+    /**
+     * Forces execution of an RPC in a cancellable context with no timeout.
+     *
+     * @param stubConsumer SystemStub stub consumer
+     */
+    void execRpcNoTimeout(Consumer<SystemGrpc.SystemStub> stubConsumer) {
+        if (log.isTraceEnabled()) {
+            log.trace("Executing RPC with no timeout (context deadline {})...",
+                    context().getDeadline());
+        }
+        runInCancellableContext(() -> stubConsumer.accept(
+                SystemGrpc.newStub(channel)));
+    }
+
+}
diff --git a/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/GnoiControllerImpl.java b/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/GnoiControllerImpl.java
new file mode 100644
index 0000000..09ef01d
--- /dev/null
+++ b/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/GnoiControllerImpl.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onosproject.gnoi.ctl;
+
+import io.grpc.ManagedChannel;
+import org.onosproject.event.AbstractEvent;
+import org.onosproject.event.EventListener;
+import org.onosproject.gnoi.api.GnoiClient;
+import org.onosproject.gnoi.api.GnoiClientKey;
+import org.onosproject.gnoi.api.GnoiController;
+import org.onosproject.grpc.ctl.AbstractGrpcClientController;
+import org.osgi.service.component.annotations.Component;
+
+/**
+ * Implementation of gNOI controller.
+ */
+@Component(immediate = true, service = GnoiController.class)
+public class GnoiControllerImpl
+        extends AbstractGrpcClientController<GnoiClientKey, GnoiClient, AbstractEvent, EventListener<AbstractEvent>>
+        implements GnoiController {
+
+    public GnoiControllerImpl() {
+        super(AbstractEvent.class);
+    }
+
+    @Override
+    protected GnoiClient createClientInstance(GnoiClientKey clientKey, ManagedChannel channel) {
+        return new GnoiClientImpl(clientKey, channel, this);
+    }
+}
\ No newline at end of file
diff --git a/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/package-info.java b/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/package-info.java
new file mode 100644
index 0000000..e031bb7
--- /dev/null
+++ b/protocols/gnoi/ctl/src/main/java/org/onosproject/gnoi/ctl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019-present Open Networking Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Implementation classes of the gNOI protocol subsystem.
+ */
+package org.onosproject.gnoi.ctl;
diff --git a/protocols/gnoi/stub/BUILD b/protocols/gnoi/stub/BUILD
new file mode 100644
index 0000000..c6a3deb
--- /dev/null
+++ b/protocols/gnoi/stub/BUILD
@@ -0,0 +1,15 @@
+load("//tools/build/bazel:osgi_java_library.bzl", "osgi_proto_jar")
+
+PROTOS = [
+    "@com_github_openconfig_gnoi//:gnoi_system_proto",
+    "@com_github_openconfig_gnoi//:gnoi_types_proto",
+    "@com_github_openconfig_gnoi//:gnoi_common_proto",
+]
+
+osgi_proto_jar(
+    grpc_proto_lib = "@com_github_openconfig_gnoi//:gnoi_system_proto",
+    proto_libs = PROTOS,
+    deps = [
+        "@com_google_api_grpc_proto_google_common_protos//jar",
+    ],
+)