de.escidoc.core.common.util.service.ConnectionUtility.java Source code

Java tutorial

Introduction

Here is the source code for de.escidoc.core.common.util.service.ConnectionUtility.java

Source

/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the Common Development and Distribution License, Version 1.0
 * only (the "License"). You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at license/ESCIDOC.LICENSE or http://www.escidoc.de/license. See the License for
 * the specific language governing permissions and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each file and include the License file at
 * license/ESCIDOC.LICENSE. If applicable, add the following below this CDDL HEADER, with the fields enclosed by
 * brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 *
 * Copyright 2006-2011 Fachinformationszentrum Karlsruhe Gesellschaft fuer wissenschaftlich-technische Information mbH
 * and Max-Planck-Gesellschaft zur Foerderung der Wissenschaft e.V. All rights reserved. Use is subject to license
 * terms.
 */
package de.escidoc.core.common.util.service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.regex.Pattern;

import javax.servlet.http.HttpServletResponse;

import org.apache.http.HttpHost;
import org.apache.http.HttpRequest;
import org.apache.http.HttpRequestInterceptor;
import org.apache.http.HttpResponse;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.AuthState;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.client.HttpClient;
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.params.CookiePolicy;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.scheme.SchemeRegistry;
import org.apache.http.cookie.Cookie;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.impl.conn.tsccm.ThreadSafeClientConnManager;
import org.apache.http.params.BasicHttpParams;
import org.apache.http.params.DefaultedHttpParams;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;
import org.apache.http.protocol.ExecutionContext;
import org.apache.http.protocol.HTTP;
import org.apache.http.protocol.HttpContext;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import de.escidoc.core.common.exceptions.system.WebserverSystemException;
import de.escidoc.core.common.util.configuration.EscidocConfiguration;

/**
 * An utility class for HTTP requests.<br />
 * This class uses pooled HTTP connections.
 * 
 * @author Steffen Wagner
 */
@Service("escidoc.core.common.util.service.ConnectionUtility")
public class ConnectionUtility {

    private static final Logger LOG = LoggerFactory.getLogger(ConnectionUtility.class);

    private static final Pattern SPLIT_PATTERN = Pattern.compile(":");

    /**
     * TODO: The connection timeout is limited to 20000ms at maximum within the HttpClient.
     */
    private static final int DEFAULT_CONNECTION_TIMEOUT = 1000 * 60; // 60 seconds

    private static final int DEFAULT_SO_TIMEOUT = 1000 * 60; // 60 seconds

    private static final int HTTP_MAX_CONNECTIONS_PER_HOST = 30;

    private static final int HTTP_MAX_TOTAL_CONNECTIONS_FACTOR = 3;

    private static final int HTTP_RESPONSE_CLASS = 100;

    /**
     * The default constructor creates a {@link SchemeRegistry} with the default {@link Scheme}s HTTP and HTTPS.
     */
    private static final ThreadSafeClientConnManager CONN_MANAGER = new ThreadSafeClientConnManager();

    private static HttpHost PROXY_HOST;

    private static Pattern NON_PROXY_HOSTS_PATTERN;

    private static final HttpParams DEFAULT_HTTP_PARAMS = new BasicHttpParams();

    static {
        init();
    }

    /**
     * Allow instantiation for Spring only.
     */
    protected ConnectionUtility() {

    }

    private static void init() {
        /*
         * Configuration independant settings and default values.
         */
        // ConnectionManager
        CONN_MANAGER.setMaxTotal(HTTP_MAX_TOTAL_CONNECTIONS_FACTOR);
        CONN_MANAGER.setDefaultMaxPerRoute(HTTP_MAX_CONNECTIONS_PER_HOST);
        // Default HttpParams
        HttpConnectionParams.setConnectionTimeout(DEFAULT_HTTP_PARAMS, DEFAULT_CONNECTION_TIMEOUT);
        HttpConnectionParams.setSoTimeout(DEFAULT_HTTP_PARAMS, DEFAULT_SO_TIMEOUT);

        /*
         * Configuration dependant settins.
         */
        final EscidocConfiguration config = EscidocConfiguration.getInstance();
        if (config == null) {
            if (LOG.isWarnEnabled()) {
                LOG.warn("Unable to get eSciDoc configuration.");
            }
            return;
        }

        // Proxy configuration: non proxy hosts (exclusions)
        String nonProxyHosts = config.get(EscidocConfiguration.ESCIDOC_CORE_NON_PROXY_HOSTS);
        if (nonProxyHosts != null && nonProxyHosts.trim().length() != 0) {
            nonProxyHosts = nonProxyHosts.replaceAll("\\.", "\\\\.");
            nonProxyHosts = nonProxyHosts.replaceAll("\\*", "");
            nonProxyHosts = nonProxyHosts.replaceAll("\\?", "\\\\?");
            NON_PROXY_HOSTS_PATTERN = Pattern.compile(nonProxyHosts);
        }

        // Proxy configuration: The proxy host to use
        final String proxyHostName = config.get(EscidocConfiguration.ESCIDOC_CORE_PROXY_HOST);
        final String proxyPort = config.get(EscidocConfiguration.ESCIDOC_CORE_PROXY_PORT);
        if (proxyHostName != null && !proxyHostName.isEmpty()) {
            PROXY_HOST = proxyPort != null && !proxyPort.isEmpty()
                    ? new HttpHost(proxyHostName, Integer.parseInt(proxyPort))
                    : new HttpHost(proxyHostName);
        }

        // HttpClient configuration
        String property = null;
        if ((property = config.get(EscidocConfiguration.HTTP_CONNECTION_TIMEOUT)) != null) {
            try {
                HttpConnectionParams.setConnectionTimeout(DEFAULT_HTTP_PARAMS, Integer.parseInt(property));
            } catch (final NumberFormatException e) {
                if (LOG.isWarnEnabled()) {
                    LOG.warn("Unable to use the " + EscidocConfiguration.HTTP_CONNECTION_TIMEOUT + " property.", e);
                }
            }
        }
        if ((property = config.get(EscidocConfiguration.HTTP_SOCKET_TIMEOUT)) != null) {
            try {
                HttpConnectionParams.setSoTimeout(DEFAULT_HTTP_PARAMS, Integer.parseInt(property));
            } catch (final NumberFormatException e) {
                if (LOG.isWarnEnabled()) {
                    LOG.warn("Unable to use the " + EscidocConfiguration.HTTP_SOCKET_TIMEOUT + " property.", e);
                }
            }
        }
    }

    /**
     * Perform a GET-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. If the URL contains an authentication part, the UserCredentials will be set to
     * the {@link HttpClient} instance. Depending on the specified <tt>url</tt> and the settings from the
     * <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a proxy or not.
     * 
     * @param url
     *            The resource URL.
     * @return String response as String.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public String getRequestURLAsString(final URL url) throws WebserverSystemException {
        return getRequestURLAsString(null, url);
    }

    /**
     * Perform a GET-request using the specified {@link HttpClient}. If the URL contains an authentication part, the
     * UserCredentials will be set to the {@link HttpClient} instance. Depending on the specified <tt>url</tt> and the
     * settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a
     * proxy or not.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     *            The {@link HttpClient} to use.
     * @param url
     *            The resource URL.
     * @return The response as a String.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public String getRequestURLAsString(final DefaultHttpClient client, final URL url)
            throws WebserverSystemException {
        final HttpResponse httpResponse = getRequestURL(client, url);
        return readResponse(httpResponse);
    }

    /**
     * Perform a GET-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. The UserCredentials will be set to the {@link HttpClient} instance using the
     * specified <tt>username</tt> and <tt>password</tt>. Depending on the specified <tt>url</tt> and the settings from
     * the <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a proxy or not.
     * 
     * @param url
     *            The resource URL.
     * @param username
     *            User name for authentication.
     * @param password
     *            Password for authentication.
     * @return String response as String.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public String getRequestURLAsString(final URL url, final String username, final String password)
            throws WebserverSystemException {
        return getRequestURLAsString(null, url, username, password);
    }

    /**
     * Perform a GET-request using the specified {@link HttpClient}. The UserCredentials will be set to the
     * {@link HttpClient} instance using the specified <tt>username</tt> and <tt>password</tt>. Depending on the
     * specified <tt>url</tt> and the settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient}
     * instance will be configured to use a proxy or not.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     *            The {@link HttpClient} to use.
     * @param url
     *            The resource URL.
     * @param username
     *            User name for authentication.
     * @param password
     *            Password for authentication.
     * @return String response as String.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public String getRequestURLAsString(final DefaultHttpClient client, final URL url, final String username,
            final String password) throws WebserverSystemException {
        final HttpResponse httpResponse = getRequestURL(client, url, username, password);
        return readResponse(httpResponse);
    }

    /**
     * Perform a GET-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. If the <tt>cookie</tt> is not null, it will be used for the request. Depending
     * on the specified <tt>url</tt> and the settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient}
     * instance will be configured to use a proxy or not.
     * 
     * @param url
     *            The resource URL.
     * @param cookie
     *            the Cookie.
     * @return String response as String.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public String getRequestURLAsString(final URL url, final Cookie cookie) throws WebserverSystemException {
        return getRequestURLAsString(null, url, cookie);
    }

    /**
     * Perform a GET-request using the specified {@link HttpClient}. If the <tt>cookie</tt> is not null, it will be used
     * for the request. Depending on the specified <tt>url</tt> and the settings from the
     * <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a proxy or not.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     * @param url
     *            The resource URL.
     * @param cookie
     *            the Cookie.
     * @return String response as String.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public String getRequestURLAsString(final DefaultHttpClient client, final URL url, final Cookie cookie)
            throws WebserverSystemException {
        final HttpResponse httpResponse = getRequestURL(client, url, cookie);
        return readResponse(httpResponse);
    }

    /**
     * Perform a GET-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. If the URL contains an authentication part, the UserCredentials will be set to
     * the {@link HttpClient} instance. Depending on the specified <tt>url</tt> and the settings from the
     * <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a proxy or not.
     * 
     * @param url
     *            The resource URL.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse getRequestURL(final URL url) throws WebserverSystemException {
        return getRequestURL(null, url);
    }

    /**
     * Perform a GET-request using the specified {@link HttpClient}. If the URL contains an authentication part, the
     * UserCredentials will be set to the {@link HttpClient} instance. Depending on the specified <tt>url</tt> and the
     * settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a
     * proxy or not.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     * @param url
     * @return The response of the request.
     * @throws WebserverSystemException
     */
    public HttpResponse getRequestURL(final DefaultHttpClient client, final URL url)
            throws WebserverSystemException {
        String username = null;
        String password = null;
        final String userinfo = url.getUserInfo();
        if (userinfo != null) {
            final String[] loginValues = SPLIT_PATTERN.split(userinfo);
            username = loginValues[0];
            password = loginValues[1];
        }

        return getRequestURL(client, url, username, password);
    }

