org.codehaus.httpcache4j.client.HTTPClientResponseResolver.java Source code

Java tutorial

Introduction

Here is the source code for org.codehaus.httpcache4j.client.HTTPClientResponseResolver.java

Source

/*
 * Copyright (c) 2008, The Codehaus. All Rights Reserved.
 *
 *   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 org.codehaus.httpcache4j.client;

import org.apache.commons.httpclient.*;
import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.methods.*;
import org.apache.commons.lang.Validate;

import org.codehaus.httpcache4j.*;
import org.codehaus.httpcache4j.StatusLine;
import org.codehaus.httpcache4j.auth.*;
import org.codehaus.httpcache4j.payload.DelegatingInputStream;
import org.codehaus.httpcache4j.resolver.AbstractResponseResolver;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;

import static org.codehaus.httpcache4j.HTTPMethod.*;

/**
 * An implementation of the ResponseResolver using the Commons HTTPClient (http://hc.apache.org/httpclient-3.x/)
 * <p/>
 * If you need to use SSL, please follow the guide here.
 * http://hc.apache.org/httpclient-3.x/sslguide.html
 *
 * @author <a href="mailto:hamnis@codehaus.org">Erlend Hamnaberg</a>
 */
//TODO: add default user agent. This should maybe only be the cache? Maybe the client type as well. Add support for the client of the cache???
public class HTTPClientResponseResolver extends AbstractResponseResolver {
    private final HttpClient client;

    protected HTTPClientResponseResolver(HttpClient client, ProxyAuthenticator proxyAuthenticator,
            Authenticator authenticator) {
        super(proxyAuthenticator, authenticator);
        Validate.notNull(client, "You may not create with a null HttpClient");
        this.client = client;
        HTTPHost proxyHost = proxyAuthenticator.getConfiguration().getHost();
        if (proxyHost != null) {
            this.client.getHostConfiguration().setProxy(proxyHost.getHost(), proxyHost.getPort());
        }
    }

    public HTTPClientResponseResolver(HttpClient client, ProxyConfiguration configuration) {
        this(client, new DefaultProxyAuthenticator(configuration), new DefaultAuthenticator());
    }

    /**
     * If you use this the cache from multiple threads you need to create a multithreaded HttpClient.
     * example: <br/>
     * {@code
     * HttpClient client = new HttpClient(new MultiThreadedConnectionManager());
     * ResponseResolver resolver = HTTPClientResponseResolver(client);
     * }
     *
     * @param client the HttpClient instance to use. may not be {@code null}
     */
    public HTTPClientResponseResolver(HttpClient client) {
        this(client, new ProxyConfiguration());
    }

    public static HTTPClientResponseResolver createMultithreadedInstance() {
        return new HTTPClientResponseResolver(new HttpClient(new MultiThreadedHttpConnectionManager()));
    }

    public final HttpClient getClient() {
        return client;
    }

    @Override
    protected HTTPResponse resolveImpl(HTTPRequest request) throws IOException {
        HttpMethod method = convertRequest(request);
        method.setDoAuthentication(true);
        client.executeMethod(method);
        return convertResponse(method);
    }

    private HttpMethod convertRequest(HTTPRequest request) {
        URI requestURI = request.getRequestURI();
        HttpMethod method = getMethod(request.getMethod(), requestURI);
        Headers requestHeaders = request.getAllHeaders();
        addHeaders(requestHeaders, method);
        method.setDoAuthentication(true);
        if (method instanceof EntityEnclosingMethod && request.hasPayload()) {
            InputStream payload = request.getPayload().getInputStream();
            EntityEnclosingMethod carrier = (EntityEnclosingMethod) method;
            if (payload != null) {
                carrier.setRequestEntity(new InputStreamRequestEntity(payload));
            }
        }

        return method;
    }

    private void addHeaders(Headers headers, HttpMethod method) {
        if (!headers.isEmpty()) {
            for (org.codehaus.httpcache4j.Header header : headers) {
                method.addRequestHeader(header.getName(), header.getValue());
            }
        }
    }

    private HTTPResponse convertResponse(HttpMethod method) {
        Headers headers = new Headers();
        for (Header header : method.getResponseHeaders()) {
            headers = headers.add(header.getName(), header.getValue());
        }
        InputStream stream = null;
        HTTPResponse response;
        try {
            stream = getInputStream(method);
            StatusLine line = new StatusLine(HTTPVersion.get(method.getStatusLine().getHttpVersion()),
                    Status.valueOf(method.getStatusCode()), method.getStatusText());
            response = getResponseCreator().createResponse(line, headers, stream);
        } finally {
            if (stream == null) {
                method.releaseConnection();
            }
        }
        return response;
    }

    private InputStream getInputStream(HttpMethod method) {
        try {
            return method.getResponseBodyAsStream() != null ? new HttpMethodStream(method) : null;
        } catch (IOException e) {
            method.releaseConnection();
            throw new HTTPException("Unable to get InputStream from HttpClient", e);
        }
    }

    /**
     * Determines the HttpClient's request method from the HTTPMethod enum.
     *
     * @param method     the HTTPCache enum that determines
     * @param requestURI the request URI.
     * @return a new HttpMethod subclass.
     */
    protected HttpMethod getMethod(HTTPMethod method, URI requestURI) {
        if (CONNECT.equals(method)) {
            HostConfiguration config = new HostConfiguration();
            config.setHost(requestURI.getHost(), requestURI.getPort(), requestURI.getScheme());
            return new ConnectMethod(config);
        } else if (DELETE.equals(method)) {
            return new DeleteMethod(requestURI.toString());
        } else if (GET.equals(method)) {
            return new GetMethod(requestURI.toString());
        } else if (HEAD.equals(method)) {
            return new HeadMethod(requestURI.toString());
        } else if (OPTIONS.equals(method)) {
            return new OptionsMethod(requestURI.toString());
        } else if (POST.equals(method)) {
            return new PostMethod(requestURI.toString());
        } else if (PUT.equals(method)) {
            return new PutMethod(requestURI.toString());
        } else if (TRACE.equals(method)) {
            return new TraceMethod(requestURI.toString());
        } else {
            throw new IllegalArgumentException("Cannot handle method: " + method);
        }
    }

    public void shutdown() {
        HttpConnectionManager connmanager = client.getHttpConnectionManager();
        if (connmanager instanceof MultiThreadedHttpConnectionManager) {
            MultiThreadedHttpConnectionManager manager = (MultiThreadedHttpConnectionManager) connmanager;
            manager.shutdown();
        }
    }

    private static class HttpMethodStream extends DelegatingInputStream {
        private final HttpMethod method;

        public HttpMethodStream(final HttpMethod method) throws IOException {
            super(method.getResponseBodyAsStream());
            this.method = method;
        }

        public void close() throws IOException {
            method.releaseConnection();
        }
    }

}