com.github.restdriver.serverdriver.RestServerDriver.java Source code

Java tutorial

Introduction

Here is the source code for com.github.restdriver.serverdriver.RestServerDriver.java

Source

/**
 * Copyright  2010-2011 Nokia
 *
 * 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.github.restdriver.serverdriver;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.net.UnknownHostException;
import java.util.concurrent.TimeUnit;

import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.client.methods.HttpOptions;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpPut;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.params.HttpClientParams;
import org.apache.http.conn.ClientConnectionManager;
import org.apache.http.conn.HttpHostConnectException;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.params.HttpConnectionParams;
import org.apache.http.params.HttpParams;

import com.github.restdriver.RestDriverProperties;
import com.github.restdriver.serverdriver.http.AnyRequestModifier;
import com.github.restdriver.serverdriver.http.BasicAuth;
import com.github.restdriver.serverdriver.http.ByteArrayRequestBody;
import com.github.restdriver.serverdriver.http.Header;
import com.github.restdriver.serverdriver.http.HttpMethod;
import com.github.restdriver.serverdriver.http.NoOpRequestProxy;
import com.github.restdriver.serverdriver.http.RequestBody;
import com.github.restdriver.serverdriver.http.RequestConnectionTimeout;
import com.github.restdriver.serverdriver.http.RequestProxy;
import com.github.restdriver.serverdriver.http.RequestSocketTimeout;
import com.github.restdriver.serverdriver.http.RequestTimeout;
import com.github.restdriver.serverdriver.http.ServerDriverHttpUriRequest;
import com.github.restdriver.serverdriver.http.Url;
import com.github.restdriver.serverdriver.http.exception.RuntimeClientProtocolException;
import com.github.restdriver.serverdriver.http.exception.RuntimeHttpHostConnectException;
import com.github.restdriver.serverdriver.http.exception.RuntimeUnknownHostException;
import com.github.restdriver.serverdriver.http.request.HttpDeleteWithEntity;
import com.github.restdriver.serverdriver.http.request.HttpGetWithEntity;
import com.github.restdriver.serverdriver.http.response.DefaultResponse;
import com.github.restdriver.serverdriver.http.response.Response;

/**
 * Provides static methods for performing HTTP requests against a resource.
 * 
 * @author mjg
 */
public final class RestServerDriver {

    private static final int DEFAULT_HTTP_PROXY_PORT = 80;
    public static final long DEFAULT_CONNECTION_TIMEOUT = 10000;
    public static final long DEFAULT_SOCKET_TIMEOUT = 10000;

    private static final String USER_AGENT = "User-Agent";
    private static final String DEFAULT_USER_AGENT = "rest-server-driver/" + RestDriverProperties.getVersion();

    private static ClientConnectionManager ccm = null;
    private static HttpParams httpParams = null;

    private RestServerDriver() {
    }

    /* ****************************************************************************
     * Helper methods to make value objects *
     * ****************************************************************************
     */

    /**
     * Make a Header.
     * 
     * @param name The name for the header
     * @param value The value for the header
     * @return The new header instance
     */
    public static Header header(String name, String value) {
        return new Header(name, value);
    }

    /**
     * Make a Header.
     * 
     * @param nameAndValue The name and value of the header in the form "name: value"
     * @return The new header instance
     */
    public static Header header(String nameAndValue) {
        return new Header(nameAndValue);
    }

    /**
     * Make a RequestBody for PUT or POST.
     * 
     * @param content Request body content as String.
     * @param contentType content-type eg text/plain.
     * @return The new request body instance.
     */
    public static RequestBody body(String content, String contentType) {
        return new RequestBody(content, contentType);
    }

    /**
     * Make a RequestBody from a byte array.
     * 
     * @param content Request body content as a byte array.
     * @param contentType Content-Type eg application/pdf.
     * @return The new request body instance.
     */
    public static ByteArrayRequestBody body(byte[] content, String contentType) {
        return new ByteArrayRequestBody(content, contentType);
    }

    /**
     * Make a RequestBody from an {@link InputStream}.
     * 
     * @param content Request body content as an {@link InputStream}.
     * @param contentType Content-Type eg application/pdf.
     * @return The new request body instance.
     */
    public static ByteArrayRequestBody body(InputStream content, String contentType) {
        byte[] bytes;

        try {
            bytes = IOUtils.toByteArray(content);
        } catch (IOException e) {
            throw new RuntimeException("Error converting stream to bytes", e);
        }

        return new ByteArrayRequestBody(bytes, contentType);
    }

