com.marvelution.hudson.plugins.apiv2.client.connectors.HttpClient3Connector.java Source code

Java tutorial

Introduction

Here is the source code for com.marvelution.hudson.plugins.apiv2.client.connectors.HttpClient3Connector.java

Source

/*
 * Licensed to Marvelution under one or more contributor license 
 * agreements.  See the NOTICE file distributed with this work 
 * for additional information regarding copyright ownership.
 * Marvelution licenses this file to you 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.marvelution.hudson.plugins.apiv2.client.connectors;

import java.io.IOException;
import java.net.Proxy;
import java.net.Proxy.Type;
import java.net.InetSocketAddress;
import java.net.ProxySelector;
import java.net.URI;
import java.net.URISyntaxException;

import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.MultiThreadedHttpConnectionManager;
import org.apache.commons.httpclient.ProxyHost;
import org.apache.commons.httpclient.UsernamePasswordCredentials;
import org.apache.commons.httpclient.auth.AuthScope;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpConnectionManagerParams;
import org.apache.commons.httpclient.util.URIUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.marvelution.hudson.plugins.apiv2.client.Host;
import com.marvelution.hudson.plugins.apiv2.client.services.Query;
import com.marvelution.hudson.plugins.apiv2.resources.model.Model;

/**
 * The Commons {@link HttpClient} {@link Connector} implementation
 * 
 * @author <a href="mailto:markrekveld@marvelution.com">Mark Rekveld<a/>
 */
public class HttpClient3Connector implements Connector {

    private static final int MAX_TOTAL_CONNECTIONS = 40;
    private static final int MAX_HOST_CONNECTIONS = 4;

    private final Log log = LogFactory.getLog(HttpClient3Connector.class);
    private final Host server;

    private HttpClient httpClient;

    /**
     * Default constructor
     * 
     * @param server the {@link Host} to connect to
     */
    public HttpClient3Connector(Host server) {
        this.server = server;
        createClient();
    }

    /**
     * Constructor for a specific {@link Host} and  pre-configured {@link HttpClient}
     * 
     * @param server the {@link Host} to connect to
     * @param httpClient the {@link HttpClient} to use for the connection
     */
    public HttpClient3Connector(Host server, HttpClient httpClient) {
        this.httpClient = httpClient;
        this.server = server;
    }

    /**
     * Create the {@link HttpClient} object
     */
    private void createClient() {
        HttpConnectionManagerParams params = new HttpConnectionManagerParams();
        params.setConnectionTimeout(TIMEOUT_MS);
        params.setDefaultMaxConnectionsPerHost(MAX_HOST_CONNECTIONS);
        params.setMaxTotalConnections(MAX_TOTAL_CONNECTIONS);
        MultiThreadedHttpConnectionManager connectionManager = new MultiThreadedHttpConnectionManager();
        connectionManager.setParams(params);
        httpClient = new HttpClient(connectionManager);
        configureCredentials();
        if (StringUtils.isNotBlank(System.getProperty("http.proxyHost"))) {
            log.debug("A HTTP Proxy is configured");
            System.setProperty("java.net.useSystemProxies", "true");
            Proxy proxy = chooseProxy();
            if (proxy.type() == Type.HTTP && proxy.address() instanceof InetSocketAddress) {
                // convert the socket address to an ProxyHost
                final InetSocketAddress isa = (InetSocketAddress) proxy.address();
                // assume default scheme (http)
                ProxyHost proxyHost = new ProxyHost(getHost(isa), isa.getPort());
                httpClient.getHostConfiguration().setProxyHost(proxyHost);
                if (StringUtils.isNotBlank(System.getProperty("http.proxyUser"))) {
                    String user = System.getProperty("http.proxyUser");
                    String password = System.getProperty("http.proxyPassword");
                    httpClient.getState().setProxyCredentials(new AuthScope(getHost(isa), isa.getPort()),
                            new UsernamePasswordCredentials(user, password));
                }
            }
        }
    }

    /**
     * Configure the credentials of the {@link #server} in the {@link #httpClient}
     */
    private void configureCredentials() {
        if (server.isSecured()) {
            log.debug("The Server is secured, set the preepmtive authentication header and credentials");
            httpClient.getParams().setAuthenticationPreemptive(true);
            Credentials defaultcreds = new UsernamePasswordCredentials(server.getUsername(), server.getPassword());
            httpClient.getState().setCredentials(getAuthScope(), defaultcreds);
        }
    }

    /**
     * Get the {@link AuthScope} for the {@link #server}
     * 
     * @return the {@link AuthScope}
     */
    private AuthScope getAuthScope() {
        String host = AuthScope.ANY_HOST;
        int port = AuthScope.ANY_PORT;
        try {
            final URI hostUri = new URI(server.getHost());
            host = hostUri.getHost();
            if (hostUri.getPort() > -1) {
                port = hostUri.getPort();
            } else if ("http".equalsIgnoreCase(hostUri.getScheme())) {
                port = 80;
            } else if ("https".equalsIgnoreCase(hostUri.getScheme())) {
                port = 443;
            }
        } catch (URISyntaxException e) {
            // Failed to parse the server host URI
            // Fall-back on preset defaults
            log.error("Failed to parse the host URI", e);
        }
        return new AuthScope(host, port, "realm");
    }

    /**
     * Get the first available {@link Proxy} using the {@link ProxySelector} implementation
     * 
     * @return the first {@link Type#HTTP} proxy available, or {@link Proxy#NO_PROXY} if no
     *         proxy is available
     */
    private Proxy chooseProxy() {
        try {
            for (Proxy proxy : ProxySelector.getDefault().select(new URI(server.getHost()))) {
                if (proxy.type() == Type.HTTP) {
                    return proxy;
                }
            }
        } catch (URISyntaxException e) {
            // Failed to parse the server host URI
            // Fallback to the default NO_PROXY
            log.error("Failed to parse the host URI", e);
        }
        return Proxy.NO_PROXY;
    }

    /**
     * Obtains a host from an {@link InetSocketAddress}.
     * 
     * @param isa the socket address
     * @return a host string, either as a symbolic name or as a literal IP address string
     */
    protected String getHost(InetSocketAddress isa) {
        return isa.isUnresolved() ? isa.getHostName() : isa.getAddress().getHostAddress();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public <MODEL extends Model> ConnectorResponse execute(Query<MODEL> query) {
        GetMethod method = null;
        String url = null;
        try {
            url = server.getHost() + URIUtil.encodeQuery(query.getUrl());
            method = new GetMethod(url);
            method.setRequestHeader("Accept", query.getAcceptHeader());
            httpClient.executeMethod(method);
            return getConnectorResponseFromMethod(method);
        } catch (HttpException e) {
            log.error("Failed to execute the query: " + query.getUrl(), e);
        } catch (IOException e) {
        } finally {
            if (method != null) {
                method.releaseConnection();
            }
        }
        return null;
    }

    /**
     * Internal method to convert a {@link HttpMethod} into a {@link ConnectorResponse}
     * 
     * @param method the {@link HttpMethod} to convert
     * @return the {@link ConnectorResponse}
     * @throws ConnectionException in case of errors while creating the {@link ConnectorResponse}
     */
    private ConnectorResponse getConnectorResponseFromMethod(HttpMethod method) throws ConnectionException {
        ConnectorResponse response = new ConnectorResponse();
        response.setStatusCode(method.getStatusCode());
        response.setReasonPhrase(method.getStatusText());
        try {
            response.setResponseAsStream(method.getResponseBodyAsStream());
        } catch (IOException e) {
            throw new ConnectionException("Failed to copy the response stream", e);
        }
        return response;
    }

}