Package com.coherentlogic.fred.client.core.builders

Source Code of com.coherentlogic.fred.client.core.builders.RequestBuilder

package com.coherentlogic.fred.client.core.builders;

import static com.coherentlogic.fred.client.core.util.Constants.DATE_FORMAT;
import static com.coherentlogic.fred.client.core.util.Constants.DATE_PATTERN;

import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.regex.Matcher;

import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.NameValuePair;
import org.apache.commons.httpclient.URI;
import org.apache.commons.httpclient.URIException;
import org.apache.commons.httpclient.methods.GetMethod;
import org.springframework.web.client.RestTemplate;

import com.coherentlogic.fred.client.core.domain.AggregationMethod;
import com.coherentlogic.fred.client.core.domain.FileType;
import com.coherentlogic.fred.client.core.domain.FilterValue;
import com.coherentlogic.fred.client.core.domain.FilterVariable;
import com.coherentlogic.fred.client.core.domain.Frequency;
import com.coherentlogic.fred.client.core.domain.OrderBy;
import com.coherentlogic.fred.client.core.domain.OutputType;
import com.coherentlogic.fred.client.core.domain.SearchType;
import com.coherentlogic.fred.client.core.domain.SortOrder;
import com.coherentlogic.fred.client.core.domain.Unit;
import com.coherentlogic.fred.client.core.exceptions.DateOutOfBoundsException;
import com.coherentlogic.fred.client.core.exceptions.InvalidDateFormatException;
import com.coherentlogic.fred.client.core.exceptions.InvalidURIException;
import com.coherentlogic.fred.client.core.exceptions.LimitOutOfBoundsException;
import com.coherentlogic.fred.client.core.exceptions.OffsetOutOfBoundsException;

/**
* Class that allows the developer to construct and execute a query to the
* Federal Reserve Bank of St. Louis' FRED web services.
* <p>
* Note that this class is <b>not</b> thread-safe and cannot be used as a member
* -level property -- if this is required, use the
* {@link com.coherentlogic.fred.client.core.builders#RequestBuilderFactory
* RequestBuilderFactory} class.
* <p>
* In order to facilitate method-chaining each setter method returns a reference
* to this object.
* <p>
* For examples, refer to the {@link
* com.coherentlogic.fred.client.core.builders#RequestBuilderTest
* RequestBuilderTest} class.
*
* @author <a href="support@coherentlogic.com">Support</a>
*/
public class RequestBuilder {

    public static final String
        API_KEY = "api_key",
        CATEGORY_ID = "category_id",
        REALTIME_START = "realtime_start",
        REALTIME_END = "realtime_end",
        LIMIT = "limit",
        OFFSET = "offset",
        ORDER_BY = "order_by",
        SORT_ORDER = "sort_order",
        FILTER_VARIABLE = "filter_variable",
        FILTER_VALUE = "filter_value",
        INCLUDE_RELEASE_DATES_WITH_NO_DATA
            = "include_release_dates_with_no_data",
        RELEASE_ID = "release_id",
        OBSERVATION_START = "observation_start",
        OBSERVATION_END = "observation_end",
        UNITS = "units",
        FREQUENCY = "frequency",
        AGGREGATION_METHOD = "aggregation_method",
        OUTPUT_TYPE = "output_type",
        FILE_TYPE = "file_type",
        VINTAGE_DATES = "vintage_dates",
        SERIES_ID = "series_id",
        SOURCE_ID = "source_id",
        SEARCH_TEXT = "search_text",
        SEARCH_TYPE = "search_type";

    private final RestTemplate restTemplate;

    private final HttpMethod method;

    private final Calendar MIN_DATE_CALENDAR, MAX_DATE_CALENDAR;

    private final List<NameValuePair> nameValuePairList;

    public RequestBuilder (
        RestTemplate restTemplate,
        String uri
    ) {
        this (restTemplate, new GetMethod(uri));
    }

    public RequestBuilder (
        RestTemplate restTemplate,
        HttpMethod method
    ) {
        this (restTemplate, method, new ArrayList<NameValuePair> ());
    }

    public RequestBuilder (
        RestTemplate restTemplate,
        HttpMethod method,
        List<NameValuePair> nameValuePairList
    ) {
        this.restTemplate = restTemplate;
        this.method = method;
        this.nameValuePairList = nameValuePairList;

        MIN_DATE_CALENDAR = Calendar.getInstance();
        MIN_DATE_CALENDAR.set(Calendar.YEAR, 1776);
        MIN_DATE_CALENDAR.set(Calendar.MONTH, Calendar.JULY);
        MIN_DATE_CALENDAR.set(Calendar.DAY_OF_MONTH, 04);

        MAX_DATE_CALENDAR = Calendar.getInstance();
        MAX_DATE_CALENDAR.set(Calendar.YEAR, 9999);
        MAX_DATE_CALENDAR.set(Calendar.MONTH, Calendar.DECEMBER);
        MAX_DATE_CALENDAR.set(Calendar.DAY_OF_MONTH, 31);
    }

