diff --git a/http/src/main/java/retrofit/http/CallbackResponseHandler.java b/http/src/main/java/retrofit/http/CallbackResponseHandler.java index d61b80e6d5f780ca877c6d5cabc5fc2e3ea58b54..6c8274593a730b8063ddac551d4b9155abf54863 100644 --- a/http/src/main/java/retrofit/http/CallbackResponseHandler.java +++ b/http/src/main/java/retrofit/http/CallbackResponseHandler.java @@ -21,7 +21,7 @@ import java.util.logging.Logger; * @author Bob Lee (bob@squareup.com) * @author Jake Wharton (jw@squareup.com) */ -public class CallbackResponseHandler implements ResponseHandler { +class CallbackResponseHandler implements ResponseHandler { private static final Logger LOGGER = Logger.getLogger(CallbackResponseHandler.class.getName()); @@ -51,7 +51,7 @@ public class CallbackResponseHandler implements ResponseHandler { * @return parsed response * @throws ConversionException if the server returns an unexpected response */ - protected Object parse(HttpEntity entity, Type type) throws ConversionException { + private Object parse(HttpEntity entity, Type type) throws ConversionException { if (LOGGER.isLoggable(Level.FINE)) { try { entity = HttpClients.copyAndLog(entity, requestUrl, start, dateFormat.get()); diff --git a/http/src/main/java/retrofit/http/Headers.java b/http/src/main/java/retrofit/http/Headers.java index 968518b5707cc7dcc4dfb4902cea7b2bd7c97102..52cfef49e3cab690e71746a4598e3ba4c29a9e8f 100644 --- a/http/src/main/java/retrofit/http/Headers.java +++ b/http/src/main/java/retrofit/http/Headers.java @@ -10,6 +10,6 @@ import org.apache.http.HttpMessage; */ public interface Headers { - /** Sets headers on the given message, with the specified MIME type */ - void setOn(HttpMessage message, String mimeType); + /** Sets headers on the given message */ + void setOn(HttpMessage message); } diff --git a/http/src/main/java/retrofit/http/HttpMethodType.java b/http/src/main/java/retrofit/http/HttpMethodType.java index 00e6b74741be349e1adb28b1f77bde86229f167c..e35ccc33398c77f1dcaa9a6ab3baf99ab50af47f 100644 --- a/http/src/main/java/retrofit/http/HttpMethodType.java +++ b/http/src/main/java/retrofit/http/HttpMethodType.java @@ -6,6 +6,7 @@ import java.lang.reflect.Method; import java.net.URI; import java.net.URISyntaxException; import java.util.List; +import org.apache.http.HttpMessage; import org.apache.http.NameValuePair; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.HttpDelete; @@ -34,7 +35,7 @@ public enum HttpMethodType { throws URISyntaxException { URI uri = getParameterizedUri(builder); HttpGet request = new HttpGet(uri); - builder.getHeaders().setOn(request, builder.getMimeType()); + addHeaders(request, builder); return request; } }, @@ -45,7 +46,7 @@ public enum HttpMethodType { URI uri = getUri(builder); HttpPost request = new HttpPost(uri); addParams(request, builder); - builder.getHeaders().setOn(request, builder.getMimeType()); + addHeaders(request, builder); return request; } }, @@ -56,7 +57,7 @@ public enum HttpMethodType { URI uri = getUri(builder); HttpPut request = new HttpPut(uri); addParams(request, builder); - builder.getHeaders().setOn(request, builder.getMimeType()); + addHeaders(request, builder); return request; } }, @@ -66,7 +67,7 @@ public enum HttpMethodType { throws URISyntaxException { URI uri = getParameterizedUri(builder); HttpDelete request = new HttpDelete(uri); - builder.getHeaders().setOn(request, builder.getMimeType()); + addHeaders(request, builder); return request; } }; @@ -96,6 +97,17 @@ public enum HttpMethodType { queryString, null); } + private static void addHeaders(HttpMessage message, HttpRequestBuilder builder) { + String mimeType = builder.getMimeType(); + if (mimeType != null) { + message.addHeader("Content-Type", mimeType); + } + Headers headers = builder.getHeaders(); + if (headers != null) { + headers.setOn(message); + } + } + /** * Adds all but the last method argument as parameters of HTTP request * object. @@ -169,4 +181,4 @@ public enum HttpMethodType { return false; } -} \ No newline at end of file +} diff --git a/http/src/main/java/retrofit/http/HttpProfiler.java b/http/src/main/java/retrofit/http/HttpProfiler.java index 722928e60c51819f7d9e37b092a0547ca9b5918f..bf728173c081c2542b4eabad73fb84ae944f88d5 100644 --- a/http/src/main/java/retrofit/http/HttpProfiler.java +++ b/http/src/main/java/retrofit/http/HttpProfiler.java @@ -8,15 +8,6 @@ package retrofit.http; */ public interface HttpProfiler { - HttpProfiler NONE = new HttpProfiler() { - @Override public Void beforeCall() { - return null; - } - @Override public void afterCall(RequestInformation requestInfo, - long elapsedTime, int statusCode, Void beforeCallData) { - } - }; - /** * Invoked before an HTTP method call. The object returned by this method will be * passed to {@link #afterCall} when the call returns. diff --git a/http/src/main/java/retrofit/http/ProfilingResponseHandler.java b/http/src/main/java/retrofit/http/ProfilingResponseHandler.java new file mode 100644 index 0000000000000000000000000000000000000000..85c74df87a61b6f7dc7002a38235e21ec72319bb --- /dev/null +++ b/http/src/main/java/retrofit/http/ProfilingResponseHandler.java @@ -0,0 +1,53 @@ +// Copyright 2012 Square, Inc. +package retrofit.http; + +import org.apache.http.HttpResponse; +import org.apache.http.client.ResponseHandler; + +import java.io.IOException; +import java.util.concurrent.atomic.AtomicReference; +import java.util.logging.Level; +import java.util.logging.Logger; + +/** Sends server call times and response status codes to {@link retrofit.http.HttpProfiler}. */ +class ProfilingResponseHandler implements ResponseHandler { + private static final Logger LOGGER = Logger.getLogger(ProfilingResponseHandler.class.getSimpleName()); + + private final ResponseHandler delegate; + private final HttpProfiler profiler; + private final HttpProfiler.RequestInformation requestInfo; + private final long startTime; + private final AtomicReference beforeCallData = new AtomicReference(); + + /** Wraps the delegate response handler. */ + ProfilingResponseHandler(ResponseHandler delegate, HttpProfiler profiler, + HttpProfiler.RequestInformation requestInfo, long startTime) { + this.delegate = delegate; + this.profiler = profiler; + this.requestInfo = requestInfo; + this.startTime = startTime; + } + + public void beforeCall() { + try { + beforeCallData.set(profiler.beforeCall()); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error occurred in HTTP profiler beforeCall().", e); + } + } + + @Override public Void handleResponse(HttpResponse httpResponse) throws IOException { + // Intercept the response and send data to profiler. + long elapsedTime = System.currentTimeMillis() - startTime; + int statusCode = httpResponse.getStatusLine().getStatusCode(); + + try { + profiler.afterCall(requestInfo, elapsedTime, statusCode, beforeCallData.get()); + } catch (Exception e) { + LOGGER.log(Level.SEVERE, "Error occurred in HTTP profiler afterCall().", e); + } + + // Pass along the response to the normal handler. + return delegate.handleResponse(httpResponse); + } +} diff --git a/http/src/main/java/retrofit/http/RestAdapter.java b/http/src/main/java/retrofit/http/RestAdapter.java index f57e4468c62b5ed06d6b8d234926805af44e6afb..3de543ed84aad734dd04b18e80c4638637708ecc 100644 --- a/http/src/main/java/retrofit/http/RestAdapter.java +++ b/http/src/main/java/retrofit/http/RestAdapter.java @@ -2,7 +2,6 @@ package retrofit.http; import org.apache.http.Header; import org.apache.http.HttpEntity; -import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.ResponseHandler; import org.apache.http.client.methods.HttpEntityEnclosingRequestBase; @@ -22,7 +21,6 @@ import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.concurrent.Executor; -import java.util.concurrent.atomic.AtomicReference; import java.util.logging.Level; import java.util.logging.Logger; @@ -47,7 +45,7 @@ public class RestAdapter { private final Converter converter; private final HttpProfiler profiler; - public RestAdapter(Server server, Provider httpClientProvider, Executor executor, MainThread mainThread, + private RestAdapter(Server server, Provider httpClientProvider, Executor executor, MainThread mainThread, Headers headers, Converter converter, HttpProfiler profiler) { this.server = server; this.httpClientProvider = httpClientProvider; @@ -128,7 +126,7 @@ public class RestAdapter { ResponseHandler rh = new CallbackResponseHandler(callback, type, converter, url, start, DATE_FORMAT); // Optionally wrap the response handler for server call profiling. - if (profiler != HttpProfiler.NONE) { + if (profiler != null) { rh = createProfiler(rh, (HttpProfiler) profiler, getRequestInfo(method, request), start); } @@ -248,44 +246,84 @@ public class RestAdapter { String.format("Last parameter of %s must be of type Callback or Callback.", method)); } - /** Sends server call times and response status codes to {@link HttpProfiler}. */ - private static class ProfilingResponseHandler implements ResponseHandler { - private final ResponseHandler delegate; - private final HttpProfiler profiler; - private final HttpProfiler.RequestInformation requestInfo; - private final long startTime; - private final AtomicReference beforeCallData = new AtomicReference(); - - /** Wraps the delegate response handler. */ - private ProfilingResponseHandler(ResponseHandler delegate, HttpProfiler profiler, - HttpProfiler.RequestInformation requestInfo, long startTime) { - this.delegate = delegate; - this.profiler = profiler; - this.requestInfo = requestInfo; - this.startTime = startTime; + /** + * Build a new {@link RestAdapter}. + *

+ * Calling the following methods is required before calling {@link #build()}: + *

    + *
  • {@link #setServer(Server)}
  • + *
  • {@link #setClient(javax.inject.Provider)}
  • + *
  • {@link #setExecutor(java.util.concurrent.Executor)}
  • + *
  • {@link #setMainThread(MainThread)}
  • + *
  • {@link #setConverter(Converter)}
  • + *
+ */ + public static class Builder { + private Server server; + private Provider clientProvider; + private Executor executor; + private MainThread mainThread; + private Headers headers; + private Converter converter; + private HttpProfiler profiler; + + public Builder setServer(String endpoint) { + return setServer(new Server(endpoint)); } - public void beforeCall() { - try { - beforeCallData.set(profiler.beforeCall()); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error occurred in HTTP profiler beforeCall().", e); - } + public Builder setServer(Server server) { + this.server = server; + return this; + } + + public Builder setClient(final HttpClient client) { + return setClient(new Provider() { + @Override public HttpClient get() { + return client; + } + }); } - @Override public Void handleResponse(HttpResponse httpResponse) throws IOException { - // Intercept the response and send data to profiler. - long elapsedTime = System.currentTimeMillis() - startTime; - int statusCode = httpResponse.getStatusLine().getStatusCode(); + public Builder setClient(Provider clientProvider) { + this.clientProvider = clientProvider; + return this; + } - try { - profiler.afterCall(requestInfo, elapsedTime, statusCode, beforeCallData.get()); - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Error occurred in HTTP profiler afterCall().", e); - } + public Builder setExecutor(Executor executor) { + this.executor = executor; + return this; + } + + public Builder setMainThread(MainThread mainThread) { + this.mainThread = mainThread; + return this; + } + + public Builder setHeaders(Headers headers) { + this.headers = headers; + return this; + } + + public Builder setConverter(Converter converter) { + this.converter = converter; + return this; + } + + public Builder setProfiler(HttpProfiler profiler) { + this.profiler = profiler; + return this; + } + + public RestAdapter build() { + if (server == null) throw new NullPointerException("server"); + if (clientProvider == null) throw new NullPointerException("clientProvider"); + if (converter == null) throw new NullPointerException("converter"); + + // TODO Remove the following two when we support synchronous invocation as they will be allowed to be null. + if (executor == null) throw new NullPointerException("executor"); + if (mainThread == null) throw new NullPointerException("mainThread"); - // Pass along the response to the normal handler. - return delegate.handleResponse(httpResponse); + return new RestAdapter(server, clientProvider, executor, mainThread, headers, converter, profiler); } } } \ No newline at end of file diff --git a/http/src/test/java/retrofit/http/HttpRequestBuilderTest.java b/http/src/test/java/retrofit/http/HttpRequestBuilderTest.java index ada6fabbca97dc4d630043f2f4f7f010297679cf..e05befe3b1c5a0889f94ef99832277326caafc16 100644 --- a/http/src/test/java/retrofit/http/HttpRequestBuilderTest.java +++ b/http/src/test/java/retrofit/http/HttpRequestBuilderTest.java @@ -2,7 +2,6 @@ package retrofit.http; import com.google.gson.Gson; -import org.apache.http.HttpMessage; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpPut; import org.apache.http.client.methods.HttpUriRequest; @@ -23,10 +22,6 @@ import static org.fest.assertions.Fail.fail; public class HttpRequestBuilderTest { private static final Gson GSON = new Gson(); private static final String API_URL = "http://taqueria.com/lengua/taco"; - private static final Headers BLANK_HEADERS = new Headers() { - @Override public void setOn(HttpMessage message, String mimeType) { - } - }; @Test public void testRegex() throws Exception { expectParams(""); @@ -205,7 +200,6 @@ public class HttpRequestBuilderTest { .setMethod(method) .setArgs(args) .setApiUrl(API_URL) - .setHeaders(BLANK_HEADERS) .build(); } diff --git a/http/src/test/java/retrofit/http/RestAdapterTest.java b/http/src/test/java/retrofit/http/RestAdapterTest.java index ba6561fbcbe9dc900e0860199accc738386800be..8b541abeadeda79a75538e4e3bae19fab3515aa2 100644 --- a/http/src/test/java/retrofit/http/RestAdapterTest.java +++ b/http/src/test/java/retrofit/http/RestAdapterTest.java @@ -23,7 +23,6 @@ import org.junit.Test; import retrofit.http.Callback.ServerError; import javax.inject.Named; -import javax.inject.Provider; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.lang.reflect.Method; @@ -66,14 +65,14 @@ public class RestAdapterTest { mockCallback = createMock(ResponseCallback.class); mockResponse = createMock(HttpResponse.class); - Server server = new Server("http://host/api/"); - Provider httpClientProvider = new Provider() { - @Override public HttpClient get() { - return mockHttpClient; - } - }; - restAdapter = new RestAdapter(server, httpClientProvider, mockExecutor, mockMainThread, mockHeaders, - new GsonConverter(GSON), HttpProfiler.NONE); + restAdapter = new RestAdapter.Builder() + .setServer("http://host/api/") + .setClient(mockHttpClient) + .setExecutor(mockExecutor) + .setMainThread(mockMainThread) + .setHeaders(mockHeaders) + .setConverter(new GsonConverter(GSON)) + .build(); } @Test public void testServiceDeleteSimple() throws IOException { @@ -392,8 +391,7 @@ public class RestAdapterTest { private void expectSetOnWithRequest(final Class expectedRequestClass, final String expectedUri) { final Capture capture = new Capture(); - final Capture captureMime = new Capture(); - mockHeaders.setOn(capture(capture), capture(captureMime)); + mockHeaders.setOn(capture(capture)); expectLastCall().andAnswer(new IAnswer() { @Override public Object answer() throws Throwable { T request = expectedRequestClass.cast(capture.getValue());