Search in sources :

Example 1 with DataTransportToken

use of org.eclipse.kura.data.DataTransportToken in project kura by eclipse.

the class MqttDataTransport method publish.

/*
     * (non-Javadoc)
     * 
     * @see org.eclipse.kura.data.DataPublisherService#publish(java.lang.String
     * , byte[], int, boolean)
     * 
     * DataConnectException this can be easily recovered connecting the service.
     * TooManyInflightMessagesException the caller SHOULD retry publishing the
     * message at a later time. RuntimeException (unchecked) all other
     * unrecoverable faults that are not recoverable by the caller.
     */
@Override
public DataTransportToken publish(String topic, byte[] payload, int qos, boolean retain) throws KuraTooManyInflightMessagesException, KuraException, KuraNotConnectedException {
    if (this.m_mqttClient == null || !this.m_mqttClient.isConnected()) {
        throw new KuraNotConnectedException("Not connected");
    }
    topic = replaceTopicVariables(topic);
    s_logger.info("Publishing message on topic: {} with QoS: {}", topic, qos);
    MqttMessage message = new MqttMessage();
    message.setPayload(payload);
    message.setQos(qos);
    message.setRetained(retain);
    Integer messageId = null;
    try {
        IMqttDeliveryToken token = this.m_mqttClient.publish(topic, message);
        // At present Paho ALWAYS allocates (gets and increments) internally
        // a message ID,
        // even for messages published with QoS == 0.
        // Of course, for QoS == 0 this "internal" message ID will not hit
        // the wire.
        // On top of that, messages published with QoS == 0 are confirmed
        // in the deliveryComplete callback.
        // Another implementation might behave differently
        // and only allocate a message ID for messages published with QoS >
        // 0.
        // We don't want to rely on this and only return and confirm IDs
        // of messages published with QoS > 0.
        s_logger.debug("Published message with ID: {}", token.getMessageId());
        if (qos > 0) {
            messageId = Integer.valueOf(token.getMessageId());
        }
    } catch (MqttPersistenceException e) {
        // This is probably an unrecoverable internal error
        s_logger.error("Cannot publish on topic: {}", topic, e);
        throw new IllegalStateException("Cannot publish on topic: " + topic, e);
    } catch (MqttException e) {
        if (e.getReasonCode() == MqttException.REASON_CODE_MAX_INFLIGHT) {
            s_logger.info("Too many inflight messages");
            throw new KuraTooManyInflightMessagesException(e, "Too many in-fligh messages");
        } else {
            s_logger.error("Cannot publish on topic: " + topic, e);
            throw KuraException.internalError(e, "Cannot publish on topic: " + topic);
        }
    }
    DataTransportToken token = null;
    if (messageId != null) {
        token = new DataTransportToken(messageId, this.m_sessionId);
    }
    return token;
}
Also used : MqttMessage(org.eclipse.paho.client.mqttv3.MqttMessage) DataTransportToken(org.eclipse.kura.data.DataTransportToken) MqttException(org.eclipse.paho.client.mqttv3.MqttException) MqttPersistenceException(org.eclipse.paho.client.mqttv3.MqttPersistenceException) KuraNotConnectedException(org.eclipse.kura.KuraNotConnectedException) KuraTooManyInflightMessagesException(org.eclipse.kura.KuraTooManyInflightMessagesException) IMqttDeliveryToken(org.eclipse.paho.client.mqttv3.IMqttDeliveryToken)

Example 2 with DataTransportToken

use of org.eclipse.kura.data.DataTransportToken in project kura by eclipse.

the class DataServiceImpl method publishInternal.

// It's very important that the publishInternal and messageConfirmed methods are synchronized
private synchronized void publishInternal(DataMessage message) throws KuraConnectException, KuraTooManyInflightMessagesException, KuraStoreException, KuraException {
    String topic = message.getTopic();
    byte[] payload = message.getPayload();
    int qos = message.getQos();
    boolean retain = message.isRetain();
    int msgId = message.getId();
    s_logger.debug("Publishing message with ID: {} on topic: {}, priority: {}", new Object[] { msgId, topic, message.getPriority() });
    DataTransportToken token = this.m_dataTransportService.publish(topic, payload, qos, retain);
    if (token == null) {
        this.m_store.published(msgId);
        s_logger.debug("Published message with ID: {}", msgId);
    } else {
        // Check if the token is already tracked in the map (in which case we are in trouble)
        Integer trackedMsgId = this.m_inFlightMsgIds.get(token);
        if (trackedMsgId != null) {
            s_logger.error("Token already tracked: " + token.getSessionId() + "-" + token.getMessageId());
        }
        this.m_inFlightMsgIds.put(token, msgId);
        this.m_store.published(msgId, token.getMessageId(), token.getSessionId());
        s_logger.debug("Published message with ID: {} and MQTT message ID: {}", msgId, token.getMessageId());
    }
}
Also used : DataTransportToken(org.eclipse.kura.data.DataTransportToken)

Example 3 with DataTransportToken

use of org.eclipse.kura.data.DataTransportToken in project kura by eclipse.

the class MqttDataTransport method deliveryComplete.

