the connect will complete exceptionally if the CONNECT meachnism fails. There are two options to react to this:
add a disconnect listener when creating the client
final Mqtt3AsyncClient client = Mqtt3Client.builder()
.serverAddress(nodeAddresses.getNodeAddress()
.getInetSocketAddress())
.identifier("test")
.addDisconnectedListener(context -> {
final Throwable cause = context.getCause();
if (cause instanceof Mqtt3ConnAckException) {
logger.info("disconnect listener: Connect failed because of Negative CONNACK with code {} ", ((Mqtt3ConnAckException) cause).getMqttMessage().getReturnCode());
} else {
logger.info("disconnect listener: MQTT connect failed because of {}", cause.getMessage());
}
})
.buildAsync();
or as you already did you can check connection success in the when complete method of the connect
client.connect().whenComplete((connAck, throwable) -> {
if (connAck != null) {
logger.info("whenComplete: MQTT connect success with code {}", connAck.getReturnCode());
} else {
if (throwable instanceof Mqtt3ConnAckException) {
logger.info("whenComplete: Connect failed because of Negative CONNACK with code {} ", ((Mqtt3ConnAckException) throwable).getMqttMessage().getReturnCode());
} else {
logger.info("whenComplete: MQTT connect failed because of {}", throwable.getMessage());
}
}
});
Some notes:
the whenComplete only works if a problem occurred in the given action (in the example during connection establishing)
the disconnect listener is more general, this listener will always be called when the connection to the broker is broken (even if client initiated the disconnect via a DISCONNECT packet)
in both examples you saw a check if the exception is a Mqtt3ConnackException, this exception is thrown by the client internally when a Connack with an error code was received
Hope this helped, cheers
Michael from the HiveMQ team
Thank you, this topic definitely needs some documentation. Or may be need a new onFailureListener to make things easier to implement?
From my tests with addDisconnectedListener approach throwable is only Mqtt3ConnAckException if MQTT authentication failed.
In other cases throwable is not Mqtt3ConnAckException. How can I clearly distinguish between intentional disconnects caused by disconnect() call and different connection failures? Only by parsing cause.getMessage() string? The cause.getMessage() string are like this:
Client sent DISCONNECT
java.io.IOException: Software caused connection abort
java.net.UnknownHostException: Unable to resolve host “farmer.cloudmqtt.com”: No address associated with hostname
This is correct, the Mqtt3ConnAckException is thrown when the client receives a negative ConnAck (a ConnAck with a failure return code indication connection is not allowed)
You can do the same as with the Mtt3ConnAckException and check if the throwable from the context is an Mqtt3DisconnectException:
else if (cause instanceof Mqtt3DisconnectException) {
logger.info("disconnect listener: Client closed connection with a DISCONNECT");
}