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

net.optionfactory.spring.upstream.hc5.HcRequestFactories Maven / Gradle / Ivy

There is a newer version: 20.1
Show newest version
package net.optionfactory.spring.upstream.hc5;

import java.net.ProxySelector;
import java.net.SocketAddress;
import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import net.optionfactory.spring.upstream.Upstream;
import net.optionfactory.spring.upstream.Upstream.HttpComponents;
import net.optionfactory.spring.upstream.UpstreamBuilder.RequestFactoryConfigurer;
import net.optionfactory.spring.upstream.annotations.Annotations;
import org.apache.hc.client5.http.AuthenticationStrategy;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.socket.LayeredConnectionSocketFactory;
import org.apache.hc.core5.http.ConnectionReuseStrategy;
import org.apache.hc.core5.http.HttpHost;
import org.apache.hc.core5.http.io.SocketConfig;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.http.client.BufferingClientHttpRequestFactory;
import org.springframework.http.client.ClientHttpRequestFactory;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.lang.Nullable;

public class HcRequestFactories {

    public static Builder builder() {
        return new Builder();
    }

    public static class Builder {

        private final List> socketConfigCustomizers = new ArrayList<>();
        private final List> connectionConfigCustomizers = new ArrayList<>();
        private final List> connectionManagerCustomizers = new ArrayList<>();
        private final List> clientBuilderCustomizers = new ArrayList<>();

        public Builder connectionManager(Consumer c) {
            this.connectionManagerCustomizers.add(c);
            return this;
        }

        public Builder tlsSocketFactory(@Nullable LayeredConnectionSocketFactory sslSocketFactory) {
            return connectionManager(c -> c.setSSLSocketFactory(sslSocketFactory));
        }

        public Builder maxConnections(int max) {
            return connectionManager(c -> c.setMaxConnTotal(max));
        }

        public Builder maxConnectionsPerRoute(int max) {
            return connectionManager(c -> c.setMaxConnPerRoute(max));
        }

        public Builder socketConfig(Consumer c) {
            this.socketConfigCustomizers.add(c);
            return this;
        }

        public Builder socketKeepAlive(boolean value) {
            return socketConfig(c -> c.setSoKeepAlive(value));
        }

        public Builder socketTcpNoDelay(boolean value) {
            return socketConfig(c -> c.setTcpNoDelay(value));
        }

        public Builder socketSocksProxy(SocketAddress address) {
            return socketConfig(c -> c.setSocksProxyAddress(address));
        }

        public Builder connectionConfig(Consumer c) {
            this.connectionConfigCustomizers.add(c);
            return this;
        }

        public Builder connectionTimeout(Duration d) {
            return connectionConfig(c -> c.setConnectTimeout(d.toSeconds(), TimeUnit.SECONDS));
        }

        public Builder socketTimeout(Duration d) {
            return connectionConfig(c -> c.setSocketTimeout((int) d.toSeconds(), TimeUnit.SECONDS));
        }

        public Builder connectionTimeToLive(Duration d) {
            return connectionConfig(c -> {
                if (d == null) {
                    c.setTimeToLive(null);
                } else {
                    c.setTimeToLive(d.toSeconds(), TimeUnit.SECONDS);
                }
            });
        }

        public Builder connectionValidateAfterInactivity(Duration d) {
            return connectionConfig(c -> {
                if (d == null) {
                    c.setValidateAfterInactivity(null);
                } else {
                    c.setValidateAfterInactivity(d.toSeconds(), TimeUnit.SECONDS);
                }
            });
        }

        public Builder clientBuilder(Consumer c) {
            this.clientBuilderCustomizers.add(c);
            return this;
        }

        public Builder connectionReuseStrategy(ConnectionReuseStrategy strategy) {
            return clientBuilder(c -> c.setConnectionReuseStrategy(strategy));
        }

        public Builder proxy(HttpHost proxy) {
            return clientBuilder(c -> c.setProxy(proxy));
        }

        public Builder proxySelector(ProxySelector selector) {
            return clientBuilder(c -> c.setProxySelector(selector));
        }

        public Builder proxyAuthenticator(AuthenticationStrategy strategy) {
            return clientBuilder(c -> c.setProxyAuthenticationStrategy(strategy));
        }

        public Builder disableAuthCaching() {
            return clientBuilder(c -> c.disableAuthCaching());
        }

        public Builder disableAutomaticRetries() {
            return clientBuilder(c -> c.disableAutomaticRetries());
        }

        public Builder disableConnectionState() {
            return clientBuilder(c -> c.disableConnectionState());
        }

        public Builder disableContentCompression() {
            return clientBuilder(c -> c.disableContentCompression());
        }

        public Builder disableCookieManagement() {
            return clientBuilder(c -> c.disableCookieManagement());
        }

        public Builder disableDefaultUserAgent() {
            return clientBuilder(c -> c.disableDefaultUserAgent());
        }

        public Builder disableRedirectHandling() {
            return clientBuilder(c -> c.disableRedirectHandling());
        }

        public enum Buffering {
            BUFFERED, UNBUFFERED;
        }

