Package com.dropbox.core

Source Code of com.dropbox.core.DbxRequestUtil$ResponseHandler

package com.dropbox.core;

import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URLEncoder;
import java.nio.charset.CharacterCodingException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import com.dropbox.core.http.HttpRequestor;
import com.dropbox.core.json.JsonReadException;
import com.dropbox.core.json.JsonReader;
import com.dropbox.core.util.IOUtil;
import com.dropbox.core.util.StringUtil;

public class DbxRequestUtil
{
    public static String encodeUrlParam(String s)
    {
        try {
            return URLEncoder.encode(s, "UTF-8");
        }
        catch (UnsupportedEncodingException ex) {
            AssertionError ae = new AssertionError("UTF-8 not supported?  Should never happen, right?");
            ae.initCause(ex);
            throw ae;
        }
    }

    public static String buildUrlWithParams(String userLocale, String host, String path, String[] params)
    {
        return buildUri(host, path) + "?" + encodeUrlParams(userLocale, params);
    }

    public static String buildUri(String host, String path)
    {
        try {
            return new URI("https", host, "/" + path, null).toURL().toExternalForm();
        }
        catch (MalformedURLException ex) {
            AssertionError ae = new AssertionError();
            ae.initCause(ex);
            throw ae;
        }
        catch (URISyntaxException ex) {
            AssertionError ae = new AssertionError();
            ae.initCause(ex);
            throw ae;
        }
    }

    private static String encodeUrlParams(String userLocale, String[] params)
    {
        StringBuilder buf = new StringBuilder();
        String sep = "";
        if (userLocale != null) {
            buf.append("locale=").append(userLocale);
            sep = "&";
        }

        if (params != null) {
            if (params.length % 2 != 0) {
                throw new IllegalArgumentException("'params.length' is " + params.length + "; expecting a multiple of two");
            }
            for (int i = 0; i < params.length; ) {
                String key = params[i++];
                String value = params[i++];
                if (value != null) {
                    buf.append(sep); sep = "&";
                    buf.append(encodeUrlParam(key));
                    buf.append("=");
                    buf.append(encodeUrlParam(value));
                }
            }
        }

        return buf.toString();
    }

    private static ArrayList<HttpRequestor.Header> addAuthHeader(ArrayList<HttpRequestor.Header> headers, String accessToken)
    {
        if (headers == null) headers = new ArrayList<HttpRequestor.Header>();
        headers.add(new HttpRequestor.Header("Authorization", "Bearer " + accessToken));
        return headers;
    }

    public static ArrayList<HttpRequestor.Header> addUserAgentHeader(ArrayList<HttpRequestor.Header> headers, DbxRequestConfig requestConfig)
    {
        if (headers == null) headers = new ArrayList<HttpRequestor.Header>();
        headers.add(buildUserAgentHeader(requestConfig));
        return headers;
    }

    public static HttpRequestor.Header buildUserAgentHeader(DbxRequestConfig requestConfig)
    {
        return new HttpRequestor.Header("User-Agent", requestConfig.clientIdentifier + " Dropbox-Java-SDK/" + DbxSdkVersion.Version);
    }

    /**
     * Convenience function for making HTTP GET requests.
     */
    public static HttpRequestor.Response startGet(DbxRequestConfig requestConfig, String accessToken, String host, String path, String[] params, ArrayList<HttpRequestor.Header> headers)
        throws DbxException.NetworkIO
    {
        headers = addUserAgentHeader(headers, requestConfig);
        headers = addAuthHeader(headers, accessToken);

        String url = buildUrlWithParams(requestConfig.userLocale, host, path, params);
        try {
            return requestConfig.httpRequestor.doGet(url, headers);
        }
        catch (IOException ex) {
            throw new DbxException.NetworkIO(ex);
        }
    }

