diff --git a/ChangeLog b/ChangeLog index ba2ed67..5ba3a05 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +v4.3.0 (2017-11-23) +--------------------------- +* added load balancing (ArangoDBAsync.Builder.loadBalancingStrategy()) +* added automatic acquiring of hosts for load balancing or as fallback (ArangoDBAsync.Builder.acquireHostList()) + v4.2.7 (2017-11-03) --------------------------- * added ArangoGraphAsync.exists() diff --git a/README.md b/README.md index e879a18..06145dc 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,8 @@ - + +
arangodb-java-driverArangoDBnetwork protocolJava version
4.2.x3.0.x, 3.1.x, 3.2.xVelocyStream1.8+
4.3.x3.0.0+VelocyStream1.8+
4.2.x3.0.0+VelocyStream1.8+
4.1.x3.1.xVelocyStream1.8+
@@ -24,18 +25,18 @@ To add the driver to your project with maven, add the following code to your pom.xml (please use a driver with a version number compatible to your ArangoDB server's version): -ArangoDB 3.2.X +ArangoDB 3.x.x ```XML com.arangodb arangodb-java-driver-async - 4.2.0 + 4.3.0 ``` -If you want to test with a snapshot version (e.g. 4.2.0-SNAPSHOT), add the staging repository of oss.sonatype.org to your pom.xml: +If you want to test with a snapshot version (e.g. 4.3.0-SNAPSHOT), add the staging repository of oss.sonatype.org to your pom.xml: ```XML @@ -58,8 +59,10 @@ mvn clean install -DskipTests=true -Dgpg.skip=true -Dmaven.javadoc.skip=true -B * [Network protocol](#network-protocol) * [SSL](#ssl) * [Connection pooling](#connection-pooling) + * [Fallback hosts](#fallback-hosts) + * [Load Balancing](#load-balancing) * [configure VelocyPack serialization](#configure-velocypack-serialization) - * [Java 8 types](#java-8-types) + * [Java 8 types](#java-8-types) * [Scala types](#scala-types) * [Joda-Time](#joda-time) * [custom serializer](#custom-serializer) @@ -114,7 +117,7 @@ Setup with default configuration, this automatically loads a properties file ara ``` Java // this instance is thread-safe - ArangoDB arangoDB = new ArangoDB.Builder().build(); + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().build(); ``` @@ -135,15 +138,15 @@ The driver is configured with some default values: To customize the configuration the parameters can be changed in the code... ``` Java - ArangoDB arangoDB = new ArangoDB.Builder().host("192.168.182.50", 8888).build(); - + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().host("192.168.182.50", 8888).build(); + ``` ... or with a custom properties file (my.properties) ``` Java InputStream in = MyClass.class.getResourceAsStream("my.properties"); - ArangoDB arangoDB = new ArangoDB.Builder().loadProperties(in).build(); - + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().loadProperties(in).build(); + ``` Example for arangodb.properties: @@ -159,9 +162,9 @@ Example for arangodb.properties: The drivers default used network protocol is the binary protocol VelocyStream which offers the best performance within the driver. To use HTTP, you have to set the configuration `useProtocol` to `Protocol.HTTP_JSON` for HTTP with Json content or `Protocol.HTTP_VPACK` for HTTP with [VelocyPack](https://github.com/arangodb/velocypack/blob/master/VelocyPack.md) content. ``` Java - - ArangoDB arangoDB = new ArangoDB.Builder().useProtocol(Protocol.VST).build(); - + + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().useProtocol(Protocol.VST).build(); + ``` **Note**: If you are using ArangoDB 3.0.x you have to set the protocol to `Protocol.HTTP_JSON` because it is the only one supported. @@ -171,9 +174,9 @@ The drivers default used network protocol is the binary protocol VelocyStream wh To use SSL, you have to set the configuration `useSsl` to `true` and set a `SSLContext`. (see [example code](../src/test/java/com/arangodb/example/ssl/SslExample.java)) ``` Java - - ArangoDB arangoDB = new ArangoDB.Builder().useSsl(true).sslContext(sc).build(); - + + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().useSsl(true).sslContext(sc).build(); + ``` ## Connection Pooling @@ -182,9 +185,57 @@ The driver supports connection pooling with a default of 1 maximum connections. ``` Java - ArangoDB arangoDB = new ArangoDB.Builder().maxConnections(8).build(); + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().maxConnections(8).build(); + +``` + +## Fallback hosts + +The driver supports configuring multiple hosts. The first host is used to open a connection to. When this host is not reachable the next host from the list is used. To use this feature just call the method `host(String, int)` multiple times. + +``` Java + + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().host("host1", 8529).host("host2", 8529).build(); ``` + +Since version 4.3 the driver support acquiring a list of known hosts in a cluster setup or a single server setup with followers. For this the driver has to be able to successfully open a connection to at least one host to get the list of hosts. Then it can use this list when fallback is needed. To use this feature just pass `true` to the method `acquireHostList(boolean)`. + +``` Java + + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().acquireHostList(true).build(); + +``` + +## Load Balancing + +Since version 4.3 the driver supports load balancing for cluster setups in two different ways. + +The first one is a round robin load balancing where the driver iterates through a list of known hosts and performs every request on a different host than the request before. This load balancing strategy only work when the maximun of connections is greater 1. + +``` Java + + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().loadBalancingStrategy(LoadBalancingStrategy.ROUND_ROBIN).maxConnections(8).build(); + +``` + +Just like the Fallback hosts feature the round robin load balancing strategy can use the `acquireHostList` configuration to acquire a list of all known hosts in the cluster. Do so only requires the manually configuration of only one host. Because this list is updated frequently it makes load balancing over the whole cluster very comfortable. + +``` Java + + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().loadBalancingStrategy(LoadBalancingStrategy.ROUND_ROBIN).maxConnections(8).acquireHostList(true).build(); + +``` + +The second load balancing strategy allows to pick a random host from the configured or acquired list of hosts and sticks to that host as long as the connection is open. This strategy is useful for an application - using the driver - which provides a session management where each session has its own instance of `ArangoDB` build from a global configured list of hosts. In this case it could be wanted that every sessions sticks with all its requests to the same host but not all sessions should use the same host. This load balancing strategy also works together with `acquireHostList`. + + +``` Java + + ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().loadBalancingStrategy(LoadBalancingStrategy.ONE_RANDOM).acquireHostList(true).build(); + +``` + ## configure VelocyPack serialization Since version `4.1.11` you can extend the VelocyPack serialization by registering additional `VPackModule`s on `ArangoDB.Builder`. @@ -211,8 +262,8 @@ Added support for: ``` ``` Java -ArangoDB arangoDB = new ArangoDB.Builder().registerModule(new VPackJdk8Module()).build(); -``` +ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().registerModule(new VPackJdk8Module()).build(); +``` ### Scala types @@ -233,7 +284,7 @@ Added support for: ``` Scala val arangoDB: ArangoDB = new ArangoDB.Builder().registerModule(new VPackScalaModule).build -``` +``` ### Joda-Time @@ -255,7 +306,7 @@ Added support for: ``` Java ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().registerModule(new VPackJodaModule()).build(); -``` +``` ## custom serializer ``` Java @@ -282,23 +333,23 @@ ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().registerModule(new VPackJod }); } }).build(); -``` +``` # Manipulating databases ## create database ``` Java - // create database + // create database arangoDB.createDatabase("myDatabase"); - + ``` ## drop database ``` Java - // drop database + // drop database arangoDB.db("myDatabase").drop(); - + ``` # Manipulating collections @@ -307,14 +358,14 @@ ArangoDBAsync arangoDB = new ArangoDBAsync.Builder().registerModule(new VPackJod ``` Java // create collection arangoDB.db("myDatabase").createCollection("myCollection", null); - + ``` ## drop collection ``` Java - // delete collection + // delete collection arangoDB.db("myDatabase").collection("myCollection").drop(); - + ``` ## truncate collection @@ -348,15 +399,15 @@ For the next examples we use a small object: /* * + getter and setter */ - - } + + } ``` ## insert document ``` Java MyObject myObject = new MyObject("Homer", 38); arangoDB.db("myDatabase").collection("myCollection").insertDocument(myObject); - + ``` When creating a document, the attributes of the object will be stored as key-value pair @@ -369,19 +420,19 @@ E.g. in the previous example the object was stored as follows: ## delete document ``` Java arangoDB.db("myDatabase").collection("myCollection").deleteDocument(myObject.getKey()); - + ``` ## update document ``` Java arangoDB.db("myDatabase").collection("myCollection").updateDocument(myObject.getKey(), myUpdatedObject); - + ``` ## replace document ``` Java arangoDB.db("myDatabase").collection("myCollection").replaceDocument(myObject.getKey(), myObject2); - + ``` ## read document as JavaBean @@ -390,7 +441,7 @@ E.g. in the previous example the object was stored as follows: document.getName(); document.getAge(); } - + ``` ## read document as VelocyPack @@ -399,26 +450,26 @@ E.g. in the previous example the object was stored as follows: document.get("name").getAsString(); document.get("age").getAsInt(); } - + ``` ## read document as Json ``` Java arangoDB.db("myDatabase").collection("myCollection").getDocument(myObject.getKey(), String.class).thenAccept(document -> { } - + ``` ## read document by key ``` Java arangoDB.db("myDatabase").collection("myCollection").getDocument("myKey", MyObject.class); - + ``` ## read document by id ``` Java arangoDB.db("myDatabase").getDocument("myCollection/myKey", MyObject.class); - + ``` # Multi Document operations @@ -430,7 +481,7 @@ E.g. in the previous example the object was stored as follows: documents.add(myObject2); documents.add(myObject3); arangoDB.db("myDatabase").collection("myCollection").insertDocuments(documents); - + ``` ## delete documents @@ -440,7 +491,7 @@ E.g. in the previous example the object was stored as follows: keys.add(myObject2.getKey()); keys.add(myObject3.getKey()); arangoDB.db("myDatabase").collection("myCollection").deleteDocuments(keys); - + ``` ## update documents @@ -450,7 +501,7 @@ E.g. in the previous example the object was stored as follows: documents.add(myObject2); documents.add(myObject3); arangoDB.db("myDatabase").collection("myCollection").updateDocuments(documents); - + ``` ## replace documents @@ -460,7 +511,7 @@ E.g. in the previous example the object was stored as follows: documents.add(myObject2); documents.add(myObject3); arangoDB.db("myDatabase").collection("myCollection").replaceDocuments(documents); - + ``` # AQL @@ -474,19 +525,19 @@ E.g. get all Simpsons aged 3 or older in ascending order: ``` Java arangoDB.createDatabase("myDatabase"); ArangoDatabaseAsync db = arangoDB.db("myDatabase"); - + db.createCollection("myCollection"); ArangoCollectionAsync collection = db.collection("myCollection"); - + collection.insertDocument(new MyObject("Homer", 38)).get(); collection.insertDocument(new MyObject("Marge", 36)).get(); collection.insertDocument(new MyObject("Bart", 10)).get(); collection.insertDocument(new MyObject("Lisa", 8)).get(); collection.insertDocument(new MyObject("Maggie", 2)).get(); - + Map bindVars = new HashMap<>(); bindVars.put("age", 3); - + db.query(query, bindVars, null, MyObject.class).thenAccept(cursor -> { cursor.forEachRemaining(obj -> { System.out.println(obj.getName()); @@ -500,7 +551,7 @@ or return the AQL result as VelocyPack: db.query(query, bindVars, null, VPackSlice.class).thenAccept(cursor -> { cursor.forEachRemaining(obj -> { System.out.println(obj.get("name").getAsString()); - }); + }); }); ``` @@ -522,19 +573,19 @@ A graph consists of vertices and edges (stored in collections). Which collection edgeDefinition.collection("myEdgeCollection"); // define a set of collections where an edge is going out... edgeDefinition.from("myCollection1", "myCollection2"); - - // repeat this for the collections where an edge is going into + + // repeat this for the collections where an edge is going into edgeDefinition.to("myCollection1", "myCollection3"); - + edgeDefinitions.add(edgeDefinition); - + // A graph can contain additional vertex collections, defined in the set of orphan collections GraphCreateOptions options = new GraphCreateOptions(); options.orphanCollections("myCollection4", "myCollection5"); - + // now it's possible to create a graph arangoDB.db("myDatabase").createGraph("myGraph", edgeDefinitions, options); - + ``` ## delete graph @@ -554,7 +605,7 @@ Vertices are stored in the vertex collections defined above. MyObject myObject2 = new MyObject("Marge", 36); arangoDB.db("myDatabase").graph("myGraph").vertexCollection("collection1").insertVertex(myObject1, null); arangoDB.db("myDatabase").graph("myGraph").vertexCollection("collection3").insertVertex(myObject2, null); - + ``` ## add edge @@ -563,8 +614,8 @@ Now an edge can be created to set a relation between vertices ``` Java arangoDB.db("myDatabase").graph("myGraph").edgeCollection("myEdgeCollection").insertEdge(myEdgeObject, null); - -``` + +``` # Foxx @@ -572,8 +623,8 @@ Now an edge can be created to set a relation between vertices ``` Java Request request = new Request("mydb", RequestType.GET, "/my/foxx/service") CompletableFuture response = arangoDB.executeAsync(request); - -``` + +``` # User management @@ -625,7 +676,7 @@ The driver can serialize/deserialize JavaBeans. They need at least a constructor super(); } - } + } ``` ## internal fields @@ -636,7 +687,7 @@ To use Arango-internal fields (like _id, _key, _rev, _from, _to) in your JavaBea @DocumentField(Type.KEY) private String key; - + private String name; private Gender gender; private int age; @@ -645,7 +696,7 @@ To use Arango-internal fields (like _id, _key, _rev, _from, _to) in your JavaBea super(); } - } + } ``` ## serialized fieldnames @@ -656,7 +707,7 @@ To use a different serialized name for a field, use the annotation `SerializedNa @SerializedName("title") private String name; - + private Gender gender; private int age; @@ -664,7 +715,7 @@ To use a different serialized name for a field, use the annotation `SerializedNa super(); } - } + } ``` ## ignore fields @@ -683,7 +734,7 @@ To ignore fields at serialization/deserialization, use the annotation `Expose` super(); } - } + } ``` ## custom serializer @@ -711,7 +762,7 @@ To ignore fields at serialization/deserialization, use the annotation `Expose` }); } }).build(); -``` +``` ## manually serialization To de-/serialize from and to VelocyPack before or after a database call, use the `ArangoUtil` from the method `util()` in `ArangoDB`, `ArangoDatabase`, `ArangoCollection`, `ArangoGraph`, `ArangoEdgeCollection`or `ArangoVertexCollection`. diff --git a/pom.xml b/pom.xml index a8e50f2..7f5f087 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.arangodb arangodb-java-driver-async - 4.2.8-SNAPSHOT + 4.3.0-SNAPSHOT 2016 jar diff --git a/src/main/java/com/arangodb/ArangoDBAsync.java b/src/main/java/com/arangodb/ArangoDBAsync.java index 38919a5..464432e 100644 --- a/src/main/java/com/arangodb/ArangoDBAsync.java +++ b/src/main/java/com/arangodb/ArangoDBAsync.java @@ -25,28 +25,39 @@ import java.lang.annotation.Annotation; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.List; +import java.util.Map; import java.util.Properties; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutionException; import javax.net.ssl.SSLContext; import com.arangodb.entity.ArangoDBVersion; +import com.arangodb.entity.LoadBalancingStrategy; import com.arangodb.entity.LogEntity; import com.arangodb.entity.LogLevelEntity; import com.arangodb.entity.Permissions; import com.arangodb.entity.ServerRole; import com.arangodb.entity.UserEntity; import com.arangodb.internal.ArangoDBConstants; +import com.arangodb.internal.ArangoExecutor.ResponseDeserializer; import com.arangodb.internal.ArangoExecutorAsync; import com.arangodb.internal.CollectionCache; import com.arangodb.internal.CollectionCache.DBAccess; -import com.arangodb.internal.CommunicationProtocol; -import com.arangodb.internal.DefaultHostHandler; import com.arangodb.internal.DocumentCache; import com.arangodb.internal.Host; -import com.arangodb.internal.HostHandler; import com.arangodb.internal.InternalArangoDB; +import com.arangodb.internal.net.CommunicationProtocol; +import com.arangodb.internal.net.ExtendedHostResolver; +import com.arangodb.internal.net.FallbackHostHandler; +import com.arangodb.internal.net.HostHandler; +import com.arangodb.internal.net.HostResolver; +import com.arangodb.internal.net.HostResolver.EndpointResolver; +import com.arangodb.internal.net.RandomHostHandler; +import com.arangodb.internal.net.RoundRobinHostHandler; +import com.arangodb.internal.net.SimpleHostResolver; import com.arangodb.internal.util.ArangoDeserializerImpl; import com.arangodb.internal.util.ArangoSerializerImpl; import com.arangodb.internal.util.ArangoUtilImpl; @@ -75,9 +86,12 @@ import com.arangodb.velocypack.VPackParser; import com.arangodb.velocypack.VPackParserModule; import com.arangodb.velocypack.VPackSerializer; +import com.arangodb.velocypack.VPackSlice; import com.arangodb.velocypack.ValueType; +import com.arangodb.velocypack.exception.VPackException; import com.arangodb.velocypack.module.jdk8.VPackJdk8Module; import com.arangodb.velocystream.Request; +import com.arangodb.velocystream.RequestType; import com.arangodb.velocystream.Response; /** @@ -101,6 +115,8 @@ public static class Builder { private final VPackParser.Builder vpackParserBuilder; private ArangoSerializer serializer; private ArangoDeserializer deserializer; + private Boolean acquireHostList; + private LoadBalancingStrategy loadBalancingStrategy; public Builder() { super(); @@ -129,6 +145,8 @@ public Builder loadProperties(final InputStream in) { useSsl = loadUseSsl(properties, useSsl); chunksize = loadChunkSize(properties, chunksize); maxConnections = loadMaxConnections(properties, maxConnections); + acquireHostList = loadAcquireHostList(properties, acquireHostList); + loadBalancingStrategy = loadLoadBalancingStrategy(properties, loadBalancingStrategy); } catch (final IOException e) { throw new ArangoDBException(e); } @@ -209,6 +227,16 @@ public Builder maxConnections(final Integer maxConnections) { return this; } + public Builder acquireHostList(final Boolean acquireHostList) { + this.acquireHostList = acquireHostList; + return this; + } + + public Builder loadBalancingStrategy(final LoadBalancingStrategy loadBalancingStrategy) { + this.loadBalancingStrategy = loadBalancingStrategy; + return this; + } + public Builder registerSerializer(final Class clazz, final VPackSerializer serializer) { vpackBuilder.registerSerializer(clazz, serializer); return this; @@ -343,9 +371,11 @@ public synchronized ArangoDBAsync build() { : new ArangoSerializerImpl(vpacker, vpackerNull, vpackParser); final ArangoDeserializer deserializerTemp = deserializer != null ? deserializer : new ArangoDeserializerImpl(vpackerNull, vpackParser); - final HostHandler hostHandler = new DefaultHostHandler(new ArrayList<>(hosts)); + + final HostResolver hostResolver = createHostResolver(); + final HostHandler hostHandler = createHostHandler(hostResolver); return new ArangoDBAsync(asyncBuilder(hostHandler), new ArangoUtilImpl(serializerTemp, deserializerTemp), - collectionCache, syncBuilder(hostHandler)); + collectionCache, syncBuilder(hostHandler), hostResolver); } private VstCommunicationAsync.Builder asyncBuilder(final HostHandler hostHandler) { @@ -358,12 +388,39 @@ private VstCommunicationSync.Builder syncBuilder(final HostHandler hostHandler) .useSsl(useSsl).sslContext(sslContext).chunksize(chunksize).maxConnections(maxConnections); } + private HostResolver createHostResolver() { + return acquireHostList != null && acquireHostList.booleanValue() + ? new ExtendedHostResolver(new ArrayList<>(hosts)) : new SimpleHostResolver(new ArrayList<>(hosts)); + } + + private HostHandler createHostHandler(final HostResolver hostResolver) { + final HostHandler hostHandler; + if (loadBalancingStrategy != null) { + switch (loadBalancingStrategy) { + case ONE_RANDOM: + hostHandler = new RandomHostHandler(hostResolver, new FallbackHostHandler(hostResolver)); + break; + case ROUND_ROBIN: + hostHandler = new RoundRobinHostHandler(hostResolver); + break; + case NONE: + default: + hostHandler = new FallbackHostHandler(hostResolver); + break; + } + } else { + hostHandler = new FallbackHostHandler(hostResolver); + } + return hostHandler; + } + } private final CommunicationProtocol cp; public ArangoDBAsync(final VstCommunicationAsync.Builder commBuilder, final ArangoSerialization util, - final CollectionCache collectionCache, final VstCommunicationSync.Builder syncbuilder) { + final CollectionCache collectionCache, final VstCommunicationSync.Builder syncbuilder, + final HostResolver hostResolver) { super(new ArangoExecutorAsync(commBuilder.build(util, collectionCache), util, new DocumentCache()), util); final VstCommunication cacheCom = syncbuilder.build(util, collectionCache); cp = new VstProtocol(cacheCom); @@ -373,6 +430,47 @@ public ArangoDatabase db(final String name) { return new ArangoDatabase(cp, util, executor.documentCache(), name); } }); + hostResolver.init(new EndpointResolver() { + @Override + public Collection resolve(final boolean closeConnections) throws ArangoDBException { + try { + return executor.execute( + new Request(ArangoDBConstants.SYSTEM, RequestType.GET, ArangoDBConstants.PATH_ENDPOINTS), + new ResponseDeserializer>() { + @Override + public Collection deserialize(final Response response) throws VPackException { + final VPackSlice field = response.getBody().get(ArangoDBConstants.ENDPOINTS); + Collection endpoints; + if (field.isNone()) { + endpoints = Collections. emptyList(); + } else { + final Collection> tmp = util().deserialize(field, + Collection.class); + endpoints = new ArrayList<>(); + for (final Map map : tmp) { + for (final String value : map.values()) { + endpoints.add(value); + } + } + } + return endpoints; + } + }, null).get(); + } catch (InterruptedException | ExecutionException e) { + throw new ArangoDBException(e); + // TODO + // if (e.getResponseCode() == 403) { + // response = Collections. emptyList(); + // } else { + // throw e; + // } + } finally { + if (closeConnections) { + ArangoDBAsync.this.shutdown(); + } + } + } + }); } @Override diff --git a/src/main/java/com/arangodb/ArangoDatabaseAsync.java b/src/main/java/com/arangodb/ArangoDatabaseAsync.java index 2dab263..06c097f 100644 --- a/src/main/java/com/arangodb/ArangoDatabaseAsync.java +++ b/src/main/java/com/arangodb/ArangoDatabaseAsync.java @@ -45,6 +45,7 @@ import com.arangodb.internal.CollectionCache; import com.arangodb.internal.DocumentCache; import com.arangodb.internal.InternalArangoDatabase; +import com.arangodb.internal.net.HostHandle; import com.arangodb.internal.velocystream.ConnectionAsync; import com.arangodb.internal.velocystream.VstCommunicationAsync; import com.arangodb.model.AqlFunctionCreateOptions; @@ -372,9 +373,9 @@ public CompletableFuture> cursor(final String cursorId, private ArangoCursorAsync createCursor(final CursorEntity result, final Class type) { return new ArangoCursorAsync<>(this, new ArangoCursorExecute() { @Override - public CursorEntity next(final String id) { + public CursorEntity next(final String id, final HostHandle hostHandle) { final CompletableFuture result = executor.execute(queryNextRequest(id), - CursorEntity.class); + CursorEntity.class, hostHandle); try { return result.get(); } catch (InterruptedException | ExecutionException e) { @@ -383,9 +384,9 @@ public CursorEntity next(final String id) { } @Override - public void close(final String id) { + public void close(final String id, final HostHandle hostHandle) { try { - executor.execute(queryCloseRequest(id), Void.class).get(); + executor.execute(queryCloseRequest(id), Void.class, hostHandle).get(); } catch (InterruptedException | ExecutionException e) { throw new ArangoDBException(e); } diff --git a/src/main/java/com/arangodb/internal/ArangoExecutorAsync.java b/src/main/java/com/arangodb/internal/ArangoExecutorAsync.java index e1a41ad..63424d0 100644 --- a/src/main/java/com/arangodb/internal/ArangoExecutorAsync.java +++ b/src/main/java/com/arangodb/internal/ArangoExecutorAsync.java @@ -20,10 +20,12 @@ package com.arangodb.internal; +import java.io.IOException; import java.lang.reflect.Type; import java.util.concurrent.CompletableFuture; import com.arangodb.ArangoDBException; +import com.arangodb.internal.net.HostHandle; import com.arangodb.internal.velocystream.VstCommunicationAsync; import com.arangodb.util.ArangoSerialization; import com.arangodb.velocypack.exception.VPackException; @@ -47,9 +49,20 @@ public CompletableFuture execute(final Request request, final Type type) return execute(request, (response) -> createResult(type, response)); } + public CompletableFuture execute(final Request request, final Type type, final HostHandle hostHandle) { + return execute(request, (response) -> createResult(type, response), hostHandle); + } + public CompletableFuture execute(final Request request, final ResponseDeserializer responseDeserializer) { + return execute(request, responseDeserializer, null); + } + + public CompletableFuture execute( + final Request request, + final ResponseDeserializer responseDeserializer, + final HostHandle hostHandle) { final CompletableFuture result = new CompletableFuture<>(); - communication.execute(request).whenComplete((response, ex) -> { + communication.execute(request, hostHandle).whenComplete((response, ex) -> { if (response != null) { try { result.complete(responseDeserializer.deserialize(response)); @@ -65,7 +78,7 @@ public CompletableFuture execute(final Request request, final ResponseDes return result; } - public void disconnect() { + public void disconnect() throws IOException { communication.disconnect(); } } diff --git a/src/main/java/com/arangodb/internal/velocystream/ConnectionAsync.java b/src/main/java/com/arangodb/internal/velocystream/ConnectionAsync.java index 59c4714..80609a0 100644 --- a/src/main/java/com/arangodb/internal/velocystream/ConnectionAsync.java +++ b/src/main/java/com/arangodb/internal/velocystream/ConnectionAsync.java @@ -27,32 +27,36 @@ import javax.net.ssl.SSLContext; -import com.arangodb.internal.HostHandler; +import com.arangodb.internal.net.HostHandler; import com.arangodb.internal.velocystream.internal.Chunk; -import com.arangodb.internal.velocystream.internal.Connection; import com.arangodb.internal.velocystream.internal.Message; import com.arangodb.internal.velocystream.internal.MessageStore; +import com.arangodb.internal.velocystream.internal.VstConnection; /** * @author Mark Vollmary * */ -public class ConnectionAsync extends Connection { +public class ConnectionAsync extends VstConnection { public static class Builder { - private final HostHandler hostHandler; private final MessageStore messageStore; + private HostHandler hostHandler; private Integer timeout; private Boolean useSsl; private SSLContext sslContext; - public Builder(final HostHandler hostHandler, final MessageStore messageStore) { + public Builder(final MessageStore messageStore) { super(); - this.hostHandler = hostHandler; this.messageStore = messageStore; } + public Builder hostHandler(final HostHandler hostHandler) { + this.hostHandler = hostHandler; + return this; + } + public Builder timeout(final Integer timeout) { this.timeout = timeout; return this; diff --git a/src/main/java/com/arangodb/internal/velocystream/VstCommunicationAsync.java b/src/main/java/com/arangodb/internal/velocystream/VstCommunicationAsync.java index 63fc752..71ff777 100644 --- a/src/main/java/com/arangodb/internal/velocystream/VstCommunicationAsync.java +++ b/src/main/java/com/arangodb/internal/velocystream/VstCommunicationAsync.java @@ -33,9 +33,11 @@ import com.arangodb.entity.ErrorEntity; import com.arangodb.internal.ArangoDBConstants; import com.arangodb.internal.CollectionCache; -import com.arangodb.internal.HostHandler; +import com.arangodb.internal.Host; +import com.arangodb.internal.net.ConnectionPool; +import com.arangodb.internal.net.DelHostHandler; +import com.arangodb.internal.net.HostHandler; import com.arangodb.internal.velocystream.internal.AuthenticationRequest; -import com.arangodb.internal.velocystream.internal.ConnectionPool; import com.arangodb.internal.velocystream.internal.Message; import com.arangodb.internal.velocystream.internal.MessageStore; import com.arangodb.util.ArangoSerialization; @@ -113,21 +115,21 @@ public VstCommunicationAsync build(final ArangoSerialization util, final Collect private VstCommunicationAsync(final HostHandler hostHandler, final Integer timeout, final String user, final String password, final Boolean useSsl, final SSLContext sslContext, final ArangoSerialization util, final CollectionCache collectionCache, final Integer chunksize, final Integer maxConnections) { - super(timeout, user, password, useSsl, sslContext, util, chunksize, - new ConnectionPool(maxConnections) { - private final ConnectionAsync.Builder builder = new ConnectionAsync.Builder(hostHandler, - new MessageStore()).timeout(timeout).useSsl(useSsl).sslContext(sslContext); - - @Override - public ConnectionAsync createConnection() { - return builder.build(); - } - }); + super(timeout, user, password, useSsl, sslContext, util, chunksize, new ConnectionPool( + maxConnections != null ? Math.max(1, maxConnections) : ArangoDBConstants.MAX_CONNECTIONS_VST_DEFAULT) { + private final ConnectionAsync.Builder builder = new ConnectionAsync.Builder(new MessageStore()) + .timeout(timeout).useSsl(useSsl).sslContext(sslContext); + + @Override + public ConnectionAsync createConnection(final Host host) { + return builder.hostHandler(new DelHostHandler(hostHandler, host)).build(); + } + }); this.collectionCache = collectionCache; } @Override - public CompletableFuture execute(final Request request, final ConnectionAsync connection) { + protected CompletableFuture execute(final Request request, final ConnectionAsync connection) { connect(connection); final CompletableFuture rfuture = new CompletableFuture<>(); try { diff --git a/src/test/java/com/arangodb/ArangoCollectionTest.java b/src/test/java/com/arangodb/ArangoCollectionTest.java index ead9edc..34bec70 100644 --- a/src/test/java/com/arangodb/ArangoCollectionTest.java +++ b/src/test/java/com/arangodb/ArangoCollectionTest.java @@ -1575,11 +1575,11 @@ public void importDocumentsJsonDetails() throws InterruptedException, ExecutionE @Test public void importDocumentsJsonOverwriteFalse() throws InterruptedException, ExecutionException { final ArangoCollectionAsync collection = db.collection(COLLECTION_NAME); - collection.insertDocument(new BaseDocument()); + collection.insertDocument(new BaseDocument()).get(); assertThat(collection.count().get().getCount(), is(1L)); final String values = "[{\"_key\":\"1\"},{\"_key\":\"2\"}]"; - collection.importDocuments(values, new DocumentImportOptions().overwrite(false)); + collection.importDocuments(values, new DocumentImportOptions().overwrite(false)).get(); assertThat(collection.count().get().getCount(), is(3L)); } diff --git a/src/test/resources/arangodb.properties b/src/test/resources/arangodb.properties index cd57805..5682618 100644 --- a/src/test/resources/arangodb.properties +++ b/src/test/resources/arangodb.properties @@ -1,2 +1 @@ arangodb.hosts=127.0.0.1:8529 -arangodb.user=root \ No newline at end of file