Introduction

HiveMQ offers a free and open source Extension SDK with service provider interfaces. The Extension System can be used to extend HiveMQ with custom business logic or to integrate virtually any system into HiveMQ.

Functionality that can be added with the help of the HiveMQ Extention System includes writing messages to a databases, integration of other service buses, collecting statistics, adding fine-grained security and virtually anything else you can imagine.
Extension development for HiveMQ is as easy as writing a Java main method once you grasp the core concepts. This documentation covers all relevant topics to get you started as quickly as possible. If you prefer to learn from real world extensions, visit the HiveMQ Github page.

This guide lists all possibilities of the HiveMQ Extension SDK.

HiveMQ 3 Extensions are not compatible with HiveMQ 4.


Pre-requisites

The pre-requisites for starting the development of your personal custom HiveMQ Extension are minimal. All you need is a basic understanding of the Java programming language and the following two components.

  1. OpenJDK 11 or newer

  2. Maven

Additionally, the use of a Java Development IDE like Eclipse or IntelliJ is strongly recommended.




Project Structure

HiveMQ Extension Structure

:Project Structure

A minimal HiveMQ extension consists of 1 Java class, a text file and an XML file.

  1. A class that implements com.hivemq.extension.sdk.api.ExtensionMain

  2. A text file residing in META-INF/services named _com.hivemq.extension.sdk.api.ExtensionMain

  3. An XML file in the resources folder named hivemq-extension.xml

Using the Maven Archetype
There is a Maven Archetype available, which generates all classes and files needed for an extension.




ExtensionMain

Starting point of every extension development is a class that implements the ExtensionMain class of the HiveMQ Extension SDK.
The methods extensionStart and extensionStop need to be overridden in order to enable the HiveMQ Extension Hot Reload, which enables HiveMQ to add or remove Extensions at runtime.

Example

The following demonstrates the minimal contents of your HiveMQ Extensions Main class, as provided by the Maven Archetype.

public class HelloWorldMain implements ExtensionMain {

    private static final @NotNull Logger log = LoggerFactory.getLogger(HelloWorldMain.class);

    @Override
    public void extensionStart(final @NotNull ExtensionStartInput extensionStartInput, final @NotNull ExtensionStartOutput extensionStartOutput) {

        try {

            log.info("Started " + extensionStartInput.getExtensionInformation().getName() + ":" + extensionStartInput.getExtensionInformation().getVersion());

        } catch (Exception e) {
            log.error("Exception thrown at extension start: ", e);
        }

    }

    @Override
    public void extensionStop(final @NotNull ExtensionStopInput extensionStopInput, final @NotNull ExtensionStopOutput extensionStopOutput) {

        log.info("Stopped " + extensionStartInput.getExtensionInformation().getName() + ":" + extensionStartInput.getExtensionInformation().getVersion());

    }

}



Extension Information

The HiveMQ Extension SDK provides a dedicated XML file hivemq-extension.xml, which can be used to store meta information as well as the extension priority
We strongly recommend utilising this method as HiveMQ will log this information, when the extension is loaded. This information can be useful for monitoring and debugging purposes and different extensions may have different priorities.

Extension Information Example
<hivemq-extension>
    <id>hello-world-extension</id>
    <name>Hello World Extension</name>
    <version>1.0-SNAPSHOT</version>
    <priority>1000</priority>
    <author>dc-square-GmbH</author>
</hivemq-extension>



Don’t Block

The single most important rule for all extension is: Don’t block any outputs. Never. You can use the com.hivemq.extension.sdk.api.ManagedExtenstionExecutorService for every action that might potentially block in the callback of an output.
By the way: It’s also a great practise to use Connection Pools (e.g. HikariCP) if you are dealing with databases.

The following demonstrates an example, where the ManagedExtensionExecutorService is used to accomplish non-blocking callback behavior.
This is a suitable example of an asynchronous Subscription Authorizer that calls an external server.
A callback like this has the potential to block the entire flow, as a call to an external service always bares the risk of taking long or timing out.
For this reason the PublishAuthorizesOutput has been made asynchronous with the help of the ManagedExtensionExecutorService.

public class MyAsyncSubscriptionAuthorizer implements SubscriptionAuthorizer {

    @Override
    public void authorizeSubscribe(@NotNull final SubscriptionAuthorizerInput input, @NotNull final SubscriptionAuthorizerOutput output) {

        //get the managed extension executor service
        final ManagedExtensionExecutorService extensionExecutorService = Services.extensionExecutorService();

        //make the output async with a timeout of 2 seconds
        final Async<SubscriptionAuthorizerOutput> async = output.async(Duration.ofSeconds(2));

        //submit a task to the extension executor
        extensionExecutorService.submit(new Runnable() {
            @Override
            public void run() {

                //call an external service to decide the outcome
                final boolean result = callExternalTaks();

                if (result) {
                    output.authorizeSuccessfully();
                } else {
                    output.failAuthorization();
                }

                //Always resume the async output, otherwise it will time out
                async.resume();
            }
        });

    }
}



Extension Isolation

The HiveMQ Extension SDK uses extension isolation. That means, each extension has its own classloader and resources and classes cannot be shared between extensions. This adds additional security for your extension and helps to avoid tricky to debug failure behavior that could be caused by using the same libraries in different extensions.
Some libraries like Jersey are trying and want to interfere with other class loaders, which may lead to side effects. HiveMQ implements workarounds for such libraries internally. If you are using such a library, which isn’t covered yet by HiveMQ, please contact support@hivemq.com so we can include workarounds for such libraries.



Initializing Objects

The HiveMQ Extension SDK provides static Services and Builder classes to enable the creation of desired Java objects inside extension classes.

Services Example Event Registry
final EventRegistry eventRegistry = Services.eventRegistry();


Builder Example TopicPermission
final TopicPermission permission = Builders.topicPermission()
        .topicFilter("allowed/topic")
        .qos(TopicPermission.Qos.ALL)
        .activity(TopicPermission.MqttActivity.ALL)
        .type(TopicPermission.PermissionType.ALLOW)
        .retain(TopicPermission.Retain.ALL)
        .build();