code.google.restclient.core.Hitter.java Source code

Java tutorial

Introduction

Here is the source code for code.google.restclient.core.Hitter.java

Source

/*******************************************************************************
 * Copyright (c) 2010 Yadu.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 * 
 * Contributors:
 *     Yadu - initial API and implementation
 ******************************************************************************/

package code.google.restclient.core;

import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.LinkedHashMap;
import java.util.Map;

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

import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.HttpVersion;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpTrace;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnRouteParams;
import org.apache.http.conn.scheme.PlainSocketFactory;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.message.BasicHeader;
import org.apache.http.params.HttpParams;
import org.apache.http.params.HttpProtocolParams;
import org.apache.http.params.SyncBasicHttpParams;
import org.apache.log4j.Logger;

import code.google.restclient.common.RCConstants;
import code.google.restclient.common.RCUtil;

/**
 * @author Yaduvendra.Singh
 */
public class Hitter {

    private static final Logger LOG = Logger.getLogger(Hitter.class);
    private static final boolean DEBUG_ENABLED = LOG.isDebugEnabled();

    private static HttpClient client = null;
    private static ClientConnectionManager conman = null;
    private String proxyHost = RCConstants.SYS_PROXY_ENABLED;
    private int proxyPort = -1;
    private Map<String, String> headers;

    // Dummy object for synchronizing getHttpClient()
    private final Object lock;

    public Hitter() {
        configureSysProxy();
        headers = new LinkedHashMap<String, String>();
        lock = new Object();
    }

    public Hitter(Map<String, String> headers) {
        this();
        this.headers = headers;
    }

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

    public void setProxy(String host, int port) {
        proxyHost = host;
        proxyPort = port;
    }

    private void configureSysProxy() {
        try {
            // check System properties
            if (RCConstants.SYS_PROXY_ENABLED.equals(proxyHost)) {
                String proxyHostEnvStr = System.getProperty("https.proxyHost");
                String proxyPortENvStr = System.getProperty("https.proxyPort");
                if (proxyHostEnvStr != null) {
                    proxyHost = proxyHostEnvStr;
                    proxyPort = Integer.parseInt(proxyPortENvStr);
                } else {
                    proxyHost = "";
                    proxyPort = -1;
                }
            } else if (RCConstants.SYS_PROXY_DISABLED.equals(proxyHost)) {
                proxyHost = "";
                proxyPort = -1;
            }
        } catch (Exception e) {
            LOG.error("failed to get proxy from system props");
            proxyHost = "";
            proxyPort = -1;
        }
    }

    private boolean isProxyConfigured() {
        if (proxyHost == null || "".equals(proxyHost))
            return false;
        if ("DISABLED".equals(proxyHost))
            return false;
        if (proxyPort == -1)
            return false;

        return true;
    }

    /**
     * Method to make POST or PUT request by sending http entity (as body)
     */
    public void hit(String url, String methodName, HttpHandler handler, Map<String, String> requestHeaders)
            throws Exception {

        if (DEBUG_ENABLED)
            LOG.debug("hit() - method => " + methodName + ", url => " + url);

        if (HttpGet.METHOD_NAME.equals(methodName)) {
            if (DEBUG_ENABLED)
                LOG.debug("hit() - ===> GET " + url);
            hit(url, new HttpGet(url), handler, requestHeaders);
        } else if (HttpHead.METHOD_NAME.equals(methodName)) {
            if (DEBUG_ENABLED)
                LOG.debug("hit() - ===> HEAD " + url);
            hit(url, new HttpHead(url), handler, requestHeaders);
        } else if (HttpDelete.METHOD_NAME.equals(methodName)) {
            if (DEBUG_ENABLED)
                LOG.debug("hit() - ===> DELETE " + url);
            hit(url, new HttpDelete(url), handler, requestHeaders);
        } else if (HttpOptions.METHOD_NAME.equals(methodName)) {
            if (DEBUG_ENABLED)
                LOG.debug("hit() - ===> OPTIONS " + url);
            hit(url, new HttpOptions(url), handler, requestHeaders);
        } else if (HttpTrace.METHOD_NAME.equals(methodName)) {
            if (DEBUG_ENABLED)
                LOG.debug("hit() - ===> TRACE " + url);
            hit(url, new HttpTrace(url), handler, requestHeaders);
        } else if (HttpPost.METHOD_NAME.equals(methodName)) { // POST
            if (DEBUG_ENABLED)
                LOG.debug("hit() - ===> POST " + url);
            HttpPost httpPost = new HttpPost(url);
            httpPost.setEntity(handler.getReqBodyEntity());
            hit(url, httpPost, handler, requestHeaders);
        } else if (HttpPut.METHOD_NAME.equals(methodName)) { // PUT
            if (DEBUG_ENABLED)
                LOG.debug("hit() - ===> PUT " + url);
            HttpPut httpPut = new HttpPut(url);
            httpPut.setEntity(handler.getReqBodyEntity());
            hit(url, httpPut, handler, requestHeaders);
        } else {
            throw new IllegalArgumentException("hit(): Unsupported method => " + methodName);
        }
    }

