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
26 changes: 18 additions & 8 deletions src/main/java/com/microsoft/graph/httpcore/RetryHandler.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,51 @@
import org.apache.http.protocol.HttpCoreContext;
import org.apache.http.util.Args;

import com.microsoft.graph.httpcore.middlewareoption.MiddlewareType;
import com.microsoft.graph.httpcore.middlewareoption.RetryOptions;

public class RetryHandler implements ServiceUnavailableRetryStrategy{

/**
* Maximum number of allowed retries if the server responds with a HTTP code
* in our retry code list. Default value is 1.
*/
private final int maxRetries;
private final int maxRetries = 2;

/**
* Retry interval between subsequent requests, in milliseconds. Default
* value is 1 second.
*/
private long retryInterval;
private long retryInterval = 1000;
private final int DELAY_MILLISECONDS = 1000;
private final String RETRY_AFTER = "Retry-After";
private final String TRANSFER_ENCODING = "Transfer-Encoding";

private final int MSClientErrorCodeTooManyRequests = 429;
private final int MSClientErrorCodeServiceUnavailable = 503;
private final int MSClientErrorCodeGatewayTimeout = 504;
private final RetryOptions mRetryOption;

public RetryHandler(final int maxRetries, final int retryInterval) {
public RetryHandler(RetryOptions option) {
super();
Args.positive(maxRetries, "Max retries");
Args.positive(retryInterval, "Retry interval");
this.maxRetries = maxRetries;
this.retryInterval = retryInterval;
this.mRetryOption = option;
}

public RetryHandler() {
this(2, 1000);
this(null);
}

@Override
public boolean retryRequest(HttpResponse response, int executionCount, HttpContext context) {

RetryOptions retryOption = (RetryOptions)context.getAttribute(MiddlewareType.RETRY.toString());
if(retryOption != null) {
return retryOption.shouldRetry().shouldRetry(response, executionCount, context);
}
if(mRetryOption != null) {
return mRetryOption.shouldRetry().shouldRetry(response, executionCount, context);
}

boolean shouldRetry = false;
int statusCode = response.getStatusLine().getStatusCode();
shouldRetry = (executionCount < maxRetries) && checkStatus(statusCode) && isBuffered(response, context);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package com.microsoft.graph.httpcore.middlewareoption;

import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.protocol.HttpClientContext;

public class HttpContextBuilder {

private RetryOptions retryoptions;
private int maxRedirect = -1;

public static HttpContextBuilder create() {
return new HttpContextBuilder();
}

public void setRetryOption(IShouldRetry shouldRetry) {
retryoptions = new RetryOptions(shouldRetry);
}

public void setRedirectOption(int maxRedirect) {
this.maxRedirect = maxRedirect;
}

public HttpClientContext build() {
HttpClientContext context = HttpClientContext.create();
if(retryoptions != null)
context.setAttribute(MiddlewareType.RETRY.toString(), retryoptions);
if(maxRedirect != -1) {
RequestConfig config = RequestConfig.custom().setMaxRedirects(maxRedirect).build();
context.setRequestConfig(config);
}
return context;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
package com.microsoft.graph.httpcore.middlewareoption;

public interface IMiddlewareControl {

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
package com.microsoft.graph.httpcore.middlewareoption;

import org.apache.http.HttpResponse;
import org.apache.http.protocol.HttpContext;

public interface IShouldRetry {
boolean shouldRetry(HttpResponse response, int executionCount, HttpContext context);
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.microsoft.graph.httpcore.middlewareoption;

public enum MiddlewareType {

//Authentication Middleware
AUTHENTICATION,

//Redirect Middleware
REDIRECT,

//Retry Middleware
RETRY,

//Not supported
NOT_SUPPORTED
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.microsoft.graph.httpcore.middlewareoption;

import org.apache.http.HttpResponse;
import org.apache.http.protocol.HttpContext;

public class RetryOptions implements IMiddlewareControl {
private IShouldRetry shouldretry;

public RetryOptions(){
this(new IShouldRetry() {
public boolean shouldRetry(HttpResponse response, int executionCount, HttpContext context) {
return true;
}
});
}

public RetryOptions(IShouldRetry shouldretry){
this.shouldretry = shouldretry;
}

public IShouldRetry shouldRetry() {
return shouldretry;
}
}
40 changes: 33 additions & 7 deletions src/test/java/com/microsoft/graph/httpcore/RetryHandlerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -14,40 +14,66 @@
import org.apache.http.client.protocol.HttpClientContext;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicHttpResponse;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpCoreContext;
import org.junit.Test;

import com.microsoft.graph.httpcore.middlewareoption.IShouldRetry;
import com.microsoft.graph.httpcore.middlewareoption.RetryOptions;

public class RetryHandlerTest {

int maxRetries = 2;
int retryInterval = 2000;
int retryInterval = 1000;
String testurl = "https://graph.microsoft.com/v1.0/";

@Test
public void testRetryHandlerCreation() {
RetryHandler retryhandler = new RetryHandler(maxRetries, retryInterval);
RetryHandler retryhandler = new RetryHandler();
assertTrue(retryhandler.getRetryInterval() == retryInterval);
}

@Test
public void testRetryHandlerWithRetryOptions() {
RetryOptions option = new RetryOptions();
RetryHandler retryhandler = new RetryHandler(option);
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
HttpClientContext localContext = HttpClientContext.create();
assertTrue(retryhandler.retryRequest(response, 1, localContext));
}

@Test
public void testRetryHandlerWithCustomRetryOptions() {
RetryOptions option = new RetryOptions(new IShouldRetry() {
public boolean shouldRetry(HttpResponse response, int executionCount, HttpContext context) {
return false;
}
});
RetryHandler retryhandler = new RetryHandler(option);
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
HttpClientContext localContext = HttpClientContext.create();
assertTrue(!retryhandler.retryRequest(response, 1, localContext));
}

@Test
public void testRetryRequestWithMaxRetryAttempts() {
RetryHandler retryhandler = new RetryHandler(maxRetries, retryInterval);
RetryHandler retryhandler = new RetryHandler();
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, "Gateway Timeout");
HttpClientContext localContext = HttpClientContext.create();
assertFalse(retryhandler.retryRequest(response, 3, localContext));
}

@Test
public void testRetryRequestForStatusCode() {
RetryHandler retryhandler = new RetryHandler(maxRetries, retryInterval);
RetryHandler retryhandler = new RetryHandler();
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_INTERNAL_SERVER_ERROR, "Internal Server Error");
HttpClientContext localContext = HttpClientContext.create();
assertFalse(retryhandler.retryRequest(response, 1, localContext));
}

@Test
public void testRetryRequestWithTransferEncoding() {
RetryHandler retryhandler = new RetryHandler(maxRetries, retryInterval);
RetryHandler retryhandler = new RetryHandler();
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, "Internal Server Error");
response.setHeader("Transfer-Encoding", "chunked");
HttpPost httppost = new HttpPost(testurl);
Expand All @@ -67,7 +93,7 @@ public void testRetryRequestWithTransferEncoding() {

@Test
public void testRetryRequestWithExponentialBackOff() {
RetryHandler retryhandler = new RetryHandler(maxRetries, retryInterval);
RetryHandler retryhandler = new RetryHandler();
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, "Internal Server Error");
HttpPost httppost = new HttpPost(testurl);

Expand All @@ -87,7 +113,7 @@ public void testRetryRequestWithExponentialBackOff() {

@Test
public void testRetryHandlerRetryRequestWithRetryAfterHeader() {
RetryHandler retryhandler = new RetryHandler(maxRetries, retryInterval);
RetryHandler retryhandler = new RetryHandler();
HttpResponse response = new BasicHttpResponse(HttpVersion.HTTP_1_1, HttpStatus.SC_GATEWAY_TIMEOUT, "Internal Server Error");
response.setHeader("Retry-After", "100");
HttpPost httppost = new HttpPost(testurl);
Expand Down