sjsucohort6/amigo-chatbot

View on GitHub
httpclient-common/src/main/java/edu/sjsu/amigo/http/client/HttpClient.java

Summary

Maintainability
C
1 day
Test Coverage
/*
 * Copyright (c) 2017 San Jose State University.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 */

package edu.sjsu.amigo.http.client;


import com.fasterxml.jackson.core.JsonProcessingException;
import com.mashape.unirest.http.HttpResponse;
import com.mashape.unirest.http.JsonNode;
import com.mashape.unirest.http.ObjectMapper;
import com.mashape.unirest.http.Unirest;
import com.mashape.unirest.http.exceptions.UnirestException;
import com.mashape.unirest.request.GetRequest;
import com.mashape.unirest.request.HttpRequestWithBody;

import java.io.*;
import java.net.URLEncoder;
import java.util.Map;
import java.util.logging.Logger;

/**
 * Wrapper over http methods using unirest-java library.
 *
 * Below methods are synchronous.
 *
 * For asynch methods use the unirest-java library directly.
 *
 * @author rwatsh on 2/27/17.
 * @see "http://unirest.io/java.html"
 */
public class HttpClient implements AutoCloseable {

    private static final Logger LOGGER = Logger.getLogger(HttpClient.class.getName());
    private String user;
    private String password;

    /**
     * Create a http client with no auth (user anonymous).
     */
    public HttpClient() {
        init();
    }

    /**
     * Create a http client with basic auth.
     *
     * @param user
     * @param passwd
     */
    public HttpClient(String user, String passwd) {
        init();
        this.user = user;
        this.password = passwd;
    }