    /**
     * Convenience function for making HTTP PUT requests.
     */
    public static HttpRequestor.Uploader startPut(DbxRequestConfig requestConfig, String accessToken, String host, String path, String[] params, long contentLength, ArrayList<HttpRequestor.Header> headers)
        throws DbxException.NetworkIO
    {
        headers = addUserAgentHeader(headers, requestConfig);
        headers = addAuthHeader(headers, accessToken);

        if (contentLength >= 0) {
            headers.add(new HttpRequestor.Header("Content-Length", Long.toString(contentLength)));
        }

        String url = buildUrlWithParams(requestConfig.userLocale, host, path, params);
        try {
            return requestConfig.httpRequestor.startPut(url, headers);
        }
        catch (IOException ex) {
            throw new DbxException.NetworkIO(ex);
        }
    }

    /**
     * Convenience function for making HTTP POST requests.
     */
    public static HttpRequestor.Response startPostNoAuth(DbxRequestConfig requestConfig, String host, String path, String[] params, ArrayList<HttpRequestor.Header> headers)
        throws DbxException.NetworkIO
    {
        String uri = buildUri(host, path);
        byte[] encodedParams = StringUtil.stringToUtf8(encodeUrlParams(requestConfig.userLocale, params));

        headers = addUserAgentHeader(headers, requestConfig);
        headers.add(new HttpRequestor.Header("Content-Type", "application/x-www-form-urlencoded; charset=utf-8"));
        headers.add(new HttpRequestor.Header("Content-Length", Integer.toString(encodedParams.length)));

        try {
            HttpRequestor.Uploader uploader = requestConfig.httpRequestor.startPost(uri, headers);
            try {
                uploader.body.write(encodedParams);
                return uploader.finish();
            }
            finally {
                uploader.close();
            }
        }
        catch (IOException ex) {
            throw new DbxException.NetworkIO(ex);
        }
    }

    public static byte[] loadErrorBody(HttpRequestor.Response response)
        throws DbxException.NetworkIO
    {
        // Slurp the body into memory (up to 4k; anything past that is probably not useful).
        try {
            return IOUtil.slurp(response.body, 4096);
        }
        catch (IOException ex) {
            throw new DbxException.NetworkIO(ex);
        }

    }

    public static String parseErrorBody(int statusCode, byte[] body)
        throws DbxException.BadResponse
    {
        // Read the error message from the body.
        // TODO: Get charset from the HTTP Content-Type header.  It's wrong to just assume UTF-8.
        // TODO: Maybe try parsing the message as JSON and do something more structured?
        try {
            return StringUtil.utf8ToString(body);
        } catch (CharacterCodingException e) {
            throw new DbxException.BadResponse("Got non-UTF8 response body: " + statusCode + ": " + e.getMessage());
        }
    }

    public static DbxException unexpectedStatus(HttpRequestor.Response response)
        throws DbxException.NetworkIO, DbxException.BadResponse
    {
        byte[] body = loadErrorBody(response);
        String message = parseErrorBody(response.statusCode, body);

        if (response.statusCode == 400) return new DbxException.BadRequest(message);
        if (response.statusCode == 401) return new DbxException.InvalidAccessToken(message);
        if (response.statusCode == 500) return new DbxException.ServerError(message);
        if (response.statusCode == 503) return new DbxException.RetryLater(message);

        return new DbxException.BadResponseCode("unexpected HTTP status code: " + response.statusCode + ": " + message, response.statusCode);
    }

    public static <T> T readJsonFromResponse(JsonReader<T> reader, InputStream body)
        throws DbxException.BadResponse, DbxException.NetworkIO
    {
        try {
            return reader.readFully(body);
        }
        catch (JsonReadException ex) {
            throw new DbxException.BadResponse("error in response JSON: " + ex.getMessage(), ex);
        }
        catch (IOException ex) {
            throw new DbxException.NetworkIO(ex);
        }
    }

    public static abstract class ResponseHandler<T>
    {
        public abstract T handle(HttpRequestor.Response response) throws DbxException;
    }

