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.io.UnsupportedEncodingException;

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.Collections;
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.servlet.http.HttpServletResponse;

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.AuthScheme;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.ChallengeState;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.AuthCache;
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.ClientContext;
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.HttpClientConnectionManager;
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.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicAuthCache;
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.client.ProxyAuthenticationStrategy;
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();

        HttpClientConnectionManager httpClientConnectionManager = getPoolingHttpClientConnectionManager();

        httpClientBuilder.setConnectionManager(httpClientConnectionManager);

        if ((!isNull(_login) && !isNull(_password)) || (!isNull(_proxyLogin) && !isNull(_proxyPassword))) {

            CredentialsProvider credentialsProvider = new BasicCredentialsProvider();

            if (!isNull(_login)) {
                credentialsProvider.setCredentials(new AuthScope(_hostName, _hostPort),
                        new UsernamePasswordCredentials(_login, _password));
            } else {
                if (_logger.isInfoEnabled()) {
                    _logger.info("No credentials are used");
                }
            }

            if (!isNull(_proxyLogin)) {
                credentialsProvider.setCredentials(new AuthScope(_proxyHostName, _proxyHostPort),
                        new UsernamePasswordCredentials(_proxyLogin, _proxyPassword));
            }

            httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider);
            httpClientBuilder.setRetryHandler(new HttpRequestRetryHandlerImpl());
        }

        try {
            setProxyHost(httpClientBuilder);

            _closeableHttpClient = httpClientBuilder.build();

            _idleConnectionMonitorThread = new IdleConnectionMonitorThread(httpClientConnectionManager);

            _idleConnectionMonitorThread.start();

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

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

        _closeableHttpClient = null;

        _idleConnectionMonitorThread.shutdown();
    }

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

        return doGet(url, parameters, Collections.<String, String>emptyMap());
    }

    @Override
    public String doGet(String url, Map<String, String> parameters, Map<String, String> headers)
            throws JSONWebServiceTransportException {

        List<NameValuePair> nameValuePairs = toNameValuePairs(parameters);

        if (!nameValuePairs.isEmpty()) {
            String queryString = URLEncodedUtils.format(nameValuePairs, "utf8");

            url += "?" + queryString;
        }

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

        HttpGet httpGet = new HttpGet(url);

        for (String key : headers.keySet()) {
            httpGet.addHeader(key, headers.get(key));
        }

        for (String key : _headers.keySet()) {
            httpGet.addHeader(key, _headers.get(key));
        }

        return execute(httpGet);
    }

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

        return doPost(url, parameters, Collections.<String, String>emptyMap());
    }

    @Override
    public String doPost(String url, Map<String, String> parameters, Map<String, String> headers)
            throws JSONWebServiceTransportException {

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

        try {
            HttpPost httpPost = new HttpPost(url);

            List<NameValuePair> nameValuePairs = toNameValuePairs(parameters);

            HttpEntity httpEntity = new UrlEncodedFormEntity(nameValuePairs, "utf8");

            for (String key : headers.keySet()) {
                httpPost.addHeader(key, headers.get(key));
            }

            for (String key : _headers.keySet()) {
                httpPost.addHeader(key, _headers.get(key));
            }

            httpPost.setEntity(httpEntity);

            return execute(httpPost);
        } catch (UnsupportedEncodingException uee) {
            throw new JSONWebServiceTransportException.CommunicationFailure(uee);
        }
    }

    @Override
    public String doPostAsJSON(String url, String json) throws JSONWebServiceTransportException {

        return doPostAsJSON(url, json, Collections.<String, String>emptyMap());
    }

    @Override
    public String doPostAsJSON(String url, String json, Map<String, String> headers)
            throws JSONWebServiceTransportException {

        HttpPost httpPost = new HttpPost(url);

        for (String key : headers.keySet()) {
            httpPost.addHeader(key, headers.get(key));
        }

        for (String key : _headers.keySet()) {
            httpPost.addHeader(key, _headers.get(key));
        }

        StringEntity stringEntity = new StringEntity(json.toString(), "utf8");

        stringEntity.setContentType("application/json");

        httpPost.setEntity(stringEntity);

        return execute(httpPost);
    }

    public Map<String, String> getHeaders() {
        return _headers;
    }

    public String getHostName() {
        return _hostName;
    }

    public int getHostPort() {
        return _hostPort;
    }

    public String getProtocol() {
        return _protocol;
    }

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

        afterPropertiesSet();
    }

    public void setHeaders(Map<String, String> headers) {
        _headers = headers;
    }

    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;
    }

    public void setProxyLogin(String proxyLogin) {
        _proxyLogin = proxyLogin;
    }

    public void setProxyPassword(String proxyPassword) {
        _proxyPassword = proxyPassword;
    }

    protected String execute(HttpRequestBase httpRequestBase) throws JSONWebServiceTransportException {

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

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

            HttpResponse httpResponse = null;

            if (!isNull(_login) && !isNull(_password)) {
                HttpClientContext httpClientContext = HttpClientContext.create();

                AuthCache authCache = new BasicAuthCache();

                AuthScheme authScheme = null;

                if (!isNull(_proxyHostName)) {
                    authScheme = new BasicScheme(ChallengeState.PROXY);
                } else {
                    authScheme = new BasicScheme(ChallengeState.TARGET);
                }

                authCache.put(httpHost, authScheme);

                httpClientContext.setAttribute(ClientContext.AUTH_CACHE, authCache);

                httpResponse = _closeableHttpClient.execute(httpHost, httpRequestBase, httpClientContext);
            } else {
                httpResponse = _closeableHttpClient.execute(httpHost, httpRequestBase);
            }

            StatusLine statusLine = httpResponse.getStatusLine();

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

                throw new JSONWebServiceTransportException.AuthenticationFailure(
                        "Not authorized to access JSON web service");
            } else if (statusLine.getStatusCode() >= 400) {
                String message = null;

                if (httpResponse.getEntity() != null) {
                    HttpEntity httpEntity = httpResponse.getEntity();

                    message = EntityUtils.toString(httpEntity, "utf8");
                }

                throw new JSONWebServiceTransportException.CommunicationFailure(message,
                        statusLine.getStatusCode());
            }

            return EntityUtils.toString(httpResponse.getEntity(), "utf8");
        } catch (IOException ioe) {
            throw new JSONWebServiceTransportException.CommunicationFailure("Unable to transmit request", ioe);
        } finally {
            httpRequestBase.releaseConnection();
        }
    }

    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;
    }

    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 boolean isNull(String s) {
        if ((s == null) || s.equals("")) {
            return true;
        }

        return false;
    }

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

        httpClientBuilder.setProxy(new HttpHost(_proxyHostName, _proxyHostPort));
        httpClientBuilder.setProxyAuthenticationStrategy(new ProxyAuthenticationStrategy());
    }

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

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

        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 Map<String, String> _headers = Collections.emptyMap();
    private String _hostName;
    private int _hostPort = 80;
    private IdleConnectionMonitorThread _idleConnectionMonitorThread;
    private KeyStore _keyStore;
    private String _login;
    private String _password;
    private String _protocol = "http";
    private String _proxyHostName;
    private int _proxyHostPort;
    private String _proxyLogin;
    private String _proxyPassword;

    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 IdleConnectionMonitorThread extends Thread {

        public IdleConnectionMonitorThread(HttpClientConnectionManager httpClientConnectionManager) {

            _httpClientConnectionManager = httpClientConnectionManager;
        }

        @Override
        public void run() {
            try {
                while (!_shutdown) {
                    synchronized (this) {
                        wait(5000);

                        _httpClientConnectionManager.closeExpiredConnections();

                        _httpClientConnectionManager.closeIdleConnections(30, TimeUnit.SECONDS);
                    }
                }
            } catch (InterruptedException ie) {
            }
        }

        public void shutdown() {
            _shutdown = true;

            synchronized (this) {
                notifyAll();
            }
        }

        private final HttpClientConnectionManager _httpClientConnectionManager;
        private volatile boolean _shutdown;

    }

    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;

    }

}