package se.chalmers.pd.playlistmanager;
import org.eclipse.paho.client.mqttv3.MqttCallback;
import org.eclipse.paho.client.mqttv3.MqttClient;
import org.eclipse.paho.client.mqttv3.MqttDefaultFilePersistence;
import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
import org.eclipse.paho.client.mqttv3.MqttException;
import org.eclipse.paho.client.mqttv3.MqttMessage;
import org.eclipse.paho.client.mqttv3.MqttPersistenceException;
import org.eclipse.paho.client.mqttv3.MqttSecurityException;
import org.eclipse.paho.client.mqttv3.MqttTopic;
import android.os.Environment;
import android.util.Log;
/**
* This thread launches an MQTT client and subscribes to the systems basic
* topics. It handles incoming and outgoing messages by subscribing and
* publishing to topics.
* <p/>
* Since it does asyncronous work it requires a callback which it can call
* when the work is done. The user of this class must therefore implement
* the Callbacks interface.
*/
public class MqttWorker extends Thread {
private static final String STORAGE_DIRECTORY = "/infotainment/";
private static final String WORKER_NAME = "MqttWorker";
private static final String CLIENT_NAME = "playlistmanager";
private static String BROKER_URL = "tcp://192.168.43.147:1883";
private MqttClient mqttClient;
private Callback callback;
/**
* The user of this class must implement
* the Callbacks interface to be able to receive messages.
*/
public interface Callback {
/**
* Called when a message has been received.
*
* @param topic the topic the message was received on
* @param payload the content of the message
*/
public void onMessage(String topic, String payload);
/**
* Called when the client has connected (or failed)
*
* @param connected true if connected, false if not
*/
public void onConnected(boolean connected);
}
/**
* Instantiates the class and saves a callback
*
* @param callback the callback to use
*/
public MqttWorker(Callback callback) {
this.callback = callback;
}
/**
* Sets up a persisence directory and connects the client. Also adds
* a mqtt callback to the client that is called when a message is received. This
* is required by the Paho library.
* <p/>
* Also triggers the onConnected callback with a message of success if connected.
*/
@Override
public void run() {
try {
// Sets up the client and subscribes to topics
String tmpDir = Environment.getExternalStorageDirectory() + STORAGE_DIRECTORY;
MqttDefaultFilePersistence dataStore = new MqttDefaultFilePersistence(tmpDir);
mqttClient = new MqttClient(BROKER_URL, CLIENT_NAME, dataStore);
mqttClient.setCallback(new CustomMqttCallback());
if (!connect()) {
callback.onConnected(false);
return;
}
} catch (MqttException e) {
e.printStackTrace();
}
}
/**
* Connectes the client to the broker.
*
* @return true if connected
*/
private boolean connect() {
boolean connected = false;
if (mqttClient != null) {
try {
mqttClient.connect();
notifyOnConnected();
connected = true;
} catch (MqttSecurityException e) {
Log.e(WORKER_NAME, "Could not connect to the broker " + e.getMessage());
} catch (MqttException e) {
Log.e(WORKER_NAME, "Could not connect to the broker " + e.getMessage());
}
}
return connected;
}
/**
* Publishes a message on the given topic.
*
* @param topic
* @param message should be stringified JSON
*/
public void publish(String topic, String message) {
Log.d(WORKER_NAME, "publishing topic " + topic + " with message " + message);
try {
MqttTopic mqttTopic = mqttClient.getTopic(topic);
if (mqttTopic != null) {
MqttMessage payload = new MqttMessage(message.getBytes());
mqttTopic.publish(payload);
}
} catch (MqttPersistenceException e) {
e.printStackTrace();
} catch (MqttException e) {
e.printStackTrace();
}
}
/**
* Subscribes to the given topic
*
* @param topic
*/
public void subscribe(String topic) {
try {
mqttClient.subscribe(topic, 2);
} catch (MqttSecurityException e) {
e.printStackTrace();
} catch (MqttException e) {
e.printStackTrace();
}
}
/**
* Unsubscribes from the given topic
*
* @param topic
*/
public void unsubscribe(String topic) {
try {
mqttClient.unsubscribe(topic);
} catch (MqttException e) {
e.printStackTrace();
}
}
private void notifyOnConnected() {
callback.onConnected(true);
}
/**
* Called when messages are received. Filters out data from installation
* messages since it is too much to pass around as Strings.
*/
class CustomMqttCallback implements MqttCallback {
@Override
public void messageArrived(MqttTopic topic, MqttMessage message) {
String payload = message.toString();
String stringTopic = topic.toString();
callback.onMessage(stringTopic, payload);
Log.d(WORKER_NAME, "messageArrived" + "topic:" + stringTopic + ", message:" + payload);
}
@Override
public void deliveryComplete(MqttDeliveryToken token) {
Log.d(WORKER_NAME, "deliveryComplete " + "token:" + token);
}
@Override
public void connectionLost(Throwable cause) {
Log.d(WORKER_NAME, "connectionLost " + "cause:" + cause.toString());
}
}
/**
* Sets the broker url
*
* @param url the url to the broker
*/
public void setUrl(String url) {
BROKER_URL = url;
}
/**
* Disconnects from the broker
*/
public void disconnect() {
try {
if (mqttClient != null) {
mqttClient.disconnect();
}
} catch (MqttException e) {
Log.d(WORKER_NAME, "disconnect " + "exception:" + e.toString());
}
}
}