        public ClientHttpRequestFactory build(Buffering buffering) {
            final var defaults = AnnotationUtils.synthesizeAnnotation(HttpComponents.class);
            final var connTimeout = Duration.parse(defaults.connectionTimeout());
            final var sockTimeout = Duration.parse(defaults.socketTimeout());
            final var maxConnections = Integer.parseInt(defaults.maxConnections());
            final var maxConnectionsPerRoute = Integer.parseInt(defaults.maxConnectionsPerRoute());

            final var socketConfigBuilder = SocketConfig.custom().setSoKeepAlive(true);

            for (final var socketConfigCustomizer : socketConfigCustomizers) {
                socketConfigCustomizer.accept(socketConfigBuilder);
            }

            final var connectionConfigBuilder = ConnectionConfig.custom()
                    .setConnectTimeout(connTimeout.toSeconds(), TimeUnit.SECONDS)
                    .setSocketTimeout((int) sockTimeout.toSeconds(), TimeUnit.SECONDS);

            for (final var connectionConfigCustomizer : connectionConfigCustomizers) {
                connectionConfigCustomizer.accept(connectionConfigBuilder);
            }

            final var connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder.create()
                    .setDefaultConnectionConfig(connectionConfigBuilder.build())
                    .setDefaultSocketConfig(socketConfigBuilder.build())
                    .setMaxConnTotal(maxConnections)
                    .setMaxConnPerRoute(maxConnectionsPerRoute);

            for (final var connectionManagerCustomizer : connectionManagerCustomizers) {
                connectionManagerCustomizer.accept(connectionManagerBuilder);
            }

            final var clientBuilder = HttpClientBuilder.create().setConnectionManager(connectionManagerBuilder.build());
            for (final var clientBuilderCustomizer : clientBuilderCustomizers) {
                clientBuilderCustomizer.accept(clientBuilder);
            }
            final var f = new HttpComponentsClientHttpRequestFactory(clientBuilder.build());
            return buffering == Buffering.BUFFERED ? new BufferingClientHttpRequestFactory(f) : f;

        }

        public RequestFactoryConfigurer buildConfigurer(Buffering buffering) {
            return (scopeHandler, klass, expressions, endpoints) -> {
                final var conf = Annotations.closest(klass, Upstream.HttpComponents.class).orElseGet(() -> AnnotationUtils.synthesizeAnnotation(HttpComponents.class));
                final var connTimeout = Duration.parse(expressions.string(conf.connectionTimeout(), conf.connectionTimeoutType()).evaluate(expressions.context()));
                final var sockTimeout = Duration.parse(expressions.string(conf.socketTimeout(), conf.socketTimeoutType()).evaluate(expressions.context()));
                final var maxConnections = expressions.integer(conf.maxConnections()).evaluate(expressions.context());
                final var maxConnectionsPerRoute = expressions.integer(conf.maxConnectionsPerRoute()).evaluate(expressions.context());

                final var socketConfigBuilder = SocketConfig.custom().setSoKeepAlive(true);

                for (final var socketConfigCustomizer : socketConfigCustomizers) {
                    socketConfigCustomizer.accept(socketConfigBuilder);
                }

                final var connectionConfigBuilder = ConnectionConfig.custom()
                        .setConnectTimeout(connTimeout.toSeconds(), TimeUnit.SECONDS)
                        .setSocketTimeout((int) sockTimeout.toSeconds(), TimeUnit.SECONDS);

                for (final var connectionConfigCustomizer : connectionConfigCustomizers) {
                    connectionConfigCustomizer.accept(connectionConfigBuilder);
                }

                final var connectionManagerBuilder = PoolingHttpClientConnectionManagerBuilder.create()
                        .setDefaultConnectionConfig(connectionConfigBuilder.build())
                        .setDefaultSocketConfig(socketConfigBuilder.build())
                        .setMaxConnTotal(maxConnections)
                        .setMaxConnPerRoute(maxConnectionsPerRoute);

                for (final var connectionManagerCustomizer : connectionManagerCustomizers) {
                    connectionManagerCustomizer.accept(connectionManagerBuilder);
                }

                final var clientBuilder = HttpClientBuilder.create().setConnectionManager(connectionManagerBuilder.build());
                if (conf.disableAuthCaching()) {
                    clientBuilder.disableAuthCaching();
                }
                if (conf.disableAutomaticRetries()) {
                    clientBuilder.disableAutomaticRetries();
                }
                if (conf.disableConnectionState()) {
                    clientBuilder.disableConnectionState();
                }
                if (conf.disableContentCompression()) {
                    clientBuilder.disableContentCompression();
                }
                if (conf.disableCookieManagement()) {
                    clientBuilder.disableCookieManagement();
                }
                if (conf.disableDefaultUserAgent()) {
                    clientBuilder.disableDefaultUserAgent();
                }
                if (conf.disableRedirectHandling()) {
                    clientBuilder.disableRedirectHandling();
                }
                for (final var clientBuilderCustomizer : clientBuilderCustomizers) {
                    clientBuilderCustomizer.accept(clientBuilder);
                }
                final var f = new HttpComponentsClientHttpRequestFactory(clientBuilder.build());
                return buffering == Buffering.BUFFERED ? new BufferingClientHttpRequestFactory(f) : f;
            };
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy