Develop EMQ X MQTT server plug-in using Java

Starting from v4.1, EMQ X MQTT server provides a special multi-language support plug-in emqx_extension_hook , and now supports the use of other programming languages ​​to handle hook events in EMQ X. Developers can use Python or Java to quickly develop their own plug-ins. Expand on the basis of official functions to meet your own business scenarios. E.g:

  • Verify the login permission of a client: when the client connects, the corresponding function is triggered, and the client information is obtained through the parameters to determine whether there is login permission by reading the database, comparing, etc.
  • Record client online status and online and offline history: trigger the corresponding function when the client status changes, obtain client information through parameters, and rewrite the online status of the client in the database
  • Verify the operation authority of a client's PUB/SUB: trigger the corresponding function when publish/subscribe, obtain the client information and current topic through the parameters, and determine whether the client has the corresponding operation authority
  • Process Sessions and Message events, realize subscription relationship and message processing/storage: trigger the corresponding function when the message is published and the state changes, obtain the current client information, message state and message content, and forward it to Kafka or database for storage .

Note: Message hooks are only supported in the enterprise version.

Python and Java drivers are based on Erlang/OTP-Port inter - process communication and have very high throughput performance. This article uses Java extension as an example to introduce the use of EMQ X cross-language extension.

img

Java extended usage example

Claim

  • The server where EMQ X is located needs to install JDK 1.8 or above

start using

  1. Create a Java project
  2. Download the io.emqx.extension.jar and erlport.jar files
  3. Adding SDK io.emqx.extension.jarand erlport.jarto project dependencies
  4. Copy examples/SampleHandler.javato your project
  5. SampleHandler.javaWrite business code according to the examples in the SDK to ensure successful compilation

deploy

After compiling all source code, you need to sdkand deployed to EMQ X code files in:

  1. Copy io.emqx.extension.jarto emqx/data/extensiondirectory
  2. The compiled .classfile, for example, SampleHandler.classcopied to emqx/data/extensiona directory
  3. Modify emqx/etc/plugins/emqx_extension_hook.confthe configuration file:
exhook.drivers = java
## Search path for scripts or library
exhook.drivers.java.path = data/extension/
exhook.drivers.java.init_module = SampleHandler

Start emqx_extension_hookplug-ins, if a configuration error or Java coding errors will not start properly. After startup, try to establish an MQTT connection and observe the business operation.

Example

The following is SampleHandler.java sample program which inherits from the SDK DefaultCommunicationHandlerclass. This sample code demonstrates how to mount all hooks in the EMQ X system:

import emqx.extension.java.handler.*;
import emqx.extension.java.handler.codec.*;
import emqx.extension.java.handler.ActionOptionConfig.Keys;

public class SampleHandler extends DefaultCommunicationHandler {
    
    
    
    @Override
    public ActionOptionConfig getActionOption() {
    
    
        ActionOptionConfig option = new ActionOptionConfig();
        option.set(Keys.MESSAGE_PUBLISH_TOPICS, "#");
        option.set(Keys.MESSAGE_DELIVERED_TOPICS, "#");
        option.set(Keys.MESSAGE_ACKED_TOPICS, "#");
        option.set(Keys.MESSAGE_DROPPED_TOPICS, "#");
        
        return option;
    }
    
    // Clients
    @Override
    public void onClientConnect(ConnInfo connInfo, Property[] props) {
    
    
        System.err.printf("[Java] onClientConnect: connInfo: %s, props: %s\n", connInfo, props);
    }

    @Override
    public void onClientConnack(ConnInfo connInfo, ReturnCode rc, Property[] props) {
    
    
        System.err.printf("[Java] onClientConnack: connInfo: %s, rc: %s, props: %s\n", connInfo, rc, props);
    }

    @Override
    public void onClientConnected(ClientInfo clientInfo) {
    
    
        System.err.printf("[Java] onClientConnected: clientinfo: %s\n", clientInfo);
    }

    @Override
    public void onClientDisconnected(ClientInfo clientInfo, Reason reason) {
    
    
        System.err.printf("[Java] onClientDisconnected: clientinfo: %s, reason: %s\n", clientInfo, reason);
    }

    // 判定认证结果,返回 true 或 false 
    @Override
    public boolean onClientAuthenticate(ClientInfo clientInfo, boolean authresult) {
    
    
        System.err.printf("[Java] onClientAuthenticate: clientinfo: %s, authresult: %s\n", clientInfo, authresult);

        return true;
    }

    // 判定 ACL 检查结果,返回 true 或 false 
    @Override
    public boolean onClientCheckAcl(ClientInfo clientInfo, PubSub pubsub, Topic topic, boolean result) {
    
    
        System.err.printf("[Java] onClientCheckAcl: clientinfo: %s, pubsub: %s, topic: %s, result: %s\n", clientInfo, pubsub, topic, result);

        return true;
    }

