Topic Aliasing Support (#722)
Co-authored-by: Bret Ambrose <[email protected]>
diff --git a/src/main/java/software/amazon/awssdk/crt/mqtt5/Mqtt5ClientOptions.java b/src/main/java/software/amazon/awssdk/crt/mqtt5/Mqtt5ClientOptions.java
index 10c227b..db54ca1 100644
--- a/src/main/java/software/amazon/awssdk/crt/mqtt5/Mqtt5ClientOptions.java
+++ b/src/main/java/software/amazon/awssdk/crt/mqtt5/Mqtt5ClientOptions.java
@@ -48,6 +48,7 @@
private LifecycleEvents lifecycleEvents;
private Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketHandshakeTransform;
private PublishEvents publishEvents;
+ private TopicAliasingOptions topicAliasingOptions;
/**
* Returns the host name of the MQTT server to connect to.
@@ -258,6 +259,15 @@
}
/**
+ * Returns the topic aliasing options to be used by the client
+ *
+ * @return the topic aliasing options to be used by the client
+ */
+ public TopicAliasingOptions getTopicAliasingOptions() {
+ return this.topicAliasingOptions;
+ }
+
+ /**
* Creates a Mqtt5ClientOptionsBuilder instance
* @param builder The builder to get the Mqtt5ClientOptions values from
*/
@@ -282,6 +292,7 @@
this.lifecycleEvents = builder.lifecycleEvents;
this.websocketHandshakeTransform = builder.websocketHandshakeTransform;
this.publishEvents = builder.publishEvents;
+ this.topicAliasingOptions = builder.topicAliasingOptions;
}
/*******************************************************************************
@@ -579,6 +590,7 @@
private LifecycleEvents lifecycleEvents;
private Consumer<Mqtt5WebsocketHandshakeTransformArgs> websocketHandshakeTransform;
private PublishEvents publishEvents;
+ private TopicAliasingOptions topicAliasingOptions;
/**
* Sets the host name of the MQTT server to connect to.
@@ -836,6 +848,17 @@
}
/**
+ * Sets the topic aliasing options for clients constructed from this builder
+ *
+ * @param options topic aliasing options that the client should use
+ * @return The Mqtt5ClientOptionsBuilder object
+ */
+ public Mqtt5ClientOptionsBuilder withTopicAliasingOptions(TopicAliasingOptions options) {
+ this.topicAliasingOptions = options;
+ return this;
+ }
+
+ /**
* Creates a new Mqtt5ClientOptionsBuilder instance
*
* @param hostName The host name of the MQTT server to connect to.
diff --git a/src/main/java/software/amazon/awssdk/crt/mqtt5/NegotiatedSettings.java b/src/main/java/software/amazon/awssdk/crt/mqtt5/NegotiatedSettings.java
index f6c2785..27a63bf 100644
--- a/src/main/java/software/amazon/awssdk/crt/mqtt5/NegotiatedSettings.java
+++ b/src/main/java/software/amazon/awssdk/crt/mqtt5/NegotiatedSettings.java
@@ -22,6 +22,8 @@
private long sessionExpiryInterval;
private int receiveMaximumFromServer;
private long maximumPacketSizeToServer;
+ private int topicAliasMaximumToServer;
+ private int topicAliasMaximumToClient;
private int serverKeepAlive;
private boolean retainAvailable;
private boolean wildcardSubscriptionsAvailable;
@@ -59,6 +61,21 @@
}
/**
+ * @return returns the maximum allowed topic alias value on publishes sent from client to server
+ */
+ public int getTopicAliasMaximumToServer() {
+ return this.topicAliasMaximumToServer;
+ }
+
+ /**
+ * @return returns the maximum allowed topic alias value on publishes sent from server to client
+ */
+ public int getTopicAliasMaximumToClient() {
+ return this.topicAliasMaximumToClient;
+ }
+
+
+ /**
* Returns the maximum amount of time in seconds between client packets. The client should use PINGREQs to ensure this
* limit is not breached. The server will disconnect the client for inactivity if no MQTT packet is received
* in a time interval equal to 1.5 x this value.
diff --git a/src/main/java/software/amazon/awssdk/crt/mqtt5/TopicAliasingOptions.java b/src/main/java/software/amazon/awssdk/crt/mqtt5/TopicAliasingOptions.java
new file mode 100644
index 0000000..73b85b0
--- /dev/null
+++ b/src/main/java/software/amazon/awssdk/crt/mqtt5/TopicAliasingOptions.java
@@ -0,0 +1,222 @@
+package software.amazon.awssdk.crt.mqtt5;
+
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Configuration for all client topic aliasing behavior.
+ */
+public class TopicAliasingOptions {
+
+ private OutboundTopicAliasBehaviorType outboundBehavior;
+ private Integer outboundCacheMaxSize;
+ private InboundTopicAliasBehaviorType inboundBehavior;
+ private Integer inboundCacheMaxSize;
+
+ /**
+ * Default constructor
+ */
+ public TopicAliasingOptions() {
+ this.outboundBehavior = OutboundTopicAliasBehaviorType.Default;
+ this.outboundCacheMaxSize = 0;
+ this.inboundBehavior = InboundTopicAliasBehaviorType.Default;
+ this.inboundCacheMaxSize = 0;
+ }
+
+ /**
+ * Controls what kind of outbound topic aliasing behavior the client should attempt to use.
+ *
+ * If topic aliasing is not supported by the server, this setting has no effect and any attempts to directly
+ * manipulate the topic alias id in outbound publishes will be ignored.
+ *
+ * By default, outbound topic aliasing is disabled.
+ *
+ * @param behavior outbound topic alias behavior to use
+ *
+ * @return the topic aliasing options object
+ */
+ public TopicAliasingOptions withOutboundBehavior(OutboundTopicAliasBehaviorType behavior) {
+ this.outboundBehavior = behavior;
+ return this;
+ }
+
+ /**
+ * If outbound topic aliasing is set to LRU, this controls the maximum size of the cache. If outbound topic
+ * aliasing is set to LRU and this is zero or undefined, a sensible default is used (25). If outbound topic
+ * aliasing is not set to LRU, then this setting has no effect.
+ *
+ * The final size of the cache is determined by the minimum of this setting and the value of the
+ * topic_alias_maximum property of the received CONNACK. If the received CONNACK does not have an explicit
+ * positive value for that field, outbound topic aliasing is disabled for the duration of that connection.
+ *
+ * @param size maximum size to use for the outbound alias cache
+ *
+ * @return the topic aliasing options object
+ */
+ public TopicAliasingOptions withOutboundCacheMaxSize(int size) {
+ this.outboundCacheMaxSize = size;
+ return this;
+ }
+
+ /**
+ * Controls whether or not the client allows the broker to use topic aliasing when sending publishes. Even if
+ * inbound topic aliasing is enabled, it is up to the server to choose whether or not to use it.
+ *
+ * If left undefined, then inbound topic aliasing is disabled.
+ *
+ * @param behavior inbound topic alias behavior to use
+ *
+ * @return the topic aliasing options object
+ */
+ public TopicAliasingOptions withInboundBehavior(InboundTopicAliasBehaviorType behavior) {
+ this.inboundBehavior = behavior;
+ return this;
+ }
+
+ /**
+ * If inbound topic aliasing is enabled, this will control the size of the inbound alias cache. If inbound
+ * aliases are enabled and this is zero or undefined, then a sensible default will be used (25). If inbound
+ * aliases are disabled, this setting has no effect.
+ *
+ * Behaviorally, this value overrides anything present in the topic_alias_maximum field of
+ * the CONNECT packet options.
+ *
+ * @param size maximum size to use for the inbound alias cache
+ *
+ * @return the topic aliasing options object
+ */
+ public TopicAliasingOptions withInboundCacheMaxSize(int size) {
+ this.inboundCacheMaxSize = size;
+ return this;
+ }
+
+ /**
+ * An enumeration that controls how the client applies topic aliasing to outbound publish packets.
+ *
+ * Topic alias behavior is described in <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113">MQTT5 Topic Aliasing</a>
+ */
+ public enum OutboundTopicAliasBehaviorType {
+
+ /**
+ * Maps to Disabled. This keeps the client from being broken (by default) if the broker
+ * topic aliasing implementation has a problem.
+ */
+ Default(0),
+
+ /**
+ * Outbound aliasing is the user's responsibility. Client will cache and use
+ * previously-established aliases if they fall within the negotiated limits of the connection.
+ *
+ * The user must still always submit a full topic in their publishes because disconnections disrupt
+ * topic alias mappings unpredictably. The client will properly use a requested alias when the most-recently-seen
+ * binding for a topic alias value matches the alias and topic in the publish packet.
+ */
+ Manual(1),
+
+ /**
+ * (Recommended) The client will ignore any user-specified topic aliasing and instead use an LRU cache to drive
+ * alias usage.
+ */
+ LRU(2),
+
+ /**
+ * Completely disable outbound topic aliasing.
+ */
+ Disabled(3);
+
+ private int value;
+
+ private OutboundTopicAliasBehaviorType(int value) {
+ this.value = value;
+ }
+
+ /**
+ * @return The native enum integer value associated with this Java enum value
+ */
+ public int getValue() {
+ return this.value;
+ }
+
+ /**
+ * Creates a Java OutboundTopicAliasBehaviorType enum value from a native integer value.
+ *
+ * @param value native integer value for the OutboundTopicAliasBehaviorType value
+ * @return a new OutboundTopicAliasBehaviorType value
+ */
+ public static OutboundTopicAliasBehaviorType getEnumValueFromInteger(int value) {
+ OutboundTopicAliasBehaviorType enumValue = enumMapping.get(value);
+ if (enumValue != null) {
+ return enumValue;
+ }
+ throw new RuntimeException("Illegal OutboundTopicAliasBehaviorType");
+ }
+
+ private static Map<Integer, OutboundTopicAliasBehaviorType> buildEnumMapping() {
+ return Stream.of(OutboundTopicAliasBehaviorType.values())
+ .collect(Collectors.toMap(OutboundTopicAliasBehaviorType::getValue, Function.identity()));
+ }
+
+ private static Map<Integer, OutboundTopicAliasBehaviorType> enumMapping = buildEnumMapping();
+ }
+
+ /**
+ * An enumeration that controls whether or not the client allows the broker to send publishes that use topic
+ * aliasing.
+ *
+ * Topic alias behavior is described in https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113
+ */
+ public enum InboundTopicAliasBehaviorType {
+
+ /**
+ * Maps to Disabled. This keeps the client from being broken (by default) if the broker
+ * topic aliasing implementation has a problem.
+ */
+ Default(0),
+
+ /**
+ * Allow the server to send PUBLISH packets to the client that use topic aliasing
+ */
+ Enabled(1),
+
+ /**
+ * Forbid the server from sending PUBLISH packets to the client that use topic aliasing
+ */
+ Disabled(2);
+
+ private int value;
+
+ private InboundTopicAliasBehaviorType(int value) {
+ this.value = value;
+ }
+
+ /**
+ * @return The native enum integer value associated with this Java enum value
+ */
+ public int getValue() {
+ return this.value;
+ }
+
+ /**
+ * Creates a Java InboundTopicAliasBehaviorType enum value from a native integer value.
+ *
+ * @param value native integer value for the InboundTopicAliasBehaviorType value
+ * @return a new InboundTopicAliasBehaviorType value
+ */
+ public static InboundTopicAliasBehaviorType getEnumValueFromInteger(int value) {
+ InboundTopicAliasBehaviorType enumValue = enumMapping.get(value);
+ if (enumValue != null) {
+ return enumValue;
+ }
+ throw new RuntimeException("Illegal InboundTopicAliasBehaviorType");
+ }
+
+ private static Map<Integer, InboundTopicAliasBehaviorType> buildEnumMapping() {
+ return Stream.of(InboundTopicAliasBehaviorType.values())
+ .collect(Collectors.toMap(InboundTopicAliasBehaviorType::getValue, Function.identity()));
+ }
+
+ private static Map<Integer, InboundTopicAliasBehaviorType> enumMapping = buildEnumMapping();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/software/amazon/awssdk/crt/mqtt5/packets/ConnAckPacket.java b/src/main/java/software/amazon/awssdk/crt/mqtt5/packets/ConnAckPacket.java
index aa4c8c3..cab1436 100644
--- a/src/main/java/software/amazon/awssdk/crt/mqtt5/packets/ConnAckPacket.java
+++ b/src/main/java/software/amazon/awssdk/crt/mqtt5/packets/ConnAckPacket.java
@@ -27,6 +27,7 @@
private Boolean retainAvailable;
private Long maximumPacketSize;
private String assignedClientIdentifier;
+ private Integer topicAliasMaximum;
private String reasonString;
private List<UserProperty> userProperties;
@@ -133,6 +134,17 @@
}
/**
+ * Returns the maximum topic alias value that the server will accept from the client.
+ *
+ * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901088">MQTT5 Topic Alias Maximum</a>
+ *
+ * @return maximum allowed topic alias value
+ */
+ public Integer getTopicAliasMaximum() {
+ return this.topicAliasMaximum;
+ }
+
+ /**
* Returns additional diagnostic information about the result of the connection attempt.
*
* See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901089">MQTT5 Reason String</a>
diff --git a/src/main/java/software/amazon/awssdk/crt/mqtt5/packets/PublishPacket.java b/src/main/java/software/amazon/awssdk/crt/mqtt5/packets/PublishPacket.java
index 8c3036f..c8ff2ae 100644
--- a/src/main/java/software/amazon/awssdk/crt/mqtt5/packets/PublishPacket.java
+++ b/src/main/java/software/amazon/awssdk/crt/mqtt5/packets/PublishPacket.java
@@ -23,6 +23,7 @@
private String topic;
private PayloadFormatIndicator payloadFormat;
private Long messageExpiryIntervalSeconds;
+ private Long topicAlias;
private String responseTopic;
private byte[] correlationData;
private List<Long> subscriptionIdentifiers;
@@ -108,6 +109,20 @@
}
/**
+ * Sent publishes - topic alias to use, if possible, when encoding this packet. Only used if the
+ * client's outbound topic aliasing mode is set to Manual.
+ *
+ * Received publishes - topic alias used by the server when transmitting the publish to the client.
+ *
+ * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113">MQTT5 Topic Alias</a>
+ *
+ * @return The topic alias associated with this PublishPacket.
+ */
+ public Long getTopicAlias() {
+ return this.topicAlias;
+ }
+
+ /**
* Returns a opaque topic string intended to assist with request/response implementations. Not internally meaningful to
* MQTT5 or this client.
*
@@ -177,6 +192,7 @@
this.topic = builder.topic;
this.payloadFormat = builder.payloadFormat;
this.messageExpiryIntervalSeconds = builder.messageExpiryIntervalSeconds;
+ this.topicAlias = builder.topicAlias;
this.responseTopic = builder.responseTopic;
this.correlationData = builder.correlationData;
this.contentType = builder.contentType;
@@ -270,6 +286,7 @@
private String topic;
private PayloadFormatIndicator payloadFormat;
private Long messageExpiryIntervalSeconds;
+ private Long topicAlias;
private String responseTopic;
private byte[] correlationData;
private String contentType;
@@ -360,6 +377,21 @@
}
/**
+ * Sets the topic alias to use when sending this publish. Will only be used if the outbound topic aliasing
+ * behavior has been set to Manual.
+ *
+ * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901113">MQTT5 Topic Alias</a>
+ *
+ * @param topicAlias alias value to use. Must be greater than 0 and less than 65536.
+ *
+ * @return The PublishPacketBuilder after setting the topic alias.
+ */
+ public PublishPacketBuilder withTopicAlias(long topicAlias) {
+ this.topicAlias = topicAlias;
+ return this;
+ }
+
+ /**
* Sets the opaque topic string intended to assist with request/response implementations. Not internally meaningful to
* MQTT5 or this client.
*
diff --git a/src/native/java_class_ids.c b/src/native/java_class_ids.c
index 53ed5ad..b143cce 100644
--- a/src/native/java_class_ids.c
+++ b/src/native/java_class_ids.c
@@ -1010,6 +1010,9 @@
mqtt5_connack_packet_properties.connack_assigned_client_identifier_field_id = (*env)->GetFieldID(
env, mqtt5_connack_packet_properties.connack_packet_class, "assignedClientIdentifier", "Ljava/lang/String;");
AWS_FATAL_ASSERT(mqtt5_connack_packet_properties.connack_assigned_client_identifier_field_id);
+ mqtt5_connack_packet_properties.connack_topic_alias_maximum_field_id = (*env)->GetFieldID(
+ env, mqtt5_connack_packet_properties.connack_packet_class, "topicAliasMaximum", "Ljava/lang/Integer;");
+ AWS_FATAL_ASSERT(mqtt5_connack_packet_properties.connack_topic_alias_maximum_field_id);
mqtt5_connack_packet_properties.connack_reason_string_field_id = (*env)->GetFieldID(
env, mqtt5_connack_packet_properties.connack_packet_class, "reasonString", "Ljava/lang/String;");
AWS_FATAL_ASSERT(mqtt5_connack_packet_properties.connack_reason_string_field_id);
@@ -1285,6 +1288,9 @@
mqtt5_publish_packet_properties.publish_message_expiry_interval_seconds_field_id = (*env)->GetFieldID(
env, mqtt5_publish_packet_properties.publish_packet_class, "messageExpiryIntervalSeconds", "Ljava/lang/Long;");
AWS_FATAL_ASSERT(mqtt5_publish_packet_properties.publish_message_expiry_interval_seconds_field_id);
+ mqtt5_publish_packet_properties.publish_topic_alias_field_id =
+ (*env)->GetFieldID(env, mqtt5_publish_packet_properties.publish_packet_class, "topicAlias", "Ljava/lang/Long;");
+ AWS_FATAL_ASSERT(mqtt5_publish_packet_properties.publish_topic_alias_field_id);
mqtt5_publish_packet_properties.publish_response_topic_field_id = (*env)->GetFieldID(
env, mqtt5_publish_packet_properties.publish_packet_class, "responseTopic", "Ljava/lang/String;");
AWS_FATAL_ASSERT(mqtt5_publish_packet_properties.publish_response_topic_field_id);
@@ -1354,6 +1360,14 @@
(*env)->GetFieldID(
env, mqtt5_negotiated_settings_properties.negotiated_settings_class, "maximumPacketSizeToServer", "J");
AWS_FATAL_ASSERT(mqtt5_negotiated_settings_properties.negotiated_settings_maximum_packet_size_to_server_field_id);
+ mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_server_field_id =
+ (*env)->GetFieldID(
+ env, mqtt5_negotiated_settings_properties.negotiated_settings_class, "topicAliasMaximumToServer", "I");
+ AWS_FATAL_ASSERT(mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_server_field_id);
+ mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_client_field_id =
+ (*env)->GetFieldID(
+ env, mqtt5_negotiated_settings_properties.negotiated_settings_class, "topicAliasMaximumToClient", "I");
+ AWS_FATAL_ASSERT(mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_client_field_id);
mqtt5_negotiated_settings_properties.negotiated_settings_server_keep_alive_field_id =
(*env)->GetFieldID(env, mqtt5_negotiated_settings_properties.negotiated_settings_class, "serverKeepAlive", "I");
AWS_FATAL_ASSERT(mqtt5_negotiated_settings_properties.negotiated_settings_server_keep_alive_field_id);
@@ -1564,6 +1578,48 @@
"lifecycleEvents",
"Lsoftware/amazon/awssdk/crt/mqtt5/Mqtt5ClientOptions$LifecycleEvents;");
AWS_FATAL_ASSERT(mqtt5_client_options_properties.lifecycle_events_field_id);
+ mqtt5_client_options_properties.topic_aliasing_options_field_id = (*env)->GetFieldID(
+ env,
+ mqtt5_client_options_properties.client_options_class,
+ "topicAliasingOptions",
+ "Lsoftware/amazon/awssdk/crt/mqtt5/TopicAliasingOptions;");
+ AWS_FATAL_ASSERT(mqtt5_client_options_properties.topic_aliasing_options_field_id);
+}
+
+struct java_aws_mqtt5_topic_aliasing_options_properties mqtt5_topic_aliasing_options_properties;
+static void s_cache_topic_aliasing_options(JNIEnv *env) {
+ jclass cls = (*env)->FindClass(env, "software/amazon/awssdk/crt/mqtt5/TopicAliasingOptions");
+ AWS_FATAL_ASSERT(cls);
+ mqtt5_topic_aliasing_options_properties.mqtt5_topic_aliasing_options_class = (*env)->NewGlobalRef(env, cls);
+ AWS_FATAL_ASSERT(mqtt5_topic_aliasing_options_properties.mqtt5_topic_aliasing_options_class);
+
+ mqtt5_topic_aliasing_options_properties.outbound_behavior_field_id = (*env)->GetFieldID(
+ env,
+ mqtt5_topic_aliasing_options_properties.mqtt5_topic_aliasing_options_class,
+ "outboundBehavior",
+ "Lsoftware/amazon/awssdk/crt/mqtt5/TopicAliasingOptions$OutboundTopicAliasBehaviorType;");
+ AWS_FATAL_ASSERT(mqtt5_topic_aliasing_options_properties.outbound_behavior_field_id);
+
+ mqtt5_topic_aliasing_options_properties.outbound_cache_max_size_field_id = (*env)->GetFieldID(
+ env,
+ mqtt5_topic_aliasing_options_properties.mqtt5_topic_aliasing_options_class,
+ "outboundCacheMaxSize",
+ "Ljava/lang/Integer;");
+ AWS_FATAL_ASSERT(mqtt5_topic_aliasing_options_properties.outbound_cache_max_size_field_id);
+
+ mqtt5_topic_aliasing_options_properties.inbound_behavior_field_id = (*env)->GetFieldID(
+ env,
+ mqtt5_topic_aliasing_options_properties.mqtt5_topic_aliasing_options_class,
+ "inboundBehavior",
+ "Lsoftware/amazon/awssdk/crt/mqtt5/TopicAliasingOptions$InboundTopicAliasBehaviorType;");
+ AWS_FATAL_ASSERT(mqtt5_topic_aliasing_options_properties.inbound_behavior_field_id);
+
+ mqtt5_topic_aliasing_options_properties.inbound_cache_max_size_field_id = (*env)->GetFieldID(
+ env,
+ mqtt5_topic_aliasing_options_properties.mqtt5_topic_aliasing_options_class,
+ "inboundCacheMaxSize",
+ "Ljava/lang/Integer;");
+ AWS_FATAL_ASSERT(mqtt5_topic_aliasing_options_properties.inbound_cache_max_size_field_id);
}
struct java_aws_mqtt5_client_properties mqtt5_client_properties;
@@ -1682,6 +1738,43 @@
AWS_FATAL_ASSERT(mqtt5_client_jitter_mode_properties.client_get_value_id);
}
+struct java_aws_mqtt5_outbound_topic_alias_behavior_type_properties mqtt5_outbound_topic_alias_behavior_type_properties;
+
+static void s_cache_mqtt5_outbound_topic_alias_behavior_type(JNIEnv *env) {
+ jclass cls =
+ (*env)->FindClass(env, "software/amazon/awssdk/crt/mqtt5/TopicAliasingOptions$OutboundTopicAliasBehaviorType");
+ AWS_FATAL_ASSERT(cls);
+ mqtt5_outbound_topic_alias_behavior_type_properties.mqtt5_outbound_topic_alias_behavior_type_class =
+ (*env)->NewGlobalRef(env, cls);
+ AWS_FATAL_ASSERT(
+ mqtt5_outbound_topic_alias_behavior_type_properties.mqtt5_outbound_topic_alias_behavior_type_class);
+ // Functions
+ mqtt5_outbound_topic_alias_behavior_type_properties.get_value_method_id = (*env)->GetMethodID(
+ env,
+ mqtt5_outbound_topic_alias_behavior_type_properties.mqtt5_outbound_topic_alias_behavior_type_class,
+ "getValue",
+ "()I");
+ AWS_FATAL_ASSERT(mqtt5_outbound_topic_alias_behavior_type_properties.get_value_method_id);
+}
+
+struct java_aws_mqtt5_inbound_topic_alias_behavior_type_properties mqtt5_inbound_topic_alias_behavior_type_properties;
+
+static void s_cache_mqtt5_inbound_topic_alias_behavior_type(JNIEnv *env) {
+ jclass cls =
+ (*env)->FindClass(env, "software/amazon/awssdk/crt/mqtt5/TopicAliasingOptions$InboundTopicAliasBehaviorType");
+ AWS_FATAL_ASSERT(cls);
+ mqtt5_inbound_topic_alias_behavior_type_properties.mqtt5_inbound_topic_alias_behavior_type_class =
+ (*env)->NewGlobalRef(env, cls);
+ AWS_FATAL_ASSERT(mqtt5_inbound_topic_alias_behavior_type_properties.mqtt5_inbound_topic_alias_behavior_type_class);
+ // Functions
+ mqtt5_inbound_topic_alias_behavior_type_properties.get_value_method_id = (*env)->GetMethodID(
+ env,
+ mqtt5_inbound_topic_alias_behavior_type_properties.mqtt5_inbound_topic_alias_behavior_type_class,
+ "getValue",
+ "()I");
+ AWS_FATAL_ASSERT(mqtt5_inbound_topic_alias_behavior_type_properties.get_value_method_id);
+}
+
struct java_aws_mqtt5_subscribe_packet_properties mqtt5_subscribe_packet_properties;
static void s_cache_mqtt5_subscribe_packet(JNIEnv *env) {
@@ -2236,6 +2329,9 @@
s_cache_boxed_boolean(env);
s_cache_boxed_list(env);
s_cache_boxed_array_list(env);
+ s_cache_mqtt5_outbound_topic_alias_behavior_type(env);
+ s_cache_mqtt5_inbound_topic_alias_behavior_type(env);
+ s_cache_topic_aliasing_options(env);
}
static aws_thread_once s_cache_once_init = AWS_THREAD_ONCE_STATIC_INIT;
diff --git a/src/native/java_class_ids.h b/src/native/java_class_ids.h
index fe0b2de..bca694a 100644
--- a/src/native/java_class_ids.h
+++ b/src/native/java_class_ids.h
@@ -463,6 +463,7 @@
jfieldID connack_retain_available_field_id;
jfieldID connack_maximum_packet_size_field_id;
jfieldID connack_assigned_client_identifier_field_id;
+ jfieldID connack_topic_alias_maximum_field_id;
jfieldID connack_reason_string_field_id;
jfieldID connack_wildcard_subscriptions_available_field_id;
jfieldID connack_subscription_identifiers_available_field_id;
@@ -561,6 +562,7 @@
jfieldID publish_topic_field_id;
jfieldID publish_payload_format_field_id;
jfieldID publish_message_expiry_interval_seconds_field_id;
+ jfieldID publish_topic_alias_field_id;
jfieldID publish_response_topic_field_id;
jfieldID publish_correlation_data_field_id;
jfieldID publish_content_type_field_id;
@@ -588,6 +590,8 @@
jfieldID negotiated_settings_session_expiry_interval_field_id;
jfieldID negotiated_settings_receive_maximum_from_server_field_id;
jfieldID negotiated_settings_maximum_packet_size_to_server_field_id;
+ jfieldID negotiated_settings_topic_alias_maximum_to_server_field_id;
+ jfieldID negotiated_settings_topic_alias_maximum_to_client_field_id;
jfieldID negotiated_settings_server_keep_alive_field_id;
jfieldID negotiated_settings_retain_available_field_id;
jfieldID negotiated_settings_wildcard_subscriptions_available_field_id;
@@ -650,6 +654,7 @@
jfieldID ack_timeout_seconds_field_id;
jfieldID publish_events_field_id;
jfieldID lifecycle_events_field_id;
+ jfieldID topic_aliasing_options_field_id;
};
extern struct java_aws_mqtt5_client_options_properties mqtt5_client_options_properties;
@@ -703,6 +708,33 @@
};
extern struct java_aws_mqtt5_client_jitter_mode_properties mqtt5_client_jitter_mode_properties;
+/* mqtt5.Mqtt5ClientOptions.OutboundTopicAliasBehaviorType */
+struct java_aws_mqtt5_outbound_topic_alias_behavior_type_properties {
+ jclass mqtt5_outbound_topic_alias_behavior_type_class;
+ jmethodID get_value_method_id;
+};
+extern struct java_aws_mqtt5_outbound_topic_alias_behavior_type_properties
+ mqtt5_outbound_topic_alias_behavior_type_properties;
+
+/* mqtt5.Mqtt5ClientOptions.InboundTopicAliasBehaviorType */
+struct java_aws_mqtt5_inbound_topic_alias_behavior_type_properties {
+ jclass mqtt5_inbound_topic_alias_behavior_type_class;
+ jmethodID get_value_method_id;
+};
+extern struct java_aws_mqtt5_inbound_topic_alias_behavior_type_properties
+ mqtt5_inbound_topic_alias_behavior_type_properties;
+
+/* mqtt5.Mqtt5ClientOptions.TopicAliasingOptions */
+struct java_aws_mqtt5_topic_aliasing_options_properties {
+ jclass mqtt5_topic_aliasing_options_class;
+
+ jfieldID outbound_behavior_field_id;
+ jfieldID outbound_cache_max_size_field_id;
+ jfieldID inbound_behavior_field_id;
+ jfieldID inbound_cache_max_size_field_id;
+};
+extern struct java_aws_mqtt5_topic_aliasing_options_properties mqtt5_topic_aliasing_options_properties;
+
/* mqtt5.packets.SubscribePacket */
struct java_aws_mqtt5_subscribe_packet_properties {
jclass subscribe_packet_class;
diff --git a/src/native/mqtt5_client.c b/src/native/mqtt5_client.c
index 2f9a92c..0a42126 100644
--- a/src/native/mqtt5_client.c
+++ b/src/native/mqtt5_client.c
@@ -1612,6 +1612,70 @@
s_ws_handshake_destroy(ws_handshake);
}
+static int s_initialize_topic_aliasing_options(
+ JNIEnv *env,
+ struct aws_mqtt5_client_topic_alias_options *topic_aliasing_options,
+ jobject jni_topic_aliasing_options) {
+
+ jobject jni_outbound_behavior = (*env)->GetObjectField(
+ env, jni_topic_aliasing_options, mqtt5_topic_aliasing_options_properties.outbound_behavior_field_id);
+ if (jni_outbound_behavior != NULL) {
+ jint enum_value = (*env)->CallIntMethod(
+ env, jni_outbound_behavior, mqtt5_outbound_topic_alias_behavior_type_properties.get_value_method_id);
+ if (aws_jni_check_and_clear_exception(env)) {
+ AWS_LOGF_ERROR(AWS_LS_MQTT_CLIENT, "Error getting native value from OutboundTopicAliasBehaviorType");
+ return aws_raise_error(AWS_ERROR_INVALID_STATE);
+ }
+
+ topic_aliasing_options->outbound_topic_alias_behavior =
+ (enum aws_mqtt5_client_outbound_topic_alias_behavior_type)enum_value;
+ }
+
+ jobject jni_outbound_cache_max_size = (*env)->GetObjectField(
+ env, jni_topic_aliasing_options, mqtt5_topic_aliasing_options_properties.outbound_cache_max_size_field_id);
+ if (jni_outbound_cache_max_size != NULL) {
+ jint int_value =
+ (*env)->CallIntMethod(env, jni_outbound_cache_max_size, boxed_integer_properties.integer_get_value_id);
+
+ if (int_value < 0 || int_value > UINT16_MAX) {
+ AWS_LOGF_ERROR(AWS_LS_MQTT_CLIENT, "Invalid outbound cache size value: %d", int_value);
+ return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ }
+
+ topic_aliasing_options->outbound_alias_cache_max_size = (uint16_t)int_value;
+ }
+
+ jobject jni_inbound_behavior = (*env)->GetObjectField(
+ env, jni_topic_aliasing_options, mqtt5_topic_aliasing_options_properties.inbound_behavior_field_id);
+ if (jni_inbound_behavior != NULL) {
+ jint enum_value = (*env)->CallIntMethod(
+ env, jni_inbound_behavior, mqtt5_inbound_topic_alias_behavior_type_properties.get_value_method_id);
+ if (aws_jni_check_and_clear_exception(env)) {
+ AWS_LOGF_ERROR(AWS_LS_MQTT_CLIENT, "Error getting native value from InboundTopicAliasBehaviorType");
+ return aws_raise_error(AWS_ERROR_INVALID_STATE);
+ }
+
+ topic_aliasing_options->inbound_topic_alias_behavior =
+ (enum aws_mqtt5_client_inbound_topic_alias_behavior_type)enum_value;
+ }
+
+ jobject jni_inbound_cache_max_size = (*env)->GetObjectField(
+ env, jni_topic_aliasing_options, mqtt5_topic_aliasing_options_properties.inbound_cache_max_size_field_id);
+ if (jni_inbound_cache_max_size != NULL) {
+ jint int_value =
+ (*env)->CallIntMethod(env, jni_inbound_cache_max_size, boxed_integer_properties.integer_get_value_id);
+
+ if (int_value < 0 || int_value > UINT16_MAX) {
+ AWS_LOGF_ERROR(AWS_LS_MQTT_CLIENT, "Invalid inbound cache size value: %d", int_value);
+ return aws_raise_error(AWS_ERROR_INVALID_ARGUMENT);
+ }
+
+ topic_aliasing_options->inbound_alias_cache_size = (uint16_t)int_value;
+ }
+
+ return AWS_OP_SUCCESS;
+}
+
/*******************************************************************************
* JNI FUNCTIONS
******************************************************************************/
@@ -2032,6 +2096,18 @@
java_client->jni_lifecycle_events = (*env)->NewGlobalRef(env, jni_lifecycle_events);
}
+ struct aws_mqtt5_client_topic_alias_options topic_aliasing_options;
+ AWS_ZERO_STRUCT(topic_aliasing_options);
+ jobject jni_topic_aliasing_options =
+ (*env)->GetObjectField(env, jni_options, mqtt5_client_options_properties.topic_aliasing_options_field_id);
+
+ if (jni_topic_aliasing_options != NULL) {
+ if (s_initialize_topic_aliasing_options(env, &topic_aliasing_options, jni_topic_aliasing_options) ==
+ AWS_OP_SUCCESS) {
+ client_options.topic_aliasing_options = &topic_aliasing_options;
+ }
+ }
+
client_options.client_termination_handler = &s_aws_mqtt5_client_java_termination;
client_options.client_termination_handler_user_data = (void *)java_client;
diff --git a/src/native/mqtt5_packets.c b/src/native/mqtt5_packets.c
index bdcf82d..d7d3fea 100644
--- a/src/native/mqtt5_packets.c
+++ b/src/native/mqtt5_packets.c
@@ -1215,6 +1215,21 @@
java_packet->packet.message_expiry_interval_seconds = &java_packet->message_expiry_interval_seconds;
}
+ if (aws_get_uint16_from_jobject(
+ env,
+ java_publish_packet,
+ mqtt5_publish_packet_properties.publish_topic_alias_field_id,
+ s_publish_packet_string,
+ "topic alias",
+ &java_packet->topic_alias,
+ true,
+ &was_value_set) == AWS_OP_ERR) {
+ goto on_error;
+ }
+ if (was_value_set) {
+ java_packet->packet.topic_alias = &java_packet->topic_alias;
+ }
+
if (aws_get_string_from_jobject(
env,
java_publish_packet,
diff --git a/src/native/mqtt5_utils.c b/src/native/mqtt5_utils.c
index ad4cff5..2aa46e9 100644
--- a/src/native/mqtt5_utils.c
+++ b/src/native/mqtt5_utils.c
@@ -339,6 +339,15 @@
true) != AWS_OP_SUCCESS) {
return NULL;
}
+ if (s_set_jni_uint16_t_field_in_packet(
+ env,
+ native_connack_data->topic_alias_maximum,
+ connack_data,
+ mqtt5_connack_packet_properties.connack_topic_alias_maximum_field_id,
+ "topic alias maximum",
+ true) != AWS_OP_SUCCESS) {
+ return NULL;
+ };
if (s_set_jni_string_field_in_packet(
env,
native_connack_data->reason_string,
@@ -514,6 +523,16 @@
(*env)->SetIntField(
env,
negotiated_settings_data,
+ mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_server_field_id,
+ (jint)native_negotiated_settings_data->topic_alias_maximum_to_server);
+ (*env)->SetIntField(
+ env,
+ negotiated_settings_data,
+ mqtt5_negotiated_settings_properties.negotiated_settings_topic_alias_maximum_to_client_field_id,
+ (jint)native_negotiated_settings_data->topic_alias_maximum_to_client);
+ (*env)->SetIntField(
+ env,
+ negotiated_settings_data,
mqtt5_negotiated_settings_properties.negotiated_settings_server_keep_alive_field_id,
(jint)native_negotiated_settings_data->server_keep_alive);
(*env)->SetBooleanField(
@@ -614,6 +633,16 @@
return NULL;
}
+ if (s_set_jni_uint16_t_field_in_packet(
+ env,
+ publish->topic_alias,
+ publish_packet_data,
+ mqtt5_publish_packet_properties.publish_topic_alias_field_id,
+ "topic alias",
+ true) != AWS_OP_SUCCESS) {
+ return NULL;
+ }
+
if (s_set_jni_string_field_in_packet(
env,
publish->response_topic,