• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 java.util.List;
8 import java.util.Map;
9 import java.util.function.Function;
10 import java.util.stream.Collectors;
11 import java.util.stream.Stream;
12 
13 /**
14  * Data model of an <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901205">MQTT5 DISCONNECT</a> packet.
15  */
16 public class DisconnectPacket {
17 
18     private DisconnectReasonCode reasonCode = DisconnectReasonCode.NORMAL_DISCONNECTION;
19     private Long sessionExpiryIntervalSeconds;
20     private String reasonString;
21     private List<UserProperty> userProperties;
22     private String serverReference;
23 
24     /**
25      * Returns a value indicating the reason that the sender is closing the connection
26      *
27      * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208">MQTT5 Disconnect Reason Code</a>
28      *
29      * @return Value indicating the reason that the sender is closing the connection
30      */
getReasonCode()31     public DisconnectReasonCode getReasonCode() {
32         return this.reasonCode;
33     }
34 
35     /**
36      * Returns a change to the session expiry interval negotiated at connection time as part of the disconnect.  Only
37      * valid for DisconnectPackets sent from client to server.  It is not valid to attempt to change session expiry
38      * from zero to a non-zero value.
39      *
40      * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901211">MQTT5 Session Expiry Interval</a>.
41      *
42      * @return A change to the session expiry interval negotiated at connection time as part of the disconnect.
43      */
getSessionExpiryIntervalSeconds()44     public Long getSessionExpiryIntervalSeconds() {
45         return this.sessionExpiryIntervalSeconds;
46     }
47 
48     /**
49      * Returns additional diagnostic information about the reason that the sender is closing the connection
50      *
51      * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901212">MQTT5 Reason String</a>
52      *
53      * @return Additional diagnostic information about the reason that the sender is closing the connection
54      */
getReasonString()55     public String getReasonString() {
56         return this.reasonString;
57     }
58 
59     /**
60      * Returns a list of MQTT5 user properties included with the packet.
61      *
62      * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901213">MQTT5 User Property</a>
63      *
64      * @return List of MQTT5 user properties included with the packet.
65      */
getUserProperties()66     public List<UserProperty> getUserProperties() {
67         return this.userProperties;
68     }
69 
70     /**
71      * Returns a property indicating an alternate server that the client may temporarily or permanently attempt
72      * to connect to instead of the configured endpoint.  Will only be set if the reason code indicates another
73      * server may be used (ServerMoved, UseAnotherServer).
74      *
75      * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901214">MQTT5 Server Reference</a>
76      *
77      * @return Property indicating an alternate server that the client may temporarily or permanently attempt
78      * to connect to instead of the configured endpoint.
79      */
getServerReference()80     public String getServerReference() {
81         return this.serverReference;
82     }
83 
84     /**
85      * Creates a DisconnectPacket instance using the provided DisconnectPacketBuilder.
86      */
DisconnectPacket(DisconnectPacketBuilder builder)87     private DisconnectPacket(DisconnectPacketBuilder builder) {
88         this.reasonCode = builder.reasonCode;
89         this.sessionExpiryIntervalSeconds = builder.sessionExpiryIntervalSeconds;
90         this.reasonString = builder.reasonString;
91         this.userProperties = builder.userProperties;
92         this.serverReference = builder.serverReference;
93     }
94 
DisconnectPacket()95     private DisconnectPacket() {}
96 
97     /**
98      * A native, JNI-only helper function for more easily setting the reason code
99      * @param reasonCode A int representing the reason code
100      */
nativeAddDisconnectReasonCode(int reasonCode)101     private void nativeAddDisconnectReasonCode(int reasonCode) {
102         this.reasonCode = DisconnectReasonCode.getEnumValueFromInteger(reasonCode);
103     }
104 
105     /*******************************************************************************
106      * builder
107      ******************************************************************************/
108 
109     /**
110      * Reason code inside DisconnectPackets.  Helps determine why a connection was terminated.
111      *
112      * Enum values match <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208">MQTT5 spec</a> encoding values.
113      */
114     public enum DisconnectReasonCode {
115 
116         /**
117          * Returned when the remote endpoint wishes to disconnect normally. Will not trigger the publish of a Will message if a
118          * Will message was configured on the connection.
119          *
120          * May be sent by the client or server.
121          */
122         NORMAL_DISCONNECTION(0),
123 
124         /**
125          * Returns when the client wants to disconnect but requires that the server publish the Will message configured
126          * on the connection.
127          *
128          * May only be sent by the client.
129          */
130         DISCONNECT_WITH_WILL_MESSAGE(4),
131 
132         /**
133          * Returned when the connection was closed but the sender does not want to specify a reason or none
134          * of the other reason codes apply.
135          *
136          * May be sent by the client or the server.
137          */
138         UNSPECIFIED_ERROR(128),
139 
140         /**
141          * Indicates the remote endpoint received a packet that does not conform to the MQTT specification.
142          *
143          * May be sent by the client or the server.
144          */
145         MALFORMED_PACKET(129),
146 
147         /**
148          * Returned when an unexpected or out-of-order packet was received by the remote endpoint.
149          *
150          * May be sent by the client or the server.
151          */
152         PROTOCOL_ERROR(130),
153 
154         /**
155          * Returned when a valid packet was received by the remote endpoint, but could not be processed by the current implementation.
156          *
157          * May be sent by the client or the server.
158          */
159         IMPLEMENTATION_SPECIFIC_ERROR(131),
160 
161         /**
162          * Returned when the remote endpoint received a packet that represented an operation that was not authorized within
163          * the current connection.
164          *
165          * May only be sent by the server.
166          */
167         NOT_AUTHORIZED(135),
168 
169         /**
170          * Returned when the server is busy and cannot continue processing packets from the client.
171          *
172          * May only be sent by the server.
173          */
174         SERVER_BUSY(137),
175 
176         /**
177          * Returned when the server is shutting down.
178          *
179          * May only be sent by the server.
180          */
181         SERVER_SHUTTING_DOWN(139),
182 
183         /**
184          * Returned when the server closes the connection because no packet from the client has been received in
185          * 1.5 times the KeepAlive time set when the connection was established.
186          *
187          * May only be sent by the server.
188          */
189         KEEP_ALIVE_TIMEOUT(141),
190 
191         /**
192          * Returned when the server has established another connection with the same client ID as a client's current
193          * connection, causing the current client to become disconnected.
194          *
195          * May only be sent by the server.
196          */
197         SESSION_TAKEN_OVER(142),
198 
199         /**
200          * Returned when the topic filter name is correctly formed but not accepted by the server.
201          *
202          * May only be sent by the server.
203          */
204         TOPIC_FILTER_INVALID(143),
205 
206         /**
207          * Returned when topic name is correctly formed, but is not accepted.
208          *
209          * May be sent by the client or the server.
210          */
211         TOPIC_NAME_INVALID(144),
212 
213         /**
214          * Returned when the remote endpoint reached a state where there were more in-progress QoS1+ publishes then the
215          * limit it established for itself when the connection was opened.
216          *
217          * May be sent by the client or the server.
218          */
219         RECEIVE_MAXIMUM_EXCEEDED(147),
220 
221         /**
222          * Returned when the remote endpoint receives a PublishPacket that contained a topic alias greater than the
223          * maximum topic alias limit that it established for itself when the connection was opened.
224          *
225          * May be sent by the client or the server.
226          */
227         TOPIC_ALIAS_INVALID(148),
228 
229         /**
230          * Returned when the remote endpoint received a packet whose size was greater than the maximum packet size limit
231          * it established for itself when the connection was opened.
232          *
233          * May be sent by the client or the server.
234          */
235         PACKET_TOO_LARGE(149),
236 
237         /**
238          * Returned when the remote endpoint's incoming data rate was too high.
239          *
240          * May be sent by the client or the server.
241          */
242         MESSAGE_RATE_TOO_HIGH(150),
243 
244         /**
245          * Returned when an internal quota of the remote endpoint was exceeded.
246          *
247          * May be sent by the client or the server.
248          */
249         QUOTA_EXCEEDED(151),
250 
251         /**
252          * Returned when the connection was closed due to an administrative action.
253          *
254          * May be sent by the client or the server.
255          */
256         ADMINISTRATIVE_ACTION(152),
257 
258         /**
259          * Returned when the remote endpoint received a packet where payload format did not match the format specified
260          * by the payload format indicator.
261          *
262          * May be sent by the client or the server.
263          */
264         PAYLOAD_FORMAT_INVALID(153),
265 
266         /**
267          * Returned when the server does not support retained messages.
268          *
269          * May only be sent by the server.
270          */
271         RETAIN_NOT_SUPPORTED(154),
272 
273         /**
274          * Returned when the client sends a QoS that is greater than the maximum QOS established when the connection was
275          * opened.
276          *
277          * May only be sent by the server.
278          */
279         QOS_NOT_SUPPORTED(155),
280 
281         /**
282          * Returned by the server to tell the client to temporarily use a different server.
283          *
284          * May only be sent by the server.
285          */
286         USE_ANOTHER_SERVER(156),
287 
288         /**
289          * Returned by the server to tell the client to permanently use a different server.
290          *
291          * May only be sent by the server.
292          */
293         SERVER_MOVED(157),
294 
295         /**
296          * Returned by the server to tell the client that shared subscriptions are not supported on the server.
297          *
298          * May only be sent by the server.
299          */
300         SHARED_SUBSCRIPTIONS_NOT_SUPPORTED(158),
301 
302         /**
303          * Returned when the server disconnects the client due to the connection rate being too high.
304          *
305          * May only be sent by the server.
306          */
307         CONNECTION_RATE_EXCEEDED(159),
308 
309         /**
310          * Returned by the server when the maximum connection time authorized for the connection was exceeded.
311          *
312          * May only be sent by the server.
313          */
314         MAXIMUM_CONNECT_TIME(160),
315 
316         /**
317          * Returned by the server when it received a SubscribePacket with a subscription identifier, but the server does
318          * not support subscription identifiers.
319          *
320          * May only be sent by the server.
321          */
322         SUBSCRIPTION_IDENTIFIERS_NOT_SUPPORTED (161),
323 
324         /**
325          * Returned by the server when it received a SubscribePacket with a wildcard topic filter, but the server does
326          * not support wildcard topic filters.
327          *
328          * May only be sent by the server.
329          */
330         WILDCARD_SUBSCRIPTIONS_NOT_SUPPORTED(162);
331 
332         private int reasonCode;
333 
DisconnectReasonCode(int code)334         private DisconnectReasonCode(int code) {
335             reasonCode = code;
336         }
337 
338         /**
339          * @return The native enum integer value associated with this Java enum value
340          */
getValue()341         public int getValue() {
342             return reasonCode;
343         }
344 
345         /**
346          * Creates a Java DisconnectReasonCode enum value from a native integer value.
347          *
348          * @param value native integer value for DisconnectReasonCode
349          * @return a new DisconnectReasonCode value
350          */
getEnumValueFromInteger(int value)351         public static DisconnectReasonCode getEnumValueFromInteger(int value) {
352             DisconnectReasonCode enumValue = enumMapping.get(value);
353             if (enumValue != null) {
354                 return enumValue;
355             }
356             throw new RuntimeException("Illegal DisconnectReasonCode");
357         }
358 
buildEnumMapping()359         private static Map<Integer, DisconnectReasonCode> buildEnumMapping() {
360             return Stream.of(DisconnectReasonCode.values())
361                 .collect(Collectors.toMap(DisconnectReasonCode::getValue, Function.identity()));
362         }
363 
364         private static Map<Integer, DisconnectReasonCode> enumMapping = buildEnumMapping();
365     }
366 
367     /**
368      * A class to that allows for the creation of a DisconnectPacket. Set all of the settings you want in the
369      * packet and then use the build() function to get a DisconnectPacket populated with the settings
370      * defined in the builder.
371      */
372     static final public class DisconnectPacketBuilder {
373 
374         private DisconnectReasonCode reasonCode = DisconnectReasonCode.NORMAL_DISCONNECTION;
375         private Long sessionExpiryIntervalSeconds;
376         private String reasonString;
377         private List<UserProperty> userProperties;
378         private String serverReference;
379 
380         /**
381          * Sets the value indicating the reason that the sender is closing the connection
382          *
383          * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901208">MQTT5 Disconnect Reason Code</a>
384          *
385          * @param reasonCode Value indicating the reason that the sender is closing the connection
386          * @return The DisconnectPacketBuilder after setting the reason code.
387          */
withReasonCode(DisconnectReasonCode reasonCode)388         public DisconnectPacketBuilder withReasonCode(DisconnectReasonCode reasonCode) {
389             this.reasonCode = reasonCode;
390             return this;
391         }
392 
393         /**
394          * Sets the change to the session expiry interval negotiated at connection time as part of the disconnect.  Only
395          * valid for DisconnectPackets sent from client to server.  It is not valid to attempt to change session expiry
396          * from zero to a non-zero value.
397          *
398          * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901211">MQTT5 Session Expiry Interval</a>
399          *
400          * @param sessionExpiryIntervalSeconds the session expiry interval negotiated at connection time as part of the disconnect
401          * @return The DisconnectPacketBuilder after setting the session expiry interval.
402          */
withSessionExpiryIntervalSeconds(long sessionExpiryIntervalSeconds)403         public DisconnectPacketBuilder withSessionExpiryIntervalSeconds(long sessionExpiryIntervalSeconds) {
404             this.sessionExpiryIntervalSeconds = sessionExpiryIntervalSeconds;
405             return this;
406         }
407 
408         /**
409          * Sets the additional diagnostic information about the reason that the sender is closing the connection
410          *
411          * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901212">MQTT5 Reason String</a>
412          *
413          * @param reasonString Additional diagnostic information about the reason that the sender is closing the connection
414          * @return The DisconnectPacketBuilder after setting the reason string.
415          */
withReasonString(String reasonString)416         public DisconnectPacketBuilder withReasonString(String reasonString) {
417             this.reasonString = reasonString;
418             return this;
419         }
420 
421         /**
422          * Sets the list of MQTT5 user properties included with the packet.
423          *
424          * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901213">MQTT5 User Property</a>
425          *
426          * @param userProperties List of MQTT5 user properties included with the packet.
427          * @return The DisconnectPacketBuilder after setting the user properties.
428          */
withUserProperties(List<UserProperty> userProperties)429         public DisconnectPacketBuilder withUserProperties(List<UserProperty> userProperties) {
430             this.userProperties = userProperties;
431             return this;
432         }
433 
434         /**
435          * Sets the property indicating an alternate server that the client may temporarily or permanently attempt
436          * to connect to instead of the configured endpoint.  Will only be set if the reason code indicates another
437          * server may be used (ServerMoved, UseAnotherServer).
438          *
439          * See <a href="https://docs.oasis-open.org/mqtt/mqtt/v5.0/os/mqtt-v5.0-os.html#_Toc3901214">MQTT5 Server Reference</a>
440          *
441          * @param serverReference Property indicating an alternate server that the client may temporarily or permanently
442          * attempt to connect to instead of the configured endpoint.
443          * @return The DisconnectPacketBuilder after setting the server reference.
444          */
withServerReference(String serverReference)445         public DisconnectPacketBuilder withServerReference(String serverReference) {
446             this.serverReference = serverReference;
447             return this;
448         }
449 
450         /**
451          * Creates a new DisconnectPacketBuilder so a DisconnectPacket can be created.
452          */
DisconnectPacketBuilder()453         public DisconnectPacketBuilder() {}
454 
455         /**
456          * Creates a new DisconnectPacket using the settings set in the builder.
457          * @return The DisconnectPacket created from the builder
458          */
build()459         public DisconnectPacket build()
460         {
461             return new DisconnectPacket(this);
462         }
463     }
464 
465 }
466