org.intermine.webservice.client.util.HttpConnection.java Source code

Java tutorial

Introduction

Here is the source code for org.intermine.webservice.client.util.HttpConnection.java

Source

package org.intermine.webservice.client.util;

/*
 * Copyright (C) 2002-2013 FlyMine
 *
 * This code may be freely distributed and modified under the
 * terms of the GNU Lesser General Public Licence.  This should
 * be distributed with the code.  See the LICENSE file for more
 * information or http://www.gnu.org/copyleft/lesser.html.
 *
 */

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.util.List;
import java.util.Map;

import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethodBase;
import org.apache.commons.httpclient.methods.DeleteMethod;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.methods.PostMethod;
import org.apache.commons.httpclient.methods.RequestEntity;
import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity;
import org.apache.commons.httpclient.methods.multipart.Part;
import org.apache.commons.httpclient.params.HttpMethodParams;
import org.intermine.webservice.client.core.ContentType;
import org.intermine.webservice.client.core.MultiPartRequest;
import org.intermine.webservice.client.core.Request;
import org.intermine.webservice.client.core.Request.RequestType;
import org.intermine.webservice.client.exceptions.BadRequestException;
import org.intermine.webservice.client.exceptions.InternalErrorException;
import org.intermine.webservice.client.exceptions.NotConnectedException;
import org.intermine.webservice.client.exceptions.NotImplementedException;
import org.intermine.webservice.client.exceptions.ResourceNotFoundException;
import org.intermine.webservice.client.exceptions.ServiceException;
import org.intermine.webservice.client.exceptions.ServiceForbiddenException;
import org.intermine.webservice.client.exceptions.ServiceUnavailableException;

import org.json.JSONObject;
import org.json.JSONException;

/**
 * The HttpConnection is class wrapping implementation details of http connection and the
 * implementation can change easily.
 *
 * @author Jakub Kulaviak
 **/
public class HttpConnection {

    private Request request;

    HttpMethodBase executedMethod;

    private int timeout;

    private int retryCount = 3;

    private boolean opened = false;

    /**
     * @param request client request
     */
    public HttpConnection(Request request) {
        this.request = request;
    }

    /**
     * @return response stream
     */
    public InputStream getResponseStream() {
        connect();
        try {
            return executedMethod.getResponseBodyAsStream();
        } catch (IOException e) {
            throw new RuntimeException("Fatal transport error.", e);
        }
    }

    /**
     * Opens connection.
     */
    public void connect() {
        executeMethod();
        opened = true;
    }

    /**
     * @param name header name
     * @return response header
     */
    public String getResponseHeader(String name) {
        if (executedMethod == null) {
            throwNotConnectedException();
        }
        return executedMethod.getResponseHeader(name).getValue();
    }

    private void throwNotConnectedException() {
        throw new NotConnectedException();
    }

    /**
     * Closes connection.
     */
    public void close() {
        if (executedMethod != null) {
            executedMethod.releaseConnection();
            opened = false;
        }
    }