    /**
     * Make a RequestBody from a {@link Reader}.
     * 
     * @param content Request body content as a {@link Reader}.
     * @param contentType Content-Type eg application/pdf.
     * @return The new request body instance.
     */
    public static ByteArrayRequestBody body(Reader content, String contentType) {
        byte[] bytes;

        try {
            bytes = IOUtils.toByteArray(content);
        } catch (IOException e) {
            throw new RuntimeException("Error converting reader to bytes", e);
        }

        return new ByteArrayRequestBody(bytes, contentType);
    }

    /**
     * Use HTTP basic authentication.
     * 
     * @param username The username.
     * @param password The password.
     * @return The new BasicAuth instance.
     */
    public static BasicAuth withBasicAuth(String username, String password) {
        return new BasicAuth(username, password);
    }

    /**
     * Use a user-specified proxy.
     * 
     * @param proxyHost The host.
     * @param proxyPort The port.
     * @return The new RequestProxy instance.
     */
    public static RequestProxy usingProxy(String proxyHost, int proxyPort) {
        return new RequestProxy(proxyHost, proxyPort);
    }

    /**
     * Do not use a proxy. This is the default anyway, but allowed for clarity.
     * 
     * @return The new NoOpRequestProxy instance.
     */
    public static NoOpRequestProxy notUsingProxy() {
        return new NoOpRequestProxy();
    }

    /**
     * Use the system proxy. These can be set with -Dhttp.proxyHost and -Dhttp.proxyPort.
     * This does not respect environment variables like HTTP_PROXY & friends.
     * 
     * @return The RequestProxy instance.
     */
    public static AnyRequestModifier usingSystemProxy() {

        String proxyHost = System.getProperty("http.proxyHost");
        int proxyPort = getSystemProxyPort();

        if (proxyHost.isEmpty()) {
            return new NoOpRequestProxy();
        }

        return new RequestProxy(proxyHost, proxyPort);
    }

    /**
     * Defaults to 80 as per UrlConnection.
     * 
     * @return The proxy port
     */
    private static int getSystemProxyPort() {
        try {
            return Integer.parseInt(System.getProperty("http.proxyPort"));
        } catch (NumberFormatException nfe) {
            return DEFAULT_HTTP_PROXY_PORT;
        }
    }

    /**
     * Use a single timeout value for both connection and socket timeouts.
     * 
     * @param timeout The timeout duration to use.
     * @param timeUnit The unit of the timeout.
     * 
     * @return The RequestTimeout instance.
     */
    public static AnyRequestModifier withTimeout(int timeout, TimeUnit timeUnit) {
        return new RequestTimeout(timeUnit.toMillis(timeout), timeUnit.toMillis(timeout));
    }

    /**
     * Specify a connection timeout.
     * 
     * @param timeout The timeout duration to use.
     * @param timeUnit The unit of the timeout.
     * 
     * @return The RequestConnectionTimeout instance.
     */
    public static AnyRequestModifier withConnectionTimeout(int timeout, TimeUnit timeUnit) {
        return new RequestConnectionTimeout(timeUnit.toMillis(timeout));
    }

    /**
     * Specify a socket timeout.
     * 
     * @param timeout The timeout duration to use.
     * @param timeUnit The unit of the timeout.
     * 
     * @return The RequestSocketTimeout instance.
     */
    public static AnyRequestModifier withSocketTimeout(int timeout, TimeUnit timeUnit) {
        return new RequestSocketTimeout(timeUnit.toMillis(timeout));
    }

    /**
     * Creates a new {@link Url} object.
     * 
     * @param base The base, like "http://localhost"
     * @return The Url object
     */
    public static Url url(String base) {
        return new Url(base);
    }

    /* ****************************************************************************
     * HTTP OPTIONS methods *
     * ****************************************************************************
     */

    /**
     * Perform an HTTP OPTIONS on a resource.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @return A Response encapsulating the server's reply.
     */
    public static Response options(Object url) {
        ServerDriverHttpUriRequest request = new ServerDriverHttpUriRequest(new HttpOptions(url.toString()));
        return doHttpRequest(request);
    }

    /**
     * Synonym for {@link #options(Object)}.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @return A Response encapsulating the server's reply.
     */
    public static Response optionsOf(Object url) {
        return options(url);
    }

    /* ****************************************************************************
     * HTTP GET methods *
     * ****************************************************************************
     */

    /**
     * Perform an HTTP GET on a resource.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @param modifiers Optional HTTP headers to put on the request.
     * @return A Response encapsulating the server's reply.
     */
    public static Response get(Object url, AnyRequestModifier... modifiers) {
        ServerDriverHttpUriRequest request = new ServerDriverHttpUriRequest(new HttpGetWithEntity(url.toString()));
        applyModifiersToRequest(modifiers, request);
        return doHttpRequest(request);
    }

