package me.dinowernli.grpc.polyglot.io;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.Message;
import com.google.protobuf.util.JsonFormat;
import io.grpc.stub.StreamObserver;
/**
* A {@link StreamObserver} which writes the contents of the received messages to an
* {@link Output}. The messages are writting in a newline-separated json format.
*/
public class MessageWriter<T extends Message> implements StreamObserver<T> {
private static final Logger logger = LoggerFactory.getLogger(MessageWriter.class);
/** Used to separate the individual plaintext json proto messages. */
private static final String MESSAGE_SEPARATOR = "\n\n";
private final JsonFormat.Printer jsonPrinter;
private final Output output;
/**
* Creates a new {@link MessageWriter} which writes the messages it sees to the supplied
* {@link Output}.
*/
public static <T extends Message> MessageWriter<T> create(Output output) {
return new MessageWriter<T>(JsonFormat.printer(), output);
}
/**
* Returns the string representation of the stream of supplied messages. Each individual message
* is represented as valid json, but not that the whole result is, itself, *not* valid json.
*/
public static <M extends Message> String writeJsonStream(ImmutableList<M> messages) {
ByteArrayOutputStream resultStream = new ByteArrayOutputStream();
MessageWriter<M> writer = MessageWriter.create(Output.forStream(new PrintStream(resultStream)));
writer.writeAll(messages);
return resultStream.toString();
}
@VisibleForTesting
MessageWriter(JsonFormat.Printer jsonPrinter, Output output) {
this.jsonPrinter = jsonPrinter;
this.output = output;
}
@Override
public void onCompleted() {
// Nothing to do.
}
@Override
public void onError(Throwable t) {
// Nothing to do.
}
@Override
public void onNext(T message) {
try {
output.write(jsonPrinter.print(message) + MESSAGE_SEPARATOR);
} catch (InvalidProtocolBufferException e) {
logger.error("Skipping invalid response message", e);
}
}
/** Writes all the supplied messages and closes the stream. */
public void writeAll(ImmutableList<? extends T> messages) {
messages.forEach(this::onNext);
onCompleted();
}
}