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