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

com.gs.api.accelrx.web.client.reflect.AccelRxWebClientInvocationHandler Maven / Gradle / Ivy

package com.gs.api.accelrx.web.client.reflect;

import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
import com.gs.api.accelrx.*;
import com.gs.api.accelrx.context.ServiceContext;
import com.gs.api.accelrx.context.ServiceContextProvider;
import com.gs.api.accelrx.context.SimplePerformanceLog;
import com.gs.api.accelrx.web.api.HttpException;
import com.gs.api.accelrx.web.api.WebClientBlockingResponse;
import com.gs.api.accelrx.web.api.WebClientObservableResponse;
import com.gs.api.accelrx.web.api.WebClientSingleResponse;
import com.gs.api.accelrx.web.client.AccelRxWebClientConfig;
import io.reactivex.rxjava3.core.Completable;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.Single;
import io.reactivex.rxjava3.core.SingleTransformer;
import io.vertx.rxjava3.core.MultiMap;
import io.vertx.rxjava3.core.RxHelper;
import io.vertx.rxjava3.core.Vertx;
import org.slf4j.MDC;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

public class AccelRxWebClientInvocationHandler implements InvocationHandler {

    private final Vertx vertx;
    private final AccelRxWebClient webClient;
    private final APIContract apiContract;
    private final AccelRxWebClientConfig config;
    private final Supplier serviceContextSupplier;
    private final Supplier perfLogSupplier;

    private AccelRxWebClientInvocationHandler(Vertx vertx,
                                              AccelRxWebClient webClient,
                                              APIContract apiContract,
                                              AccelRxWebClientConfig config,
                                              Supplier serviceContextSupplier,
                                              Supplier perfLogSupplier) {
        this.vertx = vertx;
        this.webClient = webClient;
        this.apiContract = apiContract;
        this.config = config;
        this.serviceContextSupplier = serviceContextSupplier;
        this.perfLogSupplier = perfLogSupplier;
    }

    public static AccelRxWebClientInvocationHandler create(Vertx vertx,
                                                           AccelRxWebClient webClient,
                                                           APIContract apiContract,
                                                           AccelRxWebClientConfig config,
                                                           ServiceContext serviceContext) {
        return new AccelRxWebClientInvocationHandler(vertx, webClient, apiContract, config, () -> serviceContext, SimplePerformanceLog::new);
    }

    public static AccelRxWebClientInvocationHandler create(Vertx vertx,
                                                           AccelRxWebClient webClient,
                                                           APIContract apiContract,
                                                           AccelRxWebClientConfig config) {
        return new AccelRxWebClientInvocationHandler(vertx, webClient, apiContract, config, ServiceContextProvider::getFromContext, SimplePerformanceLog::new);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) {
        ServiceContext serviceContext = serviceContextSupplier.get();
        PerformanceLog perfLog = perfLogSupplier.get();

        AccelRxProxyMethod proxyMethod = AccelRxProxyMethod.create(apiContract, method);
        if (proxyMethod.isResponseMethod()) {
            return responseMethod(proxyMethod, args, serviceContext, perfLog);
        } else {
            return directBodyMethod(proxyMethod, args, serviceContext, perfLog);
        }
    }

    private Object responseMethod(AccelRxProxyMethod proxyMethod, Object[] args, ServiceContext context, PerformanceLog perfLog) {
        if (proxyMethod.apiOperation().isResponseStream()) {
            return webClient.executeToStream(clientRequest(proxyMethod, args, context, perfLog))
                    .compose(toObservableResponseObject(proxyMethod))
                    .subscribeOn(RxHelper.scheduler(vertx));
        } else {
            Single responseSingle = webClient.execute(clientRequest(proxyMethod, args, context, perfLog))
                    .subscribeOn(RxHelper.scheduler(vertx));
            if (proxyMethod.isBlockingMethod()) {
                return responseSingle.compose(toBlockingResponseObject(proxyMethod))
                        .blockingGet();
            } else {
                return responseSingle.compose(toResponseObject(proxyMethod));
            }
        }
    }