    /**
     * Synonym for {@link #get(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @param modifiers Optional HTTP headers to put on the request.
     * @return A Response encapsulating the server's reply.
     */
    public static Response getOf(Object url, AnyRequestModifier... modifiers) {
        return get(url, modifiers);
    }

    /**
     * Synonym for {@link #get(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @param modifiers Optional HTTP headers to put on the request.
     * @return A Response encapsulating the server's reply.
     */
    public static Response doGetOf(Object url, AnyRequestModifier... modifiers) {
        return get(url, modifiers);
    }

    /**
     * Synonym for {@link #get(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @param modifiers Optional HTTP headers to put on the request.
     * @return A Response encapsulating the server's reply.
     */
    public static Response getting(Object url, AnyRequestModifier... modifiers) {
        return get(url, modifiers);
    }

    /* ****************************************************************************
     * HTTP POST methods *
     * ****************************************************************************
     */

    /**
     * Perform an HTTP POST to the given URL.
     * 
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response post(Object url, AnyRequestModifier... modifiers) {
        ServerDriverHttpUriRequest request = new ServerDriverHttpUriRequest(new HttpPost(url.toString()));
        applyModifiersToRequest(modifiers, request);
        return doHttpRequest(request);
    }

    /**
     * Synonym for {@link #post(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response postOf(Object url, AnyRequestModifier... modifiers) {
        return post(url, modifiers);
    }

    /**
     * Synonym for {@link #post(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response doPostOf(Object url, AnyRequestModifier... modifiers) {
        return post(url, modifiers);
    }

    /**
     * Synonym for {@link #post(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response posting(Object url, AnyRequestModifier... modifiers) {
        return post(url, modifiers);
    }

    /* ****************************************************************************
     * HTTP other methods *
     * ****************************************************************************
     */

    /**
     * Perform a request with a specified method to the given URL.
     * 
     * @param method The method to be used.
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response method(String method, Object url, AnyRequestModifier... modifiers) {
        ServerDriverHttpUriRequest request = new ServerDriverHttpUriRequest(new HttpMethod(method, url.toString()));
        applyModifiersToRequest(modifiers, request);
        return doHttpRequest(request);
    }

    /**
     * Synonym for {@link #method(String, Object, AnyRequestModifier...)}.
     * 
     * @param method The method to be used.
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response methodOf(String method, Object url, AnyRequestModifier... modifiers) {
        return method(method, url, modifiers);
    }

    /**
     * Synonym for {@link #method(String, Object, AnyRequestModifier...)}.
     * 
     * @param method The method to be used.
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response doMethodOf(String method, Object url, AnyRequestModifier... modifiers) {
        return method(method, url, modifiers);
    }

    /**
     * Synonym for {@link #method(String, Object, AnyRequestModifier...)}.
     * 
     * @param method The method to be used.
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response methoding(String method, Object url, AnyRequestModifier... modifiers) {
        return method(method, url, modifiers);
    }

    /* ****************************************************************************
     * HTTP PUT methods *
     * ****************************************************************************
     */

    /**
     * Perform an HTTP PUT to the given URL.
     * 
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response put(Object url, AnyRequestModifier... modifiers) {
        ServerDriverHttpUriRequest request = new ServerDriverHttpUriRequest(new HttpPut(url.toString()));
        applyModifiersToRequest(modifiers, request);
        return doHttpRequest(request);
    }

    /**
     * Synonym for {@link #put(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response putOf(Object url, AnyRequestModifier... modifiers) {
        return put(url, modifiers);
    }

    /**
     * Synonym for {@link #put(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response doPutOf(Object url, AnyRequestModifier... modifiers) {
        return put(url, modifiers);
    }

    /**
     * Synonym for {@link #put(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL. Any object may be passed, we will call .toString() on it.
     * @param modifiers The modifiers to be applied to the request.
     * @return Response encapsulating the server's reply
     */
    public static Response putting(Object url, AnyRequestModifier... modifiers) {
        return put(url, modifiers);
    }

    /* ****************************************************************************
     * HTTP DELETE methods *
     * ****************************************************************************
     */

    /**
     * Send an HTTP delete.
     * 
     * @param url The resource to delete
     * @param modifiers Any http headers
     * @return Response encapsulating the server's reply
     */
    public static Response delete(Object url, AnyRequestModifier... modifiers) {
        ServerDriverHttpUriRequest request = new ServerDriverHttpUriRequest(
                new HttpDeleteWithEntity(url.toString()));
        applyModifiersToRequest(modifiers, request);
        return doHttpRequest(request);
    }