    /**
     * Initialize the instance.
     */
    private void init() {
        // setup to serialize Json from\to Object using jackson object mapper
        Unirest.setObjectMapper(new ObjectMapper() {
            private com.fasterxml.jackson.databind.ObjectMapper jacksonObjectMapper
                    = new com.fasterxml.jackson.databind.ObjectMapper();

            public <T> T readValue(String value, Class<T> valueType) {
                try {
                    return jacksonObjectMapper.readValue(value, valueType);
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }

            public String writeValue(Object value) {
                try {
                    return jacksonObjectMapper.writeValueAsString(value);
                } catch (JsonProcessingException e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }

    public <T> Response<T> get(String url, Class<T> clazz) throws HttpClientException {
        return get(url, null, null, null, clazz);
    }

    public <T> Response<T> get(String url,
                      Map<String, String> routeParamsMap,
                      Map<String, String> queryStringMap,
                      Map<String, String> headersMap,
                      Class<T> clazz) throws HttpClientException {
        GetRequest request = Unirest.get(url);
        return executeGetRequest(routeParamsMap, queryStringMap, headersMap, clazz, request);
    }

    public <T> Response<T> head(String url, Class<T> clazz) throws HttpClientException {
        return head(url, null, null, null, clazz);
    }

    public <T> Response<T> head(String url,
                     Map<String, String> routeParamsMap,
                     Map<String, String> queryStringMap,
                     Map<String, String> headersMap,
                     Class<T> clazz) throws HttpClientException {
        GetRequest request = Unirest.head(url);
        return executeGetRequest(routeParamsMap, queryStringMap, headersMap, clazz, request);
    }

    public Response<Object> post(String url, Object bodyObject) throws HttpClientException {
        return post(url, null, null, null, bodyObject);
    }

    public Response<Object> post(String url,
                     Map<String, String> routeParamsMap,
                     Map<String, String> queryStringMap,
                     Map<String, String> headersMap,
                     Object bodyObject) throws HttpClientException {
        HttpRequestWithBody request = Unirest.post(url);
        return executeHttpRequestWithBody(routeParamsMap, queryStringMap, headersMap, bodyObject, request);
    }

    public Response<Object> put(String url, Object bodyObject) throws HttpClientException {
        return put(url, null, null, null, bodyObject);
    }

    public Response<Object> put(String url,
                      Map<String, String> routeParamsMap,
                      Map<String, String> queryStringMap,
                      Map<String, String> headersMap,
                      Object bodyObject) throws HttpClientException {
        HttpRequestWithBody request = Unirest.post(url);
        return executeHttpRequestWithBody(routeParamsMap, queryStringMap, headersMap, bodyObject, request);
    }

    public Response<Object> delete(String url, Object bodyObject) throws HttpClientException {
        return delete(url, null, null, null, bodyObject);
    }

    public Response<Object> delete(String url,
                         Map<String, String> routeParamsMap,
                         Map<String, String> queryStringMap,
                         Map<String, String> headersMap,
                         Object bodyObject) throws HttpClientException {
        HttpRequestWithBody request = Unirest.delete(url);
        return executeHttpRequestWithBody(routeParamsMap, queryStringMap, headersMap, bodyObject, request);

    }


    private <T> Response executeGetRequest(Map<String, String> routeParamsMap, Map<String, String> queryStringMap, Map<String, String> headersMap, Class<T> clazz, GetRequest request) throws HttpClientException {
        if (user != null && password != null) {
            request.basicAuth(user, password);
        }

        if(routeParamsMap != null) {
            for (Map.Entry<String, String> entry : routeParamsMap.entrySet()) {
                request.routeParam(entry.getKey(), entry.getValue());
            }
        }
        if (queryStringMap != null) {
            for (Map.Entry<String, String> entry : queryStringMap.entrySet()) {
                request.queryString(entry.getKey(), entry.getValue());
            }
        }
        if (headersMap != null) {
            for (Map.Entry<String, String> entry : headersMap.entrySet()) {
                request.header(entry.getKey(), entry.getValue());
            }
        }
        try {
            HttpResponse<T> response = request.asObject(clazz);
            Response<T> r = new Response();
            r.setStatusCode(response.getStatus());
            r.setStatusText(response.getStatusText());
            r.setRawBody(getStringFromInputStream(response.getRawBody()));
            r.setParsedObject(response.getBody());
            return r;
        } catch (UnirestException e) {
            throw new HttpClientException(e);
        }
    }


    private Response executeHttpRequestWithBody(Map<String, String> routeParamsMap, Map<String, String> queryStringMap, Map<String, String> headersMap, Object bodyObject, HttpRequestWithBody request) throws HttpClientException {
        if (user != null && password != null) {
            request.basicAuth(user, password);
        }
        if(routeParamsMap != null) {
            for (Map.Entry<String, String> entry : routeParamsMap.entrySet()) {
                request.routeParam(entry.getKey(), entry.getValue());
            }
        }
        if (queryStringMap != null) {
            for (Map.Entry<String, String> entry : queryStringMap.entrySet()) {
                request.queryString(entry.getKey(), entry.getValue());
            }
        }
        if (headersMap != null) {
            for (Map.Entry<String, String> entry : headersMap.entrySet()) {
                request.header(entry.getKey(), entry.getValue());
            }
        }
        if(bodyObject != null) {
            request.body(bodyObject);
        }
        try {
            HttpResponse<JsonNode> response = request.asJson();
            Response<Object> r = new Response();
            r.setStatusCode(response.getStatus());
            r.setStatusText(response.getStatusText());
            r.setRawBody(getStringFromInputStream(response.getRawBody()));
            r.setParsedObject(response.getBody().isArray() ?
                    response.getBody().getArray() :
                    response.getBody().getObject());

            return r;
        } catch (UnirestException e) {
            throw new HttpClientException(e);
        }
    }

    // convert InputStream to String
    private static String getStringFromInputStream(InputStream is) {

        if (is == null) return "";

        BufferedReader br = null;
        StringBuilder sb = new StringBuilder();

        String line;
        try {

            br = new BufferedReader(new InputStreamReader(is));
            while ((line = br.readLine()) != null) {
                sb.append(line);
            }

        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

        return sb.toString();

    }

    public static String getIntentFromWitAI(String message) throws UnirestException, UnsupportedEncodingException {
        String url = "https://api.wit.ai/message?v=20160526&q=" + URLEncoder.encode(message, "UTF-8");
        HttpResponse<String> response = Unirest.get(url)
                .header("authorization", "Bearer " + System.getenv("WIT_AI_SERVER_ACCESS_TOKEN"))
                .header("cache-control", "no-cache")
                .asString();
        return response.getBody();
    }

    /**
     * Closes this resource, relinquishing any underlying resources.
     * This method is invoked automatically on objects managed by the
     * {@code try}-with-resources statement.
     * <p>
     * <p>While this interface method is declared to throw {@code
     * Exception}, implementers are <em>strongly</em> encouraged to
     * declare concrete implementations of the {@code close} method to
     * throw more specific exceptions, or to throw no exception at all
     * if the close operation cannot fail.
     * <p>
     * <p> Cases where the close operation may fail require careful
     * attention by implementers. It is strongly advised to relinquish
     * the underlying resources and to internally <em>mark</em> the
     * resource as closed, prior to throwing the exception. The {@code
     * close} method is unlikely to be invoked more than once and so
     * this ensures that the resources are released in a timely manner.
     * Furthermore it reduces problems that could arise when the resource
     * wraps, or is wrapped, by another resource.
     * <p>
     * <p><em>Implementers of this interface are also strongly advised
     * to not have the {@code close} method throw {@link
     * InterruptedException}.</em>
     * <p>
     * This exception interacts with a thread's interrupted status,
     * and runtime misbehavior is likely to occur if an {@code
     * InterruptedException} is {@linkplain Throwable#addSuppressed
     * suppressed}.
     * <p>
     * More generally, if it would cause problems for an
     * exception to be suppressed, the {@code AutoCloseable.close}
     * method should not throw it.
     * <p>
     * <p>Note that unlike the {@link Closeable#close close}
     * method of {@link Closeable}, this {@code close} method
     * is <em>not</em> required to be idempotent.  In other words,
     * calling this {@code close} method more than once may have some
     * visible side effect, unlike {@code Closeable.close} which is
     * required to have no effect if called more than once.
     * <p>
     * However, implementers of this interface are strongly encouraged
     * to make their {@code close} methods idempotent.
     *
     * @throws Exception if this resource cannot be closed
     */
    @Override
    public void close() throws Exception {
        Unirest.shutdown();
    }

    public static void main(String[] args) throws UnsupportedEncodingException, UnirestException {
        String intent = getIntentFromWitAI("aws iam list-users");
        System.out.println(intent);
    }
}