[3.0-Triple] Support reflection api (#10168)
* Add proto * Update compiler * Add v1Alpha for compatibility * Abstract builtin service export * Try add get fd by name * get service by symbol now works * Add type * Support extension * Ignore reflection code scan * Remove v1
This commit is contained in:
parent
bf882c1883
commit
47f7be2fd6
|
|
@ -72,22 +72,25 @@ public abstract class AbstractGenerator extends Generator {
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<PluginProtos.CodeGeneratorResponse.File> generateFiles(PluginProtos.CodeGeneratorRequest request) throws GeneratorException {
|
||||
public List<PluginProtos.CodeGeneratorResponse.File> generateFiles(
|
||||
PluginProtos.CodeGeneratorRequest request) throws GeneratorException {
|
||||
final ProtoTypeMap typeMap = ProtoTypeMap.of(request.getProtoFileList());
|
||||
|
||||
List<FileDescriptorProto> protosToGenerate = request.getProtoFileList().stream()
|
||||
.filter(protoFile -> request.getFileToGenerateList().contains(protoFile.getName()))
|
||||
.collect(Collectors.toList());
|
||||
.filter(protoFile -> request.getFileToGenerateList().contains(protoFile.getName()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
List<ServiceContext> services = findServices(protosToGenerate, typeMap);
|
||||
return generateFiles(services);
|
||||
}
|
||||
|
||||
private List<ServiceContext> findServices(List<FileDescriptorProto> protos, ProtoTypeMap typeMap) {
|
||||
private List<ServiceContext> findServices(List<FileDescriptorProto> protos,
|
||||
ProtoTypeMap typeMap) {
|
||||
List<ServiceContext> contexts = new ArrayList<>();
|
||||
|
||||
protos.forEach(fileProto -> {
|
||||
for (int serviceNumber = 0; serviceNumber < fileProto.getServiceCount(); serviceNumber++) {
|
||||
for (int serviceNumber = 0; serviceNumber < fileProto.getServiceCount();
|
||||
serviceNumber++) {
|
||||
ServiceContext serviceContext = buildServiceContext(
|
||||
fileProto.getService(serviceNumber),
|
||||
typeMap,
|
||||
|
|
@ -96,8 +99,12 @@ public abstract class AbstractGenerator extends Generator {
|
|||
);
|
||||
serviceContext.protoName = fileProto.getName();
|
||||
serviceContext.packageName = extractPackageName(fileProto);
|
||||
if (!Strings.isNullOrEmpty(fileProto.getOptions().getJavaOuterClassname())) {
|
||||
serviceContext.outerClassName = fileProto.getOptions().getJavaOuterClassname();
|
||||
}
|
||||
serviceContext.commonPackageName = extractCommonPackageName(fileProto);
|
||||
serviceContext.multipleFiles = fileProto.getOptions() != null && fileProto.getOptions().getJavaMultipleFiles();
|
||||
serviceContext.multipleFiles =
|
||||
fileProto.getOptions() != null && fileProto.getOptions().getJavaMultipleFiles();
|
||||
contexts.add(serviceContext);
|
||||
}
|
||||
});
|
||||
|
|
@ -121,15 +128,18 @@ public abstract class AbstractGenerator extends Generator {
|
|||
return Strings.nullToEmpty(proto.getPackage());
|
||||
}
|
||||
|
||||
private ServiceContext buildServiceContext(ServiceDescriptorProto serviceProto, ProtoTypeMap typeMap, List<Location> locations, int serviceNumber) {
|
||||
private ServiceContext buildServiceContext(ServiceDescriptorProto serviceProto,
|
||||
ProtoTypeMap typeMap, List<Location> locations, int serviceNumber) {
|
||||
ServiceContext serviceContext = new ServiceContext();
|
||||
serviceContext.fileName = getClassPrefix() + serviceProto.getName() + getClassSuffix() + ".java";
|
||||
serviceContext.fileName =
|
||||
getClassPrefix() + serviceProto.getName() + getClassSuffix() + ".java";
|
||||
serviceContext.className = getClassPrefix() + serviceProto.getName() + getClassSuffix();
|
||||
|
||||
serviceContext.outerClassName = serviceProto.getName() + "OuterClass";
|
||||
serviceContext.interfaceFileName = serviceProto.getName() + ".java";
|
||||
serviceContext.interfaceClassName = serviceProto.getName();
|
||||
serviceContext.serviceName = serviceProto.getName();
|
||||
serviceContext.deprecated = serviceProto.getOptions() != null && serviceProto.getOptions().getDeprecated();
|
||||
serviceContext.deprecated =
|
||||
serviceProto.getOptions() != null && serviceProto.getOptions().getDeprecated();
|
||||
|
||||
List<Location> allLocationsForService = locations.stream()
|
||||
.filter(location ->
|
||||
|
|
@ -143,7 +153,8 @@ public abstract class AbstractGenerator extends Generator {
|
|||
.filter(location -> location.getPathCount() == SERVICE_NUMBER_OF_PATHS)
|
||||
.findFirst()
|
||||
.orElseGet(Location::getDefaultInstance);
|
||||
serviceContext.javaDoc = getJavaDoc(getComments(serviceLocation), getServiceJavaDocPrefix());
|
||||
serviceContext.javaDoc = getJavaDoc(getComments(serviceLocation),
|
||||
getServiceJavaDocPrefix());
|
||||
|
||||
for (int methodNumber = 0; methodNumber < serviceProto.getMethodCount(); methodNumber++) {
|
||||
MethodContext methodContext = buildMethodContext(
|
||||
|
|
@ -160,13 +171,15 @@ public abstract class AbstractGenerator extends Generator {
|
|||
return serviceContext;
|
||||
}
|
||||
|
||||
private MethodContext buildMethodContext(MethodDescriptorProto methodProto, ProtoTypeMap typeMap, List<Location> locations, int methodNumber) {
|
||||
private MethodContext buildMethodContext(MethodDescriptorProto methodProto,
|
||||
ProtoTypeMap typeMap, List<Location> locations, int methodNumber) {
|
||||
MethodContext methodContext = new MethodContext();
|
||||
methodContext.originMethodName = methodProto.getName();
|
||||
methodContext.methodName = lowerCaseFirst(methodProto.getName());
|
||||
methodContext.inputType = typeMap.toJavaTypeName(methodProto.getInputType());
|
||||
methodContext.outputType = typeMap.toJavaTypeName(methodProto.getOutputType());
|
||||
methodContext.deprecated = methodProto.getOptions() != null && methodProto.getOptions().getDeprecated();
|
||||
methodContext.deprecated =
|
||||
methodProto.getOptions() != null && methodProto.getOptions().getDeprecated();
|
||||
methodContext.isManyInput = methodProto.getClientStreaming();
|
||||
methodContext.isManyOutput = methodProto.getServerStreaming();
|
||||
methodContext.methodNumber = methodNumber;
|
||||
|
|
@ -203,7 +216,8 @@ public abstract class AbstractGenerator extends Generator {
|
|||
return Character.toLowerCase(s.charAt(0)) + s.substring(1);
|
||||
}
|
||||
|
||||
private List<PluginProtos.CodeGeneratorResponse.File> generateFiles(List<ServiceContext> services) {
|
||||
private List<PluginProtos.CodeGeneratorResponse.File> generateFiles(
|
||||
List<ServiceContext> services) {
|
||||
List<PluginProtos.CodeGeneratorResponse.File> allServiceFiles = new ArrayList<>();
|
||||
for (ServiceContext context : services) {
|
||||
List<PluginProtos.CodeGeneratorResponse.File> files = buildFile(context);
|
||||
|
|
@ -212,7 +226,7 @@ public abstract class AbstractGenerator extends Generator {
|
|||
return allServiceFiles;
|
||||
}
|
||||
|
||||
protected boolean enableMultipleTemplateFiles(){
|
||||
protected boolean enableMultipleTemplateFiles() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -266,7 +280,8 @@ public abstract class AbstractGenerator extends Generator {
|
|||
}
|
||||
|
||||
private String getComments(Location location) {
|
||||
return location.getLeadingComments().isEmpty() ? location.getTrailingComments() : location.getLeadingComments();
|
||||
return location.getLeadingComments().isEmpty() ? location.getTrailingComments()
|
||||
: location.getLeadingComments();
|
||||
}
|
||||
|
||||
private String getJavaDoc(String comments, String prefix) {
|
||||
|
|
@ -288,6 +303,7 @@ public abstract class AbstractGenerator extends Generator {
|
|||
* Template class for proto Service objects.
|
||||
*/
|
||||
private class ServiceContext {
|
||||
|
||||
// CHECKSTYLE DISABLE VisibilityModifier FOR 8 LINES
|
||||
public String fileName;
|
||||
public String interfaceFileName;
|
||||
|
|
@ -300,6 +316,8 @@ public abstract class AbstractGenerator extends Generator {
|
|||
public boolean deprecated;
|
||||
public String javaDoc;
|
||||
public boolean multipleFiles;
|
||||
|
||||
public String outerClassName;
|
||||
public List<MethodContext> methods = new ArrayList<>();
|
||||
|
||||
public Set<String> methodTypes = new HashSet<>();
|
||||
|
|
@ -309,11 +327,13 @@ public abstract class AbstractGenerator extends Generator {
|
|||
}
|
||||
|
||||
public List<MethodContext> unaryMethods() {
|
||||
return methods.stream().filter(m -> (!m.isManyInput && !m.isManyOutput)).collect(Collectors.toList());
|
||||
return methods.stream().filter(m -> (!m.isManyInput && !m.isManyOutput))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<MethodContext> serverStreamingMethods() {
|
||||
return methods.stream().filter(m -> !m.isManyInput && m.isManyOutput).collect(Collectors.toList());
|
||||
return methods.stream().filter(m -> !m.isManyInput && m.isManyOutput)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<MethodContext> biStreamingMethods() {
|
||||
|
|
@ -321,11 +341,13 @@ public abstract class AbstractGenerator extends Generator {
|
|||
}
|
||||
|
||||
public List<MethodContext> biStreamingWithoutClientStreamMethods() {
|
||||
return methods.stream().filter(m->m.isManyInput&&m.isManyOutput).collect(Collectors.toList());
|
||||
return methods.stream().filter(m -> m.isManyInput && m.isManyOutput)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<MethodContext> clientStreamingMethods() {
|
||||
return methods.stream().filter(m->m.isManyInput&&!m.isManyOutput).collect(Collectors.toList());
|
||||
return methods.stream().filter(m -> m.isManyInput && !m.isManyOutput)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public List<MethodContext> methods() {
|
||||
|
|
@ -338,6 +360,7 @@ public abstract class AbstractGenerator extends Generator {
|
|||
* Template class for proto RPC objects.
|
||||
*/
|
||||
private class MethodContext {
|
||||
|
||||
// CHECKSTYLE DISABLE VisibilityModifier FOR 10 LINES
|
||||
public String originMethodName;
|
||||
public String methodName;
|
||||
|
|
@ -358,7 +381,8 @@ public abstract class AbstractGenerator extends Generator {
|
|||
for (int i = 0; i < methodName.length(); i++) {
|
||||
char c = methodName.charAt(i);
|
||||
s.append(Character.toUpperCase(c));
|
||||
if ((i < methodName.length() - 1) && Character.isLowerCase(c) && Character.isUpperCase(methodName.charAt(i + 1))) {
|
||||
if ((i < methodName.length() - 1) && Character.isLowerCase(c)
|
||||
&& Character.isUpperCase(methodName.charAt(i + 1))) {
|
||||
s.append('_');
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ public final class {{className}} {
|
|||
private static final StubServiceDescriptor serviceDescriptor = new StubServiceDescriptor(SERVICE_NAME,{{interfaceClassName}}.class);
|
||||
|
||||
static {
|
||||
org.apache.dubbo.rpc.protocol.tri.service.SchemaDescriptorRegistry.addSchemaDescriptor(SERVICE_NAME,{{outerClassName}}.getDescriptor());
|
||||
StubSuppliers.addSupplier(SERVICE_NAME, {{className}}::newStub);
|
||||
StubSuppliers.addSupplier({{interfaceClassName}}.JAVA_SERVICE_NAME, {{className}}::newStub);
|
||||
StubSuppliers.addDescriptor(SERVICE_NAME, serviceDescriptor);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,6 @@ public class StubSuppliers {
|
|||
public static void addDescriptor(String interfaceName, ServiceDescriptor serviceDescriptor) {
|
||||
SERVICE_DESCRIPTOR_MAP.put(interfaceName, serviceDescriptor);
|
||||
}
|
||||
|
||||
public static void addSupplier(String interfaceName, Function<Invoker<?>, Object> supplier) {
|
||||
STUB_SUPPLIERS.put(interfaceName, supplier);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,202 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.dubbo.rpc.protocol.tri.service;
|
||||
|
||||
import org.apache.dubbo.common.stream.StreamObserver;
|
||||
import org.apache.dubbo.rpc.TriRpcStatus;
|
||||
|
||||
import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
import io.grpc.reflection.v1alpha.DubboServerReflectionTriple;
|
||||
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.ServerReflectionRequest;
|
||||
import io.grpc.reflection.v1alpha.ServerReflectionResponse;
|
||||
import io.grpc.reflection.v1alpha.ServiceResponse;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.HashSet;
|
||||
import java.util.Queue;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Provides a reflection service for Protobuf service for service test and dynamic gateway.
|
||||
*
|
||||
* @link https://github.com/grpc/grpc/blob/master/doc/server-reflection.md
|
||||
*/
|
||||
public class ReflectionV1AlphaService extends DubboServerReflectionTriple.ServerReflectionImplBase {
|
||||
|
||||
|
||||
@Override
|
||||
public StreamObserver<ServerReflectionRequest> serverReflectionInfo(
|
||||
StreamObserver<ServerReflectionResponse> responseObserver) {
|
||||
return new StreamObserver<ServerReflectionRequest>() {
|
||||
@Override
|
||||
public void onNext(ServerReflectionRequest request) {
|
||||
switch (request.getMessageRequestCase()) {
|
||||
case FILE_BY_FILENAME:
|
||||
getFileByName(request, responseObserver);
|
||||
break;
|
||||
case FILE_CONTAINING_SYMBOL:
|
||||
getFileContainingSymbol(request, responseObserver);
|
||||
break;
|
||||
case FILE_CONTAINING_EXTENSION:
|
||||
getFileByExtension(request, responseObserver);
|
||||
break;
|
||||
case ALL_EXTENSION_NUMBERS_OF_TYPE:
|
||||
getAllExtensions(request, responseObserver);
|
||||
break;
|
||||
case LIST_SERVICES:
|
||||
listServices(request, responseObserver);
|
||||
break;
|
||||
default:
|
||||
sendErrorResponse(
|
||||
request,
|
||||
TriRpcStatus.Code.UNIMPLEMENTED,
|
||||
"not implemented " + request.getMessageRequestCase(), responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Throwable throwable) {
|
||||
responseObserver.onError(throwable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCompleted() {
|
||||
responseObserver.onCompleted();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private void getFileByName(ServerReflectionRequest request,
|
||||
StreamObserver<ServerReflectionResponse> responseObserver) {
|
||||
String name = request.getFileByFilename();
|
||||
FileDescriptor fd = SchemaDescriptorRegistry.getSchemaDescriptor(name);
|
||||
if (fd != null) {
|
||||
responseObserver.onNext(createServerReflectionResponse(request, fd));
|
||||
} else {
|
||||
sendErrorResponse(request, TriRpcStatus.Code.NOT_FOUND, "File not found.",
|
||||
responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
private void getFileContainingSymbol(ServerReflectionRequest request,
|
||||
StreamObserver<ServerReflectionResponse> responseObserver) {
|
||||
String symbol = request.getFileContainingSymbol();
|
||||
FileDescriptor fd = SchemaDescriptorRegistry.getSchemaDescriptor(symbol);
|
||||
if (fd != null) {
|
||||
responseObserver.onNext(createServerReflectionResponse(request, fd));
|
||||
} else {
|
||||
sendErrorResponse(request, TriRpcStatus.Code.NOT_FOUND, "Symbol not found.",
|
||||
responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
private void getFileByExtension(ServerReflectionRequest request,
|
||||
StreamObserver<ServerReflectionResponse> responseObserver) {
|
||||
ExtensionRequest extensionRequest = request.getFileContainingExtension();
|
||||
String type = extensionRequest.getContainingType();
|
||||
int extension = extensionRequest.getExtensionNumber();
|
||||
FileDescriptor fd =
|
||||
SchemaDescriptorRegistry.getFileDescriptorByExtensionAndNumber(type, extension);
|
||||
if (fd != null) {
|
||||
responseObserver.onNext(createServerReflectionResponse(request, fd));
|
||||
} else {
|
||||
sendErrorResponse(request, TriRpcStatus.Code.NOT_FOUND, "Extension not found.",
|
||||
responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
private void getAllExtensions(ServerReflectionRequest request,
|
||||
StreamObserver<ServerReflectionResponse> responseObserver) {
|
||||
String type = request.getAllExtensionNumbersOfType();
|
||||
Set<Integer> extensions = SchemaDescriptorRegistry.getExtensionNumbers(type);
|
||||
if (extensions != null) {
|
||||
ExtensionNumberResponse.Builder builder =
|
||||
ExtensionNumberResponse.newBuilder()
|
||||
.setBaseTypeName(type)
|
||||
.addAllExtensionNumber(extensions);
|
||||
responseObserver.onNext(
|
||||
ServerReflectionResponse.newBuilder()
|
||||
.setValidHost(request.getHost())
|
||||
.setOriginalRequest(request)
|
||||
.setAllExtensionNumbersResponse(builder)
|
||||
.build());
|
||||
} else {
|
||||
sendErrorResponse(request, TriRpcStatus.Code.NOT_FOUND, "Type not found.",
|
||||
responseObserver);
|
||||
}
|
||||
}
|
||||
|
||||
private void listServices(ServerReflectionRequest request,
|
||||
StreamObserver<ServerReflectionResponse> responseObserver) {
|
||||
ListServiceResponse.Builder builder = ListServiceResponse.newBuilder();
|
||||
|
||||
for (String serviceName : SchemaDescriptorRegistry.listServiceNames()) {
|
||||
builder.addService(ServiceResponse.newBuilder().setName(serviceName));
|
||||
}
|
||||
responseObserver.onNext(
|
||||
ServerReflectionResponse.newBuilder()
|
||||
.setValidHost(request.getHost())
|
||||
.setOriginalRequest(request)
|
||||
.setListServicesResponse(builder)
|
||||
.build());
|
||||
}
|
||||
|
||||
private void sendErrorResponse(
|
||||
ServerReflectionRequest request, TriRpcStatus.Code code, String message,
|
||||
StreamObserver<ServerReflectionResponse> responseObserver) {
|
||||
ServerReflectionResponse response =
|
||||
ServerReflectionResponse.newBuilder()
|
||||
.setValidHost(request.getHost())
|
||||
.setOriginalRequest(request)
|
||||
.setErrorResponse(
|
||||
ErrorResponse.newBuilder()
|
||||
.setErrorCode(code.code)
|
||||
.setErrorMessage(message))
|
||||
.build();
|
||||
responseObserver.onNext(response);
|
||||
}
|
||||
|
||||
private ServerReflectionResponse createServerReflectionResponse(
|
||||
ServerReflectionRequest request, FileDescriptor fd) {
|
||||
FileDescriptorResponse.Builder fdRBuilder = FileDescriptorResponse.newBuilder();
|
||||
Set<String> seenFiles = new HashSet<>();
|
||||
Queue<FileDescriptor> 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();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
/*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one or more
|
||||
* contributor license agreements. See the NOTICE file distributed with
|
||||
* this work for additional information regarding copyright ownership.
|
||||
* The ASF licenses this file to You 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.apache.dubbo.rpc.protocol.tri.service;
|
||||
|
||||
import com.google.protobuf.Descriptors.Descriptor;
|
||||
import com.google.protobuf.Descriptors.FieldDescriptor;
|
||||
import com.google.protobuf.Descriptors.FileDescriptor;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class SchemaDescriptorRegistry {
|
||||
|
||||
private static final Map<String, FileDescriptor> DESCRIPTORS_BY_SYMBOL = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Map<String, Map<Integer, FileDescriptor>> EXTENSIONS = new ConcurrentHashMap<>();
|
||||
|
||||
private static final Set<String> SERVICES = new HashSet<>();
|
||||
|
||||
public static void addSchemaDescriptor(String serviceName, FileDescriptor fd) {
|
||||
SERVICES.add(serviceName);
|
||||
DESCRIPTORS_BY_SYMBOL.put(serviceName, fd);
|
||||
for (Descriptor messageType : fd.getMessageTypes()) {
|
||||
addType(messageType);
|
||||
}
|
||||
for (FieldDescriptor extension : fd.getExtensions()) {
|
||||
addExtension(extension, fd);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addType(Descriptor descriptor) {
|
||||
DESCRIPTORS_BY_SYMBOL.put(descriptor.getFullName(), descriptor.getFile());
|
||||
for (Descriptor nestedType : descriptor.getNestedTypes()) {
|
||||
addType(nestedType);
|
||||
}
|
||||
}
|
||||
|
||||
private static void addExtension(FieldDescriptor extension, FileDescriptor fd) {
|
||||
String name = extension.getContainingType().getFullName();
|
||||
int number = extension.getNumber();
|
||||
if (!EXTENSIONS.containsKey(name)) {
|
||||
EXTENSIONS.put(name, new HashMap<>());
|
||||
}
|
||||
Map<Integer, FileDescriptor> fdMap = EXTENSIONS.get(name);
|
||||
fdMap.put(number, fd);
|
||||
}
|
||||
|
||||
public static FileDescriptor getFileDescriptorByExtensionAndNumber(String extension,
|
||||
int number) {
|
||||
return EXTENSIONS.getOrDefault(extension, Collections.emptyMap()).get(number);
|
||||
}
|
||||
|
||||
public static Set<Integer> getExtensionNumbers(String extension) {
|
||||
Map<Integer, FileDescriptor> ret = EXTENSIONS.get(extension);
|
||||
if (ret == null) {
|
||||
return null;
|
||||
} else {
|
||||
return ret.keySet();
|
||||
}
|
||||
}
|
||||
|
||||
public static FileDescriptor getSchemaDescriptor(String serviceName) {
|
||||
return DESCRIPTORS_BY_SYMBOL.get(serviceName);
|
||||
}
|
||||
|
||||
public static List<String> listServiceNames() {
|
||||
return new ArrayList<>(SERVICES);
|
||||
}
|
||||
}
|
||||
|
|
@ -24,6 +24,7 @@ import org.apache.dubbo.rpc.PathResolver;
|
|||
import org.apache.dubbo.rpc.ProxyFactory;
|
||||
import org.apache.dubbo.rpc.model.ApplicationModel;
|
||||
import org.apache.dubbo.rpc.model.FrameworkModel;
|
||||
import org.apache.dubbo.rpc.model.ModuleModel;
|
||||
|
||||
import io.grpc.health.v1.DubboHealthTriple;
|
||||
import io.grpc.health.v1.Health;
|
||||
|
|
@ -44,6 +45,7 @@ public class TriBuiltinService {
|
|||
|
||||
private final Health healthService;
|
||||
|
||||
private final ReflectionV1AlphaService reflectionServiceV1Alpha;
|
||||
private final HealthStatusManager healthStatusManager;
|
||||
|
||||
private final AtomicBoolean init = new AtomicBoolean();
|
||||
|
|
@ -51,6 +53,7 @@ public class TriBuiltinService {
|
|||
public TriBuiltinService(FrameworkModel frameworkModel) {
|
||||
healthStatusManager = new HealthStatusManager(new TriHealthImpl());
|
||||
healthService = healthStatusManager.getHealthService();
|
||||
reflectionServiceV1Alpha = new ReflectionV1AlphaService();
|
||||
proxyFactory = frameworkModel.getExtensionLoader(ProxyFactory.class).getAdaptiveExtension();
|
||||
pathResolver = frameworkModel.getExtensionLoader(PathResolver.class).getDefaultExtension();
|
||||
init();
|
||||
|
|
@ -58,17 +61,23 @@ public class TriBuiltinService {
|
|||
|
||||
public void init() {
|
||||
if (init.compareAndSet(false, true)) {
|
||||
URL url = new ServiceConfigURL(CommonConstants.TRIPLE, null, null, ANYHOST_VALUE, 0,
|
||||
DubboHealthTriple.SERVICE_NAME)
|
||||
.addParameter(PROXY_KEY, CommonConstants.NATIVE_STUB)
|
||||
.setScopeModel(ApplicationModel.defaultModel().getInternalModule());
|
||||
Invoker<?> invoker = proxyFactory.getInvoker(healthService, Health.class, url);
|
||||
pathResolver.add(DubboHealthTriple.SERVICE_NAME, invoker);
|
||||
ApplicationModel.defaultModel().getInternalModule()
|
||||
.addDestroyListener(scopeModel -> pathResolver.remove(DubboHealthTriple.SERVICE_NAME));
|
||||
addSingleBuiltinService(DubboHealthTriple.SERVICE_NAME, healthService, Health.class);
|
||||
addSingleBuiltinService(ReflectionV1AlphaService.SERVICE_NAME, reflectionServiceV1Alpha,
|
||||
ReflectionV1AlphaService.class);
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void addSingleBuiltinService(String serviceName, T impl, Class<T> interfaceClass) {
|
||||
ModuleModel internalModule = ApplicationModel.defaultModel().getInternalModule();
|
||||
URL url = new ServiceConfigURL(CommonConstants.TRIPLE, null, null, ANYHOST_VALUE, 0,
|
||||
serviceName)
|
||||
.addParameter(PROXY_KEY, CommonConstants.NATIVE_STUB)
|
||||
.setScopeModel(internalModule);
|
||||
Invoker<?> invoker = proxyFactory.getInvoker(impl, interfaceClass, url);
|
||||
pathResolver.add(serviceName, invoker);
|
||||
internalModule.addDestroyListener(scopeModel -> pathResolver.remove(serviceName));
|
||||
}
|
||||
|
||||
public HealthStatusManager getHealthStatusManager() {
|
||||
return healthStatusManager;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
// 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.
|
||||
// Service exported by server reflection
|
||||
|
||||
|
||||
// Warning: this entire file is deprecated. Use this instead:
|
||||
// https://github.com/grpc/grpc-proto/blob/master/grpc/reflection/v1/reflection.proto
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package grpc.reflection.v1alpha;
|
||||
|
||||
option deprecated = true;
|
||||
option java_multiple_files = true;
|
||||
option java_package = "io.grpc.reflection.v1alpha";
|
||||
option java_outer_classname = "ServerReflectionProto";
|
||||
|
||||
service ServerReflection {
|
||||
// The reflection service is structured as a bidirectional stream, ensuring
|
||||
// all related requests go to a single server.
|
||||
rpc ServerReflectionInfo(stream ServerReflectionRequest)
|
||||
returns (stream ServerReflectionResponse);
|
||||
}
|
||||
|
||||
// The message sent by the client when calling ServerReflectionInfo method.
|
||||
message ServerReflectionRequest {
|
||||
string host = 1;
|
||||
// To use reflection service, the client should set one of the following
|
||||
// fields in message_request. The server distinguishes requests by their
|
||||
// defined field and then handles them using corresponding methods.
|
||||
oneof message_request {
|
||||
// Find a proto file by the file name.
|
||||
string file_by_filename = 3;
|
||||
|
||||
// Find the proto file that declares the given fully-qualified symbol name.
|
||||
// This field should be a fully-qualified symbol name
|
||||
// (e.g. <package>.<service>[.<method>] or <package>.<type>).
|
||||
string file_containing_symbol = 4;
|
||||
|
||||
// Find the proto file which defines an extension extending the given
|
||||
// message type with the given field number.
|
||||
ExtensionRequest file_containing_extension = 5;
|
||||
|
||||
// Finds the tag numbers used by all known extensions of extendee_type, and
|
||||
// appends them to ExtensionNumberResponse in an undefined order.
|
||||
// Its corresponding method is best-effort: it's not guaranteed that the
|
||||
// reflection service will implement this method, and it's not guaranteed
|
||||
// that this method will provide all extensions. Returns
|
||||
// StatusCode::UNIMPLEMENTED if it's not implemented.
|
||||
// This field should be a fully-qualified type name. The format is
|
||||
// <package>.<type>
|
||||
string all_extension_numbers_of_type = 6;
|
||||
|
||||
// List the full names of registered services. The content will not be
|
||||
// checked.
|
||||
string list_services = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// The type name and extension number sent by the client when requesting
|
||||
// file_containing_extension.
|
||||
message ExtensionRequest {
|
||||
// Fully-qualified type name. The format should be <package>.<type>
|
||||
string containing_type = 1;
|
||||
int32 extension_number = 2;
|
||||
}
|
||||
|
||||
// The message sent by the server to answer ServerReflectionInfo method.
|
||||
message ServerReflectionResponse {
|
||||
string valid_host = 1;
|
||||
ServerReflectionRequest original_request = 2;
|
||||
// The server set one of the following fields accroding to the message_request
|
||||
// in the request.
|
||||
oneof message_response {
|
||||
// This message is used to answer file_by_filename, file_containing_symbol,
|
||||
// file_containing_extension requests with transitive dependencies. As
|
||||
// the repeated label is not allowed in oneof fields, we use a
|
||||
// FileDescriptorResponse message to encapsulate the repeated fields.
|
||||
// The reflection service is allowed to avoid sending FileDescriptorProtos
|
||||
// that were previously sent in response to earlier requests in the stream.
|
||||
FileDescriptorResponse file_descriptor_response = 4;
|
||||
|
||||
// This message is used to answer all_extension_numbers_of_type requst.
|
||||
ExtensionNumberResponse all_extension_numbers_response = 5;
|
||||
|
||||
// This message is used to answer list_services request.
|
||||
ListServiceResponse list_services_response = 6;
|
||||
|
||||
// This message is used when an error occurs.
|
||||
ErrorResponse error_response = 7;
|
||||
}
|
||||
}
|
||||
|
||||
// Serialized FileDescriptorProto messages sent by the server answering
|
||||
// a file_by_filename, file_containing_symbol, or file_containing_extension
|
||||
// request.
|
||||
message FileDescriptorResponse {
|
||||
// Serialized FileDescriptorProto messages. We avoid taking a dependency on
|
||||
// descriptor.proto, which uses proto2 only features, by making them opaque
|
||||
// bytes instead.
|
||||
repeated bytes file_descriptor_proto = 1;
|
||||
}
|
||||
|
||||
// A list of extension numbers sent by the server answering
|
||||
// all_extension_numbers_of_type request.
|
||||
message ExtensionNumberResponse {
|
||||
// Full name of the base type, including the package name. The format
|
||||
// is <package>.<type>
|
||||
string base_type_name = 1;
|
||||
repeated int32 extension_number = 2;
|
||||
}
|
||||
|
||||
// A list of ServiceResponse sent by the server answering list_services request.
|
||||
message ListServiceResponse {
|
||||
// The information of each service may be expanded in the future, so we use
|
||||
// ServiceResponse message to encapsulate it.
|
||||
repeated ServiceResponse service = 1;
|
||||
}
|
||||
|
||||
// The information of a single service used by ListServiceResponse to answer
|
||||
// list_services request.
|
||||
message ServiceResponse {
|
||||
// Full name of a registered service, including its package name. The format
|
||||
// is <package>.<service>
|
||||
string name = 1;
|
||||
}
|
||||
|
||||
// The error code and error message sent by the server when an error occurs.
|
||||
message ErrorResponse {
|
||||
// This field uses the error codes defined in grpc::StatusCode.
|
||||
int32 error_code = 1;
|
||||
string error_message = 2;
|
||||
}
|
||||
Loading…
Reference in New Issue