1 /** 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * SPDX-License-Identifier: Apache-2.0. 4 */ 5 package software.amazon.awssdk.crt.mqtt5.packets; 6 7 import software.amazon.awssdk.crt.mqtt5.QOS; 8 9 import java.util.List; 10 import java.util.Map; 11 import java.util.function.Function; 12 import java.util.stream.Collectors; 13 import java.util.stream.Stream; 14 15 /** 16 * Data model of an <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901100">MQTT5 PUBLISH</a> packet 17 */ 18 public class PublishPacket { 19 20 private byte[] payload; 21 private QOS packetQOS; 22 private Boolean retain; 23 private String topic; 24 private PayloadFormatIndicator payloadFormat; 25 private Long messageExpiryIntervalSeconds; 26 private Long topicAlias; 27 private String responseTopic; 28 private byte[] correlationData; 29 private List<Long> subscriptionIdentifiers; 30 private String contentType; 31 private List<UserProperty> userProperties; 32 33 /** 34 * Returns the payload of the publish message. 35 * 36 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901119">MQTT5 Publish Payload</a> 37 * 38 * @return The payload of the publish message. 39 */ getPayload()40 public byte[] getPayload() { 41 return this.payload; 42 } 43 44 /** 45 * Sent publishes - Returns the MQTT quality of service level this message should be delivered with. 46 * 47 * Received publishes - Returns the MQTT quality of service level this message was delivered at. 48 * 49 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901103">MQTT5 QoS</a> 50 * 51 * @return The MQTT quality of service associated with this PUBLISH packet. 52 */ getQOS()53 public QOS getQOS() { 54 return this.packetQOS; 55 } 56 57 /** 58 * Returns true if this is a retained message, false otherwise. 59 * 60 * Always set on received publishes; on sent publishes, null implies false. 61 * 62 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901104">MQTT5 Retain</a> 63 * 64 * @return True if this is a retained message, false otherwise. 65 */ getRetain()66 public Boolean getRetain() { 67 return this.retain; 68 } 69 70 /** 71 * Sent publishes - Returns the topic this message should be published to. 72 * 73 * Received publishes - Returns the topic this message was published to. 74 * 75 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107">MQTT5 Topic Name</a> 76 * @return The topic associated with this PUBLISH packet. 77 */ getTopic()78 public String getTopic() { 79 return this.topic; 80 } 81 82 /** 83 * Returns the property specifying the format of the payload data. The Mqtt5Client does not enforce or use this 84 * value in a meaningful way. 85 * 86 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111">MQTT5 Payload Format Indicator</a> 87 * 88 * @return Property specifying the format of the payload data. 89 */ getPayloadFormat()90 public PayloadFormatIndicator getPayloadFormat() { 91 return this.payloadFormat; 92 } 93 94 /** 95 * Sent publishes - Returns the maximum amount of time allowed to elapse for message delivery before the server 96 * should instead delete the message (relative to a recipient). 97 * 98 * Received publishes - Returns the remaining amount of time (from the server's perspective) before the message would 99 * have been deleted relative to the subscribing client. 100 * 101 * If left null, indicates no expiration timeout. 102 * 103 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901112">MQTT5 Message Expiry Interval</a> 104 * 105 * @return The message expiry interval associated with this PublishPacket. 106 */ getMessageExpiryIntervalSeconds()107 public Long getMessageExpiryIntervalSeconds() { 108 return this.messageExpiryIntervalSeconds; 109 } 110 111 /** 112 * Sent publishes - topic alias to use, if possible, when encoding this packet. Only used if the 113 * client's outbound topic aliasing mode is set to Manual. 114 * 115 * Received publishes - topic alias used by the server when transmitting the publish to the client. 116 * 117 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113">MQTT5 Topic Alias</a> 118 * 119 * @return The topic alias associated with this PublishPacket. 120 */ getTopicAlias()121 public Long getTopicAlias() { 122 return this.topicAlias; 123 } 124 125 /** 126 * Returns a opaque topic string intended to assist with request/response implementations. Not internally meaningful to 127 * MQTT5 or this client. 128 * 129 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901114">MQTT5 Response Topic</a> 130 * 131 * @return Opaque topic string intended to assist with request/response implementations. 132 */ getResponseTopic()133 public String getResponseTopic() { 134 return this.responseTopic; 135 } 136 137 /** 138 * Returns a opaque binary data used to correlate between publish messages, as a potential method for request-response 139 * implementation. Not internally meaningful to MQTT5. 140 * 141 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901115">MQTT5 Correlation Data</a> 142 * 143 * @return Opaque binary data used to correlate between publish messages. 144 */ getCorrelationData()145 public byte[] getCorrelationData() { 146 return this.correlationData; 147 } 148 149 /** 150 * Returns a property specifying the content type of the payload. Not internally meaningful to MQTT5. 151 * 152 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901118">MQTT5 Content Type</a> 153 * 154 * @return Property specifying the content type of the payload. 155 */ getContentType()156 public String getContentType() { 157 return this.contentType; 158 } 159 160 /** 161 * Returns a list of MQTT5 user properties included with the packet. 162 * 163 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116">MQTT5 User Property</a> 164 * 165 * @return List of MQTT5 user properties included with the packet. 166 */ getUserProperties()167 public List<UserProperty> getUserProperties() { 168 return this.userProperties; 169 } 170 171 /** 172 * Sent publishes - Ignored 173 * 174 * Received publishes - Returns the subscription identifiers of all the subscriptions this message matched. 175 * 176 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901117">MQTT5 Subscription Identifier</a> 177 * 178 * @return the subscription identifiers of all the subscriptions this message matched. 179 */ getSubscriptionIdentifiers()180 public List<Long> getSubscriptionIdentifiers() { 181 return this.subscriptionIdentifiers; 182 } 183 184 /** 185 * Creates a Mqtt5Client options instance 186 * @throws CrtRuntimeException If the system is unable to allocate space for a native MQTT client structure 187 */ PublishPacket(PublishPacketBuilder builder)188 private PublishPacket(PublishPacketBuilder builder) { 189 this.payload = builder.payload; 190 this.packetQOS = builder.packetQOS; 191 this.retain = builder.retain; 192 this.topic = builder.topic; 193 this.payloadFormat = builder.payloadFormat; 194 this.messageExpiryIntervalSeconds = builder.messageExpiryIntervalSeconds; 195 this.topicAlias = builder.topicAlias; 196 this.responseTopic = builder.responseTopic; 197 this.correlationData = builder.correlationData; 198 this.contentType = builder.contentType; 199 this.userProperties = builder.userProperties; 200 } 201 PublishPacket()202 private PublishPacket() {} 203 204 /** 205 * A native, JNI-only helper function for more easily setting the QOS 206 * @param QOSValue A int representing the QoS 207 */ nativeSetQOS(int QOSValue)208 private void nativeSetQOS(int QOSValue) { 209 this.packetQOS = QOS.getEnumValueFromInteger(QOSValue); 210 } 211 212 /** 213 * A native, JNI-only helper function for more easily setting the payload format indicator 214 * @param payloadFormatIndicator A int representing the payload format 215 */ nativeSetPayloadFormatIndicator(int payloadFormatIndicator)216 private void nativeSetPayloadFormatIndicator(int payloadFormatIndicator) { 217 this.payloadFormat = PayloadFormatIndicator.getEnumValueFromInteger(payloadFormatIndicator); 218 } 219 220 /******************************************************************************* 221 * builder 222 ******************************************************************************/ 223 224 /** 225 * Optional property describing a PublishPacket payload's format. 226 * 227 * Enum values match <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111">MQTT5 spec</a> encoding values. 228 */ 229 public enum PayloadFormatIndicator { 230 231 /** 232 * The payload is arbitrary binary data 233 */ 234 BYTES(0), 235 236 /** 237 * The payload is a well-formed utf-8 string value. 238 */ 239 UTF8(1); 240 241 private int indicator; 242 PayloadFormatIndicator(int value)243 private PayloadFormatIndicator(int value) { 244 indicator = value; 245 } 246 247 /** 248 * @return The native enum integer value associated with this Java enum value 249 */ getValue()250 public int getValue() { 251 return indicator; 252 } 253 254 /** 255 * Creates a Java PayloadFormatIndicator enum value from a native integer value. 256 * 257 * @param value native integer value for PayloadFormatIndicator 258 * @return a new PayloadFormatIndicator value 259 */ getEnumValueFromInteger(int value)260 public static PayloadFormatIndicator getEnumValueFromInteger(int value) { 261 PayloadFormatIndicator enumValue = enumMapping.get(value); 262 if (enumValue != null) { 263 return enumValue; 264 } 265 throw new RuntimeException("Illegal PayloadFormatIndicator"); 266 } 267 buildEnumMapping()268 private static Map<Integer, PayloadFormatIndicator> buildEnumMapping() { 269 return Stream.of(PayloadFormatIndicator.values()) 270 .collect(Collectors.toMap(PayloadFormatIndicator::getValue, Function.identity())); 271 } 272 273 private static Map<Integer, PayloadFormatIndicator> enumMapping = buildEnumMapping(); 274 } 275 276 /** 277 * A class to that allows for the creation of a PublishPacket. Set all of the settings you want in the 278 * packet and then use the build() function to get a PublishPacket populated with the settings 279 * defined in the builder. 280 */ 281 static final public class PublishPacketBuilder { 282 283 private byte[] payload; 284 private QOS packetQOS; 285 private Boolean retain; 286 private String topic; 287 private PayloadFormatIndicator payloadFormat; 288 private Long messageExpiryIntervalSeconds; 289 private Long topicAlias; 290 private String responseTopic; 291 private byte[] correlationData; 292 private String contentType; 293 private List<UserProperty> userProperties; 294 295 /** 296 * Sets the payload for the publish message. 297 * 298 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901119">MQTT5 Publish Payload</a> 299 * 300 * @param payload The payload for the publish message. 301 * @return The PublishPacketBuilder after setting the payload. 302 */ withPayload(byte[] payload)303 public PublishPacketBuilder withPayload(byte[] payload) { 304 this.payload = payload; 305 return this; 306 } 307 308 /** 309 * Sets the MQTT quality of service level the message should be delivered with. 310 * 311 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901103">MQTT5 QoS</a> 312 * 313 * @param packetQOS The MQTT quality of service level the message should be delivered with. 314 * @return The PublishPacketBuilder after setting the QOS. 315 */ withQOS(QOS packetQOS)316 public PublishPacketBuilder withQOS(QOS packetQOS) { 317 this.packetQOS = packetQOS; 318 return this; 319 } 320 321 /** 322 * Sets if this should be a retained message. 323 * Null implies false. 324 * 325 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901104">MQTT5 Retain</a> 326 * 327 * @param retain if this is a retained message. 328 * @return The PublishPacketBuilder after setting the retain setting. 329 */ withRetain(Boolean retain)330 public PublishPacketBuilder withRetain(Boolean retain) { 331 this.retain = retain; 332 return this; 333 } 334 335 /** 336 * Sets the topic this message should be published to. 337 * 338 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901107">MQTT5 Topic Name</a> 339 * 340 * @param topic The topic this message should be published to. 341 * @return The PublishPacketBuilder after setting the topic. 342 */ withTopic(String topic)343 public PublishPacketBuilder withTopic(String topic) { 344 this.topic = topic; 345 return this; 346 } 347 348 /** 349 * Sets the property specifying the format of the payload data. The Mqtt5Client does not enforce or use this 350 * value in a meaningful way. 351 * 352 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901111">MQTT5 Payload Format Indicator</a> 353 * 354 * @param payloadFormat Property specifying the format of the payload data 355 * @return The PublishPacketBuilder after setting the payload format. 356 */ withPayloadFormat(PayloadFormatIndicator payloadFormat)357 public PublishPacketBuilder withPayloadFormat(PayloadFormatIndicator payloadFormat) { 358 this.payloadFormat = payloadFormat; 359 return this; 360 } 361 362 /** 363 * Sets the maximum amount of time allowed to elapse for message delivery before the server 364 * should instead delete the message (relative to a recipient). 365 * 366 * If left null, indicates no expiration timeout. 367 * 368 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901112">MQTT5 Message Expiry Interval</a> 369 * 370 * @param messageExpiryIntervalSeconds The maximum amount of time allowed to elapse for message delivery before the server 371 * should instead delete the message (relative to a recipient). 372 * @return The PublishPacketBuilder after setting the message expiry interval. 373 */ withMessageExpiryIntervalSeconds(Long messageExpiryIntervalSeconds)374 public PublishPacketBuilder withMessageExpiryIntervalSeconds(Long messageExpiryIntervalSeconds) { 375 this.messageExpiryIntervalSeconds = messageExpiryIntervalSeconds; 376 return this; 377 } 378 379 /** 380 * Sets the topic alias to use when sending this publish. Will only be used if the outbound topic aliasing 381 * behavior has been set to Manual. 382 * 383 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113">MQTT5 Topic Alias</a> 384 * 385 * @param topicAlias alias value to use. Must be greater than 0 and less than 65536. 386 * 387 * @return The PublishPacketBuilder after setting the topic alias. 388 */ withTopicAlias(long topicAlias)389 public PublishPacketBuilder withTopicAlias(long topicAlias) { 390 this.topicAlias = topicAlias; 391 return this; 392 } 393 394 /** 395 * Sets the opaque topic string intended to assist with request/response implementations. Not internally meaningful to 396 * MQTT5 or this client. 397 * 398 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901114">MQTT5 Response Topic</a> 399 * @param responseTopic Topic string intended to assist with request/response implementations 400 * @return The PublishPacketBuilder after setting the response topic. 401 */ withResponseTopic(String responseTopic)402 public PublishPacketBuilder withResponseTopic(String responseTopic) { 403 this.responseTopic = responseTopic; 404 return this; 405 } 406 407 /** 408 * Sets the opaque binary data used to correlate between publish messages, as a potential method for request-response 409 * implementation. Not internally meaningful to MQTT5. 410 * 411 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901115">MQTT5 Correlation Data</a> 412 * 413 * @param correlationData Opaque binary data used to correlate between publish messages 414 * @return The PublishPacketBuilder after setting the correlation data. 415 */ withCorrelationData(byte[] correlationData)416 public PublishPacketBuilder withCorrelationData(byte[] correlationData) { 417 this.correlationData = correlationData; 418 return this; 419 } 420 421 /** 422 * Sets the property specifying the content type of the payload. Not internally meaningful to MQTT5. 423 * 424 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901118">MQTT5 Content Type</a> 425 * 426 * @param contentType Property specifying the content type of the payload 427 * @return The PublishPacketBuilder after setting the content type. 428 */ withContentType(String contentType)429 public PublishPacketBuilder withContentType(String contentType) { 430 this.contentType = contentType; 431 return this; 432 } 433 434 /** 435 * Sets the list of MQTT5 user properties included with the packet. 436 * 437 * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901116">MQTT5 User Property</a> 438 * 439 * @param userProperties List of MQTT5 user properties included with the packet. 440 * @return The PublishPacketBuilder after setting the user properties. 441 */ withUserProperties(List<UserProperty> userProperties)442 public PublishPacketBuilder withUserProperties(List<UserProperty> userProperties) { 443 this.userProperties = userProperties; 444 return this; 445 } 446 447 /** 448 * Creates a new PublishPacketBuilder so a PublishPacket can be created. 449 */ PublishPacketBuilder()450 public PublishPacketBuilder() {} 451 452 /** 453 * Creates a new PublishPacket using the settings set in the builder. 454 * 455 * @return The PublishPacket created from the builder 456 */ build()457 public PublishPacket build() { 458 return new PublishPacket(this); 459 } 460 } 461 } 462