Looking for Cloud Services or Professional Support? Check restheart.com

How to deploy Plugins

Introduction

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

Java Plugins

Java and Kotlin plugins must be packaged as jar files.

To deploy a plugin, just copy its jar file into the directory ./plugins of RESTHeart.

Important
After deploying a jar plugin, you must restart 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 etc/restheart.yml -e etc/default.properties
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.jar, 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.

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.

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

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 test-js-plugins directory.

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 "17.0.3" 2022-04-19
OpenJDK Runtime Environment GraalVM CE 22.1.0 (build 17.0.3+7-jvmci-22.1-b06)
OpenJDK 64-Bit Server VM GraalVM CE 22.1.0 (build 17.0.3+7-jvmci-22.1-b06, mixed mode, sharing)

Make sure you have native-image installed.

$ gu install native-image

Build it.

$ ./mvnw clean package -Pnative

Native image reflection configuration for Java plugins

Note
more on GraalVM reflection configuration can be found at Reflection on Native Image

For a simple example you can look at reflect-config.json file of the plugin skeleton project.

In short you need to create in your plugin source project the file src/main/resources/META-INF/native-image/<group-id>/<artifact-id>/reflect-config.json and add an entry per each plugin.

The following entry is an example:

[
  {
    "name": "org.restheart.examples.HelloWorldService",
    "methods": [{ "name": "<init>", "parameterTypes": [] }]
  }
]

For each of your Service, Interceptor and Initializer you need to specify an entry with name equal to the class name of your component and the methods array with:

  1. the default Constructor (always)

  2. the method annotated with @InjectConfiguration (if any)

  3. the method annotated with @InjectMongoClient (if any)

  4. the method annotated with @InjectPluginsRegistry (if any)