package cgl.iotcloud.transport.mqtt;
import org.fusesource.hawtbuf.Buffer;
import org.fusesource.hawtbuf.UTF8Buffer;
import org.fusesource.mqtt.client.*;
import org.fusesource.mqtt.codec.MQTTFrame;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.net.URISyntaxException;
import java.util.UUID;
import java.util.concurrent.BlockingQueue;
public class MQTTConsumer {
private static Logger LOG = LoggerFactory.getLogger(MQTTConsumer.class);
private CallbackConnection connection;
private String url;
private int port;
private BlockingQueue messages;
private String queueName;
private boolean trace = false;
private QoS qoS;
public MQTTConsumer(String url, int port, BlockingQueue messages, String queueName) {
this(url, port, messages, queueName, QoS.AT_MOST_ONCE);
}
public MQTTConsumer(String url, int port, BlockingQueue messages, String queueName, QoS qoS) {
this.url = url;
this.messages = messages;
this.queueName = queueName;
this.qoS = qoS;
this.port = port;
}
public void setTrace(boolean trace) {
this.trace = trace;
}
private enum State {
INIT,
CONNECTED,
TOPIC_CONNECTED,
DISCONNECTED,
}
private State state = State.INIT;
public void open() {
MQTT mqtt = new MQTT();
try {
if (port != -1) {
mqtt.setHost(url, port);
} else {
mqtt.setHost(url);
}
} catch (URISyntaxException e) {
String msg = "Invalid URL for the MQTT Broker";
LOG.error(msg, e);
throw new RuntimeException(msg, e);
}
if (trace) {
mqtt.setTracer(new Tracer() {
@Override
public void onReceive(MQTTFrame frame) {
LOG.info("recv: " + frame);
}
@Override
public void onSend(MQTTFrame frame) {
LOG.info("send: " + frame);
}
@Override
public void debug(String message, Object... args) {
LOG.info(String.format("debug: " + message, args));
}
});
}
connection = mqtt.callbackConnection();
// Start add a listener to process subscription messages, and start the
// resume the connection so it starts receiving messages from the socket.
connection.listener(new Listener() {
public void onConnected() {
LOG.debug("connected");
}
public void onDisconnected() {
LOG.debug("disconnected");
}
public void onPublish(UTF8Buffer topic, Buffer payload, Runnable onComplete) {
final String uuid = UUID.randomUUID().toString();
try {
MQTTMessage message = new MQTTMessage(payload, topic.toString());
messages.put(message);
onComplete.run();
} catch (InterruptedException e) {
LOG.error("Failed to put the message to queue", e);
}
}
public void onFailure(Throwable value) {
LOG.warn("Connection failure: {}", value);
connection.disconnect(null);
state = State.DISCONNECTED;
}
});
connection.getDispatchQueue().execute(new Runnable() {
@Override
public void run() {
connection.connect(new Callback<Void>() {
public void onFailure(Throwable value) {
state = State.INIT;
String s = "Failed to connect to the broker";
LOG.error(s, value);
throw new RuntimeException(s, value);
}
// Once we connect..
public void onSuccess(Void v) {
connection.getDispatchQueue().execute(new Runnable() {
@Override
public void run() {
// Subscribe to a topic
Topic[] topics = {new Topic(queueName, qoS)};
connection.subscribe(topics, new Callback<byte[]>() {
public void onSuccess(byte[] qoses) {
// The result of the subcribe request.
LOG.debug("Subscribed to the topic {}", queueName);
state = State.TOPIC_CONNECTED;
}
public void onFailure(Throwable value) {
LOG.error("Failed to subscribe to topic", value);
connection.disconnect(null);
state = State.DISCONNECTED;
}
});
}
});
}
});
}
});
}
public void close() {
if (connection != null && (state == State.CONNECTED || state == State.TOPIC_CONNECTED)) {
connection.getDispatchQueue().execute(new Runnable() {
@Override
public void run() {
// To disconnect..
connection.disconnect(new Callback<Void>() {
public void onSuccess(Void v) {
// called once the connection is disconnected.
state = State.DISCONNECTED;
}
public void onFailure(Throwable value) {
// Disconnects never fail.
state = State.DISCONNECTED;
}
});
}
});
}
}
}