    /**
     * Perform a GET-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. If <tt>username</tt> and <tt>password</tt> are not <tt>null</tt>, the
     * UserCredentials will be set to the {@link HttpClient} instance. Depending on the specified <tt>url</tt> and the
     * settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a
     * proxy or not.
     * 
     * @param url
     *            URL of resource.
     * @param username
     *            User name for authentication.
     * @param password
     *            Password for authentication.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse getRequestURL(final URL url, final String username, final String password)
            throws WebserverSystemException {
        return getRequestURL(null, url, username, password);
    }

    /**
     * Perform a GET-request using the specified {@link HttpClient}. If <tt>username</tt> and <tt>password</tt> are not
     * <tt>null</tt>, the UserCredentials will be set to the {@link HttpClient} instance. Depending on the specified
     * <tt>url</tt> and the settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be
     * configured to use a proxy or not.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     *            The {@link HttpClient} to use.
     * @param url
     *            The resource URL.
     * @param username
     *            User name for authentication.
     * @param password
     *            Password for authentication.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse getRequestURL(final DefaultHttpClient client, final URL url, final String username,
            final String password) throws WebserverSystemException {
        return get(client, url, null, username, password);
    }

    /**
     * Perform a GET-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. If the <tt>cookie</tt> is not null, it will be used for the request. Depending
     * on the specified <tt>url</tt> and the settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient}
     * instance will be configured to use a proxy or not.
     * 
     * @param url
     *            URL of resource.
     * @param cookie
     *            the Cookie.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse getRequestURL(final URL url, final Cookie cookie) throws WebserverSystemException {
        return getRequestURL(null, url, cookie);
    }

    /**
     * Perform a GET-request using the specified {@link HttpClient}. If the <tt>cookie</tt> is not null, it will be used
     * for the request. Depending on the specified <tt>url</tt> and the settings from the
     * <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a proxy or not.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     *            The {@link HttpClient} to use.
     * @param url
     *            The resource URL.
     * @param cookie
     *            the Cookie.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse getRequestURL(final DefaultHttpClient client, final URL url, final Cookie cookie)
            throws WebserverSystemException {
        return get(client, url, cookie, null, null);
    }

    /**
     * Perform a POST-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. If <tt>username</tt> and <tt>password</tt> are not <tt>null</tt>, the
     * UserCredentials will be set to the {@link HttpClient} instance. Depending on the specified <tt>url</tt> and the
     * settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a
     * proxy or not. The <tt>body</tt> will be set to request and must be encoded as <b>UTF-8</b>.
     * 
     * @param url
     *            URL of resource.
     * @param body
     *            The post body of HTTP request encoded in UTF-8.
     * @param username
     *            User name for authentication.
     * @param password
     *            Password for authentication.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse postRequestURL(final URL url, final String body, final String username,
            final String password) throws WebserverSystemException {
        return postRequestURL(null, url, body, username, password);
    }

    /**
     * Perform a POST-request using the specified {@link HttpClient}. If <tt>username</tt> and <tt>password</tt> are not
     * <tt>null</tt>, the UserCredentials will be set to the {@link HttpClient} instance. Depending on the specified
     * <tt>url</tt> and the settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be
     * configured to use a proxy or not. The <tt>body</tt> will be set to the request and must be encoded as
     * <b>UTF-8</b>.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     *            The {@link HttpClient} to use.
     * @param url
     *            URL of resource.
     * @param body
     *            The post body of HTTP request encoded in UTF-8.
     * @param username
     *            User name for authentication.
     * @param password
     *            Password for authentication.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse postRequestURL(final DefaultHttpClient client, final URL url, final String body,
            final String username, final String password) throws WebserverSystemException {
        return post(client, url, body, null, username, password);
    }

    /**
     * Perform a POST-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. If the <tt>cookie</tt> is not null, it will be used for the request. Depending
     * on the specified <tt>url</tt> and the settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient}
     * instance will be configured to use a proxy or not. The <tt>body</tt> will be set to the request and must be
     * encoded as <b>UTF-8</b>.
     * 
     * @param url
     *            URL of resource.
     * @param body
     *            The post body of HTTP request encoded in UTF-8.
     * @param cookie
     *            The cookie to use of the request.
     * @param username
     *            User name for authentication.
     * @param password
     *            Password for authentication.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse postRequestURL(final URL url, final String body, final Cookie cookie)
            throws WebserverSystemException {
        return postRequestURL(null, url, body, cookie);
    }

    /**
     * Perform a POST-request using the specified {@link HttpClient}. If the <tt>cookie</tt> is not null, it will be
     * used for the request. Depending on the specified <tt>url</tt> and the settings from the
     * <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a proxy or not. The
     * <tt>body</tt> will be set to the request and must be encoded as <b>UTF-8</b>.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     *            The {@link HttpClient} to use.
     * @param url
     *            URL of resource.
     * @param body
     *            The post body of HTTP request encoded in UTF-8.
     * @param cookie
     *            The cookie to use of the request.
     * @param username
     *            User name for authentication.
     * @param password
     *            Password for authentication.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse postRequestURL(final DefaultHttpClient client, final URL url, final String body,
            final Cookie cookie) throws WebserverSystemException {
        return post(client, url, body, cookie, null, null);
    }

    /**
     * Perform a POST-request using the default {@link HttpClient} configuration from the
     * <tt>escidoc-core.properties</tt>. If the URL contains an authentication part, the UserCredentials will be set to
     * the {@link HttpClient} instance. Depending on the specified <tt>url</tt> and the settings from the
     * <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a proxy or not. The
     * <tt>body</tt> will be set to the request and must be encoded as <b>UTF-8</b>.
     * 
     * @param url
     *            URL of resource.
     * @param body
     *            The post body of HTTP request encoded in UTF-8.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse postRequestURL(final URL url, final String body) throws WebserverSystemException {
        return postRequestURL(null, url, body);
    }

    /**
     * Perform a POST-request using the specified {@link HttpClient}. If the URL contains an authentication part, the
     * UserCredentials will be set to the {@link HttpClient} instance. Depending on the specified <tt>url</tt> and the
     * settings from the <tt>escidoc-core.properties</tt>, the {@link HttpClient} instance will be configured to use a
     * proxy or not. The <tt>body</tt> will be set to the request and must be encoded as <b>UTF-8</b>.
     * 
     * @see ConnectionUtility#getHttpClient()
     * @see ConnectionUtility#getHttpClient(HttpParams)
     * 
     * @param client
     *            The {@link HttpClient} to use.
     * @param url
     *            URL of resource.
     * @param body
     *            The post body of HTTP request encoded in UTF-8.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public HttpResponse postRequestURL(final DefaultHttpClient client, final URL url, final String body)
            throws WebserverSystemException {
        String username = null;
        String password = null;
        final String userinfo = url.getUserInfo();
        if (userinfo != null) {
            final String[] loginValues = SPLIT_PATTERN.split(userinfo);
            username = loginValues[0];
            password = loginValues[1];
        }

        return post(client, url, body, null, username, password);
    }

    /**
     * Set Authentication to a given {@link DefaultHttpClient} instance.
     * 
     * @param url
     *            URL of resource.
     * @param username
     *            User name for authentication
     * @param password
     *            Password for authentication.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    public void setAuthentication(final DefaultHttpClient client, final URL url, final String username,
            final String password) {
        final CredentialsProvider credsProvider = new BasicCredentialsProvider();
        final AuthScope authScope = new AuthScope(url.getHost(), AuthScope.ANY_PORT, AuthScope.ANY_REALM);
        final Credentials creds = new UsernamePasswordCredentials(username, password);
        credsProvider.setCredentials(authScope, creds);
        client.setCredentialsProvider(credsProvider);
        // don't wait for auth request
        final HttpRequestInterceptor preemptiveAuth = new HttpRequestInterceptor() {

            @Override
            public void process(final HttpRequest request, final HttpContext context) {
                final AuthState authState = (AuthState) context.getAttribute(ClientContext.TARGET_AUTH_STATE);
                final CredentialsProvider credsProvider = (CredentialsProvider) context
                        .getAttribute(ClientContext.CREDS_PROVIDER);
                final HttpHost targetHost = (HttpHost) context.getAttribute(ExecutionContext.HTTP_TARGET_HOST);
                // If not auth scheme has been initialized yet
                if (authState.getAuthScheme() == null) {
                    final AuthScope authScope = new AuthScope(targetHost.getHostName(), targetHost.getPort());
                    // Obtain credentials matching the target host
                    final Credentials creds = credsProvider.getCredentials(authScope);
                    // If found, generate BasicScheme preemptively
                    if (creds != null) {
                        authState.setAuthScheme(new BasicScheme());
                        authState.setCredentials(creds);
                    }
                }
            }
        };
        client.addRequestInterceptor(preemptiveAuth, 0);
    }

    /**
     * @param url
     */
    private boolean isProxyRequired(final URL url) {
        if (NON_PROXY_HOSTS_PATTERN != null) {
            return !NON_PROXY_HOSTS_PATTERN.matcher(url.toString()).find();
        }
        return true;
    }