    /**
     * Setter method for the API key parameter. Note the API key is requires by
     * every FRED web service.
     *
     * Register for an API key <a href="http://api.stlouisfed.org/api_key.html">
     * here</a>.
     *
     * @param apiKey For example, "abcdefghijklmnopqrstuvwxyz123456".
     */
    public RequestBuilder setApiKey (String apiKey) {

        NameValuePair nvp = new NameValuePair (API_KEY, apiKey);

        nameValuePairList.add(nvp);

        return this;
    }

    /**
     * Setter method for the series id parameter.
     *
     * @param seriesId For example, "GNPCA".
     */
    public RequestBuilder setSeriesId (String seriesId) {

        put(SERIES_ID, seriesId);

        return this;
    }

    /**
     * Setter method for the release id parameter.
     *
     * @param releaseId For example, 53L.
     */
    public RequestBuilder setReleaseId (long releaseId) {

        put(RELEASE_ID, Long.toString(releaseId));

        return this;
    }

    /**
     * Setter method for the category id parameter.
     */
    public RequestBuilder setCategoryId (long categoryId) {

        put(CATEGORY_ID, Long.toString(categoryId));

        return this;
    }

    /**
     * Setter method for the source id parameter.
     */
    public RequestBuilder setSourceId (long sourceId) {

        put(SOURCE_ID, Long.toString(sourceId));

        return this;
    }

    /**
     * Setter method for the real-time start date parameter.
     */
    public RequestBuilder setRealtimeStart (Date realtimeStart) {

        boolean between = isBetween (realtimeStart);

        if (!between)
            throw new DateOutOfBoundsException(realtimeStart);

        DateFormat dateFormat = new SimpleDateFormat (DATE_FORMAT);

        String realtimeStartText = dateFormat.format(realtimeStart);

        put(REALTIME_START, realtimeStartText);

        return this;
    }

    /**
     * Setter method for the real-time start date parameter.
     *
     * @throws InvalidDateFormatException When the date does not conform to the
     *  expected format (ie. yyyy-MM-dd / 2012-06-21).
     */
    public RequestBuilder setRealtimeStart (String realtimeStart) {

        assertDateFormatIsValid ("realtimeStart", realtimeStart);

        put(REALTIME_START, realtimeStart);

        return this;
    }

    /**
     * Setter method for the real-time end date parameter.
     */
    public RequestBuilder setRealtimeEnd (Date realtimeEnd) {

        boolean between = isBetween (realtimeEnd);

        if (!between)
            throw new DateOutOfBoundsException(realtimeEnd);

        DateFormat dateFormat = new SimpleDateFormat (DATE_FORMAT);

        String realtimeEndText = dateFormat.format(realtimeEnd);

        put(REALTIME_END, realtimeEndText);

        return this;
    }

    /**
     * Setter method for the real-time end date parameter.
     *
     * @throws InvalidDateFormatException When the date does not conform to the
     *  expected format (ie. yyyy-MM-dd / 2012-06-21).
     */
    public RequestBuilder setRealtimeEnd (String realtimeEnd) {

        assertDateFormatIsValid ("realtimeEnd", realtimeEnd);

        put(REALTIME_END, realtimeEnd);

        return this;
    }

    /**
     * Setter method for the limit parameter.
     *
     * @param limit A value between 1 and 100000 (inclusive).
     */
    public RequestBuilder setLimit (long limit) {

        if (!(1 <= limit && limit <= 100000))
            throw new LimitOutOfBoundsException(limit);

        put(LIMIT, Long.toString(limit));

        return this;
    }

    /**
     * Setter method for the offset parameter.
     *
     * @param offset A non-negative integer.
     *
     * @throws OffsetOutOfBoundsException if the value of the offset is less
     *  than zero.
     */
    public RequestBuilder setOffset (int offset) {

        if (offset < 0)
            throw new OffsetOutOfBoundsException (offset);

        put(OFFSET, Integer.toString(offset));

        return this;
    }

    /**
     * Setter method for the order-by parameter.
     *
     * @see {@link OrderBy}
     */
    public RequestBuilder setOrderBy (OrderBy orderBy) {

        put(ORDER_BY, orderBy.toString());

        return this;
    }

