Skip to content

Commit 386757e

Browse files
committed
Add support for request interceptors
Request interceptors have the opportunity to manipulate requests before they're sent to the API. They may also return their own custom response which can be used in place of a normal API response.
1 parent 0f769b8 commit 386757e

File tree

5 files changed

+109
-0
lines changed

5 files changed

+109
-0
lines changed

src/main/java/com/box/sdk/BoxAPIConnection.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public class BoxAPIConnection {
4949
private boolean autoRefresh;
5050
private int maxRequestAttempts;
5151
private List<BoxAPIConnectionListener> listeners;
52+
private RequestInterceptor interceptor;
5253

5354
/**
5455
* Constructs a new BoxAPIConnection that authenticates with a developer or access token.
@@ -374,4 +375,20 @@ public void addListener(BoxAPIConnectionListener listener) {
374375
public void removeListener(BoxAPIConnectionListener listener) {
375376
this.listeners.remove(listener);
376377
}
378+
379+
/**
380+
* Gets the RequestInterceptor associated with this API connection.
381+
* @return the RequestInterceptor associated with this API connection.
382+
*/
383+
public RequestInterceptor getRequestInterceptor() {
384+
return this.interceptor;
385+
}
386+
387+
/**
388+
* Sets a RequestInterceptor that can intercept requests and manipulate them before they're sent to the Box API.
389+
* @param interceptor the RequestInterceptor.
390+
*/
391+
public void setRequestInterceptor(RequestInterceptor interceptor) {
392+
this.interceptor = interceptor;
393+
}
377394
}

src/main/java/com/box/sdk/BoxAPIRequest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,16 @@ void setBackoffCounter(BackoffCounter counter) {
308308
}
309309

310310
private BoxAPIResponse trySend(ProgressListener listener) {
311+
if (this.api != null) {
312+
RequestInterceptor interceptor = this.api.getRequestInterceptor();
313+
if (interceptor != null) {
314+
BoxAPIResponse response = interceptor.onRequest(this);
315+
if (response != null) {
316+
return response;
317+
}
318+
}
319+
}
320+
311321
HttpURLConnection connection = this.createConnection();
312322

313323
if (this.bodyLength > 0) {

src/main/java/com/box/sdk/BoxAPIResponse.java

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ public class BoxAPIResponse {
4444
*/
4545
private InputStream inputStream;
4646

47+
/**
48+
* Constructs an empty BoxAPIResponse without an associated HttpURLConnection.
49+
*/
50+
public BoxAPIResponse() {
51+
this.connection = null;
52+
}
53+
4754
/**
4855
* Constructs a BoxAPIResponse using an HttpURLConnection.
4956
* @param connection a connection that has already sent a request to the API.
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
package com.box.sdk;
2+
3+
/**
4+
* The interface for intercepting requests to the Box API.
5+
*
6+
* <p>An interceptor may handle a request in any way it sees fit. It may update a request before it's sent, or it may
7+
* choose to return a custom response. If an interceptor returns a null response, then the request will continue to be
8+
* sent to the API along with any changes that the interceptor may have made to it.</p>
9+
*
10+
* <pre>public BoxAPIResponse onRequest(BoxAPIRequest request) {
11+
* request.addHeader("My-Header", "My-Value");
12+
*
13+
* // Returning null means the request will be sent along with our new header.
14+
* return null;
15+
*}</pre>
16+
*
17+
* <p>However, if a response is returned, then the request won't be sent and the interceptor's response will take the
18+
* place of the normal response.</p>
19+
*
20+
* <pre>public BoxAPIResponse onRequest(BoxAPIRequest request) {
21+
* // Returning our own response means the request won't be sent at all.
22+
* return new BoxAPIResponse();
23+
*}</pre>
24+
*
25+
* <p>A RequestInterceptor can be very useful for testing purposes. Requests to the Box API can be intercepted and fake
26+
* responses can be returned, allowing you to effectively test your code without needing to actually communicate with
27+
* the Box API.</p>
28+
*/
29+
public interface RequestInterceptor {
30+
/**
31+
* Invoked when a request is about to be sent to the API.
32+
* @param request the request that is about to be sent.
33+
* @return an optional response to the request. If the response is null, then the request will continue to
34+
* be sent to the Box API.
35+
*/
36+
BoxAPIResponse onRequest(BoxAPIRequest request);
37+
}

src/test/java/com/box/sdk/BoxAPIConnectionTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
package com.box.sdk;
22

3+
import java.net.MalformedURLException;
4+
import java.net.URL;
5+
36
import static org.hamcrest.Matchers.equalTo;
47
import static org.hamcrest.Matchers.is;
58
import static org.hamcrest.Matchers.not;
69
import static org.junit.Assert.assertThat;
10+
import static org.mockito.Matchers.any;
11+
import static org.mockito.Mockito.mock;
12+
import static org.mockito.Mockito.when;
713

814
import org.junit.Test;
915
import org.junit.experimental.categories.Category;
@@ -44,6 +50,38 @@ public void doesNotNeedRefreshWhenExpiresIsZero() {
4450
assertThat(api.needsRefresh(), is(not(true)));
4551
}
4652

53+
@Test
54+
@Category(UnitTest.class)
55+
public void interceptorReceivesSentRequest() throws MalformedURLException {
56+
BoxAPIConnection api = new BoxAPIConnection("");
57+
58+
BoxAPIResponse fakeResponse = new BoxAPIResponse();
59+
60+
RequestInterceptor mockInterceptor = mock(RequestInterceptor.class);
61+
when(mockInterceptor.onRequest(any(BoxAPIRequest.class))).thenReturn(fakeResponse);
62+
api.setRequestInterceptor(mockInterceptor);
63+
64+
BoxAPIRequest request = new BoxAPIRequest(api, new URL("http://anyurl.com"), "GET");
65+
BoxAPIResponse response = request.send();
66+
67+
assertThat(response, is(equalTo(fakeResponse)));
68+
}
69+
70+
@Test
71+
@Category(IntegrationTest.class)
72+
public void requestIsSentNormallyWhenInterceptorReturnsNullResponse() throws MalformedURLException {
73+
BoxAPIConnection api = new BoxAPIConnection("");
74+
75+
RequestInterceptor mockInterceptor = mock(RequestInterceptor.class);
76+
when(mockInterceptor.onRequest(any(BoxAPIRequest.class))).thenReturn(null);
77+
api.setRequestInterceptor(mockInterceptor);
78+
79+
BoxAPIRequest request = new BoxAPIRequest(api, new URL("http://box.com"), "GET");
80+
BoxAPIResponse response = request.send();
81+
82+
assertThat(response.getResponseCode(), is(200));
83+
}
84+
4785
@Test
4886
@Category(IntegrationTest.class)
4987
public void refreshSucceeds() {

0 commit comments

Comments
 (0)