    /**
     * Get a new {@link HttpClient} instance. Each instance will use the same {@link ThreadSafeClientConnManager}. New
     * instances are being created because of possible configurations done on the {@link HttpClient}. See
     * {@link ConnectionUtility#setAuthentication(DefaultHttpClient, URL, String, String)} for example. If multiple
     * threads are using the same {@link HttpClient} instance, they could overwrite the credentials and everything else
     * of the {@link HttpClient} causing the {@link HttpClient} instance to become unusable for other threads. Therefore
     * new instances will be returned.<br/>
     * The {@link HttpClient} instance will be initialized with {@link DefaultedHttpParams}, which delegates resolution
     * of a parameter to the given default {@link HttpParams} instance, which is read-only, if the parameter is not
     * present in the local one.<br/>
     * <br/>
     * <b>Note:</b> A user of the returned {@link HttpClient} instance shall not modify the configurations on the
     * {@link ClientConnectionManager} of this instance, because this will affect all other users of the
     * {@link HttpClient} instances returned by this ConnectionUtility. If you need to change the behavior of the
     * {@link ClientConnectionManager}, then use the configuration of the {@link HttpClient} because {@link HttpParams}
     * will be handled in a hierarchy. <br/>
     * <br/>
     * <b>TODO:</b> return {@link HttpClient} instead of {@link DefaultHttpClient}.
     * 
     * @return DefaultHttpClient
     */
    public DefaultHttpClient getHttpClient() {
        return new DefaultHttpClient(CONN_MANAGER,
                new DefaultedHttpParams(new BasicHttpParams(), DEFAULT_HTTP_PARAMS));
    }