    /**
     * Setter method for the sort order parameter.
     *
     * @see {@link SortOrder}
     */
    public RequestBuilder setSortOrder (SortOrder sortOrder) {

        put(SORT_ORDER, sortOrder.toString());

        return this;
    }

    /**
     * Setter method for the filter variable parameter.
     *
     * @see {@link FilterVariable}
     */
    public RequestBuilder setFilterVariable (FilterVariable filterVariable) {

        put(FILTER_VARIABLE, filterVariable.toString());

        return this;
    }

    /**
     * Setter method for the filter value parameter.
     *
     * @see {@link FilterValue}
     */
    public RequestBuilder setFilterValue (FilterValue filterValue) {

        put(FILTER_VALUE, filterValue.toString());

        return this;
    }

    /**
     * Setter method for the include-release-dates-with-no-data flag parameter.
     */
    public RequestBuilder setIncludeReleaseDatesWithNoData (boolean value) {

        put(INCLUDE_RELEASE_DATES_WITH_NO_DATA, Boolean.toString(value));

        return this;
    }

    /**
     * Setter method for the observation start date parameter.
     */
    public RequestBuilder setObservationStart (Date observationStart) {

        boolean between = isBetween (observationStart);

        if (!between)
            throw new DateOutOfBoundsException(observationStart);

        DateFormat dateFormat = new SimpleDateFormat (DATE_FORMAT);

        String observationStartText = dateFormat.format(observationStart);

        put(OBSERVATION_START, observationStartText);

        return this;
    }

    /**
     * Setter method for the observation start date parameter.
     *
     * @throws InvalidDateFormatException When the date does not conform to the
     *  expected format (ie. yyyy-MM-dd / 2012-06-21).
     */
    public RequestBuilder setObservationStart (String observationStart) {

        assertDateFormatIsValid ("observationStart", observationStart);

        put(OBSERVATION_START, observationStart);

        return this;
    }

    /**
     * Setter method for the observation end date parameter.
     *
     * @param observationEnd
     */
    public RequestBuilder setObservationEnd (Date observationEnd) {

        boolean between = isBetween (observationEnd);

        if (!between)
            throw new DateOutOfBoundsException(observationEnd);

        DateFormat dateFormat = new SimpleDateFormat (DATE_FORMAT);

        String observationEndText = dateFormat.format(observationEnd);

        put(OBSERVATION_END, observationEndText);

        return this;
    }

    /**
     * Setter method for the observation end date parameter parameter.
     *
     * @throws InvalidDateFormatException When the date does not conform to the
     *  expected format (ie. yyyy-MM-dd / 2012-06-21).
     */
    public RequestBuilder setObservationEnd (String observationEnd) {

        assertDateFormatIsValid ("observationEnd", observationEnd);

        put(OBSERVATION_END, observationEnd);

        return this;
    }

    /**
     * Setter method for the units parameter.
     *
     * @see {@link #Unit}
     */
    public RequestBuilder setUnits (Unit unit) {

        put(UNITS, unit.toString());

        return this;
    }

    /**
     * Setter method for the frequency parameter.
     *
     * @see {@link Frequency}
     */
    public RequestBuilder setFrequency (Frequency frequency) {

        put(FREQUENCY, frequency.toString());

        return this;
    }

    /**
     * Setter method for the aggregation method parameter.
     *
     * @see {@link AggregationMethod}
     */
    public RequestBuilder setAggregationMethod (
        AggregationMethod aggregationMethod) {

        put(AGGREGATION_METHOD, aggregationMethod.toString());

        return this;
    }

    /**
     * Setter method for the output type parameter.
     *
     * @see {@link OutputType}
     */
    public RequestBuilder setOutputType (OutputType outputType) {

        put(OUTPUT_TYPE, outputType.toString());

        return this;
    }

    /**
     * Setter method for the file type parameter.
     *
     * @see {@link FileType}
     */
    public RequestBuilder setFileType (FileType fileType) {

        put(FILE_TYPE, fileType.toString());

        return this;
    }

    /**
     * Setter method for the vinatage dates parameter, which can be a single
     * date, or a list of dates separated by a comma.
     *
     * Note that the format of the dates is not checked client-side -- if there
     * is an invalid date, the server will reject the call.
     */
    public RequestBuilder setVintageDates (String vintageDates) {

        put(VINTAGE_DATES, vintageDates);

        return this;
    }

