package ch.epfl.gsn.networking.mqtt; import java.io.Serializable; import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken; import org.eclipse.paho.client.mqttv3.MqttAsyncClient; import org.eclipse.paho.client.mqttv3.MqttCallbackExtended; import org.eclipse.paho.client.mqttv3.MqttException; import org.eclipse.paho.client.mqttv3.MqttMessage; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import ch.epfl.gsn.beans.AddressBean; import ch.epfl.gsn.beans.DataField; import ch.epfl.gsn.beans.StreamElement; import ch.epfl.gsn.wrappers.AbstractWrapper; public class MQTTWrapper extends AbstractWrapper implements MqttCallbackExtended{ private final transient Logger logger = LoggerFactory.getLogger(MQTTWrapper.class); private MqttAsyncClient client; private AddressBean addressBean; private String serverURI; private String clientID; private String topic; private int qos; @Override public DataField[] getOutputFormat() { return new DataField[] {new DataField( "raw_packet" , "BINARY" , "The packet contains raw data received in the MQTT payload." ) }; } @Override public boolean initialize() { try { addressBean = getActiveAddressBean( ); serverURI = addressBean.getPredicateValue("uri"); if ( serverURI == null || serverURI.trim().length() == 0 ) { logger.error( "The uri parameter is missing from the MQTT wrapper, initialization failed." ); return false; } clientID = addressBean.getPredicateValue("client_id"); if ( clientID == null || clientID.trim().length() == 0 ) { logger.error( "The client_id parameter is missing from the MQTT wrapper, initialization failed." ); return false; } topic = addressBean.getPredicateValue("topic"); if ( topic == null || topic.trim().length() == 0 ) { logger.error( "The topic parameter is missing from the MQTT wrapper, initialization failed." ); return false; } qos = addressBean.getPredicateValueAsInt("qos", 0); if (qos < 0 || qos > 2) { logger.error( "The qos parameter from MQTT wrapper can be 0, 1 or 2 (found "+qos+"), initialization failed." ); return false; } client = new MqttAsyncClient(serverURI, clientID); client.setCallback(this); client.connect(); }catch (Exception e){ logger.error("Error in instanciating MQTT broker with "+topic+" @ "+serverURI,e); return false; } return true; } @Override public void dispose() { try { if (client.isConnected()){ client.unsubscribe(topic); client.disconnect(); } client.close(); } catch (MqttException e) { logger.warn("Error while closing the MQTT client.", e); } } @Override public String getWrapperName() { return "MQTTWrapper["+topic+"]"; } @Override public void connectionLost(Throwable e) { logger.warn("Connection to MQTT server lost. Reconnecting in 3s...", e); try { Thread.sleep(3000); client.reconnect(); } catch (Exception e1) { logger.error("Error while reconnecting to server "+ serverURI, e1); } } @Override public void deliveryComplete(IMqttDeliveryToken token) { //MQTTWrapper doesn't publish } @Override public void messageArrived(String s, MqttMessage m) throws Exception { logger.info("Message received on topic " + s + ": "+new String(m.getPayload())); StreamElement streamElement = new StreamElement(getOutputFormat(), new Serializable[] {m.getPayload()}, System.currentTimeMillis()); postStreamElement(streamElement); } @Override public void connectComplete(boolean reconnect, String s) { if (!reconnect){ try { client.subscribe(topic, qos); } catch (MqttException e) { logger.error("Error while subscribing to topic "+topic+" with qos "+qos, e); } }else{ logger.debug("MQTT server reconnected "+s); } } }