    /**
     * Get a new {@link HttpClient} instance overwriting the default configuration by the parameters in
     * <tt>overwriteParams</tt>. Each instance will use the same {@link ThreadSafeClientConnManager}. New instances are
     * being created because of possible configurations done on the {@link HttpClient}. See
     * {@link ConnectionUtility#setAuthentication(DefaultHttpClient, URL, String, String)} for example. If multiple
     * threads are using the same {@link HttpClient} instance, they could overwrite the credentials and everything else
     * of the {@link HttpClient} causing the {@link HttpClient} instance to become unusable for other threads. Therefore
     * new instances will be returned.<br/>
     * The {@link HttpClient} instance will be initialized with {@link DefaultedHttpParams}, which delegates resolution
     * of a parameter to the given default {@link HttpParams} instance, which is read-only, if the parameter is not
     * present in the local one.<br/>
     * <br/>
     * <b>Note:</b> A user of the returned {@link HttpClient} instance shall not modify the configurations on the
     * {@link ClientConnectionManager} of this instance, because this will affect all other users of the
     * {@link HttpClient} instances returned by this ConnectionUtility. If you need to change the behavior of the
     * {@link ClientConnectionManager}, then use the configuration of the {@link HttpClient} because {@link HttpParams}
     * will be handled in a hierarchy. <br/>
     * <br/>
     * <b>TODO:</b> return {@link HttpClient} instead of {@link DefaultHttpClient}.
     * 
     * @return DefaultHttpClient
     */
    public DefaultHttpClient getHttpClient(final HttpParams overwriteParams) {
        final HttpParams params = overwriteParams == null ? new BasicHttpParams() : overwriteParams;
        return new DefaultHttpClient(CONN_MANAGER, new DefaultedHttpParams(params, DEFAULT_HTTP_PARAMS));
    }

