Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions src/main/java/com/google/maps/GaeRequestHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ public class GaeRequestHandler implements GeoApiContext.RequestHandler {
private final URLFetchService client = URLFetchServiceFactory.getURLFetchService();

@Override
public <T, R extends ApiResponse<T>> PendingResult<T> handle(String hostName, String url, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout) {
public <T, R extends ApiResponse<T>> PendingResult<T> handle(String hostName, String url, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout, Integer maxRetries) {
FetchOptions fetchOptions = FetchOptions.Builder.withDeadline(10);
HTTPRequest req = null;
try {
Expand All @@ -52,11 +52,11 @@ public <T, R extends ApiResponse<T>> PendingResult<T> handle(String hostName, St
throw(new RuntimeException(e));
}

return new GaePendingResult<T, R>(req, client, clazz, fieldNamingPolicy, errorTimeout);
return new GaePendingResult<T, R>(req, client, clazz, fieldNamingPolicy, errorTimeout, maxRetries);
}

@Override
public <T, R extends ApiResponse<T>> PendingResult<T> handlePost(String hostName, String url, String payload, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout) {
public <T, R extends ApiResponse<T>> PendingResult<T> handlePost(String hostName, String url, String payload, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout, Integer maxRetries) {
FetchOptions fetchOptions = FetchOptions.Builder.withDeadline(10);
HTTPRequest req = null;
try {
Expand All @@ -68,7 +68,7 @@ public <T, R extends ApiResponse<T>> PendingResult<T> handlePost(String hostName
throw(new RuntimeException(e));
}

return new GaePendingResult<T, R>(req, client, clazz, fieldNamingPolicy, errorTimeout);
return new GaePendingResult<T, R>(req, client, clazz, fieldNamingPolicy, errorTimeout, maxRetries);
}


Expand Down
31 changes: 27 additions & 4 deletions src/main/java/com/google/maps/GeoApiContext.java
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ public class GeoApiContext {
private UrlSigner urlSigner;
private String channel;
private RequestHandler requestHandler;
private Integer maxRetries;


/**
Expand All @@ -55,8 +56,8 @@ public class GeoApiContext {
* @see GaeRequestHandler
*/
public interface RequestHandler {
<T, R extends ApiResponse<T>> PendingResult<T> handle(String hostName, String url, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout);
<T, R extends ApiResponse<T>> PendingResult<T> handlePost(String hostName, String url, String payload, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout);
<T, R extends ApiResponse<T>> PendingResult<T> handle(String hostName, String url, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout, Integer maxRetries);
<T, R extends ApiResponse<T>> PendingResult<T> handlePost(String hostName, String url, String payload, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout, Integer maxRetries);
void setConnectTimeout(long timeout, TimeUnit unit);
void setReadTimeout(long timeout, TimeUnit unit);
void setWriteTimeout(long timeout, TimeUnit unit);
Expand Down Expand Up @@ -168,7 +169,7 @@ <T, R extends ApiResponse<T>> PendingResult<T> post(ApiConfig config,
hostName = baseUrlOverride;
}

return requestHandler.handlePost(hostName, url.toString(), params.get("_payload"), USER_AGENT, clazz, config.fieldNamingPolicy, errorTimeout);
return requestHandler.handlePost(hostName, url.toString(), params.get("_payload"), USER_AGENT, clazz, config.fieldNamingPolicy, errorTimeout, maxRetries);
}

private <T, R extends ApiResponse<T>> PendingResult<T> getWithPath(Class<R> clazz,
Expand Down Expand Up @@ -200,7 +201,7 @@ private <T, R extends ApiResponse<T>> PendingResult<T> getWithPath(Class<R> claz
hostName = baseUrlOverride;
}

return requestHandler.handle(hostName, url.toString(), USER_AGENT, clazz, fieldNamingPolicy, errorTimeout);
return requestHandler.handle(hostName, url.toString(), USER_AGENT, clazz, fieldNamingPolicy, errorTimeout, maxRetries);
}

private void checkContext(boolean canUseClientId) {
Expand Down Expand Up @@ -279,12 +280,34 @@ public GeoApiContext setWriteTimeout(long timeout, TimeUnit unit) {
/**
* Sets the cumulative time limit for which retry-able errors will be retried. Defaults to 60
* seconds. Set to zero to retry requests forever.
*
* <p>This operates separately from the count-based {@link #setMaxRetries(Integer)}.
*/
public GeoApiContext setRetryTimeout(long timeout, TimeUnit unit) {
this.errorTimeout = unit.toMillis(timeout);
return this;
}

/**
* Sets the maximum number of times each retry-able errors will be retried. Set this to null to not have a max number.
* Set this to zero to disable retries.
*
* <p>This operates separately from the time-based {@link #setRetryTimeout(long, TimeUnit)}.
*/
public GeoApiContext setMaxRetries(Integer maxRetries) {
this.maxRetries = maxRetries;
return this;
}

/**
* Disable retries completely.
*/
public GeoApiContext disableRetries() {
setMaxRetries(0);
setRetryTimeout(0, TimeUnit.MILLISECONDS);
return this;
}

/**
* Sets the maximum number of queries that will be executed during a 1 second interval. The
* default is 10. A minimum interval between requests will also be enforced, set to 1/(2 * {@code
Expand Down
8 changes: 4 additions & 4 deletions src/main/java/com/google/maps/OkHttpRequestHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,25 +50,25 @@ public OkHttpRequestHandler() {
}

@Override
public <T, R extends ApiResponse<T>> PendingResult<T> handle(String hostName, String url, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout) {
public <T, R extends ApiResponse<T>> PendingResult<T> handle(String hostName, String url, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout, Integer maxRetries) {
Request req = new Request.Builder()
.get()
.header("User-Agent", userAgent)
.url(hostName + url).build();

LOG.log(Level.INFO, "Request: {0}", hostName + url);

return new OkHttpPendingResult<T, R>(req, client, clazz, fieldNamingPolicy, errorTimeout);
return new OkHttpPendingResult<T, R>(req, client, clazz, fieldNamingPolicy, errorTimeout, maxRetries);
}
@Override
public <T, R extends ApiResponse<T>> PendingResult<T> handlePost(String hostName, String url, String payload, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout) {
public <T, R extends ApiResponse<T>> PendingResult<T> handlePost(String hostName, String url, String payload, String userAgent, Class<R> clazz, FieldNamingPolicy fieldNamingPolicy, long errorTimeout, Integer maxRetries) {
RequestBody body = RequestBody.create(JSON, payload);
Request req = new Request.Builder()
.post(body)
.header("User-Agent", userAgent)
.url(hostName + url).build();

return new OkHttpPendingResult<T, R>(req, client, clazz, fieldNamingPolicy, errorTimeout);
return new OkHttpPendingResult<T, R>(req, client, clazz, fieldNamingPolicy, errorTimeout, maxRetries);
}
@Override
public void setConnectTimeout(long timeout, TimeUnit unit) {
Expand Down
22 changes: 19 additions & 3 deletions src/main/java/com/google/maps/internal/GaePendingResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import com.google.maps.model.PlaceDetails.Review.AspectRating.RatingType;
import com.google.maps.model.PriceLevel;
import com.google.maps.model.TravelMode;
import com.squareup.okhttp.Response;
import org.joda.time.DateTime;
import org.joda.time.Instant;
import org.joda.time.LocalTime;
Expand All @@ -64,6 +65,7 @@ public class GaePendingResult<T, R extends ApiResponse<T>>
private final URLFetchService client;
private final Class<R> responseClass;
private final FieldNamingPolicy fieldNamingPolicy;
private final Integer maxRetries;

private Callback<T> callback;
private long errorTimeOut;
Expand All @@ -80,14 +82,16 @@ public class GaePendingResult<T, R extends ApiResponse<T>>
* @param responseClass Model class to unmarshal JSON body content.
* @param fieldNamingPolicy FieldNamingPolicy for unmarshaling JSON.
* @param errorTimeOut Number of milliseconds to re-send erroring requests.
* @param maxRetries Number of times allowed to re-send erroring requests.
*/
public GaePendingResult(HTTPRequest request, URLFetchService client, Class<R> responseClass,
FieldNamingPolicy fieldNamingPolicy, long errorTimeOut) {
FieldNamingPolicy fieldNamingPolicy, long errorTimeOut, Integer maxRetries) {
this.request = request;
this.client = client;
this.responseClass = responseClass;
this.fieldNamingPolicy = fieldNamingPolicy;
this.errorTimeOut = errorTimeOut;
this.maxRetries = maxRetries;

this.call = client.fetchAsync(request);
}
Expand Down Expand Up @@ -124,7 +128,7 @@ public void cancel() {

@SuppressWarnings("unchecked")
private T parseResponse(GaePendingResult<T, R> request, HTTPResponse response) throws Exception {
if (RETRY_ERROR_CODES.contains(response.getResponseCode()) && cumulativeSleepTime < errorTimeOut) {
if (shouldRetry(response)) {
// Retry is a blocking method, but that's OK. If we're here, we're either in an await()
// call, which is blocking anyway, or we're handling a callback in a separate thread.
return request.retry();
Expand Down Expand Up @@ -195,7 +199,7 @@ private T parseResponse(GaePendingResult<T, R> request, HTTPResponse response) t
return resp.getResult();
} else {
ApiException e = resp.getError();
if (e instanceof OverQueryLimitException && cumulativeSleepTime < errorTimeOut) {
if (shouldRetry(e)) {
// Retry over_query_limit errors
return request.retry();
} else {
Expand All @@ -211,4 +215,16 @@ private T retry() throws Exception {
this.call = client.fetchAsync(request);
return this.await();
}

private boolean shouldRetry(HTTPResponse response) {
return RETRY_ERROR_CODES.contains(response.getResponseCode())
&& cumulativeSleepTime < errorTimeOut
&& (maxRetries == null || retryCounter < maxRetries);
}

private boolean shouldRetry(ApiException exception) {
return exception instanceof OverQueryLimitException
&& cumulativeSleepTime < errorTimeOut
&& (maxRetries == null || retryCounter < maxRetries);
}
}
21 changes: 18 additions & 3 deletions src/main/java/com/google/maps/internal/OkHttpPendingResult.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ public class OkHttpPendingResult<T, R extends ApiResponse<T>>
private final OkHttpClient client;
private final Class<R> responseClass;
private final FieldNamingPolicy fieldNamingPolicy;
private final Integer maxRetries;

private Call call;
private Callback<T> callback;
Expand All @@ -84,14 +85,16 @@ public class OkHttpPendingResult<T, R extends ApiResponse<T>>
* @param responseClass Model class to unmarshal JSON body content.
* @param fieldNamingPolicy FieldNamingPolicy for unmarshaling JSON.
* @param errorTimeOut Number of milliseconds to re-send erroring requests.
* @param maxRetries Number of times allowed to re-send erroring requests.
*/
public OkHttpPendingResult(Request request, OkHttpClient client, Class<R> responseClass,
FieldNamingPolicy fieldNamingPolicy, long errorTimeOut) {
FieldNamingPolicy fieldNamingPolicy, long errorTimeOut, Integer maxRetries) {
this.request = request;
this.client = client;
this.responseClass = responseClass;
this.fieldNamingPolicy = fieldNamingPolicy;
this.errorTimeOut = errorTimeOut;
this.maxRetries = maxRetries;

this.call = client.newCall(request);
}
Expand Down Expand Up @@ -204,7 +207,7 @@ public void onResponse(Response response) throws IOException {

@SuppressWarnings("unchecked")
private T parseResponse(OkHttpPendingResult<T, R> request, Response response) throws Exception {
if (RETRY_ERROR_CODES.contains(response.code()) && cumulativeSleepTime < errorTimeOut) {
if (shouldRetry(response)) {
// Retry is a blocking method, but that's OK. If we're here, we're either in an await()
// call, which is blocking anyway, or we're handling a callback in a separate thread.
return request.retry();
Expand Down Expand Up @@ -269,7 +272,7 @@ private T parseResponse(OkHttpPendingResult<T, R> request, Response response) th
return resp.getResult();
} else {
ApiException e = resp.getError();
if (e instanceof OverQueryLimitException && cumulativeSleepTime < errorTimeOut) {
if (shouldRetry(e)) {
// Retry over_query_limit errors
return request.retry();
} else {
Expand All @@ -285,4 +288,16 @@ private T retry() throws Exception {
this.call = client.newCall(request);
return this.await();
}

private boolean shouldRetry(Response response) {
return RETRY_ERROR_CODES.contains(response.code())
&& cumulativeSleepTime < errorTimeOut
&& (maxRetries == null || retryCounter < maxRetries);
}

private boolean shouldRetry(ApiException exception) {
return exception instanceof OverQueryLimitException
&& cumulativeSleepTime < errorTimeOut
&& (maxRetries == null || retryCounter < maxRetries);
}
}
Loading