eu.itesla_project.histodb.client.impl.HistoDbHttpClientImpl.java Source code

Java tutorial

Introduction

Here is the source code for eu.itesla_project.histodb.client.impl.HistoDbHttpClientImpl.java

Source

/**
 * Copyright (c) 2016, All partners of the iTesla project (http://www.itesla-project.eu/consortium)
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 */
package eu.itesla_project.histodb.client.impl;

import eu.itesla_project.commons.io.ForwardingInputStream;
import eu.itesla_project.modules.histo.cache.HistoDbCache;
import org.apache.commons.io.input.TeeInputStream;
import org.apache.http.HttpHost;
import org.apache.http.StatusLine;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.*;
import org.apache.http.client.protocol.HttpClientContext;
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.LayeredConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.CloseableHttpClient;
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.message.BasicNameValuePair;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;
import javax.net.ssl.X509TrustManager;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.nio.charset.StandardCharsets;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 * @author Geoffroy Jamgotchian <geoffroy.jamgotchian at rte-france.com>
 */
public class HistoDbHttpClientImpl implements HistoDbHttpClient {

    private static final Logger LOGGER = LoggerFactory.getLogger(HistoDbHttpClientImpl.class);

    private final HistoDbCache cache;

    private CloseableHttpClient httpClient;

    HistoDbHttpClientImpl(HistoDbCache cache) {
        this.cache = cache;
    }

    @Override
    public HistoDbCache getCache() {
        return cache;
    }

    private synchronized CloseableHttpClient getHttpclient(HistoDbConfig config) {
        if (httpClient == null) {
            try {
                ConnectionSocketFactory plainsf = PlainConnectionSocketFactory.getSocketFactory();
                TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {

                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return null;
                    }

                    @Override
                    public void checkClientTrusted(X509Certificate[] certs, String authType) {
                    }

                    @Override
                    public void checkServerTrusted(X509Certificate[] certs, String authType) {
                    }
                } };
                SSLContext sslContext = SSLContext.getInstance("SSL");
                sslContext.init(null, trustAllCerts, new java.security.SecureRandom());
                LayeredConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslContext);
                Registry<ConnectionSocketFactory> r = RegistryBuilder.<ConnectionSocketFactory>create()
                        .register("http", plainsf).register("https", sslsf).build();
                PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(r);
                cm.setDefaultMaxPerRoute(10);
                cm.setMaxTotal(20);
                HttpClientBuilder httpClientBuilder = HttpClients.custom().setConnectionManager(cm);
                CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
                credentialsProvider.setCredentials(
                        new AuthScope(new HttpHost(config.getConnectionParameters().getHost(),
                                config.getConnectionParameters().getPort())),
                        new UsernamePasswordCredentials(config.getConnectionParameters().getUserName(),
                                config.getConnectionParameters().getPassword()));
                if (config.getProxyParameters() != null) {
                    HttpHost proxy = new HttpHost(config.getProxyParameters().getHost(),
                            config.getProxyParameters().getPort());
                    credentialsProvider.setCredentials(new AuthScope(proxy), new UsernamePasswordCredentials(
                            config.getProxyParameters().getUserName(), config.getProxyParameters().getPassword()));
                    httpClientBuilder.setProxy(proxy);
                }
                httpClient = httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider).build();
            } catch (KeyManagementException | NoSuchAlgorithmException e) {
                throw new RuntimeException(e);
            }
        }
        return httpClient;
    }

    private InputStream httpRequest(HttpUriRequest request, HistoDbUrl url) throws IOException {
        if (LOGGER.isTraceEnabled()) {
            LOGGER.trace("Querying histo DB " + url.format());
        }
        if (LOGGER.isDebugEnabled()) {
            LOGGER.debug("Querying histo DB " + url.prettyFormat());
        }

        long start = System.currentTimeMillis();

        HttpContext context = HttpClientContext.create();
        CloseableHttpResponse response = getHttpclient(url.getConfig()).execute(request, context);
        StatusLine statusLine = response.getStatusLine();

        switch (statusLine.getStatusCode()) {
        case 200:
            long duration = System.currentTimeMillis() - start;
            LOGGER.debug("Query done in {} ms", duration);
            return new ForwardingInputStream<InputStream>(response.getEntity().getContent()) {
                @Override
                public void close() throws IOException {
                    super.close();
                    EntityUtils.consume(response.getEntity());
                    response.close();
                }
            };

        case 202:
            EntityUtils.consume(response.getEntity());
            response.close();
            return null;

        default:
            throw new RuntimeException("Query failed with status " + statusLine + " : " + url);
        }
    }

    private InputStream cachedHttpRequest(HttpUriRequest request, HistoDbUrl url) throws IOException {
        InputStream is = null;

        if (cache != null) {
            is = cache.getData(url.format());
        }

        if (is != null) {
            if (LOGGER.isTraceEnabled()) {
                LOGGER.trace("Using cached data for query " + url.format());
            }
            if (LOGGER.isDebugEnabled()) {
                LOGGER.debug("Using cached data for query " + url.prettyFormat());
            }
        } else {
            is = httpRequest(request, url);

            if (cache != null && is != null) {
                OutputStream os = cache.putData(url.format());
                is = new TeeInputStream(is, os, true);
            }
        }

        return is;
    }

    @Override
    public InputStream getHttpRequest(HistoDbUrl url) throws IOException {
        HttpRequestBase httpReq;
        String urlStr = url.format();
        if (urlStr.length() > 255) { // arbitrary very low value
            // replace by a post because of url size limit
            HttpPost httpPost = new HttpPost(
                    new HistoDbUrl(url.getConfig(), url.getPath(), Collections.emptyMap()).format());
            List<BasicNameValuePair> parameters = url.getQuery().entrySet().stream()
                    .map(entry -> new BasicNameValuePair(entry.getKey(), entry.getValue()))
                    .collect(Collectors.toList());
            httpPost.setEntity(new UrlEncodedFormEntity(parameters, StandardCharsets.UTF_8));
            httpReq = httpPost;
        } else {
            httpReq = new HttpGet(urlStr);
        }
        return cachedHttpRequest(httpReq, url);
    }

    @Override
    public InputStream postHttpRequest(HistoDbUrl url, byte[] content) throws IOException {
        HttpPost httppost = new HttpPost(url.format());
        httppost.setEntity(new ByteArrayEntity(content));
        return cachedHttpRequest(httppost, url);
    }

    @Override
    public InputStream deleteHttpRequest(HistoDbUrl url) throws IOException {
        HttpDelete httpdel = new HttpDelete(url.format());
        return cachedHttpRequest(httpdel, url);
    }

    @Override
    public void close() throws Exception {
        if (httpClient != null) {
            httpClient.close();
        }
        if (cache != null) {
            cache.close();
        }
    }

}