    /**
     * Call the HttpGet.
     * 
     * @param url
     *            The URL for the HTTP GET method.
     * @param cookie
     *            The Cookie.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             If connection failed.
     */
    private HttpResponse get(final DefaultHttpClient client, final URL url, final Cookie cookie,
            final String username, final String password) throws WebserverSystemException {
        return executeRequest(client, new HttpGet(), url, cookie, username, password);
    }

    /**
     * Call the HttpPost.
     * 
     * @param url
     *            The URL for the HTTP POST request
     * @param body
     *            The body for the POST request.
     * @param cookie
     *            The Cookie.
     * @return The response of the request.
     * @throws WebserverSystemException
     *             If connection failed.
     */
    private HttpResponse post(final DefaultHttpClient client, final URL url, final String body, final Cookie cookie,
            final String username, final String password) throws WebserverSystemException {
        try {
            final HttpPost httpPost = new HttpPost();
            httpPost.setEntity(new StringEntity(body, "UTF-8"));
            return executeRequest(client, httpPost, url, cookie, username, password);
        } catch (final UnsupportedEncodingException e) {
            throw new WebserverSystemException(e);
        }
    }

    /**
     * 
     * @param request
     * @param cookie
     * @return The response of the request.
     * @throws WebserverSystemException
     */
    private HttpResponse executeRequest(final DefaultHttpClient client, final HttpRequestBase request,
            final URL url, final Cookie cookie, final String username, final String password)
            throws WebserverSystemException {
        try {
            request.setURI(url.toURI());

            if (cookie != null) {
                HttpClientParams.setCookiePolicy(request.getParams(), CookiePolicy.BEST_MATCH);
                request.setHeader("Cookie", cookie.getName() + '=' + cookie.getValue());
            }

            final DefaultHttpClient clientToUse = client == null ? getHttpClient() : client;

            if (PROXY_HOST != null && isProxyRequired(url)) {
                clientToUse.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, PROXY_HOST);
            }

            if (username != null && password != null) {
                setAuthentication(clientToUse, url, username, password);
            }

            final HttpResponse httpResponse = clientToUse.execute(request);

            final int responseCode = httpResponse.getStatusLine().getStatusCode();
            if (responseCode / HTTP_RESPONSE_CLASS != HttpServletResponse.SC_OK / HTTP_RESPONSE_CLASS) {
                final String errorPage = readResponse(httpResponse);
                throw new WebserverSystemException(
                        "HTTP connection to \"" + request.getURI().toString() + "\" failed: " + errorPage);
            }

            return httpResponse;
        } catch (final IOException e) {
            throw new WebserverSystemException(e);
        } catch (final URISyntaxException e) {
            throw new WebserverSystemException("Illegal URL '" + url + "'.", e);
        }
    }

    /**
     * Reads the response as String from the HttpResponse class.
     * 
     * @param httpResponse
     *            The HttpResponse.
     * @return The response of the request as a String.
     * @throws WebserverSystemException
     *             Thrown if connection failed.
     */
    private static String readResponse(final HttpResponse httpResponse) throws WebserverSystemException {
        try {
            return EntityUtils.toString(httpResponse.getEntity(), HTTP.UTF_8);
        } catch (final IOException e) {
            throw new WebserverSystemException(e.getMessage(), e);
        }
    }
}