All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.yamcs.http.ProtobufRegistry Maven / Gradle / Ivy

There is a newer version: 5.10.9
Show newest version
package org.yamcs.http;

import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.yamcs.api.AnnotationsProto;
import org.yamcs.api.HttpRoute;
import org.yamcs.api.WebSocketTopic;

import com.google.protobuf.DescriptorProtos.DescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorProto;
import com.google.protobuf.DescriptorProtos.FileDescriptorSet;
import com.google.protobuf.DescriptorProtos.MethodDescriptorProto;
import com.google.protobuf.DescriptorProtos.MethodOptions;
import com.google.protobuf.DescriptorProtos.ServiceDescriptorProto;
import com.google.protobuf.DescriptorProtos.SourceCodeInfo.Location;
import com.google.protobuf.Descriptors.Descriptor;
import com.google.protobuf.ExtensionRegistry;
import com.google.protobuf.ExtensionRegistry.ExtensionInfo;

public class ProtobufRegistry {

    // Indexes by fully-qualified protobuf name
    private Map rpcs = new HashMap<>();
    private Map messageTypes = new HashMap<>();
    private Map javaPackages = new HashMap<>();

    private Map serviceComments = new HashMap<>();
    private Map methodComments = new HashMap<>();

    private ExtensionRegistry extensionRegistry = ExtensionRegistry.newInstance();

    private Map> extensionsByMessage = new HashMap<>();

    public ProtobufRegistry() {
        extensionRegistry.add(AnnotationsProto.route);
        extensionRegistry.add(AnnotationsProto.websocket);

        try (InputStream in = getClass().getResourceAsStream("/yamcs-api.protobin")) {
            if (in == null) {
                throw new UnsupportedOperationException("Missing binary protobuf descriptions");
            }
            importDefinitions(in);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    public void importDefinitions(InputStream in) throws IOException {
        if (in == null) {
            throw new NullPointerException("input stream cannot be null");
        }
        FileDescriptorSet proto = FileDescriptorSet.parseFrom(in, extensionRegistry);

        // Index all messages by fully-qualified protobuf name
        for (FileDescriptorProto file : proto.getFileList()) {
            scanComments(file);
            String javaPackage = file.getOptions().getJavaPackage();
            javaPackages.put(file.getName(), javaPackage);

            for (DescriptorProto messageType : file.getMessageTypeList()) {
                String qname = file.getPackage() + "." + messageType.getName();
                messageTypes.put(qname, messageType);
            }
        }

        // Index RPCs
        for (FileDescriptorProto file : proto.getFileList()) {
            for (ServiceDescriptorProto service : file.getServiceList()) {
                for (MethodDescriptorProto method : service.getMethodList()) {
                    MethodOptions options = method.getOptions();
                    String serviceName = service.getName();
                    String methodName = method.getName();
                    DescriptorProto inputType = messageTypes.get(method.getInputType().substring(1));
                    DescriptorProto outputType = messageTypes.get(method.getOutputType().substring(1));
                    if (options.hasExtension(AnnotationsProto.route)) {
                        HttpRoute route = options.getExtension(AnnotationsProto.route);
                        RpcDescriptor descriptor = new RpcDescriptor(serviceName, methodName, inputType, outputType,
                                route);

                        String qname = String.join(".", file.getPackage(), serviceName, methodName);
                        rpcs.put(qname, descriptor);
                    } else if (options.hasExtension(AnnotationsProto.websocket)) {
                        WebSocketTopic topic = options.getExtension(AnnotationsProto.websocket);
                        RpcDescriptor descriptor = new RpcDescriptor(serviceName, methodName, inputType, outputType,
                                topic);

                        String qname = String.join(".", file.getPackage(), serviceName, methodName);
                        rpcs.put(qname, descriptor);
                    }
                }
            }
        }
    }

    private void scanComments(FileDescriptorProto file) {
        List services = file.getServiceList();

        for (Location location : file.getSourceCodeInfo().getLocationList()) {
            if (location.hasLeadingComments()) {
                if (location.getPath(0) == FileDescriptorProto.SERVICE_FIELD_NUMBER) {
                    ServiceDescriptorProto service = services.get(location.getPath(1));
                    if (location.getPathCount() == 2) {
                        serviceComments.put(service, location.getLeadingComments());
                    } else if (location.getPathCount() == 4) {
                        if (location.getPath(2) == ServiceDescriptorProto.METHOD_FIELD_NUMBER) {
                            MethodDescriptorProto method = service.getMethod(location.getPath(3));
                            methodComments.put(method, location.getLeadingComments());
                        }
                    }
                }
            }
        }
    }

    public ExtensionRegistry getExtensionRegistry() {
        return extensionRegistry;
    }

    public RpcDescriptor getRpc(String id) {
        return rpcs.get(id);
    }

    /**
     * Returns extensions for a specific Message type in the order as they have been defined
     */
    public List getExtensions(Descriptor messageType) {
        List extensions = extensionsByMessage.get(messageType);
        return (extensions == null) ? Collections.emptyList() : extensions;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy