Skip to content
Closed
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
25 changes: 5 additions & 20 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -189,8 +189,8 @@
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<optional>true</optional>
</dependency>
<dependency>
Expand Down Expand Up @@ -229,24 +229,9 @@
<version>2.0.0</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpcore</artifactId>
<version>4.4.14</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.14</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.2</version>
<groupId>org.apache.httpcomponents.client5</groupId>
<artifactId>httpclient5</artifactId>
<version>5.1</version>
</dependency>
<dependency>
<groupId>com.arangodb</groupId>
Expand Down
6 changes: 3 additions & 3 deletions src/main/java/com/arangodb/ArangoDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@
import com.arangodb.velocypack.ValueType;
import com.arangodb.velocystream.Request;
import com.arangodb.velocystream.Response;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.hc.client5.http.HttpRequestRetryStrategy;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
Expand Down Expand Up @@ -212,7 +212,7 @@ public Builder hostnameVerifier(final HostnameVerifier hostnameVerifier) {
}

/**
* Sets the {@link HttpRequestRetryHandler} to be used when using http protocol.
* Sets the {@link HttpRequestRetryStrategy} to be used when using http protocol.
*
* @param httpRequestRetryHandler HttpRequestRetryHandler to be used
* @return {@link ArangoDB.Builder}
Expand All @@ -223,7 +223,7 @@ public Builder hostnameVerifier(final HostnameVerifier hostnameVerifier) {
* <a href="https://tools.ietf.org/html/rfc2616#section-9.1">9.1 Safe and Idempotent Methods</a>.
* Please refer to <a href="https://www.arangodb.com/docs/stable/http/">HTTP API Documentation</a> for details.
*/
public Builder httpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
public Builder httpRequestRetryHandler(final HttpRequestRetryStrategy httpRequestRetryHandler) {
setHttpRequestRetryHandler(httpRequestRetryHandler);
return this;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
import com.arangodb.util.ArangoSerializer;
import com.arangodb.velocypack.VPack;
import com.arangodb.velocypack.VPackParser;
import org.apache.http.client.HttpRequestRetryHandler;
import org.apache.hc.client5.http.HttpRequestRetryStrategy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down Expand Up @@ -87,7 +87,7 @@ public abstract class InternalArangoDBBuilder {
protected String password;
protected Boolean useSsl;
protected String httpCookieSpec;
protected HttpRequestRetryHandler httpRequestRetryHandler;
protected HttpRequestRetryStrategy httpRequestRetryHandler;
protected SSLContext sslContext;
protected HostnameVerifier hostnameVerifier;
protected Integer chunksize;
Expand Down Expand Up @@ -182,7 +182,7 @@ protected void setHostnameVerifier(final HostnameVerifier hostnameVerifier) {
this.hostnameVerifier = hostnameVerifier;
}

protected void setHttpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
protected void setHttpRequestRetryHandler(final HttpRequestRetryStrategy httpRequestRetryHandler) {
this.httpRequestRetryHandler = httpRequestRetryHandler;
}

Expand Down
2 changes: 1 addition & 1 deletion src/main/java/com/arangodb/internal/http/CURLLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
import com.arangodb.util.ArangoSerialization;
import com.arangodb.velocystream.Request;
import com.arangodb.velocystream.RequestType;
import org.apache.http.auth.Credentials;
import org.apache.hc.client5.http.auth.Credentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand Down
150 changes: 75 additions & 75 deletions src/main/java/com/arangodb/internal/http/HttpConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,37 +31,39 @@
import com.arangodb.velocypack.VPackSlice;
import com.arangodb.velocystream.Request;
import com.arangodb.velocystream.Response;
import org.apache.http.*;
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;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.conn.ConnectionKeepAliveStrategy;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.auth.BasicScheme;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.DefaultHttpRequestRetryHandler;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicHeaderElementIterator;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.ssl.SSLContexts;
import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
import org.apache.hc.client5.http.HttpRequestRetryStrategy;
import org.apache.hc.client5.http.auth.Credentials;
import org.apache.hc.client5.http.auth.UsernamePasswordCredentials;
import org.apache.hc.client5.http.classic.methods.*;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
import org.apache.hc.client5.http.impl.auth.BasicScheme;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.client5.http.protocol.HttpClientContext;
import org.apache.hc.client5.http.ssl.HttpsSupport;
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
import org.apache.hc.core5.http.*;
import org.apache.hc.core5.http.io.entity.ByteArrayEntity;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.apache.hc.core5.http.message.BasicClassicHttpRequest;
import org.apache.hc.core5.http.message.BasicHeaderElementIterator;
import org.apache.hc.core5.http.message.BasicNameValuePair;
import org.apache.hc.core5.net.URLEncodedUtils;
import org.apache.hc.core5.ssl.SSLContexts;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
Expand Down Expand Up @@ -91,7 +93,7 @@ public static class Builder {
private SSLContext sslContext;
private HostnameVerifier hostnameVerifier;
private Integer timeout;
private HttpRequestRetryHandler httpRequestRetryHandler;
private HttpRequestRetryStrategy httpRequestRetryHandler;

public Builder user(final String user) {
this.user = user;
Expand Down Expand Up @@ -148,7 +150,7 @@ public Builder timeout(final Integer timeout) {
return this;
}

public Builder httpRequestRetryHandler(final HttpRequestRetryHandler httpRequestRetryHandler) {
public Builder httpRequestRetryHandler(final HttpRequestRetryStrategy httpRequestRetryHandler) {
this.httpRequestRetryHandler = httpRequestRetryHandler;
return this;
}
Expand All @@ -161,76 +163,77 @@ public HttpConnection build() {

private final PoolingHttpClientConnectionManager cm;
private final CloseableHttpClient client;
private final String user;
private final String password;
private final ArangoSerialization util;
private final Boolean useSsl;
private final Protocol contentType;
private final HostDescription host;
private final HttpClientContext authCtx;
private final Credentials credentials;

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 HttpRequestRetryHandler httpRequestRetryHandler) {
final Long ttl, final String httpCookieSpec, final HttpRequestRetryStrategy httpRequestRetryHandler) {
super();
this.host = host;
this.user = user;
this.password = password;
this.useSsl = useSsl;
this.util = util;
this.contentType = contentType;
final RegistryBuilder<ConnectionSocketFactory> registryBuilder = RegistryBuilder
.create();

PoolingHttpClientConnectionManagerBuilder cmBuilder = PoolingHttpClientConnectionManagerBuilder.create()
.setMaxConnPerRoute(1)
.setMaxConnTotal(1);
if (Boolean.TRUE == useSsl) {
registryBuilder.register("https", new SSLConnectionSocketFactory(
cmBuilder.setSSLSocketFactory(new SSLConnectionSocketFactory(
sslContext != null ? sslContext : SSLContexts.createSystemDefault(),
hostnameVerifier != null ? hostnameVerifier : SSLConnectionSocketFactory.getDefaultHostnameVerifier()
hostnameVerifier != null ? hostnameVerifier : HttpsSupport.getDefaultHostnameVerifier()
));
} else {
registryBuilder.register("http", new PlainConnectionSocketFactory());
}
cm = new PoolingHttpClientConnectionManager(registryBuilder.build());
cm.setDefaultMaxPerRoute(1);
cm.setMaxTotal(1);
if (ttl != null) {
cmBuilder.setConnectionTimeToLive(TimeValue.ofMilliseconds(ttl));
}
cm = cmBuilder.build();

final RequestConfig.Builder requestConfig = RequestConfig.custom();
if (timeout != null && timeout >= 0) {
requestConfig.setConnectTimeout(timeout);
requestConfig.setConnectionRequestTimeout(timeout);
requestConfig.setSocketTimeout(timeout);
requestConfig.setConnectTimeout(Timeout.of(timeout, TimeUnit.MILLISECONDS));
requestConfig.setConnectionRequestTimeout(Timeout.of(timeout, TimeUnit.MILLISECONDS));
requestConfig.setResponseTimeout(Timeout.of(timeout, TimeUnit.MILLISECONDS));
}

if (httpCookieSpec != null && httpCookieSpec.length() > 1) {
requestConfig.setCookieSpec(httpCookieSpec);
}

final ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> HttpConnection.this.getKeepAliveDuration(response);
final ConnectionKeepAliveStrategy keepAliveStrategy = (response, context) -> TimeValue.ofSeconds(HttpConnection.this.getKeepAliveDuration(response));
final HttpClientBuilder builder = HttpClientBuilder.create().setDefaultRequestConfig(requestConfig.build())
.setConnectionManager(cm).setKeepAliveStrategy(keepAliveStrategy)
.setRetryHandler(httpRequestRetryHandler != null ? httpRequestRetryHandler : new DefaultHttpRequestRetryHandler());
if (ttl != null) {
builder.setConnectionTimeToLive(ttl, TimeUnit.MILLISECONDS);
}
.setRetryStrategy(httpRequestRetryHandler != null ? httpRequestRetryHandler : new DefaultHttpRequestRetryStrategy());

client = builder.build();
String pwd = password != null ? password : "";
credentials = user != null ? new UsernamePasswordCredentials(user, pwd.toCharArray()) : null;
authCtx = createAuthCtx();
}

private long getKeepAliveDuration(final HttpResponse response) {
final HeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HTTP.CONN_KEEP_ALIVE));
final BasicHeaderElementIterator it = new BasicHeaderElementIterator(response.headerIterator(HeaderElements.KEEP_ALIVE));
while (it.hasNext()) {
final HeaderElement he = it.nextElement();
final HeaderElement he = it.next();
final String param = he.getName();
final String value = he.getValue();
if (value != null && "timeout".equalsIgnoreCase(param)) {
try {
return Long.parseLong(value) * 1000L;
return Long.parseLong(value);
} catch (final NumberFormatException ignore) {
}
}
}
return 30L * 1000L;
return 30L;
}

@Override
public void close() throws IOException {
cm.shutdown();
cm.close();
client.close();
}

Expand All @@ -247,14 +250,14 @@ private static String buildUrl(final String baseUrl, final Request request) {
} else {
sb.append("?");
}
final String paramString = URLEncodedUtils.format(toList(request.getQueryParam()), "utf-8");
final String paramString = URLEncodedUtils.format(toList(request.getQueryParam()), StandardCharsets.UTF_8);
sb.append(paramString);
}
return sb.toString();
}

private HttpRequestBase buildHttpRequestBase(final Request request, final String url) {
final HttpRequestBase httpRequest;
private BasicClassicHttpRequest buildHttpRequestBase(final Request request, final String url) {
final BasicClassicHttpRequest httpRequest;
switch (request.getRequestType()) {
case POST:
httpRequest = requestWithBody(new HttpPost(url), request);
Expand All @@ -266,7 +269,7 @@ private HttpRequestBase buildHttpRequestBase(final Request request, final String
httpRequest = requestWithBody(new HttpPatch(url), request);
break;
case DELETE:
httpRequest = requestWithBody(new HttpDeleteWithBody(url), request);
httpRequest = requestWithBody(new HttpDelete(url), request);
break;
case HEAD:
httpRequest = new HttpHead(url);
Expand All @@ -279,7 +282,7 @@ private HttpRequestBase buildHttpRequestBase(final Request request, final String
return httpRequest;
}

private HttpRequestBase requestWithBody(final HttpEntityEnclosingRequestBase httpRequest, final Request request) {
private BasicClassicHttpRequest requestWithBody(final BasicClassicHttpRequest httpRequest, final Request request) {
final VPackSlice body = request.getBody();
if (body != null) {
if (contentType == Protocol.HTTP_VPACK) {
Expand Down Expand Up @@ -309,45 +312,42 @@ private static List<NameValuePair> toList(final Map<String, String> parameters)

public Response execute(final Request request) throws ArangoDBException, IOException {
final String url = buildUrl(buildBaseUrl(host), request);
final HttpRequestBase httpRequest = buildHttpRequestBase(request, url);
final BasicClassicHttpRequest httpRequest = buildHttpRequestBase(request, url);
httpRequest.setHeader("User-Agent", "Mozilla/5.0 (compatible; ArangoDB-JavaDriver/1.1; +http://mt.orz.at/)");
if (contentType == Protocol.HTTP_VPACK) {
httpRequest.setHeader("Accept", "application/x-velocypack");
}
addHeader(request, httpRequest);
final Credentials credentials = addCredentials(httpRequest);
if (LOGGER.isDebugEnabled()) {
CURLLogger.log(url, request, credentials, util);
}
Response response;
response = buildResponse(client.execute(httpRequest));
response = buildResponse(client.execute(httpRequest, authCtx));
checkError(response);
return response;
}

private static void addHeader(final Request request, final HttpRequestBase httpRequest) {
private static void addHeader(final Request request, final BasicClassicHttpRequest httpRequest) {
for (final Entry<String, String> header : request.getHeaderParam().entrySet()) {
httpRequest.addHeader(header.getKey(), header.getValue());
}
}

public Credentials addCredentials(final HttpRequestBase httpRequest) {
Credentials credentials = null;
if (user != null) {
credentials = new UsernamePasswordCredentials(user, password != null ? password : "");
try {
httpRequest.addHeader(new BasicScheme().authenticate(credentials, httpRequest, null));
} catch (final AuthenticationException e) {
throw new ArangoDBException(e);
}
public HttpClientContext createAuthCtx() {
final HttpClientContext localContext = HttpClientContext.create();
if (credentials != null) {
BasicScheme auth = new BasicScheme(StandardCharsets.UTF_8);
auth.initPreemptive(credentials);
HttpHost target = new HttpHost(Boolean.TRUE == useSsl ? "https" : "http", host.getHost(), host.getPort());
localContext.resetAuthExchange(target, auth);
}
return credentials;
return localContext;
}

public Response buildResponse(final CloseableHttpResponse httpResponse)
throws UnsupportedOperationException, IOException {
final Response response = new Response();
response.setResponseCode(httpResponse.getStatusLine().getStatusCode());
response.setResponseCode(httpResponse.getCode());
final HttpEntity entity = httpResponse.getEntity();
if (entity != null && entity.getContent() != null) {
if (contentType == Protocol.HTTP_VPACK) {
Expand All @@ -363,7 +363,7 @@ public Response buildResponse(final CloseableHttpResponse httpResponse)
}
}
}
final Header[] headers = httpResponse.getAllHeaders();
final Header[] headers = httpResponse.getHeaders();
final Map<String, String> meta = response.getMeta();
for (final Header header : headers) {
meta.put(header.getName(), header.getValue());
Expand Down
Loading