Skip to content

Conversation

@crazyrokr
Copy link
Collaborator

@crazyrokr crazyrokr commented Nov 19, 2025

Initial implementation of retain message feature

  1. If a client publishes a message with RETAIN flag, then the message is retained within the corresponding topic name
  2. If a client subscribes to a topic filter, then all retained messages within topic names matching the topic filter are automatically released to the client

@github-actions
Copy link

Overall Project 87.44% -0.49% 🍏
Files changed 83.18% 🍏

File Coverage
TopicFilter.java 100% 🍏
ConcurrentSubscriptionTree.java 100% 🍏
TopicFilterTreeBase.java 100% 🍏
TopicFilterNode.java 98.78% 🍏
InMemorySubscriptionService.java 96.59% 🍏
DefaultPublishDeliveringService.java 95.65% 🍏
SubscribeMqttInMessageHandler.java 93.6% -6.4% 🍏
MqttBrokerSpringConfig.java 89.57% 🍏
ConcurrentRetainedMessageTree.java 78.57% -21.43% 🍏
TopicMessageNode.java 72.85% -27.15% 🍏

@github-actions
Copy link

Overall Project 86.5% -1.49% 🍏
Files changed 61.77% 🍏

File Coverage
ConcurrentRetainedMessageTree.java 100% 🍏
TopicFilter.java 100% 🍏
ConcurrentSubscriptionTree.java 100% 🍏
TopicFilterTreeBase.java 100% 🍏
TopicFilterNode.java 98.78% 🍏
AbstractTopic.java 98.51% 🍏
InMemorySubscriptionService.java 96.59% 🍏
SubscribeMqttInMessageHandler.java 90.67% -9.33% 🍏
MqttBrokerSpringConfig.java 89.57% 🍏
DefaultPublishDeliveringService.java 86.43% 🍏
RetainedMessageNode.java 31.48% -68.52%

# Conflicts:
#	model/src/main/java/javasabr/mqtt/model/subscriber/tree/ConcurrentRetainedMessageTree.java
#	model/src/main/java/javasabr/mqtt/model/subscriber/tree/ConcurrentSubscriberTree.java
#	model/src/main/java/javasabr/mqtt/model/subscriber/tree/RetainedMessageNode.java
#	model/src/main/java/javasabr/mqtt/model/subscriber/tree/SubscriberNode.java
#	model/src/main/java/javasabr/mqtt/model/subscriber/tree/SubscriberTreeBase.java
#	model/src/main/java/javasabr/mqtt/model/subscribtion/tree/ConcurrentSubscriptionTree.java
#	model/src/main/java/javasabr/mqtt/model/subscribtion/tree/TopicFilterNode.java
#	model/src/main/java/javasabr/mqtt/model/subscribtion/tree/TopicFilterTreeBase.java
#	model/src/main/java/javasabr/mqtt/model/topic/tree/ConcurrentTopicTree.java
#	model/src/main/java/javasabr/mqtt/model/topic/tree/TopicNode.java
#	model/src/main/java/javasabr/mqtt/model/topic/tree/TopicTreeBase.java
#	model/src/test/groovy/javasabr/mqtt/model/topic/tree/SubscriberTreeTest.groovy
#	service/src/main/java/javasabr/mqtt/service/impl/InMemorySubscriptionService.java
@github-actions
Copy link

Overall Project 86.5% -1.49% 🍏
Files changed 53.91%

File Coverage
ConcurrentRetainedMessageTree.java 100% 🍏
TopicFilter.java 100% 🍏
ConcurrentSubscriberTree.java 100% 🍏
SubscriberNode.java 98.78% 🍏
AbstractTopic.java 98.51% 🍏
SubscribeMqttInMessageHandler.java 90.67% -9.33% 🍏
MqttBrokerSpringConfig.java 89.57% 🍏
DefaultPublishDeliveringService.java 86.43% 🍏
RetainedMessageNode.java 31.48% -68.52%

@github-actions
Copy link

Overall Project 85.77% -1.49% 🍏
Files changed 53.14%

File Coverage
ConcurrentRetainedMessageTree.java 100% 🍏
SubscriberNode.java 98.78% 🍏
AbstractTopic.java 98.51% 🍏
SubscribeMqttInMessageHandler.java 90.67% -9.33% 🍏
MqttBrokerSpringConfig.java 89.57% 🍏
DefaultPublishDeliveringService.java 86.43% 🍏
RetainedMessageNode.java 31.48% -68.52%

@github-actions
Copy link

Overall Project 85.77% -1.49% 🍏
Files changed 53.14%

File Coverage
ConcurrentRetainedMessageTree.java 100% 🍏
AbstractTopic.java 98.51% 🍏
SubscribeMqttInMessageHandler.java 90.67% -9.33% 🍏
MqttBrokerSpringConfig.java 89.57% 🍏
DefaultPublishDeliveringService.java 86.43% 🍏
RetainedMessageNode.java 31.48% -68.52%

@github-actions
Copy link

Overall Project 86.98% -0.3% 🍏
Files changed 90.98% 🍏

File Coverage
ConcurrentRetainedMessageTree.java 100% 🍏
AbstractTopic.java 98.51% 🍏
RetainedMessageNode.java 97.97% -2.03% 🍏
SubscribeMqttInMessageHandler.java 90.67% -9.33% 🍏
MqttBrokerSpringConfig.java 89.57% 🍏
DefaultPublishDeliveringService.java 86.43% 🍏

crazyrokr and others added 3 commits November 20, 2025 10:35
# Conflicts:
#	application/src/main/java/javasabr/mqtt/broker/application/config/MqttBrokerSpringConfig.java
#	core-service/src/main/java/javasabr/mqtt/service/impl/InMemorySubscriptionService.java
#	core-service/src/test/groovy/javasabr/mqtt/service/message/handler/impl/SubscribeMqttInMessageHandlerTest.groovy
@github-actions
Copy link

github-actions bot commented Dec 1, 2025

Overall Project 85.87% -0.59% 🍏
Files changed 85% 🍏

File Coverage
ConcurrentRetainedMessageTree.java 100% 🍏
SubscriptionService.java 100% 🍏
Qos0MqttPublishOutMessageHandler.java 100% 🍏
AbstractTopic.java 98.51% 🍏
RetainedMessageNode.java 97.97% -2.03% 🍏
PersistedMqttPublishOutMessageHandler.java 91.89% 🍏
MqttBrokerSpringConfig.java 89.52% 🍏
DefaultPublishDeliveringService.java 80.4% -6.03% 🍏
Qos2MqttPublishOutMessageHandler.java 78.79% 🍏
InMemorySubscriptionService.java 78.19% -21.81%
AbstractMqttPublishOutMessageHandler.java 74.29% -6.67% 🍏
Qos1MqttPublishOutMessageHandler.java 61.11% 🍏

@github-actions
Copy link

github-actions bot commented Dec 1, 2025

Test Coverage Report

Overall Project 86.77% -0.19% 🍏
Files changed 95.47% 🍏

File Coverage
Subscription.java 100% 🍏
ConcurrentRetainedMessageTree.java 100% 🍏
SubscriptionService.java 100% 🍏
SubscriberTreeBase.java 100% 🍏
SubscriberNode.java 100% 🍏
Qos0MqttPublishOutMessageHandler.java 100% 🍏
Publish.java 98.95% 🍏
RetainedMessageNode.java 98.9% -1.1% 🍏
DefaultPublishDeliveringService.java 96.48% 🍏
AbstractTrieNode.java 95.69% -4.31% 🍏
InMemorySubscriptionService.java 91.22% -8.78% 🍏
MqttBrokerSpringConfig.java 89.52% 🍏
AbstractMqttPublishOutMessageHandler.java 82.64% 🍏
Qos1MqttPublishOutMessageHandler.java 78.61% 🍏
Qos2MqttPublishOutMessageHandler.java 75.95% 🍏
TrackableMqttPublishOutMessageHandler.java 72.61% 🍏

@crazyrokr crazyrokr linked an issue Dec 5, 2025 that may be closed by this pull request
# Conflicts:
#	core-service/src/main/java/javasabr/mqtt/service/SubscriptionService.java
#	core-service/src/main/java/javasabr/mqtt/service/impl/InMemorySubscriptionService.java
#	core-service/src/main/java/javasabr/mqtt/service/publish/handler/impl/AbstractMqttPublishOutMessageHandler.java
#	core-service/src/main/java/javasabr/mqtt/service/publish/handler/impl/PersistedMqttPublishOutMessageHandler.java
#	core-service/src/main/java/javasabr/mqtt/service/publish/handler/impl/Qos0MqttPublishOutMessageHandler.java
#	core-service/src/main/java/javasabr/mqtt/service/publish/handler/impl/Qos1MqttPublishOutMessageHandler.java
#	core-service/src/main/java/javasabr/mqtt/service/publish/handler/impl/Qos2MqttPublishOutMessageHandler.java
@crazyrokr crazyrokr marked this pull request as ready for review December 7, 2025 14:18
@crazyrokr crazyrokr requested a review from JavaSaBr December 7, 2025 16:04
@crazyrokr crazyrokr added enhancement New feature or request core labels Dec 7, 2025
publishReceivingService,
messageOutFactoryService,
topicService);
return new PublishMqttInMessageHandler(publishReceivingService, messageOutFactoryService, topicService);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong formating

subscriptionService,
messageOutFactoryService,
topicService);
return new UnsubscribeMqttInMessageHandler(subscriptionService, messageOutFactoryService, topicService);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong formatting

env.getProperty("mqtt.external.connection.max.string.length", int.class, MqttProperties.MAXIMUM_STRING_LENGTH),
env.getProperty("mqtt.external.connection.max.binary.size", int.class, MqttProperties.MAXIMUM_BINARY_SIZE),
env.getProperty("mqtt.external.connection.max.topic.levels", int.class, MqttProperties.MAXIMUM_TOPIC_LEVELS),
env.getProperty("mqtt.external.connection.min.keep.alive", int.class, MqttProperties.SERVER_KEEP_ALIVE_DEFAULT),
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bad formatting


PublishHandlingResult startDelivering(Publish publish, SingleSubscriber subscriber);

Array<PublishHandlingResult> deliverRetainedMessages(SingleSubscriber subscriber);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PublishDeliveringService is responsible only for delivering a publish to a user. That is it.
I think you need to have a separated service like "RetainMessagesService" which will have a topic tree + with retain messages (instead of subscribers) and will use 'PublishDeliveringService' to deliver retain messages

import javasabr.rlib.collections.dictionary.LockableRefToRefDictionary;
import org.jspecify.annotations.Nullable;

public abstract class AbstractTrieNode<T> {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

looks like typo -> AbstractTreeNode

return;
}
if (level == lastLevel) {
if (level == lastLevel || TopicFilter.MULTI_LEVEL_WILDCARD.equals(segment)) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do we need to have it here?

} else if (level < lastLevel) {
subscriberNode.matchesTo(level + 1, topicName, lastLevel, result);
}
collectMatchingSubscribers(topicName.segment(level), level, topicName, lastLevel, container);
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so you returned the old way which I specially removed :D


if (existeQos.ordinal() < candidateQos.ordinal()) {
QoS existedQos = result
.get(found)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wrong formattimg

return ArrayFactory.mutableArray(RetainedMessageNode.class);
}

final AtomicReference<@Nullable Publish> retainedMessage = new AtomicReference<>();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can have only 1 message per topic? I think here should be a list

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

core enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Implement Retained Messages

3 participants