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

org.yamcs.client.base.ClientStreamingObserver Maven / Gradle / Ivy

The newest version!
package org.yamcs.client.base;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.util.concurrent.ExecutionException;

import org.yamcs.api.AnnotationsProto;
import org.yamcs.api.HttpRoute;
import org.yamcs.api.Observer;
import org.yamcs.client.ClientException;

import com.google.protobuf.Descriptors.FieldDescriptor;
import com.google.protobuf.Descriptors.MethodDescriptor;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;

import io.netty.handler.codec.http.HttpMethod;
import io.netty.handler.codec.http.QueryStringEncoder;

/**
 * A message observer that implements a streaming request over HTTP using chunked transfer encoding.
 */
public class ClientStreamingObserver implements Observer {

    private MethodDescriptor method;
    private RestClient baseClient;
    private Message responsePrototype;
    private Observer responseObserver;
    private FieldDescriptor bodyField;

    private BulkRestDataSender sender;

    public ClientStreamingObserver(MethodDescriptor method, RestClient baseClient, Message responsePrototype,
            Observer responseObserver) {
        this.method = method;
        this.baseClient = baseClient;
        this.responsePrototype = responsePrototype;
        this.responseObserver = responseObserver;

        HttpRoute route = method.getOptions().getExtension(AnnotationsProto.route);

        if (!route.hasBody()) {
            throw new IllegalArgumentException("Route does not accept request bodies");
        }
        if (!"*".equals(route.getBody())) {
            bodyField = method.getInputType().findFieldByName(route.getBody());
        }
    }

    @Override
    public synchronized void next(Message message) { // Synchronize so that sender is available after the first request
        if (sender == null) {
            HttpRoute route = method.getOptions().getExtension(AnnotationsProto.route);

            // Holder for extracting route and query params
            Message.Builder partial = message.toBuilder();

            HttpMethod httpMethod = HttpMethodHandler.getMethod(route);
            String uriTemplate = HttpMethodHandler.getPattern(route);
            QueryStringEncoder uri = HttpMethodHandler.resolveUri(uriTemplate, message, method.getInputType(), partial);
            message = partial.buildPartial();
            try {
                sender = baseClient.doBulkSendRequest(uri.toString(), httpMethod).get();
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } catch (ExecutionException e) {
                cancel(e.getCause());
            }
        } else { // First message is always the initial request setup (no payload)
            if (bodyField != null) {
                message = (Message) message.getField(bodyField);
            }
            try {
                sender.sendData(delimit(message));
            } catch (ClientException e) {
                cancel(e);
            }
        }
    }

    private static byte[] delimit(Message message) {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        try {
            message.writeDelimitedTo(bout);
        } catch (IOException e) {
            throw new AssertionError(e);
        }
        return bout.toByteArray();
    }

    private void cancel(Throwable reason) {
        // TODO
        throw new RuntimeException(reason);
    }

    @Override
    public void completeExceptionally(Throwable t) {
        throw new UnsupportedOperationException();
    }

    @Override
    public void complete() {
        sender.completeRequest().whenComplete((data, err) -> {
            if (err == null) {
                Message response;
                try {
                    response = responsePrototype.newBuilderForType().mergeFrom(data).build();
                    responseObserver.complete(response);
                } catch (InvalidProtocolBufferException e) {
                    throw new IllegalArgumentException(e);
                }
            } else {
                responseObserver.completeExceptionally(err);
            }
        });
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy