Skip to content

Feature/refactor extendedhostresolver #261

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 12 commits into from
May 24, 2019
1 change: 1 addition & 0 deletions ChangeLog.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a

### Fixed

- add arangodb.httpCookieSpec
- host handling (issue #241)
- logging extended hostresolver

Expand Down
4 changes: 2 additions & 2 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@
<arangodb.velocypack.version>1.4.1</arangodb.velocypack.version>

<!-- provided -->
<httpclient.version>4.5.7</httpclient.version>
<httpclient.version>4.5.8</httpclient.version>

<!-- test -->
<logback-classic.version>1.1.3</logback-classic.version>
Expand Down Expand Up @@ -278,7 +278,7 @@
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.11</version>
<version>1.12</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
Expand Down
3 changes: 2 additions & 1 deletion src/main/java/com/arangodb/ArangoDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -611,11 +611,12 @@ 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, custom, protocol,
connectionTtl);
connectionTtl, httpCookieSpec);

final Collection<Host> hostList = createHostList(max, connectionFactory);
final HostResolver hostResolver = createHostResolver(hostList, max, connectionFactory);
final HostHandler hostHandler = createHostHandler(hostResolver);

return new ArangoDBImpl(
new VstCommunicationSync.Builder(hostHandler).timeout(timeout).user(user).password(password)
.useSsl(useSsl).sslContext(sslContext).chunksize(chunksize).maxConnections(maxConnections)
Expand Down
75 changes: 24 additions & 51 deletions src/main/java/com/arangodb/internal/ArangoDBImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,10 @@
package com.arangodb.internal;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.arangodb.ArangoDB;
import com.arangodb.ArangoDBException;
Expand All @@ -42,7 +42,6 @@
import com.arangodb.internal.net.CommunicationProtocol;
import com.arangodb.internal.net.HostHandle;
import com.arangodb.internal.net.HostResolver;
import com.arangodb.internal.net.HostResolver.EndpointResolver;
import com.arangodb.internal.util.ArangoSerializationFactory;
import com.arangodb.internal.util.ArangoSerializationFactory.Serializer;
import com.arangodb.internal.velocystream.VstCommunicationSync;
Expand All @@ -52,10 +51,8 @@
import com.arangodb.model.UserUpdateOptions;
import com.arangodb.util.ArangoCursorInitializer;
import com.arangodb.util.ArangoSerialization;
import com.arangodb.velocypack.VPackSlice;
import com.arangodb.velocypack.exception.VPackException;
import com.arangodb.velocystream.Request;
import com.arangodb.velocystream.RequestType;
import com.arangodb.velocystream.Response;

/**
Expand All @@ -64,65 +61,41 @@
*
*/
public class ArangoDBImpl extends InternalArangoDB<ArangoExecutorSync> implements ArangoDB {

private static final Logger LOGGER = LoggerFactory.getLogger(ArangoDBImpl.class);

private ArangoCursorInitializer cursorInitializer;
private CommunicationProtocol cp;

public ArangoDBImpl(final VstCommunicationSync.Builder vstBuilder, final HttpCommunication.Builder httpBuilder,
final ArangoSerializationFactory util, final Protocol protocol, final HostResolver hostResolver,
final ArangoContext context) {
super(new ArangoExecutorSync(createProtocol(vstBuilder, httpBuilder, util.get(Serializer.INTERNAL), protocol),
util, new DocumentCache()), util, context);
cp = createProtocol(new VstCommunicationSync.Builder(vstBuilder).maxConnections(1),
new HttpCommunication.Builder(httpBuilder), util.get(Serializer.INTERNAL), protocol);
hostResolver.init(new EndpointResolver() {
@Override
public Collection<String> resolve(final boolean closeConnections) throws ArangoDBException {
Collection<String> response;
try {
response = executor.execute(new Request(ArangoRequestParam.SYSTEM, RequestType.GET, PATH_ENDPOINTS),
new ResponseDeserializer<Collection<String>>() {
@Override
public Collection<String> deserialize(final Response response) throws VPackException {
final VPackSlice field = response.getBody().get("endpoints");
Collection<String> endpoints;
if (field.isNone()) {
endpoints = Collections.<String> emptyList();
} else {
final Collection<Map<String, String>> tmp = util().deserialize(field,
Collection.class);
endpoints = new ArrayList<String>();
for (final Map<String, String> map : tmp) {
for (final String value : map.values()) {
endpoints.add(value);
}
}
}
return endpoints;
}
}, null);
} catch (final ArangoDBException e) {
final Integer responseCode = e.getResponseCode();
if (responseCode != null && responseCode == 403) {
response = Collections.<String> emptyList();
} else {
throw e;
}
} finally {
if (closeConnections) {
ArangoDBImpl.this.shutdown();
}
}
return response;
}
});

super(new ArangoExecutorSync(
createProtocol(vstBuilder, httpBuilder, util.get(Serializer.INTERNAL), protocol),
util,
new DocumentCache()),
util,
context);

cp = createProtocol(
new VstCommunicationSync.Builder(vstBuilder).maxConnections(1),
new HttpCommunication.Builder(httpBuilder),
util.get(Serializer.INTERNAL),
protocol);

hostResolver.init(this.executor(), util());

LOGGER.info("ArangoDB Client is ready to use");

}

private static CommunicationProtocol createProtocol(
final VstCommunicationSync.Builder vstBuilder,
final HttpCommunication.Builder httpBuilder,
final ArangoSerialization util,
final Protocol protocol) {

return (protocol == null || Protocol.VST == protocol) ? createVST(vstBuilder, util)
: createHTTP(httpBuilder, util);
}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/com/arangodb/internal/ArangoDefaults.java
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ private ArangoDefaults() {
public static final int MAX_CONNECTIONS_HTTP_DEFAULT = 20;
public static final Protocol DEFAULT_NETWORK_PROTOCOL = Protocol.VST;
public static final boolean DEFAULT_ACQUIRE_HOST_LIST = false;
public static final int DEFAULT_ACQUIRE_HOST_LIST_INTERVAL = 60 * 60 * 1000; // hour
public static final LoadBalancingStrategy DEFAULT_LOAD_BALANCING_STRATEGY = LoadBalancingStrategy.NONE;

}
2 changes: 1 addition & 1 deletion src/main/java/com/arangodb/internal/InternalArangoDB.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public abstract class InternalArangoDB<E extends ArangoExecutor> extends ArangoE
private static final String PATH_API_ADMIN_LOG = "/_admin/log";
private static final String PATH_API_ADMIN_LOG_LEVEL = "/_admin/log/level";
private static final String PATH_API_ROLE = "/_admin/server/role";
protected static final String PATH_ENDPOINTS = "/_api/cluster/endpoints";
private static final String PATH_ENDPOINTS = "/_api/cluster/endpoints";
private static final String PATH_API_USER = "/_api/user";

protected InternalArangoDB(final E executor, final ArangoSerializationFactory util, final ArangoContext context) {
Expand Down
31 changes: 27 additions & 4 deletions src/main/java/com/arangodb/internal/InternalArangoDBBuilder.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,14 @@
import com.arangodb.velocypack.VPack;
import com.arangodb.velocypack.VPackParser;


/**
* @author Mark Vollmary
*
*/
public abstract class InternalArangoDBBuilder {

private static final Logger LOGGER = LoggerFactory.getLogger(InternalArangoDBBuilder.class);
private static final Logger LOG = LoggerFactory.getLogger(InternalArangoDBBuilder.class);

private static final String PROPERTY_KEY_HOSTS = "arangodb.hosts";
private static final String PROPERTY_KEY_HOST = "arangodb.host";
Expand All @@ -70,10 +71,12 @@ public abstract class InternalArangoDBBuilder {
private static final String PROPERTY_KEY_USER = "arangodb.user";
private static final String PROPERTY_KEY_PASSWORD = "arangodb.password";
private static final String PROPERTY_KEY_USE_SSL = "arangodb.usessl";
private static final String PROPERTY_KEY_COOKIE_SPEC = "arangodb.httpCookieSpec";
private static final String PROPERTY_KEY_V_STREAM_CHUNK_CONTENT_SIZE = "arangodb.chunksize";
private static final String PROPERTY_KEY_MAX_CONNECTIONS = "arangodb.connections.max";
private static final String PROPERTY_KEY_CONNECTION_TTL = "arangodb.connections.ttl";
private static final String PROPERTY_KEY_ACQUIRE_HOST_LIST = "arangodb.acquireHostList";
private static final String PROPERTY_KEY_ACQUIRE_HOST_LIST_INTERVAL = "arangodb.acquireHostList.interval";
private static final String PROPERTY_KEY_LOAD_BALANCING_STRATEGY = "arangodb.loadBalancingStrategy";
private static final String DEFAULT_PROPERTY_FILE = "/arangodb.properties";

Expand All @@ -83,6 +86,7 @@ public abstract class InternalArangoDBBuilder {
protected String user;
protected String password;
protected Boolean useSsl;
protected String httpCookieSpec;
protected SSLContext sslContext;
protected Integer chunksize;
protected Integer maxConnections;
Expand All @@ -92,9 +96,12 @@ public abstract class InternalArangoDBBuilder {
protected ArangoSerializer serializer;
protected ArangoDeserializer deserializer;
protected Boolean acquireHostList;
protected Integer acquireHostListInterval;
protected LoadBalancingStrategy loadBalancingStrategy;
protected ArangoSerialization customSerializer;



public InternalArangoDBBuilder() {
super();
vpackBuilder = new VPack.Builder();
Expand Down Expand Up @@ -129,10 +136,12 @@ protected void loadProperties(final Properties properties) {
user = loadUser(properties, user);
password = loadPassword(properties, password);
useSsl = loadUseSsl(properties, useSsl);
httpCookieSpec = loadhttpCookieSpec(properties, useSsl);
chunksize = loadChunkSize(properties, chunksize);
maxConnections = loadMaxConnections(properties, maxConnections);
connectionTtl = loadConnectionTtl(properties, connectionTtl);
acquireHostList = loadAcquireHostList(properties, acquireHostList);
acquireHostListInterval = loadAcquireHostListInterval(properties, acquireHostListInterval);
loadBalancingStrategy = loadLoadBalancingStrategy(properties, loadBalancingStrategy);
}

Expand Down Expand Up @@ -195,17 +204,19 @@ protected void setSerializer(final ArangoSerialization serializer) {
protected HostResolver createHostResolver(final Collection<Host> hosts, final int maxConnections,final ConnectionFactory connectionFactory) {

if(acquireHostList) {
LOGGER.debug("acquireHostList -> Use ExtendedHostResolver");
return new ExtendedHostResolver(new ArrayList<Host>(hosts), maxConnections, connectionFactory);
LOG.debug("acquireHostList -> Use ExtendedHostResolver");
return new ExtendedHostResolver(new ArrayList<Host>(hosts), maxConnections, connectionFactory, acquireHostListInterval);
} else {
LOGGER.debug("Use SimpleHostResolver");
LOG.debug("Use SimpleHostResolver");
return new SimpleHostResolver(new ArrayList<Host>(hosts));
}

}

protected HostHandler createHostHandler(final HostResolver hostResolver) {

final HostHandler hostHandler;

if (loadBalancingStrategy != null) {
switch (loadBalancingStrategy) {
case ONE_RANDOM:
Expand All @@ -222,6 +233,9 @@ protected HostHandler createHostHandler(final HostResolver hostResolver) {
} else {
hostHandler = new FallbackHostHandler(hostResolver);
}

LOG.info("HostHandler is " + hostHandler.getClass().getSimpleName());

return new DirtyReadHostHandler(hostHandler, new RoundRobinHostHandler(hostResolver));
}

Expand Down Expand Up @@ -273,6 +287,10 @@ private static Boolean loadUseSsl(final Properties properties, final Boolean cur
return Boolean.parseBoolean(
getProperty(properties, PROPERTY_KEY_USE_SSL, currentValue, ArangoDefaults.DEFAULT_USE_SSL));
}

private static String loadhttpCookieSpec(final Properties properties, final Boolean currentValue) {
return getProperty(properties, PROPERTY_KEY_COOKIE_SPEC, currentValue, "");
}

private static Integer loadChunkSize(final Properties properties, final Integer currentValue) {
return Integer.parseInt(getProperty(properties, PROPERTY_KEY_V_STREAM_CHUNK_CONTENT_SIZE, currentValue,
Expand All @@ -295,6 +313,11 @@ private static Boolean loadAcquireHostList(final Properties properties, final Bo
ArangoDefaults.DEFAULT_ACQUIRE_HOST_LIST));
}

private static int loadAcquireHostListInterval(final Properties properties, final Integer currentValue) {
return Integer.parseInt(getProperty(properties, PROPERTY_KEY_ACQUIRE_HOST_LIST_INTERVAL, currentValue,
ArangoDefaults.DEFAULT_ACQUIRE_HOST_LIST_INTERVAL));
}

private static LoadBalancingStrategy loadLoadBalancingStrategy(
final Properties properties,
final LoadBalancingStrategy currentValue) {
Expand Down
15 changes: 13 additions & 2 deletions src/main/java/com/arangodb/internal/http/HttpConnection.java
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ public static class Builder {
private String password;
private ArangoSerialization util;
private Boolean useSsl;
private String httpCookieSpec;
private Protocol contentType;
private HostDescription host;
private Long ttl;
Expand All @@ -126,6 +127,11 @@ public Builder useSsl(final Boolean useSsl) {
this.useSsl = useSsl;
return this;
}

public Builder httpCookieSpec(String httpCookieSpec) {
this.httpCookieSpec = httpCookieSpec;
return this;
}

public Builder contentType(final Protocol contentType) {
this.contentType = contentType;
Expand Down Expand Up @@ -153,7 +159,7 @@ public Builder timeout(final Integer timeout) {
}

public HttpConnection build() {
return new HttpConnection(host, timeout, user, password, useSsl, sslContext, util, contentType, ttl);
return new HttpConnection(host, timeout, user, password, useSsl, sslContext, util, contentType, ttl, httpCookieSpec);
}
}

Expand All @@ -168,7 +174,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 ArangoSerialization util, final Protocol contentType,
final Long ttl) {
final Long ttl, final String httpCookieSpec) {
super();
this.host = host;
this.user = user;
Expand Down Expand Up @@ -196,6 +202,11 @@ private HttpConnection(final HostDescription host, final Integer timeout, final
requestConfig.setConnectionRequestTimeout(timeout);
requestConfig.setSocketTimeout(timeout);
}

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

final ConnectionKeepAliveStrategy keepAliveStrategy = new ConnectionKeepAliveStrategy() {
@Override
public long getKeepAliveDuration(final HttpResponse response, final HttpContext context) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ public class HttpConnectionFactory implements ConnectionFactory {

public HttpConnectionFactory(final Integer timeout, final String user, final String password, final Boolean useSsl,
final SSLContext sslContext, final ArangoSerialization util, final Protocol protocol,
final Long connectionTtl) {
final Long connectionTtl, String httpCookieSpec) {
super();
builder = new HttpConnection.Builder().timeout(timeout).user(user).password(password).useSsl(useSsl)
.sslContext(sslContext).serializationUtil(util).contentType(protocol).ttl(connectionTtl);
.sslContext(sslContext).serializationUtil(util).contentType(protocol).ttl(connectionTtl).httpCookieSpec(httpCookieSpec);

}

Expand Down
Loading