Adding skeletal onos-topo integration app

Change-Id: I80f39193ef25fb5d46b0053d76409165d07ec4ea
diff --git a/WORKSPACE b/WORKSPACE
index 295c6d5..ce3f50b 100644
--- a/WORKSPACE
+++ b/WORKSPACE
@@ -128,6 +128,10 @@
 
 RULES_NODEJS_SHA256 = "0d9660cf0894f1fe1e9840818553e0080fbce0851169812d77a70bdb9981c946"
 
+load("//tools/build/bazel:topo_workspace.bzl", "generate_topo_device")
+
+generate_topo_device()
+
 http_archive(
     name = "build_bazel_rules_nodejs",
     sha256 = RULES_NODEJS_SHA256,
diff --git a/apps/onos-topo/BUILD b/apps/onos-topo/BUILD
new file mode 100644
index 0000000..c8a3083c
--- /dev/null
+++ b/apps/onos-topo/BUILD
@@ -0,0 +1,14 @@
+BUNDLES = [
+    "//apps/onos-topo/api:onos-apps-onos-topo-api",
+    "//apps/onos-topo/app:onos-apps-onos-topo-app",
+]
+
+onos_app(
+    category = "Integrations",
+    included_bundles = BUNDLES,
+    required_apps = [
+        "org.onosproject.protocols.grpc",
+    ],
+    title = "µONOS Integration",
+    url = "http://onosproject.org",
+)
diff --git a/apps/onos-topo/api/BUILD b/apps/onos-topo/api/BUILD
new file mode 100644
index 0000000..0c0b22d
--- /dev/null
+++ b/apps/onos-topo/api/BUILD
@@ -0,0 +1,13 @@
+load("//tools/build/bazel:osgi_java_library.bzl", "osgi_proto_jar")
+
+PROTOS = [
+    "@com_github_onosproject_onos_topo//:topo_device_proto",
+]
+
+osgi_proto_jar(
+    grpc_proto_lib = "@com_github_onosproject_onos_topo//:topo_device_proto",
+    proto_libs = PROTOS,
+    deps = [
+        "@com_google_api_grpc_proto_google_common_protos//jar",
+    ],
+)
diff --git a/apps/onos-topo/app/BUILD b/apps/onos-topo/app/BUILD
new file mode 100644
index 0000000..324ac59
--- /dev/null
+++ b/apps/onos-topo/app/BUILD
@@ -0,0 +1,12 @@
+COMPILE_DEPS = CORE_DEPS + [
+    "//apps/onos-topo/api:onos-apps-onos-topo-api",
+    "//core/store/serializers:onos-core-serializers",
+    "@io_grpc_grpc_java//api",
+    "@io_grpc_grpc_java//netty",
+    "@io_grpc_grpc_java//stub",
+]
+
+osgi_jar_with_tests(
+    test_deps = TEST_ADAPTERS,
+    deps = COMPILE_DEPS,
+)
diff --git a/apps/onos-topo/app/src/main/java/org/onosproject/uonos/impl/MicroOnosTopoManager.java b/apps/onos-topo/app/src/main/java/org/onosproject/uonos/impl/MicroOnosTopoManager.java
new file mode 100644
index 0000000..ccfd0ce
--- /dev/null
+++ b/apps/onos-topo/app/src/main/java/org/onosproject/uonos/impl/MicroOnosTopoManager.java
@@ -0,0 +1,162 @@
+/*
+ * 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.uonos.impl;
+
+import io.grpc.Server;
+import io.grpc.netty.NettyServerBuilder;
+import io.grpc.stub.StreamObserver;
+import org.onosproject.net.AnnotationKeys;
+import org.onosproject.net.Annotations;
+import org.onosproject.net.Device;
+import org.onosproject.net.device.DeviceService;
+import org.onosproject.uonos.DeviceOuterClass;
+import org.onosproject.uonos.DeviceServiceGrpc;
+import org.osgi.service.component.annotations.Activate;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Deactivate;
+import org.osgi.service.component.annotations.Reference;
+import org.osgi.service.component.annotations.ReferenceCardinality;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static org.onosproject.uonos.DeviceOuterClass.ListRequest;
+import static org.onosproject.uonos.DeviceOuterClass.ListResponse;
+
+/**
+ * Provides implementation of the gRPC interface for onos-topo service.
+ */
+@Component(immediate = true)
+public class MicroOnosTopoManager {
+
+    private static final int MICRO_ONOS_PORT = 5150;
+    private static final byte[] MICRO_ONOS_DEFAULT_CERT = ("\n-----BEGIN CERTIFICATE-----\n" +
+            "MIIDZTCCAk0CCQDl7NF6ekffcTANBgkqhkiG9w0BAQsFADByMQswCQYDVQQGEwJV\n" +
+            "UzELMAkGA1UECAwCQ0ExEjAQBgNVBAcMCU1lbmxvUGFyazEMMAoGA1UECgwDT05G\n" +
+            "MRQwEgYDVQQLDAtFbmdpbmVlcmluZzEeMBwGA1UEAwwVY2Eub3Blbm5ldHdvcmtp\n" +
+            "bmcub3JnMB4XDTE5MDQxMTExMTYyM1oXDTIwMDQxMDExMTYyM1owdzELMAkGA1UE\n" +
+            "BhMCVVMxCzAJBgNVBAgMAkNBMRIwEAYDVQQHDAlNZW5sb1BhcmsxDDAKBgNVBAoM\n" +
+            "A09ORjEUMBIGA1UECwwLRW5naW5lZXJpbmcxIzAhBgNVBAMMGmNsaWVudDEub3Bl\n" +
+            "bm5ldHdvcmtpbmcub3JnMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA\n" +
+            "5mR12oGXP+uDD7DzQZdTg96eHWTc0UKPwie2I5LLLVsRoH2PO5s2B5r6r/E8OUG4\n" +
+            "0pGb6tkDRIJ8eC0Z/6NvBkzn4fsJ5g0UW6sVlXfaf0y9JnMSvV05+g++75a7+CRx\n" +
+            "1BG3GNjGWbke1mx8d6SrQ8D1sjI3L0D+32mi0WU9jO2Uw9YXvXgxQmL9Krxdr3M/\n" +
+            "aZO9sTJZtIT0EEY3qBpPv+daAbuP5m+uhiEzYZP2bLywyzGyfrUmj9fjG/D1kuMM\n" +
+            "haEIUJQ2VTcIApKG/Kb3Mk3b3VCfTvpEHMVrKMoyNHQXXi+6X106+cu2WtoPv+U5\n" +
+            "VFVoufjRWSbcOmQ7qIHBiwIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQBRBR6LTFEU\n" +
+            "SWeEeguMsbHxN/6NIZuPejib1q9fTHeZ9cnIHIOLJaZzHiMZn5uw8s6D26kveNps\n" +
+            "iCr4O8xOjUa0uwbhMTgm3wkODLlV1DwGjFWk8v5UKGWqUQ94wVMQ16YMIR5DgJJM\n" +
+            "0DUzVcoFz+vLnMrDZ0AEk5vra1Z5KweSRvwHX7dJ6FIW7X3IgqXTqJtlV/D/vIi3\n" +
+            "UfBnjzqOy2LVfBD7du7i5NbTHfTUpoTvddVwQaKCuQGYHocoQvQD3VQcQDh1u0DD\n" +
+            "n2GkeEDLaDAGFAIO+PDg2iT8BhKeEepqswid9gYAhZcOjrlnl6smZo7jEzBj1a9Q\n" +
+            "e3q1STjfQqe8\n" +
+            "-----END CERTIFICATE-----\n").getBytes();
+
+    private static final byte[] MICRO_ONOS_DEFAULT_KEY = ("\n-----BEGIN PRIVATE KEY-----\n" +
+            "MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQC4zBmctGU/0LQ4\n" +
+            "uJAtny0Zh/NwAVAgjAlVE9Y3hh1fTiXB7eAPhLrCa3KCzRlQAUCvorNPKYhlHV70\n" +
+            "CL8ACWVrstxeY635I3UGanPZhdNRv1h6hW8hympqIKO1otWDV6pwi0gXo6Zco8QQ\n" +
+            "/3LriBlsGn34kvP52Sh4n/id38CCw34OgkItfZb8VeSkXdNQHN1sfB/z0fJXGdIz\n" +
+            "Io5JGGfgiw/i5ccesyXxfN8A3vBhKE1sUJzeHZGEzkdmo/ZbfpVQt4H6aKurYfwD\n" +
+            "xDQjVasf+Lq+WDKd2OzN+BZ+YBMNWUcmZkAh8zZmQWhCttLL484GOeCtqq5HGsTD\n" +
+            "JvfkHSAvAgMBAAECggEBAIi5ORnfvimA2FY+9y1J36xMEaiE0CvEcAMqMgvShljF\n" +
+            "ENpyjJvur964cHimFlxDEQDhd5jSOb/WAzK6ZdY5HXiZVMHhLg5uVV7x09TUVozc\n" +
+            "7TF5F8gAYssyau0wFJige9HYuvYCdkuEPsP0u6nXgDejQiBvWWM5b+APO3pS2bPk\n" +
+            "fbyXPnp+xUQAQhH/m+VCCG4hlC1bKulkY4yWKp5wrKtj2Xun0Vh4Iu9UJiH/EuQ6\n" +
+            "mwpUeWLECO5OYDKQWH90iIVDZufe+8yw1VZrN82cTWL86jetgPEXz6klWGUu1gHU\n" +
+            "r57xz0Nb4rhFPs49aw9Yj/LswF1I5zdF6EiT0H5aRoECgYEA2tNBEo4ta3JW4wF/\n" +
+            "/3AKAE79RV+06z74x3Id5w2ED8TRq3SRu5oMmR9kJhe6owNg8WcbK/h/LuI5+CPD\n" +
+            "V8Uo8HGQs5VisSJGJdCul8gA2bDGPEokGezdEdE6UUaNxpgRU484owZau80c4Q/Y\n" +
+            "B4evLdJL9KIaSB5oPHGfu65i41kCgYEA2DD29X6i1GOSwzKXTXNdrZjxxOqeZiVv\n" +
+            "/+TTiRffIUNMObtR6B8wWi5Y+oPUUj+Xop1vM7L9ZkwfkuDMtaZbryA37rsoAKP9\n" +
+            "Sdlemyt0cB+cL7MN04Od9UD4YzbapRGAoFJduzzneQN0PBUc6wvB6cMBH2UZsEjQ\n" +
+            "GdV0r/iC1scCgYEA0pg9J/5s99syg4YOCWdqOKHMXded5kjUZB4PaS44ynRA1SF6\n" +
+            "n3HCbhsn5wEvPXMi+TChlc+xlw1hfM3uUaoNnFmvSSWbtZ2mpP4RCUISj27xWVSB\n" +
+            "KfIrT9pspYuhJl9zTVeoyjxzVgowoOj+n0CV9yNMtkLLyFx7NLClaZqK0QECgYAj\n" +
+            "rECz1YeMwDlxWCG7N/QXNwt90LD+beMDOIDnODcrR+2GATDMuojB+K/Z9nLMd43P\n" +
+            "2WaGA1zoylrTY6CjwKWUSh6wl9VL9cNPsjx4Ij1+WtjszgDUC/2+gE/8HwsI/dBZ\n" +
+            "o/2vbadMQpOlbl5tMm124ySGR6prejhMavpsJvd/9QKBgGBN5jGWqdezvFx1dY0S\n" +
+            "uZAlqQ3h5w/0MMGSmaM+yN30wjFdWd3yMAxNgIp4Oj1noqvuqXiXnBjN6YER3GNx\n" +
+            "hpjimxkZY9ogyVGz+RP9YqGKKbUtBL/8zZ/LYbWGvo9yJ6HxwO397EhyXNhCvwyF\n" +
+            "sDhPaK+DnzwfkjBk3kXNve4o\n" +
+            "-----END PRIVATE KEY-----\n").getBytes();
+
+    private final Logger log = LoggerFactory.getLogger(getClass());
+
+    private Server server;
+
+    @Reference(cardinality = ReferenceCardinality.MANDATORY)
+    protected DeviceService deviceService;
+
+    @Activate
+    protected void activate() {
+        try {
+            server = NettyServerBuilder.forPort(MICRO_ONOS_PORT)
+// FIXME: make this work later
+//                    .useTransportSecurity(new ByteArrayInputStream(MICRO_ONOS_DEFAULT_CERT),
+//                                          new ByteArrayInputStream(MICRO_ONOS_DEFAULT_KEY))
+                    .addService(new MicroOnosDeviceService())
+                    .build()
+                    .start();
+        } catch (IOException e) {
+            log.error("Unable to start gRPC server", e);
+            throw new IllegalStateException("Unable to start gRPC server", e);
+        }
+        log.info("Started");
+    }
+
+    @Deactivate
+    protected void deactivate() {
+        if (server != null) {
+            server.shutdown();
+        }
+        log.info("Stopped");
+    }
+
+    private class MicroOnosDeviceService extends DeviceServiceGrpc.DeviceServiceImplBase {
+        @Override
+        public void list(ListRequest request,
+                         StreamObserver<ListResponse> responseObserver) {
+            for (Device d : deviceService.getDevices()) {
+                Annotations annotations = d.annotations();
+                DeviceOuterClass.Device.Builder db = DeviceOuterClass.Device.newBuilder()
+                        .setId(d.id().toString())
+                        .setVersion(d.swVersion())
+                        .setType(d.type().toString());
+                String value = annotations.value(AnnotationKeys.MANAGEMENT_ADDRESS);
+                if (!isNullOrEmpty(value)) {
+                    db.setAddress(value);
+                }
+                String role = annotations.value("role");
+                if (!isNullOrEmpty(role)) {
+                    db.setRole(role);
+                }
+
+                // TODO: populate protocols, etc.
+
+                ListResponse resp = ListResponse.newBuilder()
+                        .setType(ListResponse.Type.NONE)
+                        .setDevice(db.build())
+                        .build();
+                responseObserver.onNext(resp);
+            }
+            responseObserver.onCompleted();
+        }
+    }
+
+}
diff --git a/apps/onos-topo/app/src/main/java/org/onosproject/uonos/impl/package-info.java b/apps/onos-topo/app/src/main/java/org/onosproject/uonos/impl/package-info.java
new file mode 100644
index 0000000..f6cee2d
--- /dev/null
+++ b/apps/onos-topo/app/src/main/java/org/onosproject/uonos/impl/package-info.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2015-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 for µONOS integration app.
+ */
+package org.onosproject.uonos.impl;
\ No newline at end of file
diff --git a/tools/build/bazel/generate_workspace.bzl b/tools/build/bazel/generate_workspace.bzl
index 93fc83a..d83a8a7 100644
--- a/tools/build/bazel/generate_workspace.bzl
+++ b/tools/build/bazel/generate_workspace.bzl
@@ -1,4 +1,4 @@
-# ***** This file was auto-generated at Fri, 15 Nov 2019 18:42:10 GMT. Do not edit this file manually. *****
+# ***** This file was auto-generated at Wed, 4 Dec 2019 01:44:21 GMT. Do not edit this file manually. *****
 # ***** Use onos-lib-gen *****
 
 load("//tools/build/bazel:variables.bzl", "ONOS_GROUP_ID", "ONOS_VERSION")
diff --git a/tools/build/bazel/modules.bzl b/tools/build/bazel/modules.bzl
index 3a37146..92b8076 100644
--- a/tools/build/bazel/modules.bzl
+++ b/tools/build/bazel/modules.bzl
@@ -255,6 +255,7 @@
     "//apps/workflow:onos-apps-workflow-oar",
     "//apps/workflow/ofoverlay:onos-apps-workflow-ofoverlay-oar",
     "//apps/packet-throttle:onos-apps-packet-throttle-oar",
+    "//apps/onos-topo:onos-apps-onos-topo-oar",
 ]
 
 PROTOCOL_APPS = [
diff --git a/tools/build/bazel/topo_BUILD b/tools/build/bazel/topo_BUILD
new file mode 100644
index 0000000..9a42836
--- /dev/null
+++ b/tools/build/bazel/topo_BUILD
@@ -0,0 +1,21 @@
+# Prefix string to remove from proto import statements
+IMPORT_PREFIX = "github.com/onosproject/onos-topo/api/"
+
+proto_library(
+    name = "topo_device_proto",
+    srcs = [":topo_device_proto_sed"],
+    deps = [
+        "@com_google_protobuf//:descriptor_proto",
+        "@com_google_protobuf//:duration_proto",
+        "@com_google_protobuf//:any_proto",
+    ],
+    visibility = ["//visibility:public"],
+)
+
+genrule(
+    name = "topo_device_proto_sed",
+    srcs = [":device/device.proto"],
+    outs = ["new/device/device.proto"],
+    cmd = "sed -e 's:import \"gogoproto.*;::g;s: ..gogoproto\..*:;:g;s:import \"%s:import \":g;s:^syntax = \"proto3\";:&\\\n  option java_package = \"org.onosproject.uonos\";:g' $(location :device/device.proto) >> \"$@\""
+        % IMPORT_PREFIX,
+)
diff --git a/tools/build/bazel/topo_workspace.bzl b/tools/build/bazel/topo_workspace.bzl
new file mode 100644
index 0000000..24aa004
--- /dev/null
+++ b/tools/build/bazel/topo_workspace.bzl
@@ -0,0 +1,13 @@
+load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive")
+
+TOPO_COMMIT = "8866b0a658247683bd4b852839ce91c6ba60f6ac"
+TOPO_SHA = "dc63356c3d34de18b0afdf04cce01f6de83e2b7264de177e55c0595b05dbcd07"
+
+def generate_topo_device():
+    http_archive(
+        name = "com_github_onosproject_onos_topo",
+        urls = ["https://github.com/onosproject/onos-topo/archive/%s.zip" % TOPO_COMMIT],
+        sha256 = TOPO_SHA,
+        strip_prefix = "onos-topo-%s/api" % TOPO_COMMIT,
+        build_file = "//tools/build/bazel:topo_BUILD",
+    )