diff --git a/.gitignore b/.gitignore index 7725bf202e..b731787052 100644 --- a/.gitignore +++ b/.gitignore @@ -120,4 +120,7 @@ libraries-2/src/test/resources/crawler4j/** devDb*.db #jaxb -*.xjb \ No newline at end of file +*.xjb + +#neo4j +persistence-modules/neo4j/data/** \ No newline at end of file diff --git a/persistence-modules/neo4j/README.md b/persistence-modules/neo4j/README.md new file mode 100644 index 0000000000..354d9605db --- /dev/null +++ b/persistence-modules/neo4j/README.md @@ -0,0 +1,15 @@ +## Spring Data Neo4j + +### Relevant Articles: +- [A Guide to Neo4J with Java](https://www.baeldung.com/java-neo4j) + +### Build the Project with Tests Running +``` +mvn clean install +``` + +### Run Tests Directly +``` +mvn test +``` + diff --git a/persistence-modules/neo4j/pom.xml b/persistence-modules/neo4j/pom.xml new file mode 100644 index 0000000000..91a488637a --- /dev/null +++ b/persistence-modules/neo4j/pom.xml @@ -0,0 +1,117 @@ + + + 4.0.0 + neo4j + 1.0 + neo4j + + + com.baeldung + persistence-modules + 1.0.0-SNAPSHOT + + + + + org.neo4j + neo4j + ${neo4j.version} + + + org.neo4j + neo4j-ogm-core + ${neo4j-ogm-core.version} + + + org.neo4j + neo4j-ogm-embedded-driver + ${neo4j-ogm-embedded.version} + + + org.neo4j + neo4j-ogm-bolt-driver + ${neo4j-ogm-bolt-driver.version} + + + org.neo4j.driver + neo4j-java-driver + ${neo4j-java-driver.version} + + + org.neo4j + neo4j-jdbc-driver + ${neo4j-jdbc.version} + runtime + + + com.voodoodyne.jackson.jsog + jackson-jsog + ${jackson-jsog.version} + compile + + + org.neo4j + neo4j-kernel + ${neo4j.version} + test-jar + + + org.neo4j.app + neo4j-server + ${neo4j.version} + test-jar + + + commons-logging + commons-logging + + + + + org.neo4j + neo4j-ogm-test + ${neo4j-ogm.version} + test + + + org.neo4j.test + neo4j-harness + ${neo4j.version} + test + + + org.testcontainers + neo4j + ${testcontainers.version} + test + + + org.jetbrains + annotations + + + org.apache.commons + commons-compress + + + javax.xml.bind + jaxb-api + + + + + + + 5.6.0 + 5.8.0 + 1.1.2 + 3.1.22 + 4.0.5 + 3.2.39 + 4.0.9 + 4.0.5 + + + \ No newline at end of file diff --git a/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Car.java b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Car.java new file mode 100644 index 0000000000..d396cc94e7 --- /dev/null +++ b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Car.java @@ -0,0 +1,50 @@ +package com.baeldung.neo4j.domain; + +import static org.neo4j.ogm.annotation.Relationship.Direction.INCOMING; + +import org.neo4j.ogm.annotation.GeneratedValue; +import org.neo4j.ogm.annotation.Id; +import org.neo4j.ogm.annotation.NodeEntity; +import org.neo4j.ogm.annotation.Relationship; + +@NodeEntity +public class Car { + @Id @GeneratedValue + private Long id; + + private String make; + + @Relationship(direction = INCOMING) + private Company company; + + public Car(String make, String model) { + this.make = make; + this.model = model; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getMake() { + return make; + } + + public void setMake(String make) { + this.make = make; + } + + public String getModel() { + return model; + } + + public void setModel(String model) { + this.model = model; + } + + private String model; +} diff --git a/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Company.java b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Company.java new file mode 100644 index 0000000000..7749db9d74 --- /dev/null +++ b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Company.java @@ -0,0 +1,42 @@ +package com.baeldung.neo4j.domain; + +import org.neo4j.ogm.annotation.NodeEntity; +import org.neo4j.ogm.annotation.Relationship; + +@NodeEntity +public class Company { + private Long id; + + private String name; + + @Relationship(type="owns") + private Car car; + + public Company(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Car getCar() { + return car; + } + + public void setCar(Car car) { + this.car = car; + } +} diff --git a/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Movie.java b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Movie.java new file mode 100644 index 0000000000..c6a0a9a529 --- /dev/null +++ b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Movie.java @@ -0,0 +1,66 @@ +package com.baeldung.neo4j.domain; + +import static org.neo4j.ogm.annotation.Relationship.Direction.INCOMING; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.voodoodyne.jackson.jsog.JSOGGenerator; + +import org.neo4j.ogm.annotation.GeneratedValue; +import org.neo4j.ogm.annotation.Id; +import org.neo4j.ogm.annotation.NodeEntity; +import org.neo4j.ogm.annotation.Relationship; + +import java.util.Collection; +import java.util.List; + +@JsonIdentityInfo(generator = JSOGGenerator.class) + +@NodeEntity +public class Movie { + @Id @GeneratedValue + Long id; + + private String title; + + private int released; + private String tagline; + + @Relationship(type = "ACTED_IN", direction = INCOMING) + private List roles; + + public Movie() { + } + + public String getTitle() { + return title; + } + + public int getReleased() { + return released; + } + + public String getTagline() { + return tagline; + } + + public Collection getRoles() { + return roles; + } + + public void setTitle(String title) { + this.title = title; + } + + public void setReleased(int released) { + this.released = released; + } + + public void setTagline(String tagline) { + this.tagline = tagline; + } + + public void setRoles(List roles) { + this.roles = roles; + } + +} diff --git a/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Person.java b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Person.java new file mode 100644 index 0000000000..a9491ee876 --- /dev/null +++ b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Person.java @@ -0,0 +1,52 @@ +package com.baeldung.neo4j.domain; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.voodoodyne.jackson.jsog.JSOGGenerator; + +import org.neo4j.ogm.annotation.GeneratedValue; +import org.neo4j.ogm.annotation.Id; +import org.neo4j.ogm.annotation.NodeEntity; +import org.neo4j.ogm.annotation.Relationship; + +import java.util.List; + +@JsonIdentityInfo(generator = JSOGGenerator.class) +@NodeEntity +public class Person { + @Id @GeneratedValue + Long id; + + private String name; + private int born; + + @Relationship(type = "ACTED_IN") + private List movies; + + public Person() { + } + + public String getName() { + return name; + } + + public int getBorn() { + return born; + } + + public List getMovies() { + return movies; + } + + public void setName(String name) { + this.name = name; + } + + public void setBorn(int born) { + this.born = born; + } + + public void setMovies(List movies) { + this.movies = movies; + } + +} diff --git a/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Role.java b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Role.java new file mode 100644 index 0000000000..0c91e67f0c --- /dev/null +++ b/persistence-modules/neo4j/src/main/java/com/baeldung/neo4j/domain/Role.java @@ -0,0 +1,50 @@ +package com.baeldung.neo4j.domain; + +import com.fasterxml.jackson.annotation.JsonIdentityInfo; +import com.voodoodyne.jackson.jsog.JSOGGenerator; +import org.neo4j.ogm.annotation.EndNode; +import org.neo4j.ogm.annotation.GeneratedValue; +import org.neo4j.ogm.annotation.Id; +import org.neo4j.ogm.annotation.RelationshipEntity; +import org.neo4j.ogm.annotation.StartNode; + +import java.util.Collection; + +@JsonIdentityInfo(generator = JSOGGenerator.class) +@RelationshipEntity(type = "ACTED_IN") +public class Role { + @Id @GeneratedValue + Long id; + private Collection roles; + @StartNode + private Person person; + @EndNode + private Movie movie; + + public Role() { + } + + public Collection getRoles() { + return roles; + } + + public Person getPerson() { + return person; + } + + public Movie getMovie() { + return movie; + } + + public void setRoles(Collection roles) { + this.roles = roles; + } + + public void setPerson(Person person) { + this.person = person; + } + + public void setMovie(Movie movie) { + this.movie = movie; + } +} diff --git a/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4JServerLiveTest.java b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4JServerLiveTest.java new file mode 100644 index 0000000000..2232c68e8e --- /dev/null +++ b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4JServerLiveTest.java @@ -0,0 +1,79 @@ +package com.baeldung.neo4j; + +import static com.baeldung.neo4j.TestContainersTestBase.DEFAULT_PASSWORD; +import static com.baeldung.neo4j.TestContainersTestBase.getNewBoltConnection; +import static com.baeldung.neo4j.TestContainersTestBase.neo4jServer; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.Statement; + +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.neo4j.driver.Driver; +import org.neo4j.driver.Result; +import org.neo4j.driver.Session; + + +/** + * To run this test you will need to have an instance of the docker running on your machine (Docker desktop - for Windows and Docker instance for linux) + * After your docker instance is up run this test + */ +class Neo4JServerLiveTest { + + private static Session session; + private static Driver driver; + + @BeforeAll + public static void setup() { + driver = getNewBoltConnection(); + } + + @AfterAll + public static void tearDown() { + driver.close(); + } + + @Test + void standAloneDriver() { + session = driver.session(); + session.run("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + + "RETURN baeldung, tesla"); + + Result result = session.run("MATCH (company:Company)-[:owns]-> (car:Car)" + + "WHERE car.make='tesla' and car.model='modelX'" + + "RETURN company.name"); + + assertTrue(result.hasNext()); + assertEquals("Baeldung", result.next().get("company.name").asString()); + + session.close(); + } + + @Test + void standAloneJdbc() throws Exception { + String uri = "jdbc:neo4j:" + neo4jServer.getBoltUrl() + "/?user=neo4j,password=" + DEFAULT_PASSWORD + ",scheme=basic"; + Connection con = DriverManager.getConnection(uri); + + // Querying + try (Statement stmt = con.createStatement()) { + stmt.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + + "RETURN baeldung, tesla"); + + ResultSet rs = stmt.executeQuery("MATCH (company:Company)-[:owns]-> (car:Car)" + + "WHERE car.make='tesla' and car.model='modelX'" + + "RETURN company.name"); + + while (rs.next()) { + assertEquals("Baeldung", rs.getString("company.name")); + } + } + con.close(); + } +} diff --git a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java similarity index 63% rename from persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java rename to persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java index 1ff01b93a1..8591dd3a8d 100644 --- a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java +++ b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jLiveTest.java @@ -1,7 +1,10 @@ package com.baeldung.neo4j; +import static org.neo4j.configuration.GraphDatabaseSettings.DEFAULT_DATABASE_NAME; + import java.io.File; +import java.time.Duration; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -10,101 +13,111 @@ import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.neo4j.configuration.GraphDatabaseSettings; +import org.neo4j.dbms.api.DatabaseManagementService; +import org.neo4j.dbms.api.DatabaseManagementServiceBuilder; import org.neo4j.graphdb.GraphDatabaseService; import org.neo4j.graphdb.Label; import org.neo4j.graphdb.Node; import org.neo4j.graphdb.NotFoundException; import org.neo4j.graphdb.RelationshipType; import org.neo4j.graphdb.Result; -import org.neo4j.graphdb.factory.GraphDatabaseFactory; +import org.neo4j.graphdb.Transaction; +/** + * To run this test you will need to have an instance of the docker running on your machine (Docker desktop - for Windows and Docker instance for linux) + * After your docker instance is up run this test + */ public class Neo4jLiveTest { private static GraphDatabaseService graphDb; + private static Transaction transaction; + private static DatabaseManagementService managementService; @Before public void setUp() { - GraphDatabaseFactory graphDbFactory = new GraphDatabaseFactory(); - graphDb = graphDbFactory.newEmbeddedDatabase(new File("data/cars")); + managementService = new DatabaseManagementServiceBuilder(new File("data/cars").toPath()) + .setConfig( GraphDatabaseSettings.transaction_timeout, Duration.ofSeconds( 60 ) ) + .setConfig( GraphDatabaseSettings.preallocate_logical_logs, false ).build(); + graphDb = managementService.database( DEFAULT_DATABASE_NAME ); } @After public void tearDown() { - graphDb.shutdown(); + managementService.shutdown(); } @Test public void testPersonCar() { - graphDb.beginTx(); - Node car = graphDb.createNode(Label.label("Car")); + transaction = graphDb.beginTx(); + Node car = transaction.createNode(Label.label("Car")); car.setProperty("make", "tesla"); car.setProperty("model", "model3"); - Node owner = graphDb.createNode(Label.label("Person")); + Node owner = transaction.createNode(Label.label("Person")); owner.setProperty("firstName", "baeldung"); owner.setProperty("lastName", "baeldung"); owner.createRelationshipTo(car, RelationshipType.withName("owner")); - Result result = graphDb.execute("MATCH (c:Car) <-[owner]- (p:Person) " + + Result result = transaction.execute("MATCH (c:Car) <-[owner]- (p:Person) " + "WHERE c.make = 'tesla'" + "RETURN p.firstName, p.lastName"); Map firstResult = result.next(); + Assert.assertEquals("baeldung", firstResult.get("p.firstName")); } @Test public void testCreateNode() { - - graphDb.beginTx(); - - Result result = graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"})" + + transaction = graphDb.beginTx(); + Result result = transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"})" + "RETURN baeldung"); Map firstResult = result.next(); Node firstNode = (Node) firstResult.get("baeldung"); + Assert.assertEquals(firstNode.getProperty("name"), "Baeldung"); } @Test public void testCreateNodeAndLink() { - graphDb.beginTx(); - - Result result = graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + transaction = graphDb.beginTx(); + Result result = transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + "RETURN baeldung, tesla"); Map firstResult = result.next(); + Assert.assertTrue(firstResult.containsKey("baeldung")); Assert.assertTrue(firstResult.containsKey("tesla")); } @Test public void testFindAndReturn() { - graphDb.beginTx(); - - graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + transaction = graphDb.beginTx(); + transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + "RETURN baeldung, tesla"); - Result result = graphDb.execute("MATCH (company:Company)-[:owns]-> (car:Car)" + + Result result = transaction.execute("MATCH (company:Company)-[:owns]-> (car:Car)" + "WHERE car.make='tesla' and car.model='modelX'" + "RETURN company.name"); Map firstResult = result.next(); + Assert.assertEquals(firstResult.get("company.name"), "Baeldung"); } @Test public void testUpdate() { - graphDb.beginTx(); - - graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + transaction = graphDb.beginTx(); + transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + "RETURN baeldung, tesla"); - Result result = graphDb.execute("MATCH (car:Car)" + + Result result = transaction.execute("MATCH (car:Car)" + "WHERE car.make='tesla'" + " SET car.milage=120" + " SET car :Car:Electro" + @@ -127,17 +140,16 @@ public class Neo4jLiveTest { @Test public void testDelete() { - graphDb.beginTx(); - - graphDb.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + + transaction = graphDb.beginTx(); + transaction.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + "RETURN baeldung, tesla"); - graphDb.execute("MATCH (company:Company)" + + transaction.execute("MATCH (company:Company)" + " WHERE company.name='Baeldung'" + " DELETE company"); - Result result = graphDb.execute("MATCH (company:Company)" + + Result result = transaction.execute("MATCH (company:Company)" + " WHERE company.name='Baeldung'" + " RETURN company"); @@ -146,14 +158,13 @@ public class Neo4jLiveTest { @Test public void testBindings() { - graphDb.beginTx(); - + transaction = graphDb.beginTx(); Map params = new HashMap<>(); params.put("name", "baeldung"); params.put("make", "tesla"); params.put("model", "modelS"); - Result result = graphDb.execute("CREATE (baeldung:Company {name:$name}) " + + Result result = transaction.execute("CREATE (baeldung:Company {name:$name}) " + "-[:owns]-> (tesla:Car {make: $make, model: $model})" + "RETURN baeldung, tesla", params); diff --git a/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jOgmLiveTest.java b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jOgmLiveTest.java new file mode 100644 index 0000000000..aa9dd84ed6 --- /dev/null +++ b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/Neo4jOgmLiveTest.java @@ -0,0 +1,58 @@ +package com.baeldung.neo4j; + +import static com.baeldung.neo4j.TestContainersTestBase.getDriver; +import static org.junit.jupiter.api.Assertions.assertEquals; + +import java.util.HashMap; +import java.util.Map; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; +import org.neo4j.ogm.model.Result; +import org.neo4j.ogm.session.Session; +import org.neo4j.ogm.session.SessionFactory; + +import com.baeldung.neo4j.domain.Car; +import com.baeldung.neo4j.domain.Company; + +/** + * To run this test you will need to have an instance of the docker running on your machine (Docker desktop - for Windows and Docker instance for linux) + * After your docker instance is up run this test + */ +public class Neo4jOgmLiveTest { + + private static SessionFactory sessionFactory; + private static Session session; + + @BeforeAll + public static void oneTimeSetUp() { + sessionFactory = new SessionFactory(getDriver(), "com.baeldung.neo4j.domain"); + session = sessionFactory.openSession(); + session.purgeDatabase(); + } + + @Test + void testOgm() { + Car tesla = new Car("tesla", "modelS"); + Company baeldung = new Company("baeldung"); + + baeldung.setCar(tesla); + + session.save(baeldung); + + assertEquals(1, session.countEntitiesOfType(Company.class)); + + Map params = new HashMap<>(); + params.put("make", "tesla"); + Result result = session.query("MATCH (car:Car) <-[:owns]- (company:Company)" + + " WHERE car.make=$make" + + " RETURN company", params); + + Map firstResult = result.iterator().next(); + + assertEquals(1, firstResult.size()); + + Company actual = (Company) firstResult.get("company"); + assertEquals(actual.getName(), baeldung.getName()); + } +} diff --git a/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/TestContainersTestBase.java b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/TestContainersTestBase.java new file mode 100644 index 0000000000..eed2237454 --- /dev/null +++ b/persistence-modules/neo4j/src/test/java/com/baeldung/neo4j/TestContainersTestBase.java @@ -0,0 +1,132 @@ +package com.baeldung.neo4j; + +import static org.neo4j.ogm.drivers.bolt.driver.BoltDriver.CONFIG_PARAMETER_BOLT_LOGGING; + +import java.util.Locale; +import java.util.Optional; + +import org.neo4j.driver.AccessMode; +import org.neo4j.driver.AuthTokens; +import org.neo4j.driver.GraphDatabase; +import org.neo4j.driver.Logging; +import org.neo4j.driver.Session; +import org.neo4j.driver.SessionConfig; +import org.neo4j.ogm.config.Configuration; +import org.neo4j.ogm.driver.Driver; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.testcontainers.containers.Neo4jContainer; +import org.testcontainers.utility.TestcontainersConfiguration; + +/** + * Reference: https://github.com/neo4j/neo4j-ogm/blob/master/neo4j-ogm-tests/neo4j-ogm-integration-tests/src/test/java/org/neo4j/ogm/testutil/TestContainersTestBase.java + */ +public class TestContainersTestBase { + + public static final Logger LOGGER = LoggerFactory.getLogger(TestContainersTestBase.class); + + public static final Driver driver; + + public static final String version; + + public static final String DEFAULT_IMAGE = "neo4j:5"; + + public static final String SYS_PROPERTY_ACCEPT_AND_USE_COMMERCIAL_EDITION = "NEO4J_OGM_NEO4J_ACCEPT_AND_USE_COMMERCIAL_EDITION"; + + public static final String SYS_PROPERTY_IMAGE_NAME = "NEO4J_OGM_NEO4J_IMAGE_NAME"; + + public static final String SYS_PROPERTY_NEO4J_URL = "NEO4J_OGM_NEO4J_URL"; + + public static final String SYS_PROPERTY_NEO4J_PASSWORD = "NEO4J_OGM_NEO4J_PASSWORD"; + + public static final String DEFAULT_PASSWORD = "12345"; + + public static Neo4jContainer neo4jServer; + + public static Configuration.Builder baseConfigurationBuilder; + + public static final String NEO4J_URL = Optional.ofNullable(System.getenv(SYS_PROPERTY_NEO4J_URL)).orElse(""); + + public static final String NEO4J_PASSWORD = Optional.ofNullable(System.getenv(SYS_PROPERTY_NEO4J_PASSWORD)).orElse("").trim(); + + static { + + boolean acceptAndUseCommercialEdition = hasAcceptedAndWantsToUseCommercialEdition(); + + if (!(NEO4J_URL.isEmpty() || NEO4J_PASSWORD.isEmpty())) { + LOGGER.info("Using Neo4j instance at {}.", NEO4J_URL); + driver = new org.neo4j.ogm.drivers.bolt.driver.BoltDriver(); + baseConfigurationBuilder = new Configuration.Builder() + .uri(NEO4J_URL) + .verifyConnection(true) + .withCustomProperty(CONFIG_PARAMETER_BOLT_LOGGING, Logging.slf4j()) + .credentials("neo4j", NEO4J_PASSWORD); + driver.configure(baseConfigurationBuilder.build()); + version = extractVersionFromBolt(); + } else { + LOGGER.info("Using Neo4j test container."); + String imageName = Optional.ofNullable(System.getenv(SYS_PROPERTY_IMAGE_NAME)) + .orElse(DEFAULT_IMAGE + (acceptAndUseCommercialEdition ? "-enterprise" : "")); + + version = extractVersionFromDockerImage(imageName); + + boolean containerReuseSupported = TestcontainersConfiguration + .getInstance().environmentSupportsReuse(); + neo4jServer = new Neo4jContainer<>(imageName) + .withReuse(containerReuseSupported); + + if (acceptAndUseCommercialEdition) { + neo4jServer.withEnv("NEO4J_ACCEPT_LICENSE_AGREEMENT", "yes"); + } + neo4jServer.withAdminPassword(DEFAULT_PASSWORD).start(); + + driver = new org.neo4j.ogm.drivers.bolt.driver.BoltDriver(); + + baseConfigurationBuilder = new Configuration.Builder() + .uri(neo4jServer.getBoltUrl()) + .credentials("neo4j", DEFAULT_PASSWORD) + .verifyConnection(true) + .withCustomProperty(CONFIG_PARAMETER_BOLT_LOGGING, Logging.slf4j()); + + driver.configure(baseConfigurationBuilder.build()); + + Runtime.getRuntime().addShutdownHook(new Thread(neo4jServer::stop)); + } + } + + public static org.neo4j.driver.Driver getNewBoltConnection() { + + if (neo4jServer != null) { + return GraphDatabase.driver(neo4jServer.getBoltUrl(), AuthTokens.basic("neo4j", DEFAULT_PASSWORD)); + } else { + return GraphDatabase.driver(NEO4J_URL, AuthTokens.basic("neo4j", NEO4J_PASSWORD)); + } + } + + public static boolean hasAcceptedAndWantsToUseCommercialEdition() { + return Optional.ofNullable( + System.getenv(TestContainersTestBase.SYS_PROPERTY_ACCEPT_AND_USE_COMMERCIAL_EDITION)) + .orElse("no").toLowerCase(Locale.ENGLISH).equals("yes"); + } + + public static Driver getDriver() { + return driver; + } + + private static String extractVersionFromDockerImage(String imageName) { + return imageName.replace("neo4j:", "").replace("neo4j/neo4j-experimental:", "").replace("-enterprise", ""); + } + + private static String extractVersionFromBolt() { + + org.neo4j.driver.Driver driver = getDriver().unwrap(org.neo4j.driver.Driver.class); + + String version; + SessionConfig sessionConfig = SessionConfig.builder().withDefaultAccessMode(AccessMode.READ).build(); + try (Session session = driver.session(sessionConfig)) { + version = (String) session.run("CALL dbms.components() YIELD versions").single().get("versions").asList().get(0); + } + return version.toLowerCase(Locale.ENGLISH); + } + +} \ No newline at end of file diff --git a/persistence-modules/pom.xml b/persistence-modules/pom.xml index 9361e26d7d..39172d7f42 100644 --- a/persistence-modules/pom.xml +++ b/persistence-modules/pom.xml @@ -93,7 +93,6 @@ spring-data-mongodb-2 spring-data-mongodb-reactive - spring-data-redis @@ -113,6 +112,7 @@ spring-data-rest java-mongodb questdb + neo4j diff --git a/persistence-modules/spring-data-neo4j/pom.xml b/persistence-modules/spring-data-neo4j/pom.xml index 8c5030779b..33f2966db3 100644 --- a/persistence-modules/spring-data-neo4j/pom.xml +++ b/persistence-modules/spring-data-neo4j/pom.xml @@ -14,26 +14,11 @@ - - org.neo4j - neo4j - ${neo4j.version} - - - org.neo4j - neo4j-ogm-core - ${neo4j-ogm.version} - org.neo4j neo4j-ogm-embedded-driver ${neo4j-ogm.version} - - org.neo4j.driver - neo4j-java-driver - ${neo4j-java-driver.version} - org.springframework.data spring-data-neo4j @@ -51,24 +36,6 @@ ${spring-boot.version} test - - org.neo4j - neo4j-kernel - ${neo4j.version} - test-jar - - - org.neo4j.app - neo4j-server - ${neo4j.version} - test-jar - - - commons-logging - commons-logging - - - org.neo4j neo4j-ogm-test @@ -89,7 +56,6 @@ - 1.6.2 3.4.6 5.0.1.RELEASE 1.1 diff --git a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4JServerLiveTest.java b/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4JServerLiveTest.java deleted file mode 100644 index bf187ccb2d..0000000000 --- a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4JServerLiveTest.java +++ /dev/null @@ -1,60 +0,0 @@ -package com.baeldung.neo4j; - -import java.sql.Connection; -import java.sql.DriverManager; -import java.sql.ResultSet; -import java.sql.Statement; - -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; -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.StatementResult; - -@Ignore -public class Neo4JServerLiveTest { - - @Test - public void standAloneDriver() { - Driver driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "12345")); - Session session = driver.session(); - - session.run("CREATE (baeldung:Company {name:\"Baeldung\"}) " + - "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + - "RETURN baeldung, tesla"); - - StatementResult result = session.run("MATCH (company:Company)-[:owns]-> (car:Car)" + - "WHERE car.make='tesla' and car.model='modelX'" + - "RETURN company.name"); - - Assert.assertTrue(result.hasNext()); - Assert.assertEquals(result.next().get("company.name").asString(), "Baeldung"); - - session.close(); - driver.close(); - } - - @Test - public void standAloneJdbc() throws Exception { - Connection con = DriverManager.getConnection("jdbc:neo4j:bolt://localhost/?user=neo4j,password=12345,scheme=basic"); - - // Querying - try (Statement stmt = con.createStatement()) { - stmt.execute("CREATE (baeldung:Company {name:\"Baeldung\"}) " + - "-[:owns]-> (tesla:Car {make: 'tesla', model: 'modelX'})" + - "RETURN baeldung, tesla"); - - ResultSet rs = stmt.executeQuery("MATCH (company:Company)-[:owns]-> (car:Car)" + - "WHERE car.make='tesla' and car.model='modelX'" + - "RETURN company.name"); - - while (rs.next()) { - Assert.assertEquals(rs.getString("company.name"), "Baeldung"); - } - } - con.close(); - } -} diff --git a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4jOgmLiveTest.java b/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4jOgmLiveTest.java deleted file mode 100644 index 96e5e76402..0000000000 --- a/persistence-modules/spring-data-neo4j/src/test/java/com/baeldung/neo4j/Neo4jOgmLiveTest.java +++ /dev/null @@ -1,47 +0,0 @@ -package com.baeldung.neo4j; - -import java.util.HashMap; -import java.util.Map; - -import org.junit.Assert; -import org.junit.Test; -import org.neo4j.ogm.config.Configuration; -import org.neo4j.ogm.model.Result; -import org.neo4j.ogm.session.Session; -import org.neo4j.ogm.session.SessionFactory; - -import com.baeldung.spring.data.neo4j.domain.Car; -import com.baeldung.spring.data.neo4j.domain.Company; - -public class Neo4jOgmLiveTest { - - @Test - public void testOgm() { - Configuration conf = new Configuration.Builder().build(); - - SessionFactory factory = new SessionFactory(conf, "com.baeldung.spring.data.neo4j.domain"); - Session session = factory.openSession(); - - Car tesla = new Car("tesla", "modelS"); - Company baeldung = new Company("baeldung"); - - baeldung.setCar(tesla); - - session.save(baeldung); - - Assert.assertEquals(1, session.countEntitiesOfType(Company.class)); - - Map params = new HashMap<>(); - params.put("make", "tesla"); - Result result = session.query("MATCH (car:Car) <-[:owns]- (company:Company)" + - " WHERE car.make=$make" + - " RETURN company", params); - - Map firstResult = result.iterator().next(); - - Assert.assertEquals(firstResult.size(), 1); - - Company actual = (Company) firstResult.get("company"); - Assert.assertEquals(actual.getName(), baeldung.getName()); - } -} diff --git a/pom.xml b/pom.xml index e5311ec25f..b8bc85d634 100644 --- a/pom.xml +++ b/pom.xml @@ -369,6 +369,7 @@ persistence-modules/hibernate-ogm persistence-modules/java-cassandra persistence-modules/spring-data-cassandra-reactive + persistence-modules/spring-data-neo4j @@ -545,6 +546,7 @@ persistence-modules/hibernate-ogm persistence-modules/java-cassandra persistence-modules/spring-data-cassandra-reactive + persistence-modules/spring-data-neo4j