sk.datalan.solr.impl.HttpClientUtil.java Source code

Java tutorial

Introduction

Here is the source code for sk.datalan.solr.impl.HttpClientUtil.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package sk.datalan.solr.impl;

import java.io.IOException;
import java.io.InputStream;
import java.util.zip.GZIPInputStream;
import java.util.zip.InflaterInputStream;
import javax.net.ssl.SSLContext;
import org.apache.http.Header;
import org.apache.http.HeaderElement;
import org.apache.http.HttpEntity;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.HttpResponseInterceptor;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.entity.HttpEntityWrapper;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author hlavki
 */
public final class HttpClientUtil {

    private static final Logger log = LoggerFactory.getLogger(HttpClientUtil.class);

    static final DefaultHttpRequestRetryHandler NO_RETRY = new DefaultHttpRequestRetryHandler(0, false);

    private HttpClientUtil() {
    }

    /**
     * Creates new http client by using the provided configuration.
     *
     * @param config http client configuration, if null a client with default configuration (no additional
     * configuration) is created.
     * @return http client instance
     */
    public static CloseableHttpClient createClient(final HttpClientConfiguration config) {
        if (log.isDebugEnabled()) {
            log.debug("Creating new http client, config:" + config);
        }

        HttpClientBuilder clientBuilder = configureClient(config);
        return clientBuilder.build();
    }

    public static HttpClientBuilder configureClient(final HttpClientConfiguration config) {
        HttpClientBuilder clientBuilder = HttpClientBuilder.create();

        // max total connections
        if (config.isSetMaxConnections()) {
            clientBuilder.setMaxConnTotal(config.getMaxConnections());
        }

        // max connections per route
        if (config.isSetMaxConnectionsPerRoute()) {
            clientBuilder.setMaxConnPerRoute(config.getMaxConnectionsPerRoute());
        }

        RequestConfig.Builder requestConfigBuilder = RequestConfig.custom().setCookieSpec(CookieSpecs.BEST_MATCH)
                .setExpectContinueEnabled(true).setStaleConnectionCheckEnabled(true);

        // connection timeout
        if (config.isSetConnectionTimeout()) {
            requestConfigBuilder.setConnectTimeout(config.getConnectionTimeout());
        }

        // soucket timeout
        if (config.isSetSocketTimeout()) {
            requestConfigBuilder.setSocketTimeout(config.getSocketTimeout());
        }

        // soucket timeout
        if (config.isSetFollowRedirects()) {
            requestConfigBuilder.setRedirectsEnabled(config.getFollowRedirects());
        }
        clientBuilder.setDefaultRequestConfig(requestConfigBuilder.build());

        if (config.isSetUseRetry()) {
            if (config.getUseRetry()) {
                clientBuilder.setRetryHandler(new DefaultHttpRequestRetryHandler());
            } else {
                clientBuilder.setRetryHandler(NO_RETRY);
            }
        }

        // basic authentication
        if (config.isSetBasicAuthUsername() && config.isSetBasicAuthPassword()) {
            CredentialsProvider credsProvider = new BasicCredentialsProvider();
            credsProvider.setCredentials(AuthScope.ANY,
                    new UsernamePasswordCredentials(config.getBasicAuthUsername(), config.getBasicAuthPassword()));
        }

        if (config.isSetAllowCompression()) {
            clientBuilder.addInterceptorFirst(new UseCompressionRequestInterceptor());
            clientBuilder.addInterceptorFirst(new UseCompressionResponseInterceptor());
        }

        // SSL context for secure connections can be created either based on
        // system or application specific properties.
        SSLContext sslcontext = SSLContexts.createSystemDefault();
        // Use custom hostname verifier to customize SSL hostname verification.
        X509HostnameVerifier hostnameVerifier = new BrowserCompatHostnameVerifier();

        // Create a registry of custom connection socket factories for supported
        // protocol schemes.
        Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create()
                .register("http", PlainConnectionSocketFactory.INSTANCE)
                .register("https", new SSLConnectionSocketFactory(sslcontext, hostnameVerifier)).build();

        clientBuilder.setConnectionManager(new PoolingHttpClientConnectionManager(socketFactoryRegistry));

        return clientBuilder;
    }

    private static class UseCompressionRequestInterceptor implements HttpRequestInterceptor {

        @Override
        public void process(HttpRequest request, HttpContext context) throws HttpException, IOException {
            if (!request.containsHeader("Accept-Encoding")) {
                request.addHeader("Accept-Encoding", "gzip, deflate");
            }
        }
    }

    private static class UseCompressionResponseInterceptor implements HttpResponseInterceptor {

        @Override
        public void process(final HttpResponse response, final HttpContext context)
                throws HttpException, IOException {

            HttpEntity entity = response.getEntity();
            Header ceheader = entity.getContentEncoding();
            if (ceheader != null) {
                HeaderElement[] codecs = ceheader.getElements();
                for (HeaderElement codec : codecs) {
                    if (codec.getName().equalsIgnoreCase("gzip")) {
                        response.setEntity(new GzipDecompressingEntity(response.getEntity()));
                        return;
                    }
                    if (codec.getName().equalsIgnoreCase("deflate")) {
                        response.setEntity(new DeflateDecompressingEntity(response.getEntity()));
                        return;
                    }
                }
            }
        }
    }

    private static class GzipDecompressingEntity extends HttpEntityWrapper {

        public GzipDecompressingEntity(final HttpEntity entity) {
            super(entity);
        }

        @Override
        public InputStream getContent() throws IOException, IllegalStateException {
            return new GZIPInputStream(wrappedEntity.getContent());
        }

        @Override
        public long getContentLength() {
            return -1;
        }
    }

    private static class DeflateDecompressingEntity extends GzipDecompressingEntity {

        public DeflateDecompressingEntity(final HttpEntity entity) {
            super(entity);
        }

        @Override
        public InputStream getContent() throws IOException, IllegalStateException {
            return new InflaterInputStream(wrappedEntity.getContent());
        }
    }
}