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.util.List;
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 BoxAPIResponse with an http response code and response body.
030     *
031     * @param responseCode http response code
032     * @param headers  map of http headers
033     * @param body         response body as Json Object
034     */
035    public BoxJSONResponse(int responseCode,
036                           String requestMethod,
037                           String requestUrl,
038                           Map<String, List<String>> headers,
039                           JsonObject body
040    ) {
041        super(responseCode, requestMethod, requestUrl, headers);
042        this.jsonObject = body;
043    }
044
045    /**
046     * Get response as Json Object.
047     *
048     * @return response as JsonObject
049     */
050    public JsonObject getJsonObject() {
051        if (this.jsonObject != null) {
052            return this.jsonObject;
053        } else {
054            return Json.parse(this.getJSON()).asObject();
055        }
056    }
057
058    /**
059     * Gets the body of the response as a JSON string. When this method is called, the response's body will be read and
060     * the response will be disconnected, meaning that the stream returned by {@link #getBody} can no longer be used.
061     *
062     * @return the body of the response as a JSON string.
063     */
064    public String getJSON() {
065        if (this.jsonObject != null) {
066            return this.jsonObject.toString();
067        } else if (this.getBody() == null) {
068            return null;
069        } else {
070            InputStreamReader reader = new InputStreamReader(this.getBody(), StandardCharsets.UTF_8);
071            StringBuilder builder = new StringBuilder();
072            char[] buffer = new char[BUFFER_SIZE];
073
074            try {
075                int read = reader.read(buffer, 0, BUFFER_SIZE);
076                while (read != -1) {
077                    builder.append(buffer, 0, read);
078                    read = reader.read(buffer, 0, BUFFER_SIZE);
079                }
080
081                this.close();
082                reader.close();
083            } catch (IOException e) {
084                throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e);
085            }
086            String jsonAsString = builder.toString();
087            try {
088                this.jsonObject = Json.parse(jsonAsString).asObject();
089            } catch (ParseException e) {
090                throw new RuntimeException("Error parsing JSON:\n" + jsonAsString, e);
091            }
092            return jsonAsString;
093        }
094    }
095
096    @Override
097    protected String bodyToString() {
098        String bodyString = super.bodyToString();
099        if (bodyString == null) {
100            return this.getJSON();
101        } else {
102            return bodyString;
103        }
104    }
105}