diff --git a/application/src/main/java/javasabr/mqtt/application/config/MqttBrokerConfig.java b/application/src/main/java/javasabr/mqtt/application/config/MqttBrokerConfig.java index d36e5b00..8b56d00a 100644 --- a/application/src/main/java/javasabr/mqtt/application/config/MqttBrokerConfig.java +++ b/application/src/main/java/javasabr/mqtt/application/config/MqttBrokerConfig.java @@ -1,10 +1,10 @@ package javasabr.mqtt.application.config; import javasabr.mqtt.service.handler.client.DefaultMqttClientReleaseHandler; -import javasabr.mqtt.network.handler.client.MqttClientReleaseHandler; +import javasabr.mqtt.network.handler.MqttClientReleaseHandler; import javasabr.mqtt.service.handler.in.ConnectInPacketHandler; import javasabr.mqtt.service.handler.in.DisconnetInPacketHandler; -import javasabr.mqtt.network.handler.packet.in.PacketInHandler; +import javasabr.mqtt.network.handler.PacketInHandler; import javasabr.mqtt.service.handler.in.PublishAckInPacketHandler; import javasabr.mqtt.service.handler.in.PublishCompleteInPacketHandler; import javasabr.mqtt.service.handler.in.PublishInPacketHandler; @@ -12,7 +12,7 @@ import javasabr.mqtt.service.handler.in.PublishReleaseInPacketHandler; import javasabr.mqtt.service.handler.in.SubscribeInPacketHandler; import javasabr.mqtt.service.handler.in.UnsubscribeInPacketHandler; -import javasabr.mqtt.network.handler.publish.PublishInHandler; +import javasabr.mqtt.network.handler.PublishInHandler; import javasabr.mqtt.service.handler.publish.in.Qos0PublishInHandler; import javasabr.mqtt.service.handler.publish.in.Qos1PublishInHandler; import javasabr.mqtt.service.handler.publish.in.Qos2PublishInHandler; diff --git a/application/src/main/java/javasabr/mqtt/application/config/MqttNetworkConfig.java b/application/src/main/java/javasabr/mqtt/application/config/MqttNetworkConfig.java index 3198d858..eee9eaf5 100644 --- a/application/src/main/java/javasabr/mqtt/application/config/MqttNetworkConfig.java +++ b/application/src/main/java/javasabr/mqtt/application/config/MqttNetworkConfig.java @@ -1,7 +1,7 @@ package javasabr.mqtt.application.config; -import javasabr.mqtt.network.handler.client.MqttClientReleaseHandler; -import javasabr.mqtt.network.handler.packet.in.PacketInHandler; +import javasabr.mqtt.network.handler.MqttClientReleaseHandler; +import javasabr.mqtt.network.handler.PacketInHandler; import javasabr.mqtt.model.MqttProperties; import javasabr.mqtt.model.QoS; import javasabr.mqtt.network.MqttConnection; @@ -12,7 +12,7 @@ import java.nio.channels.AsynchronousSocketChannel; import java.util.function.BiFunction; import java.util.function.Consumer; -import javasabr.mqtt.model.MqttConnectionConfig; +import javasabr.mqtt.model.MqttServerConnectionConfig; import javasabr.mqtt.network.packet.in.MqttReadablePacket; import javasabr.rlib.network.BufferAllocator; import javasabr.rlib.network.Network; @@ -23,7 +23,6 @@ import javasabr.rlib.network.server.ServerNetwork; import lombok.CustomLog; import lombok.RequiredArgsConstructor; -import lombok.extern.log4j.Log4j2; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.env.Environment; @@ -76,7 +75,7 @@ BufferAllocator externalBufferAllocator(ServerNetworkConfig externalNetworkConfi ServerNetwork externalNetwork( ServerNetworkConfig externalNetworkConfig, BufferAllocator externalBufferAllocator, - MqttConnectionConfig externalConnectionConfig, + MqttServerConnectionConfig externalConnectionConfig, PacketInHandler[] packetHandlers, MqttClientReleaseHandler mqttClientReleaseHandler) { return NetworkFactory.serverNetwork( @@ -92,7 +91,7 @@ ServerNetwork externalNetwork( ServerNetwork internalNetwork( ServerNetworkConfig internalNetworkConfig, BufferAllocator internalBufferAllocator, - MqttConnectionConfig internalConnectionConfig, + MqttServerConnectionConfig internalConnectionConfig, PacketInHandler[] packetHandlers, MqttClientReleaseHandler mqttClientReleaseHandler) { return NetworkFactory.serverNetwork( @@ -153,13 +152,21 @@ Consumer internalConnectionConsumer() { } @Bean - MqttConnectionConfig externalConnectionConfig() { - return new MqttConnectionConfig( + MqttServerConnectionConfig externalConnectionConfig() { + return new MqttServerConnectionConfig( QoS.of(env.getProperty("mqtt.connection.max.qos", int.class, 2)), env.getProperty( "mqtt.external.connection.max.packet.size", int.class, MqttProperties.MAXIMUM_PACKET_SIZE_DEFAULT), + 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.min.keep.alive", int.class, @@ -203,13 +210,21 @@ MqttConnectionConfig externalConnectionConfig() { } @Bean - MqttConnectionConfig internalConnectionConfig() { - return new MqttConnectionConfig( + MqttServerConnectionConfig internalConnectionConfig() { + return new MqttServerConnectionConfig( QoS.of(env.getProperty("mqtt.internal.connection.max.qos", int.class, 2)), env.getProperty( "mqtt.internal.connection.max.packet.size", int.class, MqttProperties.MAXIMUM_PACKET_SIZE_DEFAULT), + env.getProperty( + "mqtt.internal.connection.max.string.length", + int.class, + MqttProperties.MAXIMUM_STRING_LENGTH), + env.getProperty( + "mqtt.internal.connection.max.binary.size", + int.class, + MqttProperties.MAXIMUM_BINARY_SIZE), env.getProperty( "mqtt.internal.connection.min.keep.alive", int.class, @@ -254,7 +269,7 @@ MqttConnectionConfig internalConnectionConfig() { private ChannelFactory externalConnectionFactory( BufferAllocator bufferAllocator, - MqttConnectionConfig connectionConfig, + MqttServerConnectionConfig connectionConfig, PacketInHandler[] packetHandlers, MqttClientReleaseHandler releaseHandler) { return connectionFactory( @@ -267,7 +282,7 @@ private ChannelFactory externalConnectionFactory( private ChannelFactory internalConnectionFactory( BufferAllocator bufferAllocator, - MqttConnectionConfig connectionConfig, + MqttServerConnectionConfig connectionConfig, PacketInHandler[] packetHandlers, MqttClientReleaseHandler releaseHandler) { return connectionFactory( @@ -280,7 +295,7 @@ private ChannelFactory internalConnectionFactory( private ChannelFactory connectionFactory( BufferAllocator bufferAllocator, - MqttConnectionConfig connectionConfig, + MqttServerConnectionConfig connectionConfig, PacketInHandler[] packetHandlers, MqttClientReleaseHandler releaseHandler, BiFunction clientFactory) { diff --git a/application/src/test/groovy/javasabr/mqtt/application/extension/SpecificationExtensions.groovy b/application/src/test/groovy/javasabr/mqtt/application/extension/SpecificationExtensions.groovy index 8f1e2d06..9715531e 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/extension/SpecificationExtensions.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/extension/SpecificationExtensions.groovy @@ -56,12 +56,14 @@ class SpecificationExtensions extends Specification { static ByteBuffer putProperty(ByteBuffer self, PacketProperty property, Array values) { - switch (property.getDataType()) { - case PacketDataType.UTF_8_STRING_PAIR: + switch (property.dataType()) { + case PacketDataType.UTF_8_STRING_PAIR: { writer.writeStringPairProperties(self, property, values as Array) break - default: + } + default: { throw new IllegalStateException() + } } return self diff --git a/application/src/test/groovy/javasabr/mqtt/application/integration/IntegrationSpecification.groovy b/application/src/test/groovy/javasabr/mqtt/application/integration/IntegrationSpecification.groovy index 95cab6a7..f74f3fca 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/integration/IntegrationSpecification.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/integration/IntegrationSpecification.groovy @@ -6,7 +6,7 @@ import com.hivemq.client.mqtt.mqtt5.Mqtt5AsyncClient import javasabr.mqtt.network.MqttConnection import javasabr.mqtt.application.integration.config.MqttBrokerTestConfig import javasabr.mqtt.application.mock.MqttMockClient -import javasabr.mqtt.model.MqttConnectionConfig +import javasabr.mqtt.model.MqttServerConnectionConfig import javasabr.mqtt.model.MqttProperties import javasabr.mqtt.model.MqttVersion import org.springframework.beans.factory.annotation.Autowired @@ -36,7 +36,7 @@ class IntegrationSpecification extends Specification { InetSocketAddress internalNetworkAddress @Autowired - MqttConnectionConfig externalConnectionConfig + MqttServerConnectionConfig externalConnectionConfig def buildExternalMqtt311Client() { return buildMqtt311Client(generateClientId(), externalNetworkAddress) @@ -144,37 +144,37 @@ class IntegrationSpecification extends Specification { ) } - def mqtt5MockedConnection(MqttConnectionConfig deviceConnectionConfig) { + def mqtt5MockedConnection(MqttServerConnectionConfig deviceConnectionConfig) { return Stub(MqttConnection) { isSupported(MqttVersion.MQTT_5) >> true isSupported(MqttVersion.MQTT_3_1_1) >> true - config() >> deviceConnectionConfig + serverConnectionConfig() >> deviceConnectionConfig client() >> Stub(UnsafeMqttClient) { connectionConfig() >> deviceConnectionConfig sessionExpiryInterval() >> MqttProperties.SESSION_EXPIRY_INTERVAL_DISABLED - receiveMax() >> deviceConnectionConfig.receiveMaximum() - maximumPacketSize() >> deviceConnectionConfig.maximumPacketSize() + receiveMaxPublishes() >> deviceConnectionConfig.receiveMaxPublishes() + maxPacketSize() >> deviceConnectionConfig.maxPacketSize() clientId() >> IntegrationSpecification.clientId keepAlive() >> MqttProperties.SERVER_KEEP_ALIVE_DEFAULT - topicAliasMaximum() >> deviceConnectionConfig.topicAliasMaximum() + topicAliasMaxValue() >> deviceConnectionConfig.topicAliasMaxValue() } } } - def mqtt311MockedConnection(MqttConnectionConfig deviceConnectionConfig) { + def mqtt311MockedConnection(MqttServerConnectionConfig deviceConnectionConfig) { return Stub(MqttConnection) { isSupported(MqttVersion.MQTT_5) >> false isSupported(MqttVersion.MQTT_3_1_1) >> true - config() >> deviceConnectionConfig + serverConnectionConfig() >> deviceConnectionConfig client() >> Stub(UnsafeMqttClient) { connectionConfig() >> deviceConnectionConfig sessionExpiryInterval() >> MqttProperties.SESSION_EXPIRY_INTERVAL_DISABLED - receiveMax() >> deviceConnectionConfig.receiveMaximum() - maximumPacketSize() >> deviceConnectionConfig.maximumPacketSize() + receiveMaxPublishes() >> deviceConnectionConfig.receiveMaxPublishes() + maxPacketSize() >> deviceConnectionConfig.maxPacketSize() clientId() >> IntegrationSpecification.clientId keepAlive() >> MqttProperties.SERVER_KEEP_ALIVE_DEFAULT - topicAliasMaximum() >> deviceConnectionConfig.topicAliasMaximum() + topicAliasMaxValue() >> deviceConnectionConfig.topicAliasMaxValue() } } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/model/TopicSubscriberTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/model/TopicSubscriberTest.groovy index 0b6cf5f6..a6dcbbbf 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/model/TopicSubscriberTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/model/TopicSubscriberTest.groovy @@ -23,18 +23,17 @@ class TopicSubscriberTest extends NetworkUnitSpecification { TopicName topicNames, QoS[] subscriberQos, QoS[] matchedQos, - MqttClient[] mqttClients - ) { + MqttClient[] mqttClients) { given: - def subscribeTopicFilter = Mock(SubscribeTopicFilter) { - getQos() >>> subscriberQos - getTopicFilter() >>> topicFilters + SubscribeTopicFilter[] subscribeFilters = new SubscribeTopicFilter[mqttClients.length] + mqttClients.eachWithIndex { MqttClient entry, int i -> + subscribeFilters[i] = new SubscribeTopicFilter(topicFilters[i], subscriberQos[i]) } def topicSubscriber = new TopicSubscribers() when: - topicSubscriber.addSubscriber(mqttClients[0], subscribeTopicFilter) - topicSubscriber.addSubscriber(mqttClients[1], subscribeTopicFilter) - topicSubscriber.addSubscriber(mqttClients[2], subscribeTopicFilter) + topicSubscriber.addSubscriber(mqttClients[0], subscribeFilters[0]) + topicSubscriber.addSubscriber(mqttClients[1], subscribeFilters[1]) + topicSubscriber.addSubscriber(mqttClients[2], subscribeFilters[2]) then: def subscribers = topicSubscriber.matches(topicNames) subscribers.size() == matchedQos.size() @@ -67,10 +66,10 @@ class TopicSubscriberTest extends NetworkUnitSpecification { [AT_LEAST_ONCE, AT_MOST_ONCE, EXACTLY_ONCE] ] mqttClients << [ - [defaultMqttClient, defaultMqttClient, defaultMqttClient], - [defaultMqttClient, defaultMqttClient, defaultMqttClient], - [defaultMqttClient, defaultMqttClient, defaultMqttClient], - [defaultMqttClient(), defaultMqttClient(), defaultMqttClient()] + [defaultMqtt311Client, defaultMqtt311Client, defaultMqtt311Client], + [defaultMqtt311Client, defaultMqtt311Client, defaultMqtt311Client], + [defaultMqtt311Client, defaultMqtt311Client, defaultMqtt311Client], + [newMqtt311Client(), newMqtt311Client(), newMqtt311Client()] ] } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/NetworkUnitSpecification.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/NetworkUnitSpecification.groovy index 2bdd4b33..dd983668 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/NetworkUnitSpecification.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/NetworkUnitSpecification.groovy @@ -1,7 +1,8 @@ package javasabr.mqtt.application.network import javasabr.mqtt.application.UnitSpecification -import javasabr.mqtt.model.MqttConnectionConfig +import javasabr.mqtt.model.MqttClientConnectionConfig +import javasabr.mqtt.model.MqttServerConnectionConfig import javasabr.mqtt.model.MqttVersion import javasabr.mqtt.model.QoS import javasabr.mqtt.model.SubscribeRetainHandling @@ -16,11 +17,11 @@ import javasabr.rlib.collections.array.IntArray import spock.lang.Shared import java.nio.charset.StandardCharsets +import java.util.concurrent.atomic.AtomicInteger import static javasabr.mqtt.model.utils.TopicUtils.buildTopicFilter import static javasabr.mqtt.model.utils.TopicUtils.buildTopicName - class NetworkUnitSpecification extends UnitSpecification { public static final keepAliveEnabled = true @@ -34,7 +35,8 @@ class NetworkUnitSpecification extends UnitSpecification { public static final sessionPresent = true public static final cleanStart = false public static final willRetain = false - public static final clientId = "testClientId" + public static final mqtt311ClientId = "testMqtt311ClientId" + public static final mqtt5ClientId = "testMqtt5ClientId" public static final packetId = 1234 as short public static final userName = "testUser" public static final userPassword = "testPassword".getBytes(StandardCharsets.UTF_8) @@ -42,9 +44,11 @@ class NetworkUnitSpecification extends UnitSpecification { public static final sessionExpiryInterval = 300 public static final messageExpiryInterval = 60 public static final topicAlias = 252 - public static final receiveMaximum = 10 - public static final maximumPacketSize = 1024 - public static final topicAliasMaximum = 32 + public static final receiveMaxPublishes = 10 + public static final maxPacketSize = 1024 + public static final maxStringLength = 1024 + public static final maxBinarySize = 1024 + public static final topicAliasMaxValue = 32 public static final subscriptionId = 637 public static final subscriptionId2 = 623 public static final serverKeepAlive = 1200 @@ -63,8 +67,8 @@ class NetworkUnitSpecification extends UnitSpecification { QoS.AT_LEAST_ONCE, SubscribeRetainHandling.DO_NOT_SEND, true, - false, - ) + false) + public static final topicFilter2 = "topic/Filter2" public static final topicFilter2Obj311 = new SubscribeTopicFilter(buildTopicFilter(topicFilter2), QoS.EXACTLY_ONCE) public static final topicFilter2Obj5 = new SubscribeTopicFilter( @@ -72,164 +76,212 @@ class NetworkUnitSpecification extends UnitSpecification { QoS.EXACTLY_ONCE, SubscribeRetainHandling.DO_NOT_SEND, true, - false, - ) + false) + public static final serverReference = "serverReference" public static final contentType = "application/json" public static final subscribeAckReasonCodes = Array.typed( SubscribeAckReasonCode, SubscribeAckReasonCode.GRANTED_QOS_1, SubscribeAckReasonCode.GRANTED_QOS_0, - SubscribeAckReasonCode.IMPLEMENTATION_SPECIFIC_ERROR - ) + SubscribeAckReasonCode.IMPLEMENTATION_SPECIFIC_ERROR) + public static final unsubscribeAckReasonCodes = Array.typed( UnsubscribeAckReasonCode, UnsubscribeAckReasonCode.SUCCESS, UnsubscribeAckReasonCode.IMPLEMENTATION_SPECIFIC_ERROR, - UnsubscribeAckReasonCode.UNSPECIFIED_ERROR - ) + UnsubscribeAckReasonCode.UNSPECIFIED_ERROR) + public static final userProperties = Array.typed( StringPair, new StringPair("key1", "val1"), new StringPair("key2", "val2"), - new StringPair("key3", "val3"), - ) + new StringPair("key3", "val3")) + public static final subscriptionIds = IntArray.of(subscriptionId, subscriptionId2) public static final topicFilters = Array.of(topicFilter, topicFilter2) public static final topicFiltersObj311 = Array.of(topicFilter1Obj311, topicFilter2Obj311) public static final topicFiltersObj5 = Array.of(topicFilter1Obj5, topicFilter2Obj5) public static final publishPayload = "publishPayload".getBytes(StandardCharsets.UTF_8) public static final correlationData = "correlationData".getBytes(StandardCharsets.UTF_8) + public static final clientIdGenerator = new AtomicInteger(1) @Shared - MqttClient defaultMqttClient = defaultMqttClient() + MqttServerConnectionConfig defaultServerConnectionConfig = defaultServerConnectionConfig() @Shared - MqttConnectionConfig mqttConnectionConfig = defaultMqttConnectionConfig() + MqttClient defaultMqtt311Client = mqttClient(defaultMqtt311ClientConnectionConfig(), mqtt311ClientId) @Shared - MqttConnection mqtt5Connection = defaultMqttConnection(MqttVersion.MQTT_5) + MqttClient defaultMqtt5Client = mqttClient(defaultMqtt5ClientConnectionConfig(), mqtt5ClientId) @Shared - MqttConnection mqtt311Connection = defaultMqttConnection(MqttVersion.MQTT_3_1_1) + MqttConnection defaultMqtt5Connection = mqtt5Connection(); - MqttClient defaultMqttClient() { - return mqttClient( - mqttConnectionConfig, - sessionExpiryInterval, - receiveMaximum, - maximumPacketSize, - clientId, - serverKeepAlive, - topicAliasMaximum - ) - } + @Shared + MqttConnection defaultMqtt311Connection = mqtt311Connection(); - MqttConnectionConfig defaultMqttConnectionConfig() { - return mqttConnectionConfig( + MqttServerConnectionConfig defaultServerConnectionConfig() { + return serverConnectionConfig( maxQos, - maximumPacketSize, + maxPacketSize, + maxStringLength, + maxBinarySize, serverKeepAlive, - receiveMaximum, - topicAliasMaximum, + receiveMaxPublishes, + topicAliasMaxValue, sessionExpiryInterval, keepAliveEnabled, sessionsEnabled, retainAvailable, wildcardSubscriptionAvailable, subscriptionIdAvailable, - sharedSubscriptionAvailable - ) + sharedSubscriptionAvailable) } + MqttClientConnectionConfig defaultMqtt311ClientConnectionConfig() { + return clientConnectionConfig( + maxQos, + MqttVersion.MQTT_3_1_1, + sessionExpiryInterval, + receiveMaxPublishes, + maxPacketSize, + topicAliasMaxValue, + keepAlive, + false, + false, + sessionsEnabled, + retainAvailable, + wildcardSubscriptionAvailable, + subscriptionIdAvailable, + sharedSubscriptionAvailable) + } - MqttConnection defaultMqttConnection(MqttVersion mqttVersion) { - return mqttConnection( - mqttVersion, - mqttConnectionConfig, + MqttClientConnectionConfig defaultMqtt5ClientConnectionConfig() { + return clientConnectionConfig( + maxQos, + MqttVersion.MQTT_5, sessionExpiryInterval, - receiveMaximum, - maximumPacketSize, - clientId, - serverKeepAlive, - topicAliasMaximum - ) + receiveMaxPublishes, + maxPacketSize, + topicAliasMaxValue, + keepAlive, + false, + false, + sessionsEnabled, + retainAvailable, + wildcardSubscriptionAvailable, + subscriptionIdAvailable, + sharedSubscriptionAvailable) + } + + MqttConnection mqtt311Connection() { + return mqttConnection( + defaultServerConnectionConfig(), + defaultMqtt311ClientConnectionConfig(), + mqtt311ClientId) } + MqttConnection mqtt5Connection() { + return mqttConnection( + defaultServerConnectionConfig(), + defaultMqtt5ClientConnectionConfig(), + mqtt5ClientId) + } - static MqttConnectionConfig mqttConnectionConfig( + static MqttServerConnectionConfig serverConnectionConfig( QoS maxQos, - int maximumPacketSize, + int maxPacketSize, + int maxStringLength, + int maxBinarySize, int serverKeepAlive, - int receiveMaximum, - int topicAliasMaximum, + int receiveMaxPublishes, + int topicAliasMaxValue, long sessionExpiryInterval, boolean keepAliveEnabled, boolean sessionsEnabled, boolean retainAvailable, boolean wildcardSubscriptionAvailable, boolean subscriptionIdAvailable, - boolean sharedSubscriptionAvailable - - ) { - return new MqttConnectionConfig( + boolean sharedSubscriptionAvailable) { + return new MqttServerConnectionConfig( maxQos, - maximumPacketSize, + maxPacketSize, + maxStringLength, + maxBinarySize, serverKeepAlive, - receiveMaximum, - topicAliasMaximum, + receiveMaxPublishes, + topicAliasMaxValue, sessionExpiryInterval, keepAliveEnabled, sessionsEnabled, retainAvailable, wildcardSubscriptionAvailable, subscriptionIdAvailable, - sharedSubscriptionAvailable - ) + sharedSubscriptionAvailable) } - MqttConnection mqttConnection( + static MqttClientConnectionConfig clientConnectionConfig( + QoS maxQos, MqttVersion mqttVersion, - MqttConnectionConfig mqttConnectionConfig, long sessionExpiryInterval, - int receiveMaximum, - int maximumPacketSize, - String clientId, - int serverKeepAlive, - int topicAliasMaximum - ) { + int receiveMaxPublishes, + int maxPacketSize, + int topicAliasMaxValue, + int keepAlive, + boolean requestResponseInformation, + boolean requestProblemInformation, + boolean sessionsEnabled, + boolean retainAvailable, + boolean wildcardSubscriptionAvailable, + boolean subscriptionIdAvailable, + boolean sharedSubscriptionAvailable) { + return new MqttClientConnectionConfig( + maxQos, + mqttVersion, + sessionExpiryInterval, + receiveMaxPublishes, + maxPacketSize, + topicAliasMaxValue, + keepAlive, + requestResponseInformation, + requestProblemInformation, + sessionsEnabled, + retainAvailable, + wildcardSubscriptionAvailable, + subscriptionIdAvailable, + sharedSubscriptionAvailable) + } + + MqttConnection mqttConnection( + MqttServerConnectionConfig serverConfig, + MqttClientConnectionConfig clientConfig, + String clientId) { return Stub(MqttConnection) { - isSupported(_ as MqttVersion) >> { MqttVersion version -> mqttVersion >= version } - getConfig() >> mqttConnectionConfig - getClient() >> mqttClient( - mqttConnectionConfig, - sessionExpiryInterval, - receiveMaximum, - maximumPacketSize, - clientId, - serverKeepAlive, - topicAliasMaximum - ) + isSupported(_) >> { MqttVersion version -> + clientConfig.mqttVersion().include(version) + } + serverConnectionConfig() >> serverConfig + clientConnectionConfig() >> clientConfig + client() >> mqttClient(clientConfig, clientId) } } - MqttClient mqttClient( - MqttConnectionConfig mqttConnectionConfig, - long sessionExpiryInterval, - int receiveMaximum, - int maximumPacketSize, - String clientId, - int serverKeepAlive, - int topicAliasMaximum - ) { + MqttClient mqttClient(MqttClientConnectionConfig clientConfig, String id) { + return Stub(MqttClient.UnsafeMqttClient) { + connectionConfig() >> clientConfig + clientId() >> id + toString() >> id + } + } + + MqttClient newMqtt311Client() { + def config = defaultMqtt311ClientConnectionConfig() + def id = "generatedClient_${clientIdGenerator.incrementAndGet()}" return Stub(MqttClient.UnsafeMqttClient) { - connectionConfig() >> mqttConnectionConfig - sessionExpiryInterval() >> sessionExpiryInterval - receiveMax() >> receiveMaximum - maximumPacketSize() >> maximumPacketSize - clientId() >> clientId - keepAlive() >> serverKeepAlive - topicAliasMaximum() >> topicAliasMaximum + connectionConfig() >> config + clientId() >> id + toString() >> id } } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/AuthenticationInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/AuthenticationInPacketTest.groovy index 57c42367..4555618d 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/AuthenticationInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/AuthenticationInPacketTest.groovy @@ -9,78 +9,67 @@ import javasabr.rlib.common.util.BufferUtils class AuthenticationInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.AUTHENTICATION_METHOD, authMethod) it.putProperty(PacketProperty.AUTHENTICATION_DATA, authData) it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.put(AuthenticateReasonCode.SUCCESS.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - when: def packet = new AuthenticationInPacket(0b1111_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reasonCode == AuthenticateReasonCode.SUCCESS packet.authenticationMethod == authMethod packet.authenticationData == authData packet.reason == reasonString - packet.userProperties == userProperties + packet.userProperties() == userProperties when: - propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.AUTHENTICATION_METHOD, authMethod) it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) it.putProperty(PacketProperty.AUTHENTICATION_DATA, authData) } - dataBuffer = BufferUtils.prepareBuffer(512) { it.put(AuthenticateReasonCode.CONTINUE_AUTHENTICATION.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - packet = new AuthenticationInPacket(0b1111_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reasonCode == AuthenticateReasonCode.CONTINUE_AUTHENTICATION packet.authenticationMethod == authMethod packet.authenticationData == authData packet.reason == reasonString - packet.userProperties == userProperties + packet.userProperties() == userProperties when: - propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.AUTHENTICATION_METHOD, authMethod) it.putProperty(PacketProperty.AUTHENTICATION_DATA, authData) } - dataBuffer = BufferUtils.prepareBuffer(512) { it.put(AuthenticateReasonCode.CONTINUE_AUTHENTICATION.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - packet = new AuthenticationInPacket(0b1111_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reasonCode == AuthenticateReasonCode.CONTINUE_AUTHENTICATION packet.authenticationMethod == authMethod packet.authenticationData == authData packet.reason == "" - packet.userProperties == Array.empty() + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/ConnectAckInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/ConnectAckInPacketTest.groovy index d1bb8e41..adc7f63a 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/ConnectAckInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/ConnectAckInPacketTest.groovy @@ -11,17 +11,14 @@ import javasabr.rlib.common.util.BufferUtils class ConnectAckInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putBoolean(sessionPresent) it.put(ConnectAckReasonCode.NOT_AUTHORIZED.mqtt311) } - when: def packet = new ConnectAckInPacket(0b0010_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result packet.reasonCode == ConnectAckReasonCode.NOT_AUTHORIZED @@ -37,26 +34,24 @@ class ConnectAckInPacketTest extends BaseInPacketTest { packet.wildcardSubscriptionAvailable == MqttProperties.WILDCARD_SUBSCRIPTION_AVAILABLE_DEFAULT packet.subscriptionIdAvailable == MqttProperties.SUBSCRIPTION_IDENTIFIER_AVAILABLE_DEFAULT packet.responseInformation == "" - packet.maximumPacketSize == MqttProperties.MAXIMUM_PACKET_SIZE_UNDEFINED + packet.maxPacketSize == MqttProperties.MAXIMUM_PACKET_SIZE_UNDEFINED packet.serverKeepAlive == MqttProperties.SERVER_KEEP_ALIVE_UNDEFINED packet.sessionExpiryInterval == MqttProperties.SESSION_EXPIRY_INTERVAL_UNDEFINED - packet.topicAliasMaximum == MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED - packet.receiveMax == MqttProperties.RECEIVE_MAXIMUM_UNDEFINED + packet.topicAliasMaxValue == MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED + packet.receiveMaxPublishes == MqttProperties.RECEIVE_MAXIMUM_UNDEFINED } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.SERVER_REFERENCE, serverReference) - it.putProperty(PacketProperty.ASSIGNED_CLIENT_IDENTIFIER, clientId) + it.putProperty(PacketProperty.ASSIGNED_CLIENT_IDENTIFIER, mqtt311ClientId) it.putProperty(PacketProperty.AUTHENTICATION_DATA, authData) it.putProperty(PacketProperty.AUTHENTICATION_METHOD, authMethod) - it.putProperty(PacketProperty.MAXIMUM_PACKET_SIZE, maximumPacketSize) + it.putProperty(PacketProperty.MAXIMUM_PACKET_SIZE, maxPacketSize) it.putProperty(PacketProperty.MAXIMUM_QOS, QoS.AT_LEAST_ONCE.ordinal()) - it.putProperty(PacketProperty.RECEIVE_MAXIMUM, receiveMaximum) + it.putProperty(PacketProperty.RECEIVE_MAXIMUM_PUBLISH, receiveMaxPublishes) it.putProperty(PacketProperty.RETAIN_AVAILABLE, retainAvailable) it.putProperty(PacketProperty.RESPONSE_INFORMATION, responseInformation) it.putProperty(PacketProperty.SERVER_KEEP_ALIVE, serverKeepAlive) @@ -64,31 +59,29 @@ class ConnectAckInPacketTest extends BaseInPacketTest { it.putProperty(PacketProperty.SHARED_SUBSCRIPTION_AVAILABLE, sharedSubscriptionAvailable) it.putProperty(PacketProperty.WILDCARD_SUBSCRIPTION_AVAILABLE, wildcardSubscriptionAvailable) it.putProperty(PacketProperty.SUBSCRIPTION_IDENTIFIER_AVAILABLE, subscriptionIdAvailable) - it.putProperty(PacketProperty.TOPIC_ALIAS_MAXIMUM, topicAliasMaximum) + it.putProperty(PacketProperty.TOPIC_ALIAS_MAXIMUM, topicAliasMaxValue) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putBoolean(sessionPresent) it.put(ConnectAckReasonCode.PAYLOAD_FORMAT_INVALID.mqtt5) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - when: def packet = new ConnectAckInPacket(0b0010_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reasonCode == ConnectAckReasonCode.PAYLOAD_FORMAT_INVALID packet.sessionPresent == sessionPresent packet.serverReference == serverReference packet.reason == reasonString - packet.assignedClientId == clientId + packet.assignedClientId == mqtt311ClientId packet.authenticationData == authData packet.authenticationMethod == authMethod - packet.maximumPacketSize == maximumPacketSize + packet.maxPacketSize == maxPacketSize packet.maximumQos == QoS.AT_LEAST_ONCE - packet.receiveMax == receiveMaximum + packet.receiveMaxPublishes == receiveMaxPublishes packet.retainAvailable == retainAvailable packet.responseInformation == responseInformation packet.serverKeepAlive == serverKeepAlive @@ -96,31 +89,27 @@ class ConnectAckInPacketTest extends BaseInPacketTest { packet.sharedSubscriptionAvailable == sharedSubscriptionAvailable packet.wildcardSubscriptionAvailable == wildcardSubscriptionAvailable packet.subscriptionIdAvailable == subscriptionIdAvailable - packet.topicAliasMaximum == topicAliasMaximum + packet.topicAliasMaxValue == topicAliasMaxValue when: - propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.SHARED_SUBSCRIPTION_AVAILABLE, sharedSubscriptionAvailable) it.putProperty(PacketProperty.WILDCARD_SUBSCRIPTION_AVAILABLE, wildcardSubscriptionAvailable) it.putProperty(PacketProperty.SUBSCRIPTION_IDENTIFIER_AVAILABLE, subscriptionIdAvailable) } - dataBuffer = BufferUtils.prepareBuffer(512) { it.putBoolean(sessionPresent) it.put(ConnectAckReasonCode.PACKET_TOO_LARGE.mqtt5) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - packet = new ConnectAckInPacket(0b0010_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reasonCode == ConnectAckReasonCode.PACKET_TOO_LARGE packet.sharedSubscriptionAvailable == sharedSubscriptionAvailable packet.wildcardSubscriptionAvailable == wildcardSubscriptionAvailable packet.subscriptionIdAvailable == subscriptionIdAvailable - } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/ConnectInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/ConnectInPacketTest.groovy index 00303f0e..b627473c 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/ConnectInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/ConnectInPacketTest.groovy @@ -10,49 +10,43 @@ import javasabr.rlib.common.util.BufferUtils class ConnectInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putString("MQTT") it.put(4 as byte) it.put(0b11000010 as byte) it.putShort(keepAlive as short) - it.putString(clientId) + it.putString(mqtt311ClientId) it.putString(userName) it.putBytes(userPassword) } - when: def packet = new ConnectInPacket(0b0001_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - packet.clientId == clientId - packet.mqttVersion == MqttVersion.MQTT_3_1_1 - packet.password == userPassword - packet.username == userName - packet.willTopic == "" - packet.willQos == 0 - packet.willPayload == ArrayUtils.EMPTY_BYTE_ARRAY + packet.clientId() == mqtt311ClientId + packet.mqttVersion() == MqttVersion.MQTT_3_1_1 + packet.password() == userPassword + packet.username() == userName + packet.willTopic() == "" + packet.willQos() == 0 + packet.willPayload() == ArrayUtils.EMPTY_BYTE_ARRAY } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.SESSION_EXPIRY_INTERVAL, sessionExpiryInterval) - it.putProperty(PacketProperty.RECEIVE_MAXIMUM, receiveMaximum) - it.putProperty(PacketProperty.MAXIMUM_PACKET_SIZE, maximumPacketSize) - it.putProperty(PacketProperty.TOPIC_ALIAS_MAXIMUM, topicAliasMaximum) + it.putProperty(PacketProperty.RECEIVE_MAXIMUM_PUBLISH, receiveMaxPublishes) + it.putProperty(PacketProperty.MAXIMUM_PACKET_SIZE, maxPacketSize) + it.putProperty(PacketProperty.TOPIC_ALIAS_MAXIMUM, topicAliasMaxValue) it.putProperty(PacketProperty.REQUEST_RESPONSE_INFORMATION, requestResponseInformation ? 1 : 0) it.putProperty(PacketProperty.REQUEST_PROBLEM_INFORMATION, requestProblemInformation ? 1 : 0) it.putProperty(PacketProperty.AUTHENTICATION_METHOD, authMethod) it.putProperty(PacketProperty.AUTHENTICATION_DATA, authData) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putString("MQTT") it.put(5 as byte) @@ -60,37 +54,34 @@ class ConnectInPacketTest extends BaseInPacketTest { it.putShort(keepAlive as short) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) - it.putString(clientId) + it.putString(mqtt311ClientId) it.putString(userName) it.putBytes(userPassword) } - when: def packet = new ConnectInPacket(0b0001_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.keepAlive == keepAlive - packet.authenticationMethod == authMethod - packet.authenticationData == authData - packet.clientId == clientId - packet.mqttVersion == MqttVersion.MQTT_5 - packet.maximumPacketSize == maximumPacketSize - packet.password == userPassword - packet.username == userName - packet.topicAliasMaximum == topicAliasMaximum - packet.sessionExpiryInterval == sessionExpiryInterval - packet.receiveMax == receiveMaximum - packet.willTopic == "" - packet.willQos == 0 - packet.willPayload == ArrayUtils.EMPTY_BYTE_ARRAY - packet.userProperties == userProperties + packet.keepAlive() == keepAlive + packet.authenticationMethod() == authMethod + packet.authenticationData() == authData + packet.clientId() == mqtt311ClientId + packet.mqttVersion() == MqttVersion.MQTT_5 + packet.maxPacketSize() == maxPacketSize + packet.password() == userPassword + packet.username() == userName + packet.topicAliasMaxValue() == topicAliasMaxValue + packet.sessionExpiryInterval() == sessionExpiryInterval + packet.receiveMaxPublishes() == receiveMaxPublishes + packet.willTopic() == "" + packet.willQos() == 0 + packet.willPayload() == ArrayUtils.EMPTY_BYTE_ARRAY + packet.userProperties() == userProperties } def "should not read packet correctly with invalid UTF8 strings"(byte[] stringBytes) { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putString("MQTT") it.put(5 as byte) @@ -101,13 +92,12 @@ class ConnectInPacketTest extends BaseInPacketTest { it.putString(userName) it.putBytes(userPassword) } - when: def packet = new ConnectInPacket(0b0001_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: !result - packet.exception instanceof MalformedPacketMqttException + packet.exception() instanceof MalformedPacketMqttException where: stringBytes << [ // https://www.cl.cam.ac.uk/~mgk25/ucs/examples/UTF-8-test.txt diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/DisconnectInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/DisconnectInPacketTest.groovy index a5091bf6..47643a0f 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/DisconnectInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/DisconnectInPacketTest.groovy @@ -9,53 +9,46 @@ import javasabr.rlib.common.util.BufferUtils class DisconnectInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.SESSION_EXPIRY_INTERVAL, sessionExpiryInterval) it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.SERVER_REFERENCE, serverReference) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.put(DisconnectReasonCode.QUOTA_EXCEEDED.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - when: def packet = new DisconnectInPacket(0b1110_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reason == reasonString packet.serverReference == serverReference packet.reasonCode == DisconnectReasonCode.QUOTA_EXCEEDED packet.sessionExpiryInterval == sessionExpiryInterval - packet.userProperties == userProperties + packet.userProperties() == userProperties when: - propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.SESSION_EXPIRY_INTERVAL, sessionExpiryInterval) it.putProperty(PacketProperty.SERVER_REFERENCE, serverReference) } - dataBuffer = BufferUtils.prepareBuffer(512) { it.put(DisconnectReasonCode.PACKET_TOO_LARGE.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - packet = new DisconnectInPacket(0b1110_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reason == "" packet.serverReference == serverReference packet.reasonCode == DisconnectReasonCode.PACKET_TOO_LARGE packet.sessionExpiryInterval == sessionExpiryInterval - packet.userProperties == Array.empty() + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishAckInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishAckInPacketTest.groovy index f2bcbadd..d13c520d 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishAckInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishAckInPacketTest.groovy @@ -9,64 +9,55 @@ import javasabr.rlib.common.util.BufferUtils class PublishAckInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) } - when: def packet = new PublishAckInPacket(0b0100_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCode == PublishAckReasonCode.SUCCESS - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCode() == PublishAckReasonCode.SUCCESS + packet.userProperties() == Array.empty() } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(PublishAckReasonCode.PAYLOAD_FORMAT_INVALID.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - when: def packet = new PublishAckInPacket(0b0100_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == reasonString - packet.packetId == packetId - packet.reasonCode == PublishAckReasonCode.PAYLOAD_FORMAT_INVALID - packet.userProperties == userProperties + packet.reason() == reasonString + packet.packetId() == packetId + packet.reasonCode() == PublishAckReasonCode.PAYLOAD_FORMAT_INVALID + packet.userProperties() == userProperties when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(PublishAckReasonCode.UNSPECIFIED_ERROR.value) it.putMbi(0) } - packet = new PublishAckInPacket(0b0100_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCode == PublishAckReasonCode.UNSPECIFIED_ERROR - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCode() == PublishAckReasonCode.UNSPECIFIED_ERROR + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishCompleteInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishCompleteInPacketTest.groovy index 10a6e9cb..974a7302 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishCompleteInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishCompleteInPacketTest.groovy @@ -9,64 +9,55 @@ import javasabr.rlib.common.util.BufferUtils class PublishCompleteInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) } - when: def packet = new PublishCompleteInPacket(0b0111_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCode == PublishCompletedReasonCode.SUCCESS - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCode() == PublishCompletedReasonCode.SUCCESS + packet.userProperties() == Array.empty() } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - when: def packet = new PublishCompleteInPacket(0b0111_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == reasonString - packet.packetId == packetId - packet.reasonCode == PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND - packet.userProperties == userProperties + packet.reason() == reasonString + packet.packetId() == packetId + packet.reasonCode() == PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND + packet.userProperties() == userProperties when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND.value) it.putMbi(0) } - packet = new PublishCompleteInPacket(0b0111_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCode == PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCode() == PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishInPacketTest.groovy index 16863496..dad19cd1 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishInPacketTest.groovy @@ -13,18 +13,15 @@ import javasabr.rlib.common.util.BufferUtils class PublishInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putString(publishTopic.toString()) it.putShort(packetId) it.put(publishPayload) } - when: def packet = new PublishInPacket(0b0110_0011 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result packet.qos == QoS.AT_LEAST_ONCE @@ -36,16 +33,14 @@ class PublishInPacketTest extends BaseInPacketTest { packet.correlationData == ArrayUtils.EMPTY_BYTE_ARRAY packet.payload == publishPayload packet.packetId == packetId - packet.userProperties == Array.empty() + packet.userProperties() == Array.empty() packet.messageExpiryInterval == MqttProperties.MESSAGE_EXPIRY_INTERVAL_UNDEFINED packet.topicAlias == MqttProperties.TOPIC_ALIAS_DEFAULT packet.payloadFormatIndicator == MqttProperties.PAYLOAD_FORMAT_INDICATOR_DEFAULT } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.PAYLOAD_FORMAT_INDICATOR, 1) it.putProperty(PacketProperty.MESSAGE_EXPIRY_INTERVAL, messageExpiryInterval) @@ -56,7 +51,6 @@ class PublishInPacketTest extends BaseInPacketTest { it.putProperty(PacketProperty.SUBSCRIPTION_IDENTIFIER, subscriptionIds) it.putProperty(PacketProperty.CONTENT_TYPE, contentType) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putString(publishTopic.toString()) it.putShort(packetId) @@ -64,10 +58,9 @@ class PublishInPacketTest extends BaseInPacketTest { it.put(propertiesBuffer) it.put(publishPayload) } - when: def packet = new PublishInPacket(0b0110_0011 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.qos == QoS.AT_LEAST_ONCE @@ -79,21 +72,19 @@ class PublishInPacketTest extends BaseInPacketTest { packet.correlationData == correlationData packet.payload == publishPayload packet.packetId == packetId - packet.userProperties == userProperties + packet.userProperties() == userProperties packet.messageExpiryInterval == messageExpiryInterval packet.topicAlias == topicAlias packet.payloadFormatIndicator when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putString(publishTopic.toString()) it.putShort(packetId) it.putMbi(0) it.put(publishPayload) } - packet = new PublishInPacket(0b0110_0011 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.qos == QoS.AT_LEAST_ONCE @@ -105,7 +96,7 @@ class PublishInPacketTest extends BaseInPacketTest { packet.correlationData == ArrayUtils.EMPTY_BYTE_ARRAY packet.payload == publishPayload packet.packetId == packetId - packet.userProperties == Array.empty(StringPair) + packet.userProperties() == Array.empty(StringPair) packet.messageExpiryInterval == MqttProperties.MESSAGE_EXPIRY_INTERVAL_UNDEFINED packet.topicAlias == MqttProperties.TOPIC_ALIAS_DEFAULT packet.payloadFormatIndicator == MqttProperties.PAYLOAD_FORMAT_INDICATOR_DEFAULT diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishReceivedInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishReceivedInPacketTest.groovy index ee780750..5b478920 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishReceivedInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishReceivedInPacketTest.groovy @@ -9,64 +9,55 @@ import javasabr.rlib.common.util.BufferUtils class PublishReceivedInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) } - when: def packet = new PublishReceivedInPacket(0b0101_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCode == PublishReceivedReasonCode.SUCCESS - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCode() == PublishReceivedReasonCode.SUCCESS + packet.userProperties() == Array.empty() } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(PublishReceivedReasonCode.QUOTA_EXCEEDED.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - when: def packet = new PublishReceivedInPacket(0b0101_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == reasonString - packet.packetId == packetId - packet.reasonCode == PublishReceivedReasonCode.QUOTA_EXCEEDED - packet.userProperties == userProperties + packet.reason() == reasonString + packet.packetId() == packetId + packet.reasonCode() == PublishReceivedReasonCode.QUOTA_EXCEEDED + packet.userProperties() == userProperties when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(PublishReceivedReasonCode.IMPLEMENTATION_SPECIFIC_ERROR.value) it.putMbi(0) } - packet = new PublishReceivedInPacket(0b0101_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCode == PublishReceivedReasonCode.IMPLEMENTATION_SPECIFIC_ERROR - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCode() == PublishReceivedReasonCode.IMPLEMENTATION_SPECIFIC_ERROR + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishReleaseInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishReleaseInPacketTest.groovy index 18a12edd..f47529eb 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishReleaseInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/PublishReleaseInPacketTest.groovy @@ -9,64 +9,55 @@ import javasabr.rlib.common.util.BufferUtils class PublishReleaseInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) } - when: def packet = new PublishReleaseInPacket(0b0110_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCode == PublishReleaseReasonCode.SUCCESS - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCode() == PublishReleaseReasonCode.SUCCESS + packet.userProperties() == Array.empty() } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(PublishReleaseReasonCode.PACKET_IDENTIFIER_NOT_FOUND.value) it.putMbi(propertiesBuffer.limit()) it.put(propertiesBuffer) } - when: def packet = new PublishReleaseInPacket(0b0110_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == reasonString - packet.packetId == packetId - packet.reasonCode == PublishReleaseReasonCode.PACKET_IDENTIFIER_NOT_FOUND - packet.userProperties == userProperties + packet.reason() == reasonString + packet.packetId() == packetId + packet.reasonCode() == PublishReleaseReasonCode.PACKET_IDENTIFIER_NOT_FOUND + packet.userProperties() == userProperties when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(PublishReleaseReasonCode.SUCCESS.value) it.putMbi(0) } - packet = new PublishReleaseInPacket(0b0110_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCode == PublishReleaseReasonCode.SUCCESS - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCode() == PublishReleaseReasonCode.SUCCESS + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/SubscribeAckInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/SubscribeAckInPacketTest.groovy index 1edc71ee..d0b8c2d3 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/SubscribeAckInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/SubscribeAckInPacketTest.groovy @@ -9,9 +9,7 @@ import javasabr.rlib.common.util.BufferUtils class SubscribeAckInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.put(SubscribeAckReasonCode.GRANTED_QOS_0.value) @@ -19,10 +17,9 @@ class SubscribeAckInPacketTest extends BaseInPacketTest { it.put(SubscribeAckReasonCode.GRANTED_QOS_1.value) it.put(SubscribeAckReasonCode.UNSPECIFIED_ERROR.value) } - when: def packet = new SubscribeAckInPacket(0b1001_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result packet.reason == "" @@ -35,14 +32,11 @@ class SubscribeAckInPacketTest extends BaseInPacketTest { } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putMbi(propertiesBuffer.limit()) @@ -52,10 +46,9 @@ class SubscribeAckInPacketTest extends BaseInPacketTest { it.put(SubscribeAckReasonCode.GRANTED_QOS_1.value) it.put(SubscribeAckReasonCode.UNSPECIFIED_ERROR.value) } - when: def packet = new SubscribeAckInPacket(0b1001_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reason == reasonString @@ -65,9 +58,8 @@ class SubscribeAckInPacketTest extends BaseInPacketTest { packet.reasonCodes.get(1) == SubscribeAckReasonCode.IMPLEMENTATION_SPECIFIC_ERROR packet.reasonCodes.get(2) == SubscribeAckReasonCode.GRANTED_QOS_1 packet.reasonCodes.get(3) == SubscribeAckReasonCode.UNSPECIFIED_ERROR - packet.userProperties == userProperties + packet.userProperties() == userProperties when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putMbi(0) @@ -76,9 +68,8 @@ class SubscribeAckInPacketTest extends BaseInPacketTest { it.put(SubscribeAckReasonCode.GRANTED_QOS_1.value) it.put(SubscribeAckReasonCode.UNSPECIFIED_ERROR.value) } - packet = new SubscribeAckInPacket(0b1001_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.reason == "" @@ -88,6 +79,6 @@ class SubscribeAckInPacketTest extends BaseInPacketTest { packet.reasonCodes.get(1) == SubscribeAckReasonCode.GRANTED_QOS_2 packet.reasonCodes.get(2) == SubscribeAckReasonCode.GRANTED_QOS_1 packet.reasonCodes.get(3) == SubscribeAckReasonCode.UNSPECIFIED_ERROR - packet.userProperties == Array.empty() + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/SubscribeInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/SubscribeInPacketTest.groovy index 783eed4b..6f9b388b 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/SubscribeInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/SubscribeInPacketTest.groovy @@ -11,9 +11,7 @@ import javasabr.rlib.common.util.BufferUtils class SubscribeInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putString(topicFilter) @@ -21,10 +19,9 @@ class SubscribeInPacketTest extends BaseInPacketTest { it.putString(topicFilter2) it.put(0b0000_0010 as byte) } - when: def packet = new SubscribeInPacket(0b1000_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result packet.topicFilters.size() == 2 @@ -39,19 +36,16 @@ class SubscribeInPacketTest extends BaseInPacketTest { packet.topicFilters.get(1).isRetainAsPublished() packet.topicFilters.get(1).getRetainHandling() == SubscribeRetainHandling.SEND packet.packetId == packetId - packet.userProperties == Array.empty() + packet.userProperties() == Array.empty() packet.subscriptionId == MqttProperties.SUBSCRIPTION_ID_UNDEFINED } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.SUBSCRIPTION_IDENTIFIER, subscriptionId) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putMbi(propertiesBuffer.limit()) @@ -61,10 +55,9 @@ class SubscribeInPacketTest extends BaseInPacketTest { it.putString(topicFilter2) it.put(0b0001_0110 as byte) } - when: def packet = new SubscribeInPacket(0b0110_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.topicFilters.size() == 2 @@ -79,10 +72,9 @@ class SubscribeInPacketTest extends BaseInPacketTest { !packet.topicFilters.get(1).isRetainAsPublished() packet.topicFilters.get(1).getRetainHandling() == SubscribeRetainHandling.SEND_IF_SUBSCRIPTION_DOES_NOT_EXIST packet.packetId == packetId - packet.userProperties == userProperties + packet.userProperties() == userProperties packet.subscriptionId == subscriptionId when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putMbi(0) @@ -91,9 +83,8 @@ class SubscribeInPacketTest extends BaseInPacketTest { it.putString(topicFilter2) it.put(0b0000_0010 as byte) } - packet = new SubscribeInPacket(0b0110_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.topicFilters.size() == 2 @@ -108,7 +99,7 @@ class SubscribeInPacketTest extends BaseInPacketTest { !packet.topicFilters.get(1).isRetainAsPublished() packet.topicFilters.get(1).getRetainHandling() == SubscribeRetainHandling.SEND packet.packetId == packetId - packet.userProperties == Array.empty() + packet.userProperties() == Array.empty() packet.subscriptionId == MqttProperties.SUBSCRIPTION_ID_UNDEFINED } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/UnsubscribeAckInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/UnsubscribeAckInPacketTest.groovy index 99e19ed5..971f70d4 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/UnsubscribeAckInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/UnsubscribeAckInPacketTest.groovy @@ -9,32 +9,26 @@ import javasabr.rlib.common.util.BufferUtils class UnsubscribeAckInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) } - when: def packet = new UnsubscribeAckInPacket(0b1011_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCodes == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCodes() == Array.empty() } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.REASON_STRING, reasonString) it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putMbi(propertiesBuffer.limit()) @@ -44,38 +38,35 @@ class UnsubscribeAckInPacketTest extends BaseInPacketTest { it.put(UnsubscribeAckReasonCode.NOT_AUTHORIZED.value) it.put(UnsubscribeAckReasonCode.UNSPECIFIED_ERROR.value) } - when: def packet = new UnsubscribeAckInPacket(0b1011_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == reasonString - packet.packetId == packetId - packet.reasonCodes.size() == 4 - packet.reasonCodes.get(0) == UnsubscribeAckReasonCode.SUCCESS - packet.reasonCodes.get(1) == UnsubscribeAckReasonCode.SUCCESS - packet.reasonCodes.get(2) == UnsubscribeAckReasonCode.NOT_AUTHORIZED - packet.reasonCodes.get(3) == UnsubscribeAckReasonCode.UNSPECIFIED_ERROR - packet.userProperties == userProperties + packet.reason() == reasonString + packet.packetId() == packetId + packet.reasonCodes().size() == 4 + packet.reasonCodes().get(0) == UnsubscribeAckReasonCode.SUCCESS + packet.reasonCodes().get(1) == UnsubscribeAckReasonCode.SUCCESS + packet.reasonCodes().get(2) == UnsubscribeAckReasonCode.NOT_AUTHORIZED + packet.reasonCodes().get(3) == UnsubscribeAckReasonCode.UNSPECIFIED_ERROR + packet.userProperties() == userProperties when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putMbi(0) it.put(UnsubscribeAckReasonCode.UNSPECIFIED_ERROR.value) it.put(UnsubscribeAckReasonCode.IMPLEMENTATION_SPECIFIC_ERROR.value) } - packet = new UnsubscribeAckInPacket(0b1011_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - packet.reason == "" - packet.packetId == packetId - packet.reasonCodes.size() == 2 - packet.reasonCodes.get(0) == UnsubscribeAckReasonCode.UNSPECIFIED_ERROR - packet.reasonCodes.get(1) == UnsubscribeAckReasonCode.IMPLEMENTATION_SPECIFIC_ERROR - packet.userProperties == Array.empty() + packet.reason() == "" + packet.packetId() == packetId + packet.reasonCodes().size() == 2 + packet.reasonCodes().get(0) == UnsubscribeAckReasonCode.UNSPECIFIED_ERROR + packet.reasonCodes().get(1) == UnsubscribeAckReasonCode.IMPLEMENTATION_SPECIFIC_ERROR + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/in/UnsubscribeInPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/in/UnsubscribeInPacketTest.groovy index 3475f737..2e27e076 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/in/UnsubscribeInPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/in/UnsubscribeInPacketTest.groovy @@ -8,35 +8,29 @@ import javasabr.rlib.common.util.BufferUtils class UnsubscribeInPacketTest extends BaseInPacketTest { def "should read packet correctly as mqtt 3.1.1"() { - given: - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putString(topicFilter) it.putString(topicFilter2) } - when: def packet = new UnsubscribeInPacket(0b1011_0000 as byte) - def result = packet.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result packet.topicFilters.size() == 2 packet.topicFilters.get(0).toString() == topicFilter packet.topicFilters.get(1).toString() == topicFilter2 packet.packetId == packetId - packet.userProperties == Array.empty() + packet.userProperties() == Array.empty() } def "should read packet correctly as mqtt 5.0"() { - given: - def propertiesBuffer = BufferUtils.prepareBuffer(512) { it.putProperty(PacketProperty.USER_PROPERTY, userProperties) } - def dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putMbi(propertiesBuffer.limit()) @@ -44,34 +38,31 @@ class UnsubscribeInPacketTest extends BaseInPacketTest { it.putString(topicFilter) it.putString(topicFilter2) } - when: def packet = new UnsubscribeInPacket(0b1011_0000 as byte) - def result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + def result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.topicFilters.size() == 2 packet.topicFilters.get(0).toString() == topicFilter packet.topicFilters.get(1).toString() == topicFilter2 packet.packetId == packetId - packet.userProperties == userProperties + packet.userProperties() == userProperties when: - dataBuffer = BufferUtils.prepareBuffer(512) { it.putShort(packetId) it.putMbi(0) it.putString(topicFilter) it.putString(topicFilter2) } - packet = new UnsubscribeInPacket(0b1011_0000 as byte) - result = packet.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) + result = packet.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result packet.topicFilters.size() == 2 packet.topicFilters.get(0).toString() == topicFilter packet.topicFilters.get(1).toString() == topicFilter2 packet.packetId == packetId - packet.userProperties == Array.empty() + packet.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/Authentication5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/Authentication5OutPacketTest.groovy index c5bfa5c5..b57a889e 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/Authentication5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/Authentication5OutPacketTest.groovy @@ -8,32 +8,25 @@ import javasabr.rlib.common.util.BufferUtils class Authentication5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new Authentication5OutPacket( userProperties, AuthenticateReasonCode.CONTINUE_AUTHENTICATION, reasonString, authMethod, - authData, - ) - + authData,) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new AuthenticationInPacket(0b1111_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result reader.reasonCode == AuthenticateReasonCode.CONTINUE_AUTHENTICATION reader.authenticationMethod == authMethod reader.authenticationData == authData reader.reason == reasonString - reader.userProperties == userProperties + reader.userProperties() == userProperties } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/BaseOutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/BaseOutPacketTest.groovy index 188377f9..9885c71d 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/BaseOutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/BaseOutPacketTest.groovy @@ -1,30 +1,7 @@ package javasabr.mqtt.application.network.out -import javasabr.mqtt.network.MqttClient import javasabr.mqtt.application.network.NetworkUnitSpecification -import spock.lang.Shared class BaseOutPacketTest extends NetworkUnitSpecification { - @Shared - MqttClient mqtt5Client = Stub(MqttClient.UnsafeMqttClient) { - connectionConfig() >> mqttConnectionConfig - sessionExpiryInterval() >> NetworkUnitSpecification.sessionExpiryInterval - receiveMax() >> NetworkUnitSpecification.receiveMaximum - maximumPacketSize() >> NetworkUnitSpecification.maximumPacketSize - clientId() >> clientId - keepAlive() >> serverKeepAlive - topicAliasMaximum() >> NetworkUnitSpecification.topicAliasMaximum - } - - @Shared - MqttClient mqtt311Client = Stub(MqttClient.UnsafeMqttClient) { - connectionConfig() >> mqttConnectionConfig - sessionExpiryInterval() >> NetworkUnitSpecification.sessionExpiryInterval - receiveMax() >> NetworkUnitSpecification.receiveMaximum - maximumPacketSize() >> NetworkUnitSpecification.maximumPacketSize - clientId() >> clientId - keepAlive() >> serverKeepAlive - topicAliasMaximum() >> NetworkUnitSpecification.topicAliasMaximum - } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/Connect311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/Connect311OutPacketTest.groovy index 9734a9eb..e6d43217 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/Connect311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/Connect311OutPacketTest.groovy @@ -10,38 +10,31 @@ import javasabr.rlib.common.util.BufferUtils class Connect311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new Connect311OutPacket( userName, "", - clientId, + mqtt311ClientId, userPassword, ArrayUtils.EMPTY_BYTE_ARRAY, QoS.AT_MOST_ONCE, keepAlive, willRetain, - cleanStart, - ) - + cleanStart) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new ConnectInPacket(0b0001_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - reader.username == userName - reader.clientId == clientId - reader.password == userPassword - reader.keepAlive == keepAlive - reader.userProperties == Array.empty() - reader.cleanStart == cleanStart - reader.willRetain == willRetain + reader.username() == userName + reader.clientId() == mqtt311ClientId + reader.password() == userPassword + reader.keepAlive() == keepAlive + reader.userProperties() == Array.empty() + reader.cleanStart() == cleanStart + reader.willRetain == willRetain } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/Connect5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/Connect5OutPacketTest.groovy index 73ecddcd..378ceff0 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/Connect5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/Connect5OutPacketTest.groovy @@ -9,13 +9,11 @@ import javasabr.rlib.common.util.BufferUtils class Connect5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new Connect5OutPacket( userName, "", - clientId, + mqtt311ClientId, userPassword, ArrayUtils.EMPTY_BYTE_ARRAY, QoS.AT_MOST_ONCE, @@ -26,38 +24,33 @@ class Connect5OutPacketTest extends BaseOutPacketTest { authMethod, authData, sessionExpiryInterval, - receiveMaximum, - maximumPacketSize, - topicAliasMaximum, + receiveMaxPublishes, + maxPacketSize, + topicAliasMaxValue, requestResponseInformation, - requestProblemInformation - ) - + requestProblemInformation) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new ConnectInPacket(0b0001_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - reader.username == userName - reader.clientId == clientId - reader.password == userPassword - reader.keepAlive == keepAlive - reader.userProperties == userProperties - reader.cleanStart == cleanStart - reader.willRetain == willRetain - reader.authenticationMethod == authMethod - reader.authenticationData == authData - reader.sessionExpiryInterval == sessionExpiryInterval - reader.receiveMax == receiveMaximum - reader.maximumPacketSize == maximumPacketSize - reader.topicAliasMaximum == topicAliasMaximum - reader.requestResponseInformation == requestResponseInformation - reader.requestProblemInformation == requestProblemInformation + reader.username() == userName + reader.clientId() == mqtt311ClientId + reader.password() == userPassword + reader.keepAlive() == keepAlive + reader.userProperties() == userProperties + reader.cleanStart() == cleanStart + reader.willRetain() == willRetain + reader.authenticationMethod() == authMethod + reader.authenticationData() == authData + reader.sessionExpiryInterval() == sessionExpiryInterval + reader.receiveMaxPublishes() == receiveMaxPublishes + reader.maxPacketSize() == maxPacketSize + reader.topicAliasMaxValue() == topicAliasMaxValue + reader.requestResponseInformation() == requestResponseInformation + reader.requestProblemInformation() == requestProblemInformation } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/ConnectAck311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/ConnectAck311OutPacketTest.groovy index acc4a2c8..7acb13c8 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/ConnectAck311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/ConnectAck311OutPacketTest.groovy @@ -11,30 +11,23 @@ import javasabr.rlib.common.util.BufferUtils class ConnectAck311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new ConnectAck311OutPacket( ConnectAckReasonCode.BAD_USER_NAME_OR_PASSWORD, - sessionPresent - ) - + sessionPresent) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new ConnectAckInPacket(0b0010_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result reader.reasonCode == ConnectAckReasonCode.BAD_USER_NAME_OR_PASSWORD reader.sessionPresent == sessionPresent reader.assignedClientId == "" reader.reason == "" - reader.userProperties == Array.empty() + reader.userProperties() == Array.empty() reader.retainAvailable == MqttProperties.RETAIN_AVAILABLE_DEFAULT reader.wildcardSubscriptionAvailable == MqttProperties.WILDCARD_SUBSCRIPTION_AVAILABLE_DEFAULT reader.subscriptionIdAvailable == MqttProperties.SUBSCRIPTION_IDENTIFIER_AVAILABLE_DEFAULT @@ -43,10 +36,10 @@ class ConnectAck311OutPacketTest extends BaseOutPacketTest { reader.serverReference == "" reader.authenticationData == ArrayUtils.EMPTY_BYTE_ARRAY reader.authenticationMethod == "" - reader.topicAliasMaximum == MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED + reader.topicAliasMaxValue == MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED reader.serverKeepAlive == MqttProperties.SERVER_KEEP_ALIVE_UNDEFINED - reader.receiveMax == MqttProperties.RECEIVE_MAXIMUM_UNDEFINED + reader.receiveMaxPublishes == MqttProperties.RECEIVE_MAXIMUM_UNDEFINED reader.sessionExpiryInterval == MqttProperties.SESSION_EXPIRY_INTERVAL_UNDEFINED - reader.maximumPacketSize == MqttProperties.MAXIMUM_PACKET_SIZE_UNDEFINED + reader.maxPacketSize == MqttProperties.MAXIMUM_PACKET_SIZE_UNDEFINED } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/ConnectAck5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/ConnectAck5OutPacketTest.groovy index 9c3f4d2a..a47c4114 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/ConnectAck5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/ConnectAck5OutPacketTest.groovy @@ -1,68 +1,71 @@ package javasabr.mqtt.application.network.out +import javasabr.mqtt.model.MqttVersion import javasabr.mqtt.network.packet.in.ConnectAckInPacket import javasabr.mqtt.network.packet.out.ConnectAck5OutPacket -import javasabr.mqtt.model.MqttProperties import javasabr.mqtt.model.reason.code.ConnectAckReasonCode import javasabr.rlib.common.util.BufferUtils class ConnectAck5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - + def clientConfig = clientConnectionConfig( + maxQos, + MqttVersion.MQTT_5, + 240, + 250, + maxPacketSize, + 300, + 30, + false, + false, + sessionsEnabled, + retainAvailable, + wildcardSubscriptionAvailable, + subscriptionIdAvailable, + sharedSubscriptionAvailable); + def requestedClientId = "-1" + def requestedSessionExpireInterval = 360 + def requestedKeepAlive = 120 + def requestedReceiveMaxPublishes = 500 def packet = new ConnectAck5OutPacket( + clientConfig, ConnectAckReasonCode.BAD_USER_NAME_OR_PASSWORD, sessionPresent, - "-1", - MqttProperties.SESSION_EXPIRY_INTERVAL_UNDEFINED, - MqttProperties.SERVER_KEEP_ALIVE_UNDEFINED, - MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED, + mqtt311ClientId, + requestedClientId, + requestedSessionExpireInterval, + requestedKeepAlive, + requestedReceiveMaxPublishes, reasonString, serverReference, responseInformation, authMethod, authData, - userProperties, - clientId, - maxQos, - sessionExpiryInterval, - maximumPacketSize, - receiveMaximum, - topicAliasMaximum, - serverKeepAlive, - retainAvailable, - wildcardSubscriptionAvailable, - subscriptionIdAvailable, - sharedSubscriptionAvailable - ) - + userProperties) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new ConnectAckInPacket(0b0010_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result reader.reasonCode == ConnectAckReasonCode.BAD_USER_NAME_OR_PASSWORD reader.sessionPresent == sessionPresent reader.retainAvailable == retainAvailable - reader.sessionExpiryInterval == sessionExpiryInterval - reader.receiveMax == receiveMaximum - reader.maximumPacketSize == maximumPacketSize - reader.assignedClientId == clientId - reader.topicAliasMaximum == topicAliasMaximum + reader.sessionExpiryInterval == 240 + reader.receiveMaxPublishes == 250 + reader.maxPacketSize == maxPacketSize + reader.assignedClientId == mqtt311ClientId + reader.topicAliasMaxValue == 300 reader.reason == reasonString - reader.userProperties == userProperties + reader.userProperties() == userProperties reader.wildcardSubscriptionAvailable == wildcardSubscriptionAvailable reader.subscriptionIdAvailable == subscriptionIdAvailable reader.sharedSubscriptionAvailable == sharedSubscriptionAvailable - reader.serverKeepAlive == serverKeepAlive + reader.serverKeepAlive == 30 reader.responseInformation == responseInformation reader.serverReference == serverReference reader.authenticationData == authData diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/DisconnectAck5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/DisconnectAck5OutPacketTest.groovy index 036cdab5..8e74583a 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/DisconnectAck5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/DisconnectAck5OutPacketTest.groovy @@ -8,30 +8,23 @@ import javasabr.rlib.common.util.BufferUtils class DisconnectAck5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new Disconnect5OutPacket( DisconnectReasonCode.PACKET_TOO_LARGE, userProperties, reasonString, serverReference, - sessionExpiryInterval - ) - + sessionExpiryInterval) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new DisconnectInPacket(0b1110_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result reader.reasonCode == DisconnectReasonCode.PACKET_TOO_LARGE - reader.userProperties == userProperties + reader.userProperties() == userProperties reader.reason == reasonString reader.serverReference == serverReference reader.sessionExpiryInterval == sessionExpiryInterval diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/Publish311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/Publish311OutPacketTest.groovy index 9d096a75..330411db 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/Publish311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/Publish311OutPacketTest.groovy @@ -9,7 +9,6 @@ import javasabr.rlib.common.util.BufferUtils class Publish311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: def packet = new Publish311OutPacket( packetId, @@ -19,14 +18,11 @@ class Publish311OutPacketTest extends BaseOutPacketTest { publishTopic.toString(), publishPayload) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new PublishInPacket(0b0011_1101 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result reader.packetId == packetId @@ -35,25 +31,20 @@ class Publish311OutPacketTest extends BaseOutPacketTest { reader.duplicate reader.payload == publishPayload reader.topicName == publishTopic - reader.userProperties == Array.empty() + reader.userProperties() == Array.empty() when: - packet = new Publish311OutPacket( packetId, QoS.AT_MOST_ONCE, false, false, publishTopic.toString(), - publishPayload - ) - + publishPayload) dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - reader = new PublishInPacket(0b0011_0000 as byte) - result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result reader.packetId == 0 @@ -62,6 +53,6 @@ class Publish311OutPacketTest extends BaseOutPacketTest { !reader.duplicate reader.payload == publishPayload reader.topicName == publishTopic - reader.userProperties == Array.empty() + reader.userProperties() == Array.empty() } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/Publish5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/Publish5OutPacketTest.groovy index 12890e90..ed752d00 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/Publish5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/Publish5OutPacketTest.groovy @@ -8,7 +8,6 @@ import javasabr.rlib.common.util.BufferUtils class Publish5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: def packet = new Publish5OutPacket( packetId, @@ -21,17 +20,13 @@ class Publish5OutPacketTest extends BaseOutPacketTest { false, responseTopic, correlationData, - userProperties - ) + userProperties) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new PublishInPacket(0b0011_1101 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result reader.packetId == packetId @@ -40,13 +35,12 @@ class Publish5OutPacketTest extends BaseOutPacketTest { reader.duplicate reader.payload == publishPayload reader.topicName == publishTopic - reader.userProperties == userProperties + reader.userProperties() == userProperties reader.topicAlias == topicAlias !reader.payloadFormatIndicator reader.responseTopic == responseTopic reader.correlationData == correlationData when: - packet = new Publish5OutPacket( packetId, QoS.AT_MOST_ONCE, @@ -58,16 +52,14 @@ class Publish5OutPacketTest extends BaseOutPacketTest { true, responseTopic, correlationData, - userProperties - ) + userProperties) dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } reader = new PublishInPacket(0b0011_0000 as byte) - result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result reader.packetId == 0 @@ -76,7 +68,7 @@ class Publish5OutPacketTest extends BaseOutPacketTest { !reader.duplicate reader.payload == publishPayload reader.topicName == publishTopic - reader.userProperties == userProperties + reader.userProperties() == userProperties reader.topicAlias == topicAlias reader.payloadFormatIndicator reader.responseTopic == responseTopic diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishAck311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishAck311OutPacketTest.groovy index a5d7a70a..cb464214 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishAck311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishAck311OutPacketTest.groovy @@ -9,23 +9,19 @@ import javasabr.rlib.common.util.BufferUtils class PublishAck311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: def packet = new PublishAck311OutPacket(packetId) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new PublishAckInPacket(0b0100_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCode == PublishAckReasonCode.SUCCESS - reader.packetId == packetId - reader.userProperties == Array.empty() - reader.reason == "" + reader.reasonCode() == PublishAckReasonCode.SUCCESS + reader.packetId() == packetId + reader.userProperties() == Array.empty() + reader.reason() == "" } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishAck5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishAck5OutPacketTest.groovy index f07270b7..6eee8e88 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishAck5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishAck5OutPacketTest.groovy @@ -8,30 +8,23 @@ import javasabr.rlib.common.util.BufferUtils class PublishAck5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new PublishAck5OutPacket( packetId, PublishAckReasonCode.NOT_AUTHORIZED, userProperties, - reasonString - ) - + reasonString) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new PublishAckInPacket(0b0100_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCode == PublishAckReasonCode.NOT_AUTHORIZED - reader.packetId == packetId - reader.userProperties == userProperties - reader.reason == reasonString + reader.reasonCode() == PublishAckReasonCode.NOT_AUTHORIZED + reader.packetId() == packetId + reader.userProperties() == userProperties + reader.reason() == reasonString } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishComplete311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishComplete311OutPacketTest.groovy index 2e552699..c8953f25 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishComplete311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishComplete311OutPacketTest.groovy @@ -9,23 +9,19 @@ import javasabr.rlib.common.util.BufferUtils class PublishComplete311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: def packet = new PublishComplete311OutPacket(packetId) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new PublishCompleteInPacket(0b0111_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCode == PublishCompletedReasonCode.SUCCESS - reader.packetId == packetId - reader.userProperties == Array.empty() - reader.reason == "" + reader.reasonCode() == PublishCompletedReasonCode.SUCCESS + reader.packetId() == packetId + reader.userProperties() == Array.empty() + reader.reason() == "" } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishComplete5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishComplete5OutPacketTest.groovy index 6e5a55b3..05ec4154 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishComplete5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishComplete5OutPacketTest.groovy @@ -8,30 +8,23 @@ import javasabr.rlib.common.util.BufferUtils class PublishComplete5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new PublishComplete5OutPacket( packetId, PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND, userProperties, - reasonString - ) - + reasonString) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new PublishCompleteInPacket(0b0111_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCode == PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND - reader.packetId == packetId - reader.userProperties == userProperties - reader.reason == reasonString + reader.reasonCode() == PublishCompletedReasonCode.PACKET_IDENTIFIER_NOT_FOUND + reader.packetId() == packetId + reader.userProperties() == userProperties + reader.reason() == reasonString } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishReceived311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishReceived311OutPacketTest.groovy index b0d0c94f..0c06b381 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishReceived311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishReceived311OutPacketTest.groovy @@ -10,23 +10,19 @@ import javasabr.rlib.common.util.BufferUtils class PublishReceived311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: def packet = new PublishReceived311OutPacket(packetId) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new PublishReceivedInPacket(0b0101_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCode == PublishReceivedReasonCode.SUCCESS - reader.packetId == packetId - reader.userProperties == Array.empty(StringPair) - reader.reason == "" + reader.reasonCode() == PublishReceivedReasonCode.SUCCESS + reader.packetId() == packetId + reader.userProperties() == Array.empty(StringPair) + reader.reason() == "" } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishReceived5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishReceived5OutPacketTest.groovy index 941b966e..3f724803 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishReceived5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishReceived5OutPacketTest.groovy @@ -8,30 +8,23 @@ import javasabr.rlib.common.util.BufferUtils class PublishReceived5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new PublishReceived5OutPacket( packetId, PublishReceivedReasonCode.UNSPECIFIED_ERROR, userProperties, - reasonString - ) - + reasonString) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new PublishReceivedInPacket(0b0101_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCode == PublishReceivedReasonCode.UNSPECIFIED_ERROR - reader.packetId == packetId - reader.userProperties == userProperties - reader.reason == reasonString + reader.reasonCode() == PublishReceivedReasonCode.UNSPECIFIED_ERROR + reader.packetId() == packetId + reader.userProperties() == userProperties + reader.reason() == reasonString } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishRelease311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishRelease311OutPacketTest.groovy index 8e5dfc65..e21a6588 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishRelease311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishRelease311OutPacketTest.groovy @@ -10,23 +10,19 @@ import javasabr.rlib.common.util.BufferUtils class PublishRelease311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: def packet = new PublishRelease311OutPacket(packetId) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new PublishReleaseInPacket(0b0110_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCode == PublishReleaseReasonCode.SUCCESS - reader.packetId == packetId - reader.userProperties == Array.empty(StringPair) - reader.reason == "" + reader.reasonCode() == PublishReleaseReasonCode.SUCCESS + reader.packetId() == packetId + reader.userProperties() == Array.empty(StringPair) + reader.reason() == "" } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishRelease5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishRelease5OutPacketTest.groovy index 9b9e3b04..8646cc66 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishRelease5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/PublishRelease5OutPacketTest.groovy @@ -8,30 +8,23 @@ import javasabr.rlib.common.util.BufferUtils class PublishRelease5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new PublishRelease5OutPacket( packetId, PublishReleaseReasonCode.PACKET_IDENTIFIER_NOT_FOUND, userProperties, - reasonString - ) - + reasonString) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new PublishReleaseInPacket(0b0110_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCode == PublishReleaseReasonCode.PACKET_IDENTIFIER_NOT_FOUND - reader.packetId == packetId - reader.userProperties == userProperties - reader.reason == reasonString + reader.reasonCode() == PublishReleaseReasonCode.PACKET_IDENTIFIER_NOT_FOUND + reader.packetId() == packetId + reader.userProperties() == userProperties + reader.reason() == reasonString } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/Subscribe311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/Subscribe311OutPacketTest.groovy index 30076825..75fe9522 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/Subscribe311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/Subscribe311OutPacketTest.groovy @@ -10,28 +10,21 @@ import javasabr.rlib.common.util.BufferUtils class Subscribe311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new Subscribe311OutPacket( topicFiltersObj311, - 1 - ) - + 1) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new SubscribeInPacket(0b1000_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result reader.packetId == 1 reader.topicFilters == topicFiltersObj311 - reader.userProperties == Array.empty(StringPair) + reader.userProperties() == Array.empty(StringPair) reader.subscriptionId == MqttProperties.SUBSCRIPTION_ID_UNDEFINED } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/Subscribe5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/Subscribe5OutPacketTest.groovy index 1333ca24..9a8364cf 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/Subscribe5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/Subscribe5OutPacketTest.groovy @@ -8,30 +8,23 @@ import javasabr.rlib.common.util.BufferUtils class Subscribe5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new Subscribe5OutPacket( topicFiltersObj5, 1, userProperties, - MqttProperties.SUBSCRIPTION_ID_UNDEFINED - ) - + MqttProperties.SUBSCRIPTION_ID_UNDEFINED) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new SubscribeInPacket(0b1000_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result reader.packetId == 1 reader.topicFilters == topicFiltersObj5 - reader.userProperties == userProperties + reader.userProperties() == userProperties reader.subscriptionId == MqttProperties.SUBSCRIPTION_ID_UNDEFINED } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/SubscribeAck311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/SubscribeAck311OutPacketTest.groovy index bf408faf..54420e3c 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/SubscribeAck311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/SubscribeAck311OutPacketTest.groovy @@ -9,23 +9,19 @@ import javasabr.rlib.common.util.BufferUtils class SubscribeAck311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: def packet = new SubscribeAck311OutPacket(subscribeAckReasonCodes, packetId) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new SubscribeAckInPacket(0b1001_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result reader.reasonCodes == subscribeAckReasonCodes reader.packetId == packetId - reader.userProperties == Array.empty(StringPair) + reader.userProperties() == Array.empty(StringPair) reader.reason == "" } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/SubscribeAck5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/SubscribeAck5OutPacketTest.groovy index 6fb204d3..deadb2cd 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/SubscribeAck5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/SubscribeAck5OutPacketTest.groovy @@ -7,30 +7,23 @@ import javasabr.rlib.common.util.BufferUtils class SubscribeAck5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new SubscribeAck5OutPacket( packetId, subscribeAckReasonCodes, userProperties, - reasonString - ) - + reasonString) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new SubscribeAckInPacket(0b1001_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result reader.reasonCodes == subscribeAckReasonCodes reader.packetId == packetId - reader.userProperties == userProperties + reader.userProperties() == userProperties reader.reason == reasonString } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/UnsubscribeAck311OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/UnsubscribeAck311OutPacketTest.groovy index a840e145..e8b0e450 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/UnsubscribeAck311OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/UnsubscribeAck311OutPacketTest.groovy @@ -10,23 +10,19 @@ import javasabr.rlib.common.util.BufferUtils class UnsubscribeAck311OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: def packet = new UnsubscribeAck311OutPacket(packetId) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt311Connection, it) + packet.write(defaultMqtt311Connection, it) } - def reader = new UnsubscribeAckInPacket(0b1011_0000 as byte) - def result = reader.read(mqtt311Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt311Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCodes == Array.empty(UnsubscribeAckReasonCode) - reader.packetId == packetId - reader.userProperties == Array.empty(StringPair) - reader.reason == "" + reader.reasonCodes() == Array.empty(UnsubscribeAckReasonCode) + reader.packetId() == packetId + reader.userProperties() == Array.empty(StringPair) + reader.reason() == "" } } diff --git a/application/src/test/groovy/javasabr/mqtt/application/network/out/UnsubscribeAck5OutPacketTest.groovy b/application/src/test/groovy/javasabr/mqtt/application/network/out/UnsubscribeAck5OutPacketTest.groovy index 306ebad8..a28a8323 100644 --- a/application/src/test/groovy/javasabr/mqtt/application/network/out/UnsubscribeAck5OutPacketTest.groovy +++ b/application/src/test/groovy/javasabr/mqtt/application/network/out/UnsubscribeAck5OutPacketTest.groovy @@ -7,30 +7,23 @@ import javasabr.rlib.common.util.BufferUtils class UnsubscribeAck5OutPacketTest extends BaseOutPacketTest { def "should write packet correctly"() { - given: - def packet = new UnsubscribeAck5OutPacket( packetId, unsubscribeAckReasonCodes, userProperties, - reasonString - ) - + reasonString) when: - def dataBuffer = BufferUtils.prepareBuffer(512) { - packet.write(mqtt5Connection, it) + packet.write(defaultMqtt5Connection, it) } - def reader = new UnsubscribeAckInPacket(0b1011_0000 as byte) - def result = reader.read(mqtt5Connection, dataBuffer, dataBuffer.limit()) - + def result = reader.read(defaultMqtt5Connection, dataBuffer, dataBuffer.limit()) then: result - reader.reasonCodes == unsubscribeAckReasonCodes - reader.packetId == packetId - reader.userProperties == userProperties - reader.reason == reasonString + reader.reasonCodes() == unsubscribeAckReasonCodes + reader.packetId() == packetId + reader.userProperties() == userProperties + reader.reason() == reasonString } } diff --git a/model/src/main/java/javasabr/mqtt/model/MqttClientConnectionConfig.java b/model/src/main/java/javasabr/mqtt/model/MqttClientConnectionConfig.java new file mode 100644 index 00000000..06e4d32d --- /dev/null +++ b/model/src/main/java/javasabr/mqtt/model/MqttClientConnectionConfig.java @@ -0,0 +1,17 @@ +package javasabr.mqtt.model; + +public record MqttClientConnectionConfig( + QoS maxQos, + MqttVersion mqttVersion, + long sessionExpiryInterval, + int receiveMaxPublishes, + int maxPacketSize, + int topicAliasMaxValue, + int keepAlive, + boolean requestResponseInformation, + boolean requestProblemInformation, + boolean sessionsEnabled, + boolean retainAvailable, + boolean wildcardSubscriptionAvailable, + boolean subscriptionIdAvailable, + boolean sharedSubscriptionAvailable) {} diff --git a/model/src/main/java/javasabr/mqtt/model/MqttConnectionConfig.java b/model/src/main/java/javasabr/mqtt/model/MqttConnectionConfig.java deleted file mode 100644 index a81e3450..00000000 --- a/model/src/main/java/javasabr/mqtt/model/MqttConnectionConfig.java +++ /dev/null @@ -1,27 +0,0 @@ -package javasabr.mqtt.model; - -import lombok.Getter; -import lombok.RequiredArgsConstructor; -import lombok.experimental.Accessors; - -@Getter -@RequiredArgsConstructor -@Accessors(fluent = true, chain = false) -public class MqttConnectionConfig { - - private final QoS maxQos; - - private final int maximumPacketSize; - private final int minKeepAliveTime; - private final int receiveMaximum; - private final int topicAliasMaximum; - - private final long defaultSessionExpiryInterval; - - private final boolean keepAliveEnabled; - private final boolean sessionsEnabled; - private final boolean retainAvailable; - private final boolean wildcardSubscriptionAvailable; - private final boolean subscriptionIdAvailable; - private final boolean sharedSubscriptionAvailable; -} diff --git a/model/src/main/java/javasabr/mqtt/model/MqttProperties.java b/model/src/main/java/javasabr/mqtt/model/MqttProperties.java index f4b859ef..27906f8b 100644 --- a/model/src/main/java/javasabr/mqtt/model/MqttProperties.java +++ b/model/src/main/java/javasabr/mqtt/model/MqttProperties.java @@ -23,6 +23,9 @@ public interface MqttProperties { int MAXIMUM_PACKET_SIZE_MIN = 1; int MAXIMUM_PACKET_SIZE_MAX = MAXIMUM_PROTOCOL_PACKET_SIZE; + int MAXIMUM_STRING_LENGTH = 2048; + int MAXIMUM_BINARY_SIZE = 2048; + boolean PAYLOAD_FORMAT_INDICATOR_DEFAULT = false; long MESSAGE_EXPIRY_INTERVAL_UNDEFINED = -1; diff --git a/model/src/main/java/javasabr/mqtt/model/MqttServerConnectionConfig.java b/model/src/main/java/javasabr/mqtt/model/MqttServerConnectionConfig.java new file mode 100644 index 00000000..179e95ff --- /dev/null +++ b/model/src/main/java/javasabr/mqtt/model/MqttServerConnectionConfig.java @@ -0,0 +1,18 @@ +package javasabr.mqtt.model; + +public record MqttServerConnectionConfig( + QoS maxQos, + int maxPacketSize, + int maxStringLength, + int maxBinarySize, + int minKeepAliveTime, + int receiveMaxPublishes, + int topicAliasMaxValue, + long defaultSessionExpiryInterval, + boolean keepAliveEnabled, + boolean sessionsEnabled, + boolean retainAvailable, + boolean wildcardSubscriptionAvailable, + boolean subscriptionIdAvailable, + boolean sharedSubscriptionAvailable) { +} diff --git a/model/src/main/java/javasabr/mqtt/model/MqttVersion.java b/model/src/main/java/javasabr/mqtt/model/MqttVersion.java index ed91e126..df1d4189 100644 --- a/model/src/main/java/javasabr/mqtt/model/MqttVersion.java +++ b/model/src/main/java/javasabr/mqtt/model/MqttVersion.java @@ -4,66 +4,78 @@ import java.util.Arrays; import java.util.HashMap; import java.util.Map; +import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; @Getter +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public enum MqttVersion { UNKNOWN("Unknown", -1), MQTT_3_1_1("MQTT", 4), MQTT_5("MQTT", 5); - private static final Map NAME_LEVEL_VERSIONS; + private static final Map NAME_LEVEL_VERSIONS; static { - var map = new HashMap(); - - for (var mqttVersion : values()) { + var map = new HashMap(); + for (MqttVersion mqttVersion : values()) { if (mqttVersion.version < 0) { continue; } - var versions = map.computeIfAbsent(mqttVersion.name, name -> new MqttVersion[mqttVersion.version + 1]); - - if (versions.length > mqttVersion.version) { - versions[mqttVersion.version] = mqttVersion; + @Nullable MqttVersion[] versions = map.computeIfAbsent(mqttVersion.rawName(), _ -> new MqttVersion[mqttVersion.version + 1]); + if (versions.length > mqttVersion.version()) { + versions[mqttVersion.version()] = mqttVersion; continue; } versions = Arrays.copyOf(versions, mqttVersion.version + 1); versions[mqttVersion.version] = mqttVersion; - map.replace(mqttVersion.name, versions); + map.replace(mqttVersion.rawName, versions); } NAME_LEVEL_VERSIONS = Map.copyOf(map); } + byte[] nameInBytes; + String rawName; + byte version; + + MqttVersion(String rawName, int version) { + this.rawName = rawName; + this.version = (byte) version; + this.nameInBytes = rawName.getBytes(StandardCharsets.UTF_8); + } + + public boolean include(MqttVersion version) { + return ordinal() >= version.ordinal(); + } + + public boolean isLowerThan(MqttVersion version) { + return ordinal() < version.ordinal(); + } + public static MqttVersion of(String name, byte level) { if (level < 0) { return MqttVersion.UNKNOWN; } - var availableVersions = NAME_LEVEL_VERSIONS.get(name); - + @Nullable MqttVersion[] availableVersions = NAME_LEVEL_VERSIONS.get(name); if (availableVersions == null) { return MqttVersion.UNKNOWN; } else if (availableVersions.length <= level || availableVersions[level] == null) { return MqttVersion.UNKNOWN; } + //noinspection DataFlowIssue return availableVersions[level]; } - - private final byte[] nameInBytes; - private final String name; - private final byte version; - - MqttVersion(String name, int version) { - this.name = name; - this.version = (byte) version; - this.nameInBytes = name.getBytes(StandardCharsets.UTF_8); - } } diff --git a/model/src/main/java/javasabr/mqtt/model/PacketProperty.java b/model/src/main/java/javasabr/mqtt/model/PacketProperty.java index d4ad72fe..83feba70 100644 --- a/model/src/main/java/javasabr/mqtt/model/PacketProperty.java +++ b/model/src/main/java/javasabr/mqtt/model/PacketProperty.java @@ -4,9 +4,14 @@ import java.util.stream.Stream; import javasabr.rlib.common.util.ClassUtils; import javasabr.rlib.common.util.ObjectUtils; +import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public enum PacketProperty { PAYLOAD_FORMAT_INDICATOR(0x01, PacketDataType.BYTE), MESSAGE_EXPIRY_INTERVAL(0x02, PacketDataType.INTEGER), @@ -25,7 +30,7 @@ public enum PacketProperty { RESPONSE_INFORMATION(0x1A, PacketDataType.UTF_8_STRING), SERVER_REFERENCE(0x1C, PacketDataType.UTF_8_STRING), REASON_STRING(0x1F, PacketDataType.UTF_8_STRING), - RECEIVE_MAXIMUM(0x21, PacketDataType.SHORT), + RECEIVE_MAXIMUM_PUBLISH(0x21, PacketDataType.SHORT), TOPIC_ALIAS_MAXIMUM(0x22, PacketDataType.SHORT), TOPIC_ALIAS(0x23, PacketDataType.SHORT), MAXIMUM_QOS(0x24, PacketDataType.BYTE), @@ -42,7 +47,7 @@ public enum PacketProperty { int maxId = Stream .of(values()) - .mapToInt(PacketProperty::getId) + .mapToInt(PacketProperty::id) .max() .orElse(0); @@ -55,7 +60,7 @@ public enum PacketProperty { PROPERTIES = result; } - public static PacketProperty of(int id) { + public static PacketProperty byId(int id) { if (id < 0 || id >= PROPERTIES.length) { throw new IllegalArgumentException("Unknown property with id: " + id); } else { @@ -64,12 +69,12 @@ public static PacketProperty of(int id) { } @Getter - private final byte id; + byte id; @Getter - private final PacketDataType dataType; + PacketDataType dataType; @Nullable - private final Object defaultValue; + Object defaultValue; PacketProperty(int id, PacketDataType dataType) { this(id, dataType, null); @@ -81,7 +86,7 @@ public static PacketProperty of(int id) { this.defaultValue = defaultValue; } - public T getDefaultValue() { + public T defaultValue() { return ClassUtils.unsafeNNCast(ObjectUtils.notNull(defaultValue)); } } diff --git a/model/src/main/java/javasabr/mqtt/model/topic/TopicSubscribers.java b/model/src/main/java/javasabr/mqtt/model/topic/TopicSubscribers.java index 92e4be15..68db65fb 100644 --- a/model/src/main/java/javasabr/mqtt/model/topic/TopicSubscribers.java +++ b/model/src/main/java/javasabr/mqtt/model/topic/TopicSubscribers.java @@ -19,13 +19,151 @@ import javasabr.rlib.collections.dictionary.LockableRefToRefDictionary; import javasabr.rlib.collections.dictionary.MutableRefToRefDictionary; import javasabr.rlib.collections.dictionary.RefToRefDictionary; +import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; +@FieldDefaults(level = AccessLevel.PRIVATE) public class TopicSubscribers { private final static Supplier TOPIC_SUBSCRIBER_SUPPLIER = TopicSubscribers::new; + @Getter + @Nullable + volatile LockableRefToRefDictionary topicSubscribers; + + @Getter + @Nullable + volatile LockableArray subscribers; + + public void addSubscriber(MqttUser user, SubscribeTopicFilter subscribe) { + searchPlaceForSubscriber(0, subscribe.getTopicFilter(), user, subscribe); + } + + private void searchPlaceForSubscriber( + int level, + TopicFilter topicFilter, + MqttUser user, + SubscribeTopicFilter subscribe) { + if (level == topicFilter.levelsCount()) { + LockableArray subscribers = getOrCreateSubscribers(); + subscribers + .operations() + .inWriteLock(user, subscribe, TopicSubscribers::addSubscriber); + } else { + LockableRefToRefDictionary topicSubscribers = getOrCreateTopicSubscribers(); + TopicSubscribers topicSubscriber = topicSubscribers + .operations() + .getInWriteLock( + topicFilter.getSegment(level), + TOPIC_SUBSCRIBER_SUPPLIER, + MutableRefToRefDictionary::getOrCompute); + + //noinspection ConstantConditions + topicSubscriber.searchPlaceForSubscriber(level + 1, topicFilter, user, subscribe); + } + } + + public void removeSubscriber(MqttUser user, SubscribeTopicFilter subscribe) { + removeSubscriber(user, subscribe.getTopicFilter()); + } + + public boolean removeSubscriber(MqttUser user, TopicFilter topicFilter) { + return searchSubscriberToRemove(0, topicFilter, user); + } + + private boolean searchSubscriberToRemove(int level, TopicFilter topicFilter, MqttUser user) { + var removed = false; + + LockableRefToRefDictionary topicSubscribers = getTopicSubscribers(); + if (level == topicFilter.levelsCount()) { + removed = tryToRemoveSubscriber(topicFilter, user); + } else if (topicSubscribers != null) { + TopicSubscribers topicSubscriber = topicSubscribers + .operations() + .getInReadLock(topicFilter.getSegment(level), Dictionary::get); + if (topicSubscriber != null) { + removed = topicSubscriber.searchSubscriberToRemove(level + 1, topicFilter, user); + } + } + + return removed; + } + + private boolean tryToRemoveSubscriber(TopicFilter topicFilter, MqttUser user) { + LockableArray subscribers = getSubscribers(); + if (subscribers == null) { + return false; + } + return subscribers + .operations() + .getInWriteLock(topicFilter, user, TopicSubscribers::removeSubscriber); + } + + public Array matches(TopicName topicName) { + var resultArray = MutableArray.ofType(SingleSubscriber.class); + processLevel(0, topicName.getSegment(0), topicName, resultArray); + return resultArray; + } + + private void processLevel(int level, String segment, TopicName topicName, MutableArray result) { + var nextLevel = level + 1; + processSegment(nextLevel, segment, topicName, result); + processSegment(nextLevel, TopicUtils.SINGLE_LEVEL_WILDCARD, topicName, result); + processSegment(nextLevel, TopicUtils.MULTI_LEVEL_WILDCARD, topicName, result); + } + + private void processSegment( + int nextLevel, + String segment, + TopicName topicName, + MutableArray result) { + + LockableRefToRefDictionary subscribersMap = getTopicSubscribers(); + if (subscribersMap == null) { + return; + } + + TopicSubscribers topicSubscribers = subscribersMap + .operations() + .getInReadLock(segment, result, TopicSubscribers::collectSubscribers); + + if (topicSubscribers != null && nextLevel < topicName.levelsCount()) { + String nextSegment = topicName.getSegment(nextLevel); + topicSubscribers.processLevel(nextLevel, nextSegment, topicName, result); + } + } + + private LockableRefToRefDictionary getOrCreateTopicSubscribers() { + if (topicSubscribers == null) { + synchronized (this) { + if (topicSubscribers == null) { + topicSubscribers = DictionaryFactory.stampedLockBasedRefToRefDictionary(); + } + } + } + //noinspection ConstantConditions + return topicSubscribers; + } + + private LockableArray getOrCreateSubscribers() { + if (subscribers == null) { + synchronized (this) { + if (subscribers == null) { + subscribers = ArrayFactory.stampedLockBasedArray(Subscriber.class); + } + } + } + //noinspection ConstantConditions + return subscribers; + } + + @Override + public String toString() { + return "TopicSubscribers{" + "topicSubscribers=" + topicSubscribers + ", subscribers=" + subscribers + '}'; + } + private static void addSubscriber( LockableArray subscribers, MqttUser user, @@ -156,132 +294,4 @@ private static TopicSubscribers collectSubscribers( } return topicSubscribers; } - - private volatile @Getter - @Nullable LockableRefToRefDictionary topicSubscribers; - - private volatile @Getter - @Nullable LockableArray subscribers; - - public void addSubscriber(MqttUser user, SubscribeTopicFilter subscribe) { - searchPlaceForSubscriber(0, subscribe.getTopicFilter(), user, subscribe); - } - - private void searchPlaceForSubscriber( - int level, - TopicFilter topicFilter, - MqttUser user, - SubscribeTopicFilter subscribe) { - if (level == topicFilter.levelsCount()) { - LockableArray subscribers = getOrCreateSubscribers(); - subscribers - .operations() - .inWriteLock(user, subscribe, TopicSubscribers::addSubscriber); - } else { - LockableRefToRefDictionary topicSubscribers = getOrCreateTopicSubscribers(); - TopicSubscribers topicSubscriber = topicSubscribers - .operations() - .getInWriteLock( - topicFilter.getSegment(level), - TOPIC_SUBSCRIBER_SUPPLIER, - MutableRefToRefDictionary::getOrCompute); - - //noinspection ConstantConditions - topicSubscriber.searchPlaceForSubscriber(level + 1, topicFilter, user, subscribe); - } - } - - public void removeSubscriber(MqttUser user, SubscribeTopicFilter subscribe) { - removeSubscriber(user, subscribe.getTopicFilter()); - } - - public boolean removeSubscriber(MqttUser user, TopicFilter topicFilter) { - return searchSubscriberToRemove(0, topicFilter, user); - } - - private boolean searchSubscriberToRemove(int level, TopicFilter topicFilter, MqttUser user) { - var removed = false; - - LockableRefToRefDictionary topicSubscribers = getTopicSubscribers(); - if (level == topicFilter.levelsCount()) { - removed = tryToRemoveSubscriber(topicFilter, user); - } else if (topicSubscribers != null) { - TopicSubscribers topicSubscriber = topicSubscribers - .operations() - .getInReadLock(topicFilter.getSegment(level), Dictionary::get); - if (topicSubscriber != null) { - removed = topicSubscriber.searchSubscriberToRemove(level + 1, topicFilter, user); - } - } - - return removed; - } - - private boolean tryToRemoveSubscriber(TopicFilter topicFilter, MqttUser user) { - LockableArray subscribers = getSubscribers(); - if (subscribers == null) { - return false; - } - return subscribers - .operations() - .getInWriteLock(topicFilter, user, TopicSubscribers::removeSubscriber); - } - - public Array matches(TopicName topicName) { - var resultArray = MutableArray.ofType(SingleSubscriber.class); - processLevel(0, topicName.getSegment(0), topicName, resultArray); - return resultArray; - } - - private void processLevel(int level, String segment, TopicName topicName, MutableArray result) { - var nextLevel = level + 1; - processSegment(nextLevel, segment, topicName, result); - processSegment(nextLevel, TopicUtils.SINGLE_LEVEL_WILDCARD, topicName, result); - processSegment(nextLevel, TopicUtils.MULTI_LEVEL_WILDCARD, topicName, result); - } - - private void processSegment( - int nextLevel, - String segment, - TopicName topicName, - MutableArray result) { - - LockableRefToRefDictionary subscribersMap = getTopicSubscribers(); - if (subscribersMap == null) { - return; - } - - TopicSubscribers topicSubscribers = subscribersMap - .operations() - .getInReadLock(segment, result, TopicSubscribers::collectSubscribers); - - if (topicSubscribers != null && nextLevel < topicName.levelsCount()) { - String nextSegment = topicName.getSegment(nextLevel); - topicSubscribers.processLevel(nextLevel, nextSegment, topicName, result); - } - } - - private LockableRefToRefDictionary getOrCreateTopicSubscribers() { - if (topicSubscribers == null) { - synchronized (this) { - if (topicSubscribers == null) { - topicSubscribers = DictionaryFactory.stampedLockBasedRefToRefDictionary(); - } - } - } - //noinspection ConstantConditions - return topicSubscribers; - } - - private LockableArray getOrCreateSubscribers() { - if (subscribers == null) { - synchronized (this) { - if (subscribers == null) { - subscribers = ArrayFactory.stampedLockBasedArray(Subscriber.class); - } - } - } - //noinspection ConstantConditions - return subscribers; - } } diff --git a/network/src/main/java/javasabr/mqtt/network/MqttClient.java b/network/src/main/java/javasabr/mqtt/network/MqttClient.java index 01e5a715..696f76b5 100644 --- a/network/src/main/java/javasabr/mqtt/network/MqttClient.java +++ b/network/src/main/java/javasabr/mqtt/network/MqttClient.java @@ -1,7 +1,7 @@ package javasabr.mqtt.network; import java.util.concurrent.CompletableFuture; -import javasabr.mqtt.model.MqttConnectionConfig; +import javasabr.mqtt.model.MqttClientConnectionConfig; import javasabr.mqtt.model.MqttUser; import javasabr.mqtt.model.reason.code.ConnectAckReasonCode; import javasabr.mqtt.network.out.MqttPacketOutFactory; @@ -18,15 +18,6 @@ interface UnsafeMqttClient extends MqttClient { void handle(MqttReadablePacket packet); - void configure( - long sessionExpiryInterval, - int receiveMax, - int maximumPacketSize, - int topicAliasMaximum, - int keepAlive, - boolean requestResponseInformation, - boolean requestProblemInformation); - void clientId(String clientId); void session(@Nullable MqttSession session); @@ -38,22 +29,12 @@ void configure( MqttPacketOutFactory packetOutFactory(); - MqttConnectionConfig connectionConfig(); - String clientId(); @Nullable MqttSession session(); - int keepAlive(); - - int maximumPacketSize(); - - int receiveMax(); - - int topicAliasMaximum(); - - long sessionExpiryInterval(); + MqttClientConnectionConfig connectionConfig(); void send(MqttWritablePacket packet); diff --git a/network/src/main/java/javasabr/mqtt/network/MqttConnection.java b/network/src/main/java/javasabr/mqtt/network/MqttConnection.java index a542367b..5593ad50 100644 --- a/network/src/main/java/javasabr/mqtt/network/MqttConnection.java +++ b/network/src/main/java/javasabr/mqtt/network/MqttConnection.java @@ -2,10 +2,11 @@ import java.nio.channels.AsynchronousSocketChannel; import java.util.function.Function; -import javasabr.mqtt.model.MqttConnectionConfig; +import javasabr.mqtt.model.MqttClientConnectionConfig; +import javasabr.mqtt.model.MqttServerConnectionConfig; import javasabr.mqtt.model.MqttVersion; import javasabr.mqtt.network.MqttClient.UnsafeMqttClient; -import javasabr.mqtt.network.handler.packet.in.PacketInHandler; +import javasabr.mqtt.network.handler.PacketInHandler; import javasabr.mqtt.network.packet.MqttPacketReader; import javasabr.mqtt.network.packet.MqttPacketWriter; import javasabr.rlib.network.BufferAllocator; @@ -16,34 +17,30 @@ import lombok.AccessLevel; import lombok.CustomLog; import lombok.Getter; -import lombok.Setter; import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; @CustomLog @Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PRIVATE) public class MqttConnection extends AbstractConnection { @Getter(AccessLevel.PROTECTED) - private final NetworkPacketReader packetReader; - + final NetworkPacketReader packetReader; @Getter(AccessLevel.PROTECTED) - private final NetworkPacketWriter packetWriter; + final NetworkPacketWriter packetWriter; @Getter - private final PacketInHandler[] packetHandlers; + final PacketInHandler[] packetHandlers; @Getter - private final UnsafeMqttClient client; - @Getter - private final MqttConnectionConfig config; - + final UnsafeMqttClient client; @Getter - @Setter - private volatile MqttVersion mqttVersion; + final MqttServerConnectionConfig serverConnectionConfig; - @Getter - @Setter - private volatile MqttSession session; + @Nullable + MqttClientConnectionConfig clientConnectionConfig; public MqttConnection( Network network, @@ -51,19 +48,39 @@ public MqttConnection( BufferAllocator bufferAllocator, int maxPacketsByRead, PacketInHandler[] packetHandlers, - MqttConnectionConfig config, + MqttServerConnectionConfig config, Function clientFactory) { super(network, channel, bufferAllocator, maxPacketsByRead); this.packetHandlers = packetHandlers; - this.config = config; - this.mqttVersion = MqttVersion.MQTT_3_1_1; + this.serverConnectionConfig = config; this.packetReader = createPacketReader(); this.packetWriter = createPacketWriter(); this.client = clientFactory.apply(this); } public boolean isSupported(MqttVersion mqttVersion) { - return this.mqttVersion.ordinal() >= mqttVersion.ordinal(); + return clientConnectionConfig() + .mqttVersion() + .include(mqttVersion); + } + + public void configure(MqttClientConnectionConfig clientConnectionConfig) { + synchronized (this) { + this.clientConnectionConfig = clientConnectionConfig; + } + } + + public MqttClientConnectionConfig clientConnectionConfig() { + var config = this.clientConnectionConfig; + if (config == null) { + synchronized (this) { + config = this.clientConnectionConfig; + if (config == null) { + throw new IllegalStateException("The connection is not fully configured."); + } + } + } + return config; } private NetworkPacketReader createPacketReader() { diff --git a/network/src/main/java/javasabr/mqtt/network/client/AbstractMqttClient.java b/network/src/main/java/javasabr/mqtt/network/client/AbstractMqttClient.java index 96ee8a43..b454ae88 100644 --- a/network/src/main/java/javasabr/mqtt/network/client/AbstractMqttClient.java +++ b/network/src/main/java/javasabr/mqtt/network/client/AbstractMqttClient.java @@ -3,13 +3,13 @@ import java.util.concurrent.CompletableFuture; import java.util.concurrent.atomic.AtomicBoolean; import javasabr.mqtt.base.utils.DebugUtils; -import javasabr.mqtt.model.MqttConnectionConfig; +import javasabr.mqtt.model.MqttClientConnectionConfig; import javasabr.mqtt.model.reason.code.ConnectAckReasonCode; import javasabr.mqtt.network.MqttClient.UnsafeMqttClient; import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.MqttSession; -import javasabr.mqtt.network.handler.client.MqttClientReleaseHandler; -import javasabr.mqtt.network.handler.packet.in.PacketInHandler; +import javasabr.mqtt.network.handler.MqttClientReleaseHandler; +import javasabr.mqtt.network.handler.PacketInHandler; import javasabr.mqtt.network.out.MqttPacketOutFactories; import javasabr.mqtt.network.out.MqttPacketOutFactory; import javasabr.mqtt.network.packet.in.MqttReadablePacket; @@ -45,26 +45,11 @@ public abstract class AbstractMqttClient implements UnsafeMqttClient { @Nullable volatile MqttSession session; - volatile long sessionExpiryInterval; - volatile int receiveMax; - volatile int maximumPacketSize; - volatile int topicAliasMaximum; - volatile int keepAlive; - - volatile boolean requestResponseInformation = false; - volatile boolean requestProblemInformation = false; - public AbstractMqttClient(MqttConnection connection, MqttClientReleaseHandler releaseHandler) { - MqttConnectionConfig config = connection.config(); this.connection = connection; this.releaseHandler = releaseHandler; this.released = new AtomicBoolean(false); this.clientId = connection.remoteAddress(); - this.sessionExpiryInterval = config.defaultSessionExpiryInterval(); - this.receiveMax = config.receiveMaximum(); - this.maximumPacketSize = config.maximumPacketSize(); - this.topicAliasMaximum = config.topicAliasMaximum(); - this.keepAlive = config.minKeepAliveTime(); } @Override @@ -78,24 +63,6 @@ public void handle(MqttReadablePacket packet) { } } - @Override - public void configure( - long sessionExpiryInterval, - int receiveMax, - int maximumPacketSize, - int topicAliasMaximum, - int keepAlive, - boolean requestResponseInformation, - boolean requestProblemInformation) { - this.sessionExpiryInterval = sessionExpiryInterval; - this.receiveMax = receiveMax; - this.maximumPacketSize = maximumPacketSize; - this.topicAliasMaximum = topicAliasMaximum; - this.keepAlive = keepAlive; - this.requestProblemInformation = requestProblemInformation; - this.requestResponseInformation = requestResponseInformation; - } - @Override public void send(MqttWritablePacket packet) { log.debug(clientId, packet.name(), packet, "[%s] Send to client packet:[%s] %s"::formatted); @@ -116,12 +83,9 @@ public void reject(ConnectAckReasonCode reasonCode) { @Override public MqttPacketOutFactory packetOutFactory() { - return MqttPacketOutFactories.of(connection.mqttVersion()); - } - - @Override - public MqttConnectionConfig connectionConfig() { - return connection.config(); + return MqttPacketOutFactories.of(connection + .clientConnectionConfig() + .mqttVersion()); } @Override @@ -133,6 +97,11 @@ public Mono release() { } } + @Override + public MqttClientConnectionConfig connectionConfig() { + return connection.clientConnectionConfig(); + } + @Override public String toString() { return DebugUtils.toJsonString(this); diff --git a/network/src/main/java/javasabr/mqtt/network/client/ExternalMqttClient.java b/network/src/main/java/javasabr/mqtt/network/client/ExternalMqttClient.java index ebe321c4..b51ed805 100644 --- a/network/src/main/java/javasabr/mqtt/network/client/ExternalMqttClient.java +++ b/network/src/main/java/javasabr/mqtt/network/client/ExternalMqttClient.java @@ -2,7 +2,7 @@ import javasabr.mqtt.base.utils.DebugUtils; import javasabr.mqtt.network.MqttConnection; -import javasabr.mqtt.network.handler.client.MqttClientReleaseHandler; +import javasabr.mqtt.network.handler.MqttClientReleaseHandler; public class ExternalMqttClient extends AbstractMqttClient { diff --git a/network/src/main/java/javasabr/mqtt/network/client/InternalMqttClient.java b/network/src/main/java/javasabr/mqtt/network/client/InternalMqttClient.java index 94159851..6fa07737 100644 --- a/network/src/main/java/javasabr/mqtt/network/client/InternalMqttClient.java +++ b/network/src/main/java/javasabr/mqtt/network/client/InternalMqttClient.java @@ -2,7 +2,7 @@ import javasabr.mqtt.base.utils.DebugUtils; import javasabr.mqtt.network.MqttConnection; -import javasabr.mqtt.network.handler.client.MqttClientReleaseHandler; +import javasabr.mqtt.network.handler.MqttClientReleaseHandler; public class InternalMqttClient extends AbstractMqttClient { diff --git a/network/src/main/java/javasabr/mqtt/network/handler/client/MqttClientReleaseHandler.java b/network/src/main/java/javasabr/mqtt/network/handler/MqttClientReleaseHandler.java similarity index 80% rename from network/src/main/java/javasabr/mqtt/network/handler/client/MqttClientReleaseHandler.java rename to network/src/main/java/javasabr/mqtt/network/handler/MqttClientReleaseHandler.java index cfc5db02..ee6676c7 100644 --- a/network/src/main/java/javasabr/mqtt/network/handler/client/MqttClientReleaseHandler.java +++ b/network/src/main/java/javasabr/mqtt/network/handler/MqttClientReleaseHandler.java @@ -1,4 +1,4 @@ -package javasabr.mqtt.network.handler.client; +package javasabr.mqtt.network.handler; import javasabr.mqtt.network.MqttClient.UnsafeMqttClient; import reactor.core.publisher.Mono; diff --git a/network/src/main/java/javasabr/mqtt/network/handler/packet/in/PacketInHandler.java b/network/src/main/java/javasabr/mqtt/network/handler/PacketInHandler.java similarity index 84% rename from network/src/main/java/javasabr/mqtt/network/handler/packet/in/PacketInHandler.java rename to network/src/main/java/javasabr/mqtt/network/handler/PacketInHandler.java index 01a05d77..76142d15 100644 --- a/network/src/main/java/javasabr/mqtt/network/handler/packet/in/PacketInHandler.java +++ b/network/src/main/java/javasabr/mqtt/network/handler/PacketInHandler.java @@ -1,4 +1,4 @@ -package javasabr.mqtt.network.handler.packet.in; +package javasabr.mqtt.network.handler; import javasabr.mqtt.network.MqttClient.UnsafeMqttClient; import javasabr.mqtt.network.packet.in.MqttReadablePacket; diff --git a/network/src/main/java/javasabr/mqtt/network/handler/publish/PublishInHandler.java b/network/src/main/java/javasabr/mqtt/network/handler/PublishInHandler.java similarity index 84% rename from network/src/main/java/javasabr/mqtt/network/handler/publish/PublishInHandler.java rename to network/src/main/java/javasabr/mqtt/network/handler/PublishInHandler.java index 66f2698f..a4423e02 100644 --- a/network/src/main/java/javasabr/mqtt/network/handler/publish/PublishInHandler.java +++ b/network/src/main/java/javasabr/mqtt/network/handler/PublishInHandler.java @@ -1,4 +1,4 @@ -package javasabr.mqtt.network.handler.publish; +package javasabr.mqtt.network.handler; import javasabr.mqtt.network.MqttClient; import javasabr.mqtt.network.packet.in.PublishInPacket; diff --git a/network/src/main/java/javasabr/mqtt/network/handler/package-info.java b/network/src/main/java/javasabr/mqtt/network/handler/package-info.java new file mode 100644 index 00000000..d766ab68 --- /dev/null +++ b/network/src/main/java/javasabr/mqtt/network/handler/package-info.java @@ -0,0 +1,4 @@ +@NullMarked +package javasabr.mqtt.network.handler; + +import org.jspecify.annotations.NullMarked; \ No newline at end of file diff --git a/network/src/main/java/javasabr/mqtt/network/out/Mqtt311PacketOutFactory.java b/network/src/main/java/javasabr/mqtt/network/out/Mqtt311PacketOutFactory.java index ec006d02..74aa7e7a 100644 --- a/network/src/main/java/javasabr/mqtt/network/out/Mqtt311PacketOutFactory.java +++ b/network/src/main/java/javasabr/mqtt/network/out/Mqtt311PacketOutFactory.java @@ -26,7 +26,6 @@ import javasabr.mqtt.network.packet.out.SubscribeAck311OutPacket; import javasabr.mqtt.network.packet.out.UnsubscribeAck311OutPacket; import javasabr.rlib.collections.array.Array; -import javasabr.rlib.collections.array.MutableArray; public class Mqtt311PacketOutFactory extends MqttPacketOutFactory { @@ -44,7 +43,7 @@ public MqttWritablePacket newConnectAck( String responseInformation, String authenticationMethod, byte[] authenticationData, - MutableArray userProperties) { + Array userProperties) { return new ConnectAck311OutPacket(reasonCode, sessionPresent); } @@ -60,7 +59,7 @@ public PublishOutPacket newPublish( boolean stringPayload, String responseTopic, byte[] correlationData, - MutableArray userProperties) { + Array userProperties) { return new Publish311OutPacket(packetId, qos, retained, duplicate, topicName, payload); } @@ -69,7 +68,7 @@ public MqttWritablePacket newPublishAck( int packetId, PublishAckReasonCode reasonCode, String reason, - MutableArray userProperties) { + Array userProperties) { return new PublishAck311OutPacket(packetId); } @@ -95,7 +94,7 @@ public MqttWritablePacket newUnsubscribeAck( public MqttWritablePacket newDisconnect( MqttClient client, DisconnectReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason, String serverReference) { return new Disconnect311OutPacket(); @@ -106,7 +105,7 @@ public MqttWritablePacket newAuthenticate( AuthenticateReasonCode reasonCode, String authenticateMethod, byte[] authenticateData, - MutableArray userProperties, + Array userProperties, String reason) { throw new UnsupportedOperationException(); } @@ -125,7 +124,7 @@ public MqttWritablePacket newPingResponse() { public MqttWritablePacket newPublishRelease( int packetId, PublishReleaseReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason) { return new PublishRelease311OutPacket(packetId); } @@ -134,7 +133,7 @@ public MqttWritablePacket newPublishRelease( public MqttWritablePacket newPublishReceived( int packetId, PublishReceivedReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason) { return new PublishReceived311OutPacket(packetId); } @@ -143,7 +142,7 @@ public MqttWritablePacket newPublishReceived( public MqttWritablePacket newPublishCompleted( int packetId, PublishCompletedReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason) { return new PublishComplete311OutPacket(packetId); } diff --git a/network/src/main/java/javasabr/mqtt/network/out/Mqtt5PacketOutFactory.java b/network/src/main/java/javasabr/mqtt/network/out/Mqtt5PacketOutFactory.java index 2dba1d66..72d2f15b 100644 --- a/network/src/main/java/javasabr/mqtt/network/out/Mqtt5PacketOutFactory.java +++ b/network/src/main/java/javasabr/mqtt/network/out/Mqtt5PacketOutFactory.java @@ -1,5 +1,6 @@ package javasabr.mqtt.network.out; +import javasabr.mqtt.model.MqttClientConnectionConfig; import javasabr.mqtt.model.QoS; import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.reason.code.AuthenticateReasonCode; @@ -25,7 +26,6 @@ import javasabr.mqtt.network.packet.out.SubscribeAck5OutPacket; import javasabr.mqtt.network.packet.out.UnsubscribeAck5OutPacket; import javasabr.rlib.collections.array.Array; -import javasabr.rlib.collections.array.MutableArray; public class Mqtt5PacketOutFactory extends Mqtt311PacketOutFactory { @@ -37,38 +37,29 @@ public MqttWritablePacket newConnectAck( String requestedClientId, long requestedSessionExpiryInterval, int requestedKeepAlive, - int requestedReceiveMax, + int requestedReceiveMaxPublishes, String reason, String serverReference, String responseInformation, String authenticationMethod, byte[] authenticationData, - MutableArray userProperties) { - var config = client.connectionConfig(); + Array userProperties) { + MqttClientConnectionConfig connectionConfig = client.connectionConfig(); return new ConnectAck5OutPacket( + connectionConfig, reasonCode, sessionPresent, + client.clientId(), requestedClientId, requestedSessionExpiryInterval, requestedKeepAlive, - requestedReceiveMax, + requestedReceiveMaxPublishes, reason, serverReference, responseInformation, authenticationMethod, authenticationData, - userProperties, - client.clientId(), - config.maxQos(), - client.sessionExpiryInterval(), - client.maximumPacketSize(), - client.receiveMax(), - client.topicAliasMaximum(), - client.keepAlive(), - config.retainAvailable(), - config.wildcardSubscriptionAvailable(), - config.subscriptionIdAvailable(), - config.sharedSubscriptionAvailable()); + userProperties); } @Override @@ -83,7 +74,7 @@ public PublishOutPacket newPublish( boolean stringPayload, String responseTopic, byte[] correlationData, - MutableArray userProperties) { + Array userProperties) { return new Publish5OutPacket( packetId, qos, @@ -103,7 +94,7 @@ public MqttWritablePacket newPublishAck( int packetId, PublishAckReasonCode reasonCode, String reason, - MutableArray userProperties) { + Array userProperties) { return new PublishAck5OutPacket(packetId, reasonCode, userProperties, reason); } @@ -129,15 +120,16 @@ public MqttWritablePacket newUnsubscribeAck( public MqttWritablePacket newDisconnect( MqttClient client, DisconnectReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason, String serverReference) { + MqttClientConnectionConfig connectionConfig = client.connectionConfig(); return new Disconnect5OutPacket( reasonCode, userProperties, reason, serverReference, - client.sessionExpiryInterval()); + connectionConfig.sessionExpiryInterval()); } @Override @@ -145,7 +137,7 @@ public MqttWritablePacket newAuthenticate( AuthenticateReasonCode reasonCode, String authenticateMethod, byte[] authenticateData, - MutableArray userProperties, + Array userProperties, String reason) { return new Authentication5OutPacket(userProperties, reasonCode, reason, authenticateMethod, authenticateData); } @@ -154,7 +146,7 @@ public MqttWritablePacket newAuthenticate( public MqttWritablePacket newPublishRelease( int packetId, PublishReleaseReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason) { return new PublishRelease5OutPacket(packetId, reasonCode, userProperties, reason); } @@ -163,7 +155,7 @@ public MqttWritablePacket newPublishRelease( public MqttWritablePacket newPublishReceived( int packetId, PublishReceivedReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason) { return new PublishReceived5OutPacket(packetId, reasonCode, userProperties, reason); } @@ -172,7 +164,7 @@ public MqttWritablePacket newPublishReceived( public MqttWritablePacket newPublishCompleted( int packetId, PublishCompletedReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason) { return new PublishComplete5OutPacket(packetId, reasonCode, userProperties, reason); } diff --git a/network/src/main/java/javasabr/mqtt/network/out/MqttPacketOutFactory.java b/network/src/main/java/javasabr/mqtt/network/out/MqttPacketOutFactory.java index 5ddcc5af..3f687841 100644 --- a/network/src/main/java/javasabr/mqtt/network/out/MqttPacketOutFactory.java +++ b/network/src/main/java/javasabr/mqtt/network/out/MqttPacketOutFactory.java @@ -1,5 +1,6 @@ package javasabr.mqtt.network.out; +import javasabr.mqtt.model.MqttClientConnectionConfig; import javasabr.mqtt.model.QoS; import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.reason.code.AuthenticateReasonCode; @@ -34,7 +35,7 @@ public abstract MqttWritablePacket newConnectAck( String responseInformation, String authenticationMethod, byte[] authenticationData, - MutableArray userProperties); + Array userProperties); public MqttWritablePacket newConnectAck( MqttClient client, @@ -61,14 +62,15 @@ public MqttWritablePacket newConnectAck( } public MqttWritablePacket newConnectAck(MqttClient client, ConnectAckReasonCode reasonCode) { + MqttClientConnectionConfig connectionConfig = client.connectionConfig(); return newConnectAck( client, reasonCode, false, StringUtils.EMPTY, - client.sessionExpiryInterval(), - client.keepAlive(), - client.receiveMax(), + connectionConfig.sessionExpiryInterval(), + connectionConfig.keepAlive(), + connectionConfig.receiveMaxPublishes(), StringUtils.EMPTY, StringUtils.EMPTY, StringUtils.EMPTY, @@ -109,16 +111,16 @@ public abstract PublishOutPacket newPublish( boolean stringPayload, String responseTopic, byte[] correlationData, - MutableArray userProperties); + Array userProperties); public abstract MqttWritablePacket newPublishAck( int packetId, PublishAckReasonCode reasonCode, String reason, - MutableArray userProperties); + Array userProperties); public MqttWritablePacket newPublishAck(int packetId, PublishAckReasonCode reasonCode) { - return newPublishAck(packetId, reasonCode, StringUtils.EMPTY, MutableArray.ofType(StringPair.class)); + return newPublishAck(packetId, reasonCode, StringUtils.EMPTY, Array.empty(StringPair.class)); } public abstract MqttWritablePacket newSubscribeAck( @@ -144,7 +146,7 @@ public MqttWritablePacket newUnsubscribeAck(int packetId, Array userProperties, + Array userProperties, String reason, String serverReference); @@ -152,7 +154,7 @@ public MqttWritablePacket newDisconnect(MqttClient client, DisconnectReasonCode return newDisconnect( client, reasonCode, - MutableArray.ofType(StringPair.class), + Array.empty(StringPair.class), StringUtils.EMPTY, StringUtils.EMPTY); } @@ -161,7 +163,7 @@ public abstract MqttWritablePacket newAuthenticate( AuthenticateReasonCode reasonCode, String authenticateMethod, byte[] authenticateData, - MutableArray userProperties, + Array userProperties, String reason); public MqttWritablePacket newAuthenticate( @@ -172,7 +174,7 @@ public MqttWritablePacket newAuthenticate( reasonCode, authenticateMethod, authenticateData, - MutableArray.ofType(StringPair.class), + Array.empty(StringPair.class), StringUtils.EMPTY); } @@ -183,30 +185,30 @@ public MqttWritablePacket newAuthenticate( public abstract MqttWritablePacket newPublishRelease( int packetId, PublishReleaseReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason); public MqttWritablePacket newPublishRelease(int packetId, PublishReleaseReasonCode reasonCode) { - return newPublishRelease(packetId, reasonCode, MutableArray.ofType(StringPair.class), StringUtils.EMPTY); + return newPublishRelease(packetId, reasonCode, Array.empty(StringPair.class), StringUtils.EMPTY); } public abstract MqttWritablePacket newPublishReceived( int packetId, PublishReceivedReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason); public MqttWritablePacket newPublishReceived(int packetId, PublishReceivedReasonCode reasonCode) { - return newPublishReceived(packetId, reasonCode, MutableArray.ofType(StringPair.class), StringUtils.EMPTY); + return newPublishReceived(packetId, reasonCode, Array.empty(StringPair.class), StringUtils.EMPTY); } public abstract MqttWritablePacket newPublishCompleted( int packetId, PublishCompletedReasonCode reasonCode, - MutableArray userProperties, + Array userProperties, String reason); public MqttWritablePacket newPublishCompleted(int packetId, PublishCompletedReasonCode reasonCode) { - return newPublishCompleted(packetId, reasonCode, MutableArray.ofType(StringPair.class), StringUtils.EMPTY); + return newPublishCompleted(packetId, reasonCode, Array.empty(StringPair.class), StringUtils.EMPTY); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/AuthenticationInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/AuthenticationInPacket.java index e01f55d3..effc7efb 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/AuthenticationInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/AuthenticationInPacket.java @@ -74,7 +74,7 @@ public byte packetType() { @Override protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901219 - reasonCode = AuthenticateReasonCode.of(readUnsignedByte(buffer)); + reasonCode = AuthenticateReasonCode.of(readByteUnsigned(buffer)); } @Override diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/ConnectAckInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/ConnectAckInPacket.java index 2978f199..79ca1492 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/ConnectAckInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/ConnectAckInPacket.java @@ -26,206 +26,206 @@ public class ConnectAckInPacket extends MqttReadablePacket { private static final byte PACKET_TYPE = (byte) PacketType.CONNECT_ACK.ordinal(); private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the Four Byte Integer representing the Session Expiry Interval in seconds. It is a Protocol - Error to include the Session Expiry Interval more than once. + /* + Followed by the Four Byte Integer representing the Session Expiry Interval in seconds. It is a Protocol + Error to include the Session Expiry Interval more than once. - If the Session Expiry Interval is absent the value in the CONNECT Packet used. The server uses this - property to inform the Client that it is using a value other than that sent by the Client in the CONNACK. - */ + If the Session Expiry Interval is absent the value in the CONNECT Packet used. The server uses this + property to inform the Client that it is using a value other than that sent by the Client in the CONNACK. + */ PacketProperty.SESSION_EXPIRY_INTERVAL, - /* - Followed by the Two Byte Integer representing the Receive Maximum value. It is a Protocol Error to - include the Receive Maximum value more than once or for it to have the value 0. - - The Server uses this value to limit the number of QoS 1 and QoS 2 publications that it is willing to - process concurrently for the Client. It does not provide a mechanism to limit the QoS 0 publications that - the Client might try to send. - - If the Receive Maximum value is absent, then its value defaults to 65,535. - */ - PacketProperty.RECEIVE_MAXIMUM, - /* - Followed by a Byte with a value of either 0 or 1. It is a Protocol Error to include Maximum QoS more than - once, or to have a value other than 0 or 1. If the Maximum QoS is absent, the Client uses a Maximum - QoS of 2. - - If a Server does not support QoS 1 or QoS 2 PUBLISH packets it MUST send a Maximum QoS in the - CONNACK packet specifying the highest QoS it supports [MQTT-3.2.2-9]. A Server that does not support - QoS 1 or QoS 2 PUBLISH packets MUST still accept SUBSCRIBE packets containing a Requested QoS - of 0, 1 or 2 [MQTT-3.2.2-10]. - - If a Client receives a Maximum QoS from a Server, it MUST NOT send PUBLISH packets at a QoS level - exceeding the Maximum QoS level specified [MQTT-3.2.2-11]. It is a Protocol Error if the Server receives - a PUBLISH packet with a QoS greater than the Maximum QoS it specified. In this case use - DISCONNECT with Reason Code 0x9B (QoS not supported) as described in section 4.13 Handling - errors. - - If a Server receives a CONNECT packet containing a Will QoS that exceeds its capabilities, it MUST - reject the connection. It SHOULD use a CONNACK packet with Reason Code 0x9B (QoS not supported) - as described in section 4.13 Handling errors, and MUST close the Network Connection - */ + /* + Followed by the Two Byte Integer representing the Receive Maximum value. It is a Protocol Error to + include the Receive Maximum value more than once or for it to have the value 0. + + The Server uses this value to limit the number of QoS 1 and QoS 2 publications that it is willing to + process concurrently for the Client. It does not provide a mechanism to limit the QoS 0 publications that + the Client might try to send. + + If the Receive Maximum value is absent, then its value defaults to 65,535. + */ + PacketProperty.RECEIVE_MAXIMUM_PUBLISH, + /* + Followed by a Byte with a value of either 0 or 1. It is a Protocol Error to include Maximum QoS more than + once, or to have a value other than 0 or 1. If the Maximum QoS is absent, the Client uses a Maximum + QoS of 2. + + If a Server does not support QoS 1 or QoS 2 PUBLISH packets it MUST send a Maximum QoS in the + CONNACK packet specifying the highest QoS it supports [MQTT-3.2.2-9]. A Server that does not support + QoS 1 or QoS 2 PUBLISH packets MUST still accept SUBSCRIBE packets containing a Requested QoS + of 0, 1 or 2 [MQTT-3.2.2-10]. + + If a Client receives a Maximum QoS from a Server, it MUST NOT send PUBLISH packets at a QoS level + exceeding the Maximum QoS level specified [MQTT-3.2.2-11]. It is a Protocol Error if the Server receives + a PUBLISH packet with a QoS greater than the Maximum QoS it specified. In this case use + DISCONNECT with Reason Code 0x9B (QoS not supported) as described in section 4.13 Handling + errors. + + If a Server receives a CONNECT packet containing a Will QoS that exceeds its capabilities, it MUST + reject the connection. It SHOULD use a CONNACK packet with Reason Code 0x9B (QoS not supported) + as described in section 4.13 Handling errors, and MUST close the Network Connection + */ PacketProperty.MAXIMUM_QOS, - /* - Followed by a Byte field. If present, this byte declares whether the Server supports retained messages. A - value of 0 means that retained messages are not supported. A value of 1 means retained messages are - supported. If not present, then retained messages are supported. It is a Protocol Error to include Retain - Available more than once or to use a value other than 0 or 1. - - If a Server receives a CONNECT packet containing a Will Message with the Will Retain set to 1, and it - does not support retained messages, the Server MUST reject the connection request. It SHOULD send - CONNACK with Reason Code 0x9A (Retain not supported) and then it MUST close the Network - Connection [MQTT-3.2.2-13]. - - A Client receiving Retain Available set to 0 from the Server MUST NOT send a PUBLISH packet with the - RETAIN flag set to 1 [MQTT-3.2.2-14]. If the Server receives such a packet, this is a Protocol Error. The - Server SHOULD send a DISCONNECT with Reason Code of 0x9A (Retain not supported) as described - in section 4.13. - */ + /* + Followed by a Byte field. If present, this byte declares whether the Server supports retained messages. A + value of 0 means that retained messages are not supported. A value of 1 means retained messages are + supported. If not present, then retained messages are supported. It is a Protocol Error to include Retain + Available more than once or to use a value other than 0 or 1. + + If a Server receives a CONNECT packet containing a Will Message with the Will Retain set to 1, and it + does not support retained messages, the Server MUST reject the connection request. It SHOULD send + CONNACK with Reason Code 0x9A (Retain not supported) and then it MUST close the Network + Connection [MQTT-3.2.2-13]. + + A Client receiving Retain Available set to 0 from the Server MUST NOT send a PUBLISH packet with the + RETAIN flag set to 1 [MQTT-3.2.2-14]. If the Server receives such a packet, this is a Protocol Error. The + Server SHOULD send a DISCONNECT with Reason Code of 0x9A (Retain not supported) as described + in section 4.13. + */ PacketProperty.RETAIN_AVAILABLE, - /* - Followed by a Four Byte Integer representing the Maximum Packet Size the Server is willing to accept. If - the Maximum Packet Size is not present, there is no limit on the packet size imposed beyond the - limitations in the protocol as a result of the remaining length encoding and the protocol header sizes. - - It is a Protocol Error to include the Maximum Packet Size more than once, or for the value to be set to - zero. - - The packet size is the total number of bytes in an MQTT Control Packet, as defined in section 2.1.4. The - Server uses the Maximum Packet Size to inform the Client that it will not process packets whose size - exceeds this limit. - - The Client MUST NOT send packets exceeding Maximum Packet Size to the Server [MQTT-3.2.2-15]. If - a Server receives a packet whose size exceeds this limit, this is a Protocol Error, the Server uses - DISCONNECT with Reason Code 0x95 (Packet too large), as described in section 4.13. - */ + /* + Followed by a Four Byte Integer representing the Maximum Packet Size the Server is willing to accept. If + the Maximum Packet Size is not present, there is no limit on the packet size imposed beyond the + limitations in the protocol as a result of the remaining length encoding and the protocol header sizes. + + It is a Protocol Error to include the Maximum Packet Size more than once, or for the value to be set to + zero. + + The packet size is the total number of bytes in an MQTT Control Packet, as defined in section 2.1.4. The + Server uses the Maximum Packet Size to inform the Client that it will not process packets whose size + exceeds this limit. + + The Client MUST NOT send packets exceeding Maximum Packet Size to the Server [MQTT-3.2.2-15]. If + a Server receives a packet whose size exceeds this limit, this is a Protocol Error, the Server uses + DISCONNECT with Reason Code 0x95 (Packet too large), as described in section 4.13. + */ PacketProperty.MAXIMUM_PACKET_SIZE, - /* - Followed by the UTF-8 string which is the Assigned Client Identifier. It is a Protocol Error to include the - Assigned Client Identifier more than once. + /* + Followed by the UTF-8 string which is the Assigned Client Identifier. It is a Protocol Error to include the + Assigned Client Identifier more than once. - The Client Identifier which was assigned by the Server because a zero length Client Identifier was found - in the CONNECT packet. + The Client Identifier which was assigned by the Server because a zero length Client Identifier was found + in the CONNECT packet. - If the Client connects using a zero length Client Identifier, the Server MUST respond with a CONNACK - containing an Assigned Client Identifier. The Assigned Client Identifier MUST be a new Client Identifier - not used by any other Session currently in the Server [ - */ + If the Client connects using a zero length Client Identifier, the Server MUST respond with a CONNACK + containing an Assigned Client Identifier. The Assigned Client Identifier MUST be a new Client Identifier + not used by any other Session currently in the Server [ + */ PacketProperty.ASSIGNED_CLIENT_IDENTIFIER, - /* - Followed by the Two Byte Integer representing the Topic Alias Maximum value. It is a Protocol Error to - include the Topic Alias Maximum value more than once. If the Topic Alias Maximum property is absent, - the default value is 0. - - This value indicates the highest value that the Server will accept as a Topic Alias sent by the Client. The - Server uses this value to limit the number of Topic Aliases that it is willing to hold on this Connection. The - Client MUST NOT send a Topic Alias in a PUBLISH packet to the Server greater than this value - [MQTT1296 3.2.2-17]. A value of 0 indicates that the Server does not accept any Topic Aliases - on this connection. If Topic Alias Maximum is absent or 0, the Client MUST NOT send any Topic Aliases on - to the Server - */ + /* + Followed by the Two Byte Integer representing the Topic Alias Maximum value. It is a Protocol Error to + include the Topic Alias Maximum value more than once. If the Topic Alias Maximum property is absent, + the default value is 0. + + This value indicates the highest value that the Server will accept as a Topic Alias sent by the Client. The + Server uses this value to limit the number of Topic Aliases that it is willing to hold on this Connection. The + Client MUST NOT send a Topic Alias in a PUBLISH packet to the Server greater than this value + [MQTT1296 3.2.2-17]. A value of 0 indicates that the Server does not accept any Topic Aliases + on this connection. If Topic Alias Maximum is absent or 0, the Client MUST NOT send any Topic Aliases on + to the Server + */ PacketProperty.TOPIC_ALIAS_MAXIMUM, - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the - Client. - - The Server uses this value to give additional information to the Client. The Server MUST NOT send this - property if it would increase the size of the CONNACK packet beyond the Maximum Packet Size specified - by the Client [MQTT-3.2.2-19]. It is a Protocol Error to include the Reason String more than once. - */ + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the + Client. + + The Server uses this value to give additional information to the Client. The Server MUST NOT send this + property if it would increase the size of the CONNACK packet beyond the Maximum Packet Size specified + by the Client [MQTT-3.2.2-19]. It is a Protocol Error to include the Reason String more than once. + */ PacketProperty.REASON_STRING, - /* - Followed by a UTF-8 String Pair. This property can be used to provide additional information to the Client - including diagnostic information. The Server MUST NOT send this property if it would increase the size of - the CONNACK packet beyond the Maximum Packet Size specified by the Client [MQTT-3.2.2-20]. The - User Property is allowed to appear multiple times to represent multiple name, value pairs. The same - name is allowed to appear more than once. - - The content and meaning of this property is not defined by this specification. The receiver of a CONNACK - containing this property MAY ignore it. - */ + /* + Followed by a UTF-8 String Pair. This property can be used to provide additional information to the Client + including diagnostic information. The Server MUST NOT send this property if it would increase the size of + the CONNACK packet beyond the Maximum Packet Size specified by the Client [MQTT-3.2.2-20]. The + User Property is allowed to appear multiple times to represent multiple name, value pairs. The same + name is allowed to appear more than once. + + The content and meaning of this property is not defined by this specification. The receiver of a CONNACK + containing this property MAY ignore it. + */ PacketProperty.USER_PROPERTY, - /* - Followed by a Byte field. If present, this byte declares whether the Server supports Wildcard - Subscriptions. A value is 0 means that Wildcard Subscriptions are not supported. A value of 1 means - Wildcard Subscriptions are supported. If not present, then Wildcard Subscriptions are supported. It is a - Protocol Error to include the Wildcard Subscription Available more than once or to send a value other - than 0 or 1. - - Standards Track Work Product Copyright © OASIS Open 2019. All Rights Reserved. Page 51 of 137 - - If the Server receives a SUBSCRIBE packet containing a Wildcard Subscription and it does not support - Wildcard Subscriptions, this is a Protocol Error. The Server uses DISCONNECT with Reason Code 0xA2 - (Wildcard Subscriptions not supported) as described in section 4.13. - - If a Server supports Wildcard Subscriptions, it can still reject a particular subscribe request containing a - Wildcard Subscription. In this case the Server MAY send a SUBACK Control Packet with a Reason Code - 0xA2 (Wildcard Subscriptions not supported). - */ + /* + Followed by a Byte field. If present, this byte declares whether the Server supports Wildcard + Subscriptions. A value is 0 means that Wildcard Subscriptions are not supported. A value of 1 means + Wildcard Subscriptions are supported. If not present, then Wildcard Subscriptions are supported. It is a + Protocol Error to include the Wildcard Subscription Available more than once or to send a value other + than 0 or 1. + + Standards Track Work Product Copyright © OASIS Open 2019. All Rights Reserved. Page 51 of 137 + + If the Server receives a SUBSCRIBE packet containing a Wildcard Subscription and it does not support + Wildcard Subscriptions, this is a Protocol Error. The Server uses DISCONNECT with Reason Code 0xA2 + (Wildcard Subscriptions not supported) as described in section 4.13. + + If a Server supports Wildcard Subscriptions, it can still reject a particular subscribe request containing a + Wildcard Subscription. In this case the Server MAY send a SUBACK Control Packet with a Reason Code + 0xA2 (Wildcard Subscriptions not supported). + */ PacketProperty.WILDCARD_SUBSCRIPTION_AVAILABLE, - /* - Followed by a Byte field. If present, this byte declares whether the Server supports Subscription - Identifiers. A value is 0 means that Subscription Identifiers are not supported. A value of 1 means - Subscription Identifiers are supported. If not present, then Subscription Identifiers are supported. It is a - Protocol Error to include the Subscription Identifier Available more than once, or to send a value other - than 0 or 1. - - If the Server receives a SUBSCRIBE packet containing Subscription Identifier and it does not support - Subscription Identifiers, this is a Protocol Error. The Server uses DISCONNECT with Reason Code of - 0xA1 (Subscription Identifiers not supported) as described in section 4.13. - */ + /* + Followed by a Byte field. If present, this byte declares whether the Server supports Subscription + Identifiers. A value is 0 means that Subscription Identifiers are not supported. A value of 1 means + Subscription Identifiers are supported. If not present, then Subscription Identifiers are supported. It is a + Protocol Error to include the Subscription Identifier Available more than once, or to send a value other + than 0 or 1. + + If the Server receives a SUBSCRIBE packet containing Subscription Identifier and it does not support + Subscription Identifiers, this is a Protocol Error. The Server uses DISCONNECT with Reason Code of + 0xA1 (Subscription Identifiers not supported) as described in section 4.13. + */ PacketProperty.SUBSCRIPTION_IDENTIFIER_AVAILABLE, - /* - Followed by a Byte field. If present, this byte declares whether the Server supports Shared Subscriptions. - A value is 0 means that Shared Subscriptions are not supported. A value of 1 means Shared - Subscriptions are supported. If not present, then Shared Subscriptions are supported. It is a Protocol - Error to include the Shared Subscription Available more than once or to send a value other than 0 or 1. - - If the Server receives a SUBSCRIBE packet containing Shared Subscriptions and it does not support - Shared Subscriptions, this is a Protocol Error. The Server uses DISCONNECT with Reason Code 0x9E - (Shared Subscriptions not supported) as described in section 4.13. - */ + /* + Followed by a Byte field. If present, this byte declares whether the Server supports Shared Subscriptions. + A value is 0 means that Shared Subscriptions are not supported. A value of 1 means Shared + Subscriptions are supported. If not present, then Shared Subscriptions are supported. It is a Protocol + Error to include the Shared Subscription Available more than once or to send a value other than 0 or 1. + + If the Server receives a SUBSCRIBE packet containing Shared Subscriptions and it does not support + Shared Subscriptions, this is a Protocol Error. The Server uses DISCONNECT with Reason Code 0x9E + (Shared Subscriptions not supported) as described in section 4.13. + */ PacketProperty.SHARED_SUBSCRIPTION_AVAILABLE, - /* - Followed by a Two Byte Integer with the Keep Alive time assigned by the Server. If the Server sends a - Server Keep Alive on the CONNACK packet, the Client MUST use this value instead of the Keep Alive - value the Client sent on CONNECT [MQTT-3.2.2-21]. If the Server does not send the Server Keep Alive, - the Server MUST use the Keep Alive value set by the Client on CONNECT [MQTT-3.2.2-22]. It is a - Protocol Error to include the Server Keep Alive more than once. - */ + /* + Followed by a Two Byte Integer with the Keep Alive time assigned by the Server. If the Server sends a + Server Keep Alive on the CONNACK packet, the Client MUST use this value instead of the Keep Alive + value the Client sent on CONNECT [MQTT-3.2.2-21]. If the Server does not send the Server Keep Alive, + the Server MUST use the Keep Alive value set by the Client on CONNECT [MQTT-3.2.2-22]. It is a + Protocol Error to include the Server Keep Alive more than once. + */ PacketProperty.SERVER_KEEP_ALIVE, - /* - Followed by a UTF-8 Encoded String which is used as the basis for creating a Response Topic. The way - in which the Client creates a Response Topic from the Response Information is not defined by this - specification. It is a Protocol Error to include the Response Information more than once. - - If the Client sends a Request Response Information with a value 1, it is OPTIONAL for the Server to send - the Response Information in the CONNACK. - */ + /* + Followed by a UTF-8 Encoded String which is used as the basis for creating a Response Topic. The way + in which the Client creates a Response Topic from the Response Information is not defined by this + specification. It is a Protocol Error to include the Response Information more than once. + + If the Client sends a Request Response Information with a value 1, it is OPTIONAL for the Server to send + the Response Information in the CONNACK. + */ PacketProperty.RESPONSE_INFORMATION, - /* - Followed by a UTF-8 Encoded String which can be used by the Client to identify another Server to use. It - is a Protocol Error to include the Server Reference more than once. + /* + Followed by a UTF-8 Encoded String which can be used by the Client to identify another Server to use. It + is a Protocol Error to include the Server Reference more than once. - The Server uses a Server Reference in either a CONNACK or DISCONNECT packet with Reason code - of 0x9C (Use another server) or Reason Code 0x9D (Server moved) as described in section 4.13. + The Server uses a Server Reference in either a CONNACK or DISCONNECT packet with Reason code + of 0x9C (Use another server) or Reason Code 0x9D (Server moved) as described in section 4.13. - Refer to section 4.11 Server redirection for information about how Server Reference is used - */ + Refer to section 4.11 Server redirection for information about how Server Reference is used + */ PacketProperty.SERVER_REFERENCE, - /* - Followed by a UTF-8 Encoded String containing the name of the authentication method. It is a Protocol - Error to include the Authentication Method more than once. Refer to section 4.12 for more information - about extended authentication. - */ + /* + Followed by a UTF-8 Encoded String containing the name of the authentication method. It is a Protocol + Error to include the Authentication Method more than once. Refer to section 4.12 for more information + about extended authentication. + */ PacketProperty.AUTHENTICATION_METHOD, - /* - Followed by Binary Data containing authentication data. The contents of this data are defined by the - authentication method and the state of already exchanged authentication data. It is a Protocol Error to - include the Authentication Data more than once. Refer to section 4.12 for more information about - extended authentication. - */ + /* + Followed by Binary Data containing authentication data. The contents of this data are defined by the + authentication method and the state of already exchanged authentication data. It is a Protocol Error to + include the Authentication Data more than once. Refer to section 4.12 for more information about + extended authentication. + */ PacketProperty.AUTHENTICATION_DATA); /** @@ -255,9 +255,9 @@ public class ConnectAckInPacket extends MqttReadablePacket { private long sessionExpiryInterval; - private int receiveMax; - private int maximumPacketSize; - private int topicAliasMaximum; + private int receiveMaxPublishes; + private int maxPacketSize; + private int topicAliasMaxValue; private int serverKeepAlive; private boolean retainAvailable; @@ -281,10 +281,10 @@ public ConnectAckInPacket(byte info) { this.authenticationMethod = StringUtils.EMPTY; this.authenticationData = ArrayUtils.EMPTY_BYTE_ARRAY; this.serverKeepAlive = MqttProperties.SERVER_KEEP_ALIVE_UNDEFINED; - this.maximumPacketSize = MqttProperties.MAXIMUM_PACKET_SIZE_UNDEFINED; + this.maxPacketSize = MqttProperties.MAXIMUM_PACKET_SIZE_UNDEFINED; this.sessionExpiryInterval = MqttProperties.SESSION_EXPIRY_INTERVAL_UNDEFINED; - this.topicAliasMaximum = MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED; - this.receiveMax = MqttProperties.RECEIVE_MAXIMUM_UNDEFINED; + this.topicAliasMaxValue = MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED; + this.receiveMaxPublishes = MqttProperties.RECEIVE_MAXIMUM_UNDEFINED; } @Override @@ -296,8 +296,8 @@ public byte packetType() { protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718035 - sessionPresent = readUnsignedByte(buffer) == 1; - reasonCode = ConnectAckReasonCode.of(connection.isSupported(MqttVersion.MQTT_5), readUnsignedByte(buffer)); + sessionPresent = readByteUnsigned(buffer) == 1; + reasonCode = ConnectAckReasonCode.of(connection.isSupported(MqttVersion.MQTT_5), readByteUnsigned(buffer)); } @Override @@ -308,87 +308,106 @@ protected Set getAvailableProperties() { @Override protected void applyProperty(PacketProperty property, byte[] value) { switch (property) { - case AUTHENTICATION_DATA: + case AUTHENTICATION_DATA: { authenticationData = value; break; - default: + } + default: { unexpectedProperty(property); + } } } @Override protected void applyProperty(PacketProperty property, String value) { switch (property) { - case REASON_STRING: + case REASON_STRING: { reason = value; break; - case ASSIGNED_CLIENT_IDENTIFIER: + } + case ASSIGNED_CLIENT_IDENTIFIER: { assignedClientId = value; break; - case RESPONSE_INFORMATION: + } + case RESPONSE_INFORMATION: { responseInformation = value; break; - case AUTHENTICATION_METHOD: + } + case AUTHENTICATION_METHOD: { authenticationMethod = value; break; - case SERVER_REFERENCE: + } + case SERVER_REFERENCE: { serverReference = value; break; - default: + } + default: { unexpectedProperty(property); + } } } @Override protected void applyProperty(PacketProperty property, long value) { switch (property) { - case WILDCARD_SUBSCRIPTION_AVAILABLE: + case WILDCARD_SUBSCRIPTION_AVAILABLE: { wildcardSubscriptionAvailable = NumberUtils.toBoolean(value); break; - case SHARED_SUBSCRIPTION_AVAILABLE: + } + case SHARED_SUBSCRIPTION_AVAILABLE: { sharedSubscriptionAvailable = NumberUtils.toBoolean(value); break; - case SUBSCRIPTION_IDENTIFIER_AVAILABLE: + } + case SUBSCRIPTION_IDENTIFIER_AVAILABLE: { subscriptionIdAvailable = NumberUtils.toBoolean(value); break; - case RETAIN_AVAILABLE: + } + case RETAIN_AVAILABLE: { retainAvailable = NumberUtils.toBoolean(value); break; - case RECEIVE_MAXIMUM: - receiveMax = (int) NumberUtils.validate( + } + case RECEIVE_MAXIMUM_PUBLISH: { + receiveMaxPublishes = (int) NumberUtils.validate( value, MqttProperties.RECEIVE_MAXIMUM_MIN, MqttProperties.RECEIVE_MAXIMUM_MAX); break; - case MAXIMUM_QOS: + } + case MAXIMUM_QOS: { maximumQos = QoS.of((int) value); break; - case SERVER_KEEP_ALIVE: + } + case SERVER_KEEP_ALIVE: { serverKeepAlive = NumberUtils.validate( (int) value, MqttProperties.SERVER_KEEP_ALIVE_MIN, MqttProperties.SERVER_KEEP_ALIVE_MAX); break; - case TOPIC_ALIAS_MAXIMUM: - topicAliasMaximum = NumberUtils.validate( + } + case TOPIC_ALIAS_MAXIMUM: { + topicAliasMaxValue = NumberUtils.validate( (int) value, MqttProperties.TOPIC_ALIAS_MIN, MqttProperties.TOPIC_ALIAS_MAX); break; - case SESSION_EXPIRY_INTERVAL: + } + case SESSION_EXPIRY_INTERVAL: { sessionExpiryInterval = NumberUtils.validate( value, MqttProperties.SESSION_EXPIRY_INTERVAL_MIN, MqttProperties.SESSION_EXPIRY_INTERVAL_INFINITY); break; - case MAXIMUM_PACKET_SIZE: - maximumPacketSize = NumberUtils.validate( + } + case MAXIMUM_PACKET_SIZE: { + maxPacketSize = NumberUtils.validate( (int) value, MqttProperties.MAXIMUM_PACKET_SIZE_MIN, MqttProperties.MAXIMUM_PACKET_SIZE_MAX); break; - default: + } + default: { unexpectedProperty(property); + } } } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/ConnectInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/ConnectInPacket.java index f78b9db3..793ed6a2 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/ConnectInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/ConnectInPacket.java @@ -7,21 +7,24 @@ import javasabr.mqtt.model.MqttProperties; import javasabr.mqtt.model.MqttVersion; import javasabr.mqtt.model.PacketProperty; -import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.exception.ConnectionRejectException; import javasabr.mqtt.model.reason.code.ConnectAckReasonCode; import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.packet.PacketType; -import javasabr.rlib.collections.array.MutableArray; import javasabr.rlib.common.util.ArrayUtils; import javasabr.rlib.common.util.NumberUtils; import javasabr.rlib.common.util.StringUtils; +import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; /** * Connection request. */ @Getter +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PRIVATE) public class ConnectInPacket extends MqttReadablePacket { private static final byte PACKET_TYPE = (byte) PacketType.CONNECT.ordinal(); @@ -31,210 +34,195 @@ public class ConnectInPacket extends MqttReadablePacket { } private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - If the Session Expiry Interval is absent the value 0 is used. If it is set to 0, - or is absent, the Session ends when the Network Connection is closed. - If the Session Expiry Interval is 0xFFFFFFFF (UINT_MAX), the Session does not expire. - - The Client and Server MUST store the Session State after the Network Connection is closed if the - Session Expiry Interval is greater than 0 - */ + /* + If the Session Expiry Interval is absent the value 0 is used. If it is set to 0, + or is absent, the Session ends when the Network Connection is closed. + If the Session Expiry Interval is 0xFFFFFFFF (UINT_MAX), the Session does not expire. + + The Client and Server MUST store the Session State after the Network Connection is closed if the + Session Expiry Interval is greater than 0 + */ PacketProperty.SESSION_EXPIRY_INTERVAL, - /* - Followed by the Two Byte Integer representing the Receive Maximum value. It is a Protocol Error to - include the Receive Maximum value more than once or for it to have the value 0. - - The Client uses this value to limit the number of QoS 1 and QoS 2 publications that it is willing to process - concurrently. There is no mechanism to limit the QoS 0 publications that the Server might try to send. - - The value of Receive Maximum applies only to the current Network Connection. If the Receive Maximum - value is absent then its value defaults to 65,535. - */ - PacketProperty.RECEIVE_MAXIMUM, - /* - Followed by a Four Byte Integer representing the Maximum Packet Size the Client is willing to accept. If - the Maximum Packet Size is not present, no limit on the packet size is imposed beyond the limitations in - the protocol as a result of the remaining length encoding and the protocol header sizes. - - It is a Protocol Error to include the Maximum Packet Size more than once, or for the value to be set to - zero. - */ + /* + Followed by the Two Byte Integer representing the Receive Maximum value. It is a Protocol Error to + include the Receive Maximum value more than once or for it to have the value 0. + + The Client uses this value to limit the number of QoS 1 and QoS 2 publications that it is willing to process + concurrently. There is no mechanism to limit the QoS 0 publications that the Server might try to send. + + The value of Receive Maximum applies only to the current Network Connection. If the Receive Maximum + value is absent then its value defaults to 65,535. + */ + PacketProperty.RECEIVE_MAXIMUM_PUBLISH, + /* + Followed by a Four Byte Integer representing the Maximum Packet Size the Client is willing to accept. If + the Maximum Packet Size is not present, no limit on the packet size is imposed beyond the limitations in + the protocol as a result of the remaining length encoding and the protocol header sizes. + + It is a Protocol Error to include the Maximum Packet Size more than once, or for the value to be set to + zero. + */ PacketProperty.MAXIMUM_PACKET_SIZE, - /* - Followed by the Two Byte Integer representing the Topic Alias Maximum value. It is a Protocol Error to - include the Topic Alias Maximum value more than once. If the Topic Alias Maximum property is absent, - the default value is 0. - - This value indicates the highest value that the Client will accept as a Topic Alias sent by the Server. The - Client uses this value to limit the number of Topic Aliases that it is willing to hold on this Connection. The - Server MUST NOT send a Topic Alias in a PUBLISH packet to the Client greater than Topic Alias - Maximum [MQTT-3.1.2-26]. A value of 0 indicates that the Client does not accept any Topic Aliases on - this connection. If Topic Alias Maximum is absent or zero, the Server MUST NOT send any Topic Aliases - to the Client [MQTT-3.1.2-27]. - */ + /* + Followed by the Two Byte Integer representing the Topic Alias Maximum value. It is a Protocol Error to + include the Topic Alias Maximum value more than once. If the Topic Alias Maximum property is absent, + the default value is 0. + + This value indicates the highest value that the Client will accept as a Topic Alias sent by the Server. The + Client uses this value to limit the number of Topic Aliases that it is willing to hold on this Connection. The + Server MUST NOT send a Topic Alias in a PUBLISH packet to the Client greater than Topic Alias + Maximum [MQTT-3.1.2-26]. A value of 0 indicates that the Client does not accept any Topic Aliases on + this connection. If Topic Alias Maximum is absent or zero, the Server MUST NOT send any Topic Aliases + to the Client [MQTT-3.1.2-27]. + */ PacketProperty.TOPIC_ALIAS_MAXIMUM, - /* - Followed by a Byte with a value of either 0 or 1. It is Protocol Error to include the Request Response - Information more than once, or to have a value other than 0 or 1. If the Request Response Information is - absent, the value of 0 is used. - - The Client uses this value to request the Server to return Response Information in the CONNACK. A - value of 0 indicates that the Server MUST NOT return Response Information [MQTT-3.1.2-28]. If the - value is 1 the Server MAY return Response Information in the CONNACK packet. - */ + /* + Followed by a Byte with a value of either 0 or 1. It is Protocol Error to include the Request Response + Information more than once, or to have a value other than 0 or 1. If the Request Response Information is + absent, the value of 0 is used. + + The Client uses this value to request the Server to return Response Information in the CONNACK. A + value of 0 indicates that the Server MUST NOT return Response Information [MQTT-3.1.2-28]. If the + value is 1 the Server MAY return Response Information in the CONNACK packet. + */ PacketProperty.REQUEST_RESPONSE_INFORMATION, - /* - Followed by a Byte with a value of either 0 or 1. It is a Protocol Error to include Request Problem - Information more than once, or to have a value other than 0 or 1. If the Request Problem Information is - 8absent, the value of 1 is used. - - The Client uses this value to indicate whether the Reason String or User Properties are sent in the case - of failures. - - If the value of Request Problem Information is 0, the Server MAY return a Reason String or User - Properties on a CONNACK or DISCONNECT packet, but MUST NOT send a Reason String or User - Properties on any packet other than PUBLISH, CONNACK, or DISCONNECT [MQTT-3.1.2-29]. If the - value is 0 and the Client receives a Reason String or User Properties in a packet other than PUBLISH, - CONNACK, or DISCONNECT, it uses a DISCONNECT packet with Reason Code 0x82 (Protocol Error) - as described in section 4.13 Handling errors. - - If this value is 1, the Server MAY return a Reason String or User Properties on any packet where it is - allowed. - */ + /* + Followed by a Byte with a value of either 0 or 1. It is a Protocol Error to include Request Problem + Information more than once, or to have a value other than 0 or 1. If the Request Problem Information is + 8absent, the value of 1 is used. + + The Client uses this value to indicate whether the Reason String or User Properties are sent in the case + of failures. + + If the value of Request Problem Information is 0, the Server MAY return a Reason String or User + Properties on a CONNACK or DISCONNECT packet, but MUST NOT send a Reason String or User + Properties on any packet other than PUBLISH, CONNACK, or DISCONNECT [MQTT-3.1.2-29]. If the + value is 0 and the Client receives a Reason String or User Properties in a packet other than PUBLISH, + CONNACK, or DISCONNECT, it uses a DISCONNECT packet with Reason Code 0x82 (Protocol Error) + as described in section 4.13 Handling errors. + + If this value is 1, the Server MAY return a Reason String or User Properties on any packet where it is + allowed. + */ PacketProperty.REQUEST_PROBLEM_INFORMATION, - /* - The User Property is allowed to appear multiple times to represent multiple name, value pairs. The same - name is allowed to appear more than once - */ + /* + The User Property is allowed to appear multiple times to represent multiple name, value pairs. The same + name is allowed to appear more than once + */ PacketProperty.USER_PROPERTY, - /* - Followed by a UTF-8 Encoded String containing the name of the authentication method used for - extended authentication .It is a Protocol Error to include Authentication Method more than once. - If Authentication Method is absent, extended authentication is not performed. Refer to section 4.12. - - If a Client sets an Authentication Method in the CONNECT, the Client MUST NOT send any packets other - than AUTH or DISCONNECT packets until it has received a CONNACK packet - */ + /* + Followed by a UTF-8 Encoded String containing the name of the authentication method used for + extended authentication .It is a Protocol Error to include Authentication Method more than once. + If Authentication Method is absent, extended authentication is not performed. Refer to section 4.12. + + If a Client sets an Authentication Method in the CONNECT, the Client MUST NOT send any packets other + than AUTH or DISCONNECT packets until it has received a CONNACK packet + */ PacketProperty.AUTHENTICATION_METHOD, - /* - Followed by Binary Data containing authentication data. It is a Protocol Error to include Authentication - Data if there is no Authentication Method. It is a Protocol Error to include Authentication Data more than - once. - - The contents of this data are defined by the authentication method. Refer to section 4.12 for more - information about extended authentication. - */ + /* + Followed by Binary Data containing authentication data. It is a Protocol Error to include Authentication + Data if there is no Authentication Method. It is a Protocol Error to include Authentication Data more than + once. + + The contents of this data are defined by the authentication method. Refer to section 4.12 for more + information about extended authentication. + */ PacketProperty.AUTHENTICATION_DATA); private static final Set WILL_PROPERTIES = EnumSet.of( - /* - Followed by the Four Byte Integer representing the Will Delay Interval in seconds. It is a Protocol Error to - include the Will Delay Interval more than once. If the Will Delay Interval is absent, the default value is 0 - and there is no delay before the Will Message is published. - - The Server delays publishing the Client’s Will Message until the Will Delay Interval has passed or the - Session ends, whichever happens first. If a new Network Connection to this Session is made before the - Will Delay Interval has passed, the Server MUST NOT send the Will Message - */ + /* + Followed by the Four Byte Integer representing the Will Delay Interval in seconds. It is a Protocol Error to + include the Will Delay Interval more than once. If the Will Delay Interval is absent, the default value is 0 + and there is no delay before the Will Message is published. + + The Server delays publishing the Client’s Will Message until the Will Delay Interval has passed or the + Session ends, whichever happens first. If a new Network Connection to this Session is made before the + Will Delay Interval has passed, the Server MUST NOT send the Will Message + */ PacketProperty.WILL_DELAY_INTERVAL, - /* - Followed by the value of the Payload Format Indicator, either of: - • 0 (0x00) Byte Indicates that the Will Message is unspecified bytes, which is equivalent to not - sending a Payload Format Indicator. - • 1 (0x01) Byte Indicates that the Will Message is UTF-8 Encoded Character Data. The UTF-8 data - in the Payload MUST be well-formed UTF-8 as defined by the Unicode specification - [Unicode] and restated in RFC 3629 [RFC3629]. - - It is a Protocol Error to include the Payload Format Indicator more than once. The Server MAY validate - that the Will Message is of the format indicated, and if it is not se - */ + /* + Followed by the value of the Payload Format Indicator, either of: + • 0 (0x00) Byte Indicates that the Will Message is unspecified bytes, which is equivalent to not + sending a Payload Format Indicator. + • 1 (0x01) Byte Indicates that the Will Message is UTF-8 Encoded Character Data. The UTF-8 data + in the Payload MUST be well-formed UTF-8 as defined by the Unicode specification + [Unicode] and restated in RFC 3629 [RFC3629]. + + It is a Protocol Error to include the Payload Format Indicator more than once. The Server MAY validate + that the Will Message is of the format indicated, and if it is not se + */ PacketProperty.PAYLOAD_FORMAT_INDICATOR, - /* - Followed by the Four Byte Integer representing the Message Expiry Interval. It is a Protocol Error to - include the Message Expiry Interval more than once. + /* + Followed by the Four Byte Integer representing the Message Expiry Interval. It is a Protocol Error to + include the Message Expiry Interval more than once. - If present, the Four Byte value is the lifetime of the Will Message in seconds and is sent as the - Publication Expiry Interval when the Server publishes the Will Message. + If present, the Four Byte value is the lifetime of the Will Message in seconds and is sent as the + Publication Expiry Interval when the Server publishes the Will Message. - If absent, no Message Expiry Interval is sent when the Server publishes the Will Message. - */ + If absent, no Message Expiry Interval is sent when the Server publishes the Will Message. + */ PacketProperty.MESSAGE_EXPIRY_INTERVAL, - /* - Followed by a UTF-8 Encoded String describing the content of the Will Message. It is a Protocol Error to - include the Content Type more than once. The value of the Content Type is defined by the sending and - receiving application. - */ + /* + Followed by a UTF-8 Encoded String describing the content of the Will Message. It is a Protocol Error to + include the Content Type more than once. The value of the Content Type is defined by the sending and + receiving application. + */ PacketProperty.CONTENT_TYPE, - /* - Followed by a UTF-8 Encoded String which is used as the Topic Name for a response message. It is a - Protocol Error to include the Response Topic more than once. The presence of a Response Topic - identifies the Will Message as a Request. - */ + /* + Followed by a UTF-8 Encoded String which is used as the Topic Name for a response message. It is a + Protocol Error to include the Response Topic more than once. The presence of a Response Topic + identifies the Will Message as a Request. + */ PacketProperty.RESPONSE_TOPIC, - /* - Followed by Binary Data. The Correlation Data is used by the sender of the Request Message to identify - which request the Response Message is for when it is received. It is a Protocol Error to include - Correlation Data more than once. If the Correlation Data is not present, the Requester does not require - any correlation data. - - The value of the Correlation Data only has meaning to the sender of the Request Message and receiver - of the Response Message. - */ + /* + Followed by Binary Data. The Correlation Data is used by the sender of the Request Message to identify + which request the Response Message is for when it is received. It is a Protocol Error to include + Correlation Data more than once. If the Correlation Data is not present, the Requester does not require + any correlation data. + + The value of the Correlation Data only has meaning to the sender of the Request Message and receiver + of the Response Message. + */ PacketProperty.CORRELATION_DATA, - /* - Followed by a UTF-8 String Pair. The User Property is allowed to appear multiple times to represent - multiple name, value pairs. The same name is allowed to appear more than once. + /* + Followed by a UTF-8 String Pair. The User Property is allowed to appear multiple times to represent + multiple name, value pairs. The same name is allowed to appear more than once. - The Server MUST maintain the order of User Properties when publishing the Will Message - */ + The Server MUST maintain the order of User Properties when publishing the Will Message + */ PacketProperty.USER_PROPERTY); - private MqttVersion mqttVersion; + MqttVersion mqttVersion = MqttVersion.MQTT_3_1_1; - private String clientId; - private String willTopic; - private String username; - private byte[] password; + String clientId = StringUtils.EMPTY; + String willTopic = StringUtils.EMPTY; + byte[] willPayload = ArrayUtils.EMPTY_BYTE_ARRAY; - private byte[] willPayload; + String username = StringUtils.EMPTY; + byte[] password = ArrayUtils.EMPTY_BYTE_ARRAY; - private int keepAlive; - private int willQos; - private boolean willRetain; - private boolean cleanStart; + int keepAlive; + int willQos; + boolean willRetain; + boolean cleanStart; - private boolean hasUserName; - private boolean hasPassword; - private boolean willFlag; + boolean hasUserName; + boolean hasPassword; + boolean willFlag; // properties - private String authenticationMethod; - private byte[] authenticationData; + String authenticationMethod = StringUtils.EMPTY; + byte[] authenticationData = ArrayUtils.EMPTY_BYTE_ARRAY; - private long sessionExpiryInterval; - private int receiveMax; - private int maximumPacketSize; - private int topicAliasMaximum; - private boolean requestResponseInformation; - private boolean requestProblemInformation; + long sessionExpiryInterval = MqttProperties.SESSION_EXPIRY_INTERVAL_UNDEFINED; + int receiveMaxPublishes = MqttProperties.RECEIVE_MAXIMUM_UNDEFINED; + int maxPacketSize = MqttProperties.MAXIMUM_PACKET_SIZE_UNDEFINED; + int topicAliasMaxValue = MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED; + boolean requestResponseInformation = false; + boolean requestProblemInformation = false; public ConnectInPacket(byte info) { super(info); - this.userProperties = MutableArray.ofType(StringPair.class); - this.mqttVersion = MqttVersion.MQTT_3_1_1; - this.clientId = StringUtils.EMPTY; - this.willTopic = StringUtils.EMPTY; - this.username = StringUtils.EMPTY; - this.password = ArrayUtils.EMPTY_BYTE_ARRAY; - this.authenticationMethod = StringUtils.EMPTY; - this.willPayload = ArrayUtils.EMPTY_BYTE_ARRAY; - this.authenticationData = ArrayUtils.EMPTY_BYTE_ARRAY; - this.sessionExpiryInterval = MqttProperties.SESSION_EXPIRY_INTERVAL_UNDEFINED; - this.receiveMax = MqttProperties.RECEIVE_MAXIMUM_UNDEFINED; - this.maximumPacketSize = MqttProperties.MAXIMUM_PACKET_SIZE_UNDEFINED; - this.topicAliasMaximum = MqttProperties.TOPIC_ALIAS_MAXIMUM_UNDEFINED; - this.requestResponseInformation = false; - this.requestProblemInformation = false; } @Override @@ -244,35 +232,43 @@ public byte packetType() { @Override protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { + var connectionConfig = connection.serverConnectionConfig(); // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718030 - var protocolName = readString(buffer, Integer.MAX_VALUE); - var protocolLevel = buffer.get(); + String protocolName = readString(buffer, connectionConfig.maxStringLength()); + byte protocolLevel = buffer.get(); mqttVersion = MqttVersion.of(protocolName, protocolLevel); - if (mqttVersion == MqttVersion.UNKNOWN) { throw new ConnectionRejectException(ConnectAckReasonCode.UNSUPPORTED_PROTOCOL_VERSION); } - var flags = readUnsignedByte(buffer); - + int flags = readByteUnsigned(buffer); + /* + Used to indicate whether the will message is a retained message. + */ willRetain = NumberUtils.isSetBit(flags, 5); + /* + Used to indicate the QoS of the will message. + */ willQos = (flags & 0x18) >> 3; + /* + Used to indicate whether the current connection is a new session or + a continuation of an existing session, which determines whether the server will directly + create a new session or attempt to reuse an existing session. + */ cleanStart = NumberUtils.isSetBit(flags, 1); // for mqtt 3.1.1+ if (mqttVersion.ordinal() >= MqttVersion.MQTT_3_1_1.ordinal()) { - - var zeroReservedFlag = NumberUtils.isNotSetBit(flags, 0); - + boolean zeroReservedFlag = NumberUtils.isNotSetBit(flags, 0); if (!zeroReservedFlag) { - /* - The Server MUST validate that the reserved flag in the CONNECT packet is set to 0 [MQTT-3.1.2-3]. If - the reserved flag is not 0 it is a Malformed Packet. Refer to section 4.13 for information about - handling - errors. - */ + /* + The Server MUST validate that the reserved flag in the CONNECT packet is set to 0 [MQTT-3.1.2-3]. If + the reserved flag is not 0 it is a Malformed Packet. Refer to section 4.13 for information about + handling + errors. + */ throw new ConnectionRejectException(ConnectAckReasonCode.MALFORMED_PACKET); } } @@ -285,35 +281,43 @@ protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) throw new ConnectionRejectException(ConnectAckReasonCode.BAD_USER_NAME_OR_PASSWORD); } + /* + Used to indicate whether the Payload contains relevant fields of the will message. + */ willFlag = NumberUtils.isSetBit(flags, 2); - keepAlive = readUnsignedShort(buffer); + + /* + This is a double-byte length unsigned integer used to indicate the maximum + time interval between two adjacent control packets sent by the client. + */ + keepAlive = readShortUnsigned(buffer); } @Override protected void readPayload(MqttConnection connection, ByteBuffer buffer) { + var connectionConfig = connection.serverConnectionConfig(); + /* + The ClientID MUST be present and is the first field in the CONNECT packet Payload + The ClientID MUST be a UTF-8 Encoded String as defined in - /* - The ClientID MUST be present and is the first field in the CONNECT packet Payload - The ClientID MUST be a UTF-8 Encoded String as defined in + The Server MUST allow ClientID’s which are between 1 and 23 UTF-8 encoded bytes in length, and that + contain only the characters 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" - The Server MUST allow ClientID’s which are between 1 and 23 UTF-8 encoded bytes in length, and that - contain only the characters 0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" + The Server MAY allow ClientID’s that contain more than 23 encoded bytes. The Server MAY allow + ClientID’s that contain characters not included in the list given above. - The Server MAY allow ClientID’s that contain more than 23 encoded bytes. The Server MAY allow - ClientID’s that contain characters not included in the list given above. + A Server MAY allow a Client to supply a ClientID that has a length of zero bytes, however if it does so the + Server MUST treat this as a special case and assign a unique ClientID to that Client. It + MUST then process the CONNECT packet as if the Client had provided that unique ClientID, and MUST + return the Assigned Client Identifier in the CONNACK packet - A Server MAY allow a Client to supply a ClientID that has a length of zero bytes, however if it does so the - Server MUST treat this as a special case and assign a unique ClientID to that Client. It - MUST then process the CONNECT packet as if the Client had provided that unique ClientID, and MUST - return the Assigned Client Identifier in the CONNACK packet - - If the Server rejects the ClientID it MAY respond to the CONNECT packet with a CONNACK using - Reason Code 0x85 (Client Identifier not valid) and then it MUST close the Network Connection - */ + If the Server rejects the ClientID it MAY respond to the CONNECT packet with a CONNACK using + Reason Code 0x85 (Client Identifier not valid) and then it MUST close the Network Connection + */ clientId = readString(buffer, Integer.MAX_VALUE); if (willFlag && mqttVersion.ordinal() >= MqttVersion.MQTT_5.ordinal()) { - readProperties(buffer, WILL_PROPERTIES); + readProperties(connection, buffer, WILL_PROPERTIES); } if (willFlag) { @@ -321,7 +325,7 @@ protected void readPayload(MqttConnection connection, ByteBuffer buffer) { } if (willFlag) { - willPayload = readBytes(buffer); + willPayload = readBytes(buffer, connectionConfig.maxBinarySize()); } if (hasUserName) { @@ -329,7 +333,7 @@ protected void readPayload(MqttConnection connection, ByteBuffer buffer) { } if (hasPassword) { - password = readBytes(buffer); + password = readBytes(buffer, connectionConfig.maxBinarySize()); } } @@ -346,60 +350,71 @@ protected Set getAvailableProperties() { @Override protected void applyProperty(PacketProperty property, byte[] value) { switch (property) { - case AUTHENTICATION_DATA: + case AUTHENTICATION_DATA: { authenticationData = value; break; - default: + } + default: { unexpectedProperty(property); + } } } @Override protected void applyProperty(PacketProperty property, String value) { switch (property) { - case AUTHENTICATION_METHOD: + case AUTHENTICATION_METHOD: { authenticationMethod = value; break; - default: + } + default: { unexpectedProperty(property); + } } } @Override protected void applyProperty(PacketProperty property, long value) { switch (property) { - case REQUEST_RESPONSE_INFORMATION: + case REQUEST_RESPONSE_INFORMATION: { requestResponseInformation = NumberUtils.toBoolean(value); break; - case REQUEST_PROBLEM_INFORMATION: + } + case REQUEST_PROBLEM_INFORMATION: { requestProblemInformation = NumberUtils.toBoolean(value); break; - case RECEIVE_MAXIMUM: - receiveMax = NumberUtils.validate( + } + case RECEIVE_MAXIMUM_PUBLISH: { + receiveMaxPublishes = NumberUtils.validate( (int) value, MqttProperties.RECEIVE_MAXIMUM_MIN, MqttProperties.RECEIVE_MAXIMUM_MAX); break; - case TOPIC_ALIAS_MAXIMUM: - topicAliasMaximum = NumberUtils.validate( + } + case TOPIC_ALIAS_MAXIMUM: { + topicAliasMaxValue = NumberUtils.validate( (int) value, MqttProperties.TOPIC_ALIAS_MIN, MqttProperties.TOPIC_ALIAS_MAX); break; - case SESSION_EXPIRY_INTERVAL: + } + case SESSION_EXPIRY_INTERVAL: { sessionExpiryInterval = NumberUtils.validate( value, MqttProperties.SESSION_EXPIRY_INTERVAL_MIN, MqttProperties.SESSION_EXPIRY_INTERVAL_INFINITY); break; - case MAXIMUM_PACKET_SIZE: - maximumPacketSize = NumberUtils.validate( + } + case MAXIMUM_PACKET_SIZE: { + maxPacketSize = NumberUtils.validate( (int) value, MqttProperties.MAXIMUM_PACKET_SIZE_MIN, MqttProperties.MAXIMUM_PACKET_SIZE_MAX); break; - default: + } + default: { unexpectedProperty(property); + } } } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/DisconnectInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/DisconnectInPacket.java index 8b801408..ae82806d 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/DisconnectInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/DisconnectInPacket.java @@ -81,17 +81,16 @@ public byte packetType() { @Override protected void readImpl(MqttConnection connection, ByteBuffer buffer) { this.sessionExpiryInterval = connection - .client() + .clientConnectionConfig() .sessionExpiryInterval(); super.readImpl(connection, buffer); } @Override protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { - // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901207 if (connection.isSupported(MqttVersion.MQTT_5) && buffer.hasRemaining()) { - reasonCode = DisconnectReasonCode.of(readUnsignedByte(buffer)); + reasonCode = DisconnectReasonCode.of(readByteUnsigned(buffer)); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/MqttReadablePacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/MqttReadablePacket.java index 5c0e6df5..029e1691 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/MqttReadablePacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/MqttReadablePacket.java @@ -3,11 +3,13 @@ import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.CharsetDecoder; +import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import java.nio.charset.StandardCharsets; import java.util.Collections; import java.util.Set; import javasabr.mqtt.base.utils.DebugUtils; +import javasabr.mqtt.model.MqttServerConnectionConfig; import javasabr.mqtt.model.MqttVersion; import javasabr.mqtt.model.PacketProperty; import javasabr.mqtt.model.data.type.StringPair; @@ -17,28 +19,27 @@ import javasabr.mqtt.model.reason.code.ConnectAckReasonCode; import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.utils.MqttDataUtils; +import javasabr.rlib.collections.array.Array; import javasabr.rlib.collections.array.MutableArray; import javasabr.rlib.common.util.ArrayUtils; import javasabr.rlib.network.packet.impl.AbstractReadableNetworkPacket; +import lombok.AccessLevel; import lombok.Getter; -import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; import org.jspecify.annotations.Nullable; +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PROTECTED) public abstract class MqttReadablePacket extends AbstractReadableNetworkPacket { static { DebugUtils.registerIncludedFields("userProperties"); } - private static final MutableArray EMPTY_PROPERTIES = MutableArray.ofType(StringPair.class); + private static final Array EMPTY_PROPERTIES = Array.empty(StringPair.class); - @Getter - @RequiredArgsConstructor - private static class Utf8Decoder { - private final CharsetDecoder decoder; - private final ByteBuffer inBuffer; - private final CharBuffer outBuffer; - } + private record Utf8Decoder(CharsetDecoder decoder, ByteBuffer inBuffer, CharBuffer outBuffer) {} private static final ThreadLocal LOCAL_DECODER = ThreadLocal.withInitial(() -> { @@ -47,34 +48,39 @@ private static class Utf8Decoder { .onMalformedInput(CodingErrorAction.REPORT) .onUnmappableCharacter(CodingErrorAction.REPORT); - return new Utf8Decoder(decoder, ByteBuffer.allocate(1024), CharBuffer.allocate(1024)); + return new Utf8Decoder( + decoder, + ByteBuffer.allocate(2048), + CharBuffer.allocate(2048)); }); /** * The list of user properties. */ - @Getter - protected MutableArray userProperties; + @Nullable + MutableArray userProperties; /** * The happened exception during parsing this packet. */ @Getter @Nullable - protected Exception exception; + Exception exception; - protected MqttReadablePacket(byte info) { - this.userProperties = EMPTY_PROPERTIES; - } + protected MqttReadablePacket(byte info) {} public abstract byte packetType(); + public Array userProperties() { + return userProperties == null ? EMPTY_PROPERTIES : userProperties; + } + @Override protected void readImpl(MqttConnection connection, ByteBuffer buffer) { readVariableHeader(connection, buffer); if (isPropertiesSupported(connection, buffer)) { - readProperties(buffer); + readProperties(connection, buffer); } readPayload(connection, buffer); @@ -95,60 +101,65 @@ protected boolean isPropertiesSupported(MqttConnection connection, ByteBuffer bu return connection.isSupported(MqttVersion.MQTT_5); } - protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { - } + protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) {} - protected void readProperties(ByteBuffer buffer) { - readProperties(buffer, getAvailableProperties()); + protected void readProperties(MqttConnection connection, ByteBuffer buffer) { + readProperties(connection, buffer, getAvailableProperties()); } - protected void readPayload(MqttConnection connection, ByteBuffer buffer) { - } + protected void readPayload(MqttConnection connection, ByteBuffer buffer) {} - protected void readProperties(ByteBuffer buffer, Set availableProperties) { + protected void readProperties(MqttConnection connection, ByteBuffer buffer, Set availableProperties) { - var propertiesLength = MqttDataUtils.readMbi(buffer); - - if (propertiesLength == -1) { + int propertiesLength = MqttDataUtils.readMbi(buffer); + if (propertiesLength == MqttDataUtils.UNKNOWN_LENGTH) { throw new IllegalStateException("Can't read properties length."); } else if (propertiesLength == 0) { return; } - var lastPositionInBuffer = buffer.position() + propertiesLength; + int lastPositionInBuffer = buffer.position() + propertiesLength; + MqttServerConnectionConfig serverConnectionConfig = connection.serverConnectionConfig(); while (buffer.position() < lastPositionInBuffer) { - - var property = PacketProperty.of(readUnsignedByte(buffer)); - + PacketProperty property = PacketProperty.byId(readByteUnsigned(buffer)); if (!availableProperties.contains(property)) { - throw new IllegalStateException("Property: " + property + " is not available for this packet."); + throw new IllegalStateException("Property:[" + property + "] is not available for packet:[" + this + "]"); } - - switch (property.getDataType()) { - case BYTE: - applyProperty(property, readUnsignedByte(buffer)); + switch (property.dataType()) { + case BYTE: { + applyProperty(property, readByteUnsigned(buffer)); break; - case SHORT: - applyProperty(property, readUnsignedShort(buffer)); + } + case SHORT: { + applyProperty(property, readShortUnsigned(buffer)); break; - case INTEGER: - applyProperty(property, readUnsignedInt(buffer)); + } + case INTEGER: { + applyProperty(property, readIntUnsigned(buffer)); break; - case MULTI_BYTE_INTEGER: + } + case MULTI_BYTE_INTEGER: { applyProperty(property, MqttDataUtils.readMbi(buffer)); break; - case UTF_8_STRING: - applyProperty(property, readString(buffer, Integer.MAX_VALUE)); + } + case UTF_8_STRING: { + applyProperty(property, readString(buffer, serverConnectionConfig.maxStringLength())); break; - case UTF_8_STRING_PAIR: - applyProperty(property, new StringPair(readString(buffer, Integer.MAX_VALUE), readString(buffer, Integer.MAX_VALUE))); + } + case UTF_8_STRING_PAIR: { + String name = readString(buffer, serverConnectionConfig.maxStringLength()); + String value = readString(buffer, serverConnectionConfig.maxStringLength()); + applyProperty(property, new StringPair(name, value)); break; - case BINARY: - applyProperty(property, readBytes(buffer)); + } + case BINARY: { + applyProperty(property, readBytes(buffer, serverConnectionConfig.maxBinarySize())); break; - default: - throw new IllegalArgumentException("Unsupported data type: " + property.getDataType()); + } + default: { + throw new IllegalArgumentException("Unsupported data type: " + property.dataType()); + } } } } @@ -157,19 +168,16 @@ protected Set getAvailableProperties() { return Collections.emptySet(); } - protected void applyProperty(PacketProperty property, long value) { - } + protected void applyProperty(PacketProperty property, long value) {} - protected void applyProperty(PacketProperty property, String value) { - } + protected void applyProperty(PacketProperty property, String value) {} - protected void applyProperty(PacketProperty property, byte[] value) { - } + protected void applyProperty(PacketProperty property, byte[] value) {} protected void applyProperty(PacketProperty property, StringPair value) { switch (property) { case USER_PROPERTY: - if (userProperties == EMPTY_PROPERTIES) { + if (userProperties == null) { userProperties = MutableArray.ofType(StringPair.class); } userProperties.add(value); @@ -177,62 +185,53 @@ protected void applyProperty(PacketProperty property, StringPair value) { } } - protected int readUnsignedByte(ByteBuffer buffer) { - return Byte.toUnsignedInt(buffer.get()); - } - - protected int readUnsignedShort(ByteBuffer buffer) { - return Short.toUnsignedInt(buffer.getShort()); - } - - protected long readUnsignedInt(ByteBuffer buffer) { - return Integer.toUnsignedLong(buffer.getInt()); - } - @Override protected String readString(ByteBuffer buffer, int maxLength) { - var utf8Decoder = LOCAL_DECODER.get(); - var inBuffer = utf8Decoder.getInBuffer(); + Utf8Decoder utf8Decoder = LOCAL_DECODER.get(); + ByteBuffer inBuffer = utf8Decoder.inBuffer(); - var stringLength = readShort(buffer) & 0xFFFF; - - if (stringLength > inBuffer.capacity()) { + int stringLength = readShortUnsigned(buffer); + if (stringLength > inBuffer.capacity() || stringLength > maxLength) { throw new MalformedPacketMqttException(); } - var decoder = utf8Decoder.getDecoder(); - var outBuffer = utf8Decoder.getOutBuffer(); + inBuffer.clear(); + buffer.get(inBuffer.array(), 0, stringLength); + inBuffer + .position(stringLength) + .flip(); - buffer.get( - inBuffer - .clear() - .array(), 0, stringLength); + CharBuffer outBuffer = utf8Decoder + .outBuffer() + .clear(); + CharsetDecoder decoder = utf8Decoder.decoder(); decoder.reset(); - var result = decoder.decode( - inBuffer - .position(stringLength) - .flip(), outBuffer.clear(), true); - + CoderResult result = decoder.decode(inBuffer, outBuffer, true); if (result.isError()) { throw new MalformedPacketMqttException(); } - return new String(inBuffer.array(), 0, stringLength, StandardCharsets.UTF_8); + return outBuffer + .flip() + .toString(); } - protected byte[] readBytes(ByteBuffer buffer) { - var data = new byte[readShort(buffer) & 0xFFFF]; + protected byte[] readBytes(ByteBuffer buffer, int maxLength) { + int length = readShortUnsigned(buffer); + if (length >= maxLength) { + throw new IllegalStateException("Unexpected too many bytes:[" + length + ">" + maxLength + "]"); + } + byte[] data = new byte[length]; buffer.get(data); return data; } protected byte[] readPayload(ByteBuffer buffer) { - var payloadSize = buffer.limit() - buffer.position(); - + int payloadSize = buffer.limit() - buffer.position(); if (payloadSize < 1) { return ArrayUtils.EMPTY_BYTE_ARRAY; } @@ -243,7 +242,7 @@ protected byte[] readPayload(ByteBuffer buffer) { } protected void unexpectedProperty(PacketProperty property) { - throw new IllegalArgumentException("Unsupported property: " + property); + throw new IllegalArgumentException("Unsupported property:[" + property + "]"); } @Override diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishAckInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishAckInPacket.java index c9762f5f..7b2c1190 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishAckInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishAckInPacket.java @@ -68,11 +68,11 @@ public byte packetType() { protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718045 - packetId = readUnsignedShort(buffer); + packetId = readShortUnsigned(buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901123 if (connection.isSupported(MqttVersion.MQTT_5) && buffer.hasRemaining()) { - reasonCode = PublishAckReasonCode.of(readUnsignedByte(buffer)); + reasonCode = PublishAckReasonCode.of(readByteUnsigned(buffer)); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishCompleteInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishCompleteInPacket.java index 2cfabd0e..351fe8d1 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishCompleteInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishCompleteInPacket.java @@ -69,11 +69,11 @@ protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) super.readVariableHeader(connection, buffer); // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718083 - packetId = readUnsignedShort(buffer); + packetId = readShortUnsigned(buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154 if (connection.isSupported(MqttVersion.MQTT_5) && buffer.hasRemaining()) { - reasonCode = PublishCompletedReasonCode.of(readUnsignedByte(buffer)); + reasonCode = PublishCompletedReasonCode.of(readByteUnsigned(buffer)); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishInPacket.java index b990e5f9..9a7aff54 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishInPacket.java @@ -288,7 +288,7 @@ public byte packetType() { protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718039 topicName = buildTopicName(readString(buffer, Integer.MAX_VALUE)); - packetId = qos != QoS.AT_MOST_ONCE ? readUnsignedShort(buffer) : 0; + packetId = qos != QoS.AT_MOST_ONCE ? readShortUnsigned(buffer) : 0; } @Override diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishReceivedInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishReceivedInPacket.java index b0974c8a..2e8ca042 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishReceivedInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishReceivedInPacket.java @@ -65,11 +65,11 @@ protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) super.readVariableHeader(connection, buffer); // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718050 - packetId = readUnsignedShort(buffer); + packetId = readShortUnsigned(buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901143 if (connection.isSupported(MqttVersion.MQTT_5) && buffer.hasRemaining()) { - reasonCode = PublishReceivedReasonCode.of(readUnsignedByte(buffer)); + reasonCode = PublishReceivedReasonCode.of(readByteUnsigned(buffer)); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishReleaseInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishReleaseInPacket.java index af81b98a..8d600d77 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/PublishReleaseInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/PublishReleaseInPacket.java @@ -69,11 +69,11 @@ protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) super.readVariableHeader(connection, buffer); // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718055 - packetId = readUnsignedShort(buffer); + packetId = readShortUnsigned(buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901143 if (connection.isSupported(MqttVersion.MQTT_5) && buffer.hasRemaining()) { - reasonCode = PublishReleaseReasonCode.of(readUnsignedByte(buffer)); + reasonCode = PublishReleaseReasonCode.of(readByteUnsigned(buffer)); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/SubscribeAckInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/SubscribeAckInPacket.java index 4809d729..73ddfc68 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/SubscribeAckInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/SubscribeAckInPacket.java @@ -60,7 +60,7 @@ public byte packetType() { @Override protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718070 - packetId = readUnsignedShort(buffer); + packetId = readShortUnsigned(buffer); } @Override @@ -72,7 +72,7 @@ protected void readPayload(MqttConnection connection, ByteBuffer buffer) { } while (buffer.hasRemaining()) { - reasonCodes.add(SubscribeAckReasonCode.of(readUnsignedByte(buffer))); + reasonCodes.add(SubscribeAckReasonCode.of(readByteUnsigned(buffer))); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/SubscribeInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/SubscribeInPacket.java index 3e4bc3c7..2f60b048 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/SubscribeInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/SubscribeInPacket.java @@ -69,7 +69,7 @@ public byte packetType() { @Override protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718065 - packetId = readUnsignedShort(buffer); + packetId = readShortUnsigned(buffer); } @Override @@ -86,7 +86,7 @@ protected void readPayload(MqttConnection connection, ByteBuffer buffer) { while (buffer.hasRemaining()) { var topicFilter = readString(buffer, Integer.MAX_VALUE); - var options = readUnsignedByte(buffer); + var options = readByteUnsigned(buffer); var qos = QoS.of(options & 0x03); var retainHandling = isMqtt5 ? SubscribeRetainHandling.of((options >> 4) & 0x03) : SubscribeRetainHandling.SEND; diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/UnsubscribeAckInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/UnsubscribeAckInPacket.java index 2c4c1764..3eb61f34 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/UnsubscribeAckInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/UnsubscribeAckInPacket.java @@ -8,50 +8,58 @@ import javasabr.mqtt.model.reason.code.UnsubscribeAckReasonCode; import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.packet.PacketType; +import javasabr.rlib.collections.array.Array; import javasabr.rlib.collections.array.ArrayFactory; import javasabr.rlib.collections.array.MutableArray; import javasabr.rlib.common.util.StringUtils; +import lombok.AccessLevel; import lombok.Getter; +import lombok.experimental.Accessors; +import lombok.experimental.FieldDefaults; +import org.jspecify.annotations.Nullable; /** * Unsubscribe acknowledgement. */ @Getter +@Accessors(fluent = true, chain = false) +@FieldDefaults(level = AccessLevel.PRIVATE) public class UnsubscribeAckInPacket extends MqttReadablePacket { private static final byte PACKET_TYPE = (byte) PacketType.UNSUBSCRIBE_ACK.ordinal(); private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the - Client. - - The Server uses this value to give additional information to the Client. The Server MUST NOT send this - Property if it would increase the size of the UNSUBACK packet beyond the Maximum Packet Size - specified by the Client [MQTT-3.11.2-1]. It is a Protocol Error to include the Reason String more than - once. - */ + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the + Client. + + The Server uses this value to give additional information to the Client. The Server MUST NOT send this + Property if it would increase the size of the UNSUBACK packet beyond the Maximum Packet Size + specified by the Client [MQTT-3.11.2-1]. It is a Protocol Error to include the Reason String more than + once. + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other - information. The Server MUST NOT send this property if it would increase the size of the UNSUBACK - packet beyond the Maximum Packet Size specified by the Client [MQTT-3.11.2-2]. The User Property is - allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to - appear more than once. - */ + /* + Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other + information. The Server MUST NOT send this property if it would increase the size of the UNSUBACK + packet beyond the Maximum Packet Size specified by the Client [MQTT-3.11.2-2]. The User Property is + allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to + appear more than once. + */ PacketProperty.USER_PROPERTY); - private MutableArray reasonCodes; - private int packetId; + private static final Array EMPTY_REASON_CODES = Array.empty(UnsubscribeAckReasonCode.class); + + @Nullable + MutableArray reasonCodes; + int packetId; // properties - private String reason; + String reason = StringUtils.EMPTY; public UnsubscribeAckInPacket(byte info) { super(info); - this.reasonCodes = ArrayFactory.mutableArray(UnsubscribeAckReasonCode.class); - this.reason = StringUtils.EMPTY; } @Override @@ -62,7 +70,7 @@ public byte packetType() { @Override protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718079 - packetId = readUnsignedShort(buffer); + packetId = readShortUnsigned(buffer); } @Override @@ -80,7 +88,7 @@ protected void readPayload(MqttConnection connection, ByteBuffer buffer) { reasonCodes = ArrayFactory.mutableArray(UnsubscribeAckReasonCode.class, buffer.remaining()); while (buffer.hasRemaining()) { - reasonCodes.add(UnsubscribeAckReasonCode.of(readUnsignedByte(buffer))); + reasonCodes.add(UnsubscribeAckReasonCode.of(readByteUnsigned(buffer))); } } @@ -89,14 +97,20 @@ protected Set getAvailableProperties() { return AVAILABLE_PROPERTIES; } + public Array reasonCodes() { + return reasonCodes == null ? EMPTY_REASON_CODES : reasonCodes; + } + @Override protected void applyProperty(PacketProperty property, String value) { switch (property) { - case REASON_STRING: + case REASON_STRING: { reason = value; break; - default: + } + default: { unexpectedProperty(property); + } } } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/in/UnsubscribeInPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/in/UnsubscribeInPacket.java index 3339a362..ef081c6c 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/in/UnsubscribeInPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/in/UnsubscribeInPacket.java @@ -43,7 +43,7 @@ public byte packetType() { @Override protected void readVariableHeader(MqttConnection connection, ByteBuffer buffer) { - packetId = readUnsignedShort(buffer); + packetId = readShortUnsigned(buffer); } @Override diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/Authentication5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/Authentication5OutPacket.java index 7c6994e9..f608e93a 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/Authentication5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/Authentication5OutPacket.java @@ -6,6 +6,7 @@ import javasabr.mqtt.model.PacketProperty; import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.reason.code.AuthenticateReasonCode; +import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.packet.PacketType; import javasabr.rlib.collections.array.Array; import lombok.RequiredArgsConstructor; @@ -19,34 +20,34 @@ public class Authentication5OutPacket extends MqttWritablePacket { private static final byte PACKET_TYPE = (byte) PacketType.AUTHENTICATE.ordinal(); private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by a UTF-8 Encoded String containing the name of the authentication method. It is a Protocol - Error to omit the Authentication Method or to include it more than once. Refer to section 4.12 for more - information about extended authentication. - */ + /* + Followed by a UTF-8 Encoded String containing the name of the authentication method. It is a Protocol + Error to omit the Authentication Method or to include it more than once. Refer to section 4.12 for more + information about extended authentication. + */ PacketProperty.AUTHENTICATION_METHOD, - /* - Followed by Binary Data containing authentication data. It is a Protocol Error to include Authentication - Data more than once. The contents of this data are defined by the authentication method. Refer to - section 4.12 for more information about extended authentication. - */ + /* + Followed by Binary Data containing authentication data. It is a Protocol Error to include Authentication + Data more than once. The contents of this data are defined by the authentication method. Refer to + section 4.12 for more information about extended authentication. + */ PacketProperty.AUTHENTICATION_DATA, - /* - Followed by the UTF-8 Encoded String representing the reason for the disconnect. This Reason String is - human readable, designed for diagnostics and SHOULD NOT be parsed by the receiver. + /* + Followed by the UTF-8 Encoded String representing the reason for the disconnect. This Reason String is + human readable, designed for diagnostics and SHOULD NOT be parsed by the receiver. - The sender MUST NOT send this property if it would increase the size of the AUTH packet beyond the - Maximum Packet Size specified by the receiver [MQTT-3.15.2-2]. It is a Protocol Error to include the - Reason String more than once. - */ + The sender MUST NOT send this property if it would increase the size of the AUTH packet beyond the + Maximum Packet Size specified by the receiver [MQTT-3.15.2-2]. It is a Protocol Error to include the + Reason String more than once. + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property may be used to provide additional diagnostic or other - information. The sender MUST NOT send this property if it would increase the size of the AUTH packet - beyond the Maximum Packet Size specified by the receiver [MQTT-3.15.2-3]. The User Property is - allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to - appear more than once. - */ + /* + Followed by UTF-8 String Pair. This property may be used to provide additional diagnostic or other + information. The sender MUST NOT send this property if it would increase the size of the AUTH packet + beyond the Maximum Packet Size specified by the receiver [MQTT-3.15.2-3]. The User Property is + allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to + appear more than once. + */ PacketProperty.USER_PROPERTY); private final Array userProperties; @@ -64,18 +65,18 @@ protected byte packetType() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901219 writeByte(buffer, reasonCode.getValue()); } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901221 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/Connect311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/Connect311OutPacket.java index 01abfe82..94a318da 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/Connect311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/Connect311OutPacket.java @@ -3,6 +3,7 @@ import java.nio.ByteBuffer; import javasabr.mqtt.model.MqttVersion; import javasabr.mqtt.model.QoS; +import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.packet.PacketType; import javasabr.rlib.common.util.ArrayUtils; import javasabr.rlib.common.util.StringUtils; @@ -53,19 +54,19 @@ protected byte packetType() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { - var mqttVersion = getMqttVersion(); + MqttVersion mqttVersion = getMqttVersion(); // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718030 - writeString(buffer, mqttVersion.getName()); - writeByte(buffer, mqttVersion.getVersion()); + writeString(buffer, mqttVersion.rawName()); + writeByte(buffer, mqttVersion.version()); writeByte(buffer, buildConnectFlags()); writeShort(buffer, keepAlive); } @Override - protected void writePayload(ByteBuffer buffer) { + protected void writePayload(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718031 writeString(buffer, clientId); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/Connect5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/Connect5OutPacket.java index 260a84ef..036a508b 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/Connect5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/Connect5OutPacket.java @@ -8,6 +8,7 @@ import javasabr.mqtt.model.PacketProperty; import javasabr.mqtt.model.QoS; import javasabr.mqtt.model.data.type.StringPair; +import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.utils.MqttDataUtils; import javasabr.rlib.collections.array.Array; import javasabr.rlib.common.util.ArrayUtils; @@ -38,7 +39,7 @@ public class Connect5OutPacket extends Connect311OutPacket { The value of Receive Maximum applies only to the current Network Connection. If the Receive Maximum value is absent then its value defaults to 65,535. */ - PacketProperty.RECEIVE_MAXIMUM, + PacketProperty.RECEIVE_MAXIMUM_PUBLISH, /* Followed by a Four Byte Integer representing the Maximum Packet Size the Client is willing to accept. If the Maximum Packet Size is not present, no limit on the packet size is imposed beyond the limitations in @@ -247,14 +248,14 @@ protected MqttVersion getMqttVersion() { } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override protected void appendWillProperties(ByteBuffer buffer) { - var propertiesBuffer = getPropertiesBuffer(); + var propertiesBuffer = propertiesBuffer(); writeWillProperties(propertiesBuffer); @@ -271,14 +272,14 @@ protected void appendWillProperties(ByteBuffer buffer) { } @Override - protected void writeProperties(ByteBuffer buffer) { + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901046 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); writeNotEmptyProperty(buffer, PacketProperty.AUTHENTICATION_METHOD, authenticationMethod); writeNotEmptyProperty(buffer, PacketProperty.AUTHENTICATION_DATA, authenticationData); writeProperty(buffer, PacketProperty.REQUEST_RESPONSE_INFORMATION, requestResponseInformation, false); writeProperty(buffer, PacketProperty.REQUEST_PROBLEM_INFORMATION, requestProblemInformation, false); - writeProperty(buffer, PacketProperty.RECEIVE_MAXIMUM, receiveMax, MqttProperties.RECEIVE_MAXIMUM_UNDEFINED); + writeProperty(buffer, PacketProperty.RECEIVE_MAXIMUM_PUBLISH, receiveMax, MqttProperties.RECEIVE_MAXIMUM_UNDEFINED); writeProperty( buffer, PacketProperty.TOPIC_ALIAS_MAXIMUM, diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/ConnectAck311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/ConnectAck311OutPacket.java index f17f1083..b71bc7bd 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/ConnectAck311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/ConnectAck311OutPacket.java @@ -5,12 +5,15 @@ import javasabr.mqtt.model.reason.code.ConnectAckReasonCode; import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.packet.PacketType; +import lombok.AccessLevel; import lombok.RequiredArgsConstructor; +import lombok.experimental.FieldDefaults; /** * Connect acknowledgment. */ @RequiredArgsConstructor +@FieldDefaults(level = AccessLevel.PROTECTED, makeFinal = true) public class ConnectAck311OutPacket extends MqttWritablePacket { private static final byte PACKET_TYPE = (byte) PacketType.CONNECT_ACK.ordinal(); @@ -25,7 +28,7 @@ public class ConnectAck311OutPacket extends MqttWritablePacket { * Connect Reason code from this table. If a Server sends a CONNACK packet containing a Reason code of 128 or greater * it MUST then close the Network Connection */ - protected final ConnectAckReasonCode reasonCode; + ConnectAckReasonCode reasonCode; /** * The Session Present flag informs the Client whether the Server is using Session State from a previous connection @@ -33,7 +36,7 @@ public class ConnectAck311OutPacket extends MqttWritablePacket { * accepts a connection with Clean Start set to 1, the Server MUST set Session Present to 0 in the CONNACK packet in * addition to setting a 0x00 (Success) Reason Code in the CONNACK packet */ - private final boolean sessionPresent; + boolean sessionPresent; @Override protected byte packetType() { @@ -46,7 +49,7 @@ public int expectedLength(MqttConnection connection) { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718035 buffer.put((byte) (sessionPresent ? 0x01 : 0x00)); buffer.put(reasonCodeValue()); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/ConnectAck5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/ConnectAck5OutPacket.java index 2d39e102..034b1003 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/ConnectAck5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/ConnectAck5OutPacket.java @@ -4,17 +4,20 @@ import java.util.EnumSet; import java.util.Set; import javasabr.mqtt.base.utils.DebugUtils; +import javasabr.mqtt.model.MqttClientConnectionConfig; import javasabr.mqtt.model.MqttProperties; import javasabr.mqtt.model.PacketProperty; -import javasabr.mqtt.model.QoS; import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.reason.code.ConnectAckReasonCode; import javasabr.mqtt.network.MqttConnection; import javasabr.rlib.collections.array.Array; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; /** * Connect acknowledgment. */ +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class ConnectAck5OutPacket extends ConnectAck311OutPacket { static { @@ -22,280 +25,255 @@ public class ConnectAck5OutPacket extends ConnectAck311OutPacket { } private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the Four Byte Integer representing the Session Expiry Interval in seconds. It is a Protocol - Error to include the Session Expiry Interval more than once. + /* + Followed by the Four Byte Integer representing the Session Expiry Interval in seconds. It is a Protocol + Error to include the Session Expiry Interval more than once. - If the Session Expiry Interval is absent the value in the CONNECT Packet used. The server uses this - property to inform the Client that it is using a value other than that sent by the Client in the CONNACK. - */ + If the Session Expiry Interval is absent the value in the CONNECT Packet used. The server uses this + property to inform the Client that it is using a value other than that sent by the Client in the CONNACK. + */ PacketProperty.SESSION_EXPIRY_INTERVAL, - /* - Followed by the Two Byte Integer representing the Receive Maximum value. It is a Protocol Error to - include the Receive Maximum value more than once or for it to have the value 0. - - The Server uses this value to limit the number of QoS 1 and QoS 2 publications that it is willing to - process concurrently for the Client. It does not provide a mechanism to limit the QoS 0 publications that - the Client might try to send. - - If the Receive Maximum value is absent, then its value defaults to 65,535. - */ - PacketProperty.RECEIVE_MAXIMUM, - /* - Followed by a Byte with a value of either 0 or 1. It is a Protocol Error to include Maximum QoS more than - once, or to have a value other than 0 or 1. If the Maximum QoS is absent, the Client uses a Maximum - QoS of 2. - - If a Server does not support QoS 1 or QoS 2 PUBLISH packets it MUST send a Maximum QoS in the - CONNACK packet specifying the highest QoS it supports [MQTT-3.2.2-9]. A Server that does not support - QoS 1 or QoS 2 PUBLISH packets MUST still accept SUBSCRIBE packets containing a Requested QoS - of 0, 1 or 2 [MQTT-3.2.2-10]. - - If a Client receives a Maximum QoS from a Server, it MUST NOT send PUBLISH packets at a QoS level - exceeding the Maximum QoS level specified [MQTT-3.2.2-11]. It is a Protocol Error if the Server receives - a PUBLISH packet with a QoS greater than the Maximum QoS it specified. In this case use - DISCONNECT with Reason Code 0x9B (QoS not supported) as described in section 4.13 Handling - errors. - - If a Server receives a CONNECT packet containing a Will QoS that exceeds its capabilities, it MUST - reject the connection. It SHOULD use a CONNACK packet with Reason Code 0x9B (QoS not supported) - as described in section 4.13 Handling errors, and MUST close the Network Connection - */ + /* + Followed by the Two Byte Integer representing the Receive Maximum value. It is a Protocol Error to + include the Receive Maximum value more than once or for it to have the value 0. + + The Server uses this value to limit the number of QoS 1 and QoS 2 publications that it is willing to + process concurrently for the Client. It does not provide a mechanism to limit the QoS 0 publications that + the Client might try to send. + + If the Receive Maximum value is absent, then its value defaults to 65,535. + */ + PacketProperty.RECEIVE_MAXIMUM_PUBLISH, + /* + Followed by a Byte with a value of either 0 or 1. It is a Protocol Error to include Maximum QoS more than + once, or to have a value other than 0 or 1. If the Maximum QoS is absent, the Client uses a Maximum + QoS of 2. + + If a Server does not support QoS 1 or QoS 2 PUBLISH packets it MUST send a Maximum QoS in the + CONNACK packet specifying the highest QoS it supports [MQTT-3.2.2-9]. A Server that does not support + QoS 1 or QoS 2 PUBLISH packets MUST still accept SUBSCRIBE packets containing a Requested QoS + of 0, 1 or 2 [MQTT-3.2.2-10]. + + If a Client receives a Maximum QoS from a Server, it MUST NOT send PUBLISH packets at a QoS level + exceeding the Maximum QoS level specified [MQTT-3.2.2-11]. It is a Protocol Error if the Server receives + a PUBLISH packet with a QoS greater than the Maximum QoS it specified. In this case use + DISCONNECT with Reason Code 0x9B (QoS not supported) as described in section 4.13 Handling + errors. + + If a Server receives a CONNECT packet containing a Will QoS that exceeds its capabilities, it MUST + reject the connection. It SHOULD use a CONNACK packet with Reason Code 0x9B (QoS not supported) + as described in section 4.13 Handling errors, and MUST close the Network Connection + */ PacketProperty.MAXIMUM_QOS, - /* - Followed by a Byte field. If present, this byte declares whether the Server supports retained messages. A - value of 0 means that retained messages are not supported. A value of 1 means retained messages are - supported. If not present, then retained messages are supported. It is a Protocol Error to include Retain - Available more than once or to use a value other than 0 or 1. - - If a Server receives a CONNECT packet containing a Will Message with the Will Retain set to 1, and it - does not support retained messages, the Server MUST reject the connection request. It SHOULD send - CONNACK with Reason Code 0x9A (Retain not supported) and then it MUST close the Network - Connection [MQTT-3.2.2-13]. - - A Client receiving Retain Available set to 0 from the Server MUST NOT send a PUBLISH packet with the - RETAIN flag set to 1 [MQTT-3.2.2-14]. If the Server receives such a packet, this is a Protocol Error. The - Server SHOULD send a DISCONNECT with Reason Code of 0x9A (Retain not supported) as described - in section 4.13. - */ + /* + Followed by a Byte field. If present, this byte declares whether the Server supports retained messages. A + value of 0 means that retained messages are not supported. A value of 1 means retained messages are + supported. If not present, then retained messages are supported. It is a Protocol Error to include Retain + Available more than once or to use a value other than 0 or 1. + + If a Server receives a CONNECT packet containing a Will Message with the Will Retain set to 1, and it + does not support retained messages, the Server MUST reject the connection request. It SHOULD send + CONNACK with Reason Code 0x9A (Retain not supported) and then it MUST close the Network + Connection [MQTT-3.2.2-13]. + + A Client receiving Retain Available set to 0 from the Server MUST NOT send a PUBLISH packet with the + RETAIN flag set to 1 [MQTT-3.2.2-14]. If the Server receives such a packet, this is a Protocol Error. The + Server SHOULD send a DISCONNECT with Reason Code of 0x9A (Retain not supported) as described + in section 4.13. + */ PacketProperty.RETAIN_AVAILABLE, - /* - Followed by a Four Byte Integer representing the Maximum Packet Size the Server is willing to accept. If - the Maximum Packet Size is not present, there is no limit on the packet size imposed beyond the - limitations in the protocol as a result of the remaining length encoding and the protocol header sizes. - - It is a Protocol Error to include the Maximum Packet Size more than once, or for the value to be set to - zero. - - The packet size is the total number of bytes in an MQTT Control Packet, as defined in section 2.1.4. The - Server uses the Maximum Packet Size to inform the Client that it will not process packets whose size - exceeds this limit. - - The Client MUST NOT send packets exceeding Maximum Packet Size to the Server [MQTT-3.2.2-15]. If - a Server receives a packet whose size exceeds this limit, this is a Protocol Error, the Server uses - DISCONNECT with Reason Code 0x95 (Packet too large), as described in section 4.13. - */ + /* + Followed by a Four Byte Integer representing the Maximum Packet Size the Server is willing to accept. If + the Maximum Packet Size is not present, there is no limit on the packet size imposed beyond the + limitations in the protocol as a result of the remaining length encoding and the protocol header sizes. + + It is a Protocol Error to include the Maximum Packet Size more than once, or for the value to be set to + zero. + + The packet size is the total number of bytes in an MQTT Control Packet, as defined in section 2.1.4. The + Server uses the Maximum Packet Size to inform the Client that it will not process packets whose size + exceeds this limit. + + The Client MUST NOT send packets exceeding Maximum Packet Size to the Server [MQTT-3.2.2-15]. If + a Server receives a packet whose size exceeds this limit, this is a Protocol Error, the Server uses + DISCONNECT with Reason Code 0x95 (Packet too large), as described in section 4.13. + */ PacketProperty.MAXIMUM_PACKET_SIZE, - /* - Followed by the UTF-8 string which is the Assigned Client Identifier. It is a Protocol Error to include the - Assigned Client Identifier more than once. + /* + Followed by the UTF-8 string which is the Assigned Client Identifier. It is a Protocol Error to include the + Assigned Client Identifier more than once. - The Client Identifier which was assigned by the Server because a zero length Client Identifier was found - in the CONNECT packet. + The Client Identifier which was assigned by the Server because a zero length Client Identifier was found + in the CONNECT packet. - If the Client connects using a zero length Client Identifier, the Server MUST respond with a CONNACK - containing an Assigned Client Identifier. The Assigned Client Identifier MUST be a new Client Identifier - not used by any other Session currently in the Server [ - */ + If the Client connects using a zero length Client Identifier, the Server MUST respond with a CONNACK + containing an Assigned Client Identifier. The Assigned Client Identifier MUST be a new Client Identifier + not used by any other Session currently in the Server [ + */ PacketProperty.ASSIGNED_CLIENT_IDENTIFIER, - /* - Followed by the Two Byte Integer representing the Topic Alias Maximum value. It is a Protocol Error to - include the Topic Alias Maximum value more than once. If the Topic Alias Maximum property is absent, - the default value is 0. - - This value indicates the highest value that the Server will accept as a Topic Alias sent by the Client. The - Server uses this value to limit the number of Topic Aliases that it is willing to hold on this Connection. The - Client MUST NOT send a Topic Alias in a PUBLISH packet to the Server greater than this value - [MQTT1296 3.2.2-17]. A value of 0 indicates that the Server does not accept any Topic Aliases - on this connection. If Topic Alias Maximum is absent or 0, the Client MUST NOT send any Topic Aliases on - to the Server - */ + /* + Followed by the Two Byte Integer representing the Topic Alias Maximum value. It is a Protocol Error to + include the Topic Alias Maximum value more than once. If the Topic Alias Maximum property is absent, + the default value is 0. + + This value indicates the highest value that the Server will accept as a Topic Alias sent by the Client. The + Server uses this value to limit the number of Topic Aliases that it is willing to hold on this Connection. The + Client MUST NOT send a Topic Alias in a PUBLISH packet to the Server greater than this value + [MQTT1296 3.2.2-17]. A value of 0 indicates that the Server does not accept any Topic Aliases + on this connection. If Topic Alias Maximum is absent or 0, the Client MUST NOT send any Topic Aliases on + to the Server + */ PacketProperty.TOPIC_ALIAS_MAXIMUM, - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the - Client. - - The Server uses this value to give additional information to the Client. The Server MUST NOT send this - property if it would increase the size of the CONNACK packet beyond the Maximum Packet Size specified - by the Client [MQTT-3.2.2-19]. It is a Protocol Error to include the Reason String more than once. - */ + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the + Client. + + The Server uses this value to give additional information to the Client. The Server MUST NOT send this + property if it would increase the size of the CONNACK packet beyond the Maximum Packet Size specified + by the Client [MQTT-3.2.2-19]. It is a Protocol Error to include the Reason String more than once. + */ PacketProperty.REASON_STRING, - /* - Followed by a UTF-8 String Pair. This property can be used to provide additional information to the Client - including diagnostic information. The Server MUST NOT send this property if it would increase the size of - the CONNACK packet beyond the Maximum Packet Size specified by the Client [MQTT-3.2.2-20]. The - User Property is allowed to appear multiple times to represent multiple name, value pairs. The same - name is allowed to appear more than once. - - The content and meaning of this property is not defined by this specification. The receiver of a CONNACK - containing this property MAY ignore it. - */ + /* + Followed by a UTF-8 String Pair. This property can be used to provide additional information to the Client + including diagnostic information. The Server MUST NOT send this property if it would increase the size of + the CONNACK packet beyond the Maximum Packet Size specified by the Client [MQTT-3.2.2-20]. The + User Property is allowed to appear multiple times to represent multiple name, value pairs. The same + name is allowed to appear more than once. + + The content and meaning of this property is not defined by this specification. The receiver of a CONNACK + containing this property MAY ignore it. + */ PacketProperty.USER_PROPERTY, - /* - Followed by a Byte field. If present, this byte declares whether the Server supports Wildcard - Subscriptions. A value is 0 means that Wildcard Subscriptions are not supported. A value of 1 means - Wildcard Subscriptions are supported. If not present, then Wildcard Subscriptions are supported. It is a - Protocol Error to include the Wildcard Subscription Available more than once or to send a value other - than 0 or 1. - - Standards Track Work Product Copyright © OASIS Open 2019. All Rights Reserved. Page 51 of 137 - - If the Server receives a SUBSCRIBE packet containing a Wildcard Subscription and it does not support - Wildcard Subscriptions, this is a Protocol Error. The Server uses DISCONNECT with Reason Code 0xA2 - (Wildcard Subscriptions not supported) as described in section 4.13. - - If a Server supports Wildcard Subscriptions, it can still reject a particular subscribe request containing a - Wildcard Subscription. In this case the Server MAY send a SUBACK Control Packet with a Reason Code - 0xA2 (Wildcard Subscriptions not supported). - */ + /* + Followed by a Byte field. If present, this byte declares whether the Server supports Wildcard + Subscriptions. A value is 0 means that Wildcard Subscriptions are not supported. A value of 1 means + Wildcard Subscriptions are supported. If not present, then Wildcard Subscriptions are supported. It is a + Protocol Error to include the Wildcard Subscription Available more than once or to send a value other + than 0 or 1. + + Standards Track Work Product Copyright © OASIS Open 2019. All Rights Reserved. Page 51 of 137 + + If the Server receives a SUBSCRIBE packet containing a Wildcard Subscription and it does not support + Wildcard Subscriptions, this is a Protocol Error. The Server uses DISCONNECT with Reason Code 0xA2 + (Wildcard Subscriptions not supported) as described in section 4.13. + + If a Server supports Wildcard Subscriptions, it can still reject a particular subscribe request containing a + Wildcard Subscription. In this case the Server MAY send a SUBACK Control Packet with a Reason Code + 0xA2 (Wildcard Subscriptions not supported). + */ PacketProperty.WILDCARD_SUBSCRIPTION_AVAILABLE, - /* - Followed by a Byte field. If present, this byte declares whether the Server supports Subscription - Identifiers. A value is 0 means that Subscription Identifiers are not supported. A value of 1 means - Subscription Identifiers are supported. If not present, then Subscription Identifiers are supported. It is a - Protocol Error to include the Subscription Identifier Available more than once, or to send a value other - than 0 or 1. - - If the Server receives a SUBSCRIBE packet containing Subscription Identifier and it does not support - Subscription Identifiers, this is a Protocol Error. The Server uses DISCONNECT with Reason Code of - 0xA1 (Subscription Identifiers not supported) as described in section 4.13. - */ + /* + Followed by a Byte field. If present, this byte declares whether the Server supports Subscription + Identifiers. A value is 0 means that Subscription Identifiers are not supported. A value of 1 means + Subscription Identifiers are supported. If not present, then Subscription Identifiers are supported. It is a + Protocol Error to include the Subscription Identifier Available more than once, or to send a value other + than 0 or 1. + + If the Server receives a SUBSCRIBE packet containing Subscription Identifier and it does not support + Subscription Identifiers, this is a Protocol Error. The Server uses DISCONNECT with Reason Code of + 0xA1 (Subscription Identifiers not supported) as described in section 4.13. + */ PacketProperty.SUBSCRIPTION_IDENTIFIER_AVAILABLE, - /* - Followed by a Byte field. If present, this byte declares whether the Server supports Shared Subscriptions. - A value is 0 means that Shared Subscriptions are not supported. A value of 1 means Shared - Subscriptions are supported. If not present, then Shared Subscriptions are supported. It is a Protocol - Error to include the Shared Subscription Available more than once or to send a value other than 0 or 1. - - If the Server receives a SUBSCRIBE packet containing Shared Subscriptions and it does not support - Shared Subscriptions, this is a Protocol Error. The Server uses DISCONNECT with Reason Code 0x9E - (Shared Subscriptions not supported) as described in section 4.13. - */ + /* + Followed by a Byte field. If present, this byte declares whether the Server supports Shared Subscriptions. + A value is 0 means that Shared Subscriptions are not supported. A value of 1 means Shared + Subscriptions are supported. If not present, then Shared Subscriptions are supported. It is a Protocol + Error to include the Shared Subscription Available more than once or to send a value other than 0 or 1. + + If the Server receives a SUBSCRIBE packet containing Shared Subscriptions and it does not support + Shared Subscriptions, this is a Protocol Error. The Server uses DISCONNECT with Reason Code 0x9E + (Shared Subscriptions not supported) as described in section 4.13. + */ PacketProperty.SHARED_SUBSCRIPTION_AVAILABLE, - /* - Followed by a Two Byte Integer with the Keep Alive time assigned by the Server. If the Server sends a - Server Keep Alive on the CONNACK packet, the Client MUST use this value instead of the Keep Alive - value the Client sent on CONNECT [MQTT-3.2.2-21]. If the Server does not send the Server Keep Alive, - the Server MUST use the Keep Alive value set by the Client on CONNECT [MQTT-3.2.2-22]. It is a - Protocol Error to include the Server Keep Alive more than once. - */ + /* + Followed by a Two Byte Integer with the Keep Alive time assigned by the Server. If the Server sends a + Server Keep Alive on the CONNACK packet, the Client MUST use this value instead of the Keep Alive + value the Client sent on CONNECT [MQTT-3.2.2-21]. If the Server does not send the Server Keep Alive, + the Server MUST use the Keep Alive value set by the Client on CONNECT [MQTT-3.2.2-22]. It is a + Protocol Error to include the Server Keep Alive more than once. + */ PacketProperty.SERVER_KEEP_ALIVE, - /* - Followed by a UTF-8 Encoded String which is used as the basis for creating a Response Topic. The way - in which the Client creates a Response Topic from the Response Information is not defined by this - specification. It is a Protocol Error to include the Response Information more than once. - - If the Client sends a Request Response Information with a value 1, it is OPTIONAL for the Server to send - the Response Information in the CONNACK. - */ + /* + Followed by a UTF-8 Encoded String which is used as the basis for creating a Response Topic. The way + in which the Client creates a Response Topic from the Response Information is not defined by this + specification. It is a Protocol Error to include the Response Information more than once. + + If the Client sends a Request Response Information with a value 1, it is OPTIONAL for the Server to send + the Response Information in the CONNACK. + */ PacketProperty.RESPONSE_INFORMATION, - /* - Followed by a UTF-8 Encoded String which can be used by the Client to identify another Server to use. It - is a Protocol Error to include the Server Reference more than once. + /* + Followed by a UTF-8 Encoded String which can be used by the Client to identify another Server to use. It + is a Protocol Error to include the Server Reference more than once. - The Server uses a Server Reference in either a CONNACK or DISCONNECT packet with Reason code - of 0x9C (Use another server) or Reason Code 0x9D (Server moved) as described in section 4.13. + The Server uses a Server Reference in either a CONNACK or DISCONNECT packet with Reason code + of 0x9C (Use another server) or Reason Code 0x9D (Server moved) as described in section 4.13. - Refer to section 4.11 Server redirection for information about how Server Reference is used - */ + Refer to section 4.11 Server redirection for information about how Server Reference is used + */ PacketProperty.SERVER_REFERENCE, - /* - Followed by a UTF-8 Encoded String containing the name of the authentication method. It is a Protocol - Error to include the Authentication Method more than once. Refer to section 4.12 for more information - about extended authentication. - */ + /* + Followed by a UTF-8 Encoded String containing the name of the authentication method. It is a Protocol + Error to include the Authentication Method more than once. Refer to section 4.12 for more information + about extended authentication. + */ PacketProperty.AUTHENTICATION_METHOD, - /* - Followed by Binary Data containing authentication data. The contents of this data are defined by the - authentication method and the state of already exchanged authentication data. It is a Protocol Error to - include the Authentication Data more than once. Refer to section 4.12 for more information about - extended authentication. - */ + /* + Followed by Binary Data containing authentication data. The contents of this data are defined by the + authentication method and the state of already exchanged authentication data. It is a Protocol Error to + include the Authentication Data more than once. Refer to section 4.12 for more information about + extended authentication. + */ PacketProperty.AUTHENTICATION_DATA); - private final Array userProperties; - private final String clientId; - private final String requestedClientId; - private final String reason; - private final String serverReference; - private final String responseInformation; - private final String authenticationMethod; - private final byte[] authenticationData; - private final QoS maxQos; + String clientId; - private final long requestedSessionExpiryInterval; - private final long sessionExpiryInterval; + MqttClientConnectionConfig connectionConfig; - private final int requestedKeepAlive; - private final int requestedReceiveMax; - private final int maximumPacketSize; - private final int receiveMax; - private final int topicAliasMaximum; - private final int keepAlive; + String responseInformation; + String reason; + String serverReference; - private final boolean retainAvailable; - private final boolean wildcardSubscriptionAvailable; - private final boolean subscriptionIdAvailable; - private final boolean sharedSubscriptionAvailable; + String authenticationMethod; + byte[] authenticationData; + + String requestedClientId; + long requestedSessionExpiryInterval; + int requestedKeepAlive; + int requestedReceiveMax; + + Array userProperties; public ConnectAck5OutPacket( + MqttClientConnectionConfig connectionConfig, ConnectAckReasonCode reasonCode, boolean sessionPresent, + String clientId, String requestedClientId, long requestedSessionExpiryInterval, int requestedKeepAlive, - int requestedReceiveMax, + int requestedReceiveMaxPublishes, String reason, String serverReference, String responseInformation, String authenticationMethod, byte[] authenticationData, - Array userProperties, - String clientId, - QoS maxQos, - long sessionExpiryInterval, - int maximumPacketSize, - int receiveMax, - int topicAliasMaximum, - int keepAlive, - boolean retainAvailable, - boolean wildcardSubscriptionAvailable, - boolean subscriptionIdAvailable, - boolean sharedSubscriptionAvailable) { + Array userProperties) { super(reasonCode, sessionPresent); + this.connectionConfig = connectionConfig; + this.clientId = clientId; this.requestedClientId = requestedClientId; this.requestedSessionExpiryInterval = requestedSessionExpiryInterval; this.requestedKeepAlive = requestedKeepAlive; - this.requestedReceiveMax = requestedReceiveMax; + this.requestedReceiveMax = requestedReceiveMaxPublishes; this.reason = reason; this.serverReference = serverReference; this.responseInformation = responseInformation; this.authenticationMethod = authenticationMethod; this.authenticationData = authenticationData; this.userProperties = userProperties; - this.clientId = clientId; - this.maxQos = maxQos; - this.sessionExpiryInterval = sessionExpiryInterval; - this.maximumPacketSize = maximumPacketSize; - this.receiveMax = receiveMax; - this.topicAliasMaximum = topicAliasMaximum; - this.keepAlive = keepAlive; - this.retainAvailable = retainAvailable; - this.wildcardSubscriptionAvailable = wildcardSubscriptionAvailable; - this.subscriptionIdAvailable = subscriptionIdAvailable; - this.sharedSubscriptionAvailable = sharedSubscriptionAvailable; } @Override @@ -309,12 +287,12 @@ protected byte reasonCodeValue() { } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901080 writeNotEmptyProperty(buffer, PacketProperty.REASON_STRING, reason); @@ -326,45 +304,45 @@ protected void writeProperties(ByteBuffer buffer) { writeProperty( buffer, PacketProperty.MAXIMUM_QOS, - maxQos.ordinal(), + connectionConfig.maxQos().ordinal(), MqttProperties.MAXIMUM_QOS_DEFAULT.ordinal()); writeProperty( buffer, PacketProperty.RETAIN_AVAILABLE, - retainAvailable, + connectionConfig.retainAvailable(), MqttProperties.RETAIN_AVAILABLE_DEFAULT); writeProperty( buffer, PacketProperty.SESSION_EXPIRY_INTERVAL, - sessionExpiryInterval, + connectionConfig.sessionExpiryInterval(), requestedSessionExpiryInterval); writeProperty(buffer, PacketProperty.ASSIGNED_CLIENT_IDENTIFIER, clientId, requestedClientId); - writeProperty(buffer, PacketProperty.RECEIVE_MAXIMUM, receiveMax, requestedReceiveMax); + writeProperty(buffer, PacketProperty.RECEIVE_MAXIMUM_PUBLISH, connectionConfig.receiveMaxPublishes(), requestedReceiveMax); writeProperty( buffer, PacketProperty.MAXIMUM_PACKET_SIZE, - maximumPacketSize, + connectionConfig.maxPacketSize(), MqttProperties.MAXIMUM_PACKET_SIZE_MAX); writeProperty( buffer, PacketProperty.TOPIC_ALIAS_MAXIMUM, - topicAliasMaximum, + connectionConfig.topicAliasMaxValue(), MqttProperties.TOPIC_ALIAS_MAXIMUM_DISABLED); writeProperty( buffer, PacketProperty.WILDCARD_SUBSCRIPTION_AVAILABLE, - wildcardSubscriptionAvailable, + connectionConfig.wildcardSubscriptionAvailable(), MqttProperties.WILDCARD_SUBSCRIPTION_AVAILABLE_DEFAULT); writeProperty( buffer, PacketProperty.SUBSCRIPTION_IDENTIFIER_AVAILABLE, - subscriptionIdAvailable, + connectionConfig.subscriptionIdAvailable(), MqttProperties.SUBSCRIPTION_IDENTIFIER_AVAILABLE_DEFAULT); writeProperty( buffer, PacketProperty.SHARED_SUBSCRIPTION_AVAILABLE, - sharedSubscriptionAvailable, + connectionConfig.sharedSubscriptionAvailable(), MqttProperties.SHARED_SUBSCRIPTION_AVAILABLE_DEFAULT); - writeProperty(buffer, PacketProperty.SERVER_KEEP_ALIVE, keepAlive, requestedKeepAlive); + writeProperty(buffer, PacketProperty.SERVER_KEEP_ALIVE, connectionConfig.keepAlive(), requestedKeepAlive); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/Disconnect5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/Disconnect5OutPacket.java index 87fa8599..7b801d33 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/Disconnect5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/Disconnect5OutPacket.java @@ -7,6 +7,7 @@ import javasabr.mqtt.model.PacketProperty; import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.reason.code.DisconnectReasonCode; +import javasabr.mqtt.network.MqttConnection; import javasabr.rlib.collections.array.Array; import lombok.RequiredArgsConstructor; @@ -17,35 +18,35 @@ public class Disconnect5OutPacket extends Disconnect311OutPacket { private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - If the Session Expiry Interval is absent, the Session Expiry Interval in the CONNECT packet is used. + /* + If the Session Expiry Interval is absent, the Session Expiry Interval in the CONNECT packet is used. - The Session Expiry Interval MUST NOT be sent on a DISCONNECT by the Server [MQTT-3.14.2-2]. + The Session Expiry Interval MUST NOT be sent on a DISCONNECT by the Server [MQTT-3.14.2-2]. - If the Session Expiry Interval in the CONNECT packet was zero, then it is a Protocol Error to set a non - zero Session Expiry Interval in the DISCONNECT packet sent by the Client. If such a non-zero Session - Expiry Interval is received by the Server, it does not treat it as a valid DISCONNECT packet. The Server - uses DISCONNECT with Reason Code 0x82 (Protocol Error) as described in - */ + If the Session Expiry Interval in the CONNECT packet was zero, then it is a Protocol Error to set a non + zero Session Expiry Interval in the DISCONNECT packet sent by the Client. If such a non-zero Session + Expiry Interval is received by the Server, it does not treat it as a valid DISCONNECT packet. The Server + uses DISCONNECT with Reason Code 0x82 (Protocol Error) as described in + */ PacketProperty.SESSION_EXPIRY_INTERVAL, - /* - The sender MUST NOT send this Property if it would increase the size of the DISCONNECT packet - beyond the Maximum Packet Size specified by the receiver [MQTT-3.14.2-3]. It is a Protocol Error to - include the Reason String more than once. - */ + /* + The sender MUST NOT send this Property if it would increase the size of the DISCONNECT packet + beyond the Maximum Packet Size specified by the receiver [MQTT-3.14.2-3]. It is a Protocol Error to + include the Reason String more than once. + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property may be used to provide additional diagnostic or other - information. The sender MUST NOT send this property if it would increase the size of the DISCONNECT - packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.14.2-4]. The User Property is - allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to - appear more than once. - */ + /* + Followed by UTF-8 String Pair. This property may be used to provide additional diagnostic or other + information. The sender MUST NOT send this property if it would increase the size of the DISCONNECT + packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.14.2-4]. The User Property is + allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to + appear more than once. + */ PacketProperty.USER_PROPERTY, - /* - The Server sends DISCONNECT including a Server Reference and Reason Code {0x9C (Use another - 2601 server)} or 0x9D (Server moved) as described in section 4.13. - */ + /* + The Server sends DISCONNECT including a Server Reference and Reason Code {0x9C (Use another + 2601 server)} or 0x9D (Server moved) as described in section 4.13. + */ PacketProperty.SERVER_REFERENCE); private final DisconnectReasonCode reasonCode; @@ -57,18 +58,18 @@ public class Disconnect5OutPacket extends Disconnect311OutPacket { private final long sessionExpiryInterval; @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901207 writeByte(buffer, reasonCode.getValue()); } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901209 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/MqttWritablePacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/MqttWritablePacket.java index 97590566..726510cd 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/MqttWritablePacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/MqttWritablePacket.java @@ -22,24 +22,24 @@ public abstract class MqttWritablePacket extends AbstractWritableNetworkPacket 0) { writeProperty(buffer, property, value); } } public void writeProperty(ByteBuffer buffer, PacketProperty property, String value) { - buffer.put(property.getId()); + buffer.put(property.id()); writeString(buffer, value); } public void writeProperty(ByteBuffer buffer, PacketProperty property, byte[] value) { - buffer.put(property.getId()); + buffer.put(property.id()); writeBytes(buffer, value); } - public void writeStringPairProperties( - ByteBuffer buffer, - PacketProperty property, - Array pairs) { - + public void writeStringPairProperties(ByteBuffer buffer, PacketProperty property, Array pairs) { if (pairs.isEmpty()) { return; } - for (StringPair pair : pairs) { - buffer.put(property.getId()); + buffer.put(property.id()); writeStringPair(buffer, pair); } } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/Publish311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/Publish311OutPacket.java index 45f35174..6c8c5e3e 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/Publish311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/Publish311OutPacket.java @@ -55,7 +55,7 @@ protected byte packetFlags() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc384800412 writeString(buffer, topicName); if (qos.ordinal() > QoS.AT_MOST_ONCE.ordinal()) { @@ -64,7 +64,7 @@ protected void writeVariableHeader(ByteBuffer buffer) { } @Override - protected void writePayload(ByteBuffer buffer) { + protected void writePayload(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc384800413 buffer.put(payload); } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/Publish5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/Publish5OutPacket.java index 18f3c879..0f239ddc 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/Publish5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/Publish5OutPacket.java @@ -170,12 +170,12 @@ public int expectedLength(MqttConnection connection) { } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc511988586 writeProperty(buffer, PacketProperty.PAYLOAD_FORMAT_INDICATOR, stringPayload); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishAck311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishAck311OutPacket.java index f72ff602..a0b137b0 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishAck311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishAck311OutPacket.java @@ -29,7 +29,7 @@ protected byte packetType() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718045 buffer.putShort((short) packetId); } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishAck5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishAck5OutPacket.java index 8147c731..06e0e938 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishAck5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishAck5OutPacket.java @@ -6,6 +6,7 @@ import javasabr.mqtt.model.PacketProperty; import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.reason.code.PublishAckReasonCode; +import javasabr.mqtt.network.MqttConnection; import javasabr.rlib.collections.array.Array; /** @@ -14,24 +15,24 @@ public class PublishAck5OutPacket extends PublishAck311OutPacket { private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is a human readable string designed for diagnostics and is not intended to be parsed by - the receiver. + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is a human readable string designed for diagnostics and is not intended to be parsed by + the receiver. - The sender uses this value to give additional information to the receiver. The sender MUST NOT send - this property if it would increase the size of the PUBACK packet beyond the Maximum Packet Size - specified by the receiver [MQTT-3.4.2-2]. It is a Protocol Error to include the Reason String more than - once. - */ + The sender uses this value to give additional information to the receiver. The sender MUST NOT send + this property if it would increase the size of the PUBACK packet beyond the Maximum Packet Size + specified by the receiver [MQTT-3.4.2-2]. It is a Protocol Error to include the Reason String more than + once. + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other - information. The sender MUST NOT send this property if it would increase the size of the PUBACK - packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.4.2-3]. The User Property is - allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to - appear more than once. - */ + /* + Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other + information. The sender MUST NOT send this property if it would increase the size of the PUBACK + packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.4.2-3]. The User Property is + allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to + appear more than once. + */ PacketProperty.USER_PROPERTY); private final Array userProperties; @@ -50,20 +51,19 @@ public PublishAck5OutPacket( } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeVariableHeader(ByteBuffer buffer) { - super.writeVariableHeader(buffer); + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { + super.writeVariableHeader(connection, buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901123 writeByte(buffer, reasonCode.getValue()); } @Override - protected void writeProperties(ByteBuffer buffer) { - + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901125 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); writeNotEmptyProperty(buffer, PacketProperty.REASON_STRING, reason); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishComplete311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishComplete311OutPacket.java index 51ebfcd3..91694f96 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishComplete311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishComplete311OutPacket.java @@ -26,7 +26,7 @@ protected byte packetType() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718083 writeShort(buffer, packetId); } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishComplete5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishComplete5OutPacket.java index 38d38efc..ed11e27c 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishComplete5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishComplete5OutPacket.java @@ -16,24 +16,24 @@ public class PublishComplete5OutPacket extends PublishComplete311OutPacket { private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is human readable, designed for diagnostics and SHOULD NOT be parsed by the - receiver. + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is human readable, designed for diagnostics and SHOULD NOT be parsed by the + receiver. - The sender uses this value to give additional information to the receiver. The sender MUST NOT send - this Property if it would increase the size of the PUBREL packet beyond the Maximum Packet Size - specified by the receiver [MQTT-3.6.2-2]. It is a Protocol Error to include the Reason String more than - once. - */ + The sender uses this value to give additional information to the receiver. The sender MUST NOT send + this Property if it would increase the size of the PUBREL packet beyond the Maximum Packet Size + specified by the receiver [MQTT-3.6.2-2]. It is a Protocol Error to include the Reason String more than + once. + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other - information for the PUBREL. The sender MUST NOT send this property if it would increase the size of the - PUBREL packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.6.2-3]. The User - Property is allowed to appear multiple times to represent multiple name, value pairs. The same name is - allowed to appear more than once - */ + /* + Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other + information for the PUBREL. The sender MUST NOT send this property if it would increase the size of the + PUBREL packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.6.2-3]. The User + Property is allowed to appear multiple times to represent multiple name, value pairs. The same name is + allowed to appear more than once + */ PacketProperty.USER_PROPERTY); private final Array userProperties; @@ -61,21 +61,21 @@ public int expectedLength(MqttConnection connection) { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { - super.writeVariableHeader(buffer); + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { + super.writeVariableHeader(connection, buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901154 writeByte(buffer, reasonCode.getValue()); } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { - super.writeProperties(buffer); + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { + super.writeProperties(connection, buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901155 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishReceived311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishReceived311OutPacket.java index cb5e2a76..c5d80ee9 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishReceived311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishReceived311OutPacket.java @@ -26,7 +26,7 @@ protected byte packetType() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718050 writeShort(buffer, packetId); } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishReceived5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishReceived5OutPacket.java index b276c20a..43bc5151 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishReceived5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishReceived5OutPacket.java @@ -16,24 +16,24 @@ public class PublishReceived5OutPacket extends PublishReceived311OutPacket { private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is human readable, designed for diagnostics and SHOULD NOT be parsed by the - receiver. + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is human readable, designed for diagnostics and SHOULD NOT be parsed by the + receiver. - The sender uses this value to give additional information to the receiver. The sender MUST NOT send - this Property if it would increase the size of the PUBREL packet beyond the Maximum Packet Size - specified by the receiver [MQTT-3.6.2-2]. It is a Protocol Error to include the Reason String more than - once. - */ + The sender uses this value to give additional information to the receiver. The sender MUST NOT send + this Property if it would increase the size of the PUBREL packet beyond the Maximum Packet Size + specified by the receiver [MQTT-3.6.2-2]. It is a Protocol Error to include the Reason String more than + once. + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other - information for the PUBREL. The sender MUST NOT send this property if it would increase the size of the - PUBREL packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.6.2-3]. The User - Property is allowed to appear multiple times to represent multiple name, value pairs. The same name is - allowed to appear more than once - */ + /* + Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other + information for the PUBREL. The sender MUST NOT send this property if it would increase the size of the + PUBREL packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.6.2-3]. The User + Property is allowed to appear multiple times to represent multiple name, value pairs. The same name is + allowed to appear more than once + */ PacketProperty.USER_PROPERTY); private final Array userProperties; @@ -61,21 +61,21 @@ public int expectedLength(MqttConnection connection) { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { - super.writeVariableHeader(buffer); + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { + super.writeVariableHeader(connection, buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901143 writeByte(buffer, reasonCode.getValue()); } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { - super.writeProperties(buffer); + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { + super.writeProperties(connection, buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901135 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishRelease311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishRelease311OutPacket.java index bddcffca..2cbaffe5 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishRelease311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishRelease311OutPacket.java @@ -31,7 +31,7 @@ public int expectedLength(MqttConnection connection) { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718055 writeShort(buffer, packetId); } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishRelease5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishRelease5OutPacket.java index f91bc27c..88879cb3 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/PublishRelease5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/PublishRelease5OutPacket.java @@ -15,24 +15,24 @@ public class PublishRelease5OutPacket extends PublishRelease311OutPacket { private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is human readable, designed for diagnostics and SHOULD NOT be parsed by the - receiver. + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is human readable, designed for diagnostics and SHOULD NOT be parsed by the + receiver. - The sender uses this value to give additional information to the receiver. The sender MUST NOT send - this Property if it would increase the size of the PUBREL packet beyond the Maximum Packet Size - specified by the receiver [MQTT-3.6.2-2]. It is a Protocol Error to include the Reason String more than - once. - */ + The sender uses this value to give additional information to the receiver. The sender MUST NOT send + this Property if it would increase the size of the PUBREL packet beyond the Maximum Packet Size + specified by the receiver [MQTT-3.6.2-2]. It is a Protocol Error to include the Reason String more than + once. + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other - information for the PUBREL. The sender MUST NOT send this property if it would increase the size of the - PUBREL packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.6.2-3]. The User - Property is allowed to appear multiple times to represent multiple name, value pairs. The same name is - allowed to appear more than once - */ + /* + Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other + information for the PUBREL. The sender MUST NOT send this property if it would increase the size of the + PUBREL packet beyond the Maximum Packet Size specified by the receiver [MQTT-3.6.2-3]. The User + Property is allowed to appear multiple times to represent multiple name, value pairs. The same name is + allowed to appear more than once + */ PacketProperty.USER_PROPERTY); private final Array userProperties; @@ -56,21 +56,21 @@ public int expectedLength(MqttConnection connection) { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { - super.writeVariableHeader(buffer); + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { + super.writeVariableHeader(connection, buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901144 writeByte(buffer, reasonCode.getValue()); } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { - super.writeProperties(buffer); + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { + super.writeProperties(connection, buffer); // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901145 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/Subscribe311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/Subscribe311OutPacket.java index 3ab13cdd..1e384b6c 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/Subscribe311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/Subscribe311OutPacket.java @@ -2,6 +2,7 @@ import java.nio.ByteBuffer; import javasabr.mqtt.model.subscriber.SubscribeTopicFilter; +import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.packet.PacketType; import javasabr.rlib.collections.array.Array; import lombok.RequiredArgsConstructor; @@ -23,13 +24,13 @@ protected byte packetType() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718065 writeShort(buffer, packetId); } @Override - protected void writePayload(ByteBuffer buffer) { + protected void writePayload(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718066 for (var topicFilter : topicFilters) { writeString(buffer, diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/Subscribe5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/Subscribe5OutPacket.java index e618c11e..49a75f65 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/Subscribe5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/Subscribe5OutPacket.java @@ -7,6 +7,7 @@ import javasabr.mqtt.model.PacketProperty; import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.subscriber.SubscribeTopicFilter; +import javasabr.mqtt.network.MqttConnection; import javasabr.rlib.collections.array.Array; /** @@ -15,21 +16,21 @@ public class Subscribe5OutPacket extends Subscribe311OutPacket { private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by a Variable Byte Integer representing the identifier of the subscription. The Subscription - Identifier can have the value of 1 to 268,435,455. It is a Protocol Error if the Subscription Identifier has a - value of 0. It is a Protocol Error to include the Subscription Identifier more than once. - - The Subscription Identifier is associated with any subscription created or modified as the result of this - SUBSCRIBE packet. If there is a Subscription Identifier, it is stored with the subscription. If this - property is - not specified, then the absence of a Subscription Identifier is stored with the subscription. - */ + /* + Followed by a Variable Byte Integer representing the identifier of the subscription. The Subscription + Identifier can have the value of 1 to 268,435,455. It is a Protocol Error if the Subscription Identifier has a + value of 0. It is a Protocol Error to include the Subscription Identifier more than once. + + The Subscription Identifier is associated with any subscription created or modified as the result of this + SUBSCRIBE packet. If there is a Subscription Identifier, it is stored with the subscription. If this + property is + not specified, then the absence of a Subscription Identifier is stored with the subscription. + */ PacketProperty.SUBSCRIPTION_IDENTIFIER, - /* - The User Property is allowed to appear multiple times to represent multiple name, value pairs. The same - name is allowed to appear more than once. - */ + /* + The User Property is allowed to appear multiple times to represent multiple name, value pairs. The same + name is allowed to appear more than once. + */ PacketProperty.USER_PROPERTY); // properties @@ -74,12 +75,12 @@ protected int buildSubscriptionOptions(SubscribeTopicFilter topicFilter) { } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901164 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); writeProperty( diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/SubscribeAck311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/SubscribeAck311OutPacket.java index 407ffcfc..59a11b94 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/SubscribeAck311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/SubscribeAck311OutPacket.java @@ -44,13 +44,13 @@ protected byte packetType() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718070 writeShort(buffer, packetId); } @Override - protected void writePayload(ByteBuffer buffer) { + protected void writePayload(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718071 for (var reasonCode : reasonCodes) { writeByte(buffer, reasonCode.getValue()); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/SubscribeAck5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/SubscribeAck5OutPacket.java index 6b48b501..bc45b019 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/SubscribeAck5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/SubscribeAck5OutPacket.java @@ -20,23 +20,23 @@ public class SubscribeAck5OutPacket extends SubscribeAck311OutPacket { } private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the - Client. + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the + Client. - The Server uses this value to give additional information to the Client. The Server MUST NOT send this - Property if it would increase the size of the SUBACK packet beyond the Maximum Packet Size specified - by the Client - */ + The Server uses this value to give additional information to the Client. The Server MUST NOT send this + Property if it would increase the size of the SUBACK packet beyond the Maximum Packet Size specified + by the Client + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other - information. The Server MUST NOT send this property if it would increase the size of the SUBACK packet - beyond the Maximum Packet Size specified by Client [MQTT-3.9.2-2]. The User Property is allowed to - appear multiple times to represent multiple name, value pairs. The same name is allowed to appear more - than once. - */ + /* + Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other + information. The Server MUST NOT send this property if it would increase the size of the SUBACK packet + beyond the Maximum Packet Size specified by Client [MQTT-3.9.2-2]. The User Property is allowed to + appear multiple times to represent multiple name, value pairs. The same name is allowed to appear more + than once. + */ PacketProperty.USER_PROPERTY); private final Array userProperties; @@ -58,12 +58,12 @@ public int expectedLength(MqttConnection connection) { } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901174 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/UnsubscribeAck311OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/UnsubscribeAck311OutPacket.java index 9c4706c3..8f53e68a 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/UnsubscribeAck311OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/UnsubscribeAck311OutPacket.java @@ -26,7 +26,7 @@ protected byte packetType() { } @Override - protected void writeVariableHeader(ByteBuffer buffer) { + protected void writeVariableHeader(MqttConnection connection, ByteBuffer buffer) { // http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718074 writeShort(buffer, packetId); } diff --git a/network/src/main/java/javasabr/mqtt/network/packet/out/UnsubscribeAck5OutPacket.java b/network/src/main/java/javasabr/mqtt/network/packet/out/UnsubscribeAck5OutPacket.java index 233916c4..e236e7c3 100644 --- a/network/src/main/java/javasabr/mqtt/network/packet/out/UnsubscribeAck5OutPacket.java +++ b/network/src/main/java/javasabr/mqtt/network/packet/out/UnsubscribeAck5OutPacket.java @@ -6,37 +6,41 @@ import javasabr.mqtt.model.PacketProperty; import javasabr.mqtt.model.data.type.StringPair; import javasabr.mqtt.model.reason.code.UnsubscribeAckReasonCode; +import javasabr.mqtt.network.MqttConnection; import javasabr.rlib.collections.array.Array; +import lombok.AccessLevel; +import lombok.experimental.FieldDefaults; /** * Unsubscribe acknowledgement. */ +@FieldDefaults(level = AccessLevel.PRIVATE, makeFinal = true) public class UnsubscribeAck5OutPacket extends UnsubscribeAck311OutPacket { private static final Set AVAILABLE_PROPERTIES = EnumSet.of( - /* - Followed by the UTF-8 Encoded String representing the reason associated with this response. This - Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the - Client. + /* + Followed by the UTF-8 Encoded String representing the reason associated with this response. This + Reason String is a human readable string designed for diagnostics and SHOULD NOT be parsed by the + Client. - The Server uses this value to give additional information to the Client. The Server MUST NOT send this - Property if it would increase the size of the UNSUBACK packet beyond the Maximum Packet Size - specified by the Client [MQTT-3.11.2-1]. It is a Protocol Error to include the Reason String more than - once. - */ + The Server uses this value to give additional information to the Client. The Server MUST NOT send this + Property if it would increase the size of the UNSUBACK packet beyond the Maximum Packet Size + specified by the Client [MQTT-3.11.2-1]. It is a Protocol Error to include the Reason String more than + once. + */ PacketProperty.REASON_STRING, - /* - Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other - information. The Server MUST NOT send this property if it would increase the size of the UNSUBACK - packet beyond the Maximum Packet Size specified by the Client [MQTT-3.11.2-2]. The User Property is - allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to - appear more than once. - */ + /* + Followed by UTF-8 String Pair. This property can be used to provide additional diagnostic or other + information. The Server MUST NOT send this property if it would increase the size of the UNSUBACK + packet beyond the Maximum Packet Size specified by the Client [MQTT-3.11.2-2]. The User Property is + allowed to appear multiple times to represent multiple name, value pairs. The same name is allowed to + appear more than once. + */ PacketProperty.USER_PROPERTY); - private final Array reasonCodes; - private final Array userProperties; - private final String reason; + Array reasonCodes; + Array userProperties; + String reason; public UnsubscribeAck5OutPacket( int packetId, @@ -50,12 +54,12 @@ public UnsubscribeAck5OutPacket( } @Override - protected boolean isPropertiesSupported() { + protected boolean isPropertiesSupported(MqttConnection connection) { return true; } @Override - protected void writeProperties(ByteBuffer buffer) { + protected void writeProperties(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901182 writeStringPairProperties(buffer, PacketProperty.USER_PROPERTY, userProperties); @@ -63,7 +67,7 @@ protected void writeProperties(ByteBuffer buffer) { } @Override - protected void writePayload(ByteBuffer buffer) { + protected void writePayload(MqttConnection connection, ByteBuffer buffer) { // https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901185 for (var reasonCode : reasonCodes) { writeByte(buffer, reasonCode.getValue()); diff --git a/network/src/main/java/javasabr/mqtt/network/utils/MqttDataUtils.java b/network/src/main/java/javasabr/mqtt/network/utils/MqttDataUtils.java index 4cff8a80..fd2e18c8 100644 --- a/network/src/main/java/javasabr/mqtt/network/utils/MqttDataUtils.java +++ b/network/src/main/java/javasabr/mqtt/network/utils/MqttDataUtils.java @@ -5,6 +5,7 @@ public class MqttDataUtils { public static int MAX_MBI = 268_435_455; + public static int UNKNOWN_LENGTH = -1; /** * Write a MQTT multi-byte integer to byte buffer. @@ -41,7 +42,7 @@ public static ByteBuffer writeMbi(int number, ByteBuffer buffer) { * Read a MQTT multi-byte integer from byte buffer. * https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901011 * - * @return -1 if buffer's data isn't enough to read integer. + * @return {@link #UNKNOWN_LENGTH} if buffer's data isn't enough to read integer. */ public static int readMbi(ByteBuffer buffer) { diff --git a/service/src/main/java/javasabr/mqtt/service/handler/client/AbstractMqttClientReleaseHandler.java b/service/src/main/java/javasabr/mqtt/service/handler/client/AbstractMqttClientReleaseHandler.java index ae66975c..7f3c9237 100644 --- a/service/src/main/java/javasabr/mqtt/service/handler/client/AbstractMqttClientReleaseHandler.java +++ b/service/src/main/java/javasabr/mqtt/service/handler/client/AbstractMqttClientReleaseHandler.java @@ -1,11 +1,12 @@ package javasabr.mqtt.service.handler.client; +import javasabr.mqtt.model.MqttClientConnectionConfig; import javasabr.mqtt.network.client.AbstractMqttClient; import javasabr.mqtt.network.MqttClient.UnsafeMqttClient; import javasabr.mqtt.service.ClientIdRegistry; import javasabr.mqtt.service.MqttSessionService; import javasabr.mqtt.service.SubscriptionService; -import javasabr.mqtt.network.handler.client.MqttClientReleaseHandler; +import javasabr.mqtt.network.handler.MqttClientReleaseHandler; import javasabr.rlib.common.util.StringUtils; import lombok.CustomLog; import lombok.RequiredArgsConstructor; @@ -43,8 +44,9 @@ protected Mono releaseImpl(T client) { if (session != null) { subscriptionService.cleanSubscriptions(client, session); - if (client.connectionConfig().sessionsEnabled()) { - asyncActions = sessionService.store(clientId, session, client.sessionExpiryInterval()); + MqttClientConnectionConfig connectionConfig = client.connectionConfig(); + if (connectionConfig.sessionsEnabled()) { + asyncActions = sessionService.store(clientId, session, connectionConfig.sessionExpiryInterval()); client.session(null); } } diff --git a/service/src/main/java/javasabr/mqtt/service/handler/in/AbstractPacketHandler.java b/service/src/main/java/javasabr/mqtt/service/handler/in/AbstractPacketHandler.java index 53c6c93e..1374fdb1 100644 --- a/service/src/main/java/javasabr/mqtt/service/handler/in/AbstractPacketHandler.java +++ b/service/src/main/java/javasabr/mqtt/service/handler/in/AbstractPacketHandler.java @@ -1,7 +1,7 @@ package javasabr.mqtt.service.handler.in; import javasabr.mqtt.network.MqttClient.UnsafeMqttClient; -import javasabr.mqtt.network.handler.packet.in.PacketInHandler; +import javasabr.mqtt.network.handler.PacketInHandler; import javasabr.mqtt.network.packet.in.MqttReadablePacket; public abstract class AbstractPacketHandler implements diff --git a/service/src/main/java/javasabr/mqtt/service/handler/in/ConnectInPacketHandler.java b/service/src/main/java/javasabr/mqtt/service/handler/in/ConnectInPacketHandler.java index e3ec90bc..68fe0856 100644 --- a/service/src/main/java/javasabr/mqtt/service/handler/in/ConnectInPacketHandler.java +++ b/service/src/main/java/javasabr/mqtt/service/handler/in/ConnectInPacketHandler.java @@ -11,8 +11,11 @@ import static javasabr.mqtt.model.reason.code.ConnectAckReasonCode.CLIENT_IDENTIFIER_NOT_VALID; import static javasabr.mqtt.base.utils.ReactorUtils.ifTrue; +import javasabr.mqtt.model.MqttClientConnectionConfig; +import javasabr.mqtt.model.MqttServerConnectionConfig; import javasabr.mqtt.model.exception.ConnectionRejectException; import javasabr.mqtt.model.exception.MalformedPacketMqttException; +import javasabr.mqtt.network.MqttConnection; import javasabr.mqtt.network.MqttSession; import javasabr.mqtt.model.MqttVersion; import javasabr.mqtt.model.reason.code.ConnectAckReasonCode; @@ -38,16 +41,12 @@ public class ConnectInPacketHandler extends AbstractPacketHandler registerClient(UnsafeMqttClient client, ConnectInPacket packet) { - var requestedClientId = packet.getClientId(); - + String requestedClientId = packet.clientId(); if (StringUtils.isNotEmpty(requestedClientId)) { return clientIdRegistry .register(requestedClientId) .map(ifTrue(requestedClientId, client::clientId)); - } else { - - var mqttVersion = client - .connection() - .mqttVersion(); + } - // we can't assign generated client if for mqtt version less than 5 - if (mqttVersion.ordinal() < MqttVersion.MQTT_5.ordinal()) { - return Mono.just(false); - } + MqttVersion mqttVersion = client + .connection() + .clientConnectionConfig() + .mqttVersion(); - return clientIdRegistry - .generate() - .flatMap(newClientId -> clientIdRegistry - .register(newClientId) - .map(ifTrue(newClientId, client::clientId))); + // we can't assign generated client id for mqtt version less than 5 + if (mqttVersion.isLowerThan(MqttVersion.MQTT_5)) { + return Mono.just(false); } + + return clientIdRegistry + .generate() + .flatMap(newClientId -> clientIdRegistry + .register(newClientId) + .map(ifTrue(newClientId, client::clientId))); } private Mono restoreSession(UnsafeMqttClient client, ConnectInPacket packet) { - if (packet.isCleanStart()) { + if (packet.cleanStart()) { return mqttSessionService .create(client.clientId()) .flatMap(session -> onConnected(client, packet, session, false)); @@ -96,58 +94,73 @@ private Mono restoreSession(UnsafeMqttClient client, ConnectInPacket pa } } - private Mono onConnected( - UnsafeMqttClient client, - ConnectInPacket packet, - MqttSession session, - boolean sessionRestored) { + private void resolveClientConnectionConfig(UnsafeMqttClient client, ConnectInPacket packet) { - var connection = client.connection(); - var config = connection.config(); - - // if it was closed in parallel - if (connection.closed() && config.sessionsEnabled()) { - // store the session again - return mqttSessionService.store(client.clientId(), session, config.defaultSessionExpiryInterval()); - } + MqttConnection connection = client.connection(); + MqttServerConnectionConfig serverConfig = connection.serverConnectionConfig(); // select result keep alive time - var minimalKeepAliveTime = Math.max(config.minKeepAliveTime(), packet.getKeepAlive()); - var keepAlive = config.keepAliveEnabled() ? minimalKeepAliveTime : SERVER_KEEP_ALIVE_DISABLED; + int minimalKeepAliveTime = Math.max(serverConfig.minKeepAliveTime(), packet.keepAlive()); + int keepAlive = serverConfig.keepAliveEnabled() ? minimalKeepAliveTime : SERVER_KEEP_ALIVE_DISABLED; // select result session expiry interval - var sessionExpiryInterval = config.sessionsEnabled() - ? packet.getSessionExpiryInterval() + long sessionExpiryInterval = serverConfig.sessionsEnabled() + ? packet.sessionExpiryInterval() : SESSION_EXPIRY_INTERVAL_DISABLED; if (sessionExpiryInterval == SESSION_EXPIRY_INTERVAL_UNDEFINED) { - sessionExpiryInterval = config.defaultSessionExpiryInterval(); + sessionExpiryInterval = serverConfig.defaultSessionExpiryInterval(); } // select result receive max - var receiveMax = packet.getReceiveMax() == RECEIVE_MAXIMUM_UNDEFINED - ? config.receiveMaximum() - : Math.min(packet.getReceiveMax(), config.receiveMaximum()); + int receiveMaxPublishes = packet.receiveMaxPublishes() == RECEIVE_MAXIMUM_UNDEFINED + ? serverConfig.receiveMaxPublishes() + : Math.min(packet.receiveMaxPublishes(), serverConfig.receiveMaxPublishes()); // select result maximum packet size - var maximumPacketSize = packet.getMaximumPacketSize() == MAXIMUM_PACKET_SIZE_UNDEFINED - ? config.maximumPacketSize() - : Math.min(packet.getMaximumPacketSize(), config.maximumPacketSize()); + var maximumPacketSize = packet.maxPacketSize() == MAXIMUM_PACKET_SIZE_UNDEFINED + ? serverConfig.maxPacketSize() + : Math.min(packet.maxPacketSize(), serverConfig.maxPacketSize()); // select result topic alias maximum - var topicAliasMaximum = packet.getTopicAliasMaximum() == TOPIC_ALIAS_MAXIMUM_UNDEFINED + var topicAliasMaxValue = packet.topicAliasMaxValue() == TOPIC_ALIAS_MAXIMUM_UNDEFINED ? TOPIC_ALIAS_MAXIMUM_DISABLED - : Math.min(packet.getTopicAliasMaximum(), config.topicAliasMaximum()); + : Math.min(packet.topicAliasMaxValue(), serverConfig.topicAliasMaxValue()); - client.session(session); - client.configure( + connection.configure(new MqttClientConnectionConfig( + serverConfig.maxQos(), + packet.mqttVersion(), sessionExpiryInterval, - receiveMax, + receiveMaxPublishes, maximumPacketSize, - topicAliasMaximum, + topicAliasMaxValue, keepAlive, - packet.isRequestResponseInformation(), - packet.isRequestProblemInformation()); + packet.requestResponseInformation(), + packet.requestProblemInformation(), + serverConfig.sessionsEnabled(), + serverConfig.retainAvailable(), + serverConfig.wildcardSubscriptionAvailable(), + serverConfig.subscriptionIdAvailable(), + serverConfig.sharedSubscriptionAvailable())); + } + + private Mono onConnected( + UnsafeMqttClient client, + ConnectInPacket packet, + MqttSession session, + boolean sessionRestored) { + + MqttConnection connection = client.connection(); + MqttServerConnectionConfig serverConfig = connection.serverConnectionConfig(); + MqttClientConnectionConfig clientConfig = connection.clientConnectionConfig(); + + // if it was closed in parallel + if (connection.closed() && serverConfig.sessionsEnabled()) { + // store the session again + return mqttSessionService.store(client.clientId(), session, clientConfig.sessionExpiryInterval()); + } + + client.session(session); var connectAck = client .packetOutFactory() @@ -155,10 +168,10 @@ private Mono onConnected( client, ConnectAckReasonCode.SUCCESS, sessionRestored, - packet.getClientId(), - packet.getSessionExpiryInterval(), - packet.getKeepAlive(), - packet.getReceiveMax()); + packet.clientId(), + packet.sessionExpiryInterval(), + packet.keepAlive(), + packet.receiveMaxPublishes()); subscriptionService.restoreSubscriptions(client, session); @@ -179,17 +192,14 @@ private boolean onSentConnAck(UnsafeMqttClient client, MqttSession session, bool } private boolean checkPacketException(UnsafeMqttClient client, ConnectInPacket packet) { - - var exception = packet.getException(); - - if (exception instanceof ConnectionRejectException) { - client.reject(((ConnectionRejectException) exception).getReasonCode()); + Exception exception = packet.exception(); + if (exception instanceof ConnectionRejectException cre) { + client.reject(cre.getReasonCode()); return true; } else if (exception instanceof MalformedPacketMqttException) { client.reject(ConnectAckReasonCode.MALFORMED_PACKET); return true; } - return false; } } diff --git a/service/src/main/java/javasabr/mqtt/service/handler/publish/in/AbstractPublishInHandler.java b/service/src/main/java/javasabr/mqtt/service/handler/publish/in/AbstractPublishInHandler.java index 486aea08..5da6935b 100644 --- a/service/src/main/java/javasabr/mqtt/service/handler/publish/in/AbstractPublishInHandler.java +++ b/service/src/main/java/javasabr/mqtt/service/handler/publish/in/AbstractPublishInHandler.java @@ -5,7 +5,7 @@ import javasabr.mqtt.model.QoS; import javasabr.mqtt.model.subscriber.SingleSubscriber; import javasabr.mqtt.network.MqttClient; -import javasabr.mqtt.network.handler.publish.PublishInHandler; +import javasabr.mqtt.network.handler.PublishInHandler; import javasabr.mqtt.network.packet.in.PublishInPacket; import javasabr.mqtt.service.SubscriptionService; import lombok.RequiredArgsConstructor; diff --git a/service/src/main/java/javasabr/mqtt/service/handler/publish/out/AbstractPublishOutHandler.java b/service/src/main/java/javasabr/mqtt/service/handler/publish/out/AbstractPublishOutHandler.java index 2233497a..c5702785 100644 --- a/service/src/main/java/javasabr/mqtt/service/handler/publish/out/AbstractPublishOutHandler.java +++ b/service/src/main/java/javasabr/mqtt/service/handler/publish/out/AbstractPublishOutHandler.java @@ -49,6 +49,6 @@ void sendPublish(MqttClient client, PublishInPacket packet, int packetId, boolea packet.isPayloadFormatIndicator(), packet.getResponseTopic(), packet.getCorrelationData(), - packet.getUserProperties())); + packet.userProperties())); } } diff --git a/service/src/main/java/javasabr/mqtt/service/impl/DefaultPublishingService.java b/service/src/main/java/javasabr/mqtt/service/impl/DefaultPublishingService.java index 33c061fa..6caaa836 100644 --- a/service/src/main/java/javasabr/mqtt/service/impl/DefaultPublishingService.java +++ b/service/src/main/java/javasabr/mqtt/service/impl/DefaultPublishingService.java @@ -1,7 +1,7 @@ package javasabr.mqtt.service.impl; import javasabr.mqtt.network.MqttClient; -import javasabr.mqtt.network.handler.publish.PublishInHandler; +import javasabr.mqtt.network.handler.PublishInHandler; import javasabr.mqtt.network.packet.in.PublishInPacket; import javasabr.mqtt.service.PublishingService; import lombok.RequiredArgsConstructor; diff --git a/service/src/main/java/javasabr/mqtt/service/impl/SimpleSubscriptionService.java b/service/src/main/java/javasabr/mqtt/service/impl/SimpleSubscriptionService.java index 78265cf3..668c452d 100644 --- a/service/src/main/java/javasabr/mqtt/service/impl/SimpleSubscriptionService.java +++ b/service/src/main/java/javasabr/mqtt/service/impl/SimpleSubscriptionService.java @@ -11,7 +11,7 @@ import static javasabr.mqtt.model.utils.TopicUtils.isInvalid; import static javasabr.mqtt.model.utils.TopicUtils.isShared; -import javasabr.mqtt.model.MqttConnectionConfig; +import javasabr.mqtt.model.MqttClientConnectionConfig; import javasabr.mqtt.model.ActionResult; import javasabr.mqtt.network.MqttSession; import javasabr.mqtt.model.subscriber.SingleSubscriber; @@ -68,12 +68,12 @@ private SubscribeAckReasonCode addSubscription(SubscribeTopicFilter subscribe, M return null; } - MqttConnectionConfig config = client.connectionConfig(); + MqttClientConnectionConfig connectionConfig = client.connectionConfig(); TopicFilter topic = subscribe.getTopicFilter(); - if (!config.sharedSubscriptionAvailable() && isShared(topic)) { + if (!connectionConfig.sharedSubscriptionAvailable() && isShared(topic)) { return SHARED_SUBSCRIPTIONS_NOT_SUPPORTED; - } else if (!config.wildcardSubscriptionAvailable() && hasWildcard(topic)) { + } else if (!connectionConfig.wildcardSubscriptionAvailable() && hasWildcard(topic)) { return WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED; } else if (isInvalid(topic)) { return UNSPECIFIED_ERROR;