    @Override
    public void onClientSubscribe(ClientInfo clientInfo, Property[] props, TopicFilter[] topic) {
    
    
        System.err.printf("[Java] onClientSubscribe: clientinfo: %s, topic: %s, props: %s\n", clientInfo, topic, props);
    }

    @Override
    public void onClientUnsubscribe(ClientInfo clientInfo, Property[] props, TopicFilter[] topic) {
    
    
        System.err.printf("[Java] onClientUnsubscribe: clientinfo: %s, topic: %s, props: %s\n", clientInfo, topic, props);
    }

    // Sessions
    @Override
    public void onSessionCreated(ClientInfo clientInfo) {
    
    
        System.err.printf("[Java] onSessionCreated: clientinfo: %s\n", clientInfo);
    }

    @Override
    public void onSessionSubscribed(ClientInfo clientInfo, Topic topic, SubscribeOption opts) {
    
    
        System.err.printf("[Java] onSessionSubscribed: clientinfo: %s, topic: %s\n", clientInfo, topic);
    }

    @Override
    public void onSessionUnsubscribed(ClientInfo clientInfo, Topic topic) {
    
    
        System.err.printf("[Java] onSessionUnsubscribed: clientinfo: %s, topic: %s\n", clientInfo, topic);
    }

    @Override
    public void onSessionResumed(ClientInfo clientInfo) {
    
    
        System.err.printf("[Java] onSessionResumed: clientinfo: %s\n", clientInfo);
    }

    @Override
    public void onSessionDiscarded(ClientInfo clientInfo) {
    
    
        System.err.printf("[Java] onSessionDiscarded: clientinfo: %s\n", clientInfo);
    }
    
    @Override
    public void onSessionTakeovered(ClientInfo clientInfo) {
    
    
        System.err.printf("[Java] onSessionTakeovered: clientinfo: %s\n", clientInfo);
    }

    @Override
    public void onSessionTerminated(ClientInfo clientInfo, Reason reason) {
    
    
        System.err.printf("[Java] onSessionTerminated: clientinfo: %s, reason: %s\n", clientInfo, reason);
    }

    // Messages
    @Override
    public Message onMessagePublish(Message message) {
    
    
        System.err.printf("[Java] onMessagePublish: message: %s\n", message);
        
        return message;
    }

    @Override
    public void onMessageDropped(Message message, Reason reason) {
    
    
        System.err.printf("[Java] onMessageDropped: message: %s, reason: %s\n", message, reason);
    }

    @Override
    public void onMessageDelivered(ClientInfo clientInfo, Message message) {
    
    
        System.err.printf("[Java] onMessageDelivered: clientinfo: %s, message: %s\n", clientInfo, message);
    }

    @Override
    public void onMessageAcked(ClientInfo clientInfo, Message message) {
    
    
        System.err.printf("[Java] onMessageAcked: clientinfo: %s, message: %s\n", clientInfo, message);
    }
}

SampleHandler It mainly consists of two parts:

  1. Overloaded getActionOptionmethod. This method configures the hooks related to the message and specifies the list of topics that need to be effective.

    Configuration item Corresponding hook
    MESSAGE_PUBLISH_TOPICS message_publish
    MESSAGE_DELIVERED_TOPICS message_delivered
    MESSAGE_ACKED_TOPICS message_acked
    MESSAGE_DROPPED_TOPICS message_dropped
  2. Override on<hookName>methods that are actually processed hook event callback function, the function named after the name of each hook variant preceded onprefix variant embodiment after using Camel underlined spellings (CamelCase) to remove the hook name, e.g., a hook The function corresponding to client_connect is named onClientConnect. Events generated by the EMQ X client, such as connection, publication, subscription, etc., will eventually be distributed to these hook event callback functions, and then the callback function can perform related operations on each attribute and state. In the sample program, only the parameters are printed out. If you only care about part of the hook events, you only need to overload the callback functions of this part of the hook events, and you don't need to overload all the callback functions.

The execution timing of each callback function and the list of supported hooks are completely consistent with the built-in hooks of EMQ X, see: Hooks-EMQ X

When implementing your own extensions, the easiest way is to inherit DefaultCommunicationHandlerthe parent class, the class of binding with each hook callback function is encapsulated and further encapsulates the callback function parameter data structures involved, in order to facilitate the rapid start to use .

Advanced development

If the requirements of controllability Java extension higher, DefaultCommunicationHandlerthe class has been unable to meet the demand, it is possible by implementing CommunicationHandlerthe interface, from the lower-level logic control code, written in a more flexible extension.

package emqx.extension.java.handler;

public interface CommunicationHandler {
    
    public Object init();
    
    public void deinit();
}
  • init() Method: used to initialize, declare which hooks the extension needs to mount, and the configuration of the mount
  • deinit() Method: Used to log out.

Detailed data format description, see design documentation .

Copyright statement: This article is EMQ original, please indicate the source for reprinting.

Original link: https://www.emqx.io/cn/blog/develop-emqx-plugin-using-java

Guess you like

Origin blog.csdn.net/emqx_broker/article/details/107101496