    /**
     * Setter method for the array of vintage dates parameter.
     *
     * @throws InvalidDateFormatException If any of the dates are not of the
     *  format yyyy-MM-dd.
     */
    public RequestBuilder setVintageDates (String... vintageDates) {

        String value = convertDates ("setVintageDates", ",", vintageDates);

        put(VINTAGE_DATES, value);

        return this;
    }

    /**
     * Setter method for the search text  parameter which consists of the words
     * to match against economic data series.
     */
    public RequestBuilder setSearchText (String searchText) {

        put(SEARCH_TEXT, searchText);

        return this;
    }

    /**
     * Setter method for the search type parameter.
     *
     * @see {@link SearchType}
     */
    public RequestBuilder setSearchType (SearchType searchType) {

        put(SEARCH_TYPE, searchType.toString());

        return this;
    }

    /**
     * Method adds a name-value pair to the internal list of name-value pairs.
     *
     * @param name The name of the parameter.
     * @param value The parameter value.
     */
    private void put (String name, String value) {

        NameValuePair nvp = new NameValuePair (name, value);

        nameValuePairList.add(nvp);
    }

    /**
     * Method returns the escaped URI that is actually send to the FRED web
     * service when the execute method has been called.
     *
     * This method can be useful when debugging, just print the escaped URI and
     * paste it into the address bar in your browser and see what's returned.
     *
     * @return A sting representation of the escaped URI.
     */
    public String getEscapedURI () {

        NameValuePair[] nvps = new NameValuePair[nameValuePairList.size()];

        nvps = nameValuePairList.toArray(nvps);

        method.setQueryString(nvps);

        URI uri;

        try {
            uri = method.getURI();
        } catch (URIException uriException) {
            throw new InvalidURIException (
                "Unable to get the escaped URI for the method " + method,
                uriException);
        }

        return uri.getEscapedURI();
    }

    /**
     * Method checks that the actual date is between the
     * {@link #MIN_DATE_CALENDAR} and {@link #MAX_DATE_CALENDAR} dates.
     *
     * @param actual The actual date.
     *
     * @return True if the actual date is between the {@link #MIN_DATE_CALENDAR}
     *  and {@link #MAX_DATE_CALENDAR} dates.
     */
    private boolean isBetween (Date actual) {

        Calendar calendar = Calendar.getInstance();
        calendar.setTime(actual);

        int minValue = calendar.compareTo(MIN_DATE_CALENDAR);
        int maxValue = calendar.compareTo(MAX_DATE_CALENDAR);

        boolean result = (0 <= minValue) && (maxValue <= 0);

        return result;
    }

    /**
     * Method executes the call to the FRED web service and returns an instance
     * of type <i>type</i>.
     *
     * @param <T> The type of the type to be returned.
     *
     * @param type The type to be be returned.
     *
     * @return An instance of type T.
     */
    public <T> T execute (Class<T> type) {

        String escapedURI = getEscapedURI();

        T result = restTemplate.getForObject(escapedURI, type);

        return result;
    }

    /**
     * Method converts the <i>dates</i> into a single String, with each date
     * separated by a comma.
     *
     * @param method The name of the method calling this method; this is used
     *  when an exception is thrown because one of the dates is in an invalid
     *  format.
     *
     * @param seperator The character which separates the dates.
     *
     * @param dates An array of dates. Note that each date must be in the format
     *  yyyy-MM-dd.
     *
     * @return A single string consisting of all dates separated by the
     *  separator.
     */
    static String convertDates (
        String method,
        String seperator,
        String... dates
    ) {
        StringBuffer buffer = new StringBuffer();

        if (dates != null && 0 < dates.length) {

            for (int ctr = 0; ctr < dates.length; ctr++) {

                assertDateFormatIsValid (method, dates[ctr]);

                buffer.append(dates[ctr]);

                if (ctr < dates.length - 1)
                    buffer.append(seperator);
            }
        }

        String result = (buffer.length() == 0) ? null : buffer.toString();

        return result;
    }

    /**
     * Method simply checks that the date format is valid and throws an
     * exception if it isn't.
     *
     * @param method The method that was invoked.
     *
     * @param date For example 2001-10-20, which is valid, or X001-1-2, which
     *  is invalid.
     *
     * @throws InvalidDateFormatException Whenever the date is invalid.
     */
    static void assertDateFormatIsValid (String method, String date) {
        Matcher matcher = DATE_PATTERN.matcher(date);

        if (!matcher.matches())
            throw new InvalidDateFormatException (
                "The date parameter " + date +" passed to the method " +
                method + " is invalid.");
    }
}
TOP

Related Classes of com.coherentlogic.fred.client.core.builders.RequestBuilder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.