diff --git a/src/main/java/com/arangodb/ArangoDB.java b/src/main/java/com/arangodb/ArangoDB.java
index 260d939d9..403ba3a26 100644
--- a/src/main/java/com/arangodb/ArangoDB.java
+++ b/src/main/java/com/arangodb/ArangoDB.java
@@ -45,6 +45,7 @@
import com.arangodb.velocypack.*;
import com.arangodb.velocystream.Request;
import com.arangodb.velocystream.Response;
+import org.apache.http.client.HttpRequestRetryHandler;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@@ -187,6 +188,23 @@ public Builder hostnameVerifier(final HostnameVerifier hostnameVerifier) {
return this;
}
+ /**
+ * Sets the {@link HttpRequestRetryHandler} to be used when using http protocol.
+ *
+ * @param httpRequestRetryHandler HttpRequestRetryHandler to be used
+ * @return {@link ArangoDB.Builder}
+ *
+ *
+ * NOTE:
+ * Some ArangoDB HTTP endpoints do not honor RFC-2616 HTTP 1.1 specification in respect to
+ * 9.1 Safe and Idempotent Methods.
+ * Please refer to HTTP API Documentation for details.
+ */
+ public Builder httpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
+ setHttpRequestRetryHandler(httpRequestRetryHandler);
+ return this;
+ }
+
/**
* Sets the chunk size when {@link Protocol#VST} is used.
*
@@ -584,7 +602,7 @@ public synchronized ArangoDB build() {
final ConnectionFactory connectionFactory = (protocol == null || Protocol.VST == protocol)
? new VstConnectionFactorySync(host, timeout, connectionTtl, useSsl, sslContext)
: new HttpConnectionFactory(timeout, user, password, useSsl, sslContext, hostnameVerifier, custom,
- protocol, connectionTtl, httpCookieSpec);
+ protocol, connectionTtl, httpCookieSpec, httpRequestRetryHandler);
final Collection hostList = createHostList(max, connectionFactory);
final HostResolver hostResolver = createHostResolver(hostList, max, connectionFactory);
diff --git a/src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java b/src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java
index a8fdd01d3..41aaae257 100644
--- a/src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java
+++ b/src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java
@@ -31,6 +31,7 @@
import com.arangodb.util.ArangoSerializer;
import com.arangodb.velocypack.VPack;
import com.arangodb.velocypack.VPackParser;
+import org.apache.http.client.HttpRequestRetryHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -74,6 +75,7 @@ public abstract class InternalArangoDBBuilder {
protected String password;
protected Boolean useSsl;
protected String httpCookieSpec;
+ protected HttpRequestRetryHandler httpRequestRetryHandler;
protected SSLContext sslContext;
protected HostnameVerifier hostnameVerifier;
protected Integer chunksize;
@@ -166,6 +168,10 @@ protected void setHostnameVerifier(final HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
}
+ protected void setHttpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
+ this.httpRequestRetryHandler = httpRequestRetryHandler;
+ }
+
protected void setChunksize(final Integer chunksize) {
this.chunksize = chunksize;
}
diff --git a/src/main/java/com/arangodb/internal/http/HttpConnection.java b/src/main/java/com/arangodb/internal/http/HttpConnection.java
index 5c6069d38..5a221164c 100644
--- a/src/main/java/com/arangodb/internal/http/HttpConnection.java
+++ b/src/main/java/com/arangodb/internal/http/HttpConnection.java
@@ -35,6 +35,7 @@
import org.apache.http.auth.AuthenticationException;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.*;
import org.apache.http.client.utils.URLEncodedUtils;
@@ -90,6 +91,7 @@ public static class Builder {
private SSLContext sslContext;
private HostnameVerifier hostnameVerifier;
private Integer timeout;
+ private HttpRequestRetryHandler httpRequestRetryHandler;
public Builder user(final String user) {
this.user = user;
@@ -146,8 +148,14 @@ public Builder timeout(final Integer timeout) {
return this;
}
+ public Builder httpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
+ this.httpRequestRetryHandler = httpRequestRetryHandler;
+ return this;
+ }
+
public HttpConnection build() {
- return new HttpConnection(host, timeout, user, password, useSsl, sslContext, hostnameVerifier, util, contentType, ttl, httpCookieSpec);
+ return new HttpConnection(host, timeout, user, password, useSsl, sslContext, hostnameVerifier, util,
+ contentType, ttl, httpCookieSpec, httpRequestRetryHandler);
}
}
@@ -162,7 +170,7 @@ public HttpConnection build() {
private HttpConnection(final HostDescription host, final Integer timeout, final String user, final String password,
final Boolean useSsl, final SSLContext sslContext, final HostnameVerifier hostnameVerifier, final ArangoSerialization util, final Protocol contentType,
- final Long ttl, final String httpCookieSpec) {
+ final Long ttl, final String httpCookieSpec, final HttpRequestRetryHandler httpRequestRetryHandler) {
super();
this.host = host;
this.user = user;
@@ -197,7 +205,7 @@ private HttpConnection(final HostDescription host, final Integer timeout, final
final ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> HttpConnection.this.getKeepAliveDuration(response);
final HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig.build())
.setConnectionManager(cm).setKeepAliveStrategy(keepAliveStrategy)
- .setRetryHandler(new DefaultHttpRequestRetryHandler());
+ .setRetryHandler(httpRequestRetryHandler != null ? httpRequestRetryHandler : new DefaultHttpRequestRetryHandler());
if (ttl != null) {
builder.setConnectionTimeToLive(ttl, TimeUnit.MILLISECONDS);
}
diff --git a/src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java b/src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java
index bab2b8233..0461cd098 100644
--- a/src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java
+++ b/src/main/java/com/arangodb/internal/http/HttpConnectionFactory.java
@@ -25,6 +25,7 @@
import com.arangodb.internal.net.ConnectionFactory;
import com.arangodb.internal.net.HostDescription;
import com.arangodb.util.ArangoSerialization;
+import org.apache.http.client.HttpRequestRetryHandler;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@@ -37,12 +38,13 @@ public class HttpConnectionFactory implements ConnectionFactory {
private final HttpConnection.Builder builder;
public HttpConnectionFactory(final Integer timeout, final String user, final String password, final Boolean useSsl,
- final SSLContext sslContext, final HostnameVerifier hostnameVerifier, final ArangoSerialization util, final Protocol protocol,
- final Long connectionTtl, String httpCookieSpec) {
+ final SSLContext sslContext, final HostnameVerifier hostnameVerifier,
+ final ArangoSerialization util, final Protocol protocol, final Long connectionTtl,
+ final String httpCookieSpec, final HttpRequestRetryHandler httpRequestRetryHandler) {
super();
builder = new HttpConnection.Builder().timeout(timeout).user(user).password(password).useSsl(useSsl)
.sslContext(sslContext).hostnameVerifier(hostnameVerifier).serializationUtil(util).contentType(protocol)
- .ttl(connectionTtl).httpCookieSpec(httpCookieSpec);
+ .ttl(connectionTtl).httpCookieSpec(httpCookieSpec).httpRequestRetryHandler(httpRequestRetryHandler);
}
diff --git a/src/test/java/com/arangodb/internal/http/HttpRetryTest.java b/src/test/java/com/arangodb/internal/http/HttpRetryTest.java
new file mode 100644
index 000000000..384ae92f5
--- /dev/null
+++ b/src/test/java/com/arangodb/internal/http/HttpRetryTest.java
@@ -0,0 +1,77 @@
+/*
+ * DISCLAIMER
+ *
+ * Copyright 2016 ArangoDB GmbH, Cologne, Germany
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Copyright holder is ArangoDB GmbH, Cologne, Germany
+ */
+
+package com.arangodb.internal.http;
+
+
+import com.arangodb.ArangoDB;
+import com.arangodb.ArangoDBException;
+import com.arangodb.Protocol;
+import org.apache.http.client.HttpRequestRetryHandler;
+import org.apache.http.protocol.HttpContext;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.io.IOException;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.fail;
+
+/**
+ * @author Michele Rastelli
+ */
+public class HttpRetryTest {
+
+ private final static int RETRIES = 2;
+
+ private static class TestRetryHandler implements HttpRequestRetryHandler {
+ private int retriesCounter = 0;
+
+ @Override
+ public boolean retryRequest(IOException exception, int executionCount, HttpContext context) {
+ return ++retriesCounter < RETRIES;
+ }
+
+ }
+
+ /**
+ * remove host from src/test/resources/arangodb.properties to run this test
+ */
+ @Test
+ @Ignore
+ public void retry() {
+ TestRetryHandler retryHandler = new TestRetryHandler();
+ ArangoDB arangoDB = new ArangoDB.Builder()
+ .host("wrongHost", 8529)
+ .useProtocol(Protocol.HTTP_JSON)
+ .httpRequestRetryHandler(retryHandler)
+ .build();
+
+ try {
+ arangoDB.getVersion();
+ fail("it should throw I/O exception");
+ } catch (ArangoDBException e) {
+ assertThat(retryHandler.retriesCounter, is(RETRIES));
+ }
+
+ }
+
+}