com.kolich.http.HttpClient4ClosureBuilder.java Source code

Java tutorial

Introduction

Here is the source code for com.kolich.http.HttpClient4ClosureBuilder.java

Source

/**
 * Copyright (c) 2015 Mark S. Kolich
 * http://mark.koli.ch
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

package com.kolich.http;

import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.conn.HttpClientConnectionManager;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;

import java.net.ProxySelector;

import static com.google.common.base.Preconditions.checkArgument;
import static java.lang.Runtime.getRuntime;

public final class HttpClient4ClosureBuilder {

    private static final int AVAILABLE_CORES = getRuntime().availableProcessors();

    // A timeout value of zero is interpreted as an infinite timeout.
    private static final int DEFAULT_INFINITE_TIMEOUT = 0;

    // Trying to be like a real browser and only allow at most
    // 15-connections per route by default.
    private static final int DEFAULT_MAX_CONNECTIONS_PER_ROUTE = 15;

    // Max total connections defaults to the default max connections
    // per route multiplied by the number of cores.
    private static final int DEFAULT_MAX_TOTAL_CONNECTIONS = DEFAULT_MAX_CONNECTIONS_PER_ROUTE * AVAILABLE_CORES;

    /**
     * Defines the socket timeout (<code>SO_TIMEOUT</code>) in milliseconds,
     * which is the timeout for waiting for data  or, put differently,
     * a maximum period inactivity between two consecutive data packets).
     * A timeout value of zero is interpreted as an infinite timeout.
     */
    private int socketTimeout_ = DEFAULT_INFINITE_TIMEOUT;

    /**
     * The timeout in milliseconds until a connection is established.
     * A timeout value of zero is interpreted as an infinite timeout.
     */
    private int connectTimeout_ = DEFAULT_INFINITE_TIMEOUT;

    /**
     * The maximum number of total outgoing connections from this
     * {@link HttpClient4ClosureBuilder} instance.
     */
    private int maxTotalConnections_ = DEFAULT_MAX_TOTAL_CONNECTIONS;

    /**
     * The maximum number of outgoing connections per route from this
     * {@link HttpClient4ClosureBuilder} instance.
     */
    private int maxConnectionsPerRoute_ = DEFAULT_MAX_CONNECTIONS_PER_ROUTE;

    private String userAgent_ = null;

    private boolean staleConnectionCheckEnabled_ = true;
    private boolean disableContentCompression_ = true;
    private boolean disableAutomaticRetries_ = true;
    private boolean disableAuthCaching_ = true;

    private boolean useProxySelector_ = true;

    public HttpClient4ClosureBuilder() {
    }

    public HttpClient4ClosureBuilder setSocketTimeout(final int socketTimeout) {
        socketTimeout_ = socketTimeout;
        return this;
    }

    public HttpClient4ClosureBuilder setConnectTimeout(final int connectTimeout) {
        connectTimeout_ = connectTimeout;
        return this;
    }

    public HttpClient4ClosureBuilder setMaxTotalConnections(final int maxTotalConnections) {
        checkArgument(maxTotalConnections > 0, "Max total connections " + "must be greater than zero.");
        maxTotalConnections_ = maxTotalConnections;
        return this;
    }

    public HttpClient4ClosureBuilder setMaxConnectionsPerRoute(final int maxConnectionsPerRoute) {
        checkArgument(maxConnectionsPerRoute >= 1, "Max connections per route" + "must be positive.");
        maxConnectionsPerRoute_ = maxConnectionsPerRoute;
        return this;
    }

    public HttpClient4ClosureBuilder setUserAgent(final String userAgent) {
        userAgent_ = userAgent;
        return this;
    }

    public HttpClient4ClosureBuilder setStaleConnectionCheckEnabled(final boolean staleConnectionCheckEnabled) {
        staleConnectionCheckEnabled_ = staleConnectionCheckEnabled;
        return this;
    }

    public HttpClient4ClosureBuilder disableContentCompression(final boolean disableContentCompression) {
        disableContentCompression_ = disableContentCompression;
        return this;
    }

    public HttpClient4ClosureBuilder disableAutomaticRetries(final boolean disableAutomaticRetries) {
        disableAutomaticRetries_ = disableAutomaticRetries;
        return this;
    }

    public HttpClient4ClosureBuilder disableAuthCaching(final boolean disableAuthCaching) {
        disableAuthCaching_ = disableAuthCaching;
        return this;
    }

    public HttpClient4ClosureBuilder useProxySelector(final boolean useProxySelector) {
        useProxySelector_ = useProxySelector;
        return this;
    }

    /**
     * Creates a new {@link HttpClient} global {@link RequestConfig} object.
     * The {@link RequestConfig} object is where request specific settings
     * like socket and connection timeouts live.
     */
    public RequestConfig getRequestConfig() {
        return RequestConfig.custom().setSocketTimeout(socketTimeout_).setConnectTimeout(connectTimeout_)
                .setConnectionRequestTimeout(connectTimeout_)
                // When this is set to false, this apparently causes bugs
                // with the PoolingHttpClientConnectionManager in 4.3.3. It's
                // unclear to me why, but I'm leaving this 'true' although
                // claims are made it adds 30ms of lag time to every request.
                .setStaleConnectionCheckEnabled(staleConnectionCheckEnabled_).build();
    }

    public HttpClientConnectionManager getConnectionManager() {
        final PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager();
        connectionManager.setDefaultMaxPerRoute(maxConnectionsPerRoute_);
        connectionManager.setMaxTotal(maxTotalConnections_);
        return connectionManager;
    }

    public HttpClientBuilder getHttpClientBuilder() {
        final HttpClientBuilder builder = HttpClients.custom().setDefaultRequestConfig(getRequestConfig())
                .setConnectionManager(getConnectionManager()).setUserAgent(userAgent_);
        // See http://stackoverflow.com/questions/21818242/with-httpclient-4-3-x-executing-a-httphead-for-a-specific-url-gives-nohttprespo
        // Also, see https://issues.apache.org/jira/browse/HTTPCLIENT-1464
        // This disables the addition of the `Accept-Encoding: gzip,deflate`
        // header on outgoing requests which seems to confuse some servers.
        // This is off by default, but can be turned off if desired.
        if (disableContentCompression_) {
            builder.disableContentCompression();
        }
        if (disableAutomaticRetries_) {
            builder.disableAutomaticRetries();
        }
        if (disableAuthCaching_) {
            builder.disableAuthCaching();
        }
        if (useProxySelector_) {
            builder.setRoutePlanner(new SystemDefaultRoutePlanner(ProxySelector.getDefault()));
        }
        return builder;
    }

    public HttpClient getNewHttpClientInstance() {
        return getHttpClientBuilder().build();
    }

    /**
     * An inline class that provides a few static factory methods for beans
      * and others who just want a dead simple way to get a working and
      * reasonable {@link HttpClient} instance.
     */
    public static final class Factory {

        public static final HttpClient getNewInstanceNoProxySelector(final String userAgent, int socketTimeout,
                int connectTimeout, int maxTotalConnections, int maxConnectionsPerRoute) {
            return new HttpClient4ClosureBuilder().setUserAgent(userAgent).setSocketTimeout(socketTimeout)
                    .setConnectTimeout(connectTimeout).setMaxTotalConnections(maxTotalConnections)
                    .setMaxConnectionsPerRoute(maxConnectionsPerRoute).useProxySelector(false)
                    .getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceNoProxySelector(int socketTimeout, int connectTimeout,
                int maxTotalConnections, int maxConnectionsPerRoute) {
            return new HttpClient4ClosureBuilder().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)
                    .setMaxTotalConnections(maxTotalConnections).setMaxConnectionsPerRoute(maxConnectionsPerRoute)
                    .useProxySelector(false).getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceNoProxySelector(int maxTotalConnections,
                int maxConnectionsPerRoute) {
            return new HttpClient4ClosureBuilder().setMaxTotalConnections(maxTotalConnections)
                    .setMaxConnectionsPerRoute(maxConnectionsPerRoute).useProxySelector(false)
                    .getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceNoProxySelector(final String userAgent) {
            return new HttpClient4ClosureBuilder().setUserAgent(userAgent).useProxySelector(false)
                    .getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceNoProxySelector() {
            return new HttpClient4ClosureBuilder().useProxySelector(false).getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceWithProxySelector(final String userAgent, int socketTimeout,
                int connectTimeout, int maxTotalConnections, int maxConnectionsPerRoute) {
            return new HttpClient4ClosureBuilder().setUserAgent(userAgent).setSocketTimeout(socketTimeout)
                    .setConnectTimeout(connectTimeout).setMaxTotalConnections(maxTotalConnections)
                    .setMaxConnectionsPerRoute(maxConnectionsPerRoute).getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceWithProxySelector(int socketTimeout, int connectTimeout,
                int maxTotalConnections, int maxConnectionsPerRoute) {
            return new HttpClient4ClosureBuilder().setSocketTimeout(socketTimeout).setConnectTimeout(connectTimeout)
                    .setMaxTotalConnections(maxTotalConnections).setMaxConnectionsPerRoute(maxConnectionsPerRoute)
                    .getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceWithProxySelector(int maxTotalConnections,
                int maxConnectionsPerRoute) {
            return new HttpClient4ClosureBuilder().setMaxTotalConnections(maxTotalConnections)
                    .setMaxConnectionsPerRoute(maxConnectionsPerRoute).getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceWithProxySelector(final String userAgent) {
            return new HttpClient4ClosureBuilder().setUserAgent(userAgent).getNewHttpClientInstance();
        }

        public static final HttpClient getNewInstanceWithProxySelector() {
            return new HttpClient4ClosureBuilder().getNewHttpClientInstance();
        }

    }

}