From ff73e1cbc232fe7e1cc6fe00e540a177d6bcb98d Mon Sep 17 00:00:00 2001 From: Mark Date: Wed, 3 Aug 2016 14:06:39 +0200 Subject: [PATCH] started new api --- .gitignore | 18 +- pom.xml | 254 ++++++ src/main/java/com/arangodb/ArangoDB.java | 68 ++ .../java/com/arangodb/ArangoException.java | 13 + .../com/arangodb/entity/CollectionEntity.java | 9 + .../com/arangodb/internal/Connection.java | 9 + .../java/com/arangodb/internal/Constants.java | 14 + .../com/arangodb/model/CollectionCreate.java | 37 + .../com/arangodb/model/CollectionDelete.java | 24 + src/main/java/com/arangodb/model/DB.java | 39 + .../java/com/arangodb/model/DBCollection.java | 45 + .../java/com/arangodb/model/DBCreate.java | 26 + .../java/com/arangodb/model/DBDelete.java | 26 + .../com/arangodb/model/DocumentCreate.java | 31 + .../com/arangodb/model/DocumentDelete.java | 29 + .../java/com/arangodb/model/DocumentRead.java | 32 + .../com/arangodb/model/DocumentReadAll.java | 23 + .../com/arangodb/model/DocumentUpdate.java | 32 + .../com/arangodb/model/ExecuteCallback.java | 11 + .../com/arangodb/model/ExecuteResult.java | 21 + .../java/com/arangodb/model/Executeable.java | 24 + .../java/com/arangodb/util/MapBuilder.java | 38 + .../arangodb/velocypack/ArrayIterator.java | 35 + .../arangodb/velocypack/ObjectIterator.java | 47 ++ .../arangodb/velocypack/SliceIterator.java | 38 + .../java/com/arangodb/velocypack/VPack.java | 544 ++++++++++++ .../velocypack/VPackAttributeTranslator.java | 19 + .../com/arangodb/velocypack/VPackBuilder.java | 787 ++++++++++++++++++ .../VPackDeserializationContext.java | 25 + .../velocypack/VPackDeserializer.java | 13 + .../velocypack/VPackInstanceCreator.java | 11 + .../velocypack/VPackKeyMapAdapter.java | 13 + .../com/arangodb/velocypack/VPackParser.java | 102 +++ .../velocypack/VPackSerializationContext.java | 18 + .../arangodb/velocypack/VPackSerializer.java | 14 + .../com/arangodb/velocypack/VPackSlice.java | 731 ++++++++++++++++ .../java/com/arangodb/velocypack/Value.java | 217 +++++ .../com/arangodb/velocypack/ValueType.java | 26 + .../velocypack/annotations/Expose.java | 20 + .../annotations/SerializedName.java | 18 + .../exception/VPackBuilderException.java | 21 + ...PackBuilderKeyAlreadyWrittenException.java | 13 + ...VPackBuilderNeedOpenCompoundException.java | 13 + .../VPackBuilderNeedOpenObjectException.java | 13 + ...VPackBuilderNumberOutOfRangeException.java | 15 + .../VPackBuilderUnexpectedValueException.java | 39 + .../velocypack/exception/VPackException.java | 21 + .../exception/VPackKeyTypeException.java | 13 + ...VPackNeedAttributeTranslatorException.java | 9 + .../exception/VPackParserException.java | 13 + .../exception/VPackValueTypeException.java | 27 + .../VPackAttributeTranslatorImpl.java | 87 ++ .../velocypack/internal/VPackCache.java | 155 ++++ .../internal/VPackDeserializers.java | 99 +++ .../internal/VPackInstanceCreators.java | 49 ++ .../internal/VPackKeyMapAdapters.java | 155 ++++ .../velocypack/internal/VPackOptionsImpl.java | 53 ++ .../velocypack/internal/VPackSerializers.java | 132 +++ .../velocypack/internal/util/BinaryUtil.java | 21 + .../velocypack/internal/util/DateUtil.java | 19 + .../velocypack/internal/util/NumberUtil.java | 83 ++ .../internal/util/ObjectArrayUtil.java | 74 ++ .../velocypack/internal/util/StringUtil.java | 17 + .../internal/util/ValueLengthUtil.java | 286 +++++++ .../internal/util/ValueTypeUtil.java | 285 +++++++ src/test/java/com/arangodb/BaseTest.java | 36 + 66 files changed, 5237 insertions(+), 12 deletions(-) create mode 100644 pom.xml create mode 100644 src/main/java/com/arangodb/ArangoDB.java create mode 100644 src/main/java/com/arangodb/ArangoException.java create mode 100644 src/main/java/com/arangodb/entity/CollectionEntity.java create mode 100644 src/main/java/com/arangodb/internal/Connection.java create mode 100644 src/main/java/com/arangodb/internal/Constants.java create mode 100644 src/main/java/com/arangodb/model/CollectionCreate.java create mode 100644 src/main/java/com/arangodb/model/CollectionDelete.java create mode 100644 src/main/java/com/arangodb/model/DB.java create mode 100644 src/main/java/com/arangodb/model/DBCollection.java create mode 100644 src/main/java/com/arangodb/model/DBCreate.java create mode 100644 src/main/java/com/arangodb/model/DBDelete.java create mode 100644 src/main/java/com/arangodb/model/DocumentCreate.java create mode 100644 src/main/java/com/arangodb/model/DocumentDelete.java create mode 100644 src/main/java/com/arangodb/model/DocumentRead.java create mode 100644 src/main/java/com/arangodb/model/DocumentReadAll.java create mode 100644 src/main/java/com/arangodb/model/DocumentUpdate.java create mode 100644 src/main/java/com/arangodb/model/ExecuteCallback.java create mode 100644 src/main/java/com/arangodb/model/ExecuteResult.java create mode 100644 src/main/java/com/arangodb/model/Executeable.java create mode 100644 src/main/java/com/arangodb/util/MapBuilder.java create mode 100644 src/main/java/com/arangodb/velocypack/ArrayIterator.java create mode 100644 src/main/java/com/arangodb/velocypack/ObjectIterator.java create mode 100644 src/main/java/com/arangodb/velocypack/SliceIterator.java create mode 100644 src/main/java/com/arangodb/velocypack/VPack.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackAttributeTranslator.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackBuilder.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackDeserializationContext.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackDeserializer.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackInstanceCreator.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackKeyMapAdapter.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackParser.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackSerializationContext.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackSerializer.java create mode 100644 src/main/java/com/arangodb/velocypack/VPackSlice.java create mode 100644 src/main/java/com/arangodb/velocypack/Value.java create mode 100644 src/main/java/com/arangodb/velocypack/ValueType.java create mode 100644 src/main/java/com/arangodb/velocypack/annotations/Expose.java create mode 100644 src/main/java/com/arangodb/velocypack/annotations/SerializedName.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackBuilderException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackBuilderKeyAlreadyWrittenException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackBuilderNeedOpenCompoundException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackBuilderNeedOpenObjectException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackBuilderNumberOutOfRangeException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackBuilderUnexpectedValueException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackKeyTypeException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackNeedAttributeTranslatorException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackParserException.java create mode 100644 src/main/java/com/arangodb/velocypack/exception/VPackValueTypeException.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/VPackAttributeTranslatorImpl.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/VPackCache.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/VPackDeserializers.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/VPackInstanceCreators.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/VPackKeyMapAdapters.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/VPackOptionsImpl.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/VPackSerializers.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/util/BinaryUtil.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/util/DateUtil.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/util/NumberUtil.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/util/ObjectArrayUtil.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/util/StringUtil.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/util/ValueLengthUtil.java create mode 100644 src/main/java/com/arangodb/velocypack/internal/util/ValueTypeUtil.java create mode 100644 src/test/java/com/arangodb/BaseTest.java diff --git a/.gitignore b/.gitignore index 32858aad3..fef573878 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,6 @@ -*.class - -# Mobile Tools for Java (J2ME) -.mtj.tmp/ - -# Package Files # -*.jar -*.war -*.ear - -# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml -hs_err_pid* +/.classpath +/.project +/.settings +/target +/.idea +/*.iml diff --git a/pom.xml b/pom.xml new file mode 100644 index 000000000..52e46447f --- /dev/null +++ b/pom.xml @@ -0,0 +1,254 @@ + + 4.0.0 + + com.arangodb + arangodb-java-driver + 3.1.0-SNAPSHOT + 2016 + jar + + arangodb-java-driver + ArangoDB Java Driver + http://maven.apache.org + + + + Apache License 2.0 + http://www.apache.org/licenses/LICENSE-2.0 + repo + + + + + UTF-8 + 1.7.13 + 1.1.3 + 1.3 + 4.12 + + + + + a-brandt + a-brandt + https://github.com/a-brandt + + + mpv1989 + Mark + https://github.com/mpv1989 + + + + + + ossrh + https://oss.sonatype.org/content/repositories/snapshots + + + ossrh + https://oss.sonatype.org/service/local/staging/deploy/maven2/ + + + + + + + + + + + + + + + + + + + org.sonatype.plugins + nexus-staging-maven-plugin + 1.6.5 + true + + ossrh + https://oss.sonatype.org/ + 84aff6e87e214c + false + + + + + org.apache.maven.plugins + maven-assembly-plugin + 2.4.1 + + + assembly + package + + single + + + + + + ${project.artifactId}-${project.version}-standalone + + false + false + + jar-with-dependencies + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.2 + + 1.8 + 1.8 + + + + + + org.apache.maven.plugins + maven-resources-plugin + 2.7 + + UTF-8 + + + + + org.apache.maven.plugins + maven-source-plugin + 2.4 + + + + jar + + + + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.9.1 + + + attach-javadocs + + jar + + + ${javadoc.opts} + + + + + + + + + + + + + + + + + + maven-deploy-plugin + 2.8.2 + + false + 10 + + + + + org.apache.maven.plugins + maven-gpg-plugin + 1.5 + + + sign-artifacts + verify + + sign + + + + + + + + + + + + org.slf4j + slf4j-api + + + ch.qos.logback + logback-classic + provided + + + junit + junit + test + + + org.hamcrest + hamcrest-all + test + + + + + + + org.slf4j + slf4j-api + ${slf4j-api.version} + + + ch.qos.logback + logback-classic + ${logback-classic.version} + + + junit + junit + ${junit.version} + + + org.hamcrest + hamcrest-all + ${hamcrest-all.version} + + + + + + https://github.com/arangodb/arangodb-java-driver2 + scm:git:git://github.com/arangodb/arangodb-java-driver2.git + scm:git:git://github.com/arangodb/arangodb-java-driver2.git + + + + ArangoDB GmbH + https://www.arangodb.com + + + diff --git a/src/main/java/com/arangodb/ArangoDB.java b/src/main/java/com/arangodb/ArangoDB.java new file mode 100644 index 000000000..55677b023 --- /dev/null +++ b/src/main/java/com/arangodb/ArangoDB.java @@ -0,0 +1,68 @@ +package com.arangodb; + +import java.util.Optional; + +import com.arangodb.internal.Constants; +import com.arangodb.model.DB; +import com.arangodb.model.DBCreate; +import com.arangodb.model.DBDelete; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class ArangoDB { + + public static class Builder { + + private Optional host = Optional.empty(); + private Optional port = Optional.empty(); + private Optional user = Optional.empty(); + private Optional password = Optional.empty(); + + public ArangoDB build() { + return new ArangoDB(this); + } + + public Builder host(final String url) { + this.host = Optional.ofNullable(url); + return this; + } + + public Builder port(final int port) { + this.port = Optional.of(port); + return this; + } + + public Builder user(final String user) { + this.user = Optional.ofNullable(user); + return this; + } + + public Builder password(final String password) { + this.password = Optional.ofNullable(password); + return this; + } + + } + + private ArangoDB(final Builder builder) { + } + + public DBCreate dbCreate(final String name) { + return new DBCreate(this, name); + } + + public DBDelete dbDelete(final String name) { + return new DBDelete(this, name); + } + + public DB db() { + return db(Constants.SYSTEM_COLLECTION); + } + + public DB db(final String name) { + return new DB(this, name); + } + +} diff --git a/src/main/java/com/arangodb/ArangoException.java b/src/main/java/com/arangodb/ArangoException.java new file mode 100644 index 000000000..fe0c11b0f --- /dev/null +++ b/src/main/java/com/arangodb/ArangoException.java @@ -0,0 +1,13 @@ +package com.arangodb; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class ArangoException extends Exception { + + public ArangoException(final Exception e) { + super(e); + } + +} diff --git a/src/main/java/com/arangodb/entity/CollectionEntity.java b/src/main/java/com/arangodb/entity/CollectionEntity.java new file mode 100644 index 000000000..e7de851b3 --- /dev/null +++ b/src/main/java/com/arangodb/entity/CollectionEntity.java @@ -0,0 +1,9 @@ +package com.arangodb.entity; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class CollectionEntity { + +} diff --git a/src/main/java/com/arangodb/internal/Connection.java b/src/main/java/com/arangodb/internal/Connection.java new file mode 100644 index 000000000..df1cf4294 --- /dev/null +++ b/src/main/java/com/arangodb/internal/Connection.java @@ -0,0 +1,9 @@ +package com.arangodb.internal; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class Connection { + +} diff --git a/src/main/java/com/arangodb/internal/Constants.java b/src/main/java/com/arangodb/internal/Constants.java new file mode 100644 index 000000000..106bbb20f --- /dev/null +++ b/src/main/java/com/arangodb/internal/Constants.java @@ -0,0 +1,14 @@ +package com.arangodb.internal; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class Constants { + + public static final String SYSTEM_COLLECTION = "_system"; + public static final String DEFAULT_HOST = "127.0.0.1"; + public static final int DEFAULT_PORT = 8529; + public static final String DEFAULT_PROPERTY_FILE = "/arangodb.properties"; + +} diff --git a/src/main/java/com/arangodb/model/CollectionCreate.java b/src/main/java/com/arangodb/model/CollectionCreate.java new file mode 100644 index 000000000..319014fbe --- /dev/null +++ b/src/main/java/com/arangodb/model/CollectionCreate.java @@ -0,0 +1,37 @@ +package com.arangodb.model; + +import java.util.Optional; +import java.util.concurrent.Future; + +import com.arangodb.entity.CollectionEntity; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class CollectionCreate implements Executeable { + + private final DB db; + private final String name; + private final Options options; + + public static class Options { + private Optional waitForSync = Optional.empty(); + + public Options waitForSync(final Boolean waitForSync) { + this.waitForSync = Optional.of(waitForSync); + return this; + } + } + + protected CollectionCreate(final DB db, final String name, final Options options) { + this.db = db; + this.name = name; + this.options = options; + } + + @Override + public Future execute(final ExecuteCallback callback) { + return null; + } +} diff --git a/src/main/java/com/arangodb/model/CollectionDelete.java b/src/main/java/com/arangodb/model/CollectionDelete.java new file mode 100644 index 000000000..9208e158e --- /dev/null +++ b/src/main/java/com/arangodb/model/CollectionDelete.java @@ -0,0 +1,24 @@ +package com.arangodb.model; + +import java.util.concurrent.Future; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class CollectionDelete implements Executeable { + + private final DB db; + private final String name; + + protected CollectionDelete(final DB db, final String name) { + this.db = db; + this.name = name; + } + + @Override + public Future execute(final ExecuteCallback callback) { + return null; + } + +} diff --git a/src/main/java/com/arangodb/model/DB.java b/src/main/java/com/arangodb/model/DB.java new file mode 100644 index 000000000..b6af33274 --- /dev/null +++ b/src/main/java/com/arangodb/model/DB.java @@ -0,0 +1,39 @@ +package com.arangodb.model; + +import com.arangodb.ArangoDB; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class DB { + + private final ArangoDB arangoDB; + private final String name; + + public DB(final ArangoDB arangoDB, final String name) { + this.arangoDB = arangoDB; + this.name = name; + } + + protected ArangoDB arangoDB() { + return arangoDB; + } + + protected String name() { + return name; + } + + public DBCollection collection(final String name) { + return new DBCollection(this, name); + } + + public CollectionCreate collectionCreate(final String name, final CollectionCreate.Options options) { + return new CollectionCreate(this, name, options); + } + + public CollectionDelete collectionDelete(final String name) { + return new CollectionDelete(this, name); + } + +} diff --git a/src/main/java/com/arangodb/model/DBCollection.java b/src/main/java/com/arangodb/model/DBCollection.java new file mode 100644 index 000000000..a37465d12 --- /dev/null +++ b/src/main/java/com/arangodb/model/DBCollection.java @@ -0,0 +1,45 @@ +package com.arangodb.model; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class DBCollection { + + private final DB db; + private final String name; + + protected DBCollection(final DB db, final String name) { + this.db = db; + this.name = name; + } + + protected DB db() { + return db; + } + + protected String name() { + return name; + } + + public DocumentCreate documentCreate(final T value, final DocumentCreate.Options options) { + return new DocumentCreate<>(this, value, options); + } + + public DocumentRead documentRead(final String key, final Class type, final DocumentRead.Options options) { + return new DocumentRead<>(this, key, type, options); + } + + public DocumentUpdate documentUpdate(final String key, final T value, final DocumentUpdate.Options options) { + return new DocumentUpdate<>(this, key, value, options); + } + + public DocumentDelete documentDelete(final String key, final DocumentDelete.Options options) { + return new DocumentDelete(this, key, options); + } + + public DocumentReadAll documentReadAll() { + return new DocumentReadAll(this); + } + +} diff --git a/src/main/java/com/arangodb/model/DBCreate.java b/src/main/java/com/arangodb/model/DBCreate.java new file mode 100644 index 000000000..59b4ecdce --- /dev/null +++ b/src/main/java/com/arangodb/model/DBCreate.java @@ -0,0 +1,26 @@ +package com.arangodb.model; + +import java.util.concurrent.Future; + +import com.arangodb.ArangoDB; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class DBCreate implements Executeable { + + private final ArangoDB arangoDB; + private final String name; + + public DBCreate(final ArangoDB arangoDB, final String name) { + this.arangoDB = arangoDB; + this.name = name; + } + + @Override + public Future execute(final ExecuteCallback callback) { + return null; + } + +} diff --git a/src/main/java/com/arangodb/model/DBDelete.java b/src/main/java/com/arangodb/model/DBDelete.java new file mode 100644 index 000000000..bc30b6198 --- /dev/null +++ b/src/main/java/com/arangodb/model/DBDelete.java @@ -0,0 +1,26 @@ +package com.arangodb.model; + +import java.util.concurrent.Future; + +import com.arangodb.ArangoDB; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class DBDelete implements Executeable { + + private final ArangoDB arangoDB; + private final String name; + + public DBDelete(final ArangoDB arangoDB, final String name) { + this.arangoDB = arangoDB; + this.name = name; + } + + @Override + public Future execute(final ExecuteCallback callback) { + return null; + } + +} diff --git a/src/main/java/com/arangodb/model/DocumentCreate.java b/src/main/java/com/arangodb/model/DocumentCreate.java new file mode 100644 index 000000000..dcbb37f73 --- /dev/null +++ b/src/main/java/com/arangodb/model/DocumentCreate.java @@ -0,0 +1,31 @@ +package com.arangodb.model; + +import java.util.concurrent.Future; + +/** + * @author Mark - mark at arangodb.com + * @param + * + */ +public class DocumentCreate implements Executeable { + + private final DBCollection dbCollection; + private final T value; + private final Options options; + + public static class Options { + + } + + protected DocumentCreate(final DBCollection dbCollection, final T value, final Options options) { + this.dbCollection = dbCollection; + this.value = value; + this.options = options; + } + + @Override + public Future execute(final ExecuteCallback callback) { + return null; + } + +} diff --git a/src/main/java/com/arangodb/model/DocumentDelete.java b/src/main/java/com/arangodb/model/DocumentDelete.java new file mode 100644 index 000000000..04558c47a --- /dev/null +++ b/src/main/java/com/arangodb/model/DocumentDelete.java @@ -0,0 +1,29 @@ +package com.arangodb.model; + +import java.util.concurrent.Future; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class DocumentDelete implements Executeable { + + private final DBCollection dbCollection; + private final String key; + private final Options options; + + public static class Options { + + } + + protected DocumentDelete(final DBCollection dbCollection, final String key, final Options options) { + this.dbCollection = dbCollection; + this.key = key; + this.options = options; + } + + @Override + public Future execute(final ExecuteCallback callback) { + return null; + } +} diff --git a/src/main/java/com/arangodb/model/DocumentRead.java b/src/main/java/com/arangodb/model/DocumentRead.java new file mode 100644 index 000000000..fe9096856 --- /dev/null +++ b/src/main/java/com/arangodb/model/DocumentRead.java @@ -0,0 +1,32 @@ +package com.arangodb.model; + +import java.util.concurrent.Future; + +/** + * @author Mark - mark at arangodb.com + * @param + * + */ +public class DocumentRead implements Executeable { + + private final DBCollection dbCollection; + private final String key; + private final Class type; + private final Options options; + + public static class Options { + + } + + public DocumentRead(final DBCollection dbCollection, final String key, final Class type, final Options options) { + this.dbCollection = dbCollection; + this.key = key; + this.type = type; + this.options = options; + } + + @Override + public Future execute(final ExecuteCallback callback) { + return null; + } +} diff --git a/src/main/java/com/arangodb/model/DocumentReadAll.java b/src/main/java/com/arangodb/model/DocumentReadAll.java new file mode 100644 index 000000000..1ce165c21 --- /dev/null +++ b/src/main/java/com/arangodb/model/DocumentReadAll.java @@ -0,0 +1,23 @@ +package com.arangodb.model; + +import java.util.Collection; +import java.util.concurrent.Future; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class DocumentReadAll implements Executeable> { + + private final DBCollection dbCollection; + + protected DocumentReadAll(final DBCollection dbCollection) { + this.dbCollection = dbCollection; + } + + @Override + public Future> execute(final ExecuteCallback> callback) { + return null; + } + +} diff --git a/src/main/java/com/arangodb/model/DocumentUpdate.java b/src/main/java/com/arangodb/model/DocumentUpdate.java new file mode 100644 index 000000000..b9c2f742a --- /dev/null +++ b/src/main/java/com/arangodb/model/DocumentUpdate.java @@ -0,0 +1,32 @@ +package com.arangodb.model; + +import java.util.concurrent.Future; + +/** + * @author Mark - mark at arangodb.com + * @param + * + */ +public class DocumentUpdate implements Executeable { + + private final DBCollection dbCollection; + private final String key; + private final T value; + private final Options options; + + public static class Options { + + } + + protected DocumentUpdate(final DBCollection dbCollection, final String key, final T value, final Options options) { + this.dbCollection = dbCollection; + this.key = key; + this.value = value; + this.options = options; + } + + @Override + public Future execute(final ExecuteCallback callback) { + return null; + } +} diff --git a/src/main/java/com/arangodb/model/ExecuteCallback.java b/src/main/java/com/arangodb/model/ExecuteCallback.java new file mode 100644 index 000000000..f86e09a2b --- /dev/null +++ b/src/main/java/com/arangodb/model/ExecuteCallback.java @@ -0,0 +1,11 @@ +package com.arangodb.model; + +/** + * @author Mark - mark at arangodb.com + * + */ +public interface ExecuteCallback { + + void process(ExecuteResult result); + +} diff --git a/src/main/java/com/arangodb/model/ExecuteResult.java b/src/main/java/com/arangodb/model/ExecuteResult.java new file mode 100644 index 000000000..84673c464 --- /dev/null +++ b/src/main/java/com/arangodb/model/ExecuteResult.java @@ -0,0 +1,21 @@ +package com.arangodb.model; + +import java.util.Optional; + +import com.arangodb.ArangoException; + +/** + * @author Mark - mark at arangodb.com + * + */ +public interface ExecuteResult { + + default boolean isSuccess() { + return getResult().isPresent(); + } + + Optional getException(); + + Optional getResult(); + +} diff --git a/src/main/java/com/arangodb/model/Executeable.java b/src/main/java/com/arangodb/model/Executeable.java new file mode 100644 index 000000000..1a5e53e9c --- /dev/null +++ b/src/main/java/com/arangodb/model/Executeable.java @@ -0,0 +1,24 @@ +package com.arangodb.model; + +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; + +import com.arangodb.ArangoException; + +/** + * @author Mark - mark at arangodb.com + * + */ +public interface Executeable { + + default T execute() throws ArangoException { + try { + return execute(null).get(); + } catch (InterruptedException | ExecutionException e) { + throw new ArangoException(e); + } + } + + Future execute(final ExecuteCallback callback); + +} diff --git a/src/main/java/com/arangodb/util/MapBuilder.java b/src/main/java/com/arangodb/util/MapBuilder.java new file mode 100644 index 000000000..084f797a4 --- /dev/null +++ b/src/main/java/com/arangodb/util/MapBuilder.java @@ -0,0 +1,38 @@ +package com.arangodb.util; + +import java.util.LinkedHashMap; +import java.util.Map; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class MapBuilder { + + private final boolean ignoreValue; + private final LinkedHashMap map; + + public MapBuilder() { + this(true); + } + + public MapBuilder(final boolean ignoreValue) { + this.ignoreValue = ignoreValue; + map = new LinkedHashMap<>(); + } + + public MapBuilder put(final String key, final Object value) { + return put(key, value, false); + } + + public MapBuilder put(final String key, final Object value, final boolean toString) { + if (!this.ignoreValue || (key != null && value != null)) { + map.put(key, toString ? value.toString() : value); + } + return this; + } + + public Map get() { + return map; + } +} diff --git a/src/main/java/com/arangodb/velocypack/ArrayIterator.java b/src/main/java/com/arangodb/velocypack/ArrayIterator.java new file mode 100644 index 000000000..2137b2bbd --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/ArrayIterator.java @@ -0,0 +1,35 @@ +package com.arangodb.velocypack; + +import java.util.NoSuchElementException; + +import com.arangodb.velocypack.exception.VPackValueTypeException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class ArrayIterator extends SliceIterator { + + /** + * @param slice + * @throws VPackValueTypeException + */ + public ArrayIterator(final VPackSlice slice) throws VPackValueTypeException { + super(slice); + if (!slice.isArray()) { + throw new VPackValueTypeException(ValueType.ARRAY); + } + } + + @Override + public VPackSlice next() { + final VPackSlice next; + if (hasNext()) { + next = slice.get((int) position++); + } else { + throw new NoSuchElementException(); + } + return next; + } + +} diff --git a/src/main/java/com/arangodb/velocypack/ObjectIterator.java b/src/main/java/com/arangodb/velocypack/ObjectIterator.java new file mode 100644 index 000000000..9bdda2665 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/ObjectIterator.java @@ -0,0 +1,47 @@ +package com.arangodb.velocypack; + +import java.util.NoSuchElementException; + +import com.arangodb.velocypack.exception.VPackValueTypeException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class ObjectIterator extends SliceIterator { + + /** + * @param slice + * @throws VPackValueTypeException + */ + public ObjectIterator(final VPackSlice slice) throws VPackValueTypeException { + super(slice); + if (!slice.isObject()) { + throw new VPackValueTypeException(ValueType.OBJECT); + } + if (size > 0) { + final byte head = slice.head(); + if (head == 0x14) { + current = slice.keyAt(0).getStart(); + } else { + current = slice.getStart() + slice.findDataOffset(); + } + } + } + + @Override + public VPackSlice next() { + if (position++ > 0) { + if (position <= size && current != 0) { + // skip over key + current += getCurrent().getByteSize(); + // skip over value + current += getCurrent().getByteSize(); + } else { + throw new NoSuchElementException(); + } + } + return getCurrent(); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/SliceIterator.java b/src/main/java/com/arangodb/velocypack/SliceIterator.java new file mode 100644 index 000000000..e3d573483 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/SliceIterator.java @@ -0,0 +1,38 @@ +package com.arangodb.velocypack; + +import java.util.Iterator; + +import com.arangodb.velocypack.exception.VPackValueTypeException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public abstract class SliceIterator implements Iterator { + + protected final VPackSlice slice; + protected final long size; + protected long position; + protected long current; + + protected SliceIterator(final VPackSlice slice) throws VPackValueTypeException { + super(); + this.slice = slice; + size = slice.getLength(); + position = 0; + } + + @Override + public boolean hasNext() { + return position < size; + } + + protected VPackSlice getCurrent() { + return new VPackSlice(slice.getVpack(), (int) current); + } + + @Override + public void remove() { + throw new UnsupportedOperationException(); + } +} diff --git a/src/main/java/com/arangodb/velocypack/VPack.java b/src/main/java/com/arangodb/velocypack/VPack.java new file mode 100644 index 000000000..b27feac3f --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPack.java @@ -0,0 +1,544 @@ +package com.arangodb.velocypack; + +import java.lang.reflect.Array; +import java.lang.reflect.InvocationTargetException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +import com.arangodb.velocypack.VPackBuilder.BuilderOptions; +import com.arangodb.velocypack.exception.VPackException; +import com.arangodb.velocypack.exception.VPackParserException; +import com.arangodb.velocypack.internal.VPackCache; +import com.arangodb.velocypack.internal.VPackCache.FieldInfo; +import com.arangodb.velocypack.internal.VPackDeserializers; +import com.arangodb.velocypack.internal.VPackInstanceCreators; +import com.arangodb.velocypack.internal.VPackKeyMapAdapters; +import com.arangodb.velocypack.internal.VPackOptionsImpl; +import com.arangodb.velocypack.internal.VPackSerializers; + +/** + * @author Mark - mark@arangodb.com + * + */ +@SuppressWarnings({ "unchecked", "rawtypes" }) +public class VPack { + + public static interface VPackOptions extends BuilderOptions { + boolean isSerializeNullValues(); + + void setSerializeNullValues(boolean serializeNullValues); + } + + private static final String ATTR_KEY = "key"; + private static final String ATTR_VALUE = "value"; + + private final Map, VPackSerializer> serializers; + private final Map, VPackDeserializer> deserializers; + private final Map, VPackInstanceCreator> instanceCreators; + private final Map, VPackKeyMapAdapter> keyMapAdapters; + private final VPackOptions options; + + private final VPackCache cache; + private final VPackSerializationContext serializationContext; + private final VPackDeserializationContext deserializationContext; + + public VPack() { + this(new VPackOptionsImpl()); + } + + public VPack(final VPackOptions options) { + super(); + this.options = options; + serializers = new HashMap, VPackSerializer>(); + deserializers = new HashMap, VPackDeserializer>(); + instanceCreators = new HashMap, VPackInstanceCreator>(); + keyMapAdapters = new HashMap, VPackKeyMapAdapter>(); + cache = new VPackCache(); + serializationContext = new VPackSerializationContext() { + @Override + public void serialize(final VPackBuilder builder, final String attribute, final Object entity) + throws VPackParserException { + VPack.this.serialize(attribute, entity, builder, new HashMap()); + } + + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Map entity, + final Class keyType) throws VPackParserException { + VPack.this.serialize(attribute, entity, keyType, builder, new HashMap()); + } + + }; + deserializationContext = new VPackDeserializationContext() { + @Override + public T deserialize(final VPackSlice vpack, final Class type) throws VPackParserException { + return VPack.this.deserialize(vpack, type); + } + + @Override + public , C> T deserialize( + final VPackSlice vpack, + final Class type, + final Class contentType) throws VPackParserException { + return VPack.this.deserialize(vpack, type, contentType); + } + + @Override + public , K, C> T deserialize( + final VPackSlice vpack, + final Class type, + final Class keyType, + final Class contentType) throws VPackParserException { + return VPack.this.deserialize(vpack, type, keyType, contentType); + } + }; + instanceCreators.put(Collection.class, VPackInstanceCreators.COLLECTION); + instanceCreators.put(List.class, VPackInstanceCreators.LIST); + instanceCreators.put(Set.class, VPackInstanceCreators.SET); + instanceCreators.put(Map.class, VPackInstanceCreators.MAP); + + serializers.put(String.class, VPackSerializers.STRING); + serializers.put(Boolean.class, VPackSerializers.BOOLEAN); + serializers.put(boolean.class, VPackSerializers.BOOLEAN); + serializers.put(Integer.class, VPackSerializers.INTEGER); + serializers.put(int.class, VPackSerializers.INTEGER); + serializers.put(Long.class, VPackSerializers.LONG); + serializers.put(long.class, VPackSerializers.LONG); + serializers.put(Short.class, VPackSerializers.SHORT); + serializers.put(short.class, VPackSerializers.SHORT); + serializers.put(Double.class, VPackSerializers.DOUBLE); + serializers.put(double.class, VPackSerializers.DOUBLE); + serializers.put(Float.class, VPackSerializers.FLOAT); + serializers.put(float.class, VPackSerializers.FLOAT); + serializers.put(BigInteger.class, VPackSerializers.BIG_INTEGER); + serializers.put(BigDecimal.class, VPackSerializers.BIG_DECIMAL); + serializers.put(Number.class, VPackSerializers.NUMBER); + serializers.put(Character.class, VPackSerializers.CHARACTER); + serializers.put(char.class, VPackSerializers.CHARACTER); + + deserializers.put(String.class, VPackDeserializers.STRING); + deserializers.put(Boolean.class, VPackDeserializers.BOOLEAN); + deserializers.put(boolean.class, VPackDeserializers.BOOLEAN); + deserializers.put(Integer.class, VPackDeserializers.INTEGER); + deserializers.put(int.class, VPackDeserializers.INTEGER); + deserializers.put(Long.class, VPackDeserializers.LONG); + deserializers.put(long.class, VPackDeserializers.LONG); + deserializers.put(Short.class, VPackDeserializers.SHORT); + deserializers.put(short.class, VPackDeserializers.SHORT); + deserializers.put(Double.class, VPackDeserializers.DOUBLE); + deserializers.put(double.class, VPackDeserializers.DOUBLE); + deserializers.put(Float.class, VPackDeserializers.FLOAT); + deserializers.put(float.class, VPackDeserializers.FLOAT); + deserializers.put(BigInteger.class, VPackDeserializers.BIG_INTEGER); + deserializers.put(BigDecimal.class, VPackDeserializers.BIG_DECIMAL); + deserializers.put(Number.class, VPackDeserializers.NUMBER); + deserializers.put(Character.class, VPackDeserializers.CHARACTER); + deserializers.put(char.class, VPackDeserializers.CHARACTER); + + keyMapAdapters.put(String.class, VPackKeyMapAdapters.STRING); + keyMapAdapters.put(Boolean.class, VPackKeyMapAdapters.BOOLEAN); + keyMapAdapters.put(Integer.class, VPackKeyMapAdapters.INTEGER); + keyMapAdapters.put(Long.class, VPackKeyMapAdapters.LONG); + keyMapAdapters.put(Short.class, VPackKeyMapAdapters.SHORT); + keyMapAdapters.put(Double.class, VPackKeyMapAdapters.DOUBLE); + keyMapAdapters.put(Float.class, VPackKeyMapAdapters.FLOAT); + keyMapAdapters.put(BigInteger.class, VPackKeyMapAdapters.BIG_INTEGER); + keyMapAdapters.put(BigDecimal.class, VPackKeyMapAdapters.BIG_DECIMAL); + keyMapAdapters.put(Number.class, VPackKeyMapAdapters.NUMBER); + keyMapAdapters.put(Character.class, VPackKeyMapAdapters.CHARACTER); + } + + public VPackOptions getOptions() { + return options; + } + + public VPack registerSerializer(final Class clazz, final VPackSerializer serializer) { + serializers.put(clazz, serializer); + return this; + } + + public VPack registerDeserializer(final Class clazz, final VPackDeserializer deserializer) { + deserializers.put(clazz, deserializer); + return this; + } + + public VPack regitserInstanceCreator(final Class clazz, final VPackInstanceCreator creator) { + instanceCreators.put(clazz, creator); + return this; + } + + public T deserialize(final VPackSlice vpack, final Class type) throws VPackParserException { + final T entity; + try { + entity = (T) getValue(vpack, type, null); + } catch (final Exception e) { + throw new VPackParserException(e); + } + return entity; + } + + public , C> T deserialize( + final VPackSlice vpack, + final Class type, + final Class contentType) throws VPackParserException { + final T entity; + try { + entity = (T) deserializeCollection(vpack, type, contentType); + } catch (final Exception e) { + throw new VPackParserException(e); + } + return entity; + } + + public , K, C> T deserialize( + final VPackSlice vpack, + final Class type, + final Class keyType, + final Class contentType) throws VPackParserException { + final T entity; + try { + entity = (T) deserializeMap(vpack, type, keyType, contentType); + } catch (final Exception e) { + throw new VPackParserException(e); + } + return entity; + } + + private T deserializeObject(final VPackSlice vpack, final Class type) throws InstantiationException, + IllegalAccessException, NoSuchMethodException, InvocationTargetException, VPackException { + final T entity; + final VPackDeserializer deserializer = deserializers.get(type); + if (deserializer != null) { + entity = ((VPackDeserializer) deserializer).deserialize(vpack, deserializationContext); + } else { + entity = createInstance(type); + deserializeFields(entity, vpack); + } + return entity; + } + + private T createInstance(final Class type) throws InstantiationException, IllegalAccessException { + final T entity; + final VPackInstanceCreator creator = instanceCreators.get(type); + if (creator != null) { + entity = (T) creator.createInstance(); + } else { + entity = type.newInstance(); + } + return entity; + } + + private void deserializeFields(final Object entity, final VPackSlice vpack) throws NoSuchMethodException, + IllegalAccessException, InvocationTargetException, InstantiationException, VPackException { + final Map fields = cache.getFields(entity.getClass()); + for (final Iterator iterator = vpack.iterator(); iterator.hasNext();) { + final VPackSlice attr = iterator.next(); + final FieldInfo fieldInfo = fields.get(attr.makeKey().getAsString()); + if (fieldInfo != null && fieldInfo.isDeserialize()) { + deserializeField(attr, entity, fieldInfo); + } + } + } + + private void deserializeField(final VPackSlice vpack, final Object entity, final FieldInfo fieldInfo) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, + VPackException { + final VPackSlice attr = new VPackSlice(vpack.getVpack(), vpack.getStart() + vpack.getByteSize()); + if (!attr.isNone()) { + final Object value = getValue(attr, fieldInfo.getType(), fieldInfo); + fieldInfo.set(entity, value); + } + } + + private Object getValue(final VPackSlice vpack, final Class type, final FieldInfo fieldInfo) + throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, + VPackException { + final Object value; + if (vpack.isNull()) { + value = null; + } else { + final VPackDeserializer deserializer = deserializers.get(type); + if (deserializer != null) { + value = ((VPackDeserializer) deserializer).deserialize(vpack, deserializationContext); + } else if (type.isArray()) { + value = deserializeArray(vpack, type, fieldInfo); + } else if (type.isEnum()) { + value = Enum.valueOf((Class) type, vpack.getAsString()); + } else if (Collection.class.isAssignableFrom(type)) { + value = deserializeCollection(vpack, type, fieldInfo.getParameterizedTypes()[0]); + } else if (Map.class.isAssignableFrom(type)) { + final Class[] parameterizedTypes = fieldInfo.getParameterizedTypes(); + value = deserializeMap(vpack, type, parameterizedTypes[0], parameterizedTypes[1]); + } else { + value = deserializeObject(vpack, type); + } + } + return value; + } + + private Object deserializeArray(final VPackSlice vpack, final Class type, final FieldInfo fieldInfo) + throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, + VPackException { + final int length = (int) vpack.getLength(); + final Class componentType = fieldInfo != null ? fieldInfo.getParameterizedTypes()[0] + : type.getComponentType(); + final Object value = Array.newInstance(componentType, length); + for (int i = 0; i < length; i++) { + Array.set(value, i, getValue(vpack.get(i), componentType, null)); + } + return value; + } + + private Object deserializeCollection(final VPackSlice vpack, final Class type, final Class contentType) + throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, + VPackException { + final Collection value = (Collection) createInstance(type); + final long length = vpack.getLength(); + if (length > 0) { + final Class componentType = contentType; + for (int i = 0; i < length; i++) { + value.add(getValue(vpack.get(i), componentType, null)); + } + } + return value; + } + + private Object deserializeMap( + final VPackSlice vpack, + final Class type, + final Class keyType, + final Class valueType) throws InstantiationException, IllegalAccessException, NoSuchMethodException, + InvocationTargetException, VPackException { + final int length = (int) vpack.getLength(); + final Map value = (Map) createInstance(type); + if (length > 0) { + final VPackKeyMapAdapter keyMapAdapter = getKeyMapAdapter(keyType); + if (keyMapAdapter != null) { + for (final Iterator iterator = vpack.iterator(); iterator.hasNext();) { + final VPackSlice key = iterator.next(); + final VPackSlice valueAt = new VPackSlice(key.getVpack(), key.getStart() + key.getByteSize()); + value.put(keyMapAdapter.deserialize(key.makeKey().getAsString()), + getValue(valueAt, valueType, null)); + } + } else { + for (int i = 0; i < vpack.getLength(); i++) { + final VPackSlice entry = vpack.get(i); + final Object mapKey = getValue(entry.get(ATTR_KEY), keyType, null); + final Object mapValue = getValue(entry.get(ATTR_VALUE), valueType, null); + value.put(mapKey, mapValue); + } + } + } + return value; + } + + public VPackSlice serialize(final Object entity) throws VPackParserException { + return serialize(entity, new HashMap()); + } + + public VPackSlice serialize(final Object entity, final Map additionalFields) + throws VPackParserException { + final VPackBuilder builder = new VPackBuilder(options); + serialize(null, entity, builder, new HashMap(additionalFields)); + return builder.slice(); + } + + private void serialize( + final String name, + final Object entity, + final VPackBuilder builder, + final Map additionalFields) throws VPackParserException { + try { + addValue(name, entity.getClass(), entity, builder, null, additionalFields); + } catch (final Exception e) { + throw new VPackParserException(e); + } + } + + public VPackSlice serialize(final Map entity, final Class keyType) throws VPackParserException { + final VPackBuilder builder = new VPackBuilder(options); + serialize(null, entity, keyType, builder, new HashMap()); + return builder.slice(); + } + + private void serialize( + final String name, + final Map entity, + final Class keyType, + final VPackBuilder builder, + final Map additionalFields) throws VPackParserException { + try { + serializeMap(name, entity, builder, keyType, additionalFields); + } catch (final Exception e) { + throw new VPackParserException(e); + } + } + + private void serializeObject( + final String name, + final Object entity, + final VPackBuilder builder, + final Map additionalFields) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, VPackException { + + final VPackSerializer serializer = serializers.get(entity.getClass()); + if (serializer != null) { + ((VPackSerializer) serializer).serialize(builder, name, entity, serializationContext); + } else { + builder.add(name, new Value(ValueType.OBJECT)); + serializeFields(entity, builder, additionalFields); + if (!additionalFields.isEmpty()) { + additionalFields.clear(); + builder.close(true); + } else { + builder.close(false); + } + } + } + + private void serializeFields( + final Object entity, + final VPackBuilder builder, + final Map additionalFields) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, VPackException { + final Map fields = cache.getFields(entity.getClass()); + for (final FieldInfo fieldInfo : fields.values()) { + if (fieldInfo.isSerialize()) { + serializeField(entity, builder, fieldInfo, additionalFields); + } + } + for (final Entry entry : additionalFields.entrySet()) { + final String key = entry.getKey(); + if (!fields.containsKey(key)) { + final Object value = entry.getValue(); + addValue(key, value != null ? value.getClass() : null, value, builder, null, additionalFields); + } + } + } + + private void serializeField( + final Object entity, + final VPackBuilder builder, + final FieldInfo fieldInfo, + final Map additionalFields) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, VPackException { + + final String fieldName = fieldInfo.getFieldName(); + final Class type = fieldInfo.getType(); + final Object value = fieldInfo.get(entity); + addValue(fieldName, type, value, builder, fieldInfo, additionalFields); + } + + private void addValue( + final String name, + final Class type, + final Object value, + final VPackBuilder builder, + final FieldInfo fieldInfo, + final Map additionalFields) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, VPackException { + + if (value == null) { + if (options.isSerializeNullValues()) { + builder.add(name, new Value(ValueType.NULL)); + } + } else { + final VPackSerializer serializer = serializers.get(type); + if (serializer != null) { + ((VPackSerializer) serializer).serialize(builder, name, value, serializationContext); + } else if (type.isArray()) { + serializeArray(name, value, builder, additionalFields); + } else if (type.isEnum()) { + builder.add(name, new Value(Enum.class.cast(value).name())); + } else if (Iterable.class.isAssignableFrom(type)) { + serializeIterable(name, value, builder, additionalFields); + } else if (Map.class.isAssignableFrom(type)) { + serializeMap(name, value, builder, fieldInfo.getParameterizedTypes()[0], additionalFields); + } else { + serializeObject(name, value, builder, additionalFields); + } + } + } + + private void serializeArray( + final String name, + final Object value, + final VPackBuilder builder, + final Map additionalFields) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, VPackException { + builder.add(name, new Value(ValueType.ARRAY)); + for (int i = 0; i < Array.getLength(value); i++) { + final Object element = Array.get(value, i); + addValue(null, element.getClass(), element, builder, null, additionalFields); + } + builder.close(); + } + + private void serializeIterable( + final String name, + final Object value, + final VPackBuilder builder, + final Map additionalFields) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, VPackException { + builder.add(name, new Value(ValueType.ARRAY)); + for (final Iterator iterator = Iterable.class.cast(value).iterator(); iterator.hasNext();) { + final Object element = iterator.next(); + addValue(null, element.getClass(), element, builder, null, additionalFields); + } + builder.close(); + } + + private void serializeMap( + final String name, + final Object value, + final VPackBuilder builder, + final Class keyType, + final Map additionalFields) + throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, VPackException { + final Map map = Map.class.cast(value); + if (map.size() > 0) { + final VPackKeyMapAdapter keyMapAdapter = getKeyMapAdapter(keyType); + if (keyMapAdapter != null) { + builder.add(name, new Value(ValueType.OBJECT)); + final Set> entrySet = map.entrySet(); + for (final Entry entry : entrySet) { + addValue(keyMapAdapter.serialize(entry.getKey()), entry.getValue().getClass(), entry.getValue(), + builder, null, additionalFields); + } + builder.close(); + } else { + builder.add(name, new Value(ValueType.ARRAY)); + final Set> entrySet = map.entrySet(); + for (final Entry entry : entrySet) { + builder.add(null, new Value(ValueType.OBJECT)); + addValue(ATTR_KEY, entry.getKey().getClass(), entry.getKey(), builder, null, additionalFields); + addValue(ATTR_VALUE, entry.getValue().getClass(), entry.getValue(), builder, null, + additionalFields); + builder.close(); + } + builder.close(); + } + } else { + builder.add(name, new Value(ValueType.OBJECT)); + builder.close(); + } + } + + private VPackKeyMapAdapter getKeyMapAdapter(final Class type) { + VPackKeyMapAdapter adapter = keyMapAdapters.get(type); + if (adapter == null && Enum.class.isAssignableFrom(type)) { + adapter = VPackKeyMapAdapters.createEnumAdapter(type); + } + return (VPackKeyMapAdapter) adapter; + } + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackAttributeTranslator.java b/src/main/java/com/arangodb/velocypack/VPackAttributeTranslator.java new file mode 100644 index 000000000..06194a1f7 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackAttributeTranslator.java @@ -0,0 +1,19 @@ +package com.arangodb.velocypack; + +import com.arangodb.velocypack.exception.VPackException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public interface VPackAttributeTranslator { + + void add(String attribute, int key) throws VPackException; + + void seal() throws VPackException; + + VPackSlice translate(String attribute); + + VPackSlice translate(int key); + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackBuilder.java b/src/main/java/com/arangodb/velocypack/VPackBuilder.java new file mode 100644 index 000000000..d59370b45 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackBuilder.java @@ -0,0 +1,787 @@ +package com.arangodb.velocypack; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.arangodb.velocypack.exception.VPackBuilderException; +import com.arangodb.velocypack.exception.VPackBuilderKeyAlreadyWrittenException; +import com.arangodb.velocypack.exception.VPackBuilderNeedOpenCompoundException; +import com.arangodb.velocypack.exception.VPackBuilderNeedOpenObjectException; +import com.arangodb.velocypack.exception.VPackBuilderNumberOutOfRangeException; +import com.arangodb.velocypack.exception.VPackBuilderUnexpectedValueException; +import com.arangodb.velocypack.exception.VPackKeyTypeException; +import com.arangodb.velocypack.exception.VPackNeedAttributeTranslatorException; +import com.arangodb.velocypack.internal.VPackOptionsImpl; +import com.arangodb.velocypack.internal.util.NumberUtil; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackBuilder { + + public static interface BuilderOptions { + boolean isBuildUnindexedArrays(); + + void setBuildUnindexedArrays(boolean buildUnindexedArrays); + + boolean isBuildUnindexedObjects(); + + void setBuildUnindexedObjects(boolean buildUnindexedObjects); + } + + private static final int DOUBLE_BYTES = 8; + private static final int LONG_BYTES = 8; + private static final int INT_BYTES = 4; + private static final int SHORT_BYTES = 2; + + private byte[] buffer; // Here we collect the result + private int size; + private final List stack; // Start positions of open + // objects/arrays + private final Map> index; // Indices for starts + // of + // subindex + private boolean keyWritten; // indicates that in the current object the key + // has been written but the value not yet + private final BuilderOptions options; + + public VPackBuilder() { + this(new VPackOptionsImpl()); + } + + public VPackBuilder(final BuilderOptions options) { + super(); + this.options = options; + size = 0; + buffer = new byte[10]; + stack = new ArrayList(); + index = new HashMap>(); + } + + public BuilderOptions getOptions() { + return options; + } + + private void add(final byte b) { + ensureCapacity(size + 1); + buffer[size++] = b; + } + + private void remove(final int index) { + final int numMoved = size - index - 1; + if (numMoved > 0) { + System.arraycopy(buffer, index + 1, buffer, index, numMoved); + } + buffer[--size] = 0; + } + + private void ensureCapacity(final int minCapacity) { + final int oldCapacity = buffer.length; + if (minCapacity > oldCapacity) { + final byte[] oldData = buffer; + int newCapacity = (oldCapacity * 3) / 2 + 1; + if (newCapacity < minCapacity) { + newCapacity = minCapacity; + } + buffer = Arrays.copyOf(oldData, newCapacity); + } + } + + public VPackBuilder add(final Value sub) throws VPackBuilderException { + addInternal(sub); + return this; + } + + public VPackBuilder add(final String attribute, final Value sub) throws VPackBuilderException { + if (attribute != null) { + addInternal(attribute, sub); + } else { + addInternal(sub); + } + return this; + } + + private void addInternal(final Value sub) throws VPackBuilderException { + boolean haveReported = false; + if (!stack.isEmpty() && !keyWritten) { + reportAdd(); + haveReported = true; + } + try { + set(sub); + } catch (final VPackBuilderException e) { + // clean up in case of an exception + if (haveReported) { + cleanupAdd(); + } + throw e; + } + } + + private void addInternal(final String attribute, final Value sub) throws VPackBuilderException { + boolean haveReported = false; + if (!stack.isEmpty()) { + final byte head = head(); + if (head != 0x0b && head != 0x14) { + throw new VPackBuilderNeedOpenObjectException(); + } + if (keyWritten) { + throw new VPackBuilderKeyAlreadyWrittenException(); + } + reportAdd(); + haveReported = true; + } + try { + if (VPackSlice.attributeTranslator != null) { + final VPackSlice translate = VPackSlice.attributeTranslator.translate(attribute); + if (translate != null) { + final byte[] value = translate.getValue(); + for (int i = 0; i < value.length; i++) { + add(value[i]); + } + keyWritten = true; + set(sub); + return; + } + // otherwise fall through to regular behavior + } + set(new Value(attribute)); + keyWritten = true; + set(sub); + } catch (final VPackBuilderException e) { + // clean up in case of an exception + if (haveReported) { + cleanupAdd(); + } + throw e; + } finally { + keyWritten = false; + } + } + + private void set(final Value item) throws VPackBuilderException { + final Class clazz = item.getClazz(); + switch (item.getType()) { + case NULL: + appendNull(); + break; + case BOOL: + checkClass(clazz, ValueType.BOOL, Boolean.class); + appendBoolean(item.getBoolean()); + break; + case DOUBLE: + final double d; + if (clazz == Double.class) { + d = item.getDouble(); + } else if (clazz == BigDecimal.class) { + d = item.getBigDecimal().doubleValue(); + } else if (clazz == Float.class) { + d = item.getFloat().doubleValue(); + } else { + throw new VPackBuilderUnexpectedValueException(ValueType.DOUBLE, Double.class, BigDecimal.class, + Float.class); + } + appendDouble(d); + break; + case SMALLINT: + final long vSmallInt; + if (clazz == Long.class) { + vSmallInt = item.getLong(); + } else if (clazz == Integer.class) { + vSmallInt = item.getInteger(); + } else if (clazz == BigInteger.class) { + vSmallInt = item.getBigInteger().longValue(); + } else if (clazz == Short.class) { + vSmallInt = item.getShort(); + } else { + throw new VPackBuilderUnexpectedValueException(ValueType.SMALLINT, Long.class, Integer.class, + BigInteger.class); + } + if (vSmallInt < -6 || vSmallInt > 9) { + throw new VPackBuilderNumberOutOfRangeException(ValueType.SMALLINT); + } + appendSmallInt(vSmallInt); + break; + case INT: + if (clazz == Long.class) { + appendLong(item.getLong()); + } else if (clazz == Integer.class) { + appendInt(item.getInteger()); + } else if (clazz == BigInteger.class) { + appendLong(item.getBigInteger().longValue()); + } else if (clazz == Short.class) { + appendShort(item.getShort()); + } else { + throw new VPackBuilderUnexpectedValueException(ValueType.INT, Long.class, Integer.class, + BigInteger.class, Short.class); + } + break; + case UINT: + final BigInteger vUInt; + if (clazz == Long.class) { + vUInt = BigInteger.valueOf(item.getLong()); + } else if (clazz == Integer.class) { + vUInt = BigInteger.valueOf(item.getInteger()); + } else if (clazz == BigInteger.class) { + vUInt = item.getBigInteger(); + } else { + throw new VPackBuilderUnexpectedValueException(ValueType.UINT, Long.class, Integer.class, + BigInteger.class); + } + if (-1 == vUInt.compareTo(BigInteger.ZERO)) { + throw new VPackBuilderUnexpectedValueException(ValueType.UINT, "non-negative", Long.class, + Integer.class, BigInteger.class); + } + appendUInt(vUInt); + break; + case UTC_DATE: + checkClass(clazz, ValueType.UTC_DATE, Date.class); + appendUTCDate(item.getDate()); + break; + case STRING: + final String string; + if (clazz == String.class) { + string = item.getString(); + } else if (clazz == Character.class) { + string = String.valueOf(item.getCharacter()); + } else { + throw new VPackBuilderUnexpectedValueException(ValueType.STRING, String.class, Character.class); + } + appendString(string); + break; + case ARRAY: + addArray(item.isUnindexed()); + break; + case OBJECT: + addObject(item.isUnindexed()); + break; + case BINARY: + add((byte) 0xc3); + final byte[] binary = item.getBinary(); + append(binary.length, INT_BYTES); + ensureCapacity(size + binary.length); + System.arraycopy(binary, 0, buffer, size, binary.length); + size += binary.length; + break; + default: + break; + } + } + + private void checkClass(final Class clazz, final ValueType type, final Class expectedClass) + throws VPackBuilderUnexpectedValueException { + if (expectedClass != clazz) { + throw new VPackBuilderUnexpectedValueException(type, clazz); + } + } + + private void appendNull() { + add((byte) 0x18); + } + + private void appendBoolean(final boolean value) { + if (value) { + add((byte) 0x1a); + } else { + add((byte) 0x19); + } + } + + private void appendDouble(final double value) { + add((byte) 0x1b); + append(value); + } + + private void append(final double value) { + append(Double.doubleToRawLongBits(value), DOUBLE_BYTES); + } + + private void appendSmallInt(final long value) { + if (value >= 0) { + add((byte) (value + 0x30)); + } else { + add((byte) (value + 0x40)); + } + } + + private void appendLong(final long value) { + add((byte) 0x27); + append(value, LONG_BYTES); + } + + private void appendInt(final int value) { + add((byte) 0x23); + append(value, INT_BYTES); + } + + private void appendShort(final short value) { + add((byte) 0x21); + append(value, SHORT_BYTES); + } + + private void appendUInt(final BigInteger value) { + add((byte) 0x2f); + append(value, LONG_BYTES); + } + + private void append(final long value, final int length) { + final long l = value; + for (int i = 0; i < length; i++) { + add((byte) (l >> (length - i - 1 << 3))); + } + } + + private void appendReversed(final long value, final int length) { + final long l = value; + for (int i = length - 1; i >= 0; i--) { + add((byte) (l >> (length - i - 1 << 3))); + } + } + + private void append(final BigInteger value, final int length) { + final BigInteger l = value; + for (int i = 0; i < length; ++i) { + add(l.shiftRight(length - i - 1 << 3).byteValue()); + } + } + + private void appendUTCDate(final Date value) { + add((byte) 0x1c); + append(value.getTime(), LONG_BYTES); + } + + private void appendString(final String value) throws VPackBuilderException { + final int length = value.length(); + if (length <= 126) { + // short string + add((byte) (0x40 + length)); + } else { + // long string + add((byte) 0xbf); + appendLength(length); + } + try { + append(value); + } catch (final UnsupportedEncodingException e) { + throw new VPackBuilderException(e); + } + } + + private void append(final String value) throws UnsupportedEncodingException { + final byte[] bytes = value.getBytes("UTF-8"); + for (final byte b : bytes) { + add(b); + } + } + + private void addArray(final boolean unindexed) { + addCompoundValue((byte) (unindexed ? 0x13 : 0x06)); + } + + private void addObject(final boolean unindexed) { + addCompoundValue((byte) (unindexed ? 0x14 : 0x0b)); + } + + private void addCompoundValue(final byte head) { + // an Array or Object is started: + stack.add(size); + index.put(stack.size() - 1, new ArrayList()); + add(head); + for (int i = 0; i < 8; i++) { + // Will be filled later with bytelength and nr subs + add((byte) 0x00); + } + } + + private void appendLength(final long length) { + appendReversed(length, LONG_BYTES); + } + + private void reportAdd() { + final Collection depth = index.get(stack.size() - 1); + depth.add(size - stack.get(stack.size() - 1)); + } + + private void cleanupAdd() { + final List depth = index.get(stack.size() - 1); + depth.remove(depth.size() - 1); + } + + public VPackBuilder close() + throws VPackBuilderNeedOpenCompoundException, VPackKeyTypeException, VPackNeedAttributeTranslatorException { + return close(true); + } + + protected VPackBuilder close(final boolean sort) + throws VPackBuilderNeedOpenCompoundException, VPackKeyTypeException, VPackNeedAttributeTranslatorException { + if (isClosed()) { + throw new VPackBuilderNeedOpenCompoundException(); + } + final byte head = head(); + final boolean isArray = head == 0x06 || head == 0x13; + final List in = index.get(stack.size() - 1); + final int tos = stack.get(stack.size() - 1); + if (in.isEmpty()) { + return closeEmptyArrayOrObject(tos, isArray); + } + if (head == 0x13 || head == 0x14 || (head == 0x06 && options.isBuildUnindexedArrays()) + || head == 0x0b && (options.isBuildUnindexedObjects() || in.size() == 1)) { + if (closeCompactArrayOrObject(tos, isArray, in)) { + return this; + } + // This might fall through, if closeCompactArrayOrObject gave up! + } + if (isArray) { + return closeArray(tos, in); + } + // fix head byte in case a compact Array / Object was originally + // requested + buffer[tos] = (byte) 0x0b; + + // First determine byte length and its format: + final int offsetSize; + // can be 1, 2, 4 or 8 for the byte width of the offsets, + // the byte length and the number of subvalues: + if ((size - 1 - tos) + in.size() - 6 <= 0xff) { + // We have so far used _pos - tos bytes, including the reserved 8 + // bytes for byte length and number of subvalues. In the 1-byte + // number + // case we would win back 6 bytes but would need one byte per + // subvalue + // for the index table + offsetSize = 1; + } else if ((size - 1 - tos) + 2 * in.size() <= 0xffff) { + offsetSize = 2; + } else if (((size - 1 - tos) / 2) + 4 * in.size() / 2 <= Integer.MAX_VALUE/* 0xffffffffu */) { + offsetSize = 4; + } else { + offsetSize = 8; + } + // Maybe we need to move down data + if (offsetSize == 1) { + final int targetPos = 3; + if ((size - 1) > (tos + 9)) { + for (int i = tos + targetPos; i < tos + 9; i++) { + remove(tos + targetPos); + } + } + final int diff = 9 - targetPos; + final int n = in.size(); + for (int i = 0; i < n; i++) { + in.set(i, in.get(i) - diff); + } + } + // One could move down things in the offsetSize == 2 case as well, + // since we only need 4 bytes in the beginning. However, saving these + // 4 bytes has been sacrificed on the Altar of Performance. + + // Now build the table: + if (sort && in.size() >= 2) { + // Object + sortObjectIndex(tos, in); + } + // final int tableBase = size; + for (int i = 0; i < in.size(); i++) { + long x = in.get(i); + for (int j = 0; j < offsetSize; j++) { + add(/* tableBase + offsetSize * i + j, */ (byte) (x & 0xff)); + x >>= 8; + } + } + // Finally fix the byte width in the type byte: + if (offsetSize > 1) { + if (offsetSize == 2) { + buffer[tos] = (byte) (buffer[tos] + 1); + } else if (offsetSize == 4) { + buffer[tos] = (byte) (buffer[tos] + 2); + } else { // offsetSize == 8 + buffer[tos] = (byte) (buffer[tos] + 3); + appendLength(in.size()); + } + } + // Fix the byte length in the beginning + long x = size - tos; + for (int i = 1; i <= offsetSize; i++) { + buffer[tos + i] = (byte) (x & 0xff); + x >>= 8; + } + // set the number of items in the beginning + if (offsetSize < 8) { + x = in.size(); + for (int i = offsetSize + 1; i <= 2 * offsetSize; i++) { + buffer[tos + i] = (byte) (x & 0xff); + x >>= 8; + } + } + stack.remove(stack.size() - 1); + return this; + } + + private VPackBuilder closeEmptyArrayOrObject(final int tos, final boolean isArray) { + // empty Array or Object + buffer[tos] = (byte) (isArray ? 0x01 : 0x0a); + // no bytelength and number subvalues needed + for (int i = 1; i <= 8; i++) { + remove(tos + 1); + } + stack.remove(stack.size() - 1); + return this; + } + + private boolean closeCompactArrayOrObject(final int tos, final boolean isArray, final List in) { + // use the compact Array / Object format + final long nLen = NumberUtil.getVariableValueLength(in.size()); + long byteSize = size - (tos + 8) + nLen; + long bLen = NumberUtil.getVariableValueLength(byteSize); + byteSize += bLen; + if (NumberUtil.getVariableValueLength(byteSize) != bLen) { + byteSize += 1; + bLen += 1; + } + if (bLen < 9) { + // can only use compact notation if total byte length is at most + // 8 bytes long + buffer[tos] = (byte) (isArray ? 0x13 : 0x14); + final int targetPos = (int) (1 + bLen); + if (size - 1 > (tos + 9)) { + for (int i = tos + targetPos; i < tos + 9; i++) { + remove(tos + targetPos); + } + } + // store byte length + storeVariableValueLength(tos, byteSize, false); + // need additional memory for storing the number of values + if (nLen > 8 - bLen) { + ensureCapacity((int) (size + nLen)); + } + // store number of values + storeVariableValueLength((int) (tos + byteSize), in.size(), true); + size += nLen; + stack.remove(stack.size() - 1); + return true; + } + return false; + } + + private void storeVariableValueLength(final int offset, final long value, final boolean reverse) { + int i = offset; + long val = value; + if (reverse) { + while (val >= 0x80) { + buffer[--i] = (byte) ((byte) (val & 0x7f) | (byte) 0x80); + val >>= 7; + } + buffer[--i] = (byte) (val & 0x7f); + } else { + while (val >= 0x80) { + buffer[++i] = (byte) ((byte) (val & 0x7f) | (byte) 0x80); + val >>= 7; + } + buffer[++i] = (byte) (val & 0x7f); + } + } + + private VPackBuilder closeArray(final int tos, final List in) { + // fix head byte in case a compact Array was originally + // requested + buffer[tos] = (byte) 0x06; + + boolean needIndexTable = true; + boolean needNrSubs = true; + final int n = in.size(); + if (n == 1) { + needIndexTable = false; + needNrSubs = false; + } else if ((size - tos) - in.get(0) == n * (in.get(1) - in.get(0))) { + // In this case it could be that all entries have the same length + // and we do not need an offset table at all: + boolean noTable = true; + final int subLen = in.get(1) - in.get(0); + if ((size - tos) - in.get(n - 1) != subLen) { + noTable = false; + } else { + for (int i = 1; i < n - 1; i++) { + if (in.get(i + 1) - in.get(i) != subLen) { + noTable = false; + break; + } + } + } + if (noTable) { + needIndexTable = false; + needNrSubs = false; + } + } + + // First determine byte length and its format: + final int offsetSize; + // can be 1, 2, 4 or 8 for the byte width of the offsets, + // the byte length and the number of subvalues: + if ((size - 1 - tos) + (needIndexTable ? n : 0) - (needNrSubs ? 6 : 7) <= 0xff) { + // We have so far used _pos - tos bytes, including the reserved 8 + // bytes for byte length and number of subvalues. In the 1-byte + // number + // case we would win back 6 bytes but would need one byte per + // subvalue + // for the index table + offsetSize = 1; + } else if ((size - 1 - tos) + (needIndexTable ? 2 * n : 0) <= 0xffff) { + offsetSize = 2; + } else if (((size - 1 - tos) / 2) + ((needIndexTable ? 4 * n : 0) / 2) <= Integer.MAX_VALUE/* 0xffffffffu */) { + offsetSize = 4; + } else { + offsetSize = 8; + } + // Maybe we need to move down data + if (offsetSize == 1) { + int targetPos = 3; + if (!needIndexTable) { + targetPos = 2; + } + if ((size - 1) > (tos + 9)) { + for (int i = tos + targetPos; i < tos + 9; i++) { + remove(tos + targetPos); + } + } + final int diff = 9 - targetPos; + if (needIndexTable) { + for (int i = 0; i < n; i++) { + in.set(i, in.get(i) - diff); + } + } // Note: if !needIndexTable the index is now wrong! + } + // One could move down things in the offsetSize == 2 case as well, + // since we only need 4 bytes in the beginning. However, saving these + // 4 bytes has been sacrificed on the Altar of Performance. + + // Now build the table: + if (needIndexTable) { + // final int tableBase = size; + for (int i = 0; i < n; i++) { + long x = in.get(i); + for (int j = 0; j < offsetSize; j++) { + add(/* tableBase + offsetSize * i + j, */ (byte) (x & 0xff)); + x >>= 8; + } + } + } else { // no index table + buffer[tos] = (byte) 0x02; + } + // Finally fix the byte width in the type byte: + if (offsetSize > 1) { + if (offsetSize == 2) { + buffer[tos] = (byte) (buffer[tos] + 1); + } else if (offsetSize == 4) { + buffer[tos] = (byte) (buffer[tos] + 2); + } else { // offsetSize == 8 + buffer[tos] = (byte) (buffer[tos] + 3); + if (needNrSubs) { + appendLength(n); + } + } + } + // Fix the byte length in the beginning + long x = size - tos; + for (int i = 1; i <= offsetSize; i++) { + buffer[tos + i] = (byte) (x & 0xff); + x >>= 8; + } + // set the number of items in the beginning + if (offsetSize < 8 && needNrSubs) { + x = n; + for (int i = offsetSize + 1; i <= 2 * offsetSize; i++) { + buffer[tos + i] = (byte) (x & 0xff); + x >>= 8; + } + } + stack.remove(stack.size() - 1); + return this; + } + + private static class SortEntry { + private final VPackSlice slice; + private final int offset; + + public SortEntry(final VPackSlice slice, final int offset) { + super(); + this.slice = slice; + this.offset = offset; + } + } + + private void sortObjectIndex(final int start, final List offsets) + throws VPackKeyTypeException, VPackNeedAttributeTranslatorException { + final List attributes = new ArrayList(); + for (final Integer offset : offsets) { + attributes.add(new SortEntry(new VPackSlice(buffer, start + offset).makeKey(), offset)); + } + final Comparator comparator = new Comparator() { + @Override + public int compare(final SortEntry o1, final SortEntry o2) { + return o1.slice.getAsString().compareTo(o2.slice.getAsString()); + // return compareTo(o1.slice.getValue(), 1, + // o1.slice.getValue().length - 1, o2.slice.getValue(), 1, + // o2.slice.getValue().length - 1); + } + }; + Collections.sort(attributes, comparator); + offsets.clear(); + for (final SortEntry sortEntry : attributes) { + offsets.add(sortEntry.offset); + } + } + + public static int compareTo( + final byte[] b1, + final int b1Index, + final int b1Length, + final byte[] b2, + final int b2Index, + final int b2Length) { + final int commonLength = Math.min(b1Length, b2Length); + for (int i = 0; i < commonLength; i++) { + final byte byte1 = b1[b1Index + i]; + final byte byte2 = b2[b2Index + i]; + if (byte1 != byte2) { + return (byte1 < byte2) ? -1 : 1; + } + } + if (b1Length != b2Length) { + return (b1Length < b2Length) ? -2 : 2; + } + return 0; + } + + private boolean isClosed() { + return stack.isEmpty(); + } + + /** + * + * @return head of open object/array + */ + private byte head() { + final Integer in = stack.get(stack.size() - 1); + return buffer[in]; + } + + public VPackSlice slice() { + return new VPackSlice(buffer); + } + + public int getVpackSize() { + return size; + } + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackDeserializationContext.java b/src/main/java/com/arangodb/velocypack/VPackDeserializationContext.java new file mode 100644 index 000000000..487ddcf8f --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackDeserializationContext.java @@ -0,0 +1,25 @@ +package com.arangodb.velocypack; + +import java.util.Collection; +import java.util.Map; + +import com.arangodb.velocypack.exception.VPackParserException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public interface VPackDeserializationContext { + + T deserialize(final VPackSlice vpack, final Class type) throws VPackParserException; + + , C> T deserialize(final VPackSlice vpack, final Class type, final Class contentType) + throws VPackParserException; + + , K, C> T deserialize( + final VPackSlice vpack, + final Class type, + final Class keyType, + final Class contentType) throws VPackParserException; + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackDeserializer.java b/src/main/java/com/arangodb/velocypack/VPackDeserializer.java new file mode 100644 index 000000000..86d63c48a --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackDeserializer.java @@ -0,0 +1,13 @@ +package com.arangodb.velocypack; + +import com.arangodb.velocypack.exception.VPackException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public interface VPackDeserializer { + + T deserialize(VPackSlice vpack, VPackDeserializationContext context) throws VPackException; + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackInstanceCreator.java b/src/main/java/com/arangodb/velocypack/VPackInstanceCreator.java new file mode 100644 index 000000000..af9fb7295 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackInstanceCreator.java @@ -0,0 +1,11 @@ +package com.arangodb.velocypack; + +/** + * @author Mark - mark@arangodb.com + * + */ +public interface VPackInstanceCreator { + + T createInstance(); + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackKeyMapAdapter.java b/src/main/java/com/arangodb/velocypack/VPackKeyMapAdapter.java new file mode 100644 index 000000000..b17ccec86 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackKeyMapAdapter.java @@ -0,0 +1,13 @@ +package com.arangodb.velocypack; + +/** + * @author Mark - mark@arangodb.com + * + */ +public interface VPackKeyMapAdapter { + + String serialize(T key); + + T deserialize(String key); + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackParser.java b/src/main/java/com/arangodb/velocypack/VPackParser.java new file mode 100644 index 000000000..d93e9000a --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackParser.java @@ -0,0 +1,102 @@ +package com.arangodb.velocypack; + +import java.text.DateFormat; +import java.util.Iterator; +import java.util.Locale; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackParser { + + private static final String OBJECT_OPEN = "{"; + private static final String OBJECT_CLOSE = "}"; + private static final String ARRAY_OPEN = "["; + private static final String ARRAY_CLOSE = "]"; + private static final String STRING = "\""; + private static final String FIELD = ":"; + private static final String SEPARATOR = ","; + private static final String NULL = "null"; + private static final DateFormat DATEFORMAT = DateFormat.getDateTimeInstance(DateFormat.DEFAULT, DateFormat.DEFAULT, + Locale.US); + + public static String toJson(final VPackSlice vpack) { + return toJson(vpack, false); + } + + public static String toJson(final VPackSlice vpack, final boolean includeNullValue) { + final StringBuilder json = new StringBuilder(); + parse(null, vpack, json, includeNullValue); + return json.toString(); + } + + private static void parse( + final VPackSlice attribute, + final VPackSlice value, + final StringBuilder json, + final boolean includeNullValue) { + if (attribute != null && attribute.isString()) { + appendField(attribute, json); + } + if (value.isObject()) { + parseObject(value, json, includeNullValue); + } else if (value.isArray()) { + parseArray(value, json, includeNullValue); + } else if (value.isBoolean()) { + json.append(value.getAsBoolean()); + } else if (value.isString()) { + json.append(STRING); + json.append(value.getAsString()); + json.append(STRING); + } else if (value.isNumber()) { + json.append(value.getAsNumber()); + } else if (value.isDate()) { + json.append(STRING); + json.append(DATEFORMAT.format(value.getAsDate())); + json.append(STRING); + } else if (value.isNull()) { + json.append(NULL); + } + } + + private static void appendField(final VPackSlice attribute, final StringBuilder json) { + json.append(STRING); + json.append(attribute.getAsString()); + json.append(STRING); + json.append(FIELD); + } + + private static void parseObject(final VPackSlice value, final StringBuilder json, final boolean includeNullValue) { + json.append(OBJECT_OPEN); + int added = 0; + for (final Iterator iterator = value.iterator(); iterator.hasNext();) { + final VPackSlice nextAttr = iterator.next(); + final VPackSlice nextValue = new VPackSlice(nextAttr.getVpack(), + nextAttr.getStart() + nextAttr.getByteSize()); + if (!nextValue.isNull() || includeNullValue) { + if (added++ > 0) { + json.append(SEPARATOR); + } + parse(nextAttr, nextValue, json, includeNullValue); + } + } + json.append(OBJECT_CLOSE); + } + + private static void parseArray(final VPackSlice value, final StringBuilder json, final boolean includeNullValue) { + json.append(ARRAY_OPEN); + int added = 0; + for (int i = 0; i < value.getLength(); i++) { + final VPackSlice valueAt = value.get(i); + if (!valueAt.isNull() || includeNullValue) { + if (added++ > 0) { + json.append(SEPARATOR); + } + parse(null, valueAt, json, includeNullValue); + } + } + json.append(ARRAY_CLOSE); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackSerializationContext.java b/src/main/java/com/arangodb/velocypack/VPackSerializationContext.java new file mode 100644 index 000000000..b5583897f --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackSerializationContext.java @@ -0,0 +1,18 @@ +package com.arangodb.velocypack; + +import java.util.Map; + +import com.arangodb.velocypack.exception.VPackParserException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public interface VPackSerializationContext { + + void serialize(final VPackBuilder builder, final String attribute, final Object entity) throws VPackParserException; + + void serialize(final VPackBuilder builder, final String attribute, final Map entity, final Class keyType) + throws VPackParserException; + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackSerializer.java b/src/main/java/com/arangodb/velocypack/VPackSerializer.java new file mode 100644 index 000000000..d24c8016a --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackSerializer.java @@ -0,0 +1,14 @@ +package com.arangodb.velocypack; + +import com.arangodb.velocypack.exception.VPackException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public interface VPackSerializer { + + void serialize(VPackBuilder builder, String attribute, T value, VPackSerializationContext context) + throws VPackException; + +} diff --git a/src/main/java/com/arangodb/velocypack/VPackSlice.java b/src/main/java/com/arangodb/velocypack/VPackSlice.java new file mode 100644 index 000000000..abbe20db5 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/VPackSlice.java @@ -0,0 +1,731 @@ +package com.arangodb.velocypack; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Date; +import java.util.Iterator; + +import com.arangodb.velocypack.exception.VPackException; +import com.arangodb.velocypack.exception.VPackKeyTypeException; +import com.arangodb.velocypack.exception.VPackNeedAttributeTranslatorException; +import com.arangodb.velocypack.exception.VPackValueTypeException; +import com.arangodb.velocypack.internal.VPackAttributeTranslatorImpl; +import com.arangodb.velocypack.internal.util.BinaryUtil; +import com.arangodb.velocypack.internal.util.DateUtil; +import com.arangodb.velocypack.internal.util.NumberUtil; +import com.arangodb.velocypack.internal.util.ObjectArrayUtil; +import com.arangodb.velocypack.internal.util.StringUtil; +import com.arangodb.velocypack.internal.util.ValueLengthUtil; +import com.arangodb.velocypack.internal.util.ValueTypeUtil; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackSlice { + + public static VPackAttributeTranslator attributeTranslator; + static { + attributeTranslator = new VPackAttributeTranslatorImpl(); + } + + private final byte[] vpack; + private final int start; + + protected VPackSlice() { + this(new byte[] { 0x00 }, 0); + } + + public VPackSlice(final byte[] vpack) { + this(vpack, 0); + } + + public VPackSlice(final byte[] vpack, final int start) { + super(); + this.vpack = vpack; + this.start = start; + } + + public byte head() { + return vpack[start]; + } + + public byte[] getVpack() { + return vpack; + } + + public int getStart() { + return start; + } + + private ValueType type() { + return ValueTypeUtil.get(head()); + } + + private int length() { + return ValueLengthUtil.get(head()) - 1; + } + + private boolean isType(final ValueType type) { + return type() == type; + } + + public boolean isNone() { + return isType(ValueType.NONE); + } + + public boolean isNull() { + return isType(ValueType.NULL); + } + + public boolean isIllegal() { + return isType(ValueType.ILLEGAL); + } + + public boolean isBoolean() { + return isType(ValueType.BOOL); + } + + public boolean isTrue() { + return head() == 0x1a; + } + + public boolean isFalse() { + return head() == 0x19; + } + + public boolean isArray() { + return isType(ValueType.ARRAY); + } + + public boolean isObject() { + return isType(ValueType.OBJECT); + } + + public boolean isDouble() { + return isType(ValueType.DOUBLE); + } + + public boolean isDate() { + return isType(ValueType.UTC_DATE); + } + + public boolean isExternal() { + return isType(ValueType.EXTERNAL); + } + + public boolean isMinKey() { + return isType(ValueType.MIN_KEY); + } + + public boolean isMaxKey() { + return isType(ValueType.MAX_KEY); + } + + public boolean isInt() { + return isType(ValueType.INT); + } + + public boolean isUInt() { + return isType(ValueType.UINT); + } + + public boolean isSmallInt() { + return isType(ValueType.SMALLINT); + } + + public boolean isInteger() { + return isInt() || isUInt() || isSmallInt(); + } + + public boolean isNumber() { + return isInteger() || isDouble(); + } + + public boolean isString() { + return isType(ValueType.STRING); + } + + public boolean isBinary() { + return isType(ValueType.BINARY); + } + + public boolean isBCD() { + return isType(ValueType.BCD); + } + + public boolean isCustom() { + return isType(ValueType.CUSTOM); + } + + public boolean getAsBoolean() { + if (!isBoolean()) { + throw new VPackValueTypeException(ValueType.BOOL); + } + return isTrue(); + } + + public double getAsDouble() { + if (!isDouble()) { + throw new VPackValueTypeException(ValueType.DOUBLE); + } + return getAsDoubleUnchecked(); + } + + private double getAsDoubleUnchecked() { + return NumberUtil.toDouble(vpack, start + 1, length()); + } + + public BigDecimal getAsBigDecimal() { + return new BigDecimal(getAsDouble()); + } + + private long getSmallInt() { + final byte head = head(); + final long smallInt; + if (head >= 0x30 && head <= 0x39) { + smallInt = head - 0x30; + } else /* if (head >= 0x3a && head <= 0x3f) */ { + smallInt = head - 0x3a - 6; + } + return smallInt; + } + + private long getInt() { + return NumberUtil.toLong(vpack, start + 1, length()); + } + + private long getUInt() { + return NumberUtil.toLong(vpack, start + 1, length()); + } + + public Number getAsNumber() { + final Number result; + if (isSmallInt()) { + result = getSmallInt(); + } else if (isInt()) { + result = getInt(); + } else if (isUInt()) { + result = getUInt(); + } else if (isDouble()) { + result = getAsDouble(); + } else { + throw new VPackValueTypeException(ValueType.INT, ValueType.UINT, ValueType.SMALLINT); + } + return result; + } + + public long getAsLong() { + return getAsNumber().longValue(); + } + + public int getAsInt() { + return getAsNumber().intValue(); + } + + public float getAsFloat() { + return (float) getAsDoubleUnchecked(); + } + + public short getAsShort() { + return getAsNumber().shortValue(); + } + + public BigInteger getAsBigInteger() { + if (isSmallInt() || isInt()) { + return BigInteger.valueOf(getAsLong()); + } else if (isUInt()) { + return NumberUtil.toBigInteger(vpack, start + 1, length()); + } else { + throw new VPackValueTypeException(ValueType.INT, ValueType.UINT, ValueType.SMALLINT); + } + } + + public Date getAsDate() { + if (!isDate()) { + throw new VPackValueTypeException(ValueType.UTC_DATE); + } + return DateUtil.toDate(vpack, start + 1, length()); + } + + public String getAsString() { + if (!isString()) { + throw new VPackValueTypeException(ValueType.STRING); + } + return isLongString() ? getLongString() : getShortString(); + } + + public char getAsChar() { + return getAsString().charAt(0); + } + + private boolean isLongString() { + return head() == (byte) 0xbf; + } + + private String getShortString() { + return StringUtil.toString(vpack, start + 1, length()); + } + + private String getLongString() { + return StringUtil.toString(vpack, start + 9, getLongStringLength()); + } + + private int getLongStringLength() { + return (int) NumberUtil.toLongReversed(vpack, start + 1, 8); + } + + private int getStringLength() { + return isLongString() ? getLongStringLength() : head() - 0x40; + } + + public byte[] getAsBinary() { + if (!isBinary()) { + throw new VPackValueTypeException(ValueType.BINARY); + } + final byte[] binary = BinaryUtil.toBinary(vpack, start + 1 + head() - ((byte) 0xbf), getBinaryLength()); + return binary; + } + + public int getBinaryLength() { + if (!isBinary()) { + throw new VPackValueTypeException(ValueType.BINARY); + } + return getBinaryLengthUnchecked(); + } + + private int getBinaryLengthUnchecked() { + return (int) NumberUtil.toLong(vpack, start + 1, head() - ((byte) 0xbf)); + } + + /** + * @return the number of members for an Array, Object or String + */ + public long getLength() { + final long length; + if (isString()) { + length = getStringLength(); + } else if (!isArray() && !isObject()) { + throw new VPackValueTypeException(ValueType.ARRAY, ValueType.OBJECT, ValueType.STRING); + } else { + final byte head = head(); + if (head == 0x01 || head == 0x0a) { + // empty + length = 0; + } else if (head == 0x13 || head == 0x14) { + // compact array or object + final long end = NumberUtil.readVariableValueLength(vpack, start + 1, false); + length = NumberUtil.readVariableValueLength(vpack, (int) (start + end - 1), true); + } else { + final int offsetsize = ObjectArrayUtil.getOffsetSize(head); + final long end = NumberUtil.toLongReversed(vpack, start + 1, offsetsize); + if (head <= 0x05) { + // array with no offset table or length + final int dataOffset = findDataOffset(); + final VPackSlice first = new VPackSlice(vpack, start + dataOffset); + length = (end - dataOffset) / first.getByteSize(); + } else if (offsetsize < 8) { + length = NumberUtil.toLongReversed(vpack, start + 1 + offsetsize, offsetsize); + } else { + length = NumberUtil.toLongReversed(vpack, (int) (start + end - offsetsize), offsetsize); + } + } + } + return length; + } + + public int size() { + return (int) getLength(); + } + + /** + * Must be called for a nonempty array or object at start(): + */ + protected int findDataOffset() { + final int fsm = ObjectArrayUtil.getFirstSubMap(head()); + final int offset; + if (fsm <= 2 && vpack[start + 2] != 0) { + offset = 2; + } else if (fsm <= 3 && vpack[start + 3] != 0) { + offset = 3; + } else if (fsm <= 5 && vpack[start + 6] != 0) { + offset = 5; + } else { + offset = 9; + } + return offset; + } + + public int getByteSize() { + final long size; + final byte head = head(); + final int valueLength = ValueLengthUtil.get(head); + if (valueLength != 0) { + size = valueLength; + } else { + switch (type()) { + case ARRAY: + case OBJECT: + if (head == 0x13 || head == 0x14) { + // compact Array or Object + size = NumberUtil.readVariableValueLength(vpack, start + 1, false); + } else /* if (head <= 0x14) */ { + size = NumberUtil.toLongReversed(vpack, start + 1, ObjectArrayUtil.getOffsetSize(head)); + } + break; + case STRING: + // long UTF-8 String + size = getLongStringLength() + 1 + 8; + break; + case BINARY: + size = 1 + head - ((byte) 0xbf) + getBinaryLengthUnchecked(); + break; + case BCD: + if (head <= 0xcf) { + size = 1 + head + ((byte) 0xc7) + NumberUtil.toLong(vpack, start + 1, head - ((byte) 0xc7)); + } else { + size = 1 + head - ((byte) 0xcf) + NumberUtil.toLong(vpack, start + 1, head - ((byte) 0xcf)); + } + break; + case CUSTOM: + if (head == 0xf4 || head == 0xf5 || head == 0xf6) { + size = 2 + NumberUtil.toLong(vpack, start + 1, 1); + } else if (head == 0xf7 || head == 0xf8 || head == 0xf9) { + size = 3 + NumberUtil.toLong(vpack, start + 1, 2); + } else if (head == 0xfa || head == 0xfb || head == 0xfc) { + size = 5 + NumberUtil.toLong(vpack, start + 1, 4); + } else /* if (head == 0xfd || head == 0xfe || head == 0xff) */ { + size = 9 + NumberUtil.toLong(vpack, start + 1, 8); + } + break; + default: + // TODO + throw new InternalError(); + } + } + return (int) size; + } + + /** + * @return array value at the specified index + * @throws VPackValueTypeException + */ + public VPackSlice get(final int index) { + if (!isArray()) { + throw new VPackValueTypeException(ValueType.ARRAY); + } + return getNth(index); + } + + public VPackSlice get(final String attribute) throws VPackException { + if (!isObject()) { + throw new VPackValueTypeException(ValueType.OBJECT); + } + final byte head = head(); + VPackSlice result = new VPackSlice(); + if (head == 0x0a) { + // special case, empty object + result = new VPackSlice(); + } else if (head == 0x14) { + // compact Object + result = getFromCompactObject(attribute); + } else { + final int offsetsize = ObjectArrayUtil.getOffsetSize(head); + final long end = NumberUtil.toLongReversed(vpack, start + 1, offsetsize); + final long n; + if (offsetsize < 8) { + n = NumberUtil.toLongReversed(vpack, start + 1 + offsetsize, offsetsize); + } else { + n = NumberUtil.toLongReversed(vpack, (int) (start + end - offsetsize), offsetsize); + } + if (n == 1) { + // Just one attribute, there is no index table! + final VPackSlice key = new VPackSlice(vpack, start + findDataOffset()); + + if (key.isString()) { + if (key.isEqualString(attribute)) { + result = new VPackSlice(vpack, key.start + key.getByteSize()); + } else { + // no match + result = new VPackSlice(); + } + } else if (key.isInteger()) { + // translate key + if (VPackSlice.attributeTranslator == null) { + throw new VPackNeedAttributeTranslatorException(); + } + if (key.translateUnchecked().isEqualString(attribute)) { + result = new VPackSlice(vpack, key.start + key.getByteSize()); + } else { + // no match + result = new VPackSlice(); + } + } else { + // no match + result = new VPackSlice(); + } + } else { + final long ieBase = end - n * offsetsize - (offsetsize == 8 ? 8 : 0); + + // only use binary search for attributes if we have at least + // this many entries + // otherwise we'll always use the linear search + final long sortedSearchEntriesThreshold = 4; + + final boolean sorted = head >= 0x0b && head <= 0x0e; + if (sorted && n >= sortedSearchEntriesThreshold) { + // This means, we have to handle the special case n == 1 + // only in the linear search! + result = searchObjectKeyBinary(attribute, ieBase, offsetsize, n); + } else { + result = searchObjectKeyLinear(attribute, ieBase, offsetsize, n); + } + } + } + return result; + } + + /** + * translates an integer key into a string, without checks + */ + protected VPackSlice translateUnchecked() { + final VPackSlice result = attributeTranslator.translate(getAsInt()); + return result != null ? result : new VPackSlice(); + } + + protected VPackSlice makeKey() throws VPackKeyTypeException, VPackNeedAttributeTranslatorException { + if (isString()) { + return this; + } + if (isInteger()) { + if (VPackSlice.attributeTranslator == null) { + throw new VPackNeedAttributeTranslatorException(); + } + return translateUnchecked(); + } + throw new VPackKeyTypeException("Cannot translate key of this type"); + } + + private VPackSlice getFromCompactObject(final String attribute) + throws VPackKeyTypeException, VPackNeedAttributeTranslatorException { + for (final Iterator iterator = iterator(); iterator.hasNext();) { + final VPackSlice key = iterator.next(); + if (key.makeKey().isEqualString(attribute)) { + return new VPackSlice(vpack, key.start + key.getByteSize()); + } + } + // not found + return new VPackSlice(); + } + + private VPackSlice searchObjectKeyBinary( + final String attribute, + final long ieBase, + final int offsetsize, + final long n) throws VPackValueTypeException, VPackNeedAttributeTranslatorException { + + final boolean useTranslator = VPackSlice.attributeTranslator != null; + VPackSlice result; + long l = 0; + long r = n - 1; + + for (;;) { + // midpoint + final long index = l + ((r - l) / 2); + final long offset = ieBase + index * offsetsize; + final long keyIndex = NumberUtil.toLongReversed(vpack, (int) (start + offset), offsetsize); + final VPackSlice key = new VPackSlice(vpack, (int) (start + keyIndex)); + int res = 0; + if (key.isString()) { + res = key.compareString(attribute); + } else if (key.isInteger()) { + // translate key + if (!useTranslator) { + // no attribute translator + throw new VPackNeedAttributeTranslatorException(); + } + res = key.translateUnchecked().compareString(attribute); + } else { + // invalid key + result = new VPackSlice(); + break; + } + if (res == 0) { + // found + result = new VPackSlice(vpack, key.start + key.getByteSize()); + break; + } + if (res > 0) { + if (index == 0) { + result = new VPackSlice(); + break; + } + r = index - 1; + } else { + l = index + 1; + } + if (r < l) { + result = new VPackSlice(); + break; + } + } + return result; + } + + private VPackSlice searchObjectKeyLinear( + final String attribute, + final long ieBase, + final int offsetsize, + final long n) throws VPackValueTypeException, VPackNeedAttributeTranslatorException { + + final boolean useTranslator = VPackSlice.attributeTranslator != null; + VPackSlice result = new VPackSlice(); + for (long index = 0; index < n; index++) { + final long offset = ieBase + index * offsetsize; + final long keyIndex = NumberUtil.toLongReversed(vpack, (int) (start + offset), offsetsize); + final VPackSlice key = new VPackSlice(vpack, (int) (start + keyIndex)); + if (key.isString()) { + if (!key.isEqualString(attribute)) { + continue; + } + } else if (key.isInteger()) { + // translate key + if (!useTranslator) { + // no attribute translator + throw new VPackNeedAttributeTranslatorException(); + } + if (!key.translateUnchecked().isEqualString(attribute)) { + continue; + } + } else { + // invalid key type + result = new VPackSlice(); + break; + } + // key is identical. now return value + result = new VPackSlice(vpack, key.start + key.getByteSize()); + break; + } + return result; + + } + + public VPackSlice keyAt(final int index) { + if (!isObject()) { + throw new VPackValueTypeException(ValueType.OBJECT); + } + return getNthKey(index); + } + + public VPackSlice valueAt(final int index) { + if (!isObject()) { + throw new VPackValueTypeException(ValueType.OBJECT); + } + final VPackSlice key = getNthKey(index); + return new VPackSlice(vpack, key.start + key.getByteSize()); + } + + private VPackSlice getNthKey(final int index) { + return new VPackSlice(vpack, start + getNthOffset(index)); + } + + private VPackSlice getNth(final int index) { + return new VPackSlice(vpack, start + getNthOffset(index)); + } + + /** + * + * @return the offset for the nth member from an Array or Object type + */ + private int getNthOffset(final int index) { + final int offset; + final byte head = head(); + if (head == 0x13 || head == 0x14) { + // compact Array or Object + offset = getNthOffsetFromCompact(index); + } else if (head == 0x01 || head == 0x0a) { + // special case: empty Array or empty Object + throw new IndexOutOfBoundsException(); + } else { + final long n; + final int offsetsize = ObjectArrayUtil.getOffsetSize(head); + final long end = NumberUtil.toLongReversed(vpack, start + 1, offsetsize); + int dataOffset = findDataOffset(); + if (head <= 0x05) { + // array with no offset table or length + final VPackSlice first = new VPackSlice(vpack, start + dataOffset); + n = (end - dataOffset) / first.getByteSize(); + } else if (offsetsize < 8) { + n = NumberUtil.toLongReversed(vpack, start + 1 + offsetsize, offsetsize); + } else { + n = NumberUtil.toLongReversed(vpack, (int) (start + end - offsetsize), offsetsize); + } + if (index >= n) { + throw new IndexOutOfBoundsException(); + } + if (head <= 0x05 || n == 1) { + // no index table, but all array items have the same length + // or only one item is in the array + // now fetch first item and determine its length + if (dataOffset == 0) { + dataOffset = findDataOffset(); + } + offset = dataOffset + index * new VPackSlice(vpack, start + dataOffset).getByteSize(); + } else { + final long ieBase = end - n * offsetsize + index * offsetsize - (offsetsize == 8 ? 8 : 0); + offset = (int) NumberUtil.toLongReversed(vpack, (int) (start + ieBase), offsetsize); + } + } + return offset; + } + + /** + * @return the offset for the nth member from a compact Array or Object type + */ + private int getNthOffsetFromCompact(final int index) { + final long end = NumberUtil.readVariableValueLength(vpack, start + 1, false); + final long n = NumberUtil.readVariableValueLength(vpack, (int) (start + end - 1), true); + if (index >= n) { + throw new IndexOutOfBoundsException(); + } + final byte head = head(); + long offset = 1 + NumberUtil.getVariableValueLength(end); + long current = 0; + while (current != index) { + final long byteSize = new VPackSlice(vpack, (int) (start + offset)).getByteSize(); + offset += byteSize; + if (head == 0x14) { + offset += byteSize; + } + ++current; + } + return (int) offset; + } + + private boolean isEqualString(final String s) { + final String string = getAsString(); + return string.equals(s); + } + + private int compareString(final String s) { + final String string = getAsString(); + return string.compareTo(s); + } + + public Iterator iterator() { + final Iterator iterator; + if (isObject()) { + iterator = new ObjectIterator(this); + } else if (isArray()) { + iterator = new ArrayIterator(this); + } else { + throw new VPackValueTypeException(ValueType.ARRAY, ValueType.OBJECT); + } + return iterator; + } + + protected byte[] getValue() { + return Arrays.copyOfRange(vpack, start, start + getByteSize()); + } +} diff --git a/src/main/java/com/arangodb/velocypack/Value.java b/src/main/java/com/arangodb/velocypack/Value.java new file mode 100644 index 000000000..e61ef4650 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/Value.java @@ -0,0 +1,217 @@ +package com.arangodb.velocypack; + +import java.math.BigDecimal; +import java.math.BigInteger; +import java.util.Date; + +import com.arangodb.velocypack.exception.VPackValueTypeException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class Value { + + private Boolean b; + private Double d; + private Long l; + private Integer i; + private Float f; + private Short sh; + private BigInteger bi; + private BigDecimal bd; + private String s; + private Character c; + private Date date; + private byte[] blob; + + private final ValueType type; + private final Class clazz; + private final boolean unindexed; + + private Value(final ValueType type, final Class clazz) { + this(type, clazz, false); + } + + private Value(final ValueType type, final Class clazz, final boolean unindexed) { + super(); + this.type = type; + this.clazz = clazz; + this.unindexed = unindexed; + } + + /** + * creates a Value with the specified type Array or Object + * + * @throws VPackValueTypeException + */ + public Value(final ValueType type) { + this(type, false); + } + + /** + * creates a Value with the specified type Array or Object or Null + * + * @throws VPackValueTypeException + */ + public Value(final ValueType type, final boolean unindexed) throws VPackValueTypeException { + this(type, null, unindexed); + if (type != ValueType.ARRAY && type != ValueType.OBJECT && type != ValueType.NULL) { + throw new VPackValueTypeException(ValueType.ARRAY, ValueType.OBJECT, ValueType.NULL); + } + } + + public Value(final Boolean value) { + this(checkNull(value, ValueType.BOOL), Boolean.class); + b = value; + } + + public Value(final Long value) { + this(checkSmallInt(value, ValueType.INT), Long.class); + l = value; + } + + public Value(final Long value, final ValueType type) throws VPackValueTypeException { + this(checkSmallInt(value, type), Long.class); + if (type != ValueType.INT && type != ValueType.UINT && type != ValueType.SMALLINT) { + throw new VPackValueTypeException(ValueType.INT, ValueType.UINT, ValueType.SMALLINT); + } + l = value; + } + + public Value(final Integer value) { + this(checkSmallInt(value, ValueType.INT), Integer.class); + i = value; + } + + public Value(final Integer value, final ValueType type) throws VPackValueTypeException { + this(checkSmallInt(value, type), Integer.class); + if (type != ValueType.INT && type != ValueType.UINT && type != ValueType.SMALLINT) { + throw new VPackValueTypeException(ValueType.INT, ValueType.UINT, ValueType.SMALLINT); + } + i = value; + } + + public Value(final Short value) { + this(checkSmallInt(value, ValueType.INT), Short.class); + sh = value; + } + + public Value(final BigInteger value) { + this(checkSmallInt(value, ValueType.INT), BigInteger.class); + bi = value; + } + + public Value(final BigInteger value, final ValueType type) throws VPackValueTypeException { + this(checkSmallInt(value, type), BigInteger.class); + if (type != ValueType.INT && type != ValueType.UINT && type != ValueType.SMALLINT) { + throw new VPackValueTypeException(ValueType.INT, ValueType.UINT, ValueType.SMALLINT); + } + bi = value; + } + + public Value(final Double value) { + this(checkNull(value, ValueType.DOUBLE), Double.class); + d = value; + } + + public Value(final Float value) { + this(checkNull(value, ValueType.DOUBLE), Float.class); + f = value; + } + + public Value(final BigDecimal value) { + this(checkNull(value, ValueType.DOUBLE), BigDecimal.class); + bd = value; + } + + public Value(final String value) { + this(checkNull(value, ValueType.STRING), String.class); + s = value; + } + + public Value(final Character value) { + this(checkNull(value, ValueType.STRING), Character.class); + c = value; + } + + public Value(final Date value) { + this(checkNull(value, ValueType.UTC_DATE), Date.class); + date = value; + } + + public Value(final byte[] value) { + this(checkNull(value, ValueType.BINARY), null); + blob = value; + } + + private static ValueType checkSmallInt(final Number value, final ValueType type) { + return value != null ? value.longValue() <= 9 && value.longValue() >= -6 ? ValueType.SMALLINT : type + : ValueType.NULL; + } + + private static ValueType checkNull(final Object obj, final ValueType type) { + return obj != null ? type : ValueType.NULL; + } + + public ValueType getType() { + return type; + } + + public Class getClazz() { + return clazz; + } + + public boolean isUnindexed() { + return unindexed; + } + + public Boolean getBoolean() { + return b; + } + + public Double getDouble() { + return d; + } + + public Long getLong() { + return l; + } + + public Integer getInteger() { + return i; + } + + public Float getFloat() { + return f; + } + + public Short getShort() { + return sh; + } + + public BigInteger getBigInteger() { + return bi; + } + + public BigDecimal getBigDecimal() { + return bd; + } + + public String getString() { + return s; + } + + public Character getCharacter() { + return c; + } + + public Date getDate() { + return date; + } + + public byte[] getBinary() { + return blob; + } + +} diff --git a/src/main/java/com/arangodb/velocypack/ValueType.java b/src/main/java/com/arangodb/velocypack/ValueType.java new file mode 100644 index 000000000..d2465cbf8 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/ValueType.java @@ -0,0 +1,26 @@ +package com.arangodb.velocypack; + +/** + * @author Mark - mark@arangodb.com + * + */ +public enum ValueType { + NONE, // not yet initialized + ILLEGAL, // illegal value + NULL, // JSON null + BOOL, + ARRAY, + OBJECT, + DOUBLE, + UTC_DATE, // UTC Date + EXTERNAL, + MIN_KEY, + MAX_KEY, + INT, + UINT, + SMALLINT, + STRING, + BINARY, + BCD, + CUSTOM +} diff --git a/src/main/java/com/arangodb/velocypack/annotations/Expose.java b/src/main/java/com/arangodb/velocypack/annotations/Expose.java new file mode 100644 index 000000000..56c3445a4 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/annotations/Expose.java @@ -0,0 +1,20 @@ +package com.arangodb.velocypack.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Mark - mark@arangodb.com + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Expose { + + boolean serialize() default true; + + boolean deserialize() default true; + +} diff --git a/src/main/java/com/arangodb/velocypack/annotations/SerializedName.java b/src/main/java/com/arangodb/velocypack/annotations/SerializedName.java new file mode 100644 index 000000000..5679e38b8 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/annotations/SerializedName.java @@ -0,0 +1,18 @@ +package com.arangodb.velocypack.annotations; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * @author Mark - mark@arangodb.com + * + */ +@Retention(RetentionPolicy.RUNTIME) +@Target({ ElementType.FIELD }) +public @interface SerializedName { + + String value(); + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackBuilderException.java b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderException.java new file mode 100644 index 000000000..dfc32521a --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderException.java @@ -0,0 +1,21 @@ +package com.arangodb.velocypack.exception; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackBuilderException extends VPackException { + + public VPackBuilderException() { + super(); + } + + public VPackBuilderException(final String message) { + super(message); + } + + public VPackBuilderException(final Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackBuilderKeyAlreadyWrittenException.java b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderKeyAlreadyWrittenException.java new file mode 100644 index 000000000..edf3169cf --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderKeyAlreadyWrittenException.java @@ -0,0 +1,13 @@ +package com.arangodb.velocypack.exception; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackBuilderKeyAlreadyWrittenException extends VPackBuilderException { + + public VPackBuilderKeyAlreadyWrittenException() { + super(); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNeedOpenCompoundException.java b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNeedOpenCompoundException.java new file mode 100644 index 000000000..dbb9f32e8 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNeedOpenCompoundException.java @@ -0,0 +1,13 @@ +package com.arangodb.velocypack.exception; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackBuilderNeedOpenCompoundException extends VPackBuilderException { + + public VPackBuilderNeedOpenCompoundException() { + super(); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNeedOpenObjectException.java b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNeedOpenObjectException.java new file mode 100644 index 000000000..705e775da --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNeedOpenObjectException.java @@ -0,0 +1,13 @@ +package com.arangodb.velocypack.exception; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackBuilderNeedOpenObjectException extends VPackBuilderNeedOpenCompoundException { + + public VPackBuilderNeedOpenObjectException() { + super(); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNumberOutOfRangeException.java b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNumberOutOfRangeException.java new file mode 100644 index 000000000..966296458 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderNumberOutOfRangeException.java @@ -0,0 +1,15 @@ +package com.arangodb.velocypack.exception; + +import com.arangodb.velocypack.ValueType; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackBuilderNumberOutOfRangeException extends VPackBuilderException { + + public VPackBuilderNumberOutOfRangeException(final ValueType type) { + super(String.format("Number out of range of %s.%s", type.getClass().getSimpleName(), type.name())); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackBuilderUnexpectedValueException.java b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderUnexpectedValueException.java new file mode 100644 index 000000000..28988b9a2 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackBuilderUnexpectedValueException.java @@ -0,0 +1,39 @@ +package com.arangodb.velocypack.exception; + +import com.arangodb.velocypack.ValueType; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackBuilderUnexpectedValueException extends VPackBuilderException { + + public VPackBuilderUnexpectedValueException(final ValueType type, final Class... classes) { + super(createMessage(type, null, classes)); + } + + public VPackBuilderUnexpectedValueException(final ValueType type, final String specify, final Class... classes) { + super(createMessage(type, specify, classes)); + } + + private static String createMessage(final ValueType type, final String specify, final Class... classes) { + final StringBuilder sb = new StringBuilder(); + sb.append("Must give "); + if (specify != null) { + sb.append(specify); + sb.append(" "); + } + for (int i = 0; i < classes.length; i++) { + if (i > 0) { + sb.append(" or "); + } + sb.append(classes[i].getSimpleName()); + } + sb.append(" for "); + sb.append(type.getClass().getSimpleName()); + sb.append("."); + sb.append(type.name()); + return sb.toString(); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackException.java b/src/main/java/com/arangodb/velocypack/exception/VPackException.java new file mode 100644 index 000000000..854d5ee8c --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackException.java @@ -0,0 +1,21 @@ +package com.arangodb.velocypack.exception; + +/** + * @author Mark - mark@arangodb.com + * + */ +public abstract class VPackException extends Exception { + + protected VPackException() { + super(); + } + + protected VPackException(final String message) { + super(message); + } + + protected VPackException(final Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackKeyTypeException.java b/src/main/java/com/arangodb/velocypack/exception/VPackKeyTypeException.java new file mode 100644 index 000000000..9afb64c30 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackKeyTypeException.java @@ -0,0 +1,13 @@ +package com.arangodb.velocypack.exception; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackKeyTypeException extends VPackException { + + public VPackKeyTypeException(final String message) { + super(message); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackNeedAttributeTranslatorException.java b/src/main/java/com/arangodb/velocypack/exception/VPackNeedAttributeTranslatorException.java new file mode 100644 index 000000000..fddcb38fd --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackNeedAttributeTranslatorException.java @@ -0,0 +1,9 @@ +package com.arangodb.velocypack.exception; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackNeedAttributeTranslatorException extends VPackException { + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackParserException.java b/src/main/java/com/arangodb/velocypack/exception/VPackParserException.java new file mode 100644 index 000000000..ba43d2bd8 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackParserException.java @@ -0,0 +1,13 @@ +package com.arangodb.velocypack.exception; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackParserException extends VPackException { + + public VPackParserException(final Throwable cause) { + super(cause); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/exception/VPackValueTypeException.java b/src/main/java/com/arangodb/velocypack/exception/VPackValueTypeException.java new file mode 100644 index 000000000..f3b14ba02 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/exception/VPackValueTypeException.java @@ -0,0 +1,27 @@ +package com.arangodb.velocypack.exception; + +import com.arangodb.velocypack.ValueType; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackValueTypeException extends IllegalStateException { + + public VPackValueTypeException(final ValueType... types) { + super(createMessage(types)); + } + + private static String createMessage(final ValueType... types) { + final StringBuilder sb = new StringBuilder(); + sb.append("Expecting type "); + for (int i = 0; i < types.length; i++) { + if (i > 0) { + sb.append(" or "); + } + sb.append(types[i].name()); + } + return sb.toString(); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/VPackAttributeTranslatorImpl.java b/src/main/java/com/arangodb/velocypack/internal/VPackAttributeTranslatorImpl.java new file mode 100644 index 000000000..caefd090b --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/VPackAttributeTranslatorImpl.java @@ -0,0 +1,87 @@ +package com.arangodb.velocypack.internal; + +import java.util.HashMap; +import java.util.Map; + +import com.arangodb.velocypack.VPackAttributeTranslator; +import com.arangodb.velocypack.VPackBuilder; +import com.arangodb.velocypack.VPackSlice; +import com.arangodb.velocypack.Value; +import com.arangodb.velocypack.ValueType; +import com.arangodb.velocypack.exception.VPackException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackAttributeTranslatorImpl implements VPackAttributeTranslator { + + private static final String KEY = "_key"; + private static final String REV = "_rev"; + private static final String ID = "_id"; + private static final String FROM = "_from"; + private static final String TO = "_to"; + + private static final byte KEY_ATTRIBUTE = 0x31; + private static final byte REV_ATTRIBUTE = 0x32; + private static final byte ID_ATTRIBUTE = 0x33; + private static final byte FROM_ATTRIBUTE = 0x34; + private static final byte TO_ATTRIBUTE = 0x35; + private static final byte ATTRIBUTE_BASE = 0x30; + + private VPackBuilder builder; + private final Map attributeToKey; + private final Map keyToAttribute; + + public VPackAttributeTranslatorImpl() { + super(); + builder = null; + attributeToKey = new HashMap(); + keyToAttribute = new HashMap(); + try { + add(KEY, KEY_ATTRIBUTE - ATTRIBUTE_BASE); + add(REV, REV_ATTRIBUTE - ATTRIBUTE_BASE); + add(ID, ID_ATTRIBUTE - ATTRIBUTE_BASE); + add(FROM, FROM_ATTRIBUTE - ATTRIBUTE_BASE); + add(TO, TO_ATTRIBUTE - ATTRIBUTE_BASE); + seal(); + } catch (final VPackException e) { + throw new RuntimeException(e); + } + } + + @Override + public void add(final String attribute, final int key) throws VPackException { + if (builder == null) { + builder = new VPackBuilder(); + builder.add(new Value(ValueType.OBJECT)); + } + builder.add(attribute, new Value(key, (key < -6 || key > 9) ? ValueType.INT : ValueType.SMALLINT)); + } + + @Override + public void seal() throws VPackException { + if (builder == null) { + return; + } + builder.close(); + final VPackSlice slice = builder.slice(); + for (int i = 0; i < slice.getLength(); i++) { + final VPackSlice key = slice.keyAt(i); + final VPackSlice value = slice.valueAt(i); + attributeToKey.put(key.getAsString(), value); + keyToAttribute.put(value.getAsInt(), key); + } + } + + @Override + public VPackSlice translate(final String attribute) { + return attributeToKey.get(attribute); + } + + @Override + public VPackSlice translate(final int key) { + return keyToAttribute.get(key); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/VPackCache.java b/src/main/java/com/arangodb/velocypack/internal/VPackCache.java new file mode 100644 index 000000000..f3a09e0ca --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/VPackCache.java @@ -0,0 +1,155 @@ +package com.arangodb.velocypack.internal; + +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.lang.reflect.ParameterizedType; +import java.lang.reflect.Type; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +import com.arangodb.velocypack.annotations.Expose; +import com.arangodb.velocypack.annotations.SerializedName; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackCache { + + public abstract static class FieldInfo { + private final Class type; + private final String fieldName; + private final boolean serialize; + private final boolean deserialize; + private final Class[] parameterizedTypes; + + private FieldInfo(final Class type, final String fieldName, final boolean serialize, + final boolean deserialize, final Class[] parameterizedTypes) { + super(); + this.type = type; + this.fieldName = fieldName; + this.serialize = serialize; + this.deserialize = deserialize; + this.parameterizedTypes = parameterizedTypes; + } + + public Class getType() { + return type; + } + + public String getFieldName() { + return fieldName; + } + + public boolean isSerialize() { + return serialize; + } + + public boolean isDeserialize() { + return deserialize; + } + + public Class[] getParameterizedTypes() { + return parameterizedTypes; + } + + public abstract void set(Object obj, Object value) throws IllegalAccessException; + + public abstract Object get(Object obj) throws IllegalAccessException; + } + + private final Map, Map> cache; + private final Comparator> fieldComparator; + + public VPackCache() { + super(); + cache = new ConcurrentHashMap, Map>(); + fieldComparator = new Comparator>() { + @Override + public int compare(final Entry o1, final Entry o2) { + return o1.getKey().compareTo(o2.getKey()); + } + }; + } + + public Map getFields(final Class entityClass) { + Map fields = cache.get(entityClass); + if (fields == null) { + fields = new HashMap(); + Class tmp = entityClass; + while (tmp != null && tmp != Object.class) { + final Field[] declaredFields = tmp.getDeclaredFields(); + for (final Field field : declaredFields) { + if (!field.isSynthetic() && !Modifier.isStatic(field.getModifiers())) { + field.setAccessible(true); + final FieldInfo fieldInfo = createFieldInfo(field); + if (fieldInfo.serialize || fieldInfo.deserialize) { + fields.put(fieldInfo.getFieldName(), fieldInfo); + } + } + } + tmp = tmp.getSuperclass(); + } + fields = sort(fields.entrySet()); + cache.put(entityClass, fields); + } + return fields; + } + + private Map sort(final Set> entrySet) { + final Map sorted = new LinkedHashMap(); + final List> tmp = new ArrayList>(entrySet); + Collections.sort(tmp, fieldComparator); + for (final Entry entry : tmp) { + sorted.put(entry.getKey(), entry.getValue()); + } + return sorted; + } + + private FieldInfo createFieldInfo(final Field field) { + final SerializedName annotationName = field.getAnnotation(SerializedName.class); + final String fieldName = annotationName != null ? annotationName.value() : field.getName(); + final Expose expose = field.getAnnotation(Expose.class); + final boolean serialize = expose != null ? expose.serialize() : true; + final boolean deserialize = expose != null ? expose.deserialize() : true; + final Class type = field.getType(); + Class[] parameterizedTypes = null; + if (type.isArray()) { + parameterizedTypes = new Class[] { type.getComponentType() }; + } else if (Collection.class.isAssignableFrom(type)) { + final ParameterizedType genericType = (ParameterizedType) field.getGenericType(); + parameterizedTypes = new Class[] { getParameterizedType(genericType.getActualTypeArguments()[0]) }; + } else if (Map.class.isAssignableFrom(type)) { + final ParameterizedType genericType = (ParameterizedType) field.getGenericType(); + final Class key = getParameterizedType(genericType.getActualTypeArguments()[0]); + final Class value = getParameterizedType(genericType.getActualTypeArguments()[1]); + parameterizedTypes = new Class[] { key, value }; + } + return new FieldInfo(field.getType(), fieldName, serialize, deserialize, parameterizedTypes) { + @Override + public void set(final Object obj, final Object value) throws IllegalAccessException { + field.set(obj, value); + } + + @Override + public Object get(final Object obj) throws IllegalAccessException { + return field.get(obj); + } + }; + } + + private Class getParameterizedType(final Type argType) { + return (Class) (ParameterizedType.class.isAssignableFrom(argType.getClass()) + ? ParameterizedType.class.cast(argType).getRawType() : argType); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/VPackDeserializers.java b/src/main/java/com/arangodb/velocypack/internal/VPackDeserializers.java new file mode 100644 index 000000000..4ac9ddb7d --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/VPackDeserializers.java @@ -0,0 +1,99 @@ +package com.arangodb.velocypack.internal; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import com.arangodb.velocypack.VPackDeserializationContext; +import com.arangodb.velocypack.VPackDeserializer; +import com.arangodb.velocypack.VPackSlice; +import com.arangodb.velocypack.exception.VPackException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackDeserializers { + + private VPackDeserializers() { + super(); + } + + public static final VPackDeserializer STRING = new VPackDeserializer() { + @Override + public String deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsString(); + } + }; + public static final VPackDeserializer BOOLEAN = new VPackDeserializer() { + @Override + public Boolean deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsBoolean(); + } + }; + public static final VPackDeserializer INTEGER = new VPackDeserializer() { + @Override + public Integer deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsInt(); + } + }; + public static final VPackDeserializer LONG = new VPackDeserializer() { + @Override + public Long deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsLong(); + } + }; + public static final VPackDeserializer SHORT = new VPackDeserializer() { + @Override + public Short deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsShort(); + } + }; + public static final VPackDeserializer DOUBLE = new VPackDeserializer() { + @Override + public Double deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsDouble(); + } + }; + public static final VPackDeserializer FLOAT = new VPackDeserializer() { + @Override + public Float deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsFloat(); + } + }; + public static final VPackDeserializer BIG_INTEGER = new VPackDeserializer() { + @Override + public BigInteger deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsBigInteger(); + } + }; + public static final VPackDeserializer BIG_DECIMAL = new VPackDeserializer() { + @Override + public BigDecimal deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsBigDecimal(); + } + }; + public static final VPackDeserializer NUMBER = new VPackDeserializer() { + @Override + public Number deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsNumber(); + } + }; + public static final VPackDeserializer CHARACTER = new VPackDeserializer() { + @Override + public Character deserialize(final VPackSlice vpack, final VPackDeserializationContext context) + throws VPackException { + return vpack.getAsChar(); + } + }; + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/VPackInstanceCreators.java b/src/main/java/com/arangodb/velocypack/internal/VPackInstanceCreators.java new file mode 100644 index 000000000..807f49632 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/VPackInstanceCreators.java @@ -0,0 +1,49 @@ +package com.arangodb.velocypack.internal; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import com.arangodb.velocypack.VPackInstanceCreator; + +/** + * @author Mark - mark@arangodb.com + * + */ +@SuppressWarnings("rawtypes") +public class VPackInstanceCreators { + + private VPackInstanceCreators() { + super(); + } + + public static final VPackInstanceCreator COLLECTION = new VPackInstanceCreator() { + @Override + public Collection createInstance() { + return new ArrayList(); + } + }; + public static final VPackInstanceCreator LIST = new VPackInstanceCreator() { + @Override + public List createInstance() { + return new ArrayList(); + } + }; + public static final VPackInstanceCreator SET = new VPackInstanceCreator() { + @Override + public Set createInstance() { + return new HashSet(); + } + }; + public static final VPackInstanceCreator MAP = new VPackInstanceCreator() { + @Override + public Map createInstance() { + return new HashMap(); + } + }; + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/VPackKeyMapAdapters.java b/src/main/java/com/arangodb/velocypack/internal/VPackKeyMapAdapters.java new file mode 100644 index 000000000..799c23e8a --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/VPackKeyMapAdapters.java @@ -0,0 +1,155 @@ +package com.arangodb.velocypack.internal; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import com.arangodb.velocypack.VPackKeyMapAdapter; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackKeyMapAdapters { + + private VPackKeyMapAdapters() { + super(); + } + + public static final VPackKeyMapAdapter> createEnumAdapter(final Class type) { + return new VPackKeyMapAdapter>() { + @Override + public String serialize(final Enum key) { + return key.name(); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + @Override + public Enum deserialize(final String key) { + final Class enumType = (Class) type; + return Enum.valueOf(enumType, key); + } + }; + } + + public static final VPackKeyMapAdapter STRING = new VPackKeyMapAdapter() { + @Override + public String serialize(final String key) { + return key; + } + + @Override + public String deserialize(final String key) { + return key; + } + }; + public static final VPackKeyMapAdapter BOOLEAN = new VPackKeyMapAdapter() { + @Override + public String serialize(final Boolean key) { + return key.toString(); + } + + @Override + public Boolean deserialize(final String key) { + return Boolean.valueOf(key); + } + }; + public static final VPackKeyMapAdapter INTEGER = new VPackKeyMapAdapter() { + @Override + public String serialize(final Integer key) { + return key.toString(); + } + + @Override + public Integer deserialize(final String key) { + return Integer.valueOf(key); + } + }; + public static final VPackKeyMapAdapter LONG = new VPackKeyMapAdapter() { + @Override + public String serialize(final Long key) { + return key.toString(); + } + + @Override + public Long deserialize(final String key) { + return Long.valueOf(key); + } + }; + public static final VPackKeyMapAdapter SHORT = new VPackKeyMapAdapter() { + @Override + public String serialize(final Short key) { + return key.toString(); + } + + @Override + public Short deserialize(final String key) { + return Short.valueOf(key); + } + }; + public static final VPackKeyMapAdapter DOUBLE = new VPackKeyMapAdapter() { + @Override + public String serialize(final Double key) { + return key.toString(); + } + + @Override + public Double deserialize(final String key) { + return Double.valueOf(key); + } + }; + public static final VPackKeyMapAdapter FLOAT = new VPackKeyMapAdapter() { + @Override + public String serialize(final Float key) { + return key.toString(); + } + + @Override + public Float deserialize(final String key) { + return Float.valueOf(key); + } + }; + public static final VPackKeyMapAdapter BIG_INTEGER = new VPackKeyMapAdapter() { + @Override + public String serialize(final BigInteger key) { + return key.toString(); + } + + @Override + public BigInteger deserialize(final String key) { + return new BigInteger(key); + } + }; + public static final VPackKeyMapAdapter BIG_DECIMAL = new VPackKeyMapAdapter() { + @Override + public String serialize(final BigDecimal key) { + return key.toString(); + } + + @Override + public BigDecimal deserialize(final String key) { + return new BigDecimal(key); + } + }; + public static final VPackKeyMapAdapter NUMBER = new VPackKeyMapAdapter() { + @Override + public String serialize(final Number key) { + return key.toString(); + } + + @Override + public Number deserialize(final String key) { + return Double.valueOf(key); + } + }; + public static final VPackKeyMapAdapter CHARACTER = new VPackKeyMapAdapter() { + @Override + public String serialize(final Character key) { + return key.toString(); + } + + @Override + public Character deserialize(final String key) { + return key.charAt(0); + } + }; +} diff --git a/src/main/java/com/arangodb/velocypack/internal/VPackOptionsImpl.java b/src/main/java/com/arangodb/velocypack/internal/VPackOptionsImpl.java new file mode 100644 index 000000000..3c0ff207a --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/VPackOptionsImpl.java @@ -0,0 +1,53 @@ +package com.arangodb.velocypack.internal; + +import com.arangodb.velocypack.VPack.VPackOptions; +import com.arangodb.velocypack.VPackBuilder.BuilderOptions; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackOptionsImpl implements VPackOptions, BuilderOptions { + + private boolean serializeNullValues; + private boolean buildUnindexedArrays; + private boolean buildUnindexedObjects; + + public VPackOptionsImpl() { + super(); + serializeNullValues = false; + buildUnindexedArrays = false; + buildUnindexedObjects = false; + } + + @Override + public boolean isSerializeNullValues() { + return serializeNullValues; + } + + @Override + public void setSerializeNullValues(final boolean serializeNullValues) { + this.serializeNullValues = serializeNullValues; + } + + @Override + public boolean isBuildUnindexedArrays() { + return buildUnindexedArrays; + } + + @Override + public void setBuildUnindexedArrays(final boolean buildUnindexedArrays) { + this.buildUnindexedArrays = buildUnindexedArrays; + } + + @Override + public boolean isBuildUnindexedObjects() { + return buildUnindexedObjects; + } + + @Override + public void setBuildUnindexedObjects(final boolean buildUnindexedObjects) { + this.buildUnindexedObjects = buildUnindexedObjects; + } + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/VPackSerializers.java b/src/main/java/com/arangodb/velocypack/internal/VPackSerializers.java new file mode 100644 index 000000000..19751237a --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/VPackSerializers.java @@ -0,0 +1,132 @@ +package com.arangodb.velocypack.internal; + +import java.math.BigDecimal; +import java.math.BigInteger; + +import com.arangodb.velocypack.VPackBuilder; +import com.arangodb.velocypack.VPackSerializationContext; +import com.arangodb.velocypack.VPackSerializer; +import com.arangodb.velocypack.Value; +import com.arangodb.velocypack.exception.VPackException; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class VPackSerializers { + + private VPackSerializers() { + super(); + } + + public static VPackSerializer STRING = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final String value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(String.class.cast(value))); + } + }; + public static VPackSerializer BOOLEAN = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Boolean value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(Boolean.class.cast(value))); + } + }; + public static VPackSerializer INTEGER = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Integer value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(Integer.class.cast(value))); + } + }; + public static VPackSerializer LONG = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Long value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(Long.class.cast(value))); + } + }; + public static VPackSerializer SHORT = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Short value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(Short.class.cast(value))); + } + }; + public static VPackSerializer DOUBLE = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Double value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(Double.class.cast(value))); + } + }; + public static VPackSerializer FLOAT = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Float value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(Float.class.cast(value))); + } + }; + public static VPackSerializer BIG_INTEGER = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final BigInteger value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(BigInteger.class.cast(value))); + } + }; + public static VPackSerializer BIG_DECIMAL = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final BigDecimal value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(BigDecimal.class.cast(value))); + } + }; + public static VPackSerializer NUMBER = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Number value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(Double.class.cast(value))); + } + }; + public static VPackSerializer CHARACTER = new VPackSerializer() { + @Override + public void serialize( + final VPackBuilder builder, + final String attribute, + final Character value, + final VPackSerializationContext context) throws VPackException { + builder.add(attribute, new Value(Character.class.cast(value))); + } + }; +} diff --git a/src/main/java/com/arangodb/velocypack/internal/util/BinaryUtil.java b/src/main/java/com/arangodb/velocypack/internal/util/BinaryUtil.java new file mode 100644 index 000000000..594b1f8cf --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/util/BinaryUtil.java @@ -0,0 +1,21 @@ +package com.arangodb.velocypack.internal.util; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class BinaryUtil { + + private BinaryUtil() { + super(); + } + + public static byte[] toBinary(final byte[] array, final int offset, final int length) { + final byte[] result = new byte[length]; + for (int i = offset, j = 0; j < length; i++, j++) { + result[j] = array[i]; + } + return result; + } + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/util/DateUtil.java b/src/main/java/com/arangodb/velocypack/internal/util/DateUtil.java new file mode 100644 index 000000000..c5dd98312 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/util/DateUtil.java @@ -0,0 +1,19 @@ +package com.arangodb.velocypack.internal.util; + +import java.util.Date; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class DateUtil { + + private DateUtil() { + super(); + } + + public static Date toDate(final byte[] array, final int offset, final int length) { + final long milliseconds = NumberUtil.toLong(array, offset, length); + return new Date(milliseconds); + } +} diff --git a/src/main/java/com/arangodb/velocypack/internal/util/NumberUtil.java b/src/main/java/com/arangodb/velocypack/internal/util/NumberUtil.java new file mode 100644 index 000000000..98d539d4f --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/util/NumberUtil.java @@ -0,0 +1,83 @@ +package com.arangodb.velocypack.internal.util; + +import java.math.BigInteger; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class NumberUtil { + + private static final int DOUBLE_BYTES = 8; + + private NumberUtil() { + super(); + } + + public static double toDouble(final byte[] array, final int offset, final int length) { + return Double.longBitsToDouble(toLong(array, offset, DOUBLE_BYTES)); + } + + public static long toLong(final byte[] array, final int offset, final int length) { + long result = 0; + for (int i = offset; i < (offset + length); i++) { + result <<= 8; + result |= (array[i] & 0xFF); + } + return result; + } + + public static long toLongReversed(final byte[] array, final int offset, final int length) { + long result = 0; + for (int i = (offset + length - 1); i >= offset; i--) { + result <<= 8; + result |= (array[i] & 0xFF); + } + return result; + } + + public static BigInteger toBigInteger(final byte[] array, final int offset, final int length) { + BigInteger result = new BigInteger(1, new byte[] {}); + for (int i = offset; i < (offset + length); i++) { + result = result.shiftLeft(8); + result = result.or(BigInteger.valueOf(array[i] & 0xFF)); + } + return result; + } + + /** + * read a variable length integer in unsigned LEB128 format + */ + public static long readVariableValueLength(final byte[] array, final int offset, final boolean reverse) { + long len = 0; + byte v; + long p = 0; + int i = offset; + do { + v = array[i]; + len += ((long) (v & (byte) 0x7f)) << p; + p += 7; + if (reverse) { + --i; + } else { + ++i; + } + } while ((v & (byte) 0x80) != 0); + return len; + } + + /** + * calculate the length of a variable length integer in unsigned LEB128 + * format + */ + public static long getVariableValueLength(final long value) { + long len = 1; + long val = value; + while (val >= 0x80) { + val >>= 7; + ++len; + } + return len; + } + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/util/ObjectArrayUtil.java b/src/main/java/com/arangodb/velocypack/internal/util/ObjectArrayUtil.java new file mode 100644 index 000000000..e837f0abb --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/util/ObjectArrayUtil.java @@ -0,0 +1,74 @@ +package com.arangodb.velocypack.internal.util; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class ObjectArrayUtil { + + private static final Map FIRST_SUB_MAP; + + static { + FIRST_SUB_MAP = new HashMap(); + + FIRST_SUB_MAP.put((byte) 0x00, 0); // None + FIRST_SUB_MAP.put((byte) 0x01, 1); // empty array + FIRST_SUB_MAP.put((byte) 0x02, 2); // array without index table + FIRST_SUB_MAP.put((byte) 0x03, 3); // array without index table + FIRST_SUB_MAP.put((byte) 0x04, 5); // array without index table + FIRST_SUB_MAP.put((byte) 0x05, 9); // array without index table + FIRST_SUB_MAP.put((byte) 0x06, 3); // array with index table + FIRST_SUB_MAP.put((byte) 0x07, 5); // array with index table + FIRST_SUB_MAP.put((byte) 0x08, 9); // array with index table + FIRST_SUB_MAP.put((byte) 0x09, 9); // array with index table + FIRST_SUB_MAP.put((byte) 0x0a, 1); // empty object + FIRST_SUB_MAP.put((byte) 0x0b, 3); // object with sorted index table + FIRST_SUB_MAP.put((byte) 0x0c, 5); // object with sorted index table + FIRST_SUB_MAP.put((byte) 0x0d, 9); // object with sorted index table + FIRST_SUB_MAP.put((byte) 0x0e, 9); // object with sorted index table + FIRST_SUB_MAP.put((byte) 0x0f, 3); // object with unsorted index table + FIRST_SUB_MAP.put((byte) 0x10, 5); // object with unsorted index table + FIRST_SUB_MAP.put((byte) 0x11, 9); // object with unsorted index table + FIRST_SUB_MAP.put((byte) 0x12, 9); // object with unsorted index table + } + + public static int getFirstSubMap(final byte key) { + return FIRST_SUB_MAP.get(key); + } + + private static final Map OFFSET_SIZE; + static { + OFFSET_SIZE = new HashMap(); + + OFFSET_SIZE.put((byte) 0x00, 0); // None + OFFSET_SIZE.put((byte) 0x01, 1); // empty array + OFFSET_SIZE.put((byte) 0x02, 1); // array without index table + OFFSET_SIZE.put((byte) 0x03, 2); // array without index table + OFFSET_SIZE.put((byte) 0x04, 4); // array without index table + OFFSET_SIZE.put((byte) 0x05, 8); // array without index table + OFFSET_SIZE.put((byte) 0x06, 1); // array with index table + OFFSET_SIZE.put((byte) 0x07, 2); // array with index table + OFFSET_SIZE.put((byte) 0x08, 4); // array with index table + OFFSET_SIZE.put((byte) 0x09, 8); // array with index table + OFFSET_SIZE.put((byte) 0x0a, 1); // empty object + OFFSET_SIZE.put((byte) 0x0b, 1); // object with sorted index table + OFFSET_SIZE.put((byte) 0x0c, 2); // object with sorted index table + OFFSET_SIZE.put((byte) 0x0d, 4); // object with sorted index table + OFFSET_SIZE.put((byte) 0x0e, 8); // object with sorted index table + OFFSET_SIZE.put((byte) 0x0f, 1); // object with unsorted index table + OFFSET_SIZE.put((byte) 0x10, 2); // object with unsorted index table + OFFSET_SIZE.put((byte) 0x11, 4); // object with unsorted index table + OFFSET_SIZE.put((byte) 0x12, 8); // object with unsorted index table + } + + private ObjectArrayUtil() { + super(); + } + + public static int getOffsetSize(final byte key) { + return OFFSET_SIZE.get(key); + } +} diff --git a/src/main/java/com/arangodb/velocypack/internal/util/StringUtil.java b/src/main/java/com/arangodb/velocypack/internal/util/StringUtil.java new file mode 100644 index 000000000..e1b055565 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/util/StringUtil.java @@ -0,0 +1,17 @@ +package com.arangodb.velocypack.internal.util; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class StringUtil { + + private StringUtil() { + super(); + } + + public static String toString(final byte[] array, final int offset, final int length) { + return new String(array, offset, length); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/util/ValueLengthUtil.java b/src/main/java/com/arangodb/velocypack/internal/util/ValueLengthUtil.java new file mode 100644 index 000000000..d85be74ef --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/util/ValueLengthUtil.java @@ -0,0 +1,286 @@ +package com.arangodb.velocypack.internal.util; + +import java.util.HashMap; +import java.util.Map; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class ValueLengthUtil { + + private static final int DOUBLE_BYTES = 8; + private static final int LONG_BYTES = 8; + private static final int CHARACTER_BYTES = 2; + + private static final Map MAP; + + static { + MAP = new HashMap(); + MAP.put((byte) 0x00, 1); + MAP.put((byte) 0x01, 1); + MAP.put((byte) 0x02, 0); + MAP.put((byte) 0x03, 0); + MAP.put((byte) 0x04, 0); + MAP.put((byte) 0x05, 0); + MAP.put((byte) 0x06, 0); + MAP.put((byte) 0x07, 0); + MAP.put((byte) 0x08, 0); + MAP.put((byte) 0x09, 0); + MAP.put((byte) 0x0a, 1); + MAP.put((byte) 0x0b, 0); + MAP.put((byte) 0x0c, 0); + MAP.put((byte) 0x0d, 0); + MAP.put((byte) 0x0e, 0); + MAP.put((byte) 0x0f, 0); + MAP.put((byte) 0x10, 0); + MAP.put((byte) 0x11, 0); + MAP.put((byte) 0x12, 0); + MAP.put((byte) 0x13, 0); + MAP.put((byte) 0x14, 0); + MAP.put((byte) 0x15, 0); + MAP.put((byte) 0x16, 0); + MAP.put((byte) 0x17, 1); + MAP.put((byte) 0x18, 1); + MAP.put((byte) 0x19, 1); + MAP.put((byte) 0x1a, 1); + MAP.put((byte) 0x1b, 1 + DOUBLE_BYTES); + MAP.put((byte) 0x1c, 1 + LONG_BYTES); + MAP.put((byte) 0x1d, 1 + CHARACTER_BYTES); + MAP.put((byte) 0x1e, 1); + MAP.put((byte) 0x1f, 1); + MAP.put((byte) 0x20, 2); + MAP.put((byte) 0x21, 3); + MAP.put((byte) 0x22, 4); + MAP.put((byte) 0x23, 5); + MAP.put((byte) 0x24, 6); + MAP.put((byte) 0x25, 7); + MAP.put((byte) 0x26, 8); + MAP.put((byte) 0x27, 9); + MAP.put((byte) 0x28, 2); + MAP.put((byte) 0x29, 3); + MAP.put((byte) 0x2a, 4); + MAP.put((byte) 0x2b, 5); + MAP.put((byte) 0x2c, 6); + MAP.put((byte) 0x2d, 7); + MAP.put((byte) 0x2e, 8); + MAP.put((byte) 0x2f, 9); + MAP.put((byte) 0x30, 1); + MAP.put((byte) 0x31, 1); + MAP.put((byte) 0x32, 1); + MAP.put((byte) 0x33, 1); + MAP.put((byte) 0x34, 1); + MAP.put((byte) 0x35, 1); + MAP.put((byte) 0x36, 1); + MAP.put((byte) 0x37, 1); + MAP.put((byte) 0x38, 1); + MAP.put((byte) 0x39, 1); + MAP.put((byte) 0x3a, 1); + MAP.put((byte) 0x3b, 1); + MAP.put((byte) 0x3c, 1); + MAP.put((byte) 0x3d, 1); + MAP.put((byte) 0x3e, 1); + MAP.put((byte) 0x3f, 1); + MAP.put((byte) 0x40, 1); + MAP.put((byte) 0x41, 2); + MAP.put((byte) 0x42, 3); + MAP.put((byte) 0x43, 4); + MAP.put((byte) 0x44, 5); + MAP.put((byte) 0x45, 6); + MAP.put((byte) 0x46, 7); + MAP.put((byte) 0x47, 8); + MAP.put((byte) 0x48, 9); + MAP.put((byte) 0x49, 10); + MAP.put((byte) 0x4a, 11); + MAP.put((byte) 0x4b, 12); + MAP.put((byte) 0x4c, 13); + MAP.put((byte) 0x4d, 14); + MAP.put((byte) 0x4e, 15); + MAP.put((byte) 0x4f, 16); + MAP.put((byte) 0x50, 17); + MAP.put((byte) 0x51, 18); + MAP.put((byte) 0x52, 19); + MAP.put((byte) 0x53, 20); + MAP.put((byte) 0x54, 21); + MAP.put((byte) 0x55, 22); + MAP.put((byte) 0x56, 23); + MAP.put((byte) 0x57, 24); + MAP.put((byte) 0x58, 25); + MAP.put((byte) 0x59, 26); + MAP.put((byte) 0x5a, 27); + MAP.put((byte) 0x5b, 28); + MAP.put((byte) 0x5c, 29); + MAP.put((byte) 0x5d, 30); + MAP.put((byte) 0x5e, 31); + MAP.put((byte) 0x5f, 32); + MAP.put((byte) 0x60, 33); + MAP.put((byte) 0x61, 34); + MAP.put((byte) 0x62, 35); + MAP.put((byte) 0x63, 36); + MAP.put((byte) 0x64, 37); + MAP.put((byte) 0x65, 38); + MAP.put((byte) 0x66, 39); + MAP.put((byte) 0x67, 40); + MAP.put((byte) 0x68, 41); + MAP.put((byte) 0x69, 42); + MAP.put((byte) 0x6a, 43); + MAP.put((byte) 0x6b, 44); + MAP.put((byte) 0x6c, 45); + MAP.put((byte) 0x6d, 46); + MAP.put((byte) 0x6e, 47); + MAP.put((byte) 0x6f, 48); + MAP.put((byte) 0x70, 49); + MAP.put((byte) 0x71, 50); + MAP.put((byte) 0x72, 51); + MAP.put((byte) 0x73, 52); + MAP.put((byte) 0x74, 53); + MAP.put((byte) 0x75, 54); + MAP.put((byte) 0x76, 55); + MAP.put((byte) 0x77, 56); + MAP.put((byte) 0x78, 57); + MAP.put((byte) 0x79, 58); + MAP.put((byte) 0x7a, 59); + MAP.put((byte) 0x7b, 60); + MAP.put((byte) 0x7c, 61); + MAP.put((byte) 0x7d, 62); + MAP.put((byte) 0x7e, 63); + MAP.put((byte) 0x7f, 64); + MAP.put((byte) 0x80, 65); + MAP.put((byte) 0x81, 66); + MAP.put((byte) 0x82, 67); + MAP.put((byte) 0x83, 68); + MAP.put((byte) 0x84, 69); + MAP.put((byte) 0x85, 70); + MAP.put((byte) 0x86, 71); + MAP.put((byte) 0x87, 72); + MAP.put((byte) 0x88, 73); + MAP.put((byte) 0x89, 74); + MAP.put((byte) 0x8a, 75); + MAP.put((byte) 0x8b, 76); + MAP.put((byte) 0x8c, 77); + MAP.put((byte) 0x8d, 78); + MAP.put((byte) 0x8e, 79); + MAP.put((byte) 0x8f, 80); + MAP.put((byte) 0x90, 81); + MAP.put((byte) 0x91, 82); + MAP.put((byte) 0x92, 83); + MAP.put((byte) 0x93, 84); + MAP.put((byte) 0x94, 85); + MAP.put((byte) 0x95, 86); + MAP.put((byte) 0x96, 87); + MAP.put((byte) 0x97, 88); + MAP.put((byte) 0x98, 89); + MAP.put((byte) 0x99, 90); + MAP.put((byte) 0x9a, 91); + MAP.put((byte) 0x9b, 92); + MAP.put((byte) 0x9c, 93); + MAP.put((byte) 0x9d, 94); + MAP.put((byte) 0x9e, 95); + MAP.put((byte) 0x9f, 96); + MAP.put((byte) 0xa0, 97); + MAP.put((byte) 0xa1, 98); + MAP.put((byte) 0xa2, 99); + MAP.put((byte) 0xa3, 100); + MAP.put((byte) 0xa4, 101); + MAP.put((byte) 0xa5, 102); + MAP.put((byte) 0xa6, 103); + MAP.put((byte) 0xa7, 104); + MAP.put((byte) 0xa8, 105); + MAP.put((byte) 0xa9, 106); + MAP.put((byte) 0xaa, 107); + MAP.put((byte) 0xab, 108); + MAP.put((byte) 0xac, 109); + MAP.put((byte) 0xad, 110); + MAP.put((byte) 0xae, 111); + MAP.put((byte) 0xaf, 112); + MAP.put((byte) 0xb0, 113); + MAP.put((byte) 0xb1, 114); + MAP.put((byte) 0xb2, 115); + MAP.put((byte) 0xb3, 116); + MAP.put((byte) 0xb4, 117); + MAP.put((byte) 0xb5, 118); + MAP.put((byte) 0xb6, 119); + MAP.put((byte) 0xb7, 120); + MAP.put((byte) 0xb8, 121); + MAP.put((byte) 0xb9, 122); + MAP.put((byte) 0xba, 123); + MAP.put((byte) 0xbb, 124); + MAP.put((byte) 0xbc, 125); + MAP.put((byte) 0xbd, 126); + MAP.put((byte) 0xbe, 127); + MAP.put((byte) 0xbf, 0); + MAP.put((byte) 0xc0, 0); + MAP.put((byte) 0xc1, 0); + MAP.put((byte) 0xc2, 0); + MAP.put((byte) 0xc3, 0); + MAP.put((byte) 0xc4, 0); + MAP.put((byte) 0xc5, 0); + MAP.put((byte) 0xc6, 0); + MAP.put((byte) 0xc7, 0); + MAP.put((byte) 0xc8, 0); + MAP.put((byte) 0xc9, 0); + MAP.put((byte) 0xca, 0); + MAP.put((byte) 0xcb, 0); + MAP.put((byte) 0xcc, 0); + MAP.put((byte) 0xcd, 0); + MAP.put((byte) 0xce, 0); + MAP.put((byte) 0xcf, 0); + MAP.put((byte) 0xd0, 0); + MAP.put((byte) 0xd1, 0); + MAP.put((byte) 0xd2, 0); + MAP.put((byte) 0xd3, 0); + MAP.put((byte) 0xd4, 0); + MAP.put((byte) 0xd5, 0); + MAP.put((byte) 0xd6, 0); + MAP.put((byte) 0xd7, 0); + MAP.put((byte) 0xd8, 0); + MAP.put((byte) 0xd9, 0); + MAP.put((byte) 0xda, 0); + MAP.put((byte) 0xdb, 0); + MAP.put((byte) 0xdc, 0); + MAP.put((byte) 0xdd, 0); + MAP.put((byte) 0xde, 0); + MAP.put((byte) 0xdf, 0); + MAP.put((byte) 0xe0, 0); + MAP.put((byte) 0xe1, 0); + MAP.put((byte) 0xe2, 0); + MAP.put((byte) 0xe3, 0); + MAP.put((byte) 0xe4, 0); + MAP.put((byte) 0xe5, 0); + MAP.put((byte) 0xe6, 0); + MAP.put((byte) 0xe7, 0); + MAP.put((byte) 0xe8, 0); + MAP.put((byte) 0xe9, 0); + MAP.put((byte) 0xea, 0); + MAP.put((byte) 0xeb, 0); + MAP.put((byte) 0xec, 0); + MAP.put((byte) 0xed, 0); + MAP.put((byte) 0xee, 0); + MAP.put((byte) 0xef, 0); + MAP.put((byte) 0xf0, 2); + MAP.put((byte) 0xf1, 3); + MAP.put((byte) 0xf2, 5); + MAP.put((byte) 0xf3, 9); + MAP.put((byte) 0xf4, 0); + MAP.put((byte) 0xf5, 0); + MAP.put((byte) 0xf6, 0); + MAP.put((byte) 0xf7, 0); + MAP.put((byte) 0xf8, 0); + MAP.put((byte) 0xf9, 0); + MAP.put((byte) 0xfa, 0); + MAP.put((byte) 0xfb, 0); + MAP.put((byte) 0xfc, 0); + MAP.put((byte) 0xfd, 0); + MAP.put((byte) 0xfe, 0); + MAP.put((byte) 0xff, 0); + } + + private ValueLengthUtil() { + super(); + } + + public static int get(final byte key) { + return MAP.get(key); + } + +} diff --git a/src/main/java/com/arangodb/velocypack/internal/util/ValueTypeUtil.java b/src/main/java/com/arangodb/velocypack/internal/util/ValueTypeUtil.java new file mode 100644 index 000000000..0a8e4d362 --- /dev/null +++ b/src/main/java/com/arangodb/velocypack/internal/util/ValueTypeUtil.java @@ -0,0 +1,285 @@ +package com.arangodb.velocypack.internal.util; + +import java.util.HashMap; +import java.util.Map; + +import com.arangodb.velocypack.ValueType; + +/** + * @author Mark - mark@arangodb.com + * + */ +public class ValueTypeUtil { + + private static final Map MAP; + + static { + MAP = new HashMap(); + + MAP.put((byte) 0x00, ValueType.NONE); + MAP.put((byte) 0x01, ValueType.ARRAY); + MAP.put((byte) 0x02, ValueType.ARRAY); + MAP.put((byte) 0x03, ValueType.ARRAY); + MAP.put((byte) 0x04, ValueType.ARRAY); + MAP.put((byte) 0x05, ValueType.ARRAY); + MAP.put((byte) 0x06, ValueType.ARRAY); + MAP.put((byte) 0x07, ValueType.ARRAY); + MAP.put((byte) 0x08, ValueType.ARRAY); + MAP.put((byte) 0x09, ValueType.ARRAY); + MAP.put((byte) 0x0a, ValueType.OBJECT); + MAP.put((byte) 0x0b, ValueType.OBJECT); + MAP.put((byte) 0x0c, ValueType.OBJECT); + MAP.put((byte) 0x0d, ValueType.OBJECT); + MAP.put((byte) 0x0e, ValueType.OBJECT); + MAP.put((byte) 0x0f, ValueType.OBJECT); + MAP.put((byte) 0x10, ValueType.OBJECT); + MAP.put((byte) 0x11, ValueType.OBJECT); + MAP.put((byte) 0x12, ValueType.OBJECT); + MAP.put((byte) 0x13, ValueType.ARRAY); + MAP.put((byte) 0x14, ValueType.OBJECT); + MAP.put((byte) 0x15, ValueType.NONE); + MAP.put((byte) 0x16, ValueType.NONE); + MAP.put((byte) 0x17, ValueType.ILLEGAL); + MAP.put((byte) 0x18, ValueType.NULL); + MAP.put((byte) 0x19, ValueType.BOOL); + MAP.put((byte) 0x1a, ValueType.BOOL); + MAP.put((byte) 0x1b, ValueType.DOUBLE); + MAP.put((byte) 0x1c, ValueType.UTC_DATE); + MAP.put((byte) 0x1d, ValueType.EXTERNAL); + MAP.put((byte) 0x1e, ValueType.MIN_KEY); + MAP.put((byte) 0x1f, ValueType.MAX_KEY); + MAP.put((byte) 0x20, ValueType.INT); + MAP.put((byte) 0x21, ValueType.INT); + MAP.put((byte) 0x22, ValueType.INT); + MAP.put((byte) 0x23, ValueType.INT); + MAP.put((byte) 0x24, ValueType.INT); + MAP.put((byte) 0x25, ValueType.INT); + MAP.put((byte) 0x26, ValueType.INT); + MAP.put((byte) 0x27, ValueType.INT); + MAP.put((byte) 0x28, ValueType.UINT); + MAP.put((byte) 0x29, ValueType.UINT); + MAP.put((byte) 0x2a, ValueType.UINT); + MAP.put((byte) 0x2b, ValueType.UINT); + MAP.put((byte) 0x2c, ValueType.UINT); + MAP.put((byte) 0x2d, ValueType.UINT); + MAP.put((byte) 0x2e, ValueType.UINT); + MAP.put((byte) 0x2f, ValueType.UINT); + MAP.put((byte) 0x30, ValueType.SMALLINT); + MAP.put((byte) 0x31, ValueType.SMALLINT); + MAP.put((byte) 0x32, ValueType.SMALLINT); + MAP.put((byte) 0x33, ValueType.SMALLINT); + MAP.put((byte) 0x34, ValueType.SMALLINT); + MAP.put((byte) 0x35, ValueType.SMALLINT); + MAP.put((byte) 0x36, ValueType.SMALLINT); + MAP.put((byte) 0x37, ValueType.SMALLINT); + MAP.put((byte) 0x38, ValueType.SMALLINT); + MAP.put((byte) 0x39, ValueType.SMALLINT); + MAP.put((byte) 0x3a, ValueType.SMALLINT); + MAP.put((byte) 0x3b, ValueType.SMALLINT); + MAP.put((byte) 0x3c, ValueType.SMALLINT); + MAP.put((byte) 0x3d, ValueType.SMALLINT); + MAP.put((byte) 0x3e, ValueType.SMALLINT); + MAP.put((byte) 0x3f, ValueType.SMALLINT); + MAP.put((byte) 0x40, ValueType.STRING); + MAP.put((byte) 0x41, ValueType.STRING); + MAP.put((byte) 0x42, ValueType.STRING); + MAP.put((byte) 0x43, ValueType.STRING); + MAP.put((byte) 0x44, ValueType.STRING); + MAP.put((byte) 0x45, ValueType.STRING); + MAP.put((byte) 0x46, ValueType.STRING); + MAP.put((byte) 0x47, ValueType.STRING); + MAP.put((byte) 0x48, ValueType.STRING); + MAP.put((byte) 0x49, ValueType.STRING); + MAP.put((byte) 0x4a, ValueType.STRING); + MAP.put((byte) 0x4b, ValueType.STRING); + MAP.put((byte) 0x4c, ValueType.STRING); + MAP.put((byte) 0x4d, ValueType.STRING); + MAP.put((byte) 0x4e, ValueType.STRING); + MAP.put((byte) 0x4f, ValueType.STRING); + MAP.put((byte) 0x50, ValueType.STRING); + MAP.put((byte) 0x51, ValueType.STRING); + MAP.put((byte) 0x52, ValueType.STRING); + MAP.put((byte) 0x53, ValueType.STRING); + MAP.put((byte) 0x54, ValueType.STRING); + MAP.put((byte) 0x55, ValueType.STRING); + MAP.put((byte) 0x56, ValueType.STRING); + MAP.put((byte) 0x57, ValueType.STRING); + MAP.put((byte) 0x58, ValueType.STRING); + MAP.put((byte) 0x59, ValueType.STRING); + MAP.put((byte) 0x5a, ValueType.STRING); + MAP.put((byte) 0x5b, ValueType.STRING); + MAP.put((byte) 0x5c, ValueType.STRING); + MAP.put((byte) 0x5d, ValueType.STRING); + MAP.put((byte) 0x5e, ValueType.STRING); + MAP.put((byte) 0x5f, ValueType.STRING); + MAP.put((byte) 0x60, ValueType.STRING); + MAP.put((byte) 0x61, ValueType.STRING); + MAP.put((byte) 0x62, ValueType.STRING); + MAP.put((byte) 0x63, ValueType.STRING); + MAP.put((byte) 0x64, ValueType.STRING); + MAP.put((byte) 0x65, ValueType.STRING); + MAP.put((byte) 0x66, ValueType.STRING); + MAP.put((byte) 0x67, ValueType.STRING); + MAP.put((byte) 0x68, ValueType.STRING); + MAP.put((byte) 0x69, ValueType.STRING); + MAP.put((byte) 0x6a, ValueType.STRING); + MAP.put((byte) 0x6b, ValueType.STRING); + MAP.put((byte) 0x6c, ValueType.STRING); + MAP.put((byte) 0x6d, ValueType.STRING); + MAP.put((byte) 0x6e, ValueType.STRING); + MAP.put((byte) 0x6f, ValueType.STRING); + MAP.put((byte) 0x70, ValueType.STRING); + MAP.put((byte) 0x71, ValueType.STRING); + MAP.put((byte) 0x72, ValueType.STRING); + MAP.put((byte) 0x73, ValueType.STRING); + MAP.put((byte) 0x74, ValueType.STRING); + MAP.put((byte) 0x75, ValueType.STRING); + MAP.put((byte) 0x76, ValueType.STRING); + MAP.put((byte) 0x77, ValueType.STRING); + MAP.put((byte) 0x78, ValueType.STRING); + MAP.put((byte) 0x79, ValueType.STRING); + MAP.put((byte) 0x7a, ValueType.STRING); + MAP.put((byte) 0x7b, ValueType.STRING); + MAP.put((byte) 0x7c, ValueType.STRING); + MAP.put((byte) 0x7d, ValueType.STRING); + MAP.put((byte) 0x7e, ValueType.STRING); + MAP.put((byte) 0x7f, ValueType.STRING); + MAP.put((byte) 0x80, ValueType.STRING); + MAP.put((byte) 0x81, ValueType.STRING); + MAP.put((byte) 0x82, ValueType.STRING); + MAP.put((byte) 0x83, ValueType.STRING); + MAP.put((byte) 0x84, ValueType.STRING); + MAP.put((byte) 0x85, ValueType.STRING); + MAP.put((byte) 0x86, ValueType.STRING); + MAP.put((byte) 0x87, ValueType.STRING); + MAP.put((byte) 0x88, ValueType.STRING); + MAP.put((byte) 0x89, ValueType.STRING); + MAP.put((byte) 0x8a, ValueType.STRING); + MAP.put((byte) 0x8b, ValueType.STRING); + MAP.put((byte) 0x8c, ValueType.STRING); + MAP.put((byte) 0x8d, ValueType.STRING); + MAP.put((byte) 0x8e, ValueType.STRING); + MAP.put((byte) 0x8f, ValueType.STRING); + MAP.put((byte) 0x90, ValueType.STRING); + MAP.put((byte) 0x91, ValueType.STRING); + MAP.put((byte) 0x92, ValueType.STRING); + MAP.put((byte) 0x93, ValueType.STRING); + MAP.put((byte) 0x94, ValueType.STRING); + MAP.put((byte) 0x95, ValueType.STRING); + MAP.put((byte) 0x96, ValueType.STRING); + MAP.put((byte) 0x97, ValueType.STRING); + MAP.put((byte) 0x98, ValueType.STRING); + MAP.put((byte) 0x99, ValueType.STRING); + MAP.put((byte) 0x9a, ValueType.STRING); + MAP.put((byte) 0x9b, ValueType.STRING); + MAP.put((byte) 0x9c, ValueType.STRING); + MAP.put((byte) 0x9d, ValueType.STRING); + MAP.put((byte) 0x9e, ValueType.STRING); + MAP.put((byte) 0x9f, ValueType.STRING); + MAP.put((byte) 0xa0, ValueType.STRING); + MAP.put((byte) 0xa1, ValueType.STRING); + MAP.put((byte) 0xa2, ValueType.STRING); + MAP.put((byte) 0xa3, ValueType.STRING); + MAP.put((byte) 0xa4, ValueType.STRING); + MAP.put((byte) 0xa5, ValueType.STRING); + MAP.put((byte) 0xa6, ValueType.STRING); + MAP.put((byte) 0xa7, ValueType.STRING); + MAP.put((byte) 0xa8, ValueType.STRING); + MAP.put((byte) 0xa9, ValueType.STRING); + MAP.put((byte) 0xaa, ValueType.STRING); + MAP.put((byte) 0xab, ValueType.STRING); + MAP.put((byte) 0xac, ValueType.STRING); + MAP.put((byte) 0xad, ValueType.STRING); + MAP.put((byte) 0xae, ValueType.STRING); + MAP.put((byte) 0xaf, ValueType.STRING); + MAP.put((byte) 0xb0, ValueType.STRING); + MAP.put((byte) 0xb1, ValueType.STRING); + MAP.put((byte) 0xb2, ValueType.STRING); + MAP.put((byte) 0xb3, ValueType.STRING); + MAP.put((byte) 0xb4, ValueType.STRING); + MAP.put((byte) 0xb5, ValueType.STRING); + MAP.put((byte) 0xb6, ValueType.STRING); + MAP.put((byte) 0xb7, ValueType.STRING); + MAP.put((byte) 0xb8, ValueType.STRING); + MAP.put((byte) 0xb9, ValueType.STRING); + MAP.put((byte) 0xba, ValueType.STRING); + MAP.put((byte) 0xbb, ValueType.STRING); + MAP.put((byte) 0xbc, ValueType.STRING); + MAP.put((byte) 0xbd, ValueType.STRING); + MAP.put((byte) 0xbe, ValueType.STRING); + MAP.put((byte) 0xbf, ValueType.STRING); + MAP.put((byte) 0xc0, ValueType.BINARY); + MAP.put((byte) 0xc1, ValueType.BINARY); + MAP.put((byte) 0xc2, ValueType.BINARY); + MAP.put((byte) 0xc3, ValueType.BINARY); + MAP.put((byte) 0xc4, ValueType.BINARY); + MAP.put((byte) 0xc5, ValueType.BINARY); + MAP.put((byte) 0xc6, ValueType.BINARY); + MAP.put((byte) 0xc7, ValueType.BINARY); + MAP.put((byte) 0xc8, ValueType.BCD); + MAP.put((byte) 0xc9, ValueType.BCD); + MAP.put((byte) 0xca, ValueType.BCD); + MAP.put((byte) 0xcb, ValueType.BCD); + MAP.put((byte) 0xcc, ValueType.BCD); + MAP.put((byte) 0xcd, ValueType.BCD); + MAP.put((byte) 0xce, ValueType.BCD); + MAP.put((byte) 0xcf, ValueType.BCD); + MAP.put((byte) 0xd0, ValueType.BCD); + MAP.put((byte) 0xd1, ValueType.BCD); + MAP.put((byte) 0xd2, ValueType.BCD); + MAP.put((byte) 0xd3, ValueType.BCD); + MAP.put((byte) 0xd4, ValueType.BCD); + MAP.put((byte) 0xd5, ValueType.BCD); + MAP.put((byte) 0xd6, ValueType.BCD); + MAP.put((byte) 0xd7, ValueType.BCD); + MAP.put((byte) 0xd8, ValueType.NONE); + MAP.put((byte) 0xd9, ValueType.NONE); + MAP.put((byte) 0xda, ValueType.NONE); + MAP.put((byte) 0xdb, ValueType.NONE); + MAP.put((byte) 0xdc, ValueType.NONE); + MAP.put((byte) 0xdd, ValueType.NONE); + MAP.put((byte) 0xde, ValueType.NONE); + MAP.put((byte) 0xdf, ValueType.NONE); + MAP.put((byte) 0xe0, ValueType.NONE); + MAP.put((byte) 0xe1, ValueType.NONE); + MAP.put((byte) 0xe2, ValueType.NONE); + MAP.put((byte) 0xe3, ValueType.NONE); + MAP.put((byte) 0xe4, ValueType.NONE); + MAP.put((byte) 0xe5, ValueType.NONE); + MAP.put((byte) 0xe6, ValueType.NONE); + MAP.put((byte) 0xe7, ValueType.NONE); + MAP.put((byte) 0xe8, ValueType.NONE); + MAP.put((byte) 0xe9, ValueType.NONE); + MAP.put((byte) 0xea, ValueType.NONE); + MAP.put((byte) 0xeb, ValueType.NONE); + MAP.put((byte) 0xec, ValueType.NONE); + MAP.put((byte) 0xed, ValueType.NONE); + MAP.put((byte) 0xee, ValueType.NONE); + MAP.put((byte) 0xef, ValueType.NONE); + MAP.put((byte) 0xf0, ValueType.CUSTOM); + MAP.put((byte) 0xf1, ValueType.CUSTOM); + MAP.put((byte) 0xf2, ValueType.CUSTOM); + MAP.put((byte) 0xf3, ValueType.CUSTOM); + MAP.put((byte) 0xf4, ValueType.CUSTOM); + MAP.put((byte) 0xf5, ValueType.CUSTOM); + MAP.put((byte) 0xf6, ValueType.CUSTOM); + MAP.put((byte) 0xf7, ValueType.CUSTOM); + MAP.put((byte) 0xf8, ValueType.CUSTOM); + MAP.put((byte) 0xf9, ValueType.CUSTOM); + MAP.put((byte) 0xfa, ValueType.CUSTOM); + MAP.put((byte) 0xfb, ValueType.CUSTOM); + MAP.put((byte) 0xfc, ValueType.CUSTOM); + MAP.put((byte) 0xfd, ValueType.CUSTOM); + MAP.put((byte) 0xfe, ValueType.CUSTOM); + MAP.put((byte) 0xff, ValueType.CUSTOM); + } + + private ValueTypeUtil() { + super(); + } + + public static ValueType get(final byte key) { + return MAP.get(key); + } + +} diff --git a/src/test/java/com/arangodb/BaseTest.java b/src/test/java/com/arangodb/BaseTest.java new file mode 100644 index 000000000..96318eda9 --- /dev/null +++ b/src/test/java/com/arangodb/BaseTest.java @@ -0,0 +1,36 @@ +package com.arangodb; + +import org.junit.AfterClass; +import org.junit.BeforeClass; + +import com.arangodb.model.DB; + +/** + * @author Mark - mark at arangodb.com + * + */ +public class BaseTest { + + private static final String TEST_DB = "java-driver-test-db"; + private static ArangoDB arangoDB; + protected static DB db; + + @BeforeClass + public static void setup() { + arangoDB = new ArangoDB.Builder().build(); + try { + arangoDB.dbCreate(TEST_DB).execute(); + } catch (final ArangoException e) { + } + BaseTest.db = arangoDB.db(TEST_DB); + } + + @AfterClass + public static void shutdown() { + try { + arangoDB.dbDelete(TEST_DB).execute(); + } catch (final ArangoException e) { + } + } + +}