com.liferay.jsonwebserviceclient.JSONWebServiceClientImpl.java Source code

Java tutorial

Introduction

Here is the source code for com.liferay.jsonwebserviceclient.JSONWebServiceClientImpl.java

Source

/**
 * Copyright (c) 2000-present Liferay, Inc. All rights reserved.
 *
 * This library is free software; you can redistribute it and/or modify it under
 * the terms of the GNU Lesser General Public License as published by the Free
 * Software Foundation; either version 2.1 of the License, or (at your option)
 * any later version.
 *
 * This library is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
 * details.
 */

package com.liferay.jsonwebserviceclient;

import java.io.IOException;
import java.io.InterruptedIOException;

import java.net.SocketException;
import java.net.UnknownHostException;

import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import javax.security.auth.login.CredentialException;

import javax.servlet.http.HttpServletResponse;

import org.apache.commons.codec.Charsets;
import org.apache.http.HttpEntity;
import org.apache.http.HttpEntityEnclosingRequest;
import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
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.HttpRequestRetryHandler;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.client.utils.URLEncodedUtils;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.routing.HttpRoutePlanner;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContextBuilder;
import org.apache.http.conn.ssl.SSLContexts;
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.DefaultProxyRoutePlanner;
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;

/**
 * @author Ivica Cardic
 * @author Igor Beslic
 */
public class JSONWebServiceClientImpl implements JSONWebServiceClient {

    public void afterPropertiesSet() {
        HttpClientBuilder httpClientBuilder = HttpClients.custom();

        httpClientBuilder.setConnectionManager(getPoolingHttpClientConnectionManager());

        if ((_login != null) && (_password != null)) {
            CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

            credentialsProvider.setCredentials(new AuthScope(_hostName, _hostPort),
                    new UsernamePasswordCredentials(_login, _password));

            httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            httpClientBuilder.setRetryHandler(new HttpRequestRetryHandlerImpl());
        } else {
            if (_logger.isWarnEnabled()) {
                _logger.warn("Login and password are required");
            }
        }

        try {
            setProxyHost(httpClientBuilder);

            _closeableHttpClient = httpClientBuilder.build();

            if (_logger.isDebugEnabled()) {
                _logger.debug("Configured client for " + _protocol + "://" + _hostName);
            }
        } catch (Exception e) {
            _logger.error("Unable to configure client", e);
        }
    }

    protected PoolingHttpClientConnectionManager getPoolingHttpClientConnectionManager() {

        PoolingHttpClientConnectionManager poolingHttpClientConnectionManager = null;

        if (_keyStore != null) {
            poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(getSocketFactoryRegistry(),
                    null, null, null, 60000, TimeUnit.MILLISECONDS);
        } else {
            poolingHttpClientConnectionManager = new PoolingHttpClientConnectionManager(60000,
                    TimeUnit.MILLISECONDS);
        }

        poolingHttpClientConnectionManager.setMaxTotal(20);

        return poolingHttpClientConnectionManager;
    }

    public void destroy() {
        try {
            _closeableHttpClient.close();
        } catch (IOException e) {
            _logger.error("Unable to close client", e);
        }

        _closeableHttpClient = null;
    }

    @Override
    public String doGet(String url, Map<String, String> parameters) throws CredentialException, IOException {

        List<NameValuePair> nameValuePairs = toNameValuePairs(parameters);

        if (!nameValuePairs.isEmpty()) {
            String queryString = URLEncodedUtils.format(nameValuePairs, Charsets.UTF_8);

            url += "?" + queryString;
        }

        if (_logger.isDebugEnabled()) {
            _logger.debug("Sending GET request to " + _login + "@" + _hostName + url);
        }

        HttpGet httpGet = new HttpGet(url);

        return execute(httpGet);
    }

    @Override
    public String doPost(String url, Map<String, String> parameters) throws CredentialException, IOException {

        if (_logger.isDebugEnabled()) {
            _logger.debug("Sending POST request to " + _login + "@" + _hostName + url);
        }

        HttpPost httpPost = new HttpPost(url);

        List<NameValuePair> nameValuePairs = toNameValuePairs(parameters);

        HttpEntity httpEntity = new UrlEncodedFormEntity(nameValuePairs, Charsets.UTF_8);

        httpPost.setEntity(httpEntity);

        return execute(httpPost);
    }

    public String getHostName() {
        return _hostName;
    }

    public int getPort() {
        return _hostPort;
    }

    public String getProtocol() {
        return _protocol;
    }

    @Override
    public void resetHttpClient() {
        destroy();

        afterPropertiesSet();
    }

    public void setHostName(String hostName) {
        _hostName = hostName;
    }

    public void setHostPort(int hostPort) {
        _hostPort = hostPort;
    }

    @Override
    public void setKeyStore(KeyStore keyStore) {
        _keyStore = keyStore;
    }

    @Override
    public void setLogin(String login) {
        _login = login;
    }

    @Override
    public void setPassword(String password) {
        _password = password;
    }

    public void setProtocol(String protocol) {
        _protocol = protocol;
    }

    public void setProxyHostName(String proxyHostName) {
        _proxyHostName = proxyHostName;
    }

    public void setProxyHostPort(int proxyHostPort) {
        _proxyHostPort = proxyHostPort;
    }

