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

com.turbospaces.rpc.DefaultGrpcApiResponse Maven / Gradle / Ivy

There is a newer version: 2.0.33
Show newest version
package com.turbospaces.rpc;

import java.util.Objects;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import com.google.common.util.concurrent.FluentFuture;
import com.google.common.util.concurrent.FutureCallback;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import com.google.protobuf.Message;
import com.turbospaces.api.facade.RequestWrapperFacade;
import com.turbospaces.api.facade.ResponseWrapperFacade;
import com.turbospaces.api.mappers.RequestFacadeMapper;

import api.v1.ApiFactory;
import api.v1.Headers;
import api.v1.ReplyUtil;
import io.cloudevents.core.builder.CloudEventBuilder;
import io.grpc.StatusRuntimeException;
import io.grpc.protobuf.StatusProto;
import io.vavr.CheckedConsumer;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public class DefaultGrpcApiResponse extends AbstractApiResponse {
    private final FluentFuture> subject;
    private final RESP prototype;

    public DefaultGrpcApiResponse(
            ApiFactory apiFactory,
            RequestWrapperFacade req,
            ListenableFuture post,
            RESP prototype) {
        super(apiFactory, req);
        this.prototype = Objects.requireNonNull(prototype);

        SettableFuture> completable = SettableFuture.create();
        RequestFacadeMapper requestMapper = apiFactory.requestMapper();
        CloudEventBuilder eventTemplate = apiFactory.eventTemplate();
        Headers headers = req.headers();
        subject = FluentFuture.from(completable);
        FluentFuture.from(post).addCallback(new FutureCallback() {
            @Override
            @SuppressWarnings("unchecked")
            public void onSuccess(RESP result) {
                ResponseWrapperFacade reply = apiFactory.requestMapper().toReply(
                        apiFactory.eventTemplate(),
                        req.headers(),
                        result,
                        api.v1.CacheControl.getDefaultInstance());
                Class clazz = (Class) result.getClass();
                completable.set(new DefaultApiResponseEntity<>(reply, clazz));
            }
            @Override
            @SuppressWarnings("unchecked")
            public void onFailure(Throwable t) {
                log.error(t.getMessage(), t);

                if (t instanceof StatusRuntimeException) {
                    com.google.rpc.Status orig = StatusProto.fromThrowable(t);
                    com.google.rpc.Code origCode = com.google.rpc.Code.forNumber(orig.getCode());

                    String msg = String.format(ReplyUtil.ERROR_FORMAT, req.headers().getMessageId());
                    Class clazz = (Class) prototype.getClass();

                    switch (origCode) {
                        case OK: {
                            var resp = requestMapper.toReply(eventTemplate, headers, prototype, api.v1.CacheControl.getDefaultInstance());
                            completable.set(new DefaultApiResponseEntity<>(resp, clazz));
                            break;
                        }
                        case NOT_FOUND: {
                            var resp = requestMapper.toExceptionalNotFoundReply(eventTemplate, headers, prototype, msg);
                            completable.set(new DefaultApiResponseEntity<>(resp, clazz));
                            break;
                        }
                        case PERMISSION_DENIED:
                        case UNAUTHENTICATED: {
                            var resp = requestMapper.toExceptionalAuthReply(eventTemplate, headers, prototype, msg);
                            completable.set(new DefaultApiResponseEntity<>(resp, clazz));
                            break;
                        }
                        case FAILED_PRECONDITION:
                        case OUT_OF_RANGE:
                        case INVALID_ARGUMENT: {
                            var resp = requestMapper.toExceptionalBadRequestReply(eventTemplate, headers, prototype, msg);
                            completable.set(new DefaultApiResponseEntity<>(resp, clazz));
                            break;
                        }
                        case UNAVAILABLE:
                        case DEADLINE_EXCEEDED: {
                            var resp = requestMapper.toExceptionalTimeoutReply(eventTemplate, headers, prototype, msg);
                            completable.set(new DefaultApiResponseEntity<>(resp, clazz));
                            break;
                        }
                        case INTERNAL:
                        case CANCELLED:
                        case ABORTED:
                        case ALREADY_EXISTS:
                        case DATA_LOSS:
                        case RESOURCE_EXHAUSTED:
                        case UNIMPLEMENTED:
                        case UNKNOWN:
                        case UNRECOGNIZED:
                        default: {
                            var resp = requestMapper.toExceptionalSystemReply(eventTemplate, headers, prototype, msg);
                            completable.set(new DefaultApiResponseEntity<>(resp, clazz));
                            break;
                        }
                    }
                } else {
                    completable.setException(t);
                }
            }
        }, MoreExecutors.directExecutor());
    }
    public DefaultGrpcApiResponse(ApiFactory apiFactory, RequestWrapperFacade req, FluentFuture> subject, RESP prototype) {
        super(apiFactory, req);
        this.subject = Objects.requireNonNull(subject);
        this.prototype = Objects.requireNonNull(prototype);
    }
    @Override
    public ApiResponseEntity get() throws InterruptedException, ExecutionException {
        return subject.get();
    }
    @Override
    public ApiResponseEntity get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        return subject.get(timeout, unit);
    }
    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return subject.cancel(mayInterruptIfRunning);
    }
    @Override
    public boolean isCancelled() {
        return subject.isCancelled();
    }
    @Override
    public boolean isDone() {
        return subject.isDone();
    }
    @Override
    public void addListener(Runnable listener, Executor executor) {
        subject.addListener(listener, executor);
    }
    @Override
    public void addCallback(FutureCallback> callback, Executor executor) {
        var wrapper = new FutureCallbackWrapper>(callback);
        wrapper.setBootstrap(bootstrap);
        subject.addCallback(isDone() ? callback : wrapper, executor);
    }
    @Override
    public ApiResponse thenVerifyOkAndAccept(CheckedConsumer callback, Executor executor) {
        SettableFuture> toReturn = SettableFuture.create();
        subject.addCallback(new FutureCallback>() {
            @Override
            public void onSuccess(ApiResponseEntity result) {
                boolean isOK = true;

                try {
                    result.verifyOk();
                } catch (Exception err) {
                    toReturn.setException(err);
                    isOK = false;
                }

                if (isOK) {
                    try {
                        RESP body = result.body();
                        callback.accept(body);
                        toReturn.set(result);
                    } catch (Throwable err) {
                        toReturn.setException(err);
                    }
                }
            }
            @Override
            public void onFailure(Throwable t) {
                toReturn.setException(t);
            }
        }, executor);

        //
        // ~ new API response by contract
        //
        DefaultGrpcApiResponse resp = new DefaultGrpcApiResponse(apiFactory, requestWrapper, FluentFuture.from(toReturn), prototype);
        resp.setBootstrap(bootstrap);
        return resp;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy