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

com.turbospaces.resteasy.AbstractJaxRsClient Maven / Gradle / Ivy

The newest version!
package com.turbospaces.resteasy;

import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.Consumer;
import java.util.function.Supplier;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.impl.client.CloseableHttpClient;
import org.jboss.resteasy.client.jaxrs.ResteasyClient;
import org.jboss.resteasy.client.jaxrs.ResteasyWebTarget;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.service.UriBasedServiceInfo;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.netflix.archaius.api.Property;
import com.turbospaces.cfg.ApplicationProperties;
import com.turbospaces.ups.UPSs;

import io.github.resilience4j.ratelimiter.RateLimiterRegistry;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.binder.cache.GuavaCacheMetrics;
import lombok.extern.slf4j.Slf4j;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Sinks;

@Slf4j
public abstract class AbstractJaxRsClient implements InitializingBean, DisposableBean, BeanNameAware {
    private final Sinks.Many> processor = Sinks.many().replay().latest();
    private final Flux> flux = processor.asFlux();
    private final AtomicBoolean alive = new AtomicBoolean();
    protected final ApplicationProperties props;
    protected final MeterRegistry meterRegistry;
    protected final RateLimiterRegistry rateLimiterRegistry;
    protected final CloseableHttpClient httpClient;
    protected final Supplier mapper;
    protected String beanName;

    protected AbstractJaxRsClient(
            ApplicationProperties props,
            MeterRegistry meterRegistry,
            RateLimiterRegistry rateLimiterRegistry,
            CloseableHttpClient httpClient,
            Supplier mapper) {
        this.props = Objects.requireNonNull(props);
        this.meterRegistry = Objects.requireNonNull(meterRegistry);
        this.rateLimiterRegistry = Objects.requireNonNull(rateLimiterRegistry);
        this.httpClient = Objects.requireNonNull(httpClient);
        this.mapper = Objects.requireNonNull(mapper);
    }
    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
    @Override
    public void afterPropertiesSet() throws Exception {
        LoadingCache newInstance = createCache();

        processor.tryEmitNext(newInstance);
        accept(newInstance);

        alive.set(true);
    }
    @Override
    public void destroy() throws Exception {
        alive.set(false);
    }
    protected Flux> asFlux() {
        return flux;
    }
    protected void accept(LoadingCache cache) {

    }
    private LoadingCache createCache() {
        LoadingCache cache = CacheBuilder.newBuilder().build(new CacheLoader() {
            @Override
            public ResteasyWebTarget load(WebTargetConfig key) throws Exception {
                subscribeOnChange(key.connectionTimeout);
                subscribeOnChange(key.socketTimeout);

                return newWebTarget(key.ups, key.connectionTimeout, key.socketTimeout);
            }
        });
        GuavaCacheMetrics.monitor(meterRegistry, cache, this.getClass().getSimpleName());
        return cache;
    }
    private void subscribeOnChange(Property property) {
        property.subscribe(new Consumer() {
            @Override
            public void accept(Integer val) {
                if (alive.get() && val > 0) {
                    try {
                        log.debug("re-creating Jax-RS client: {}, {} changed to: {}", beanName, property.getKey(), val);
                        processor.tryEmitNext(createCache());
                    } catch (Exception err) {
                        log.error(err.getMessage(), err);
                    }
                }
            }
        });
    }
    private ResteasyWebTarget newWebTarget(UriBasedServiceInfo ups, Property connectionTimeout, Property socketTimeout) throws Exception {
        URIBuilder uri = new URIBuilder().setScheme(ups.getScheme()).setHost(ups.getHost()).setPort(ups.getPort());

        //
        // path might be relevant to distinguish
        //
        if (StringUtils.isNotEmpty(ups.getPath())) {
            uri = uri.setPath(ups.getPath());
        }

        JaxrsClientFactoryBean jaxrs = new JaxrsClientFactoryBean(props, rateLimiterRegistry, httpClient);
        jaxrs.setMapper(mapper.get());
        jaxrs.setRequestConfig(new Consumer() {
            @Override
            public void accept(RequestConfig.Builder cfg) {
                cfg.setConnectTimeout((int) TimeUnit.SECONDS.toMillis(connectionTimeout.get()));
                cfg.setSocketTimeout((int) TimeUnit.SECONDS.toMillis(socketTimeout.get()));
            }
        });

        ResteasyClient resteasyClient = jaxrs.getObject().build();
        return resteasyClient.target(uri.build());
    }

    public static class WebTargetConfig {
        private final UriBasedServiceInfo ups;
        private final Property connectionTimeout;
        private final Property socketTimeout;

        public WebTargetConfig(UriBasedServiceInfo ups, Property connectionTimeout, Property socketTimeout) {
            this.ups = Objects.requireNonNull(ups);
            this.connectionTimeout = Objects.requireNonNull(connectionTimeout);
            this.socketTimeout = Objects.requireNonNull(socketTimeout);
        }
        @Override
        public boolean equals(Object o) {
            if (this == o) {
                return true;
            }
            if (o == null || getClass() != o.getClass()) {
                return false;
            }

            for (;;) {
                try {
                    WebTargetConfig that = (WebTargetConfig) o;
                    return UPSs.isEquals(ups, that.ups)
                            && Objects.equals(connectionTimeout.get(), that.connectionTimeout.get())
                            && Objects.equals(socketTimeout.get(), that.socketTimeout.get());
                } catch (IOException err) {
                    ExceptionUtils.wrapAndThrow(err);
                }
            }
        }
        @Override
        public int hashCode() {
            for (;;) {
                try {
                    return Objects.hash(UPSs.hashCode(ups), connectionTimeout.get(), socketTimeout.get());
                } catch (IOException err) {
                    ExceptionUtils.wrapAndThrow(err);
                }
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy