Edit Page

How to deploy Plugins

Introduction

This section provides information on how to package and deploy plugins.

Note
To quick start a new Java plugin, you can clone the plugin skeleton repository. It contains a basic skeleton for a plugin and an helper script that allows to build, deploy the plugin.

Deploying Java Plugins in RESTHeart

Java (and Kotlin, Scala, etc.) plugins must be packaged as JAR files. Deploying a plugin is straightforward: just copy its JAR file into the ./plugins directory of RESTHeart.

IMPORTANT: After deploying a JAR plugin, you must restart RESTHeart.

You can also nest your JARs into the ./plugins directory up to two levels deep. This is particularly useful when developing a custom plugin. In this scenario, your Java project directory structure might look like this:

.
├── LICENSE
├── README.md
├── pom.xml
├── src
│   ├── main
│   └── test
└── target
    ├── classes
    ├── lib
    │   ├── lib1.jar
    │   └── lib2.jar
    ├── plugin.jar

In this case, you need to deploy plugin.jar along with the dependency libraries lib1.jar and lib2.jar.

To deploy, you can simply copy the entire target directory into the ./plugins directory. If you are using Docker, you can mount the target directory under /opt/restheart/plugins/custom with the following command:

$ docker run --name restheart --rm -p "8080:8080" -v ./target:/opt/restheart/plugins/custom softinstigate/restheart

Example

As an example we will build and deploy the simple Greeter Service example plugin.

Let’s clone the RESTHeart repository that includes the examples directory and build the greeter-service example.

$ git clone --depth 1 git@github.com:SoftInstigate/restheart.git
$ cd restheart/examples/greeter-service
$ ../mvnw clean package

The built plugin jar file is target/greeter-service.jar. Copy it into the RESTHeart plugins directory.

$ cp target/greeter-service.jar <RH_HOME>/plugins

Restarting RESTHeart will produce the following log message:

$ java -jar restheart.jar
INFO  org.restheart.Bootstrapper - Starting RESTHeart instance default
...
INFO  org.restheart.plugins.PluginsFactory - Found plugin jar file:/Users/uji/development/restheart/core/target/plugins/greeter-service.jar
...
INFO  org.restheart.Bootstrapper - URI /greetings bound to service greetings, secured: false, uri match PREFIX
....

Let’s test it (for example, using the httpie client):

$ http -b :8080/greetings
{
    "message": "Hello World!"
}

External dependencies

The Random String Service example plugin shows how to add to the classpath an external dependency required by a plugin.

By external dependency we mean a dependency that is not included in restheart, thus it must be added to the classpath for the service to work.

Important
To add an external dependency to the classpath just copy it into the RESTHeart plugins directory.
Important
Starting from v8.1.0, Restheart will no longer scan library jars for plugins. A jar file will be categorized as a library if it resides in a subdirectory of the ./plugins directory that includes "lib", "-lib", or "_lib" in its relative path.

The plugin pom.xml file defines the following dependencies:

<dependencies>
    <dependency>
        <groupId>org.restheart</groupId>
        <artifactId>restheart-commons</artifactId>
        <scope>provided</scope>
    </dependency>
    <dependency>
        <groupId>org.apache.commons</groupId>
        <artifactId>commons-lang3</artifactId>
        <version>3.10</version>
    </dependency>
</dependencies>

The scope of restheart-commons is provided since it is provided by the RESTHeart runtime, together with many others.

To get a list of all the dependencies included in the RESTHeart runtime, you can use the following command:

$ cd <RH_HOME>/core
$ ../mvnw dependency:tree -Dscope=compile

On the other side, the scope of commons-lang3 is compile as it is not provided by the RESTHeart runtime. Thus it is an external dependency and it must be copied into the RESTHeart plugins directory.

Let’s build the plugin.

$ git clone --depth 1 git@github.com:SoftInstigate/restheart.git
$ cd restheart/examples/random-string-service
$ ../mvnw clean package

