com.yahoo.flowetl.services.HttpService.java Source code

Java tutorial

Introduction

Here is the source code for com.yahoo.flowetl.services.HttpService.java

Source

/*******************************************************
 *                                                     *
 * Copyright (C) 2011 Yahoo! Inc. All Rights Reserved. *
 *                                                     *
 *                Licensed under the New               *
 *                 BSD License. See the                *
 *              accompanying LICENSE file              *
 *              for the specific language              *
 *              governing permissions and              *
 *                limitations under the                *
 *                       License.                      *
 *******************************************************/
package com.yahoo.flowetl.services;

import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.Map;
import java.util.TreeMap;

import org.apache.commons.httpclient.Header;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.io.IOUtils;

import com.yahoo.flowetl.core.Logger;
import com.yahoo.flowetl.core.Logger.Level;
import com.yahoo.flowetl.core.services.Service;
import com.yahoo.flowetl.core.services.ServiceRegistry;
import com.yahoo.flowetl.core.util.Pair;
import com.yahoo.flowetl.services.http.BaseHttpCaller;
import com.yahoo.flowetl.services.http.BaseHttpGenerator;

/**
 * This is a http service which allows the user to make calls to external http
 * based services by providing a set of input params that define the outgoing
 * call and then getting back a result that represents that calls status and
 * response.
 * 
 * @author Joshua Harlow
 */
public class HttpService implements Service {
    // logging
    private static final Logger logger = new Logger(HttpService.class);

    // this object will actually make the corresponding objects to call upon
    private final HttpGenerator generator;

    // this object will take generated objects and give back a response
    private final HttpCaller caller;

    /**
     * This class represents what typically composes a http parameter set.
     */
    public static abstract class HttpParams {
        public HttpParams() {
            this.headers = new TreeMap<String, String>();
            this.connectionTO = 1000;
            this.socketTO = 1000;
            this.retries = 0;
        }

        /** The uri to call. */
        public URI uri;

        /** The headers that may be sent out. */
        public Map<String, String> headers;

        /** The connection timeout. */
        public int connectionTO;

        /** The socket timeout. */
        public int socketTO;

        /** The retries amount to try if failed. */
        public int retries;

        /** The user agent which may override the useragent header if set. */
        public String userAgent;

        /*
         * (non-Javadoc)
         * 
         * @see java.lang.Object#toString()
         */
        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append(super.toString() + " [connectionTO=");
            builder.append(connectionTO);
            builder.append(", headers=");
            builder.append(headers);
            builder.append(", retries=");
            builder.append(retries);
            builder.append(", socketTO=");
            builder.append(socketTO);
            builder.append(", uri=");
            builder.append(uri);
            builder.append(", userAgent=");
            builder.append(userAgent);
            builder.append("]");
            return builder.toString();
        }
    };

    /**
     * This is a http post type, which adds in some additional data
     */
    public static class PostHttpParams extends HttpParams {
        // any additional data for this http call
        // ie map for POST or a string for POST or other object (which will be
        // converted to a string via toString)
        public Object additionalData;

        /*
         * (non-Javadoc)
         * 
         * @see com.yahoo.flowetl.services.HttpService.HttpParams#toString()
         */
        @Override
        public String toString() {
            StringBuilder builder = new StringBuilder();
            builder.append(super.toString() + " [additionalData=");
            builder.append(additionalData);
            builder.append("]");
            return builder.toString();
        }
    }

    /**
     * A market class for http get type since nothing else is needed...
     */
    public static class GetHttpParams extends HttpParams {
        // just a marker class
    }

    /**
     * A http call results in the following
     */
    public static class HttpResult {

        /** The response body. */
        public String responseBody;

        /** The http status code. */
        public int statusCode;

        /** The returned headers. */
        public Map<String, String> headers;

        /** The source params. */
        public HttpParams sourceParams;
    }

    /**
     * A class that generates a http client and http method must implement the
     * following.
     */
    public static interface HttpGenerator {
        // returns a valid pair (can be useful for mocking)
        public Pair<HttpClient, HttpMethod> generate(HttpParams in);
    }

    /**
     * This represents a interface that takes the generated http client and http
     * method and executes it with the given amount of retries. The http method
     * itself contains the result so no return is needed.
     */
    public static interface HttpCaller {
        public void execute(HttpClient hc, HttpMethod hm, int maxRetry) throws IOException;
    }

    /**
     * Instantiates a new http service.
     */
    public HttpService(ServiceRegistry reg) {
        this(new BaseHttpGenerator(reg), new BaseHttpCaller(reg));
    }

    /**
     * Instantiates a new http service (useful for mocking).
     * 
     * @param generator
     * @param caller
     */
    public HttpService(HttpGenerator generator, HttpCaller caller) {
        this.generator = generator;
        this.caller = caller;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.yahoo.flowetl.core.services.Service#shutdown()
     */
    public void shutdown() {
        // doesn't shutdown anything...
    }

    /**
     * Calls the given http params and returns a result object.
     * 
     * @param params
     * 
     * @return the http result
     */
    public HttpResult call(HttpParams params) {
        Pair<HttpClient, HttpMethod> clientMet = generator.generate(params);
        HttpClient client = clientMet.getFirst();
        HttpMethod toCall = clientMet.getSecond();
        HttpResult out = new HttpResult();
        out.statusCode = -1;
        out.sourceParams = params;
        InputStream is = null;
        try {
            if (logger.isEnabled(Level.INFO)) {
                logger.log(Level.INFO, "Running http method " + toCall + " with params " + params);
            }
            caller.execute(client, toCall, params.retries);
            is = toCall.getResponseBodyAsStream();
            String responseBody = IOUtils.toString(is);
            int st = toCall.getStatusCode();
            Header[] hv = toCall.getResponseHeaders();
            // copy over
            out.statusCode = st;
            out.responseBody = responseBody;
            Map<String, String> headersIn = new TreeMap<String, String>();
            if (hv != null) {
                for (Header h : hv) {
                    headersIn.put(h.getName(), h.getValue());
                }
            }
            out.headers = headersIn;
        } catch (HttpException e) {
            if (logger.isEnabled(Level.WARN)) {
                logger.log(Level.WARN, e, "Failed calling " + toCall);
            }
        } catch (IOException e) {
            if (logger.isEnabled(Level.WARN)) {
                logger.log(Level.WARN, e, "Failed calling " + toCall);
            }
        } finally {
            IOUtils.closeQuietly(is);
            toCall.releaseConnection();
        }
        return out;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.yahoo.flowetl.core.services.Service#creates(java.lang.Class)
     */
    public boolean creates(Class<? extends Service> c) {
        if (HttpService.class.equals(c)) {
            return true;
        }
        return false;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.yahoo.flowetl.core.services.Service#fetch(java.lang.Class)
     */
    public Service fetch(Class<? extends Service> c) {
        return this;
    }

}