Setting up a plugin project

You can set up a project for extending Neo4j with a user-defined procedure, build the project, and deploy the procedure to a Neo4j instance. The same steps can be used for user-defined functions.

The example described in this section is available on GitHub (neo4j-examples/neo4j-procedure-template).

Set up a project with Maven

A project can be set up in any way that allows for compiling a procedure and producing a JAR file.

Below are the main parts of the example configuration, using the Maven build system.

Excerpts from the Maven pom.xml file
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>org.neo4j.example</groupId>
  <artifactId>procedure-template</artifactId>
  <version>1.0.0-SNAPSHOT</version>

  <packaging>jar</packaging>
  <name>Neo4j Procedure Template</name>
  <description>A template project for building a Neo4j Procedure</description>

  <properties>
    <java.version>17</java.version>
    <maven.compiler.release>${java.version}</maven.compiler.release>

    <neo4j.version>5.26.0</neo4j.version>
  </properties>

Build dependencies

Add a dependency section that includes the procedure and function APIs, which procedures and functions use at runtime.

The scope is set to provided because once the procedure is deployed to a Neo4j instance, this dependency is provided by Neo4j. If non-Neo4j dependencies are added to the project, their scope should normally be compile.

<dependency>
 <groupId>org.neo4j</groupId>
 <artifactId>neo4j</artifactId>
 <version>${neo4j.version}</version>
 <scope>provided</scope>
</dependency>

Add dependencies that are necessary for testing the procedure.

Neo4j Harness, a utility that allows for starting a lightweight Neo4j instance. It is used to start Neo4j with a specific procedure or function deployed, which greatly simplifies testing.

Neo4j Java Driver, used to send Cypher statements that call the procedure or function.

JUnit, a common Java test framework.

<dependency>
 <groupId>org.neo4j.test</groupId>
 <artifactId>neo4j-harness</artifactId>
 <version>${neo4j.version}</version>
 <scope>test</scope>
</dependency>

<dependency>
 <groupId>org.neo4j.driver</groupId>
 <artifactId>neo4j-java-driver</artifactId>
 <version>5.27.0</version>
 <scope>test</scope>
</dependency>

<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.9.1</version>
<scope>test</scope>
</dependency>

Build steps

The steps that Maven will go through to build the project.

The goal is first to compile the source, then to package it in a JAR that can be deployed to a Neo4j instance.

The Maven Shade plugin is used to package the compiled procedure. It also includes all dependencies in the package, unless the dependency scope is set to test or provided.

Once the procedure has been deployed to the plugins directory of each Neo4j instance and the instances have restarted, the procedure is available for use.

<build>
<plugins>
 <plugin>
   <artifactId>maven-compiler-plugin</artifactId>
   <configuration>
     <source>17</source>
     <target>17</target>
   </configuration>
 </plugin>
 <plugin>
   <artifactId>maven-shade-plugin</artifactId>
   <executions>
     <execution>
       <phase>package</phase>
       <goals>
         <goal>shade</goal>
       </goals>
     </execution>
   </executions>
 </plugin>
</plugins>
</build>

Implement custom seed providers

The Seed from URI feature provides the ability to dynamically discover additional seed provider implementations from the class path.

Seed providers should be implemented in Java and this guide provides instructions on how to do this using Maven as the build tool.

Set up a Maven project

Include this dependency to build against the Neo4j-provided API:

<dependency>
   <groupId>com.neo4j</groupId>
   <artifactId>neo4j-dbms-api</artifactId>
   <version>${project.version}</version>
   <scope>compile</scope>
</dependency>

Implement Java class

DatabaseSeedProvider

In Neo4j 5.26, the DatabaseSeedProvider was introduced to replace the now-deprecated SeedProvider.

import com.neo4j.dbms.seeding.DatabaseSeedProvider;

public class CustomDatabaseSeedProvider implements DatabaseSeedProvider {

  @Override
	public boolean matches(String uri) {
   		// Return true if uri is supported by this
      // provider.
  }

  @Override
  public InputStream stream(
          String uri,
          Map<String, Object> options) throws IOException {
          // This method should obtain an input stream in an
          // implementation specific way.
  }

  @Override
  public void inject(Dependencies dependencies) {
      // This method should provide implementation
      // specific dependencies to the provider.
  }

  public static class CustomDependencies implements Dependencies {
        @Override
        public <T> T resolveDependency(Class<T> type) {
            // This method should resolve dependencies
            // required by the provider.
        }
    }
}

To implement the custom database seed provider, you must define three methods on the top-level DatabaseSeedProvider interface:

  • A method to match the URIs that the provider can manage.

  • A method to stream backups or dumps from a specified URI.

  • A method to inject dependencies in the provider.

Additionally, you must implement a method on the nested Dependencies interface to resolve any dependencies required by your seed provider implementation.

Typically, the match method uses the URI scheme (the part specified before the first colon) to determine whether it can support the given URI or not. For example, file, http, https etc.

The stream method should implement a scheme-specific way to obtain an input stream for the backup or dump.

Implementation-specific seed configuration can be passed through from options specified in the CREATE DATABASE command using seedConfig.

SeedProvider

import com.neo4j.dbms.seeding.ParsedSeedProviderConfig;
import com.neo4j.dbms.seeding.SeedProvider;

public class CustomSeedProvider extends SeedProvider {

	public boolean matches(String uri) {
   		// return true if uri is supported by this
      // provider
  }

public Path download(
     	String uri,
      Optional<String> credentials,
      Optional<String> config,
      Path destinationFolder ) throws Exception {
      // This method should obtain the downloaded in an
      // implementation specific way and copy it to a
      // file within the destinationFolder directory.
  }
}

To implement the custom seed provider, you must implement two methods. One method to match the URIs it can manage and one to download backups or dumps from the given URI.

Typically, the match method uses the URI scheme (the part specified before the first colon) to determine whether it can support the given URI or not. For example, file, http, https etc.

The download method should implement a scheme-specific way to obtain the backup or dump and place it into a file in the supplied destination folder. It should then return the path of the created file.

Both credentials and configurations are passed through from options specified in the CREATE DATABASE command. ParsedSeedProviderConfig provides a convenient way to parse and access the comma-separated configuration string.

Deploy

Build a jar file from Maven and place this onto the Neo4j classpath.

The jar must include a META-INF file to enable discovery of the providers with the path:

/META_INF/services/com.neo4j.dbms.seeding.SeedProvider

It should be a plain text file with one line for each provider contained within the jar, the line should contain the fully qualified name of the provider class.

If you need assistance with custom seed providers, please contact Professional Services.