diff --git a/src/main/java/com/box/sdk/BoxAPIException.java b/src/main/java/com/box/sdk/BoxAPIException.java index 2c74734a8..4eadc588e 100644 --- a/src/main/java/com/box/sdk/BoxAPIException.java +++ b/src/main/java/com/box/sdk/BoxAPIException.java @@ -10,9 +10,9 @@ public class BoxAPIException extends RuntimeException { private static final long serialVersionUID = 1L; - private final int responseCode; - private final String response; - private final Map> headers; + private int responseCode; + private String response; + private Map> headers; /** * Constructs a BoxAPIException with a specified message. @@ -131,4 +131,28 @@ public Map> getHeaders() { return Collections.emptyMap(); } } + + /** + * Sets the response code returned by the server. + * @param responseCode the response code returned by the server. + */ + protected void setResponseCode(int responseCode) { + this.responseCode = responseCode; + } + + /** + * Sets the response returned by ther server. + * @param response the response returned by the server. + */ + protected void setResponse(String response) { + this.response = response; + } + + /** + * Sets the response headers. + * @param headers headers to set. + */ + protected void setHeaders(Map> headers) { + this.headers = headers; + } } diff --git a/src/main/java/com/box/sdk/BoxAPIResponse.java b/src/main/java/com/box/sdk/BoxAPIResponse.java index 2eece3715..e9ae0f8be 100644 --- a/src/main/java/com/box/sdk/BoxAPIResponse.java +++ b/src/main/java/com/box/sdk/BoxAPIResponse.java @@ -5,6 +5,7 @@ import java.io.InputStreamReader; import java.net.HttpURLConnection; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.logging.Level; @@ -70,7 +71,6 @@ public BoxAPIResponse(int responseCode, Map headers) { */ public BoxAPIResponse(HttpURLConnection connection) { this.connection = connection; - this.headers = null; this.inputStream = null; try { @@ -79,10 +79,15 @@ public BoxAPIResponse(HttpURLConnection connection) { throw new BoxAPIException("Couldn't connect to the Box API due to a network error.", e); } + Map responseHeaders = new HashMap(); + for (String headerKey : connection.getHeaderFields().keySet()) { + responseHeaders.put(headerKey, connection.getHeaderField(headerKey)); + } + this.headers = responseHeaders; + if (!isSuccess(this.responseCode)) { this.logResponse(); - throw new BoxAPIException("The API returned an error code: " + this.responseCode, this.responseCode, - this.bodyToString(), this.connection.getHeaderFields()); + throw new BoxAPIResponseException("The API returned an error code", this); } this.logResponse(); @@ -194,6 +199,14 @@ public void disconnect() { } } + /** + * + * @return A Map containg headers on this Box API Response. + */ + public Map getHeaders() { + return this.headers; + } + @Override public String toString() { String lineSeparator = System.getProperty("line.separator"); diff --git a/src/main/java/com/box/sdk/BoxAPIResponseException.java b/src/main/java/com/box/sdk/BoxAPIResponseException.java new file mode 100644 index 000000000..4d461f05f --- /dev/null +++ b/src/main/java/com/box/sdk/BoxAPIResponseException.java @@ -0,0 +1,79 @@ +package com.box.sdk; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.eclipsesource.json.JsonObject; + + + +/** + * Thrown to indicate than an error occured while returning with a response from the Box API. + */ +public class BoxAPIResponseException extends BoxAPIException { + + private String message; + private BoxAPIResponse responseObj; + + /** + * Constructs a BoxAPIException that contains detailed message for underlying exception. + * + * @param message a message explaining why the error occurred. + * @param responseObj a response object from the server. + */ + public BoxAPIResponseException(String message, BoxAPIResponse responseObj) { + super(message, responseObj.getResponseCode(), responseObj.bodyToString()); + String requestId = ""; + String apiMessage = ""; + JsonObject responseJSON = null; + this.responseObj = responseObj; + + Map> responseHeaders = new HashMap>(); + for (String headerKey : responseObj.getHeaders().keySet()) { + List headerValues = new ArrayList(); + headerValues.add(responseObj.getHeaderField(headerKey)); + responseHeaders.put(headerKey, headerValues); + } + + this.setHeaders(responseHeaders); + + if (responseObj.bodyToString() != null && !responseObj.bodyToString().equals("")) { + responseJSON = JsonObject.readFrom(responseObj.bodyToString()); + + if (responseObj.bodyToString() != null && responseJSON.get("request_id") != null) { + requestId = " | " + responseJSON.get("request_id").asString(); + } + + if (responseObj.bodyToString() != null && responseJSON.get("code") != null) { + apiMessage += " " + responseJSON.get("code").asString(); + } + + if (responseObj.bodyToString() != null && responseJSON.get("message") != null) { + apiMessage += " - " + responseJSON.get("message").asString(); + } + + this.setMessage(message + " [" + responseObj.getResponseCode() + requestId + "]" + apiMessage); + + } else { + this.setMessage(message + " [" + responseObj.getResponseCode() + "]"); + } + } + + /** + * The message to return for the API exception. + * @param message the constructed for the API exception. + */ + protected void setMessage(String message) { + this.message = message; + } + + /** + * + * @return The constructed message for the API exception. + */ + public String getMessage() { + return this.message; + } +} diff --git a/src/main/java/com/box/sdk/BoxFolder.java b/src/main/java/com/box/sdk/BoxFolder.java index 38f3f4f09..74de9d4b4 100644 --- a/src/main/java/com/box/sdk/BoxFolder.java +++ b/src/main/java/com/box/sdk/BoxFolder.java @@ -239,8 +239,6 @@ public Collection getCollaborations() { return collaborations; } - - @Override public BoxFolder.Info getInfo() { URL url = FOLDER_INFO_URL_TEMPLATE.build(this.getAPI().getBaseURL(), this.getID()); diff --git a/src/test/java/com/box/sdk/BoxAPIResponseExceptionTest.java b/src/test/java/com/box/sdk/BoxAPIResponseExceptionTest.java new file mode 100644 index 000000000..1478fe8be --- /dev/null +++ b/src/test/java/com/box/sdk/BoxAPIResponseExceptionTest.java @@ -0,0 +1,137 @@ +package com.box.sdk; + +import java.net.MalformedURLException; +import java.net.URL; + +import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; +import static org.mockito.Mockito.*; + +import com.eclipsesource.json.JsonObject; +import org.junit.Assert; +import org.junit.Rule; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; + +/** + * + */ +public class BoxAPIResponseExceptionTest { + @Rule + public WireMockRule wireMockRule = new WireMockRule(53620); + + @Test + @Category(UnitTest.class) + public void testAPIResponseExceptionReturnsCorrectErrorMessage() throws MalformedURLException { + BoxAPIConnection api = new BoxAPIConnection(""); + + final JsonObject fakeJSONResponse = JsonObject.readFrom("{\n" + + " \"type\": \"error\",\n" + + " \"status\": \"409\",\n" + + " \"code\": \"item_name_in_use\",\n" + + " \"context_info\": {\n" + + " \"conflicts\": [\n" + + " {\n" + + " \"type\": \"folder\",\n" + + " \"id\": \"12345\",\n" + + " \"sequence_id\": \"1\",\n" + + " \"etag\": \"1\",\n" + + " \"name\": \"Helpful things\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"help_url\": \"http://developers.box.com/docs/#errors\",\n" + + " \"message\": \"Item with the same name already exists\",\n" + + " \"request_id\": \"5678\"\n" + + " }"); + + stubFor(post(urlEqualTo("/folders")) + .willReturn(aResponse() + .withStatus(409) + .withHeader("Content-Type", "application/json") + .withBody(fakeJSONResponse.toString()))); + + URL url = new URL("http://localhost:53620/folders"); + BoxAPIRequest request = new BoxAPIRequest(api, url, "POST"); + + try { + BoxJSONResponse response = (BoxJSONResponse) request.send(); + } catch (BoxAPIResponseException e) { + Assert.assertEquals(409, e.getResponseCode()); + Assert.assertEquals("The API returned an error code [409 | 5678] item_name_in_use - " + + "Item with the same name already exists", e.getMessage()); + return; + } + + Assert.fail("Never threw a BoxAPIResponseException"); + } + + @Test + @Category(UnitTest.class) + public void testAPIResponseExceptionMissingFieldsReturnsCorrectErrorMessage() throws MalformedURLException { + BoxAPIConnection api = new BoxAPIConnection(""); + final JsonObject fakeJSONResponse = JsonObject.readFrom("{\n" + + " \"type\": \"error\",\n" + + " \"status\": \"409\",\n" + + " \"context_info\": {\n" + + " \"conflicts\": [\n" + + " {\n" + + " \"type\": \"folder\",\n" + + " \"id\": \"12345\",\n" + + " \"sequence_id\": \"1\",\n" + + " \"etag\": \"1\",\n" + + " \"name\": \"Helpful things\"\n" + + " }\n" + + " ]\n" + + " },\n" + + " \"help_url\": \"http://developers.box.com/docs/#errors\"\n" + + " }"); + + stubFor(post(urlEqualTo("/folders")) + .willReturn(aResponse() + .withStatus(409) + .withHeader("Content-Type", "application/json") + .withBody(fakeJSONResponse.toString()))); + + URL url = new URL("http://localhost:53620/folders"); + BoxAPIRequest request = new BoxAPIRequest(api, url, "POST"); + + try { + BoxJSONResponse response = (BoxJSONResponse) request.send(); + } catch (BoxAPIResponseException e) { + Assert.assertEquals(409, e.getResponseCode()); + Assert.assertEquals("The API returned an error code [409]", e.getMessage()); + return; + } + + Assert.fail("Never threw a BoxAPIResponseException"); + } + + @Test + @Category(UnitTest.class) + public void testAPIResponseExceptionMissingBodyReturnsCorrectErrorMessage() throws MalformedURLException { + BoxAPIConnection api = new BoxAPIConnection(""); + + stubFor(post(urlEqualTo("/folders")) + .willReturn(aResponse() + .withStatus(403))); + + URL url = new URL("http://localhost:53620/folders"); + BoxAPIRequest request = new BoxAPIRequest(api, url, "POST"); + + try { + BoxJSONResponse response = (BoxJSONResponse) request.send(); + } catch (BoxAPIResponseException e) { + Assert.assertEquals(403, e.getResponseCode()); + Assert.assertEquals("", e.getResponse()); + Assert.assertEquals("The API returned an error code [403]", e.getMessage()); + return; + } + + Assert.fail("Never threw a BoxAPIResponseException"); + } +} diff --git a/src/test/java/com/box/sdk/BoxFolderTest.java b/src/test/java/com/box/sdk/BoxFolderTest.java index 7edaa05d0..5eff27580 100644 --- a/src/test/java/com/box/sdk/BoxFolderTest.java +++ b/src/test/java/com/box/sdk/BoxFolderTest.java @@ -18,7 +18,6 @@ import java.text.SimpleDateFormat; import java.util.*; - import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.*; import static org.junit.Assert.*;