    /**
     * Synonym for {@link #delete(Object, AnyRequestModifier...)}.
     * 
     * @param url The resource to delete
     * @param modifiers Any http headers
     * @return Response encapsulating the server's reply
     */
    public static Response deleteOf(Object url, AnyRequestModifier... modifiers) {
        return delete(url, modifiers);
    }

    /**
     * Synonym for {@link #delete(Object, AnyRequestModifier...)}.
     * 
     * @param url The resource to delete
     * @param modifiers Any http headers
     * @return Response encapsulating the server's reply
     */
    public static Response doDeleteOf(Object url, AnyRequestModifier... modifiers) {
        return delete(url, modifiers);
    }

    /**
     * Synonym for {@link #delete(Object, AnyRequestModifier...)}.
     * 
     * @param url The resource to delete
     * @param modifiers Any http headers
     * @return Response encapsulating the server's reply
     */
    public static Response deleting(Object url, AnyRequestModifier... modifiers) {
        return delete(url, modifiers);
    }

    /* ****************************************************************************
     * HTTP HEAD methods *
     * ****************************************************************************
     */

    /**
     * Perform an HTTP HEAD on a resource.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @param modifiers Optional HTTP headers to put on the request.
     * @return A Response encapsulating the server's reply.
     */
    public static Response head(Object url, AnyRequestModifier... modifiers) {
        ServerDriverHttpUriRequest request = new ServerDriverHttpUriRequest(new HttpHead(url.toString()));
        applyModifiersToRequest(modifiers, request);
        return doHttpRequest(request);
    }

    /**
     * Synonym for {@link #head(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @param modifiers Optional HTTP headers to put on the request.
     * @return A Response encapsulating the server's reply.
     */
    public static Response headOf(Object url, AnyRequestModifier... modifiers) {
        return head(url, modifiers);
    }

    /**
     * Synonym for {@link #head(Object, AnyRequestModifier...)}.
     * 
     * @param url The URL of a resource. Accepts any Object and calls .toString() on it.
     * @param modifiers Optional HTTP headers to put on the request.
     * @return A Response encapsulating the server's reply.
     */
    public static Response doHeadOf(Object url, AnyRequestModifier... modifiers) {
        return head(url, modifiers);
    }

    /*
     * Internal methods for creating requests and responses
     */
    private static void applyModifiersToRequest(AnyRequestModifier[] modifiers,
            ServerDriverHttpUriRequest request) {
        if (modifiers == null) {
            return;
        }

        for (AnyRequestModifier modifier : modifiers) {
            modifier.applyTo(request);
        }
    }

    /*
     * This is the method which actually makes http requests over the wire.
     */
    private static Response doHttpRequest(ServerDriverHttpUriRequest request) {

        HttpClient httpClient = new DefaultHttpClient(RestServerDriver.ccm, RestServerDriver.httpParams);

        HttpParams httpParams = httpClient.getParams();
        HttpConnectionParams.setConnectionTimeout(httpParams, (int) request.getConnectionTimeout());
        HttpConnectionParams.setSoTimeout(httpParams, (int) request.getSocketTimeout());
        HttpClientParams.setRedirecting(httpParams, false);

        if (request.getProxyHost() != null) {
            httpParams.setParameter(ConnRoutePNames.DEFAULT_PROXY, request.getProxyHost());
        }

        HttpUriRequest httpUriRequest = request.getHttpUriRequest();

        if (!httpUriRequest.containsHeader(USER_AGENT)) {
            httpUriRequest.addHeader(USER_AGENT, DEFAULT_USER_AGENT);
        }

        HttpResponse response;

        try {
            long startTime = System.currentTimeMillis();
            response = httpClient.execute(httpUriRequest);
            long endTime = System.currentTimeMillis();

            return new DefaultResponse(response, (endTime - startTime));

        } catch (ClientProtocolException cpe) {
            throw new RuntimeClientProtocolException(cpe);

        } catch (UnknownHostException uhe) {
            throw new RuntimeUnknownHostException(uhe);

        } catch (HttpHostConnectException hhce) {
            throw new RuntimeHttpHostConnectException(hhce);

        } catch (IOException e) {
            throw new RuntimeException("Error executing request", e);
        } finally {
            httpClient.getConnectionManager().shutdown();
        }

    }

    /**
     * Set the default ClientConnectionManager for all HTTP requests. <br>
     * Pass null to use default ClientConnectionManager
     * 
     * @param ccm
     */
    public static void setClientConnectionManager(ClientConnectionManager ccm) {
        RestServerDriver.ccm = ccm;
    }

    /**
     * Set the default HttpParams for all HTTP requests. <br>
     * Pass null to use default HttpParams
     * 
     * @param httpParams
     */
    public static void getHttpParams(HttpParams httpParams) {
        RestServerDriver.httpParams = httpParams;
    }
}