@Override
public void deliveryComplete(IMqttDeliveryToken token) {
    if (token == null) {
        s_logger.error("null token");
        return;
    }
    // Weird, tokens related to messages published with QoS > 0 have a null
    // nested message
    MqttMessage msg = null;
    try {
        msg = token.getMessage();
    } catch (MqttException e) {
        s_logger.error("Cannot get message", e);
        return;
    }
    if (msg != null) {
        // Note that Paho call this also for messages published with QoS ==
        // 0.
        // We don't want to rely on that and we drop asynchronous confirms
        // for QoS == 0.
        int qos = msg.getQos();
        if (qos == 0) {
            s_logger.debug("Ignoring deliveryComplete for messages published with QoS == 0");
            return;
        }
    }
    int id = token.getMessageId();
    s_logger.debug("Delivery complete for message with ID: {}", id);
    // FIXME: We should be more selective here and only call the listener
    // that actually published the message.
    // Anyway we don't have such a mapping and so the publishers MUST track
    // their own
    // identifiers and filter confirms.
    // FIXME: it can happen that the listener that has published the message
    // has not come up yet.
    // This is the scenario:
    // * Paho has some in-flight messages.
    // * Kura gets stopped, crashes or the power is removed.
    // * Kura starts again, Paho connects and restores in-flight messages
    // from its persistence.
    // * These messages are delivered (this callback gets called) before the
    // publisher (also a DataPublisherListener)
    // * has come up (not yet tracked by the OSGi container).
    // These confirms will be lost!
    // notify the listeners
    DataTransportToken dataPublisherToken = new DataTransportToken(id, this.m_sessionId);
    this.m_dataTransportListeners.onMessageConfirmed(dataPublisherToken);
}
Also used : MqttMessage(org.eclipse.paho.client.mqttv3.MqttMessage) DataTransportToken(org.eclipse.kura.data.DataTransportToken) MqttException(org.eclipse.paho.client.mqttv3.MqttException)

Example 4 with DataTransportToken

use of org.eclipse.kura.data.DataTransportToken in project kura by eclipse.

the class DataServiceImpl method activate.

// ----------------------------------------------------------------
// 
// Activation APIs
// 
// ----------------------------------------------------------------
protected void activate(ComponentContext componentContext, Map<String, Object> properties) {
    String pid = (String) properties.get(ConfigurationService.KURA_SERVICE_PID);
    s_logger.info("Activating {}...", pid);
    this.m_reconnectExecutor = Executors.newSingleThreadScheduledExecutor();
    this.m_publisherExecutor = Executors.newSingleThreadScheduledExecutor();
    this.m_congestionExecutor = Executors.newSingleThreadScheduledExecutor();
    this.m_properties.putAll(properties);
    String[] parts = pid.split("-");
    String table = "ds_messages";
    if (parts.length > 1) {
        table += "_" + parts[1];
    }
    this.m_store = new DbDataStore(table);
    try {
        this.m_store.start(this.m_dbService, (Integer) this.m_properties.get(STORE_HOUSEKEEPER_INTERVAL_PROP_NAME), (Integer) this.m_properties.get(STORE_PURGE_AGE_PROP_NAME), (Integer) this.m_properties.get(STORE_CAPACITY_PROP_NAME));
        // The initial list of in-flight messages
        List<DataMessage> inFlightMsgs = this.m_store.allInFlightMessagesNoPayload();
        // The map associating a DataTransportToken with a message ID
        this.m_inFlightMsgIds = new ConcurrentHashMap<DataTransportToken, Integer>();
        if (inFlightMsgs != null) {
            for (DataMessage message : inFlightMsgs) {
                DataTransportToken token = new DataTransportToken(message.getPublishedMessageId(), message.getSessionId());
                this.m_inFlightMsgIds.put(token, message.getId());
                s_logger.debug("Restored in-fligh messages from store. Topic: {}, ID: {}, MQTT message ID: {}", new Object[] { message.getTopic(), message.getId(), message.getPublishedMessageId() });
            }
        }
    } catch (KuraStoreException e) {
        s_logger.error("Failed to start store", e);
        throw new ComponentException("Failed to start store", e);
    }
    this.m_dataServiceListeners = new DataServiceListenerS(componentContext);
    // Register the component in the CloudConnectionStatus Service
    this.m_cloudConnectionStatusService.register(this);
    this.m_dataTransportService.addDataTransportListener(this);
    startReconnectTask();
}
Also used : DataTransportToken(org.eclipse.kura.data.DataTransportToken) DbDataStore(org.eclipse.kura.core.data.store.DbDataStore) ComponentException(org.osgi.service.component.ComponentException) KuraStoreException(org.eclipse.kura.KuraStoreException)

Aggregations

DataTransportToken (org.eclipse.kura.data.DataTransportToken)4 MqttException (org.eclipse.paho.client.mqttv3.MqttException)2 MqttMessage (org.eclipse.paho.client.mqttv3.MqttMessage)2 KuraNotConnectedException (org.eclipse.kura.KuraNotConnectedException)1 KuraStoreException (org.eclipse.kura.KuraStoreException)1 KuraTooManyInflightMessagesException (org.eclipse.kura.KuraTooManyInflightMessagesException)1 DbDataStore (org.eclipse.kura.core.data.store.DbDataStore)1 IMqttDeliveryToken (org.eclipse.paho.client.mqttv3.IMqttDeliveryToken)1 MqttPersistenceException (org.eclipse.paho.client.mqttv3.MqttPersistenceException)1 ComponentException (org.osgi.service.component.ComponentException)1