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

com.fullcontact.rpc.jersey.GrpcJerseyErrorHandler Maven / Gradle / Ivy

The newest version!
package com.fullcontact.rpc.jersey;

import com.google.common.annotations.Beta;
import com.google.common.collect.ImmutableMultimap;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.rpc.Status;
import java.io.IOException;
import java.util.Map;
import java.util.Optional;
import javax.ws.rs.container.AsyncResponse;
import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder;

/**
 * Pluggable error handler used by the {@link JerseyUnaryObserver} and {@link JerseyStreamingObserver}.
 */
@Beta
public interface GrpcJerseyErrorHandler {
    /**
     * Handles an exception raised in a unary (request/response) RPC handler.
     *
     * It is up to each implementation as to whether they honor the responseHeaders set by the RPC handler.
     *
     * @param t throwable raised
     * @param responseHeaders headers set by the RPC handler
     * @return response JAX-RS Response. Returning {@link Optional#empty()} will call {@link AsyncResponse#cancel()}.
     */
    Optional handleUnaryError(Throwable t, ImmutableMultimap responseHeaders);

    /**
     * Handles an exception raised in a server streaming RPC handler. As HTTP/1.1 practically doesn't support trailers,
     * there isn't a real way to signal well-formed errors except via another streaming payload.
     *
     * @param t throwable raised.
     * @return Literal string, if you want JSON-encoded data use the {@link JsonHandler#streamPrinter()} to retain
     * server-sent events compatibility. Return {@link Optional#empty()} to silently abort.
     * @throws IOException usually if serialization of errors break.
     */
    Optional handleStreamingError(Throwable t) throws IOException;

    class Default implements GrpcJerseyErrorHandler {
        @Override
        public Optional handleUnaryError(Throwable t, ImmutableMultimap responseHeaders) {
            Response response;
            if (t instanceof InvalidProtocolBufferException) {
                response = Response.status(Response.Status.BAD_REQUEST).entity(t.getMessage()).build();
            } else {
                response = GrpcErrorUtil.createJerseyResponse(t);
            }

            if (!responseHeaders.isEmpty()) {
                ResponseBuilder responseBuilder = Response.fromResponse(response);
                for (Map.Entry entry : responseHeaders.entries()) {
                    responseBuilder.header(entry.getKey(), entry.getValue());
                }

                response = responseBuilder.build();
            }

            return Optional.of(response);
        }

        @Override
        public Optional handleStreamingError(Throwable t) throws InvalidProtocolBufferException {
            Status grpcError = GrpcErrorUtil.throwableToStatus(t).getPayload();

            // JsonFormat doesn't support serializing Any.
            if (!grpcError.getDetailsList().isEmpty()) {
                grpcError = grpcError.toBuilder().clearDetails().build();
            }

            return Optional.of(JsonHandler.streamPrinter().print(grpcError));
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy