From 4d420a4b4df00f09f0ecc1331e5e3ddc8dccb7b8 Mon Sep 17 00:00:00 2001 From: Aleksandar Seovic Date: Wed, 20 May 2020 05:45:50 -0400 Subject: [PATCH 1/4] Publish snapshots to Synoki Nexus --- .github/maven/synoki.xml | 49 ++++++++++++++++++++++++++++++++++++ .github/workflows/build.yaml | 34 +++++++++++++++++++++++++ 2 files changed, 83 insertions(+) create mode 100644 .github/maven/synoki.xml create mode 100644 .github/workflows/build.yaml diff --git a/.github/maven/synoki.xml b/.github/maven/synoki.xml new file mode 100644 index 00000000000..e20be43bc0a --- /dev/null +++ b/.github/maven/synoki.xml @@ -0,0 +1,49 @@ + + + + + synoki-nexus + ${env.MAVEN_USER} + ${env.MAVEN_PASSWORD} + + + + + + default + + + synoki-nexus + https://nexus.synoki.io/repository/maven/ + + true + never + + + true + always + + + + + + synoki-nexus + https://nexus.synoki.io/repository/maven/ + + true + never + + + true + always + + + + + + + + default + + + diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml new file mode 100644 index 00000000000..a52f6c3c27f --- /dev/null +++ b/.github/workflows/build.yaml @@ -0,0 +1,34 @@ +# This workflow will build a Java project with Maven +# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven + +name: Java CI with Maven + +on: + push: + branches: [ master ] + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + + - name: Set up Java 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + + - name: Cache Maven packages + uses: actions/cache@v1 + with: + path: ~/.m2 + key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} + restore-keys: ${{ runner.os }}-m2 + + - name: Build with Maven + env: + MAVEN_USER: ${{ secrets.MavenUser }} + MAVEN_PASSWORD: ${{ secrets.MavenPassword }} + run: mvn -B deploy --file pom.xml -DskipTests -s .github/maven/synoki.xml -DaltDeploymentRepository=synoki-nexus::default::https://nexus.synoki.io/repository/maven-snapshots/ From 8fab4d16c2f094432900020897d1898e2a09bec1 Mon Sep 17 00:00:00 2001 From: Aleks Seovic Date: Tue, 2 Mar 2021 02:53:41 -0500 Subject: [PATCH 2/4] gRPC reflection support --- .../grpc/server/BindableServiceImpl.java | 11 +- .../helidon/grpc/server/GrpcServerImpl.java | 3 +- .../grpc/server/ProtoReflectionService.java | 579 ++++++++++++++++++ .../grpc/server/ServiceDescriptor.java | 23 +- 4 files changed, 610 insertions(+), 6 deletions(-) create mode 100644 grpc/server/src/main/java/io/helidon/grpc/server/ProtoReflectionService.java diff --git a/grpc/server/src/main/java/io/helidon/grpc/server/BindableServiceImpl.java b/grpc/server/src/main/java/io/helidon/grpc/server/BindableServiceImpl.java index e294c7813a8..c66dd11819c 100644 --- a/grpc/server/src/main/java/io/helidon/grpc/server/BindableServiceImpl.java +++ b/grpc/server/src/main/java/io/helidon/grpc/server/BindableServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -33,6 +33,7 @@ import io.grpc.ServerCallHandler; import io.grpc.ServerInterceptor; import io.grpc.ServerServiceDefinition; +import io.grpc.protobuf.ProtoFileDescriptorSupplier; import io.grpc.stub.StreamObserver; /** @@ -72,8 +73,14 @@ static BindableServiceImpl create(ServiceDescriptor descriptor, PriorityBag serviceDescriptorBuilder.addMethod(method.descriptor())); + ServerServiceDefinition.Builder builder = ServerServiceDefinition.builder(serviceDescriptorBuilder.build()); descriptor.methods() .forEach(method -> builder.addMethod(method.descriptor(), wrapCallHandler(method))); diff --git a/grpc/server/src/main/java/io/helidon/grpc/server/GrpcServerImpl.java b/grpc/server/src/main/java/io/helidon/grpc/server/GrpcServerImpl.java index 032124bcb7b..87f6d46a06f 100644 --- a/grpc/server/src/main/java/io/helidon/grpc/server/GrpcServerImpl.java +++ b/grpc/server/src/main/java/io/helidon/grpc/server/GrpcServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -182,6 +182,7 @@ public CompletionStage start() { server = configureNetty(builder) .directExecutor() .addService(healthService) + .addService(ProtoReflectionService.newInstance()) .fallbackHandlerRegistry(handlerRegistry) .build() .start(); diff --git a/grpc/server/src/main/java/io/helidon/grpc/server/ProtoReflectionService.java b/grpc/server/src/main/java/io/helidon/grpc/server/ProtoReflectionService.java new file mode 100644 index 00000000000..f5463b5a6f7 --- /dev/null +++ b/grpc/server/src/main/java/io/helidon/grpc/server/ProtoReflectionService.java @@ -0,0 +1,579 @@ +/* + * Copyright 2021, Oracle and/or its affiliates. + * Copyright 2016 The gRPC Authors + * + * 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 io.helidon.grpc.server; + +import java.util.ArrayDeque; +import java.util.Collection; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Queue; +import java.util.Set; +import java.util.WeakHashMap; + +import com.google.protobuf.Any; +import com.google.protobuf.DescriptorProtos; +import com.google.protobuf.Descriptors; +import com.google.protobuf.Descriptors.Descriptor; +import com.google.protobuf.Descriptors.FieldDescriptor; +import com.google.protobuf.Descriptors.FileDescriptor; +import com.google.protobuf.Descriptors.MethodDescriptor; +import com.google.protobuf.Descriptors.ServiceDescriptor; +import io.grpc.BindableService; +import io.grpc.InternalServer; +import io.grpc.Server; +import io.grpc.ServerMethodDefinition; +import io.grpc.ServerServiceDefinition; +import io.grpc.Status; +import io.grpc.protobuf.ProtoFileDescriptorSupplier; +import io.grpc.reflection.v1alpha.ErrorResponse; +import io.grpc.reflection.v1alpha.ExtensionNumberResponse; +import io.grpc.reflection.v1alpha.ExtensionRequest; +import io.grpc.reflection.v1alpha.FileDescriptorResponse; +import io.grpc.reflection.v1alpha.ListServiceResponse; +import io.grpc.reflection.v1alpha.ServerReflectionGrpc; +import io.grpc.reflection.v1alpha.ServerReflectionRequest; +import io.grpc.reflection.v1alpha.ServerReflectionResponse; +import io.grpc.reflection.v1alpha.ServiceResponse; +import io.grpc.stub.ServerCallStreamObserver; +import io.grpc.stub.StreamObserver; + +import static io.grpc.MethodDescriptor.MethodType.BIDI_STREAMING; +import static io.grpc.MethodDescriptor.MethodType.CLIENT_STREAMING; +import static io.grpc.MethodDescriptor.MethodType.SERVER_STREAMING; + +/** + * Provides a reflection service for Protobuf services (including the reflection service itself). + * + *

