com.buffalokiwi.api.APIResponse.java Source code

Java tutorial

Introduction

Here is the source code for com.buffalokiwi.api.APIResponse.java

Source

/**
 * This file is part of the Aerodrome package, and is subject to the 
 * terms and conditions defined in file 'LICENSE', which is part 
 * of this source code package.
 *
 * Copyright (c) 2016 All Rights Reserved, John T. Quinn III,
 * <johnquinn3@gmail.com>
 *
 * THIS CODE AND INFORMATION ARE PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
 * KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A
 * PARTICULAR PURPOSE.
 */

package com.buffalokiwi.api;

import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.net.URI;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.json.Json;
import javax.json.JsonException;
import javax.json.JsonObject;
import javax.json.JsonReader;
import javax.json.stream.JsonParsingException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Header;
import org.apache.http.ProtocolVersion;
import org.apache.http.StatusLine;

/**
 * The response object used to store data related to a HTTP request response.
 */
public class APIResponse implements IAPIResponse {
    private static final Log LOG = LogFactory.getLog(APIResponse.class);

    /**
     * APIResponse protocol version
     */
    private final ProtocolVersion protocolVersion;

    /**
     * APIResponse status line
     */
    private final StatusLine status;

    /**
     * APIResponse hedaers
     */
    private final List<Header> headers;

    /**
     * The 301/302 redirect chain
     */
    private final List<URI> redirectLocations;

    /**
     * APIResponse content length
     */
    private int contentLength = 0;

    /**
     * APIResponse content
     */
    private String content = "";

    /**
     * APIResponse charset
     */
    private String charset = "";

    private byte[] bytes;

    /**
     * Clone an api response 
     * @param <T> some class that extends APIResponse
     * @param that Some response to clone 
     * @param type The class 
     * @return A copy of that 
     * @throws java.lang.NoSuchMethodException 
     * @throws java.lang.InstantiationException 
     * @throws java.lang.reflect.InvocationTargetException 
     * @throws java.lang.IllegalAccessException 
     */
    public static <T extends APIResponse> T copyFrom(final IAPIResponse that, Class<T> type)
            throws NoSuchMethodException, InstantiationException, InvocationTargetException,
            IllegalArgumentException, IllegalAccessException {
        for (final Constructor<?> c : type.getConstructors()) {
            if (c.getParameterCount() == 6) {
                final T r = (T) c.newInstance(that.getProtocolVersion(), that.getStatusLine(), that.headers(),
                        that.getRedirectLocations(), that.getBytes(), that.getResponseCharsetName());
                return r;
            }
        }
        //T r = type.getConstructor( ProtocolVersion.class, StatusLine.class, List.class ).newInstance( that.getProtocolVersion(), that.getStatusLine(), that.headers());
        //r.setContent( that.getResponseContent(), that.getResponseCharsetName());
        //return r;    
        throw new NoSuchMethodException("Failed to locate constructor in class " + type);
    }

    /**
     * Create a new Response instance.
     * This must contain the response from some http request
     * @param pv protocol version
     * @param status status line
     * @param headers response headers
     */
    public APIResponse(final ProtocolVersion pv, final StatusLine status, final List<Header> headers,
            final List<URI> redirectLocations, final byte[] content, final String charset) {
        protocolVersion = pv;
        this.status = status;

        if (headers != null)
            this.headers = Collections.unmodifiableList(headers);
        else
            this.headers = Collections.unmodifiableList(new ArrayList<>());

        if (redirectLocations != null)
            this.redirectLocations = Collections.unmodifiableList(redirectLocations);
        else
            this.redirectLocations = Collections.unmodifiableList(new ArrayList<>());

        this.charset = (charset == null) ? "" : charset;

        if (!this.charset.isEmpty()) {
            try {
                this.content = (content == null) ? "" : new String(content, 0, content.length, charset);
            } catch (UnsupportedEncodingException e) {
                APILog.error(LOG, e, "Failed to create response string");
                this.content = "";
            }
            bytes = new byte[0];
        } else
            this.bytes = content;

        processHeaders();
    }

    /**
     * Create a new Response instance.
     * This must contain the response from some http request
     * @param pv protocol version
     * @param status status line
     * @param headers response headers
     */
    public APIResponse(final ProtocolVersion pv, final StatusLine status, final List<Header> headers,
            final byte[] content, final String charset) {
        this(pv, status, headers, null, content, charset);
    }

    @Override
    public byte[] getBytes() {
        if (!content.isEmpty()) {
            try {
                return content.getBytes(charset);
            } catch (UnsupportedEncodingException e) {
                return content.getBytes();
            }
        } else
            return bytes;
    }

    /**
     * Retrieve the protocol version
     * @return version
     */
    @Override
    public ProtocolVersion getProtocolVersion() {
        return protocolVersion;
    }

    /**
     * Retrieve the status line
     * @return status
     */
    @Override
    public StatusLine getStatusLine() {
        return status;
    }

    /**
     * Access the response headers list
     * @return headers
     */
    @Override
    public List<Header> headers() {
        return headers;
    }

    /**
     * Retrieve the redirect chain
     * @return 301/302 redirects as part of this request 
     */
    @Override
    public List<URI> getRedirectLocations() {
        return redirectLocations;
    }

    /**
     * Retrieve the content length
     * @return length
     */
    @Override
    public int getContentLength() {
        return contentLength;
    }

    /**
     * Retrieve the response content
     * @return content
     */
    @Override
    public String getResponseContent() {
        return content;
    }

    /**
     * Retrieve the response content character set name
     * @return charset name
     */
    @Override
    public String getResponseCharsetName() {
        return charset;
    }

    /**
     * Retrieve the response as a parsed JsonObject
     * @return response
     * @throws JsonException if a JSON object cannot
     *     be created due to i/o error (IOException would be
     *     cause of JsonException)
     * @throws javax.json.stream.JsonParsingException if a JSON object cannot
     *     be created due to incorrect representation
     */
    @Override
    public JsonObject getJsonObject() throws JsonException, JsonParsingException {
        try (final JsonReader reader = Json.createReader(new StringReader(content))) {
            return reader.readObject();
        }
    }

    /**
     * A crude way to see if a response might have json in it.
     * Checks to see if a { is in position 0.
     * 
     * @return might be json
     */
    @Override
    public boolean isJson() {
        return content.trim().startsWith("{");
    }

    /**
     * Find out if the last request was successful
     * @return request successful
     */
    @Override
    public boolean isSuccess() {
        return status.getStatusCode() >= 200 && status.getStatusCode() < 300;
    }

    /**
     * Find out if the last request was a failure
     * Code is 400-599
     * @return is fail
     */
    @Override
    public boolean isFailure() {
        return status.getStatusCode() >= 400 && status.getStatusCode() < 600;
    }

    /**
     * Find out if the last request was a failure due to client input.
     * Code: 400-499
     * @return is fail
     */
    @Override
    public boolean isRequestFail() {
        return status.getStatusCode() >= 400 && status.getStatusCode() < 500;
    }

    /**
     * Find out if the last request returned a 500 range error.
     * @return is server failure 
     */
    @Override
    public boolean isServerFailure() {
        return status.getStatusCode() >= 500 && status.getStatusCode() < 600;
    }

    /**
     * Process the headers to look for stuff like content length
     */
    private void processHeaders() {
        //..Check for a content length header
        for (Header h : headers) {
            if (h.getName().equals("Content-Length")) {
                try {
                    contentLength = Integer.valueOf(h.getValue());
                } catch (NumberFormatException e) {
                    contentLength = -1;
                }
            }
        }
    }
}