com.scottjjohnson.finance.analysis.HttpClient.java Source code

Java tutorial

Introduction

Here is the source code for com.scottjjohnson.finance.analysis.HttpClient.java

Source

/*
 * Copyright 2014 Scott J. Johnson (http://scottjjohnson.com)
 * 
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.scottjjohnson.finance.analysis;

import java.io.IOException;
import java.util.Properties;

import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.config.RequestConfig.Builder;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.scottjjohnson.util.ParseUtils;

/**
 * Contains methods for building and sending HTTP requests
 */
public class HttpClient {

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

    private static final String CONNECTION_CONFIG_PROPERTIES_FILE = "connection.properties";

    private static final int DEFAULT_SOCKET_TIMEOUT = 5000;
    private static final int DEFAULT_CONNECTION_TIMEOUT = 5000;

    private Properties connectionProperties = null;
    private ResponseHandler<String> responseHandler = null;
    private RequestConfig requestConfig = null;

    /**
     * Constructor that uses configuration defaults
     */
    public HttpClient() {
        this(getDefaultConnectionProperties(), getDefaultResponseHandler());
    }

    /**
     * Constructor to allow overriding client configuration
     * 
     * @param connectionProperties key-value pairs describing connection properties
     * @param responseHandler HttpClient response handler that returns a String object
     */
    public HttpClient(Properties connectionProperties, ResponseHandler<String> responseHandler) {
        if (connectionProperties == null)
            connectionProperties = getDefaultConnectionProperties();
        if (responseHandler == null)
            responseHandler = getDefaultResponseHandler();

        this.connectionProperties = connectionProperties;
        this.responseHandler = responseHandler;
        this.requestConfig = getRequestConfig();
    }

    /**
     * Builds a request configuration based on application connection properties.
     * 
     * @return request configuration
     */
    private RequestConfig getRequestConfig() {

        int socketTimeout = ParseUtils.safeParseInt(connectionProperties.getProperty("SOCKET_TIMEOUT"),
                DEFAULT_SOCKET_TIMEOUT);
        int connectionTimeout = ParseUtils.safeParseInt(connectionProperties.getProperty("CONNECTION_TIMEOUT"),
                DEFAULT_CONNECTION_TIMEOUT);
        String proxyHost = connectionProperties.getProperty("PROXY_HOST");
        int proxyPort = ParseUtils.safeParseInt(connectionProperties.getProperty("PROXY_PORT"), 0);

        Builder config = RequestConfig.custom().setSocketTimeout(socketTimeout)
                .setConnectTimeout(connectionTimeout);

        if (proxyHost != null && proxyPort > 0) {
            config.setProxy(new HttpHost(proxyHost, proxyPort));
        }

        return config.build();
    }

    /**
     * Extracts http connection properties from the configuration file and returns them as a Properties object.
     * 
     * @returns map of cookie key-value pairs (never null)
     */
    public static Properties getDefaultConnectionProperties() {
        Properties connectionProps = new Properties();
        try {
            ClassLoader loader = HttpClient.class.getClassLoader();
            connectionProps.load(loader.getResourceAsStream(CONNECTION_CONFIG_PROPERTIES_FILE));

            LOGGER.debug("Connection configuration properties: {}.", connectionProps);
        } catch (IOException e) {
            LOGGER.warn("Unable to load connection properties from {}.", CONNECTION_CONFIG_PROPERTIES_FILE);
        }

        return connectionProps;
    }

    /**
     * Builds a simple HTTP response handler that checks for status of 2XX.
     * 
     * @return response handler
     */
    public static ResponseHandler<String> getDefaultResponseHandler() {

        // Create a custom response handler -- from httpclient docs
        return new ResponseHandler<String>() {

            @Override
            public String handleResponse(final HttpResponse response) throws ClientProtocolException, IOException {
                int status = response.getStatusLine().getStatusCode();
                if (status >= 200 && status < 300) {
                    HttpEntity entity = response.getEntity();
                    return entity != null ? EntityUtils.toString(entity) : null;
                } else {
                    throw new ClientProtocolException("Unexpected response status: " + status);
                }
            }
        };
    }

    /**
     * Executes a HTTP GET request.
     * 
     * @param url
     *            URL with optional query parameters
     * @return response body
     * @throws IOException
     *             if the HTTP request fails
     */
    public String sendGetRequest(String url) throws IOException {

        // I'm not using try-with-resources because I want to handle an exception on close() differently than other
        // exceptions.  Other exceptions are allowed to bubble up.
        CloseableHttpClient apacheHttpClient = HttpClients.createDefault();
        String responseBody = null;

        LOGGER.debug("URL = {}", url);

        try {
            HttpGet httpGet = new HttpGet(url);
            httpGet.setConfig(requestConfig);
            responseBody = apacheHttpClient.execute(httpGet, responseHandler);
        } finally {
            try {
                apacheHttpClient.close();
            } catch (IOException e) {
                LOGGER.debug("Non-fatal exception: Caught IOException when calling ClosableHttpClient.close().", e);
            }
        }

        LOGGER.debug("HTTP Response body = {}", responseBody);

        return responseBody;
    }
}