Example usage for io.netty.handler.codec.mqtt MqttQoS AT_MOST_ONCE

List of usage examples for io.netty.handler.codec.mqtt MqttQoS AT_MOST_ONCE

Introduction

In this page you can find the example usage for io.netty.handler.codec.mqtt MqttQoS AT_MOST_ONCE.

Prototype

MqttQoS AT_MOST_ONCE

To view the source code for io.netty.handler.codec.mqtt MqttQoS AT_MOST_ONCE.

Click Source Link

Usage

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();
}