001package com.box.sdk;
002
003import com.eclipsesource.json.Json;
004import com.eclipsesource.json.JsonObject;
005import com.eclipsesource.json.ParseException;
006import java.io.IOException;
007import java.io.InputStreamReader;
008import java.net.HttpURLConnection;
009import java.util.Map;
010
011/**
012 * Used to read HTTP responses containing JSON from the Box API.
013 *
014 * <p>This request type extends BoxAPIResponse to provide additional functionality for handling JSON strings. It reads
015 * the response body into a string and allows the JSON in the response to be logged.</p>
016 */
017public class BoxJSONResponse extends BoxAPIResponse {
018    private static final int BUFFER_SIZE = 8192;
019    private JsonObject jsonObject;
020
021    /**
022     * Constructs a BoxJSONResponse without an associated HttpURLConnection.
023     */
024    public BoxJSONResponse() {
025        super();
026    }
027
028    /**
029     * Constructs a BoxJSONResponse using an HttpURLConnection.
030     *
031     * @param connection a connection that has already sent a request to the API.
032     */
033    public BoxJSONResponse(HttpURLConnection connection) {
034        super(connection);
035    }
036
037    /**
038     * Constructs a BoxAPIResponse with an http response code and response body.
039     *
040     * @param responseCode http response code
041     * @param httpHeaders  map of http headers
042     * @param body         response body as Json Object
043     */
044    public BoxJSONResponse(int responseCode, Map<String, String> httpHeaders, JsonObject body) {
045        super(responseCode, httpHeaders);
046        this.jsonObject = body;
047    }
048
049    /**
050     * Get response as Json Object.
051     *
052     * @return response as JsonObject
053     */
054    public JsonObject getJsonObject() {
055        if (this.jsonObject != null) {
056            return this.jsonObject;
057        } else {
058            return Json.parse(this.getJSON()).asObject();
059        }
060    }
061
062    /**
063     * Gets the body of the response as a JSON string. When this method is called, the response's body will be read and
064     * the response will be disconnected, meaning that the stream returned by {@link #getBody} can no longer be used.
065     *
066     * @return the body of the response as a JSON string.
067     */
068    public String getJSON() {
069        if (this.jsonObject != null) {
070            return this.jsonObject.toString();
071        } else {
072            InputStreamReader reader = new InputStreamReader(this.getBody(), StandardCharsets.UTF_8);
073            StringBuilder builder = new StringBuilder();
074            char[] buffer = new char[BUFFER_SIZE];
075
076            try {
077                int read = reader.read(buffer, 0, BUFFER_SIZE);
078                while (read != -1) {
079                    builder.append(buffer, 0, read);
080                    read = reader.read(buffer, 0, BUFFER_SIZE);
081                }
082
083                this.disconnect();
084                reader.close();
085            } catch (IOException e) {
086                throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e);
087            }
088            String jsonAsString = builder.toString();
089            try {
090                this.jsonObject = Json.parse(jsonAsString).asObject();
091            } catch (ParseException e) {
092                throw new RuntimeException("Error parsing JSON:\n" + jsonAsString, e);
093            }
094            return jsonAsString;
095        }
096    }
097
098    @Override
099    protected String bodyToString() {
100        String bodyString = super.bodyToString();
101        if (bodyString == null) {
102            return this.getJSON();
103        } else {
104            return bodyString;
105        }
106    }
107}