Quarkus meets Neo4j

Quarkus meets Neo4j

I’m gonna first speak briefly about Neo4j itself, what’s the core product and why you might interested in it.
Give you an idea about my background (while this is often irrelevant or marketing, it may be of interest in the context of Quarkus)
Praise the Java community, which despite some other rumors manages to work closely together with great benefit for the whole ecosystem
We will than have a look at the building blocks of a Quarkus extension as well as the Neo4j database drivers
Quarkus calls itself „Supersonic subatomic Java“ and „a Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM“, meaning that applications build with it should be able to use GraalVM’s native-image tool to produce binary running GraalVMs SubstrateVM. For us this required changes to our Java driver which I would like to discuss as well.
And last but not least, I want to show you the resulting pieces in action

20492a196bb034ad3aa7e05e593fede9?s=128

Michael Simons

September 09, 2020
Tweet

Transcript

  1. About writing a natively compilable Quarkus extension Michael Simons, @rotnroll666

    Quarkus meets Neo4j
  2. Quarkus meets Neo4j by @rotnroll666 • About Neo4j • About

    me and Quarkus • Building blocks of… • … the Neo4j database driver • … a Quarkus extension • The search for the holy Graal(VM): AoT compiling a database driver. 2 Agenda
  3. About Neo4j

  4. Ecosystem Neo4j Professional Services 300+ partners 47,000 group members 61,000

    trained engineers 3.5M downloads Mindset “Graph Thinking” is all about considering connections in data as important as the data itself. Native Graph Platform Neo4j is an internet-scale, native graph database which executes connected workloads faster than any other database management system. Neo4j 4
  5. The whiteboard model IS the physical model • Bands are

    founded in and solo artists are born in countries • Sometimes Artists are associated with other Artists and bands have member • Artists used to release Albums :Artist :Band :SoloArtist :Country :FOUNDED_IN :BORN_IN :ASSOCIATED_WITH :HAS_MEMBER :Album :RELEASED_BY 5
  6. Querying with Cypher • Cypher is to Neo4j what SQL

    is to RDBMS: A declarative, powerful query language • https://www.opencypher.org / The GQL Manifesto MATCH (a:Album) -[:RELEASED_BY]-# (b:Band), (c) $-[:FOUNDED_IN]- (b) -[:HAS_MEMBER]-# (m) -[:BORN_IN]-# (c2) WHERE a.name = 'Innuendo' RETURN b, m, c, c2 6
  7. About me and Quarkus

  8. Quarkus meets Neo4j by @rotnroll666 • Neo4j since July 2018

    • Java Champion • Co-Founder and current lead of Java User Group EuregJUG • Author (Spring Boot 2 und Arc42 by example) About me 8 First contact to Neo4j through
  9. Quarkus meets Neo4j by @rotnroll666 Graph Tour 2019 9 Now

    online: https://neo4j.com/graphtour/
  10. Quarkus meets Neo4j by @rotnroll666 Graph Tour 2019 9 Now

    online: https://neo4j.com/graphtour/
  11. Quarkus meets Neo4j by @rotnroll666 A Hibernate team lead appears…

    10 With Sanne Grinovero, Hibernate Team Lead & Quarkus R&D
  12. Building blocks

  13. Quarkus meets Neo4j by @rotnroll666 12 The Neo4j Java-Driver <dependency>

    <groupId>org.neo4j.driver#$groupId> <artifactId>neo4j-java-driver#$artifactId> <version>4.1.1#$version> #$dependency> var driver = GraphDatabase.driver( "bolt:#%localhost:7687", AuthTokens.basic("neo4j", "secret"), Config.builder().withLogging(Logging.console(Level.INFO)).build() );
  14. Quarkus meets Neo4j by @rotnroll666 13 Imperative sessions Function<Record, String>

    getNameFromRecord = record #& record.get("name").asString(); try (var session = driver.session()) { var names = session.readTransaction( tx #& tx .run("MATCH (n:Artist) RETURN n.name AS name") .stream().map(getNameFromRecord) .collect(toList()) ); names.forEach(System.out#'println); }
  15. Quarkus meets Neo4j by @rotnroll666 14 Reactive sessions with Project

    Reactor Function<Record, String> getNameFromRecord = record #& record.get("name").asString(); RxTransactionWork<Publisher<Record#( txFunction = tx #& tx.run("MATCH (n:Artist) RETURN n.name AS name").records(); Flux.usingWhen( Mono.fromSupplier(driver#'rxSession), session #& session.readTransaction(txFunction), RxSession#'close ) .map(getNameFromRecord) .doOnNext(System.out#'println) .blockLast(); !" Don't block at home
  16. Quarkus meets Neo4j by @rotnroll666 15 Reactive sessions with SmallRye

    Mutiny Function<Record, String> getNameFromRecord = record #& record.get("name").asString(); RxTransactionWork<Publisher<Record#( txFunction = tx #& tx.run("MATCH (n:Artist) RETURN n.name AS name").records(); Uni.createFrom().item(driver#'rxSession).toMulti() .flatMap(session #& session.readTransaction(txFunction)) .map(getNameFromRecord) .subscribe() .asStream() .forEach(System.out#'println);
  17. Quarkus meets Neo4j by @rotnroll666 16 The Quarkus extension system

    var driver = GraphDatabase.driver( "bolt:#%localhost:7687", AuthTokens.basic("neo4j", "secret"), Config.builder().withLogging(Logging.console(Level.INFO)).build() );
  18. Quarkus meets Neo4j by @rotnroll666 16 The Quarkus extension system

    quarkus.neo4j.uri = bolt:#%localhost:7687 quarkus.neo4j.authentication.username = neo4j quarkus.neo4j.authentication.password = secret @Path("/hello") public class ExampleResource { private final Driver driver; @Inject public ExampleResource(Driver driver) { this.driver = driver; } }
  19. Quarkus meets Neo4j by @rotnroll666 • The runtime module which

    represents the capabilities the extension developer exposes to the application’s developer • The deployment module which is used during the augmentation phase of the build, it describes how to "deploy" a library following the Quarkus philosophy The deployment module often depends on the runtime module. 17 The Quarkus extension system A Quarkus extension consists of two parts:
  20. Quarkus meets Neo4j by @rotnroll666 • GraalVM restrictions • Dynamic

    class loading (Classes must be enumerated) • Reflection (Must be enumerated, too) • JCA (Java Cryptography Architecture) needs special treatment • Optimizing things (i.e. Replacing Service Loader with an index) • @BuildStep’s record byte code with @Recorder’s 18 The Quarkus extension system Three phases of bootstrapping: 1. Augmentation via build step processors
  21. Quarkus meets Neo4j by @rotnroll666 •@Record(STATIC_INIT) • Will run in

    a static init method on the main class during native build • Executed on the standard JVM during build • Objects will be directly serialized into the native executable 19 The Quarkus extension system Three phases of bootstrapping: 2. Static init
  22. Quarkus meets Neo4j by @rotnroll666 •@Record(RUNTIME_INIT) • Will run from

    the applications main method during native boot 20 The Quarkus extension system Three phases of bootstrapping: 3. Runtime init
  23. Quarkus meets Neo4j by @rotnroll666 •@Record(RUNTIME_INIT) • Will run from

    the applications main method during native boot 21
  24. Quarkus meets Neo4j by @rotnroll666 •@Record(RUNTIME_INIT) • Will run from

    the applications main method during native boot 21
  25. Quarkus meets Neo4j by @rotnroll666 •@Record(RUNTIME_INIT) • Will run from

    the applications main method during native boot 21
  26. Quarkus meets Neo4j by @rotnroll666 •@Record(RUNTIME_INIT) • Will run from

    the applications main method during native boot 21
  27. Quarkus meets Neo4j by @rotnroll666 •@Record(RUNTIME_INIT) • Will run from

    the applications main method during native boot 21
  28. Quarkus meets Neo4j by @rotnroll666 •BUILD_TIME •BUILD_AND_RUN_TIME_FIXED •RUN_TIME 22 The

    Quarkus extension system Phases of configuration
  29. Quarkus meets Neo4j by @rotnroll666 23 Demo @Path("/artists") public class

    ArtistsResource { private final Driver driver; @Inject public ArtistsResource(Driver driver) { this.driver = driver; } private Multi<Record> executeArtistQuery(RxSession session) { return Multi.createFrom().publisher( session.readTransaction(tx #& tx.run("MATCH (n:Artist) RETURN n.name AS name").records()) ); } @GET @Produces(MediaType.APPLICATION_JSON) public Multi<String> getArtists() { return Uni.createFrom().item(driver#'rxSession) .toMulti() .flatMap(this#'executeArtistQuery) .map(record #& record.get("name").asString()); } }
  30. The search for the holy Graal(VM): AoT compiling a database

    driver.
  31. Quarkus meets Neo4j by @rotnroll666 25

  32. Quarkus meets Neo4j by @rotnroll666 • Neo4j: https://neo4j.com • Neo4j

    Quarkus Guide: https://quarkus.io/guides/neo4j • Neo4j Java Driver Manual: https://neo4j.com/docs/driver-manual/current/ • The demo project: https://github.com/michael-simons/neo4j-sdn-ogm-tips/tree/master/ examples/simple-quarkus • Neo4j Migrations: https://github.com/michael-simons/neo4j-migrations • Cypher-DSL: https://github.com/neo4j-contrib/cypher-dsl 26 Resources