    private Object directBodyMethod(AccelRxProxyMethod proxyMethod, Object[] args, ServiceContext context, PerformanceLog perfLog) {
        if (proxyMethod.apiOperation().isResponseStream()) {
            return webClient.executeToStream(clientRequest(proxyMethod, args, context, perfLog))
                    .compose(toResponseStreamOrError())
                    .flatMapObservable(body -> (Observable) body)
                    .subscribeOn(RxHelper.scheduler(vertx));
        } else if (!proxyMethod.apiOperation().hasSuccessResponseBody()) {
            Completable responseCompletable = webClient.execute(clientRequest(proxyMethod, args, context, perfLog))
                    .flatMapCompletable(response -> {
                        if (response.successful()) {
                            return Completable.complete();
                        } else {
                            return Completable.error(exceptionFrom(response));
                        }
                    })
                    .subscribeOn(RxHelper.scheduler(vertx));
            if (proxyMethod.isBlockingMethod()) {
                responseCompletable.blockingAwait(config.blockingTimeout(), TimeUnit.MILLISECONDS);
                return null;
            } else {
                return responseCompletable;
            }
        } else {
            Single responseSingle = webClient.execute(clientRequest(proxyMethod, args, context, perfLog))
                    .compose(toResponseBodyOrError(proxyMethod))
                    .subscribeOn(RxHelper.scheduler(vertx));
            if (proxyMethod.isBlockingMethod()) {
                return responseSingle.blockingGet();
            } else {
                return responseSingle;
            }
        }
    }

    private AccelRxWebClientRequest clientRequest(AccelRxProxyMethod proxyMethod, Object[] args, ServiceContext context, PerformanceLog perfLog) {
        return new ReflectionWebClientRequest(
                proxyMethod.apiOperation(),
                config,
                proxyMethod.argsMap(args),
                context,
                perfLog);
    }

    private SingleTransformer toResponseObject(AccelRxProxyMethod proxyMethod) {
        return upstream ->
                upstream.flatMap(response ->
                        Single.just(((Class) proxyMethod.responseType())
                                .getConstructor(WebClientSingleResponse.class)
                                .newInstance(response))
                );
    }

    private SingleTransformer toBlockingResponseObject(AccelRxProxyMethod proxyMethod) {
        return upstream ->
                upstream.map(AccelRxWebClientBlockingResponse::from)
                        .flatMap(response ->
                                Single.just(((Class) proxyMethod.responseType())
                                        .getConstructor(WebClientBlockingResponse.class)
                                        .newInstance(response))
                        );
    }

    private SingleTransformer toObservableResponseObject(AccelRxProxyMethod proxyMethod) {
        return upstream ->
                upstream.flatMap(response ->
                        Single.just(((Class) proxyMethod.responseType())
                                .getConstructor(WebClientObservableResponse.class)
                                .newInstance(response))
                );
    }

    private SingleTransformer toResponseBodyOrError(AccelRxProxyMethod proxyMethod) {
        return upstream ->
                upstream.flatMap(response -> {
                    if (response.successful()) {
                        return response.body(proxyMethod.responseType());
                    } else {
                        return Single.error(exceptionFrom(response));
                    }
                });
    }

    private SingleTransformer toResponseStreamOrError() {
        return upstream ->
                upstream.flatMap(response -> {
                    if (response.successful()) {
                        return response.bodyStream();
                    } else {
                        return Single.error(exceptionFrom(response));
                    }
                });
    }

    private HttpException exceptionFrom(AccelRxWebClientResponse response) {
        return new HttpException(response.serviceName() + "." + response.operationId(),
                response.statusCode(),
                response.message(),
                response.errorBody(),
                toGoogleCollections(response.headers()));
    }

    private ListMultimap toGoogleCollections(MultiMap map) {
        ListMultimap googleMap = ArrayListMultimap.create();
        map.forEach(googleMap::put);
        return googleMap;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy