List of usage examples for io.netty.handler.codec.mqtt MqttQoS AT_MOST_ONCE
MqttQoS AT_MOST_ONCE
To view the source code for io.netty.handler.codec.mqtt MqttQoS AT_MOST_ONCE.
Click Source Link
From source file:com.caricah.iotracah.core.handlers.PublishInHandler.java
License:Apache License
/** * A PUBLISH Control Packet is sent from a Client to a Server or from Server to a Client * to transport an Application Message.//from w w w . ja v a2s. c o m * * @throws RetriableException * @throws UnRetriableException */ @Override public void handle(PublishMessage publishMessage) throws RetriableException, UnRetriableException { log.debug(" handle : client attempting to publish a message."); /** * During an attempt to publish a message. * * All Topic Names and Topic Filters MUST be at least one character long [MQTT-4.7.3-1] * * The wildcard characters can be used in Topic Filters, * but MUST NOT be used within a Topic Name [MQTT-4.7.1-1]. * * Topic Names and Topic Filters MUST NOT include the null character (Unicode U+0000) [Unicode] [MQTT-4.7.3-2] * * Topic Names and Topic Filters are UTF-8 encoded strings, they MUST NOT encode to more than 65535 bytes [MQTT-4.7.3-3]. See Section 1.5.3 * */ String topic = publishMessage.getTopic(); if (null == topic || topic.isEmpty() || topic.contains(Constant.MULTI_LEVEL_WILDCARD) || topic.contains(Constant.SINGLE_LEVEL_WILDCARD) || topic.contains(Constant.SYS_PREFIX)) { log.info(" handle : Invalid topic " + publishMessage.getTopic()); throw new ShutdownException(" Invalid topic name"); } /** * Before publishing we should get the current session and validate it. */ Observable<IOTClient> permissionObservable = checkPermission(publishMessage.getSessionId(), publishMessage.getAuthKey(), AuthorityRole.PUBLISH, topic); permissionObservable.subscribe((iotSession) -> { try { publishMessage.setPartitionId(iotSession.getPartitionId()); publishMessage.setClientId(iotSession.getSessionId()); publishMessage.setId(-1); /** * Message processing is based on 4.3 Quality of Service levels and protocol flows */ /** * 4.3.1 QoS 0: At most once delivery * Accepts ownership of the message when it receives the PUBLISH packet. */ if (MqttQoS.AT_MOST_ONCE.value() == publishMessage.getQos()) { getMessenger().publish(iotSession.getPartitionId(), publishMessage); } /** * 4.3.2 QoS 1: At least once delivery * * MUST respond with a PUBACK Packet containing the Packet Identifier from the incoming PUBLISH Packet, having accepted ownership of the Application Message * After it has sent a PUBACK Packet the Receiver MUST treat any incoming PUBLISH packet that contains the same Packet Identifier as being a new publication, irrespective of the setting of its DUP flag. */ if (MqttQoS.AT_LEAST_ONCE.value() == publishMessage.getQos()) { getMessenger().publish(iotSession.getPartitionId(), publishMessage); //We need to generate a puback message to close this conversation. AcknowledgeMessage acknowledgeMessage = AcknowledgeMessage.from(publishMessage.getMessageId()); acknowledgeMessage.copyTransmissionData(publishMessage); pushToServer(acknowledgeMessage); } /** * 4.3.3 QoS 2: Exactly once delivery * * MUST respond with a PUBREC containing the Packet Identifier from the incoming PUBLISH Packet, having accepted ownership of the Application Message. * Until it has received the corresponding PUBREL packet, the Receiver MUST acknowledge any subsequent PUBLISH packet with the same Packet Identifier by sending a PUBREC. * It MUST NOT cause duplicate messages to be delivered to any onward recipients in this case. * */ if (MqttQoS.EXACTLY_ONCE.value() == publishMessage.getQos()) { queueQos2Message(publishMessage); } } catch (UnRetriableException | RetriableException e) { disconnectDueToError(e, publishMessage); } }, throwable -> disconnectDueToError(throwable, publishMessage) ); }
From source file:com.caricah.iotracah.core.worker.DumbWorker.java
License:Apache License
/** * Provides the Observer with a new item to observe. * <p>// ww w.j a va 2 s . c om * The {@link com.caricah.iotracah.core.modules.Server} may call this method 0 or more times. * <p> * The {@code Observable} will not call this method again after it calls either {@link #onCompleted} or * {@link #onError}. * * @param iotMessage the item emitted by the Observable */ @Override public void onNext(IOTMessage iotMessage) { getExecutorService().submit(() -> { log.info(" onNext : received {}", iotMessage); try { IOTMessage response = null; switch (iotMessage.getMessageType()) { case ConnectMessage.MESSAGE_TYPE: ConnectMessage connectMessage = (ConnectMessage) iotMessage; response = ConnectAcknowledgeMessage.from(connectMessage.isDup(), connectMessage.getQos(), connectMessage.isRetain(), connectMessage.getKeepAliveTime(), MqttConnectReturnCode.CONNECTION_ACCEPTED); break; case SubscribeMessage.MESSAGE_TYPE: SubscribeMessage subscribeMessage = (SubscribeMessage) iotMessage; List<Integer> grantedQos = new ArrayList<>(); subscribeMessage.getTopicFilterList().forEach(topic -> { String topicKey = quickCheckIdKey("", Arrays.asList(topic.getKey().split(Constant.PATH_SEPARATOR))); Set<String> channelIds = subscriptions.get(topicKey); if (Objects.isNull(channelIds)) { channelIds = new HashSet<>(); } channelIds.add(subscribeMessage.getConnectionId()); subscriptions.put(topicKey, channelIds); grantedQos.add(topic.getValue()); }); response = SubscribeAcknowledgeMessage.from(subscribeMessage.getMessageId(), grantedQos); break; case UnSubscribeMessage.MESSAGE_TYPE: UnSubscribeMessage unSubscribeMessage = (UnSubscribeMessage) iotMessage; response = UnSubscribeAcknowledgeMessage.from(unSubscribeMessage.getMessageId()); break; case Ping.MESSAGE_TYPE: response = iotMessage; break; case PublishMessage.MESSAGE_TYPE: PublishMessage publishMessage = (PublishMessage) iotMessage; Set<String> matchingTopics = getMatchingSubscriptions("", publishMessage.getTopic()); for (String match : matchingTopics) { Set<String> channelIds = subscriptions.get(match); if (Objects.nonNull(channelIds)) { channelIds.forEach(id -> { PublishMessage clonePublishMessage = publishMessage.cloneMessage(); clonePublishMessage.copyTransmissionData(iotMessage); clonePublishMessage.setConnectionId(id); pushToServer(clonePublishMessage); }); } } if (MqttQoS.AT_MOST_ONCE.value() == publishMessage.getQos()) { break; } else if (MqttQoS.AT_LEAST_ONCE.value() == publishMessage.getQos()) { response = AcknowledgeMessage.from(publishMessage.getMessageId()); break; } case PublishReceivedMessage.MESSAGE_TYPE: case ReleaseMessage.MESSAGE_TYPE: case CompleteMessage.MESSAGE_TYPE: case DisconnectMessage.MESSAGE_TYPE: case AcknowledgeMessage.MESSAGE_TYPE: default: DisconnectMessage disconnectMessage = DisconnectMessage.from(true); disconnectMessage.copyTransmissionData(iotMessage); throw new ShutdownException(disconnectMessage); } if (Objects.nonNull(response)) { response.copyTransmissionData(iotMessage); pushToServer(response); } } catch (ShutdownException e) { IOTMessage response = e.getResponse(); if (Objects.nonNull(response)) { pushToServer(response); } } catch (Exception e) { log.error(" onNext : Serious error that requires attention ", e); } }); }
From source file:com.caricah.iotracah.core.worker.state.Messenger.java
License:Apache License
private void publish(PublishMessage publishMessage) throws RetriableException { log.debug(" publish : new message {} to publish from {} in partition {}", publishMessage, publishMessage.getSessionId(), publishMessage.getPartitionId()); //Obtain a list of all the subscribed clients who will receive a message. Observable<IotSubscriptionFilter> subscriptionFilterObservable = getDatastore() .getMatchingSubscriptionFilter(publishMessage.getPartitionId(), publishMessage.getTopic()); subscriptionFilterObservable.subscribe(subscriptionFilter -> { try {/*from w w w . ja va2 s.co m*/ Observable<IotSubscription> subscriptionObservable = getDatastore() .getSubscriptions(subscriptionFilter, publishMessage.getQos()); subscriptionObservable.subscribeOn(getWorker().getScheduler()).distinct() .subscribe(subscription -> { IotClientKey clientKey = new IotClientKey(); clientKey.setSessionId(subscription.getClientId()); Observable<IOTClient> clientObservable = getDatastore().getSession(clientKey); clientObservable.subscribe(iotSession -> { try { log.debug(" publish : found subscription {} for message {} in partition {}", iotSession, publishMessage, publishMessage.getPartitionId()); final PublishMessage clonePublishMessage = iotSession .copyTransmissionData(publishMessage.cloneMessage()); if (clonePublishMessage.getQos() > MqttQoS.AT_MOST_ONCE.value()) { try { //Save the message as we proceed. Map.Entry<Long, IotMessageKey> messageIdentity = getDatastore() .saveMessage(clonePublishMessage).toBlocking().single(); log.debug(" publish : new generated message id is {}", messageIdentity); clonePublishMessage .setMessageId(messageIdentity.getValue().getMessageId()); } catch (Exception e) { log.error(" publish : error details ", e); } } if (iotSession.getIsActive()) { //Actually push out the message. //This message should be released to the connected client getWorker().getHandler(PublishOutHandler.class).handle(clonePublishMessage); } } catch (RetriableException | UnRetriableException e) { log.error(" publish : problems releasing stored messages", e); } }); }, throwable -> log.error(" process : database problems", throwable)); } catch (UnRetriableException e) { e.printStackTrace(); } }, throwable -> log.error(" publish : database problems", throwable), () -> { //Store the retained message. if (publishMessage.getIsRetain()) { log.debug(" publish : Message {} on partition {} should be retained", publishMessage, publishMessage.getPartitionId()); /** * 3.3.1.3 RETAIN * Position: byte 1, bit 0. * If the RETAIN flag is set to 1, in a PUBLISH Packet sent by a Client to a Server, the Server MUST store the Application Message and its QoS, so that it can be delivered to future subscribers whose subscriptions match its topic name [MQTT-3.3.1-5]. When a new subscription is established, the last retained message, if any, on each matching topic name MUST be sent to the subscriber [MQTT-3.3.1-6]. If the Server receives a QoS 0 message with the RETAIN flag set to 1 it MUST discard any message previously retained for that topic. It SHOULD store the new QoS 0 message as the new retained message for that topic, but MAY choose to discard it at any time - if this happens there will be no retained message for that topic [MQTT-3.3.1-7]. See Section 4.1 for more information on storing state. * When sending a PUBLISH Packet to a Client the Server MUST set the RETAIN flag to 1 if a message is sent as a result of a new subscription being made by a Client [MQTT-3.3.1-8]. It MUST set the RETAIN flag to 0 when a PUBLISH Packet is sent to a Client because it matches an established subscription regardless of how the flag was set in the message it received [MQTT-3.3.1-9]. * A PUBLISH Packet with a RETAIN flag set to 1 and a payload containing zero bytes will be processed as normal by the Server and sent to Clients with a subscription matching the topic name. Additionally any existing retained message with the same topic name MUST be removed and any future subscribers for the topic will not receive a retained message [MQTT-3.3.1-10]. As normal? means that the RETAIN flag is not set in the message received by existing Clients. A zero byte retained message MUST NOT be stored as a retained message on the Server [MQTT-3.3.1-11]. * If the RETAIN flag is 0, in a PUBLISH Packet sent by a Client to a Server, the Server MUST NOT store the message and MUST NOT remove or replace any existing retained message [MQTT-3.3.1-12]. * Non normative comment * Retained messages are useful where publishers send state messages on an irregular basis. A new subscriber will receive the most recent state. * */ //Get or Create a new subscription filter just in case it does not already exist. Observable<IotSubscriptionFilter> retainedSubscriptionFilterObservable = getDatastore() .getOrCreateSubscriptionFilter(publishMessage.getPartitionId(), publishMessage.getTopic()); retainedSubscriptionFilterObservable.subscribe(subscriptionFilter -> { log.debug(" publish : Message {} will be retained on subscription filter {}", publishMessage, subscriptionFilter); try { if (((byte[]) publishMessage.getPayload()).length > 0) { //Save the retain message. getDatastore().saveRetainedMessage(subscriptionFilter, publishMessage.getQos(), publishMessage.getPayload()); } else { getDatastore().removeRetainedMessage(subscriptionFilter); } } catch (UnRetriableException e) { log.warn(" publish : problems ", e); } }); } }); }
From source file:io.crate.mqtt.protocol.MqttQualityOfServiceTest.java
@Test public void testProcessQoS0() throws Exception { expectedException.expect(UnsupportedOperationException.class); expectedException.expectMessage("QoS 0 (AT_MOST_ONCE) is not supported."); MqttPublishMessage message = messageWithQoS(MqttQoS.AT_MOST_ONCE); processor.handlePublish(ch, message); }
From source file:io.moquette.persistence.AbstractStoreTest.java
License:Open Source License
@Test public void overridingSubscriptions() { ClientSession session1 = sessionsStore.createNewSession("SESSION_ID_1", true, 0); // Subscribe on /topic with QOSType.MOST_ONE Subscription oldSubscription = new Subscription(session1.clientID, new Topic("/topic"), MqttQoS.AT_MOST_ONCE); session1.subscribe(oldSubscription); // Subscribe on /topic again that overrides the previous subscription. Subscription overridingSubscription = new Subscription(session1.clientID, new Topic("/topic"), MqttQoS.EXACTLY_ONCE);/*w ww . j a v a2 s .co m*/ session1.subscribe(overridingSubscription); // Verify List<ClientTopicCouple> subscriptions = sessionsStore.subscriptionStore().listAllSubscriptions(); assertThat(subscriptions).hasSize(1); Subscription sub = sessionsStore.subscriptionStore().getSubscription(subscriptions.get(0)); assertThat(sub.getRequestedQos()).isEqualTo(overridingSubscription.getRequestedQos()); }
From source file:io.moquette.persistence.AbstractStoreTest.java
License:Open Source License
@Test public void checkRetained() { Message message = new Message("message".getBytes(), MqttQoS.AT_MOST_ONCE, "id1/topic"); messagesStore.storeRetained(new Topic(message.getTopic()), message); Message message2 = new Message("message".getBytes(), MqttQoS.AT_MOST_ONCE, "id1/topic2"); messagesStore.storeRetained(new Topic(message2.getTopic()), message2); Message message3 = new Message("message".getBytes(), MqttQoS.AT_MOST_ONCE, "id2/topic2"); messagesStore.storeRetained(new Topic(message3.getTopic()), message3); Subscription subscription1 = new Subscription("cid", new Topic("id1/#"), MqttQoS.AT_MOST_ONCE); Subscription subscription2 = new Subscription("cid", new Topic("id1/topic"), MqttQoS.AT_MOST_ONCE); await().untilAsserted(() -> {//from w ww .java 2s . co m Map<Subscription, Collection<Message>> result = messagesStore .searchMatching(Arrays.asList(subscription1, subscription2)); assertThat(result).containsOnlyKeys(subscription1, subscription2); assertThat(result.get(subscription1)).containsExactlyInAnyOrder(message, message2); assertThat(result.get(subscription2)).containsExactlyInAnyOrder(message); }); messagesStore.cleanRetained(new Topic("id1/topic2")); await().untilAsserted(() -> { Map<Subscription, Collection<Message>> result = messagesStore .searchMatching(Arrays.asList(subscription1, subscription2)); assertThat(result).containsOnlyKeys(subscription1, subscription2); assertThat(result.get(subscription1)).containsExactlyInAnyOrder(message); assertThat(result.get(subscription2)).containsExactlyInAnyOrder(message); }); messagesStore.cleanRetained(new Topic("id1/topic")); await().untilAsserted(() -> { Map<Subscription, Collection<Message>> result = messagesStore .searchMatching(Arrays.asList(subscription1, subscription2)); assertThat(result).isEmpty(); }); }
From source file:io.moquette.persistence.AbstractStoreTest.java
License:Open Source License
@Test public void singleTopicRetained() { // This message will be stored in a wrong place id1/ Message message = new Message("message".getBytes(), MqttQoS.AT_MOST_ONCE, "id1"); messagesStore.storeRetained(new Topic(message.getTopic()), message); Subscription subscription1 = new Subscription("cid", new Topic("id1/#"), MqttQoS.AT_MOST_ONCE); Subscription subscription2 = new Subscription("cid", new Topic("id1"), MqttQoS.AT_MOST_ONCE); await().untilAsserted(() -> {// w ww .j a v a 2s . com Map<Subscription, Collection<Message>> result = messagesStore .searchMatching(Arrays.asList(subscription1, subscription2)); assertThat(result).containsOnlyKeys(subscription1, subscription2); assertThat(result.get(subscription1)) .containsExactlyInAnyOrder(new Message("message".getBytes(), MqttQoS.AT_MOST_ONCE, "id1")); assertThat(result.get(subscription2)).isNotEmpty(); }); messagesStore.cleanRetained(new Topic("id1")); await().untilAsserted(() -> { Map<Subscription, Collection<Message>> result = messagesStore .searchMatching(Arrays.asList(subscription1, subscription2)); assertThat(result).isEmpty(); }); }
From source file:io.moquette.persistence.AbstractStoreTest.java
License:Open Source License
@Test public void checkSubs() { String id = "TestClient3"; Topic t = new Topic("id1/#"); sessionsStore.createNewSession(id, true, 0); Subscription subscription1 = new Subscription(id, t, MqttQoS.AT_MOST_ONCE); sessionsStore.subscriptionStore().addNewSubscription(subscription1); assertThat(sessionsStore.contains(id)).isTrue(); assertThat(sessionsStore.subscriptionStore().getSubscriptions()).containsExactly(subscription1); sessionsStore.subscriptionStore().removeSubscription(t, id); assertThat(sessionsStore.contains(id)).isTrue(); assertThat(sessionsStore.subscriptionStore().getSubscriptions()).isEmpty(); }
From source file:io.moquette.persistence.AbstractStoreTest.java
License:Open Source License
@Test public void wipeSubs() { String id = "TestClient33"; Topic t = new Topic("id1/#"); sessionsStore.createNewSession(id, true, 0); Subscription subscription1 = new Subscription(id, t, MqttQoS.AT_MOST_ONCE); sessionsStore.subscriptionStore().addNewSubscription(subscription1); assertThat(sessionsStore.contains(id)).isTrue(); assertThat(sessionsStore.subscriptionStore().getSubscriptions()).containsExactly(subscription1); sessionsStore.subscriptionStore().wipeSubscriptions(id); assertThat(sessionsStore.contains(id)).isTrue(); assertThat(sessionsStore.subscriptionStore().getSubscriptions()).isEmpty(); }
From source file:io.moquette.server.ServerIntegrationEmbeddedPublishTest.java
License:Open Source License
@Test public void testClientSubscribeAfterNotRetainedQoS0IsSent() throws Exception { LOG.info("*** testClientSubscribeAfterNotRetainedQoS0IsSent ***"); // Exercise//from w w w . j ava2 s .c o m internalPublishToWithQosAndRetained("/topic", MqttQoS.AT_MOST_ONCE, false); subscribeToWithQos("/topic", 0); // Verify verifyNoMessageIsReceived(); }