MQTT Client Features: Fluent API - HiveMQ

Written by Silvio Giebl

Category: HiveMQ MQTT Client HiveMQ MQTT Client Features

Published: June 26, 2019




Welcome to the HiveMQ MQTT Client Features blog post series.

Last time we looked at the Reconnect Handling functionality. Today´s blog post will be about a general topic: the fluent API style used throughout the library.

The pattern

The used pattern could be called context-sensitive fluent builder pattern and combines:

  • The builder pattern : Each parameter can be set separately by using a method with a descriptive name. This allows you to specify only the properties you need without confusing parameters that have the same type.
  • Fluent method chaining : The return type of methods can be used to proceed with calling other methods. This also enables IDEs to support you through code completion.
  • Context sensitivity : A builder knows the current state of your method calls. This allows builders to be used in a nested fashion, enhancing the fluent style even more. Additionally you can be forced to set mandatory parameters first so you won’t miss any.

But enough about the concepts – let’s look at actual examples.

Fluent API of MQTT operations

Setting parameters in the Connect message is possible through the builder pattern using fluent method chaining:

1
2
3
4
Mqtt5AsyncClient client = ...

Mqtt5Connect connectMessage = Mqtt5Connect.builder().cleanStart(false).keepAlive(10).build();
client.connect(connectMessage);

The above code makes sense when you reuse the connectMessage or build it at a different place.

If you only need it once you would write:

1
client.connect(Mqtt5Connect.builder().cleanStart(false).keepAlive(10).build());

This is really verbose and can be simplified to:

1
client.connectWith().cleanStart(false).keepAlive(10).send();

The last code example shows the context sensitivity of the fluent builder. You actually will not notice that there is a builder pattern, as the build method is replaced with the send method, which is more appropriate in this context.

The same pattern can be used for all MQTT operations on the client. They all offer fluent methods with the ...With prefix:

1
2
3
4
5
6
7
client.subscribeWith().topicFilter("test").qos(MqttQos.AT_LEAST_ONCE).send();

client.publishWith().topic("test").qos(MqttQos.AT_LEAST_ONCE).payload("payload".getBytes()).send();

client.unsubscribeWith().topicFilter("test").send();

client.disconnectWith().reasonCode(Mqtt5DisconnectReasonCode.DISCONNECT_WITH_WILL_MESSAGE).send();

The publishWith, subscribeWith and unsubscribeWith methods force their user to specify the mandatory topic (filter) as the first parameter, all other properties are optional.

Nesting builders multiple times

The context-sensitive builders also allow nesting them. The following code shows nested builders for simple authentication credentials and the Will publish message inside the connect builder. The Will publish builder also contains a further nested builder for user properties, so there is no limit in nesting builders multiple times.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
client.connectWith()
        .cleanStart(false)
        .keepAlive(10)
        .simpleAuth()
            .username("username")
            .password("password".getBytes())
            .applySimpleAuth()
        .willPublish()
            .topic("test")
            .qos(MqttQos.EXACTLY_ONCE)
            .payload("payload".getBytes())
            .userProperties()
                .add("name1", "value1")
                .add("name2", "value2")
                .applyUserProperties()
            .applyWillPublish()
        .send();

All nested builders follow the same naming scheme. If the fluent method that starts a nested builder is called foo, then it is completed by an applyFoo method. Only the MQTT operations follow a different naming schema (as shown above) because it is just more appropriate for the context.

Conclusion

The context-sensitive fluent builder pattern is used throughout the whole library. In addition to the demonstrated MQTT operations and messages it is also used for the client configuration as well (e.g. sslConfig, webSocketConfig, automaticReconnect).



If you have not already done so, check out the project on GitHub.

Have a great day, Silvio from the HiveMQ Team

About Silvio Giebl

Silvio Giebl is a software developer at HiveMQ and maintainer of the open source library “HiveMQ MQTT Client”. He is interested in high-performance applications on the JVM and reactive programming.

<  MQTT Client Features: Reconnect Handling - HiveMQ   |   The HiveMQ Control center at a glance   >