    private HttpHandler hit(String url, HttpUriRequest request, HttpHandler handler,
            Map<String, String> requestHeaders) throws Exception {

        if (DEBUG_ENABLED)
            LOG.debug("hit() - hitting url (params encoded) --> " + url);

        HttpResponse response = null;
        HttpClient client = getHttpClient();

        // set request headers
        Map<String, String> hs = new LinkedHashMap<String, String>();
        if (headers != null)
            hs.putAll(headers);
        if (requestHeaders != null)
            hs.putAll(requestHeaders);
        if (!hs.isEmpty()) {
            for (String header : hs.keySet())
                request.setHeader(new BasicHeader(header, hs.get(header)));
        }
        handler.setRequest(request);

        response = client.execute(request); // **** execute request ****
        handler.setResponse(response);
        return handler;

    }

    /*
     * Since DefaultHttpClient and its connection manager are all thread-safe, all HttpClient
     * impl configuration should be synchronized. this entire dance is here because we want to use
     * a ThreadSafeClientConnManager and not the SingleClientConnManager.
     */
    private HttpClient getHttpClient()
            throws KeyManagementException, NoSuchAlgorithmException, UnrecoverableKeyException, KeyStoreException {
        // Early exit: already configured. Want all the gets to be fast so not synchronizing it
        if (client != null)
            return client;

        synchronized (lock) {
            HttpParams params = new SyncBasicHttpParams();

            // Set proxy
            if (isProxyConfigured()) {
                if (DEBUG_ENABLED)
                    LOG.debug("CONFIGURING PROXY TO => " + proxyHost + ":" + proxyPort);
                HttpHost proxy = new HttpHost(proxyHost, proxyPort);
                ConnRouteParams.setDefaultProxy(params, proxy);
            }

            // http params apply at client level so shared by all request. They can be overridden by params set at request level.
            HttpProtocolParams.setVersion(params, HttpVersion.HTTP_1_1);
            HttpProtocolParams.setContentCharset(params, RCConstants.DEFAULT_CHARSET);
            HttpProtocolParams.setUserAgent(params, RCConstants.APP_DISPLAY_NAME);
            HttpClientParams.setRedirecting(params, true);

            /*
             HttpConnectionParams.setTcpNoDelay(params, true);
             HttpConnectionParams.setLinger(params, 30);
             HttpConnectionParams.setConnectionTimeout(params, 30000);
             HttpConnectionParams.setSoTimeout(params, 30000);
             HttpProtocolParams.setUseExpectContinue(params, false);
             HttpClientParams.setCookiePolicy(params,
             CookiePolicy.BROWSER_COMPATIBILITY);
             */

            SchemeRegistry registry = new SchemeRegistry();
            registry.register(getPlainScheme());
            registry.register(getSSLScheme(isDisabledCertVerifier(), isDisabledHostVerifier()));

            if (conman == null)
                conman = new ThreadSafeClientConnManager(registry);

            if (client == null) {
                client = new DefaultHttpClient(conman);
                ((DefaultHttpClient) client).setParams(params);
                ((DefaultHttpClient) client).setKeepAliveStrategy(new CustomKeepAliveStrategy());
                /*
                // set custom request retry handler which doesn't allow retry for POST request
                HttpRequestRetryHandler retryHandler = new CustomRetryHandler();
                ((DefaultHttpClient) client).setHttpRequestRetryHandler(retryHandler);
                client.getParams().setParameter(CoreProtocolPNames.WAIT_FOR_CONTINUE, 10000); // 10 seconds
                */

            }

            return client;
        }
    }