The pom.xml uses the maven-dependency-plugin to copy the jars of the external dependencies into the directory target/lib

To deploy the plugin copy its jar file and the jars of the dependencies into the plugins directory.

$ mkdir <RH_HOME>/plugins/lib
$ cp target/random-string-service.jar target/lib/* <RH_HOME>/plugins/lib

With Docker this is ever more straightforward. Mounting the target directory in the container /opt/restheart/plugins/custom directory, will deploy it together with the library jar contained in target/lib.

$ docker run --name restheart --rm -e RHO="/http-listener/host->'0.0.0.0';/mclient/connection-string->'mongodb://host.docker.internal';/helloWorldService/message->'Ciao Mondo!'" -p "8080:8080" -v ./target:/opt/restheart/plugins/custom softinstigate/restheart -s

Speeding Up Plugin Scanning at Startup

If a custom plugin has many dependencies, you may need to copy numerous JAR files into the ./plugins directory. All JARs are scanned to find plugins (classes annotated with @RegisterPlugin), which can slow down the bootstrap process.

To address this, the configuration option /core/plugins-packages allows you to limit the scanning to specific packages (and their sub-packages).

core:
  ...
  # Limit the scanning of classes annotated with @RegisterPlugin
  # to the specified packages. This can speed up the boot time
  # for large plugin JARs. It is usually not required.
  # Use an empty array to not limit scanning.
  # Always add the package org.restheart to the list.
  plugins-packages: [ org.restheart, com.acme ]

For example, the following command limits the scanning to org.restheart and com.acme:

$ RHO='/core/plugins-packages->[ "org.restheart", "com.acme" ]' java -jar restheart.jar

By specifying only the necessary packages, you can significantly reduce startup times when dealing with large plugin JARs.

JavaScript Plugins

Important
JavaScript plugins can be deployed only running RESTHeart on GraalVM and on restheart native.
Note
Deploying JavaScript plugins does not require restarting RESTHeart, they can be hot-deployed! To update an already deployed JavaScript plugin, touch its root directory.

The JavaScript plugins are packaged in directories containing the JavaScript files and the package.json file.

The JavaScript plugin Credit Card Hider is an example.

Its package.json file declares the Interceptor cc-hider.js via the property rh:interceptors (Services are declared with rh:services):

{
  "name": "restheart-demo-cc-hider",
  "version": "1.0.0",
  "description": "demo plugins for RESTHeart",
  "rh:interceptors": [ "cc-hider.js" ]
}

Let’s deploy it.

$ git clone --depth 1 git@github.com:SoftInstigate/restheart.git
$ cp -r restheart/examples/credit-card-hider <RH_HOME>/plugins

RESTHeart log files shows the following message:

INFO  o.r.polyglot.PolyglotDeployer - Added interceptor ccHider, description: hides credit card numbers

Refer to the Credit Card Hider README.md for more information on how to play with this JavaScript plugin.

Note
More JavaScript plugins examples are available in the examples/js-plugin directory of RESTHeart repository.

Deploy Java plugins on RESTHeart Native

RESTHeart native can run JavaScript plugins as previously described.

However you cannot deploy Java plugins in RESTHeart native by merely copying jars file into the plugins directory (this will be allowed in the future).

In order to use Java plugins on RESTHeart native you must build them as native image together with RESTHeart.

The repository restheart-plugin-skeleton defines a skeleton project for Java plugins. Its pom.xml maven file defines the native profile that uses the native-maven-plugin to build the native image, defining the required dependencies.

Fork the repository

$ git clone git@github.com:SoftInstigate/restheart-plugin-skeleton.git
$ cd restheart-plugin-skeleton

Make sure you are using GraalVM.

$ java -version
openjdk version "21.0.2" 2024-01-16
OpenJDK Runtime Environment GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30)
OpenJDK 64-Bit Server VM GraalVM CE 21.0.2+13.1 (build 21.0.2+13-jvmci-23.1-b30, mixed mode, sharing)

Build it.

$ ./mvnw clean package -Pnative