diff --git a/modules/coverage-report/pom.xml b/modules/coverage-report/pom.xml
index 32c1ba31e1..4598528340 100644
--- a/modules/coverage-report/pom.xml
+++ b/modules/coverage-report/pom.xml
@@ -90,6 +90,7 @@
${project.parent.basedir}/jooby-lang-js/src/main/java
${project.parent.basedir}/jooby-requery/src/main/java
${project.parent.basedir}/jooby-rocker/src/main/java
+ ${project.parent.basedir}/jooby-neo4j/src/main/java
@@ -155,6 +156,7 @@
${project.parent.basedir}/jooby-lang-js/src/test/java
${project.parent.basedir}/jooby-requery/src/test/java
${project.parent.basedir}/jooby-rocker/src/test/java
+ ${project.parent.basedir}/jooby-neo4j/src/test/java
@@ -180,8 +182,10 @@
${project.parent.basedir}/jooby-hbm/src/test/resources
- ${project.parent.basedir}/jooby-whoops/src/test/resources
-
+ ${project.parent.basedir}/jooby-whoops/src/test/resources
+
+
+ ${project.parent.basedir}/jooby-neo4j/src/test/resources
@@ -400,6 +404,12 @@
${project.version}
+
+ org.jooby
+ jooby-neo4j
+ ${project.version}
+
+
org.jooby
jooby-jooq
diff --git a/modules/jooby-neo4j/foo.conf b/modules/jooby-neo4j/foo.conf
new file mode 100644
index 0000000000..5f56c8b494
--- /dev/null
+++ b/modules/jooby-neo4j/foo.conf
@@ -0,0 +1 @@
+com.graphaware.runtime.enabled = false
\ No newline at end of file
diff --git a/modules/jooby-neo4j/pom.xml b/modules/jooby-neo4j/pom.xml
index 4d66e0445d..b6d7377521 100644
--- a/modules/jooby-neo4j/pom.xml
+++ b/modules/jooby-neo4j/pom.xml
@@ -1,6 +1,6 @@
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
org.jooby
@@ -44,25 +44,55 @@
expire
3.1.4.49.4
+
com.graphaware.neo4j
runtime
3.1.4.49
+
org.neo4j
neo4j-graphdb-api
3.1.4
+
org.neo4j
neo4j
3.1.4
+
+
+ org.neo4j
+ neo4j-slf4j
+ 3.1.4
+
+
+
+ org.slf4j
+ jul-to-slf4j
+
+
+
+ org.javassist
+ javassist
+
+
net.iot-solutions.graphdb
jcypher
3.7.0
+
+
+ org.neo4j
+ neo4j-kernel
+
+
+ org.neo4j
+ neo4j-io
+
+
diff --git a/modules/jooby-neo4j/src/main/java/org/jooby/embedded/neo4j/EmbeddedNeo4j.java b/modules/jooby-neo4j/src/main/java/org/jooby/embedded/neo4j/EmbeddedNeo4j.java
deleted file mode 100644
index 4a1db855e9..0000000000
--- a/modules/jooby-neo4j/src/main/java/org/jooby/embedded/neo4j/EmbeddedNeo4j.java
+++ /dev/null
@@ -1,223 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/**
- * This copy of Woodstox XML processor is licensed under the
- * Apache (Software) License, version 2.0 ("the License").
- * See the License for details about distribution rights, and the
- * specific rights regarding derivate works.
- *
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/
- *
- * A copy is also included in the downloadable source code package
- * containing Woodstox, in file "ASL2.0", under the same directory
- * as this file.
- */
-package org.jooby.embedded.neo4j;
-
-import com.google.inject.Binder;
-import com.graphaware.runtime.GraphAwareRuntime;
-import com.graphaware.runtime.GraphAwareRuntimeFactory;
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import org.jooby.Env;
-import org.jooby.Jooby;
-import org.neo4j.graphdb.GraphDatabaseService;
-import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
-import org.neo4j.graphdb.factory.GraphDatabaseFactory;
-import org.neo4j.kernel.configuration.Settings;
-
-import java.io.File;
-import java.util.AbstractMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.function.BiConsumer;
-import java.util.stream.Collectors;
-
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.nonNull;
-import static java.util.Objects.requireNonNull;
-
-/**
- * Exposes {@link GraphDatabaseService} and {@link GraphAwareRuntime}.
- *
- *
usage
- *
- *
- * application.conf:
- *
- *
- *
- * databaseDir = "/tmp"
- *
- *
- *
- * {
- * use(new EmbeddedNeo4j());
- *
- * get("/", req {@literal ->} {
- * // work with db
- * DB = req.require(GraphDatabaseService.class);
- * });
- * }
- *
- *
- * Default DatabaseDir property is databaseDir
but of course you can use any other name:
- *
- *
- * application.conf:
- *
- *
- *
- * mydbDir = "bolt://localhost:7687"
- *
- *
- *
- * {
- * use(new Neo4j("mydbDir"));
- *
- * get("/", req {@literal ->} {
- * DB mydb = req.require(GraphDatabaseService.class);
- * // work with mydb
- * });
- * }
- *
- *
- * options
- *
- * Options can be set via .conf
file:
- *
- *
- *
- * neo4j.dbms.security.allow_csv_import_from_file_urls = true
- *
- *
- *
- * or programmatically:
- *
- *
- *
- * {
- * use(new Neo4j()
- * .properties((properties, config) {@literal ->} {
- * properties.put(GraphDatabaseSettings.allow_file_urls, config.get("dbms.security.allow_csv_import_from_file_urls"))
- * })
- * );
- * }
- *
- *
- *
- * @author sbcd90
- * @since 1.2.0
- */
-public class EmbeddedNeo4j implements Jooby.Module {
- private final String databaseDir;
-
- private BiConsumer properties;
-
- private final long timeout = 60000L;
-
- /**
- * Creates a new {@link EmbeddedNeo4j} module.
- *
- * @param databaseDir Database dir location.
- */
- public EmbeddedNeo4j(final String databaseDir) {
- this.databaseDir = requireNonNull(databaseDir, "A database directory is required");
- }
-
- /**
- * Creates a new {@link EmbeddedNeo4j} using the default property: databaseDir
.
- */
- public EmbeddedNeo4j() {
- this("databaseDir");
- }
-
- @Override
- public void configure(final Env env, final Config config, final Binder binder) {
- Properties properties = options(embeddedneo4j(config));
-
- if (nonNull(this.properties)) {
- this.properties.accept(properties, config);
- }
-
- GraphDatabaseFactory graphDatabaseFactory = new GraphDatabaseFactory();
- GraphDatabaseBuilder builder = graphDatabaseFactory
- .newEmbeddedDatabaseBuilder(new File(properties.getProperty("databaseDir")));
- String database = properties.remove("databaseDir").toString();
-
- properties.forEach((key, value) ->
- builder.setConfig(Settings.setting(key.toString(), Settings.STRING, "default"), value.toString()));
-
- GraphDatabaseService dbService = builder.newGraphDatabase();
- GraphAwareRuntime graphRuntime = GraphAwareRuntimeFactory.createRuntime(dbService);
- checkArgument(dbService.isAvailable(timeout), "Cannot connect to Database");
-
- Env.ServiceKey serviceKey = env.serviceKey();
- serviceKey.generate(GraphDatabaseService.class, database, k -> binder.bind(k).toInstance(dbService));
- serviceKey.generate(GraphAwareRuntime.class, database, k -> binder.bind(k).toInstance(graphRuntime));
-
- env.onStop(dbService::shutdown);
- }
-
- /**
- * Set a properties callback.
- *
- *
- * {
- * use(new EmbeddedNeo4j()
- * .properties((properties, config) {@literal ->} {
- * properties.put(GraphDatabaseSettings.allow_file_urls, true);
- * })
- * );
- * }
- *
- *
- * @param properties Configure callback.
- * @return This module
- */
- public EmbeddedNeo4j properties(final BiConsumer properties) {
- this.properties = requireNonNull(properties, "properties callback is required");
- return this;
- }
-
- @Override
- public Config config() {
- return ConfigFactory.parseResources(EmbeddedNeo4j.class, "embedded_neo4j.conf");
- }
-
- private Properties options(final Config config) {
- Properties properties = new Properties();
- properties.putAll(config.entrySet()
- .stream()
- .map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue().unwrapped()))
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
- return properties;
- }
-
- private Config embeddedneo4j(final Config config) {
- Config $embeddedNeo4j = config.getConfig("neo4j");
-
- if (config.hasPath("neo4j")) {
- $embeddedNeo4j = config.getConfig("neo4j").withFallback($embeddedNeo4j);
- }
- return $embeddedNeo4j;
- }
-}
\ No newline at end of file
diff --git a/modules/jooby-neo4j/src/main/java/org/jooby/embedded/neo4j/EmbeddedNeo4jSessionStore.java b/modules/jooby-neo4j/src/main/java/org/jooby/embedded/neo4j/EmbeddedNeo4jSessionStore.java
deleted file mode 100644
index 8392ed5360..0000000000
--- a/modules/jooby-neo4j/src/main/java/org/jooby/embedded/neo4j/EmbeddedNeo4jSessionStore.java
+++ /dev/null
@@ -1,255 +0,0 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-/**
- * This copy of Woodstox XML processor is licensed under the
- * Apache (Software) License, version 2.0 ("the License").
- * See the License for details about distribution rights, and the
- * specific rights regarding derivate works.
- *
- * You may obtain a copy of the License at:
- *
- * http://www.apache.org/licenses/
- *
- * A copy is also included in the downloadable source code package
- * containing Woodstox, in file "ASL2.0", under the same directory
- * as this file.
- */
-
-package org.jooby.embedded.neo4j;
-
-import com.google.inject.Inject;
-import com.google.inject.name.Named;
-import com.graphaware.neo4j.expire.ExpirationModule;
-import com.graphaware.neo4j.expire.config.ExpirationConfiguration;
-import com.graphaware.runtime.GraphAwareRuntime;
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigValueFactory;
-import org.jooby.Session;
-import org.neo4j.graphdb.GraphDatabaseService;
-import org.neo4j.graphdb.NotFoundException;
-import org.neo4j.graphdb.Transaction;
-import org.neo4j.graphdb.Label;
-import org.neo4j.graphdb.Node;
-
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.Optional;
-import java.util.concurrent.TimeUnit;
-
-import static java.util.Objects.requireNonNull;
-
-/**
- * A {@link Session.Store} powered by
- * Neo4j .
- *
- * usage
- *
- *
- * {
- *
- * session(EmbeddedNeo4jSessionStore.class);
- *
- * get("/", req {@literal ->} {
- * req.session().set("name", "jooby");
- * });
- * }
- *
- *
- * The name
attribute and value will be stored in a
- * Neo4j .
- *
- * options
- *
- * timeout
- *
- * By default, a neo4j session will expire after 30 minutes
. Changing the default
- * timeout is as simple as:
- *
- *
- *
- * # 8 hours
- * session.timeout = 8h
- *
- * # 15 seconds
- * session.timeout = 15
- *
- * # 120 minutes
- * session.timeout = 120m
- *
- *
- *
- * It uses GraphAware's Expire library to automatically remove
- * expired sessions.
- *
- *
- * If no timeout is required, use -1
.
- *
- * session label
- *
- * It's possible to provide the session label using the neo4j.session.label
- * properties.
- *
- *
- * @author sbcd90
- * @since 1.1.2
- */
-public class EmbeddedNeo4jSessionStore implements Session.Store {
-
- private static final char DOT = '.';
-
- private static final char UDOT = '\uFF0E';
-
- private static final char DOLLAR = '$';
-
- private static final char UDOLLAR = '\uFF04';
-
- protected final String sessionLabel;
-
- protected final long timeout;
-
- protected final GraphDatabaseService dbService;
- protected final GraphAwareRuntime graphRuntime;
-
- public EmbeddedNeo4jSessionStore(final GraphDatabaseService dbService, final GraphAwareRuntime graphRuntime,
- final String sessionLabel, final long timeoutInSeconds) {
- this.dbService = requireNonNull(dbService, "Neo4j Graph Database Service cannot be null");
- this.graphRuntime = requireNonNull(graphRuntime, "Neo4j Graph Aware Runtime cannot be null");
- this.sessionLabel = requireNonNull(sessionLabel, "Neo4j Label to store sessions is required");
- this.timeout = timeoutInSeconds;
-
- try {
- graphRuntime.getModule(ExpirationModule.class);
- } catch (NotFoundException ex) {
- ExpirationConfiguration configuration = ExpirationConfiguration.defaultConfiguration().withNodeExpirationProperty("_expire");
- graphRuntime.registerModule(new ExpirationModule("EXP", dbService, configuration));
- }
-
- this.graphRuntime.start();
- this.graphRuntime.waitUntilStarted();
- }
-
- @Inject
- public EmbeddedNeo4jSessionStore(final GraphDatabaseService dbService,
- final GraphAwareRuntime graphRuntime,
- final @Named("neo4j.session.label") String sessionLabel,
- final @Named("session.timeout") String timeout) {
- this(dbService, graphRuntime, sessionLabel, seconds(timeout));
- }
-
- @Override
- public Session get(Session.Builder builder) {
- try(Transaction tx = dbService.beginTx()) {
- return Optional.ofNullable(dbService.findNode(Label.label(sessionLabel), "_id", builder.sessionId()))
- .map(node -> {
- Map session = new LinkedHashMap<>(node.getAllProperties());
-
- Long accessedAt = (Long) session.remove("_accessedAt");
- Long createdAt = (Long) session.remove("_createdAt");
- Long savedAt = (Long) session.remove("_savedAt");
- session.remove("_id");
- session.remove("_expire");
-
- builder
- .accessedAt(accessedAt)
- .createdAt(createdAt)
- .savedAt(savedAt);
- session.forEach((k ,v) -> builder.set(decode(k), v.toString()));
- tx.success();
- return builder.build();
- }).orElse(null);
- }
- }
-
- @Override
- public void save(Session session) {
- String id = session.id();
- Map attributes = session.attributes();
-
- try(Transaction tx = dbService.beginTx()) {
- Optional.ofNullable(dbService.findNode(Label.label(sessionLabel), "_id", id))
- .map(node -> {
- node.setProperty("_accessedAt", session.accessedAt());
- node.setProperty("_createdAt", session.createdAt());
- node.setProperty("_savedAt", session.savedAt());
-
- attributes.forEach((k, v) -> node.setProperty(encode(k), v));
-
- if (!node.hasProperty("_expire")) {
- node.setProperty("_expire", System.currentTimeMillis() + timeout * 1000);
- }
-
- return node;
- }).orElseGet(() -> {
- Node node = dbService.createNode(Label.label(sessionLabel));
-
- node.setProperty("_accessedAt", session.accessedAt());
- node.setProperty("_createdAt", session.createdAt());
- node.setProperty("_savedAt", session.savedAt());
-
- attributes.forEach((k, v) -> node.setProperty(encode(k), v));
- node.setProperty("_expire", System.currentTimeMillis() + timeout * 1000);
-
- return node;
- });
- tx.success();
- }
- }
-
- @Override
- public void create(Session session) {
- save(session);
- }
-
- @Override
- public void delete(String id) {
- try(Transaction tx = dbService.beginTx()) {
- dbService.findNode(Label.label(sessionLabel), "_id", id).delete();
- tx.success();
- }
- }
-
- private static long seconds(final String value) {
- try {
- return Long.parseLong(value);
- } catch (NumberFormatException ex) {
- Config config = ConfigFactory.empty()
- .withValue("timeout", ConfigValueFactory.fromAnyRef(value));
- return config.getDuration("timeout", TimeUnit.SECONDS);
- } catch (NullPointerException ex) {
- return 1800L;
- }
- }
-
- private String encode(final String key) {
- String value = key;
- if (value.charAt(0) == DOLLAR) {
- value = UDOLLAR + value.substring(1);
- }
- return value.replace(DOT, UDOT);
- }
-
- private String decode(final String key) {
- String value = key;
- if (value.charAt(0) == UDOLLAR) {
- value = DOLLAR + value.substring(1);
- }
- return value.replace(UDOT, DOT);
- }
-}
\ No newline at end of file
diff --git a/modules/jooby-neo4j/src/main/java/org/jooby/neo4j/Neo4j.java b/modules/jooby-neo4j/src/main/java/org/jooby/neo4j/Neo4j.java
index 2ef72ee51e..b2681387ee 100644
--- a/modules/jooby-neo4j/src/main/java/org/jooby/neo4j/Neo4j.java
+++ b/modules/jooby-neo4j/src/main/java/org/jooby/neo4j/Neo4j.java
@@ -1,239 +1,245 @@
-/**
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements. See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership. The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License. You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied. See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
package org.jooby.neo4j;
+import static iot.jcypher.database.DBProperties.DATABASE_DIR;
+import static iot.jcypher.database.DBProperties.SERVER_ROOT_URI;
+import static java.util.Objects.requireNonNull;
+
+import java.io.IOException;
+import java.lang.reflect.Field;
+import java.nio.file.FileVisitResult;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.SimpleFileVisitor;
+import java.nio.file.attribute.BasicFileAttributes;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.concurrent.atomic.AtomicInteger;
+
+import org.jooby.Env;
+import org.jooby.Env.ServiceKey;
+import org.jooby.Jooby.Module;
+import org.neo4j.driver.v1.AuthTokens;
+import org.neo4j.driver.v1.Driver;
+import org.neo4j.driver.v1.GraphDatabase;
+import org.neo4j.driver.v1.Session;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
+import org.neo4j.graphdb.factory.GraphDatabaseFactory;
+import org.neo4j.logging.slf4j.Slf4jLogProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.bridge.SLF4JBridgeHandler;
+
import com.google.inject.Binder;
+import com.graphaware.runtime.RuntimeRegistry;
import com.typesafe.config.Config;
+import com.typesafe.config.ConfigException;
import com.typesafe.config.ConfigFactory;
-import iot.jcypher.database.DBAccessFactory;
+import com.typesafe.config.ConfigValue;
+import com.typesafe.config.ConfigValueFactory;
+import com.typesafe.config.ConfigValueType;
+
import iot.jcypher.database.DBProperties;
-import iot.jcypher.database.DBType;
+import iot.jcypher.database.IDBAccess;
+import iot.jcypher.database.embedded.AbstractEmbeddedDBAccess;
+import iot.jcypher.database.embedded.EmbeddedDBAccess;
import iot.jcypher.database.remote.BoltDBAccess;
-import org.jooby.Env;
-import org.jooby.Jooby;
-import java.util.AbstractMap;
-import java.util.Map;
-import java.util.Properties;
-import java.util.function.BiConsumer;
-import java.util.stream.Collectors;
+public class Neo4j implements Module {
-import static com.google.common.base.Preconditions.checkArgument;
-import static java.util.Objects.nonNull;
-import static java.util.Objects.requireNonNull;
+ static {
+ if (!SLF4JBridgeHandler.isInstalled()) {
+ SLF4JBridgeHandler.removeHandlersForRootLogger();
+ SLF4JBridgeHandler.install();
+ }
+ }
+
+ /** The logging system. */
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ private String db;
-/**
- * Exposes {@link BoltDBAccess}.
- *
- * usage
- *
- *
- * application.conf:
- *
- *
- *
- * db = "bolt://localhost:7687"
- *
- *
- *
- * {
- * use(new Neo4j());
- *
- * get("/", req {@literal ->} {
- * // work with db
- * DB = req.require(BoltDBAccess.class);
- * });
- * }
- *
- *
- * Default DB connection info property is db
but of course you can use any other name:
- *
- *
- * application.conf:
- *
- *
- *
- * mydb = "bolt://localhost:7687"
- *
- *
- *
- * {
- * use(new Neo4j("mydb"));
- *
- * get("/", req {@literal ->} {
- * DB mydb = req.require(DB.class);
- * // work with mydb
- * });
- * }
- *
- *
- * options
- *
- * Options can be set via .conf
file:
- *
- *
- *
- * neo4j.server_root_uri = "bolt://localhost:7687"
- *
- *
- *
- * or programmatically:
- *
- *
- *
- * {
- * use(new Neo4j()
- * .properties((properties, config) {@literal ->} {
- * properties.put(DBProperties.SERVER_ROOT_URI, config.get("server_root_uri"))
- * })
- * );
- * }
- *
- *
- *
- * Default connection URI is defined by the server_root_uri
property. Neo4j URI looks like:
- *
- *
- *
- * bolt://host1[:port1]
- *
- *
- *
- * Credentials have to be passed separately in username
& password
params.
- *
- *
- * two or more connections
- *
- *
- * db1 = "bolt://localhost:7687"
- * db2 = "bolt://localhost:7688"
- *
- *
- *
- * {
- * use(new Neo4j("db1"));
- * use(new Neo4j("db2"));
- *
- * get("/", req {@literal ->} {
- * BoltDBAccess client1 = req.require("mydb1", BoltDBAccess.class);
- * // work with mydb1
- * BoltDBAccess client2 = req.require("mydb2", BoltDBAccess.class);
- * // work with mydb1
- * });
- * }
- *
- *
- * @author sbcd90
- * @since 1.2.0
- */
-public class Neo4j implements Jooby.Module {
-
- private final String db;
-
- private BiConsumer properties;
-
- /**
- * Creates a new {@link Neo4j} module.
- *
- * @param db Name of the property with the connection info.
- */
public Neo4j(final String db) {
- this.db = requireNonNull(db, "A neo4j bolt configuration is required");
+ this.db = requireNonNull(db, "Database required.");
}
- /**
- * Creates a new {@link Neo4j} using the default property: db
.
- */
public Neo4j() {
this("db");
}
+ @SuppressWarnings({"unchecked", "rawtypes" })
@Override
- public void configure(final Env env, final Config config, final Binder binder) {
- Properties properties = options(neo4j(config));
+ public void configure(final Env env, final Config conf, final Binder binder) throws Throwable {
+ String db = database(conf, this.db);
+ Properties props = props(neo4j(conf, this.db));
- if (nonNull(this.properties)) {
- this.properties.accept(properties, config);
- }
+ ServiceKey keys = env.serviceKey();
+ IDBAccess dbaccess = dbaccess(conf, this.db, db, props, keys, binder);
- String dbUser = nonNull(properties.getProperty("username")) ? properties.getProperty("username"): "";
- String dbPassword = nonNull(properties.getProperty("password")) ? properties.getProperty("password"): "";
+ Arrays.asList(props.getProperty(SERVER_ROOT_URI), props.getProperty(DATABASE_DIR))
+ .stream()
+ .filter(Objects::nonNull)
+ .findFirst()
+ .ifPresent(it -> log.info("Starting neo4j: {}", it));
- BoltDBAccess remoteClient;
- if (dbUser.isEmpty() && dbPassword.isEmpty()) {
- remoteClient = (BoltDBAccess) DBAccessFactory.createDBAccess(DBType.REMOTE, properties);
- } else {
- remoteClient = (BoltDBAccess) DBAccessFactory.createDBAccess(DBType.REMOTE, properties, dbUser, dbPassword);
- }
- checkArgument(remoteClient.getSession() != null,
- "Cannot connect to Database at: " + properties.get(DBProperties.SERVER_ROOT_URI));
- String database = properties.getProperty(DBProperties.SERVER_ROOT_URI);
+ Class dbaccessType = dbaccess.getClass();
+ keys.generate(IDBAccess.class, this.db, k -> binder.bind(k).toInstance(dbaccess));
+ keys.generate(dbaccessType, this.db, k -> binder.bind(k).toInstance(dbaccess));
- Env.ServiceKey serviceKey = env.serviceKey();
- serviceKey.generate(BoltDBAccess.class, database, k -> binder.bind(k).toInstance(remoteClient));
+ env.onStop(dbaccess::close);
+ }
- env.onStop(remoteClient::close);
+ @Override
+ public Config config() {
+ return ConfigFactory.empty(getClass().getName().toLowerCase() + ".conf")
+ .withValue("neo4j.session.label", ConfigValueFactory.fromAnyRef("session"));
}
- /**
- * Set a properties callback.
- *
- *
- * {
- * use(new Neo4j()
- * .properties((properties, config) {@literal ->} {
- * properties.put(DBProperties.ARRAY_BLOCK_SIZE, "120);
- * })
- * );
- * }
- *
- *
- * @param properties Configure callback.
- * @return This module
- */
- public Neo4j properties(final BiConsumer properties) {
- this.properties = requireNonNull(properties, "properties callback is required");
- return this;
+ private Config neo4j(final Config conf, final String db) {
+ Config result = conf.hasPath("com.graphaware")
+ ? ConfigFactory.empty().withValue("com.graphaware", conf.getConfig("com.graphaware").root())
+ : ConfigFactory.empty();
+ String[] paths = {"neo4j", db, "neo4j." + db };
+ for (String path : paths) {
+ try {
+ if (conf.hasPath(path)) {
+ Config it = conf.getConfig(path);
+ result = it.withFallback(result);
+ }
+ } catch (ConfigException x) {
+ // Skip/ignore bad path
+ }
+ }
+ return result;
}
- @Override
- public Config config() {
- return ConfigFactory.parseResources(Neo4j.class, "neo4j.conf");
+ @SuppressWarnings("deprecation")
+ private IDBAccess dbaccess(final Config conf, final String dbkey, final String db,
+ final Properties props, final Env.ServiceKey keys, final Binder binder) throws Exception {
+ // remote
+ if (db.startsWith("bolt")) {
+ String username = conf.getString(dbkey + ".user");
+ String password = conf.getString(dbkey + ".password");
+ Driver driver = GraphDatabase.driver(db, AuthTokens.basic(username, password));
+ Session session = driver.session();
+ props.setProperty(DBProperties.SERVER_ROOT_URI, db);
+ keys.generate(Driver.class, dbkey, k -> binder.bind(k).toInstance(driver));
+ keys.generate(Session.class, dbkey, k -> binder.bind(k).toInstance(session));
+ BoltDBAccess dbaccess = new BoltDBAccess();
+ dbaccess.initialize(props);
+ driverhack(dbaccess, driver);
+ return dbaccess;
+ }
+ boolean mem = db.equals("mem");
+ Path path = (db.equals("fs") || mem
+ ? Paths.get(conf.getString("application.tmpdir")).resolve("neo4j" + db)
+ : Paths.get(db)).toAbsolutePath();
+ props.setProperty(DBProperties.DATABASE_DIR, path.toString());
+ if (mem) {
+ // clean up existing database
+ rm(path);
+ }
+ GraphDatabaseBuilder builder = new GraphDatabaseFactory()
+ .setUserLogProvider(new Slf4jLogProvider())
+ .newEmbeddedDatabaseBuilder(path.toFile());
+ props.forEach((k, v) -> builder.setConfig(k.toString(), v.toString()));
+ GraphDatabaseService graphDatabaseService = builder.newGraphDatabase();
+ RuntimeRegistry.getStartedRuntime(graphDatabaseService);
+ keys.generate(GraphDatabaseService.class, dbkey,
+ k -> binder.bind(k).toInstance(graphDatabaseService));
+
+ EmbeddedDBAccess dbaccess = new EmbeddedDBAccess();
+ dbaccess.initialize(props);
+ dbServicehack(dbaccess, graphDatabaseService);
+
+ return dbaccess;
}
- private Properties options(final Config config) {
- Properties properties = new Properties();
- properties.putAll(config.entrySet()
- .stream()
- .map(entry -> new AbstractMap.SimpleEntry<>(entry.getKey(), entry.getValue().unwrapped()))
- .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)));
+ private String database(final Config conf, final String db) {
+ String[] paths = {db + ".url", db };
+ for (String path : paths) {
+ if (conf.hasPath(path)) {
+ return conf.getString(path);
+ }
+ }
+ if (db.equals("db")) {
+ throw new ConfigException.Missing(db);
+ }
+ // path
+ return db;
+ }
+
+ private Properties props(final Config conf) {
+ Properties props = new Properties();
+ conf.entrySet().stream()
+ .filter(it -> !it.getKey().startsWith("com.graphaware.module"))
+ .forEach(prop -> {
+ String key = prop.getKey();
+ Object value = prop.getValue().unwrapped();
+ props.put(key, value);
+ });
+ // write module:
+ if (conf.hasPath("com.graphaware.module")) {
+ ConfigValue raw = conf.getValue("com.graphaware.module");
+ List modules = new ArrayList<>();
+ if (raw.valueType() == ConfigValueType.LIST) {
+ modules.addAll(conf.getConfigList("com.graphaware.module"));
+ } else {
+ modules.add(conf.getConfig("com.graphaware.module"));
+ }
+ AtomicInteger nextOrder = new AtomicInteger(0);
+ modules.forEach(module -> {
+ String type = module.getString("class");
+ int order = nextOrder.incrementAndGet();
+ String key = "com.graphaware.module.m" + order;
+ props.put(key + "." + order, type);
+ module.withoutPath("class").root()
+ .forEach((k, v) -> props.put(key + "." + k, v.unwrapped().toString()));
+ });
+ }
+ log.debug("neo4j properties: {}", props);
+ return props;
+ }
+
+ static void driverhack(final BoltDBAccess dbaccess, final Driver value) throws Exception {
+ fieldhack(BoltDBAccess.class, dbaccess, "driver", value);
+ }
- return properties;
+ static void dbServicehack(final EmbeddedDBAccess dbaccess, final GraphDatabaseService value)
+ throws Exception {
+ fieldhack(AbstractEmbeddedDBAccess.class, dbaccess, "graphDb", value);
}
- private Config neo4j(final Config config) {
- Config $neo4j = config.getConfig("neo4j");
+ @SuppressWarnings("rawtypes")
+ static void fieldhack(final Class owner, final Object instance, final String name,
+ final Object value) throws Exception {
+ Field field = owner.getDeclaredField(name);
+ field.setAccessible(true);
+ field.set(instance, value);
+ }
- if (config.hasPath("neo4j." + db)) {
- $neo4j = config.getConfig("neo4j." + db).withFallback($neo4j);
+ static void rm(final Path path) throws IOException {
+ if (Files.exists(path)) {
+ Files.walkFileTree(path, new SimpleFileVisitor() {
+ @Override
+ public FileVisitResult visitFile(final Path file, final BasicFileAttributes attrs)
+ throws IOException {
+ Files.delete(file);
+ return FileVisitResult.CONTINUE;
+ }
+
+ @Override
+ public FileVisitResult postVisitDirectory(final Path dir, final IOException exc)
+ throws IOException {
+ Files.delete(dir);
+ return FileVisitResult.CONTINUE;
+ }
+
+ });
}
- return $neo4j;
}
-}
\ No newline at end of file
+}
diff --git a/modules/jooby-neo4j/src/main/java/org/jooby/neo4j/Neo4jSessionStore.java b/modules/jooby-neo4j/src/main/java/org/jooby/neo4j/Neo4jSessionStore.java
index 7ffe36198f..940c0f1c11 100644
--- a/modules/jooby-neo4j/src/main/java/org/jooby/neo4j/Neo4jSessionStore.java
+++ b/modules/jooby-neo4j/src/main/java/org/jooby/neo4j/Neo4jSessionStore.java
@@ -19,31 +19,41 @@
package org.jooby.neo4j;
-import com.graphaware.neo4j.expire.ExpirationModule;
-import com.graphaware.neo4j.expire.config.ExpirationConfiguration;
-import com.graphaware.runtime.GraphAwareRuntime;
-import com.graphaware.runtime.GraphAwareRuntimeFactory;
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigValueFactory;
-import org.apache.commons.lang3.tuple.Pair;
-import org.jooby.Session;
-import org.neo4j.graphdb.GraphDatabaseService;
-import org.neo4j.graphdb.Label;
-import org.neo4j.graphdb.Node;
-import org.neo4j.graphdb.Transaction;
-import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
-import org.neo4j.graphdb.factory.GraphDatabaseFactory;
+import static java.util.Objects.requireNonNull;
-import javax.inject.Inject;
-import javax.inject.Named;
-import java.io.File;
-import java.util.LinkedHashMap;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
import java.util.Map;
-import java.util.Optional;
+import java.util.Set;
import java.util.concurrent.TimeUnit;
+import java.util.function.LongSupplier;
+import java.util.stream.Collectors;
-import static java.util.Objects.requireNonNull;
+import javax.inject.Inject;
+import javax.inject.Named;
+
+import org.jooby.Session;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.google.common.collect.ImmutableSet;
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigValueFactory;
+
+import iot.jcypher.database.IDBAccess;
+import iot.jcypher.graph.GrNode;
+import iot.jcypher.graph.GrProperty;
+import iot.jcypher.query.JcQuery;
+import iot.jcypher.query.JcQueryResult;
+import iot.jcypher.query.api.IClause;
+import iot.jcypher.query.api.pattern.Node;
+import iot.jcypher.query.factories.clause.CREATE;
+import iot.jcypher.query.factories.clause.DO;
+import iot.jcypher.query.factories.clause.MATCH;
+import iot.jcypher.query.factories.clause.RETURN;
+import iot.jcypher.query.values.JcNode;
/**
* A {@link Session.Store} powered by
@@ -102,110 +112,132 @@
*/
public class Neo4jSessionStore implements Session.Store {
- private static final char DOT = '.';
+ private final Set SPECIAL = ImmutableSet.of("_accessedAt", "_createdAt", "_savedAt",
+ "_expire", "_id");
- private static final char UDOT = '\uFF0E';
+ /** The logging system. */
+ private final Logger log = LoggerFactory.getLogger(getClass());
- private static final char DOLLAR = '$';
+ private final String label;
- private static final char UDOLLAR = '\uFF04';
+ private final LongSupplier expire;
- protected final String sessionLabel;
+ private final IDBAccess db;
- protected final long timeout;
-
- private static GraphDatabaseService dbService;
- private static GraphAwareRuntime graphRuntime;
-
- protected final GraphDatabaseService db;
- protected final GraphAwareRuntime graphAwareRuntime;
-
-
- public Neo4jSessionStore(Pair graph, final String sessionLabel,
- final long timeoutInSeconds) {
- this.db = requireNonNull(graph.getLeft(), "GraphDatabaseService instance is required");
- this.graphAwareRuntime = requireNonNull(graph.getRight(), "GraphAwareRuntime instance is required");
- this.sessionLabel = requireNonNull(sessionLabel, "Label to store sessions is required");
- this.timeout = timeoutInSeconds;
+ public Neo4jSessionStore(final IDBAccess dbaccess, final String sessionLabel,
+ final long timeoutInSeconds) {
+ this.db = dbaccess;
+ this.label = requireNonNull(sessionLabel, "Label to store sessions is required");
+ long expire = TimeUnit.SECONDS.toMillis(timeoutInSeconds);
+ this.expire = () -> System.currentTimeMillis() + expire;
}
@Inject
- public Neo4jSessionStore(@Named("databaseDir") String databaseDir,
- final @Named("neo4j.session.label") String sessionLabel,
- final @Named("session.timeout") String timeout) {
- this(getOrCreateGraph(databaseDir), sessionLabel, seconds(timeout));
+ public Neo4jSessionStore(final IDBAccess dbaccess,
+ final @Named("neo4j.session.label") String sessionLabel,
+ final @Named("session.timeout") String timeout) {
+ this(dbaccess, sessionLabel, seconds(timeout));
}
@Override
public Session get(final Session.Builder builder) {
- try(Transaction tx = db.beginTx()) {
- return Optional.ofNullable(db.findNode(Label.label(sessionLabel), "_id", builder.sessionId()))
- .map(node -> {
- Map session = new LinkedHashMap<>(node.getAllProperties());
-
- Long accessedAt = (Long) session.remove("_accessedAt");
- Long createdAt = (Long) session.remove("_createdAt");
- Long savedAt = (Long) session.remove("_savedAt");
- session.remove("_id");
- session.remove("_expire");
-
- builder
- .accessedAt(accessedAt)
- .createdAt(createdAt)
- .savedAt(savedAt);
- session.forEach((k, v) -> builder.set(decode(k), v.toString()));
- tx.success();
- return builder.build();
- }).orElse(null);
+ String sid = builder.sessionId();
+ JcNode node = new JcNode("n");
+ JcQuery query = new JcQuery();
+ query.setClauses(new IClause[]{
+ MATCH.node(node).label(label).property("_id").value(sid),
+ // touch session
+ DO.SET(node.property("_expire")).to(expire.getAsLong()),
+ RETURN.value(node)
+ });
+
+ List result = db.execute(query).resultOf(node);
+ log.debug("touch {} session {} ", sid, result);
+ if (result.size() == 1) {
+ GrNode found = result.get(0);
+ builder
+ .accessedAt(((Number) found.getProperty("_accessedAt").getValue()).longValue())
+ .createdAt(((Number) found.getProperty("_createdAt").getValue()).longValue())
+ .savedAt(((Number) found.getProperty("_savedAt").getValue()).longValue());
+
+ found.getProperties()
+ .stream()
+ .filter(it -> !SPECIAL.contains(it.getName()))
+ .forEach(p -> builder.set(p.getName(), p.getValue().toString()));
+
+ return builder.build();
}
+
+ return null;
}
@Override
public void save(final Session session) {
- String id = session.id();
- Map attributes = session.attributes();
-
- try(Transaction tx = db.beginTx()) {
- Optional.ofNullable(db.findNode(Label.label(sessionLabel), "_id", id))
- .map(node -> {
- node.setProperty("_accessedAt", session.accessedAt());
- node.setProperty("_createdAt", session.createdAt());
- node.setProperty("_savedAt", session.savedAt());
-
- attributes.forEach((k ,v) -> node.setProperty(encode(k), v));
-
- if (!node.hasProperty("_expire")) {
- node.setProperty("_expire", System.currentTimeMillis() + timeout * 1000);
- }
-
- return node;
- }).orElseGet(() -> {
- Node node = db.createNode(Label.label(sessionLabel));
-
- node.setProperty("_accessedAt", session.accessedAt());
- node.setProperty("_createdAt", session.createdAt());
- node.setProperty("_savedAt", session.savedAt());
-
- attributes.forEach((k, v) -> node.setProperty(encode(k), v));
- node.setProperty("_expire", System.currentTimeMillis() + timeout * 1000);
-
- return node;
+ String sid = session.id();
+ Map attributes = new HashMap<>(session.attributes());
+
+ JcNode node = new JcNode("n");
+ JcQuery query = new JcQuery();
+ List clauses = new ArrayList<>();
+ clauses.add(MATCH.node(node).label(label).property("_id").value(sid));
+ attributes.put("_accessedAt", session.accessedAt());
+ attributes.put("_createdAt", session.createdAt());
+ attributes.put("_savedAt", session.savedAt());
+ attributes.put("_expire", expire.getAsLong());
+ attributes.forEach((k, v) -> {
+ clauses.add(DO.SET(node.property(k)).to(v));
+ });
+ clauses.add(RETURN.value(node));
+
+ query.setClauses(clauses.toArray(new IClause[clauses.size()]));
+ List nodes = db.execute(query).resultOf(node);
+ if (nodes.size() == 1) {
+ GrNode found = nodes.get(0);
+ Set keys = found.getProperties().stream()
+ .map(GrProperty::getName)
+ .collect(Collectors.toSet());
+ keys.removeAll(attributes.keySet());
+ // unset properties
+ if (keys.size() > 0) {
+ log.debug("removing {} => {}", sid, keys);
+ JcQuery unsetQuery = new JcQuery();
+ List unsetClauses = new ArrayList<>();
+ unsetClauses.add(MATCH.node(node).label(label).property("_id").value(sid));
+ keys.forEach(key -> unsetClauses.add(DO.REMOVE(node.property(key))));
+ unsetQuery.setClauses(unsetClauses.toArray(new IClause[unsetClauses.size()]));
+ db.execute(unsetQuery);
+ }
+ log.debug("saved {} => {}", sid, nodes);
+ } else {
+ // create session:
+ query = new JcQuery();
+ Node create = CREATE.node(node).label(label);
+ attributes.put("_id", sid);
+ attributes.forEach((k, v) -> {
+ create.property(k).value(v);
});
- tx.success();
+
+ query.setClauses(new IClause[]{create });
+ List result = db.execute(query).resultOf(node);
+ log.debug("created {} => {}", sid, result);
}
}
@Override
- public void create(Session session) {
+ public void create(final Session session) {
save(session);
}
@Override
- public void delete(String id) {
- try(Transaction tx = db.beginTx()) {
- db.findNode(Label.label(sessionLabel), "_id", id).delete();
- tx.success();
- }
+ public void delete(final String id) {
+ JcNode session = new JcNode("n");
+ JcQuery q = new JcQuery();
+ q.setClauses(new IClause[]{
+ MATCH.node(session).label(label).property("_id").value(id),
+ DO.DELETE(session)
+ });
+ JcQueryResult rsp = db.execute(q);
+ log.debug("destroyed {} => {}", id, rsp);
}
private static long seconds(final String value) {
@@ -213,43 +245,8 @@ private static long seconds(final String value) {
return Long.parseLong(value);
} catch (NumberFormatException ex) {
Config config = ConfigFactory.empty()
- .withValue("timeout", ConfigValueFactory.fromAnyRef(value));
+ .withValue("timeout", ConfigValueFactory.fromAnyRef(value));
return config.getDuration("timeout", TimeUnit.SECONDS);
- } catch (NullPointerException ex) {
- return 1800L;
- }
- }
-
- private String encode(final String key) {
- String value = key;
- if (value.charAt(0) == DOLLAR) {
- value = UDOLLAR + value.substring(1);
- }
- return value.replace(DOT, UDOT);
- }
-
- private String decode(final String key) {
- String value = key;
- if (value.charAt(0) == UDOLLAR) {
- value = DOLLAR + value.substring(1);
- }
- return value.replace(UDOT, DOT);
- }
-
- private static Pair getOrCreateGraph(String databaseDir) {
- if (dbService == null && graphRuntime == null) {
- GraphDatabaseBuilder builder = new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(new File(databaseDir));
- dbService = builder.newGraphDatabase();
- graphRuntime = GraphAwareRuntimeFactory.createRuntime(dbService);
-
- ExpirationConfiguration configuration = ExpirationConfiguration.defaultConfiguration().withNodeExpirationProperty("_expire");
- graphRuntime.registerModule(new ExpirationModule("EXP", dbService, configuration));
-
- graphRuntime.start();
- graphRuntime.waitUntilStarted();
-
- return Pair.of(dbService, graphRuntime);
}
- return Pair.of(dbService, graphRuntime);
}
-}
\ No newline at end of file
+}
diff --git a/modules/jooby-neo4j/src/test/java/apps/embedded/neo4j/EmbeddedNeo4jApp.java b/modules/jooby-neo4j/src/test/java/apps/embedded/neo4j/EmbeddedNeo4jApp.java
deleted file mode 100644
index c166af760f..0000000000
--- a/modules/jooby-neo4j/src/test/java/apps/embedded/neo4j/EmbeddedNeo4jApp.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package apps.embedded.neo4j;
-
-import org.jooby.Jooby;
-import org.jooby.Session;
-import org.jooby.embedded.neo4j.EmbeddedNeo4j;
-import org.jooby.embedded.neo4j.EmbeddedNeo4jSessionStore;
-
-import java.util.concurrent.atomic.AtomicInteger;
-
-public class EmbeddedNeo4jApp extends Jooby {
-
- {
-
- conf("embedded/application.conf");
-
- use(new EmbeddedNeo4j());
-
- AtomicInteger inc = new AtomicInteger(0);
- session(EmbeddedNeo4jSessionStore.class);
-
- get("/", req -> {
- Session session = req.ifSession().orElseGet(() -> {
- Session newSession = req.session();
- int next = newSession.get("inc").intValue(inc.getAndIncrement());
- newSession.set("inc", next);
- return newSession;
- });
- return session.get("inc");
- });
- }
-
- public static void main(String[] args) {
- run(EmbeddedNeo4jApp::new, args);
- }
-}
\ No newline at end of file
diff --git a/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jBoltApp.java b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jBoltApp.java
new file mode 100644
index 0000000000..cac86b666e
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jBoltApp.java
@@ -0,0 +1,30 @@
+package apps.neo4j;
+
+import org.jooby.Jooby;
+import org.jooby.neo4j.Neo4j;
+
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigValueFactory;
+
+import iot.jcypher.database.remote.BoltDBAccess;
+
+public class Neo4jBoltApp extends Jooby {
+
+ {
+ use(ConfigFactory.empty()
+ .withValue("db.url", ConfigValueFactory.fromAnyRef("bolt://localhost:7687"))
+ .withValue("db.user", ConfigValueFactory.fromAnyRef("neo4j"))
+ .withValue("db.password", ConfigValueFactory.fromAnyRef("development")));
+
+ use(new Neo4j());
+
+ onStart(() -> {
+ System.out.println(require(BoltDBAccess.class).getSession());
+ });
+
+ }
+
+ public static void main(final String[] args) {
+ run(Neo4jBoltApp::new, args);
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jBoltSessionApp.java b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jBoltSessionApp.java
new file mode 100644
index 0000000000..d40739c4a9
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jBoltSessionApp.java
@@ -0,0 +1,57 @@
+package apps.neo4j;
+
+import org.jooby.Jooby;
+import org.jooby.Session;
+import org.jooby.neo4j.Neo4j;
+import org.jooby.neo4j.Neo4jSessionStore;
+
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigValueFactory;
+
+import iot.jcypher.database.IDBAccess;
+
+public class Neo4jBoltSessionApp extends Jooby {
+
+ {
+ use(ConfigFactory.empty()
+ .withValue("db.url", ConfigValueFactory.fromAnyRef("bolt://localhost:7687"))
+ .withValue("db.user", ConfigValueFactory.fromAnyRef("neo4j"))
+ .withValue("db.password", ConfigValueFactory.fromAnyRef("development")));
+
+ use(new Neo4j());
+
+ session(Neo4jSessionStore.class);
+
+ get("/set", req -> {
+ String attr = req.param("attr").value("foo");
+ Session session = req.session();
+ session.set("attr", attr);
+ return attr;
+ });
+
+ get("/get", req -> {
+ Session session = req.session();
+ return session.get("attr").value();
+ });
+
+ get("/remove", req -> {
+ Session session = req.session();
+ return session.unset("attr").value();
+ });
+
+ get("/clear", req -> {
+ IDBAccess db = require(IDBAccess.class);
+ db.clearDatabase();
+ return "done";
+ });
+
+ get("/destroy", req -> {
+ req.session().destroy();
+ return "destroy";
+ });
+ }
+
+ public static void main(final String[] args) {
+ run(Neo4jBoltSessionApp::new, args);
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jFsApp.java b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jFsApp.java
new file mode 100644
index 0000000000..919ae6a866
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jFsApp.java
@@ -0,0 +1,28 @@
+package apps.neo4j;
+
+import org.jooby.Jooby;
+import org.jooby.neo4j.Neo4j;
+import org.neo4j.graphdb.GraphDatabaseService;
+
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigValueFactory;
+
+public class Neo4jFsApp extends Jooby {
+
+ {
+ use(ConfigFactory.empty()
+ .withValue("com.graphaware.runtime.enabled", ConfigValueFactory.fromAnyRef(true))
+ .withValue("db", ConfigValueFactory.fromAnyRef("fs")));
+
+ use(new Neo4j("target/localdb"));
+
+ onStart(() -> {
+ System.out.println(require(GraphDatabaseService.class));
+ });
+
+ }
+
+ public static void main(final String[] args) {
+ run(Neo4jFsApp::new, args);
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jFsApp2.java b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jFsApp2.java
new file mode 100644
index 0000000000..a7f75fc613
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jFsApp2.java
@@ -0,0 +1,21 @@
+package apps.neo4j;
+
+import org.jooby.Jooby;
+import org.jooby.neo4j.Neo4j;
+import org.neo4j.graphdb.GraphDatabaseService;
+
+public class Neo4jFsApp2 extends Jooby {
+
+ {
+ use(new Neo4j("fs"));
+
+ onStart(() -> {
+ System.out.println(require(GraphDatabaseService.class));
+ });
+
+ }
+
+ public static void main(final String[] args) {
+ run(Neo4jFsApp2::new, args);
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jInMemoryApp.java b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jInMemoryApp.java
new file mode 100644
index 0000000000..6e12d46875
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jInMemoryApp.java
@@ -0,0 +1,26 @@
+package apps.neo4j;
+
+import org.jooby.Jooby;
+import org.jooby.neo4j.Neo4j;
+import org.neo4j.graphdb.GraphDatabaseService;
+
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigValueFactory;
+
+public class Neo4jInMemoryApp extends Jooby {
+
+ {
+ use(ConfigFactory.empty()
+ .withValue("db", ConfigValueFactory.fromAnyRef("mem")));
+ use(new Neo4j());
+
+ onStart(() -> {
+ System.out.println(require(GraphDatabaseService.class));
+ });
+
+ }
+
+ public static void main(final String[] args) {
+ run(Neo4jInMemoryApp::new, args);
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jInMemoryApp2.java b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jInMemoryApp2.java
new file mode 100644
index 0000000000..f6ffd1aba4
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jInMemoryApp2.java
@@ -0,0 +1,21 @@
+package apps.neo4j;
+
+import org.jooby.Jooby;
+import org.jooby.neo4j.Neo4j;
+import org.neo4j.graphdb.GraphDatabaseService;
+
+public class Neo4jInMemoryApp2 extends Jooby {
+
+ {
+ use(new Neo4j("mem"));
+
+ onStart(() -> {
+ System.out.println(require(GraphDatabaseService.class));
+ });
+
+ }
+
+ public static void main(final String[] args) {
+ run(Neo4jInMemoryApp2::new, args);
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jSessionApp.java b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jSessionApp.java
new file mode 100644
index 0000000000..9f0c763b28
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jSessionApp.java
@@ -0,0 +1,61 @@
+package apps.neo4j;
+
+import org.jooby.Jooby;
+import org.jooby.Session;
+import org.jooby.neo4j.Neo4j;
+import org.jooby.neo4j.Neo4jSessionStore;
+
+import com.google.common.collect.ImmutableMap;
+import com.graphaware.neo4j.expire.ExpirationModuleBootstrapper;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigValueFactory;
+
+import iot.jcypher.database.IDBAccess;
+
+public class Neo4jSessionApp extends Jooby {
+
+ {
+ use(ConfigFactory.empty()
+ .withValue("session.timeout", ConfigValueFactory.fromAnyRef(30))
+ .withValue("com.graphaware.runtime.enabled", ConfigValueFactory.fromAnyRef(true))
+ .withValue("com.graphaware.module", ConfigValueFactory.fromAnyRef(
+ (ImmutableMap.of("class", ExpirationModuleBootstrapper.class.getName(),
+ "nodeExpirationProperty", "_expire")))));
+
+ use(new Neo4j("mem"));
+
+ session(Neo4jSessionStore.class);
+
+ get("/set", req -> {
+ String attr = req.param("attr").value("foo");
+ Session session = req.session();
+ session.set("attr", attr);
+ return attr;
+ });
+
+ get("/get", req -> {
+ Session session = req.session();
+ return session.get("attr").value();
+ });
+
+ get("/unset", req -> {
+ Session session = req.session();
+ return session.unset("attr").value();
+ });
+
+ get("/clear", req -> {
+ IDBAccess db = require(IDBAccess.class);
+ db.clearDatabase();
+ return "done";
+ });
+
+ get("/destroy", req -> {
+ req.session().destroy();
+ return "destroy";
+ });
+ }
+
+ public static void main(final String[] args) {
+ run(Neo4jSessionApp::new, args);
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jWrongApp.java b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jWrongApp.java
new file mode 100644
index 0000000000..0eafcb9c6a
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/apps/neo4j/Neo4jWrongApp.java
@@ -0,0 +1,15 @@
+package apps.neo4j;
+
+import org.jooby.Jooby;
+import org.jooby.neo4j.Neo4j;
+
+public class Neo4jWrongApp extends Jooby {
+
+ {
+ use(new Neo4j());
+ }
+
+ public static void main(final String[] args) {
+ run(Neo4jWrongApp::new, args);
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/org/jooby/embedded/neo4j/EmbeddedNeo4jSessionStoreTest.java b/modules/jooby-neo4j/src/test/java/org/jooby/embedded/neo4j/EmbeddedNeo4jSessionStoreTest.java
deleted file mode 100644
index ce8d2dd520..0000000000
--- a/modules/jooby-neo4j/src/test/java/org/jooby/embedded/neo4j/EmbeddedNeo4jSessionStoreTest.java
+++ /dev/null
@@ -1,242 +0,0 @@
-package org.jooby.embedded.neo4j;
-
-import com.google.common.collect.ImmutableMap;
-import com.graphaware.neo4j.expire.ExpirationModule;
-import com.graphaware.runtime.GraphAwareRuntime;
-import org.jooby.Session;
-import org.jooby.test.MockUnit;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.neo4j.graphdb.GraphDatabaseService;
-import org.neo4j.graphdb.Label;
-import org.neo4j.graphdb.Node;
-import org.neo4j.graphdb.Transaction;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-import java.util.Collections;
-import java.util.LinkedHashMap;
-import java.util.Map;
-import java.util.function.BiConsumer;
-
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.isA;
-import static org.junit.Assert.assertEquals;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({EmbeddedNeo4jSessionStore.class, LinkedHashMap.class, ExpirationModule.class})
-public class EmbeddedNeo4jSessionStoreTest {
- private static GraphDatabaseService dbService;
- private static GraphAwareRuntime graphAwareRuntime;
- private static Session.Builder sb;
-
- @SuppressWarnings("unchecked")
- MockUnit.Block boot = unit -> {
- dbService = unit.get(GraphDatabaseService.class);
- graphAwareRuntime = unit.get(GraphAwareRuntime.class);
- ExpirationModule expirationModule = unit.get(ExpirationModule.class);
- expect(graphAwareRuntime.getModule(isA(ExpirationModule.class.getClass()))).andReturn(expirationModule);
- graphAwareRuntime.start();
- expectLastCall();
- graphAwareRuntime.waitUntilStarted();
- expectLastCall();
- };
-
- long now = System.currentTimeMillis();
-
- Map attrs = ImmutableMap.of("k.v", "v", "$d", "d");
- Map properties;
-
- MockUnit.Block saveSession = unit -> {
-
- Session session = unit.get(Session.class);
- expect(session.id()).andReturn("1234");
- expect(session.accessedAt()).andReturn(now);
- expect(session.createdAt()).andReturn(now);
- expect(session.savedAt()).andReturn(now);
- expect(session.attributes()).andReturn(attrs);
-
- Node node = unit.mock(Node.class);
- node.setProperty(isA(String.class), isA(Object.class));
- expectLastCall().anyTimes();
- expect(node.hasProperty(isA(String.class))).andReturn(false);
- expect(dbService.findNode(isA(Label.class), isA(String.class), isA(Object.class))).andReturn(node);
- };
-
- MockUnit.Block updateSession = unit -> {
-
- Session session = unit.get(Session.class);
- expect(session.id()).andReturn("1234");
- expect(session.accessedAt()).andReturn(now);
- expect(session.createdAt()).andReturn(now);
- expect(session.savedAt()).andReturn(now);
- expect(session.attributes()).andReturn(attrs);
-
- Node node = unit.mock(Node.class);
- node.setProperty(isA(String.class), isA(Object.class));
- expectLastCall().anyTimes();
- expect(dbService.findNode(isA(Label.class), isA(String.class), isA(Object.class))).andReturn(null);
- expect(dbService.createNode(isA(Label.class))).andReturn(node);
- };
-
- @SuppressWarnings("unchecked")
- MockUnit.Block getFromSession = unit -> {
- long now = System.currentTimeMillis();
-
- Node node = unit.mock(Node.class);
- expect(node.getAllProperties()).andReturn(properties);
-
- Map sessionMap = unit.constructor(LinkedHashMap.class)
- .args(Map.class).build(properties);
-
- expect(sessionMap.remove("_accessedAt")).andReturn(now);
- expect(sessionMap.remove("_createdAt")).andReturn(now);
- expect(sessionMap.remove("_savedAt")).andReturn(now);
- expect(sessionMap.remove("_id")).andReturn(now);
- expect(sessionMap.remove("_expire")).andReturn(null);
- sessionMap.forEach(unit.capture(BiConsumer.class));
-
- sb = unit.mock(Session.Builder.class);
- expect(sb.sessionId()).andReturn("1234");
- expect(sb.accessedAt(now)).andReturn(sb);
- expect(sb.createdAt(now)).andReturn(sb);
- expect(sb.savedAt(now)).andReturn(sb);
-
- Map.Entry property = properties.entrySet().iterator().next();
- expect(sb.set(property.getKey(), property.getValue().toString())).andReturn(sb);
-
- expect(sb.build()).andReturn(unit.get(Session.class));
- expect(dbService.findNode(isA(Label.class), isA(String.class), isA(Object.class))).andReturn(node);
- };
-
- MockUnit.Block handleTransaction = unit -> {
- Transaction t = unit.mock(Transaction.class);
- t.success();
- expectLastCall();
- t.close();
- expectLastCall();
- expect(dbService.beginTx()).andReturn(t);
- };
-
- @Test
- public void defaults() throws Exception {
- new MockUnit(GraphDatabaseService.class, GraphAwareRuntime.class, ExpirationModule.class)
- .expect(boot)
- .run(unit -> {
- new EmbeddedNeo4jSessionStore(dbService, graphAwareRuntime, "sess", 60L);
- });
- }
-
- @Test(expected = NullPointerException.class)
- public void defaultsNullDB() throws Exception {
- new EmbeddedNeo4jSessionStore(null, null, "sess", 60L);
- }
-
- @Test
- public void create() throws Exception {
- new MockUnit(Session.class, GraphDatabaseService.class, GraphAwareRuntime.class, ExpirationModule.class)
- .expect(boot)
- .expect(saveSession)
- .expect(handleTransaction)
- .run(unit -> {
- new EmbeddedNeo4jSessionStore(dbService, graphAwareRuntime, "sess", 60L)
- .create(unit.get(Session.class));
- });
- }
-
- @Test
- public void save() throws Exception {
- new MockUnit(Session.class, GraphDatabaseService.class, GraphAwareRuntime.class, ExpirationModule.class)
- .expect(boot)
- .expect(saveSession)
- .expect(handleTransaction)
- .run(unit -> {
- new EmbeddedNeo4jSessionStore(dbService, graphAwareRuntime, "sess", 60L)
- .save(unit.get(Session.class));
- });
- }
-
- @Test
- public void update() throws Exception {
- new MockUnit(Session.class, GraphDatabaseService.class, GraphAwareRuntime.class, ExpirationModule.class)
- .expect(boot)
- .expect(updateSession)
- .expect(handleTransaction)
- .run(unit -> {
- new EmbeddedNeo4jSessionStore(dbService, graphAwareRuntime, "sess", 60L)
- .save(unit.get(Session.class));
- });
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void get() throws Exception {
- properties = Collections.singletonMap("a.b", "c");
- new MockUnit(Session.class, GraphDatabaseService.class, GraphAwareRuntime.class, ExpirationModule.class)
- .expect(boot)
- .expect(getFromSession)
- .expect(handleTransaction)
- .run(unit -> {
- EmbeddedNeo4jSessionStore nss = new EmbeddedNeo4jSessionStore(dbService, graphAwareRuntime, "sess", 60L);
- assertEquals(unit.get(Session.class), nss.get(sb));
- }, unit -> {
- BiConsumer setter = unit.captured(BiConsumer.class).get(0);
- setter.accept("a\uFF0Eb", "c");
- });
- }
-
- @SuppressWarnings("unchecked")
- @Test
- public void getDollar() throws Exception {
- properties = Collections.singletonMap("$ab", "c");
- new MockUnit(Session.class, GraphDatabaseService.class, GraphAwareRuntime.class, ExpirationModule.class)
- .expect(boot)
- .expect(getFromSession)
- .expect(handleTransaction)
- .run(unit -> {
- EmbeddedNeo4jSessionStore nss = new EmbeddedNeo4jSessionStore(dbService, graphAwareRuntime, "sess", 60L);
- assertEquals(unit.get(Session.class), nss.get(sb));
- }, unit -> {
- BiConsumer setter = unit.captured(BiConsumer.class).get(0);
- setter.accept("\uFF04ab", "c");
- });
- }
-
- @Test
- public void getExpired() throws Exception {
- new MockUnit(Session.class, GraphDatabaseService.class, GraphAwareRuntime.class, ExpirationModule.class)
- .expect(boot)
- .expect(unit -> {
- sb = unit.mock(Session.Builder.class);
- expect(sb.sessionId()).andReturn("1234");
- expect(dbService.findNode(isA(Label.class), isA(String.class), isA(Object.class))).andReturn(null);
- })
- .expect(unit -> {
- Transaction t = unit.mock(Transaction.class);
- t.close();
- expectLastCall();
- expect(dbService.beginTx()).andReturn(t);
- })
- .run(unit -> {
- EmbeddedNeo4jSessionStore nss = new EmbeddedNeo4jSessionStore(dbService, graphAwareRuntime, "sess", 60L);
- assertEquals(null, nss.get(sb));
- });
- }
-
- @Test
- public void delete() throws Exception {
- new MockUnit(Session.class, GraphDatabaseService.class, GraphAwareRuntime.class, ExpirationModule.class)
- .expect(boot)
- .expect(unit -> {
- Node node = unit.mock(Node.class);
- node.delete();
- expectLastCall();
- expect(dbService.findNode(isA(Label.class), isA(String.class), isA(Object.class))).andReturn(node);
- })
- .expect(handleTransaction)
- .run(unit -> {
- new EmbeddedNeo4jSessionStore(dbService, graphAwareRuntime, "sess", 60L).delete("1234");
- });
- }
-}
\ No newline at end of file
diff --git a/modules/jooby-neo4j/src/test/java/org/jooby/embedded/neo4j/EmbeddedNeo4jTest.java b/modules/jooby-neo4j/src/test/java/org/jooby/embedded/neo4j/EmbeddedNeo4jTest.java
deleted file mode 100644
index 3a8bdf20cf..0000000000
--- a/modules/jooby-neo4j/src/test/java/org/jooby/embedded/neo4j/EmbeddedNeo4jTest.java
+++ /dev/null
@@ -1,183 +0,0 @@
-package org.jooby.embedded.neo4j;
-
-import com.google.inject.Binder;
-import com.google.inject.Key;
-import com.google.inject.binder.AnnotatedBindingBuilder;
-import com.google.inject.name.Names;
-import com.graphaware.runtime.GraphAwareRuntime;
-import com.graphaware.runtime.GraphAwareRuntimeFactory;
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigValueFactory;
-import javaslang.control.Try;
-import org.jooby.Env;
-import org.jooby.test.MockUnit;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.neo4j.graphdb.GraphDatabaseService;
-import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
-import org.neo4j.graphdb.factory.GraphDatabaseFactory;
-import org.powermock.core.classloader.annotations.PrepareForTest;
-import org.powermock.modules.junit4.PowerMockRunner;
-
-import java.io.File;
-
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.expectLastCall;
-import static org.easymock.EasyMock.isA;
-import static org.junit.Assert.assertEquals;
-
-@RunWith(PowerMockRunner.class)
-@PrepareForTest({GraphDatabaseService.class, GraphAwareRuntime.class,
- GraphAwareRuntimeFactory.class, GraphDatabaseFactory.class,
- GraphDatabaseBuilder.class, EmbeddedNeo4j.class})
-public class EmbeddedNeo4jTest {
-
- private Config $neo4j = ConfigFactory.parseResources(getClass(), "/embedded/embedded_neo4j.conf");
- private GraphDatabaseService dbService;
- private GraphAwareRuntime graphRuntime;
-
- @SuppressWarnings("unchecked")
- MockUnit.Block neo4j = unit -> {
- dbService = unit.mock(GraphDatabaseService.class);
- unit.registerMock(GraphDatabaseService.class, dbService);
- dbService.shutdown();
- expectLastCall();
-
- GraphDatabaseBuilder graphDatabaseBuilder = unit.mock(GraphDatabaseBuilder.class);
- unit.registerMock(GraphDatabaseBuilder.class, graphDatabaseBuilder);
- expect(graphDatabaseBuilder.newGraphDatabase()).andReturn(dbService);
-
- GraphDatabaseFactory graphDatabaseFactory = unit.mockConstructor(GraphDatabaseFactory.class);
- expect(graphDatabaseFactory.newEmbeddedDatabaseBuilder(isA(File.class))).andReturn(graphDatabaseBuilder);
- unit.registerMock(GraphDatabaseFactory.class, graphDatabaseFactory);
-
- graphRuntime = unit.mock(GraphAwareRuntime.class);
- unit.registerMock(GraphAwareRuntime.class, graphRuntime);
-
- unit.mockStatic(GraphAwareRuntimeFactory.class);
- expect(GraphAwareRuntimeFactory.createRuntime(dbService)).andReturn(graphRuntime);
-
- AnnotatedBindingBuilder dbsABB = unit.mock(AnnotatedBindingBuilder.class);
- dbsABB.toInstance(dbService);
- dbsABB.toInstance(dbService);
-
- AnnotatedBindingBuilder grABB = unit.mock(AnnotatedBindingBuilder.class);
- grABB.toInstance(graphRuntime);
- grABB.toInstance(graphRuntime);
-
- Binder binder = unit.get(Binder.class);
- expect(binder.bind(Key.get(GraphDatabaseService.class))).andReturn(dbsABB);
- expect(binder.bind(Key.get(GraphDatabaseService.class, Names.named("/tmp")))).andReturn(dbsABB);
-
- expect(binder.bind(Key.get(GraphAwareRuntime.class))).andReturn(grABB);
- expect(binder.bind(Key.get(GraphAwareRuntime.class, Names.named("/tmp")))).andReturn(grABB);
-
- Env env = unit.get(Env.class);
- expect(env.onStop(unit.capture(Try.CheckedRunnable.class))).andReturn(env);
- };
-
- @Test
- public void defaults() throws Exception {
- new MockUnit(Config.class, Binder.class, Env.class)
- .expect(unit -> {
- Config config = unit.get(Config.class);
- expect(config.getConfig("neo4j")).andReturn($neo4j.getConfig("neo4j"));
- expect(config.hasPath("neo4j")).andReturn(false);
- })
- .expect(serviceKey(new Env.ServiceKey()))
- .expect(neo4j)
- .expect(unit -> {
- expect(dbService.isAvailable(60000L)).andReturn(true);
- })
- .run(unit -> {
- EmbeddedNeo4j embeddedNeo4j = new EmbeddedNeo4j();
- embeddedNeo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
- }, unit -> {
- unit.captured(Try.CheckedRunnable.class).iterator().next().run();
- });
- }
-
- @Test(expected = IllegalArgumentException.class)
- public void shouldFailWhenDbIsMissing() throws Exception {
- new MockUnit(Config.class, Binder.class, Env.class)
- .expect(unit -> {
- Config config = unit.get(Config.class);
- expect(config.getConfig("neo4j")).andReturn($neo4j.getConfig("neo4j"));
- expect(config.hasPath("neo4j")).andReturn(false);
- })
- .expect(neo4j)
- .expect(unit -> {
- expect(dbService.isAvailable(60000L)).andReturn(false);
- })
- .run(unit -> {
- EmbeddedNeo4j embeddedNeo4j = new EmbeddedNeo4j();
- embeddedNeo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
- });
- }
-
- @Test
- public void defaultsWithCustomAction() throws Exception {
- new MockUnit(Config.class, Binder.class, Env.class)
- .expect(unit -> {
- Config config = unit.get(Config.class);
- expect(config.getConfig("neo4j")).andReturn($neo4j.getConfig("neo4j"));
- expect(config.hasPath("neo4j")).andReturn(true);
- expect(config.getConfig("neo4j")).andReturn(ConfigFactory.empty()
- .withValue("databaseDir", ConfigValueFactory.fromAnyRef("/tmp")));
- })
- .expect(serviceKey(new Env.ServiceKey()))
- .expect(neo4j)
- .expect(unit -> {
- expect(dbService.isAvailable(60000L)).andReturn(true);
- })
- .run(unit -> {
- new EmbeddedNeo4j()
- .properties((properties, config) -> {
- assertEquals("/tmp", properties.getProperty("databaseDir"));
- })
- .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
- }, unit -> {
- unit.captured(Try.CheckedRunnable.class).iterator().next().run();
- });
- }
-
- @Test
- public void defaultsConfig() throws Exception {
- new MockUnit(Config.class, Binder.class, Env.class)
- .expect(unit -> {
- assertEquals($neo4j, new EmbeddedNeo4j().config());
- });
- }
-
- @Test
- public void defaultsWithProperties() throws Exception {
- new MockUnit(Config.class, Binder.class, Env.class)
- .expect(unit -> {
- Config config = unit.get(Config.class);
- expect(config.getConfig("neo4j")).andReturn($neo4j.getConfig("neo4j"));
- expect(config.hasPath("neo4j")).andReturn(false);
- })
- .expect(serviceKey(new Env.ServiceKey()))
- .expect(neo4j)
- .expect(unit -> {
- expect(dbService.isAvailable(60000L)).andReturn(true);
- })
- .run(unit -> {
- new EmbeddedNeo4j()
- .properties((properties, config) -> {
- properties.put("databaseDir", "/tmp");
- })
- .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
- }, unit -> {
- unit.captured(Try.CheckedRunnable.class).iterator().next().run();
- });
- }
-
- private MockUnit.Block serviceKey(final Env.ServiceKey serviceKey) {
- return unit -> {
- Env env = unit.get(Env.class);
- expect(env.serviceKey()).andReturn(serviceKey);
- };
- }
-}
\ No newline at end of file
diff --git a/modules/jooby-neo4j/src/test/java/org/jooby/neo4j/Neo4jSessionStoreTest.java b/modules/jooby-neo4j/src/test/java/org/jooby/neo4j/Neo4jSessionStoreTest.java
new file mode 100644
index 0000000000..039c06b6f8
--- /dev/null
+++ b/modules/jooby-neo4j/src/test/java/org/jooby/neo4j/Neo4jSessionStoreTest.java
@@ -0,0 +1,287 @@
+package org.jooby.neo4j;
+
+import static org.easymock.EasyMock.expect;
+import static org.junit.Assert.assertEquals;
+
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+import org.jooby.Session;
+import org.jooby.Session.Builder;
+import org.jooby.test.MockUnit;
+import org.jooby.test.MockUnit.Block;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+import com.google.common.collect.ImmutableList;
+import com.google.common.collect.ImmutableMap;
+
+import iot.jcypher.database.IDBAccess;
+import iot.jcypher.graph.GrNode;
+import iot.jcypher.graph.GrProperty;
+import iot.jcypher.query.JcQuery;
+import iot.jcypher.query.JcQueryResult;
+import iot.jcypher.query.api.IClause;
+import iot.jcypher.query.api.modify.ModifyTerminal;
+import iot.jcypher.query.api.modify.Set;
+import iot.jcypher.query.api.pattern.Node;
+import iot.jcypher.query.api.pattern.Property;
+import iot.jcypher.query.api.returns.RSortable;
+import iot.jcypher.query.factories.clause.DO;
+import iot.jcypher.query.factories.clause.MATCH;
+import iot.jcypher.query.factories.clause.RETURN;
+import iot.jcypher.query.values.JcNode;
+import iot.jcypher.query.values.JcProperty;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({Neo4jSessionStore.class, JcQuery.class, JcNode.class, MATCH.class, DO.class,
+ System.class, RETURN.class })
+public class Neo4jSessionStoreTest {
+
+ @Test
+ public void newStore() throws Exception {
+ new MockUnit(IDBAccess.class)
+ .run(unit -> {
+ new Neo4jSessionStore(unit.get(IDBAccess.class), "session", "30m");
+ });
+ }
+
+ @Test
+ public void get() throws Exception {
+ new MockUnit(IDBAccess.class, Session.Builder.class)
+ .expect(sessionId("sidfoo"))
+ .expect(newNode("n"))
+ .expect(millis())
+ .expect(GET("sidfoo", "session", TimeUnit.MINUTES.toMillis(30)))
+ .expect(newQuery())
+ .expect(execute())
+ .expect(resultOf())
+ .expect(newSession())
+ .run(unit -> {
+ Session session = new Neo4jSessionStore(unit.get(IDBAccess.class), "session", "30m")
+ .get(unit.get(Session.Builder.class));
+ assertEquals(unit.get(Session.class), session);
+ });
+ }
+
+ @Test
+ public void getNull() throws Exception {
+ new MockUnit(IDBAccess.class, Session.Builder.class)
+ .expect(sessionId("sidfoo"))
+ .expect(newNode("n"))
+ .expect(millis())
+ .expect(GET("sidfoo", "session", TimeUnit.SECONDS.toMillis(30)))
+ .expect(newQuery())
+ .expect(execute())
+ .expect(emptyResultOf())
+ .run(unit -> {
+ Session session = new Neo4jSessionStore(unit.get(IDBAccess.class), "session", "30")
+ .get(unit.get(Session.Builder.class));
+ assertEquals(null, session);
+ });
+ }
+
+ @Test
+ public void save() throws Exception {
+ new MockUnit(IDBAccess.class, Session.class)
+ .expect(sid("sidfoo", ImmutableMap.of("foo", "bar"), 1L, 2L, 3L))
+ .expect(newNode("n"))
+ .expect(millis())
+ .expect(SAVE("sidfoo", "session", 1L, 2L, 3L, TimeUnit.MINUTES.toMillis(30)))
+ .expect(newQuery())
+ .expect(execute())
+ .expect(resultOf())
+ .expect(unit -> {
+ GrProperty foo = unit.mock(GrProperty.class);
+ expect(foo.getName()).andReturn("foo");
+
+ GrNode node = unit.get(GrNode.class);
+ expect(node.getProperties()).andReturn(ImmutableList.of(foo));
+ })
+ .run(unit -> {
+ new Neo4jSessionStore(unit.get(IDBAccess.class), "session", "30m")
+ .save(unit.get(Session.class));
+ });
+ }
+
+ @SuppressWarnings("unchecked")
+ private Block SAVE(final String sid, final String label, final long accessedAt,
+ final long createdAt, final long savedAt, final long timeout) {
+ return unit -> {
+ {
+ unit.mockStatic(MATCH.class);
+
+ Node node = unit.mock(Node.class);
+
+ Property prop = unit.mock(Property.class);
+ expect(prop.value(sid)).andReturn(node);
+
+ expect(node.label(label)).andReturn(node);
+ expect(node.property("_id")).andReturn(prop);
+ expect(MATCH.node(unit.get(JcNode.class))).andReturn(node);
+ }
+
+ DO_SET(unit, "_accessedAt", accessedAt);
+ DO_SET(unit, "_createdAt", createdAt);
+ DO_SET(unit, "_savedAt", savedAt);
+ DO_SET(unit, "_expire", timeout);
+ DO_SET(unit, "foo", "bar");
+ };
+ }
+
+ @SuppressWarnings("unchecked")
+ private void DO_SET(final MockUnit unit, final String name, final Object value) {
+ unit.mockStatic(DO.class);
+
+ JcProperty prop = unit.mock(JcProperty.class);
+ JcNode node = unit.get(JcNode.class);
+ expect(node.property(name)).andReturn(prop);
+
+ Set mod = unit.mock(Set.class);
+ expect(mod.to(value)).andReturn(null);
+
+ expect(DO.SET(prop)).andReturn(mod);
+ }
+
+ @SuppressWarnings("unchecked")
+ private Block GET(final String sid, final String label, final long timeout) {
+ return unit -> {
+ {
+ unit.mockStatic(MATCH.class);
+
+ Node node = unit.mock(Node.class);
+
+ Property prop = unit.mock(Property.class);
+ expect(prop.value(sid)).andReturn(node);
+
+ expect(node.label(label)).andReturn(node);
+ expect(node.property("_id")).andReturn(prop);
+ expect(MATCH.node(unit.get(JcNode.class))).andReturn(node);
+ }
+
+ {
+ unit.mockStatic(DO.class);
+
+ JcNode node = unit.get(JcNode.class);
+
+ Set setprop = unit.mock(Set.class);
+ expect(setprop.to(timeout))
+ .andReturn(unit.registerMock(ModifyTerminal.class));
+
+ JcProperty prop = unit.mock(JcProperty.class);
+ expect(node.property("_expire")).andReturn(prop);
+ expect(DO.SET(prop)).andReturn(setprop);
+ }
+
+ {
+ unit.mockStatic(RETURN.class);
+ expect(RETURN.value(unit.get(JcNode.class)))
+ .andReturn(unit.registerMock(RSortable.class));
+ }
+ };
+ }
+
+ private Block newSession() {
+ return unit -> {
+ Builder builder = unit.get(Session.Builder.class);
+
+ GrProperty accessedAt = unit.mock(GrProperty.class);
+ expect(accessedAt.getValue()).andReturn(1L);
+ expect(builder.accessedAt(1L)).andReturn(builder);
+
+ GrProperty createdAt = unit.mock(GrProperty.class);
+ expect(createdAt.getValue()).andReturn(2L);
+ expect(builder.createdAt(2L)).andReturn(builder);
+
+ GrProperty savedAt = unit.mock(GrProperty.class);
+ expect(savedAt.getValue()).andReturn(3L);
+ expect(builder.savedAt(3L)).andReturn(builder);
+
+ GrProperty foo = unit.mock(GrProperty.class);
+ expect(foo.getName()).andReturn("foo").times(2);
+ expect(foo.getValue()).andReturn("bar");
+ expect(builder.set("foo", "bar")).andReturn(builder);
+
+ GrProperty sid = unit.mock(GrProperty.class);
+ expect(sid.getName()).andReturn("_id");
+
+ GrNode node = unit.get(GrNode.class);
+ expect(node.getProperty("_accessedAt")).andReturn(accessedAt);
+ expect(node.getProperty("_createdAt")).andReturn(createdAt);
+ expect(node.getProperty("_savedAt")).andReturn(savedAt);
+
+ expect(node.getProperties()).andReturn(ImmutableList.of(foo, sid));
+
+ expect(builder.build()).andReturn(unit.registerMock(Session.class));
+ };
+ }
+
+ private Block resultOf() {
+ return unit -> {
+ GrNode node = unit.registerMock(GrNode.class);
+ JcQueryResult result = unit.get(JcQueryResult.class);
+ expect(result.resultOf(unit.get(JcNode.class))).andReturn(ImmutableList.of(node));
+ };
+ }
+
+ private Block emptyResultOf() {
+ return unit -> {
+ JcQueryResult result = unit.get(JcQueryResult.class);
+ expect(result.resultOf(unit.get(JcNode.class))).andReturn(ImmutableList.of());
+ };
+ }
+
+ private Block millis() {
+ return unit -> {
+ unit.mockStatic(System.class);
+ expect(System.currentTimeMillis()).andReturn(0L);
+ };
+ }
+
+ private Block newNode(final String name) {
+ return unit -> {
+ JcNode node = unit.constructor(JcNode.class)
+ .build(name);
+ unit.registerMock(JcNode.class, node);
+ };
+ }
+
+ private Block execute() {
+ return unit -> {
+ JcQueryResult result = unit.registerMock(JcQueryResult.class);
+ IDBAccess db = unit.get(IDBAccess.class);
+ expect(db.execute(unit.get(JcQuery.class))).andReturn(result);
+ };
+ }
+
+ private Block newQuery() {
+ return unit -> {
+ JcQuery query = unit.constructor(JcQuery.class)
+ .build();
+ query.setClauses(unit.capture(IClause[].class));
+ unit.registerMock(JcQuery.class, query);
+ };
+ }
+
+ private Block sessionId(final String sid) {
+ return unit -> {
+ Builder builder = unit.get(Session.Builder.class);
+ expect(builder.sessionId()).andReturn(sid);
+ };
+ }
+
+ private Block sid(final String sid, final Map attrs, final long accessedAt,
+ final long createdAt, final long savedAt) {
+ return unit -> {
+ Session session = unit.get(Session.class);
+ expect(session.id()).andReturn(sid);
+ expect(session.attributes()).andReturn(attrs);
+
+ expect(session.accessedAt()).andReturn(accessedAt);
+ expect(session.createdAt()).andReturn(createdAt);
+ expect(session.savedAt()).andReturn(savedAt);
+ };
+ }
+}
diff --git a/modules/jooby-neo4j/src/test/java/org/jooby/neo4j/Neo4jTest.java b/modules/jooby-neo4j/src/test/java/org/jooby/neo4j/Neo4jTest.java
index 670599f896..d4111be4bc 100644
--- a/modules/jooby-neo4j/src/test/java/org/jooby/neo4j/Neo4jTest.java
+++ b/modules/jooby-neo4j/src/test/java/org/jooby/neo4j/Neo4jTest.java
@@ -1,171 +1,529 @@
package org.jooby.neo4j;
-import com.google.inject.Binder;
-import com.google.inject.Key;
-import com.google.inject.binder.AnnotatedBindingBuilder;
-import com.google.inject.name.Names;
-import com.typesafe.config.Config;
-import com.typesafe.config.ConfigFactory;
-import com.typesafe.config.ConfigValueFactory;
-import iot.jcypher.database.DBAccessFactory;
-import iot.jcypher.database.DBProperties;
-import iot.jcypher.database.DBType;
-import iot.jcypher.database.remote.BoltDBAccess;
-import javaslang.control.Try;
+import static org.easymock.EasyMock.eq;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.easymock.EasyMock.isA;
+import static org.junit.Assert.assertEquals;
+
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Properties;
+import java.util.function.BiConsumer;
+import java.util.function.Consumer;
+
import org.jooby.Env;
+import org.jooby.Env.ServiceKey;
import org.jooby.test.MockUnit;
+import org.jooby.test.MockUnit.Block;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.neo4j.driver.v1.AuthToken;
+import org.neo4j.driver.v1.AuthTokens;
+import org.neo4j.driver.v1.Driver;
+import org.neo4j.driver.v1.GraphDatabase;
import org.neo4j.driver.v1.Session;
-import org.neo4j.driver.v1.exceptions.ClientException;
-import org.powermock.api.easymock.PowerMock;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.factory.GraphDatabaseBuilder;
+import org.neo4j.graphdb.factory.GraphDatabaseFactory;
+import org.neo4j.logging.slf4j.Slf4jLogProvider;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
-import java.util.Properties;
+import com.google.common.collect.ImmutableMap;
+import com.google.inject.Binder;
+import com.google.inject.Key;
+import com.google.inject.binder.LinkedBindingBuilder;
+import com.graphaware.neo4j.expire.ExpirationModuleBootstrapper;
+import com.graphaware.runtime.RuntimeRegistry;
+import com.typesafe.config.Config;
+import com.typesafe.config.ConfigException;
+import com.typesafe.config.ConfigFactory;
+import com.typesafe.config.ConfigValueFactory;
-import static org.easymock.EasyMock.expect;
-import static org.easymock.EasyMock.isA;
-import static org.junit.Assert.assertEquals;
-import static org.powermock.api.easymock.PowerMock.replayAll;
+import iot.jcypher.database.DBAccessFactory;
+import iot.jcypher.database.DBProperties;
+import iot.jcypher.database.IDBAccess;
+import iot.jcypher.database.embedded.EmbeddedDBAccess;
+import iot.jcypher.database.remote.BoltDBAccess;
+import javaslang.control.Try.CheckedRunnable;
@RunWith(PowerMockRunner.class)
-@PrepareForTest({BoltDBAccess.class, DBAccessFactory.class})
+@PrepareForTest({Neo4j.class, BoltDBAccess.class, DBAccessFactory.class, Properties.class,
+ GraphDatabaseFactory.class, RuntimeRegistry.class, EmbeddedDBAccess.class, GraphDatabase.class,
+ AuthTokens.class })
public class Neo4jTest {
- private Config $neo4j = ConfigFactory.parseResources(getClass(), "/neo4j/neo4j.conf");
- private BoltDBAccess remoteClient;
+ @Test(expected = ConfigException.Missing.class)
+ public void missingDatabase() throws Exception {
+ new MockUnit(Env.class, Config.class, Binder.class)
+ .expect(hasPath("db.url", false))
+ .expect(hasPath("db", false))
+ .run(unit -> {
+ Neo4j neo4j = new Neo4j();
+ neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
+ });
+ }
- @SuppressWarnings("unchecked")
- MockUnit.Block neo4j = unit -> {
+ @Test
+ public void config() throws Exception {
+ assertEquals(ConfigFactory.empty(getClass().getName().toLowerCase() + ".conf")
+ .withValue("neo4j.session.label", ConfigValueFactory.fromAnyRef("session")),
+ new Neo4j().config());
+ }
- remoteClient = unit.mock(BoltDBAccess.class);
- unit.registerMock(BoltDBAccess.class, remoteClient);
+ @Test
+ public void rm() throws Exception {
+ Path dir = Paths.get("target", "foo");
+ Neo4j.rm(dir);
+ Files.createDirectories(dir);
+ Files.createFile(dir.resolve("foo.txt"));
+ Path subdir = dir.resolve("bar");
+ Files.createDirectories(subdir);
+ Files.createFile(subdir.resolve("bar.txt"));
- AnnotatedBindingBuilder rcABB = unit.mock(AnnotatedBindingBuilder.class);
- rcABB.toInstance(remoteClient);
- rcABB.toInstance(remoteClient);
+ assertEquals(true, Files.exists(dir));
+ Neo4j.rm(dir);
+ assertEquals(false, Files.exists(dir));
+ Neo4j.rm(dir);
+ assertEquals(false, Files.exists(dir));
+ }
+
+ @Test
+ public void memDirect() throws Exception {
+ Path dir = Paths.get("target", "des").toAbsolutePath();
+ Path dbdir = dir.resolve("neo4jmem").toAbsolutePath();
+ new MockUnit(Env.class, Config.class, Binder.class)
+ .expect(hasPath("mem.url", false))
+ .expect(hasPath("mem", false))
+ .expect(hasPath("mem", false))
+ .expect(hasPath("com.graphaware", false))
+ .expect(hasPath("neo4j", false))
+ .expect(hasPath("neo4j.mem", false))
+ .expect(confString("application.tmpdir", dir.toString()))
+ .expect(props())
+ .expect(setProp("database_dir", dbdir.toString()))
+ .expect(serviceKey())
+ .expect(dbFactory(dbdir, "mem"))
+ .expect(embeddedAccess("mem"))
+ .expect(logdb(null, dbdir.toString()))
+ .expect(onStop())
+ .run(unit -> {
+ Neo4j neo4j = new Neo4j("mem");
+ neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
+ }, closeOnStop(),
+ bind(GraphDatabaseService.class, 0),
+ bind(IDBAccess.class, 1),
+ unit -> {
+ IDBAccess db = unit.get(IDBAccess.class);
+ bind(db.getClass(), 2).run(unit);
+ });
+ }
- Binder binder = unit.get(Binder.class);
- expect(binder.bind(Key.get(BoltDBAccess.class))).andReturn(rcABB);
- expect(binder.bind(Key.get(BoltDBAccess.class, Names.named("bolt://localhost:7687")))).andReturn(rcABB);
+ @SuppressWarnings({"unchecked", "rawtypes" })
+ private Block bind(final Class class1, final int i) {
+ return unit -> {
+ List consumers = unit.captured(Consumer.class);
+ consumers.get(i).accept(Key.get(class1));
+ };
+ }
- Env env = unit.get(Env.class);
- expect(env.onStop(unit.capture(Try.CheckedRunnable.class))).andReturn(env);
- };
+ @Test
+ public void memAsProperty() throws Exception {
+ Path dir = Paths.get("target", "des").toAbsolutePath();
+ Path dbdir = dir.resolve("neo4jmem").toAbsolutePath();
+ new MockUnit(Env.class, Config.class, Binder.class)
+ .expect(hasPath("db.url", false))
+ .expect(hasPath("db", true))
+ .expect(confString("db", "mem"))
+ .expect(hasPath("com.graphaware", false))
+ .expect(hasPath("neo4j", false))
+ .expect(hasPath("db", true))
+ .expect(notAConf("db"))
+ .expect(hasPath("neo4j.db", false))
+ .expect(confString("application.tmpdir", dir.toString()))
+ .expect(props())
+ .expect(setProp("database_dir", dbdir.toString()))
+ .expect(serviceKey())
+ .expect(dbFactory(dbdir, "db"))
+ .expect(embeddedAccess("db"))
+ .expect(logdb(null, dbdir.toString()))
+ .expect(onStop())
+ .run(unit -> {
+ Neo4j neo4j = new Neo4j();
+ neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
+ }, closeOnStop(),
+ bind(GraphDatabaseService.class, 0),
+ bind(IDBAccess.class, 1),
+ unit -> {
+ IDBAccess db = unit.get(IDBAccess.class);
+ bind(db.getClass(), 2).run(unit);
+ });
+ }
@Test
- public void defaults() throws Exception {
+ public void bolt() throws Exception {
new MockUnit(Env.class, Config.class, Binder.class)
- .expect(unit -> {
- Config config = unit.get(Config.class);
- expect(config.getConfig("neo4j")).andReturn($neo4j.getConfig("neo4j"));
- expect(config.hasPath("neo4j.db")).andReturn(false);
- })
- .expect(serviceKey(new Env.ServiceKey()))
- .expect(neo4j)
- .expect(unit -> {
- PowerMock.mockStatic(DBAccessFactory.class);
- expect(DBAccessFactory.createDBAccess(isA(DBType.class), isA(Properties.class),
- isA(String.class), isA(String.class))).andReturn(remoteClient);
- replayAll();
- expect(remoteClient.getSession()).andReturn(unit.registerMock(Session.class));
- })
- .expect(unit -> {
- BoltDBAccess remoteClient = unit.get(BoltDBAccess.class);
- remoteClient.close();
- })
- .run(unit -> {
- Neo4j neo4j = new Neo4j();
- neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
- }, unit -> {
- unit.captured(Try.CheckedRunnable.class).iterator().next().run();
- });
- }
-
- @Test(expected = ClientException.class)
- public void shouldFailWhenDbIsMissing() throws Exception {
+ .expect(hasPath("db.url", true))
+ .expect(confString("db.url", "bolt://localhost:7687"))
+ .expect(hasPath("com.graphaware", false))
+ .expect(hasPath("neo4j", false))
+ .expect(hasPath("db", true))
+ .expect(confConf("db", ConfigFactory.empty()))
+ .expect(hasPath("neo4j.db", false))
+ .expect(serviceKey())
+ .expect(confString("db.user", "test"))
+ .expect(confString("db.password", "test"))
+ .expect(bolt("bolt://localhost:7687", "db", "test", "test"))
+ .expect(props())
+ .expect(setProp("server_root_uri", "bolt://localhost:7687"))
+ .expect(boltAccess("db"))
+ .expect(logdb("bolt://localhost:7687", null))
+ .expect(onStop())
+ .run(unit -> {
+ Neo4j neo4j = new Neo4j();
+ neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
+ }, closeOnStop(),
+ bind(Driver.class, 0),
+ bind(Session.class, 1));
+ }
+
+ @Test
+ public void fs() throws Exception {
+ Path dir = Paths.get("target", "des").toAbsolutePath();
+ Path dbdir = dir.resolve("neo4jfs").toAbsolutePath();
new MockUnit(Env.class, Config.class, Binder.class)
- .expect(unit -> {
- Config config = unit.get(Config.class);
- expect(config.getConfig("neo4j")).andReturn($neo4j.getConfig("neo4j"));
- expect(config.hasPath("neo4j.db")).andReturn(false);
- expect(config.getString("server_root_uri")).andReturn("bolt://localhost:7687");
- })
- .expect(neo4j)
- .run(unit -> {
- Neo4j neo4j = new Neo4j();
- neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
- });
+ .expect(hasPath("db.url", false))
+ .expect(hasPath("db", true))
+ .expect(confString("db", "fs"))
+ .expect(hasPath("com.graphaware", false))
+ .expect(hasPath("neo4j", false))
+ .expect(hasPath("db", true))
+ .expect(notAConf("db"))
+ .expect(hasPath("neo4j.db", false))
+ .expect(confString("application.tmpdir", dir.toString()))
+ .expect(props())
+ .expect(setProp("database_dir", dbdir.toString()))
+ .expect(serviceKey())
+ .expect(dbFactory(dbdir, "db"))
+ .expect(embeddedAccess("db"))
+ .expect(logdb(null, dbdir.toString()))
+ .expect(onStop())
+ .run(unit -> {
+ Neo4j neo4j = new Neo4j();
+ neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
+ }, closeOnStop(),
+ bind(GraphDatabaseService.class, 0),
+ bind(IDBAccess.class, 1),
+ unit -> {
+ IDBAccess db = unit.get(IDBAccess.class);
+ bind(db.getClass(), 2).run(unit);
+ });
}
@Test
- public void defaultsWithCustomAction() throws Exception {
+ public void oneModule() throws Exception {
+ Path dir = Paths.get("target", "des").toAbsolutePath();
+ Path dbdir = dir.resolve("neo4jfs").toAbsolutePath();
new MockUnit(Env.class, Config.class, Binder.class)
- .expect(unit -> {
- Config config = unit.get(Config.class);
- expect(config.getConfig("neo4j"))
- .andReturn($neo4j.getConfig("neo4j"));
- expect(config.hasPath("neo4j.db")).andReturn(true);
- expect(config.getConfig("neo4j.db")).andReturn(ConfigFactory.empty()
- .withValue("server_root_uri", ConfigValueFactory.fromAnyRef("bolt://localhost:7687")));
- })
- .expect(serviceKey(new Env.ServiceKey()))
- .expect(neo4j)
- .expect(unit -> {
- PowerMock.mockStatic(DBAccessFactory.class);
- expect(DBAccessFactory.createDBAccess(isA(DBType.class), isA(Properties.class),
- isA(String.class), isA(String.class))).andReturn(remoteClient);
- replayAll();
- expect(remoteClient.getSession()).andReturn(unit.registerMock(Session.class));
- })
- .run(unit -> {
- new Neo4j()
- .properties((properties, config) -> {
- assertEquals("bolt://localhost:7687", properties.getProperty(DBProperties.SERVER_ROOT_URI));
- })
- .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
- });
+ .expect(hasPath("db.url", false))
+ .expect(hasPath("db", true))
+ .expect(confString("db", dbdir.toString()))
+ .expect(hasPath("com.graphaware", true))
+ .expect(confConf("com.graphaware",
+ ConfigFactory.empty().withValue("module",
+ ConfigValueFactory.fromAnyRef(
+ (ImmutableMap.of("class", ExpirationModuleBootstrapper.class.getName(),
+ "nodeExpirationProperty", "_expire"))))))
+ .expect(hasPath("neo4j", false))
+ .expect(hasPath("db", false))
+ .expect(hasPath("neo4j.db", false))
+ .expect(props())
+ .expect(setProp("database_dir", dbdir.toString()))
+ .expect(putProp("com.graphaware.module.m1.1", ExpirationModuleBootstrapper.class.getName()))
+ .expect(putProp("com.graphaware.module.m1.nodeExpirationProperty", "_expire"))
+ .expect(serviceKey())
+ .expect(dbFactory(dbdir, "db"))
+ .expect(embeddedAccess("db"))
+ .expect(logdb(null, dbdir.toString()))
+ .expect(onStop())
+ .run(unit -> {
+ Neo4j neo4j = new Neo4j();
+ neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
+ }, closeOnStop(),
+ bind(GraphDatabaseService.class, 0),
+ bind(IDBAccess.class, 1),
+ unit -> {
+ IDBAccess db = unit.get(IDBAccess.class);
+ bind(db.getClass(), 2).run(unit);
+ });
}
@Test
- public void defaultsConfig() throws Exception {
+ public void multipleModule() throws Exception {
+ Path dir = Paths.get("target", "des").toAbsolutePath();
+ Path dbdir = dir.resolve("neo4jfs").toAbsolutePath();
new MockUnit(Env.class, Config.class, Binder.class)
- .expect(unit -> {
- assertEquals($neo4j, new Neo4j().config());
- });
+ .expect(hasPath("db.url", false))
+ .expect(hasPath("db", true))
+ .expect(confString("db", dbdir.toString()))
+ .expect(hasPath("com.graphaware", true))
+ .expect(confConf("com.graphaware",
+ ConfigFactory.empty().withValue("module",
+ ConfigValueFactory.fromAnyRef(Arrays.asList(
+ (ImmutableMap.of("class", ExpirationModuleBootstrapper.class.getName(),
+ "nodeExpirationProperty", "_expire")),
+ (ImmutableMap.of("class", "com.foo.Foo",
+ "foo", "bar")))))))
+ .expect(hasPath("neo4j", false))
+ .expect(hasPath("db", false))
+ .expect(hasPath("neo4j.db", false))
+ .expect(props())
+ .expect(setProp("database_dir", dbdir.toString()))
+ .expect(putProp("com.graphaware.module.m1.1", ExpirationModuleBootstrapper.class.getName()))
+ .expect(putProp("com.graphaware.module.m1.nodeExpirationProperty", "_expire"))
+ .expect(putProp("com.graphaware.module.m2.2", "com.foo.Foo"))
+ .expect(putProp("com.graphaware.module.m2.foo", "bar"))
+ .expect(serviceKey())
+ .expect(dbFactory(dbdir, "db"))
+ .expect(embeddedAccess("db"))
+ .expect(logdb(null, dbdir.toString()))
+ .expect(onStop())
+ .run(unit -> {
+ Neo4j neo4j = new Neo4j();
+ neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
+ }, closeOnStop(),
+ bind(GraphDatabaseService.class, 0),
+ bind(IDBAccess.class, 1),
+ unit -> {
+ IDBAccess db = unit.get(IDBAccess.class);
+ bind(db.getClass(), 2).run(unit);
+ });
}
+ @SuppressWarnings({"unchecked", "deprecation" })
@Test
- public void defaultsWithProperties() throws Exception {
+ public void embedded() throws Exception {
+ Path dir = Paths.get("target", "des").toAbsolutePath();
+ Path dbdir = dir.resolve("neo4jfs").toAbsolutePath();
new MockUnit(Env.class, Config.class, Binder.class)
- .expect(unit -> {
- Config config = unit.get(Config.class);
- expect(config.getConfig("neo4j")).andReturn($neo4j.getConfig("neo4j"));
- expect(config.hasPath("neo4j.db")).andReturn(false);
- })
- .expect(serviceKey(new Env.ServiceKey()))
- .expect(neo4j)
- .expect(unit -> {
- PowerMock.mockStatic(DBAccessFactory.class);
- expect(DBAccessFactory.createDBAccess(isA(DBType.class), isA(Properties.class),
- isA(String.class), isA(String.class))).andReturn(remoteClient);
- replayAll();
- expect(remoteClient.getSession()).andReturn(unit.registerMock(Session.class));
- })
- .run(unit -> {
- new Neo4j()
- .properties((properties, config) -> {
- properties.put(DBProperties.SERVER_ROOT_URI, "bolt://localhost:7687");
- })
- .configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
- });
- }
-
- private MockUnit.Block serviceKey(final Env.ServiceKey serviceKey) {
+ .expect(hasPath("db.url", false))
+ .expect(hasPath("db", true))
+ .expect(confString("db", dbdir.toString()))
+ .expect(hasPath("com.graphaware", false))
+ .expect(hasPath("neo4j", true))
+ .expect(confConf("neo4j",
+ ConfigFactory.empty().withValue("unsupported.dbms.block_size.array_properties",
+ ConfigValueFactory.fromAnyRef(120))))
+ .expect(hasPath("db", false))
+ .expect(hasPath("neo4j.db", false))
+ .expect(props())
+ .expect(setProp("database_dir", dbdir.toString()))
+ .expect(putProp("unsupported.dbms.block_size.array_properties", 120))
+ .expect(serviceKey())
+ .expect(dbFactory(dbdir, "db"))
+ .expect(embeddedAccess("db"))
+ .expect(logdb(null, dbdir.toString()))
+ .expect(onStop())
+ .expect(unit -> {
+ GraphDatabaseBuilder builder = unit.get(GraphDatabaseBuilder.class);
+ expect(builder.setConfig("unsupported.dbms.block_size.array_properties", "120"))
+ .andReturn(builder);
+ })
+ .run(unit -> {
+ Neo4j neo4j = new Neo4j();
+ neo4j.configure(unit.get(Env.class), unit.get(Config.class), unit.get(Binder.class));
+ }, closeOnStop(),
+ bind(GraphDatabaseService.class, 0),
+ bind(IDBAccess.class, 1),
+ unit -> {
+ IDBAccess db = unit.get(IDBAccess.class);
+ bind(db.getClass(), 2).run(unit);
+ }, unit -> {
+ unit.captured(BiConsumer.class).get(0)
+ .accept("unsupported.dbms.block_size.array_properties", "120");
+ });
+ }
+
+ private Block closeOnStop() {
+ return unit -> {
+ unit.captured(CheckedRunnable.class).get(0).run();
+ };
+ }
+
+ private Block onStop() {
+ return unit -> {
+ Env env = unit.get(Env.class);
+ unit.get(IDBAccess.class).close();
+ expect(env.onStop(unit.capture(CheckedRunnable.class))).andReturn(env);
+ };
+ }
+
+ private Block logdb(final String uri, final String dir) {
+ return unit -> {
+ Properties props = unit.get(Properties.class);
+ expect(props.getProperty(DBProperties.SERVER_ROOT_URI)).andReturn(uri);
+ expect(props.getProperty(DBProperties.DATABASE_DIR)).andReturn(dir);
+ };
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes" })
+ private Block embeddedAccess(final String dbkey) {
+ return unit -> {
+ EmbeddedDBAccess db = unit.constructor(EmbeddedDBAccess.class)
+ .build();
+ unit.registerMock(IDBAccess.class, db);
+ db.initialize(unit.get(Properties.class));
+
+ LinkedBindingBuilder lbb = unit.mock(LinkedBindingBuilder.class);
+ lbb.toInstance(db);
+ lbb.toInstance(db);
+
+ Binder binder = unit.get(Binder.class);
+ expect(binder.bind(Key.get(IDBAccess.class))).andReturn(lbb);
+ expect(binder.bind(Key.get(db.getClass()))).andReturn(lbb);
+
+ ServiceKey keys = unit.get(ServiceKey.class);
+ keys.generate(eq(IDBAccess.class), eq(dbkey), unit.capture(Consumer.class));
+ keys.generate(eq(db.getClass()), eq(dbkey), unit.capture(Consumer.class));
+ };
+ }
+
+ @SuppressWarnings("unchecked")
+ private Block boltAccess(final String dbkey) {
+ return unit -> {
+ BoltDBAccess db = unit.constructor(BoltDBAccess.class)
+ .build();
+ unit.registerMock(IDBAccess.class, db);
+ db.initialize(unit.get(Properties.class));
+
+ ServiceKey keys = unit.get(ServiceKey.class);
+ keys.generate(eq(IDBAccess.class), eq(dbkey), unit.capture(Consumer.class));
+ keys.generate(eq(db.getClass()), eq(dbkey), unit.capture(Consumer.class));
+ };
+ }
+
+ @SuppressWarnings("unchecked")
+ private Block dbFactory(final Path dbdir, final String dbkey) {
+ return unit -> {
+ GraphDatabaseService dbservice = unit.registerMock(GraphDatabaseService.class);
+ unit.mockStatic(RuntimeRegistry.class);
+ expect(RuntimeRegistry.getStartedRuntime(dbservice)).andReturn(null);
+
+ LinkedBindingBuilder lbb = unit.mock(LinkedBindingBuilder.class);
+ lbb.toInstance(dbservice);
+
+ Binder binder = unit.get(Binder.class);
+ expect(binder.bind(Key.get(GraphDatabaseService.class))).andReturn(lbb);
+
+ ServiceKey keys = unit.get(ServiceKey.class);
+ keys.generate(eq(GraphDatabaseService.class), eq(dbkey), unit.capture(Consumer.class));
+
+ GraphDatabaseBuilder dbbuilder = unit.registerMock(GraphDatabaseBuilder.class);
+ expect(dbbuilder.newGraphDatabase()).andReturn(dbservice);
+
+ GraphDatabaseFactory factory = unit.constructor(GraphDatabaseFactory.class)
+ .build();
+ expect(factory.setUserLogProvider(isA(Slf4jLogProvider.class))).andReturn(factory);
+ expect(factory.newEmbeddedDatabaseBuilder(dbdir.toFile())).andReturn(dbbuilder);
+ };
+ }
+
+ private Block setProp(final String key, final String value) {
+ return unit -> {
+ Properties props = unit.get(Properties.class);
+ expect(props.setProperty(key, value)).andReturn(null);
+ };
+ }
+
+ private Block putProp(final String key, final Object value) {
+ return unit -> {
+ Properties props = unit.get(Properties.class);
+ expect(props.put(key, value)).andReturn(null);
+ };
+ }
+
+ private Block serviceKey() {
return unit -> {
+ ServiceKey keys = unit.registerMock(Env.ServiceKey.class);
Env env = unit.get(Env.class);
- expect(env.serviceKey()).andReturn(serviceKey);
+ expect(env.serviceKey()).andReturn(keys);
+ };
+ }
+
+ @SuppressWarnings("unchecked")
+ private Block props() {
+ return unit -> {
+ Properties props = unit.constructor(Properties.class)
+ .build();
+ props.forEach(unit.capture(BiConsumer.class));
+ expectLastCall().times(0, 1);
+ unit.registerMock(Properties.class, props);
+ };
+ }
+
+ private Block notAConf(final String path) {
+ return unit -> {
+ Config conf = unit.get(Config.class);
+ expect(conf.getConfig(path))
+ .andThrow(new ConfigException.WrongType(ConfigFactory.empty().origin(), path));
+ };
+ }
+
+ private Block confString(final String path, final String value) {
+ return unit -> {
+ Config conf = unit.get(Config.class);
+ expect(conf.getString(path)).andReturn(value);
+ };
+ }
+
+ private Block hasPath(final String path, final boolean value) {
+ return unit -> {
+ Config conf = unit.get(Config.class);
+ expect(conf.hasPath(path)).andReturn(value);
+ };
+ }
+
+ private Block confConf(final String path, final Config value) {
+ return unit -> {
+ Config conf = unit.get(Config.class);
+ expect(conf.getConfig(path)).andReturn(value);
+ };
+ }
+
+ @SuppressWarnings({"unchecked", "rawtypes" })
+ private Block bolt(final String uri, final String dbkey, final String user, final String pass) {
+ return unit -> {
+ AuthToken token = unit.mock(AuthToken.class);
+
+ unit.mockStatic(AuthTokens.class);
+ expect(AuthTokens.basic(user, pass)).andReturn(token);
+
+ Binder binder = unit.get(Binder.class);
+
+ Session session = unit.registerMock(Session.class);
+
+ LinkedBindingBuilder lbbs = unit.mock(LinkedBindingBuilder.class);
+ lbbs.toInstance(session);
+ expect(binder.bind(Key.get(Session.class))).andReturn(lbbs);
+
+ Driver driver = unit.registerMock(Driver.class);
+ expect(driver.session()).andReturn(session);
+
+ LinkedBindingBuilder lbb = unit.mock(LinkedBindingBuilder.class);
+ lbb.toInstance(driver);
+
+ expect(binder.bind(Key.get(Driver.class))).andReturn(lbb);
+
+ unit.mockStatic(GraphDatabase.class);
+ expect(GraphDatabase.driver(uri, token)).andReturn(driver);
+
+ ServiceKey keys = unit.get(ServiceKey.class);
+ keys.generate(eq(Driver.class), eq(dbkey), unit.capture(Consumer.class));
+ keys.generate(eq(Session.class), eq(dbkey), unit.capture(Consumer.class));
};
}
-}
\ No newline at end of file
+}