    private Scheme getPlainScheme() {
        return new Scheme("http", RCConstants.PLAIN_SOCKET_PORT, PlainSocketFactory.getSocketFactory());
    }

    private Scheme getSSLScheme(boolean disableVerifyCert, boolean disableVerifyHost)
            throws NoSuchAlgorithmException, KeyManagementException, UnrecoverableKeyException, KeyStoreException {
        SSLSocketFactory sslFactory = null;

        if (isUseSelfSignedCertVerifier()) {
            TrustSelfSignedStrategy selfSignedStrategy = new TrustSelfSignedStrategy();

            // AllowAllHostnameVerifier doesn't verify host names contained in SSL certificate. It should not be set in
            // production environment. It may allow man in middle attack. Other host name verifiers for specific needs
            // are StrictHostnameVerifier and BrowserCompatHostnameVerifier.
            if (disableVerifyHost)
                sslFactory = new SSLSocketFactory(selfSignedStrategy, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            else
                sslFactory = new SSLSocketFactory(selfSignedStrategy); // BROWSER_COMPATIBLE_HOSTNAME_VERIFIER is used by default

        } else {
            SSLContext sslContext = SSLContext.getInstance("TLS");

            if (disableVerifyCert)
                sslContext.init(null, new TrustManager[] { getNoCheckTrustManager() }, null);
            else
                sslContext.init(null, null, null);

            if (disableVerifyHost)
                sslFactory = new SSLSocketFactory(sslContext, SSLSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER);
            else
                sslFactory = new SSLSocketFactory(sslContext);
        }

        return new Scheme("https", RCConstants.SSL_SOCKET_PORT, sslFactory);
    }

    private TrustManager getNoCheckTrustManager() {
        return new X509TrustManager() {
            @Override
            public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // Do nothing
            }

            @Override
            public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
                // Do nothing
            }

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

    /**
     * First checks property disable.ssl.cert.verifier as system property if not found it uses configured one.
     * 
     * @return
     */
    private boolean isDisabledCertVerifier() {
        String disable = RCUtil.getSSLOverrideProperty("disable.ssl.cert.verifier");
        if (disable == null)
            return RCConstants.DISABLE_SSL_CERT_VERIFIER;
        else
            return new Boolean(disable);
    }

    /**
     * First checks property disable.host.name.verifier as system property if not found it uses configured one.
     * 
     * @return
     */
    private boolean isDisabledHostVerifier() {
        String disable = RCUtil.getSSLOverrideProperty("disable.host.name.verifier");
        if (disable == null)
            return RCConstants.DISABLE_HOST_NAME_VERIFIER;
        else
            return new Boolean(disable);
    }

    /**
     * First checks property disable.host.name.verifier as system property if not found it uses configured one.
     * 
     * @return
     */
    private boolean isUseSelfSignedCertVerifier() {
        String disable = RCUtil.getSSLOverrideProperty("use.self.signed.cert.verifier");
        if (disable == null)
            return RCConstants.USE_SELF_SIGNED_CERT_VERIFIER;
        else
            return new Boolean(disable);
    }

    /*
    public static void main(String[] args) {
    Hitter hitter = new Hitter();
    String url = "https://localhost.mlbam.com:8443/";
    HttpHandler httpHandler = new HttpHandler();
        
    try {
        hitter.hit(url, "GET", httpHandler, null);
    } catch ( Exception e ) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    LOG.debug("Response Headers: \n" + httpHandler.getResponseHeaders());
    System.out.println("Response Headers: \n" + httpHandler.getResponseHeaders());
    }
    */

}