    public static Map<String,String> parseAsQueryString(InputStream in)
        throws DbxException
    {
        // TODO: Maybe just slurp string up to a max limit.
        Scanner scanner = new Scanner(in).useDelimiter("&");
        Map<String,String> result = new HashMap<String,String>();
        while (scanner.hasNext()) {
            String pair = scanner.next();

            // The 'Scanner' class masks any IOExceptions that happen on '.next()', so we
            // have to check for them explicitly.
            IOException ioe = scanner.ioException();
            if (ioe != null) {
                throw new DbxException.NetworkIO(ioe);
            }

            String[] parts = pair.split("=");
            if (parts.length < 2) {
                throw new DbxException.BadResponse("expecting a name-value pair, but there's no '=': \"" + pair + "\"");
            }
            else if (parts.length > 2) {
                throw new DbxException.BadResponse("expecting a single name-value pair, but there's more than one '=': \"" + pair + "\"");
            }
            String displaced = result.put(parts[0], parts[1]);
            if (displaced != null) {
                throw new DbxException.BadResponse("duplicate query parameter name: \"" + parts[0] + "\"");
            }
        }
        return result;
    }

    public static <T> T doGet(DbxRequestConfig requestConfig, String accessToken, String host, String path, String[] params, ArrayList<HttpRequestor.Header> headers, ResponseHandler<T> handler)
        throws DbxException
    {
        HttpRequestor.Response response = startGet(requestConfig, accessToken, host, path, params, headers);
        try {
            return handler.handle(response);
        }
        finally {
            try {
                response.body.close();
            }
            catch (IOException ex) {
                //noinspection ThrowFromFinallyBlock
                throw new DbxException.NetworkIO(ex);
            }
        }
    }

    public static <T> T doPost(DbxRequestConfig requestConfig, String accessToken, String host, String path, String[] params, ArrayList<HttpRequestor.Header> headers, ResponseHandler<T> handler)
            throws DbxException
    {
        headers = addAuthHeader(headers, accessToken);
        return doPostNoAuth(requestConfig, host, path, params, headers, handler);
    }

    public static <T> T doPostNoAuth(DbxRequestConfig requestConfig, String host, String path, String[] params, ArrayList<HttpRequestor.Header> headers, ResponseHandler<T> handler)
        throws DbxException
    {
        HttpRequestor.Response response = startPostNoAuth(requestConfig, host, path, params, headers);
        return finishResponse(response, handler);
    }

    public static <T> T finishResponse(HttpRequestor.Response response, ResponseHandler<T> handler)
        throws DbxException
    {
        try {
            return handler.handle(response);
        }
        finally {
            IOUtil.closeInput(response.body);
        }
    }

    public static String getFirstHeader(HttpRequestor.Response response, String name)
        throws DbxException
    {
        List<String> values = response.headers.get(name);
        if (values == null) {
            throw new DbxException.BadResponse("missing HTTP header \"" + name + "\"");
        }
        assert !values.isEmpty();
        return values.get(0);
    }

    public static String getFirstHeaderMaybe(HttpRequestor.Response response, String name)
        throws DbxException
    {
        List<String> values = response.headers.get(name);
        if (values == null) return null;
        assert !values.isEmpty();
        return values.get(0);
    }

    public static abstract class RequestMaker<T, E extends Throwable>
    {
        public abstract T run() throws DbxException, E;
    }

    public static <T, E extends Throwable> T runAndRetry(int maxTries, RequestMaker<T,E> requestMaker)
        throws DbxException, E
    {
        int numTries = 0;
        while (true) {
            try {
                numTries++;
                return requestMaker.run();
            }
            catch (DbxException ex) {
                // If we can't retry, just let this exception through.
                if (!isRetriableException(ex) || numTries >= maxTries) throw ex;
                // Otherwise, run through the loop again.
            }
        }
    }

    private static boolean isRetriableException(DbxException ex)
    {
        return ex instanceof DbxException.RetryLater || ex instanceof DbxException.ServerError;
    }
}
TOP

Related Classes of com.dropbox.core.DbxRequestUtil$ResponseHandler

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.