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