    private void executeMethod() {
        HttpClient client = new HttpClient();
        client.getParams().setConnectionManagerTimeout(timeout);
        String url = request.getEncodedUrl();
        if (request.getType() == RequestType.GET) {
            executedMethod = new GetMethod(url);
        } else if (request.getType() == RequestType.DELETE) {
            executedMethod = new DeleteMethod(url);
        } else {
            PostMethod postMethod;
            if (request.getContentType() == ContentType.MULTI_PART_FORM) {
                postMethod = new PostMethod(url);
                setMultiPartPostEntity(postMethod, ((MultiPartRequest) request));
            } else {
                url = request.getServiceUrl();
                postMethod = new PostMethod(url);
                setPostMethodParameters(postMethod, request.getParameterMap());
            }
            executedMethod = postMethod;
        }
        // Provide custom retry handler is necessary
        executedMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER,
                new DefaultHttpMethodRetryHandler(retryCount, false));
        for (String name : request.getHeaders().keySet()) {
            executedMethod.setRequestHeader(name, request.getHeader(name));
        }
        try {
            // Execute the method.
            client.executeMethod(executedMethod);
            checkResponse();
        } catch (HttpException e) {
            throw new RuntimeException("Fatal protocol violation.", e);
        } catch (IOException e) {
            throw new RuntimeException("Fatal transport error connecting to " + url, e);
        }
    }

    private void setMultiPartPostEntity(PostMethod postMethod, MultiPartRequest req) {
        List<Part> parts = req.getParts();
        if (!parts.isEmpty()) {
            RequestEntity entity = new MultipartRequestEntity(req.getParts().toArray(new Part[1]),
                    postMethod.getParams());
            postMethod.setRequestEntity(entity);
        }
    }

    private void setPostMethodParameters(PostMethod postMethod, Map<String, List<String>> parameterMap) {
        for (String name : parameterMap.keySet()) {
            for (String value : parameterMap.get(name)) {
                postMethod.addParameter(name, value);
            }
        }
    }

    /**
     * Sets timeout.
     * @param timeout timeout in milliseconds
     */
    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    /**
     * Sets retry count.
     * @param times The number of times to flog a dead horse. (3 by default).
     */
    public void setRetryCount(int times) {
        this.retryCount = times;
    }

    /**
     * @return response code.
     */
    public int getResponseCode() {
        if (executedMethod == null) {
            throwNotConnectedException();
        }
        return executedMethod.getStatusCode();
    }

    /**
     *
     * @return true if connection is opened else false
     */
    public boolean isOpened() {
        return opened;
    }

    /**
     * Called to check the response and generate an appropriate exception (on failure).
     * If the connection is not opened then it is opened and response checked.
     *
     * @throws ServiceException when an error happens
     */
    protected void checkResponse() {
        if (executedMethod.getStatusCode() >= 300) {
            try {
                handleErrorResponse();
            } catch (ServiceException e) {
                throw new ServiceException("Error while accessing " + request, e);
            } catch (IOException e) {
                throw new ServiceException("Error while accessing " + request, e);
            }
        }
    }

    /**
     * Handles an error response received while executing a service request.
     * Throws a {@link ServiceException} or one of its subclasses, depending on
     * the failure conditions.
     *
     * @throws ServiceException exception describing the failure.
     * @throws IOException error reading the error response from the
     *         service.
     */
    protected void handleErrorResponse() throws IOException {

        String message = executedMethod.getResponseBodyAsString();
        try {
            JSONObject jo = new JSONObject(message);
            message = jo.getString("error");
        } catch (JSONException e) {
            // Pass
        }

        switch (executedMethod.getStatusCode()) {

        case HttpURLConnection.HTTP_NOT_FOUND:
            throw new ResourceNotFoundException(this);

        case HttpURLConnection.HTTP_BAD_REQUEST:
            if (message != null) {
                throw new BadRequestException(message);
            } else {
                throw new BadRequestException(this);
            }
        case HttpURLConnection.HTTP_FORBIDDEN:
            if (message != null) {
                throw new ServiceForbiddenException(message);
            } else {
                throw new ServiceForbiddenException(this);
            }
        case HttpURLConnection.HTTP_NOT_IMPLEMENTED:
            throw new NotImplementedException(this);

        case HttpURLConnection.HTTP_INTERNAL_ERROR:
            if (message != null) {
                throw new InternalErrorException(message);
            } else {
                throw new InternalErrorException(this);
            }
        case HttpURLConnection.HTTP_UNAVAILABLE:
            throw new ServiceUnavailableException(this);

        default:
            if (message != null) {
                throw new ServiceException(message);
            } else {
                throw new ServiceException(this);
            }
        }
    }

    /**
     * Return the response body, ensuring that the connection is closed
     * upon completion.
     * @return the response body body as the string
     */
    public String getResponseBodyAsString() {
        if (executedMethod == null) {
            throwNotConnectedException();
        }
        String res = null;
        try {
            res = executedMethod.getResponseBodyAsString();
        } catch (IOException e) {
            throw new ServiceException(e);
        } finally {
            executedMethod.releaseConnection();
        }
        return res;
    }

    /**
     * @return the response body as the stream
     */
    public InputStream getResponseBodyAsStream() {
        if (executedMethod == null) {
            throwNotConnectedException();
        }
        try {
            return executedMethod.getResponseBodyAsStream();
        } catch (IOException e) {
            throw new ServiceException(e);
        }
    }
}