Separately tracks mutable and immutable services. Throws an exception if either group of + * services contains multiple Protobuf files with declarations of the same service, method, type, or + * extension. + */ +public final class ProtoReflectionService extends ServerReflectionGrpc.ServerReflectionImplBase { + + private final Object lock = new Object(); + + private final Map serverReflectionIndexes = new WeakHashMap<>(); + + private ProtoReflectionService() { + } + + /** + * Creates a instance of {@link ProtoReflectionService}. + * @return a service instance + */ + public static BindableService newInstance() { + return new ProtoReflectionService(); + } + + /** + * Retrieves the index for services of the server that dispatches the current call. Computes + * one if not exist. The index is updated if any changes to the server's mutable services are + * detected. A change is any addition or removal in the set of file descriptors attached to the + * mutable services or a change in the service names. + */ + private ServerReflectionIndex getRefreshedIndex() { + synchronized (lock) { + Server server = InternalServer.SERVER_CONTEXT_KEY.get(); + ServerReflectionIndex index = serverReflectionIndexes.get(server); + if (index == null) { + index = + new ServerReflectionIndex(server.getImmutableServices(), server.getMutableServices()); + serverReflectionIndexes.put(server, index); + return index; + } + + Set serverFileDescriptors = new HashSet<>(); + Set serverServiceNames = new HashSet<>(); + List serverMutableServices = server.getMutableServices(); + for (ServerServiceDefinition mutableService : serverMutableServices) { + io.grpc.ServiceDescriptor serviceDescriptor = mutableService.getServiceDescriptor(); + if (serviceDescriptor.getSchemaDescriptor() instanceof ProtoFileDescriptorSupplier) { + String serviceName = serviceDescriptor.getName(); + FileDescriptor fileDescriptor = + ((ProtoFileDescriptorSupplier) serviceDescriptor.getSchemaDescriptor()) + .getFileDescriptor(); + serverFileDescriptors.add(fileDescriptor); + serverServiceNames.add(serviceName); + } + } + + // Replace the index if the underlying mutable services have changed. Check both the file + // descriptors and the service names, because one file descriptor can define multiple + // services. + FileDescriptorIndex mutableServicesIndex = index.getMutableServicesIndex(); + if (!mutableServicesIndex.getServiceFileDescriptors().equals(serverFileDescriptors) + || !mutableServicesIndex.getServiceNames().equals(serverServiceNames)) { + index = + new ServerReflectionIndex(server.getImmutableServices(), serverMutableServices); + serverReflectionIndexes.put(server, index); + } + + return index; + } + } + + @Override + public StreamObserver serverReflectionInfo( + final StreamObserver responseObserver) { + final ServerCallStreamObserver serverCallStreamObserver = + (ServerCallStreamObserver) responseObserver; + ProtoReflectionStreamObserver requestObserver = + new ProtoReflectionStreamObserver(getRefreshedIndex(), serverCallStreamObserver); + serverCallStreamObserver.setOnReadyHandler(requestObserver); + serverCallStreamObserver.disableAutoRequest(); + serverCallStreamObserver.request(1); + return requestObserver; + } + + private static class ProtoReflectionStreamObserver + implements Runnable, StreamObserver { + private final ServerReflectionIndex serverReflectionIndex; + private final ServerCallStreamObserver serverCallStreamObserver; + + private boolean closeAfterSend = false; + private ServerReflectionRequest request; + + ProtoReflectionStreamObserver( + ServerReflectionIndex serverReflectionIndex, + ServerCallStreamObserver serverCallStreamObserver) { + this.serverReflectionIndex = serverReflectionIndex; + this.serverCallStreamObserver = Objects.requireNonNull(serverCallStreamObserver, "observer"); + } + + @Override + public void run() { + if (request != null) { + handleReflectionRequest(); + } + } + + @Override + public void onNext(ServerReflectionRequest request) { + this.request = Objects.requireNonNull(request); + handleReflectionRequest(); + } + + private void handleReflectionRequest() { + if (serverCallStreamObserver.isReady()) { + switch (request.getMessageRequestCase()) { + case FILE_BY_FILENAME: + getFileByName(request); + break; + case FILE_CONTAINING_SYMBOL: + getFileContainingSymbol(request); + break; + case FILE_CONTAINING_EXTENSION: + getFileByExtension(request); + break; + case ALL_EXTENSION_NUMBERS_OF_TYPE: + getAllExtensions(request); + break; + case LIST_SERVICES: + listServices(request); + break; + default: + sendErrorResponse( + request, + Status.Code.UNIMPLEMENTED, + "not implemented " + request.getMessageRequestCase()); + } + request = null; + if (closeAfterSend) { + serverCallStreamObserver.onCompleted(); + } else { + serverCallStreamObserver.request(1); + } + } + } + + @Override + public void onCompleted() { + if (request != null) { + closeAfterSend = true; + } else { + serverCallStreamObserver.onCompleted(); + } + } + + @Override + public void onError(Throwable cause) { + serverCallStreamObserver.onError(cause); + } + + private void getFileByName(ServerReflectionRequest request) { + String name = request.getFileByFilename(); + FileDescriptor fd = serverReflectionIndex.getFileDescriptorByName(name); + if (fd != null) { + serverCallStreamObserver.onNext(createServerReflectionResponse(request, fd)); + } else { + sendErrorResponse(request, Status.Code.NOT_FOUND, "File not found."); + } + } + + private void getFileContainingSymbol(ServerReflectionRequest request) { + String symbol = request.getFileContainingSymbol(); + FileDescriptor fd = serverReflectionIndex.getFileDescriptorBySymbol(symbol); + if (fd != null) { + serverCallStreamObserver.onNext(createServerReflectionResponse(request, fd)); + } else { + getFileContainingSymbolFromServer(request); + } + } + + private void getFileContainingSymbolFromServer(ServerReflectionRequest request) { + Server server = InternalServer.SERVER_CONTEXT_KEY.get(); + String symbol = request.getFileContainingSymbol(); + + try { + ServerServiceDefinition service = server.getServices().stream() + .filter(s -> s.getServiceDescriptor().getName().equals(symbol)) + .findFirst().orElse(null); + + if (service != null) { + sendServiceDetails(request, service, null); + } else { + sendErrorResponse(request, Status.Code.NOT_FOUND, "Symbol not found."); + } + + } catch (Throwable e) { + sendErrorResponse(request, Status.Code.NOT_FOUND, "Symbol not found."); + } + } + + private void sendServiceDetails(ServerReflectionRequest request, + ServerServiceDefinition service, + ServerMethodDefinition method) + throws Descriptors.DescriptorValidationException { + String name = service.getServiceDescriptor().getName(); + var serviceDesc = DescriptorProtos.ServiceDescriptorProto.newBuilder() + .setName(name.substring(name.lastIndexOf('.') + 1)); + Collection> methods = method == null + ? service.getMethods() + : Set.of(method); + for (ServerMethodDefinition m : methods) { + io.grpc.MethodDescriptor md = m.getMethodDescriptor(); + serviceDesc.addMethod(DescriptorProtos.MethodDescriptorProto.newBuilder() + .setName(md.getBareMethodName()) + .setServerStreaming(EnumSet.of(SERVER_STREAMING, BIDI_STREAMING) + .contains(md.getType())) + .setClientStreaming(EnumSet.of(CLIENT_STREAMING, BIDI_STREAMING) + .contains(md.getType())) + .setInputType(Any.getDescriptor().getFullName()) + .setOutputType(Any.getDescriptor().getFullName()) + .build()); + } + + var fileDesc = DescriptorProtos.FileDescriptorProto.newBuilder() + .setPackage(name.substring(0, name.lastIndexOf('.'))) + .addDependency(Any.getDescriptor().getFile().getFullName()) + .addService(serviceDesc).build(); + + serverCallStreamObserver.onNext(createServerReflectionResponse(request, + FileDescriptor.buildFrom(fileDesc, + new FileDescriptor[] {Any.getDescriptor().getFile()}, + true))); + } + + private void getFileByExtension(ServerReflectionRequest request) { + ExtensionRequest extensionRequest = request.getFileContainingExtension(); + String type = extensionRequest.getContainingType(); + int extension = extensionRequest.getExtensionNumber(); + FileDescriptor fd = + serverReflectionIndex.getFileDescriptorByExtensionAndNumber(type, extension); + if (fd != null) { + serverCallStreamObserver.onNext(createServerReflectionResponse(request, fd)); + } else { + sendErrorResponse(request, Status.Code.NOT_FOUND, "Extension not found."); + } + } + + private void getAllExtensions(ServerReflectionRequest request) { + String type = request.getAllExtensionNumbersOfType(); + Set extensions = serverReflectionIndex.getExtensionNumbersOfType(type); + if (extensions != null) { + ExtensionNumberResponse.Builder builder = + ExtensionNumberResponse.newBuilder() + .setBaseTypeName(type) + .addAllExtensionNumber(extensions); + serverCallStreamObserver.onNext( + ServerReflectionResponse.newBuilder() + .setValidHost(request.getHost()) + .setOriginalRequest(request) + .setAllExtensionNumbersResponse(builder) + .build()); + } else { + sendErrorResponse(request, Status.Code.NOT_FOUND, "Type not found."); + } + } + + private void listServices(ServerReflectionRequest request) { + ListServiceResponse.Builder builder = ListServiceResponse.newBuilder(); + for (String serviceName : serverReflectionIndex.getServiceNames()) { + builder.addService(ServiceResponse.newBuilder().setName(serviceName)); + } + Server server = InternalServer.SERVER_CONTEXT_KEY.get(); + for (ServerServiceDefinition def : server.getServices()) { + if (def.getServiceDescriptor().getSchemaDescriptor() == null) { + builder.addService(ServiceResponse.newBuilder().setName(def.getServiceDescriptor().getName())); + } + } + serverCallStreamObserver.onNext( + ServerReflectionResponse.newBuilder() + .setValidHost(request.getHost()) + .setOriginalRequest(request) + .setListServicesResponse(builder) + .build()); + } + + private void sendErrorResponse( + ServerReflectionRequest request, Status.Code code, String message) { + ServerReflectionResponse response = + ServerReflectionResponse.newBuilder() + .setValidHost(request.getHost()) + .setOriginalRequest(request) + .setErrorResponse( + ErrorResponse.newBuilder() + .setErrorCode(code.value()) + .setErrorMessage(message)) + .build(); + serverCallStreamObserver.onNext(response); + } + + private ServerReflectionResponse createServerReflectionResponse( + ServerReflectionRequest request, FileDescriptor fd) { + FileDescriptorResponse.Builder fdRBuilder = FileDescriptorResponse.newBuilder(); + + Set seenFiles = new HashSet<>(); + Queue frontier = new ArrayDeque<>(); + seenFiles.add(fd.getName()); + frontier.add(fd); + while (!frontier.isEmpty()) { + FileDescriptor nextFd = frontier.remove(); + fdRBuilder.addFileDescriptorProto(nextFd.toProto().toByteString()); + for (FileDescriptor dependencyFd : nextFd.getDependencies()) { + if (!seenFiles.contains(dependencyFd.getName())) { + seenFiles.add(dependencyFd.getName()); + frontier.add(dependencyFd); + } + } + } + return ServerReflectionResponse.newBuilder() + .setValidHost(request.getHost()) + .setOriginalRequest(request) + .setFileDescriptorResponse(fdRBuilder) + .build(); + } + } + + /** + * Indexes the server's services and allows lookups of file descriptors by filename, symbol, type, + * and extension number. + * + *

Internally, this stores separate indices for the immutable and mutable services. When + * queried, the immutable service index is checked for a matching value. Only if there is no match + * in the immutable service index are the mutable services checked. + */ + private static final class ServerReflectionIndex { + private final FileDescriptorIndex immutableServicesIndex; + private final FileDescriptorIndex mutableServicesIndex; + + ServerReflectionIndex( + List immutableServices, + List mutableServices) { + immutableServicesIndex = new FileDescriptorIndex(immutableServices); + mutableServicesIndex = new FileDescriptorIndex(mutableServices); + } + + private FileDescriptorIndex getMutableServicesIndex() { + return mutableServicesIndex; + } + + private Set getServiceNames() { + Set immutableServiceNames = immutableServicesIndex.getServiceNames(); + Set mutableServiceNames = mutableServicesIndex.getServiceNames(); + Set serviceNames = + new HashSet<>(immutableServiceNames.size() + mutableServiceNames.size()); + serviceNames.addAll(immutableServiceNames); + serviceNames.addAll(mutableServiceNames); + return serviceNames; + } + + private FileDescriptor getFileDescriptorByName(String name) { + FileDescriptor fd = immutableServicesIndex.getFileDescriptorByName(name); + if (fd == null) { + fd = mutableServicesIndex.getFileDescriptorByName(name); + } + return fd; + } + + private FileDescriptor getFileDescriptorBySymbol(String symbol) { + FileDescriptor fd = immutableServicesIndex.getFileDescriptorBySymbol(symbol); + if (fd == null) { + fd = mutableServicesIndex.getFileDescriptorBySymbol(symbol); + } + return fd; + } + + private FileDescriptor getFileDescriptorByExtensionAndNumber(String type, int extension) { + FileDescriptor fd = + immutableServicesIndex.getFileDescriptorByExtensionAndNumber(type, extension); + if (fd == null) { + fd = mutableServicesIndex.getFileDescriptorByExtensionAndNumber(type, extension); + } + return fd; + } + + private Set getExtensionNumbersOfType(String type) { + Set extensionNumbers = immutableServicesIndex.getExtensionNumbersOfType(type); + if (extensionNumbers == null) { + extensionNumbers = mutableServicesIndex.getExtensionNumbersOfType(type); + } + return extensionNumbers; + } + } + + /** + * Provides a set of methods for answering reflection queries for the file descriptors underlying + * a set of services. Used by {@link ServerReflectionIndex} to separately index immutable and + * mutable services. + */ + private static final class FileDescriptorIndex { + private final Set serviceNames = new HashSet<>(); + private final Set serviceFileDescriptors = new HashSet<>(); + private final Map fileDescriptorsByName = + new HashMap<>(); + private final Map fileDescriptorsBySymbol = + new HashMap<>(); + private final Map> fileDescriptorsByExtensionAndNumber = + new HashMap<>(); + + FileDescriptorIndex(List services) { + Queue fileDescriptorsToProcess = new ArrayDeque<>(); + Set seenFiles = new HashSet<>(); + for (ServerServiceDefinition service : services) { + io.grpc.ServiceDescriptor serviceDescriptor = service.getServiceDescriptor(); + if (serviceDescriptor.getSchemaDescriptor() instanceof ProtoFileDescriptorSupplier) { + FileDescriptor fileDescriptor = + ((ProtoFileDescriptorSupplier) serviceDescriptor.getSchemaDescriptor()) + .getFileDescriptor(); + String serviceName = serviceDescriptor.getName(); + serviceFileDescriptors.add(fileDescriptor); + serviceNames.add(serviceName); + if (!seenFiles.contains(fileDescriptor.getName())) { + seenFiles.add(fileDescriptor.getName()); + fileDescriptorsToProcess.add(fileDescriptor); + } + } + } + + while (!fileDescriptorsToProcess.isEmpty()) { + FileDescriptor currentFd = fileDescriptorsToProcess.remove(); + processFileDescriptor(currentFd); + for (FileDescriptor dependencyFd : currentFd.getDependencies()) { + if (!seenFiles.contains(dependencyFd.getName())) { + seenFiles.add(dependencyFd.getName()); + fileDescriptorsToProcess.add(dependencyFd); + } + } + } + } + + /** + * Returns the file descriptors for the indexed services, but not their dependencies. This is + * used to check if the server's mutable services have changed. + */ + private Set getServiceFileDescriptors() { + return Collections.unmodifiableSet(serviceFileDescriptors); + } + + private Set getServiceNames() { + return Collections.unmodifiableSet(serviceNames); + } + + private FileDescriptor getFileDescriptorByName(String name) { + return fileDescriptorsByName.get(name); + } + + private FileDescriptor getFileDescriptorBySymbol(String symbol) { + return fileDescriptorsBySymbol.get(symbol); + } + + private FileDescriptor getFileDescriptorByExtensionAndNumber(String type, int number) { + if (fileDescriptorsByExtensionAndNumber.containsKey(type)) { + return fileDescriptorsByExtensionAndNumber.get(type).get(number); + } + return null; + } + + private Set getExtensionNumbersOfType(String type) { + if (fileDescriptorsByExtensionAndNumber.containsKey(type)) { + return Collections.unmodifiableSet(fileDescriptorsByExtensionAndNumber.get(type).keySet()); + } + return null; + } + + private void processFileDescriptor(FileDescriptor fd) { + String fdName = fd.getName(); + fileDescriptorsByName.put(fdName, fd); + for (ServiceDescriptor service : fd.getServices()) { + processService(service, fd); + } + for (Descriptor type : fd.getMessageTypes()) { + processType(type, fd); + } + for (FieldDescriptor extension : fd.getExtensions()) { + processExtension(extension, fd); + } + } + + private void processService(ServiceDescriptor service, FileDescriptor fd) { + String serviceName = service.getFullName(); + fileDescriptorsBySymbol.put(serviceName, fd); + for (MethodDescriptor method : service.getMethods()) { + String methodName = method.getFullName(); + fileDescriptorsBySymbol.put(methodName, fd); + } + } + + private void processType(Descriptor type, FileDescriptor fd) { + String typeName = type.getFullName(); + fileDescriptorsBySymbol.put(typeName, fd); + for (FieldDescriptor extension : type.getExtensions()) { + processExtension(extension, fd); + } + for (Descriptor nestedType : type.getNestedTypes()) { + processType(nestedType, fd); + } + } + + private void processExtension(FieldDescriptor extension, FileDescriptor fd) { + String extensionName = extension.getContainingType().getFullName(); + int extensionNumber = extension.getNumber(); + if (!fileDescriptorsByExtensionAndNumber.containsKey(extensionName)) { + fileDescriptorsByExtensionAndNumber.put( + extensionName, new HashMap()); + } + fileDescriptorsByExtensionAndNumber.get(extensionName).put(extensionNumber, fd); + } + } +} diff --git a/grpc/server/src/main/java/io/helidon/grpc/server/ServiceDescriptor.java b/grpc/server/src/main/java/io/helidon/grpc/server/ServiceDescriptor.java index 10f0316ff33..b768017522b 100644 --- a/grpc/server/src/main/java/io/helidon/grpc/server/ServiceDescriptor.java +++ b/grpc/server/src/main/java/io/helidon/grpc/server/ServiceDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019 Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -36,6 +36,7 @@ import io.grpc.ServerInterceptor; import io.grpc.ServerMethodDefinition; import io.grpc.ServerServiceDefinition; +import io.grpc.protobuf.ProtoFileDescriptorSupplier; import io.grpc.stub.ServerCalls; import org.eclipse.microprofile.health.HealthCheck; @@ -56,17 +57,20 @@ public class ServiceDescriptor { private final PriorityBag interceptors; private final Map, Object> context; private final HealthCheck healthCheck; + private final Descriptors.FileDescriptor proto; private ServiceDescriptor(String name, Map methods, PriorityBag interceptors, Map, Object> context, - HealthCheck healthCheck) { + HealthCheck healthCheck, + Descriptors.FileDescriptor proto) { this.name = Objects.requireNonNull(name); this.methods = methods; this.context = Collections.unmodifiableMap(context); this.healthCheck = healthCheck; this.interceptors = interceptors.copyMe(); + this.proto = proto; } /** @@ -119,6 +123,14 @@ public HealthCheck healthCheck() { return healthCheck; } + /** + * Return a proto file descriptor. + * @return a proto file descriptor + */ + public Descriptors.FileDescriptor proto() { + return proto; + } + BindableService bindableService(PriorityBag interceptors) { return BindableServiceImpl.create(this, interceptors); } @@ -457,6 +469,11 @@ public static final class Builder implements Rules, io.helidon.common.Builder Date: Tue, 2 Mar 2021 02:56:25 -0500 Subject: [PATCH 3/4] gRPC reflection support --- .github/maven/synoki.xml | 49 ------------------------------------ .github/workflows/build.yaml | 34 ------------------------- 2 files changed, 83 deletions(-) delete mode 100644 .github/maven/synoki.xml delete mode 100644 .github/workflows/build.yaml diff --git a/.github/maven/synoki.xml b/.github/maven/synoki.xml deleted file mode 100644 index e20be43bc0a..00000000000 --- a/.github/maven/synoki.xml +++ /dev/null @@ -1,49 +0,0 @@ - - - - - synoki-nexus - ${env.MAVEN_USER} - ${env.MAVEN_PASSWORD} - - - - - - default - - - synoki-nexus - https://nexus.synoki.io/repository/maven/ - - true - never - - - true - always - - - - - - synoki-nexus - https://nexus.synoki.io/repository/maven/ - - true - never - - - true - always - - - - - - - - default - - - diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml deleted file mode 100644 index a52f6c3c27f..00000000000 --- a/.github/workflows/build.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# This workflow will build a Java project with Maven -# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven - -name: Java CI with Maven - -on: - push: - branches: [ master ] - -jobs: - build: - - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v2 - - - name: Set up Java 11 - uses: actions/setup-java@v1 - with: - java-version: 11 - - - name: Cache Maven packages - uses: actions/cache@v1 - with: - path: ~/.m2 - key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }} - restore-keys: ${{ runner.os }}-m2 - - - name: Build with Maven - env: - MAVEN_USER: ${{ secrets.MavenUser }} - MAVEN_PASSWORD: ${{ secrets.MavenPassword }} - run: mvn -B deploy --file pom.xml -DskipTests -s .github/maven/synoki.xml -DaltDeploymentRepository=synoki-nexus::default::https://nexus.synoki.io/repository/maven-snapshots/ From 9fef66c8574576405fd9206e9d6f844c824543cb Mon Sep 17 00:00:00 2001 From: Aleks Seovic Date: Thu, 4 Mar 2021 21:47:22 -0500 Subject: [PATCH 4/4] Copyright fixes --- .../main/java/io/helidon/grpc/server/BindableServiceImpl.java | 2 +- .../src/main/java/io/helidon/grpc/server/GrpcServerImpl.java | 2 +- .../java/io/helidon/grpc/server/ProtoReflectionService.java | 2 +- .../src/main/java/io/helidon/grpc/server/ServiceDescriptor.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/grpc/server/src/main/java/io/helidon/grpc/server/BindableServiceImpl.java b/grpc/server/src/main/java/io/helidon/grpc/server/BindableServiceImpl.java index c66dd11819c..aef31a12782 100644 --- a/grpc/server/src/main/java/io/helidon/grpc/server/BindableServiceImpl.java +++ b/grpc/server/src/main/java/io/helidon/grpc/server/BindableServiceImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/grpc/server/src/main/java/io/helidon/grpc/server/GrpcServerImpl.java b/grpc/server/src/main/java/io/helidon/grpc/server/GrpcServerImpl.java index 87f6d46a06f..227f6f28112 100644 --- a/grpc/server/src/main/java/io/helidon/grpc/server/GrpcServerImpl.java +++ b/grpc/server/src/main/java/io/helidon/grpc/server/GrpcServerImpl.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. + * Copyright (c) 2019, 2021 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. diff --git a/grpc/server/src/main/java/io/helidon/grpc/server/ProtoReflectionService.java b/grpc/server/src/main/java/io/helidon/grpc/server/ProtoReflectionService.java index f5463b5a6f7..3185be38aa6 100644 --- a/grpc/server/src/main/java/io/helidon/grpc/server/ProtoReflectionService.java +++ b/grpc/server/src/main/java/io/helidon/grpc/server/ProtoReflectionService.java @@ -1,5 +1,5 @@ /* - * Copyright 2021, Oracle and/or its affiliates. + * Copyright 2021 Oracle and/or its affiliates. * Copyright 2016 The gRPC Authors * * Licensed under the Apache License, Version 2.0 (the "License"); diff --git a/grpc/server/src/main/java/io/helidon/grpc/server/ServiceDescriptor.java b/grpc/server/src/main/java/io/helidon/grpc/server/ServiceDescriptor.java index b768017522b..c2616f3d024 100644 --- a/grpc/server/src/main/java/io/helidon/grpc/server/ServiceDescriptor.java +++ b/grpc/server/src/main/java/io/helidon/grpc/server/ServiceDescriptor.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 2019, 2021 Oracle and/or its affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License.