    protected String execute(HttpRequestBase httpRequestBase) throws CredentialException, IOException {

        HttpHost httpHost = new HttpHost(_hostName, _hostPort, _protocol);

        try {
            if (_closeableHttpClient == null) {
                afterPropertiesSet();
            }

            HttpResponse httpResponse = _closeableHttpClient.execute(httpHost, httpRequestBase);

            StatusLine statusLine = httpResponse.getStatusLine();

            if (statusLine.getStatusCode() == HttpServletResponse.SC_NOT_FOUND) {

                if (_logger.isWarnEnabled()) {
                    _logger.warn("Status code " + statusLine.getStatusCode());
                }

                return null;
            } else if (statusLine.getStatusCode() == HttpServletResponse.SC_UNAUTHORIZED) {

                throw new CredentialException("Not authorized to access JSON web service");
            } else if (statusLine.getStatusCode() == HttpServletResponse.SC_SERVICE_UNAVAILABLE) {

                throw new JSONWebServiceUnavailableException("Service unavailable");
            }

            return EntityUtils.toString(httpResponse.getEntity(), Charsets.UTF_8);
        } finally {
            httpRequestBase.releaseConnection();
        }
    }

    protected Registry<ConnectionSocketFactory> getSocketFactoryRegistry() {
        RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder
                .<ConnectionSocketFactory>create();

        registryBuilder.register("http", new PlainConnectionSocketFactory());
        registryBuilder.register("https", getSSLConnectionSocketFactory());

        return registryBuilder.build();
    }

    protected SSLConnectionSocketFactory getSSLConnectionSocketFactory() {
        SSLContextBuilder sslContextBuilder = SSLContexts.custom();

        SSLContext sslContext = null;

        try {
            sslContextBuilder.loadTrustMaterial(_keyStore);

            sslContext = sslContextBuilder.build();

            sslContext.init(null, new TrustManager[] { new X509TrustManagerImpl() }, null);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        return new SSLConnectionSocketFactory(sslContext, new String[] { "TLSv1" }, null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
    }

    protected void setProxyHost(HttpClientBuilder httpClientBuilder) {
        if ((_proxyHostName == null) || _proxyHostName.equals("")) {
            return;
        }

        HttpHost httpHost = new HttpHost(_proxyHostName, _proxyHostPort);

        HttpRoutePlanner httpRoutePlanner = new DefaultProxyRoutePlanner(httpHost);

        httpClientBuilder.setRoutePlanner(httpRoutePlanner);
    }

    protected List<NameValuePair> toNameValuePairs(Map<String, String> parameters) {

        List<NameValuePair> nameValuePairs = new LinkedList<NameValuePair>();

        for (Map.Entry<String, String> entry : parameters.entrySet()) {
            String key = entry.getKey();

            String value = entry.getValue();

            if (value == null) {
                key = "-" + key;

                value = "";
            }

            NameValuePair nameValuePair = new BasicNameValuePair(key, value);

            nameValuePairs.add(nameValuePair);
        }

        return nameValuePairs;
    }

    private static Logger _logger = LoggerFactory.getLogger(JSONWebServiceClientImpl.class);

    private CloseableHttpClient _closeableHttpClient;
    private String _hostName;
    private int _hostPort = 80;
    private KeyStore _keyStore;
    private String _login;
    private String _password;
    private String _protocol = "http";
    private String _proxyHostName;
    private int _proxyHostPort;

    private class HttpRequestRetryHandlerImpl implements HttpRequestRetryHandler {

        public boolean retryRequest(IOException ioe, int retryCount, HttpContext httpContext) {

            if (retryCount >= 5) {
                return false;
            }

            if (ioe instanceof ConnectTimeoutException) {
                return false;
            }

            if (ioe instanceof InterruptedIOException) {
                return false;
            }

            if (ioe instanceof SocketException) {
                return true;
            }

            if (ioe instanceof SSLException) {
                return false;
            }

            if (ioe instanceof UnknownHostException) {
                return false;
            }

            HttpClientContext httpClientContext = HttpClientContext.adapt(httpContext);

            HttpRequest httpRequest = httpClientContext.getRequest();

            if (httpRequest instanceof HttpEntityEnclosingRequest) {
                return false;
            }

            return true;
        }

    };

    private class X509TrustManagerImpl implements X509TrustManager {

        public X509TrustManagerImpl() {
            try {
                TrustManagerFactory trustManagerFactory = TrustManagerFactory
                        .getInstance(TrustManagerFactory.getDefaultAlgorithm());

                trustManagerFactory.init((KeyStore) null);

                for (TrustManager trustManager : trustManagerFactory.getTrustManagers()) {

                    if (trustManager instanceof X509TrustManager) {
                        _x509TrustManager = (X509TrustManager) trustManager;

                        break;
                    }
                }
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
        }

        @Override
        public void checkClientTrusted(X509Certificate[] x509Certificates, String authType)
                throws CertificateException {

            if (x509Certificates.length != 1) {
                _x509TrustManager.checkClientTrusted(x509Certificates, authType);
            }
        }

        @Override
        public void checkServerTrusted(X509Certificate[] x509Certificates, String authType)
                throws CertificateException {

            if (x509Certificates.length != 1) {
                _x509TrustManager.checkServerTrusted(x509Certificates, authType);
            }
        }

        @Override
        public X509Certificate[] getAcceptedIssuers() {
            return _x509TrustManager.getAcceptedIssuers();
        }

        private X509TrustManager _x509TrustManager;

    }

}