me.dinowernli.grpc.polyglot.protobuf.ServiceResolver Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of qaf-support-grpc Show documentation
Show all versions of qaf-support-grpc Show documentation
QAF support library for grpc test automation
The newest version!
package me.dinowernli.grpc.polyglot.protobuf;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.Descriptors.DescriptorValidationException;
import com.google.protobuf.Descriptors.FileDescriptor;
import com.google.protobuf.Descriptors.MethodDescriptor;
import com.google.protobuf.Descriptors.ServiceDescriptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
/** A locator used to read proto file descriptors and extract method definitions. */
public class ServiceResolver {
private static final Logger logger = LoggerFactory.getLogger(ServiceResolver.class);
private final ImmutableList fileDescriptors;
/** Creates a resolver which searches the supplied {@link FileDescriptorSet}. */
public static ServiceResolver fromFileDescriptorSet(FileDescriptorSet descriptorSet) {
ImmutableMap descriptorProtoIndex =
computeDescriptorProtoIndex(descriptorSet);
Map descriptorCache = new HashMap<>();
ImmutableList.Builder result = ImmutableList.builder();
for (FileDescriptorProto descriptorProto : descriptorSet.getFileList()) {
try {
result.add(descriptorFromProto(descriptorProto, descriptorProtoIndex, descriptorCache));
} catch (DescriptorValidationException e) {
logger.warn("Skipped descriptor " + descriptorProto.getName() + " due to error", e);
continue;
}
}
return new ServiceResolver(result.build());
}
/** Lists all of the services found in the file descriptors */
public Iterable listServices() {
ArrayList serviceDescriptors = new ArrayList();
for (FileDescriptor fileDescriptor: fileDescriptors) {
serviceDescriptors.addAll(fileDescriptor.getServices());
}
return serviceDescriptors;
}
/** Lists all the known message types. */
public ImmutableSet listMessageTypes() {
ImmutableSet.Builder resultBuilder = ImmutableSet.builder();
fileDescriptors.forEach(d -> resultBuilder.addAll(d.getMessageTypes()));
return resultBuilder.build();
}
private ServiceResolver(Iterable fileDescriptors) {
this.fileDescriptors = ImmutableList.copyOf(fileDescriptors);
}
/**
* Returns the descriptor of a protobuf method with the supplied grpc method name. If the method
* cannot be found, this throws {@link IllegalArgumentException}.
*/
public MethodDescriptor resolveServiceMethod(ProtoMethodName method) {
return resolveServiceMethod(
method.getServiceName(),
method.getMethodName(),
method.getPackageName());
}
private MethodDescriptor resolveServiceMethod(
String serviceName, String methodName, String packageName) {
ServiceDescriptor service = findService(serviceName, packageName);
MethodDescriptor method = service.findMethodByName(methodName);
if (method == null) {
throw new IllegalArgumentException(
"Unable to find method " + methodName + " in service " + serviceName);
}
return method;
}
private ServiceDescriptor findService(String serviceName, String packageName) {
// TODO(dino): Consider creating an index.
for (FileDescriptor fileDescriptor : fileDescriptors) {
if (!fileDescriptor.getPackage().equals(packageName)) {
// Package does not match this file, ignore.
continue;
}
ServiceDescriptor serviceDescriptor = fileDescriptor.findServiceByName(serviceName);
if (serviceDescriptor != null) {
return serviceDescriptor;
}
}
throw new IllegalArgumentException("Unable to find service with name: " + serviceName);
}
/**
* Returns a map from descriptor proto name as found inside the descriptors to protos.
*/
private static ImmutableMap computeDescriptorProtoIndex(
FileDescriptorSet fileDescriptorSet) {
ImmutableMap.Builder resultBuilder = ImmutableMap.builder();
for (FileDescriptorProto descriptorProto : fileDescriptorSet.getFileList()) {
resultBuilder.put(descriptorProto.getName(), descriptorProto);
}
return resultBuilder.build();
}
/**
* Recursively constructs file descriptors for all dependencies of the supplied proto and returns
* a {@link FileDescriptor} for the supplied proto itself. For maximal efficiency, reuse the
* descriptorCache argument across calls.
*/
private static FileDescriptor descriptorFromProto(
FileDescriptorProto descriptorProto,
ImmutableMap descriptorProtoIndex,
Map descriptorCache) throws DescriptorValidationException {
// First, check the cache.
String descritorName = descriptorProto.getName();
if (descriptorCache.containsKey(descritorName)) {
return descriptorCache.get(descritorName);
}
// Then, fetch all the required dependencies recursively.
ImmutableList.Builder dependencies = ImmutableList.builder();
for (String dependencyName : descriptorProto.getDependencyList()) {
if (!descriptorProtoIndex.containsKey(dependencyName)) {
throw new IllegalArgumentException("Could not find dependency: " + dependencyName);
}
FileDescriptorProto dependencyProto = descriptorProtoIndex.get(dependencyName);
dependencies.add(descriptorFromProto(dependencyProto, descriptorProtoIndex, descriptorCache));
}
// Finally, construct the actual descriptor.
FileDescriptor[] empty = new FileDescriptor[0];
return FileDescriptor.buildFrom(descriptorProto, dependencies.build().toArray(empty));
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy