Added multiple global subscribers and improved logging
This commit is contained in:
parent
214bf0f40d
commit
46b608489d
1 changed files with 40 additions and 20 deletions
|
|
@ -54,7 +54,7 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
public static final int MQTT_PORT_TLS = 8883;
|
public static final int MQTT_PORT_TLS = 8883;
|
||||||
public static final int MQTT_PROTOCOL_VERSION = 0x04; // MQTT 3.1.1
|
public static final int MQTT_PROTOCOL_VERSION = 0x04; // MQTT 3.1.1
|
||||||
|
|
||||||
private MqttSubscriptionListener globalListener;
|
private List<MqttSubscriptionListener> globalListeners = new ArrayList<>();
|
||||||
private Map<String, List<MqttSubscriptionListener>> subscriptionListeners = new HashMap<>();
|
private Map<String, List<MqttSubscriptionListener>> subscriptionListeners = new HashMap<>();
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -86,29 +86,43 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign a listener that will be called for any topic. Provide null to disable.
|
* Assign a listener that will be called for any topic.
|
||||||
|
*
|
||||||
|
* @param listener the listener that will be called.
|
||||||
*/
|
*/
|
||||||
public void setGlobalSubscriber(MqttSubscriptionListener listener) {
|
public void addGlobalSubscriber(MqttSubscriptionListener listener) {
|
||||||
globalListener = listener;
|
globalListeners.add(listener);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove the given listener from global subscribers.
|
||||||
|
*
|
||||||
|
* @param listener the listener that should not be called anymore.
|
||||||
|
*/
|
||||||
|
public void removeGlobalSubscriber(MqttSubscriptionListener listener) {
|
||||||
|
globalListeners.remove(listener);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add the listener as a subscriber of the specific topic.
|
* Add the listener as a subscriber of the specific topic.
|
||||||
|
*
|
||||||
|
* @param topic the topic that will be subscribed to.
|
||||||
|
* @param listener the listener that will be called.
|
||||||
*/
|
*/
|
||||||
public synchronized void subscribe(String topic, MqttSubscriptionListener listener) {
|
public synchronized void subscribe(String topic, MqttSubscriptionListener listener) {
|
||||||
if (topic == null || topic.isEmpty() || listener == null)
|
if (topic == null || topic.isEmpty() || listener == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!subscriptionListeners.containsKey(topic)) {
|
if (!subscriptionListeners.containsKey(topic)) {
|
||||||
logger.fine("Creating new topic: " + topic);
|
logger.finest("Creating new topic: " + topic);
|
||||||
subscriptionListeners.put(topic, new ArrayList<>());
|
subscriptionListeners.put(topic, new ArrayList<>());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MqttSubscriptionListener> topicSubscriptions = subscriptionListeners.get(topic);
|
List<MqttSubscriptionListener> topicSubscriptions = subscriptionListeners.get(topic);
|
||||||
|
|
||||||
if (!topicSubscriptions.contains(listener)) {
|
if (!topicSubscriptions.contains(listener)) {
|
||||||
logger.finer("New subscriber on topic (" + topic + "), subscriber count: " + topicSubscriptions.size());
|
|
||||||
topicSubscriptions.add(listener);
|
topicSubscriptions.add(listener);
|
||||||
|
logger.finer("New subscriber on topic: " + topic + " (subscriber count: " + topicSubscriptions.size() + ")");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -116,16 +130,14 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
* Publish data to the specific topic
|
* Publish data to the specific topic
|
||||||
*/
|
*/
|
||||||
public void publish(String topic, byte[] data) {
|
public void publish(String topic, byte[] data) {
|
||||||
logger.finer("Data has been published to topic (" + topic + ")");
|
logger.finer("Data has been published to topic: " + topic);
|
||||||
|
|
||||||
if (globalListener != null)
|
if (globalListeners != null)
|
||||||
globalListener.dataPublished(topic, data);
|
globalListeners.forEach(listener -> listener.dataPublished(topic, data));
|
||||||
|
|
||||||
List<MqttSubscriptionListener> topicSubscriptions = subscriptionListeners.get(topic);
|
List<MqttSubscriptionListener> topicSubscriptions = subscriptionListeners.get(topic);
|
||||||
if (topicSubscriptions != null) {
|
if (topicSubscriptions != null) {
|
||||||
for (MqttSubscriptionListener subscriber : topicSubscriptions) {
|
topicSubscriptions.forEach(subscriber -> subscriber.dataPublished(topic, data));
|
||||||
subscriber.dataPublished(topic, data);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -154,10 +166,10 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
List<MqttSubscriptionListener> topicSubscriptions = subscriptionListeners.get(topic);
|
List<MqttSubscriptionListener> topicSubscriptions = subscriptionListeners.get(topic);
|
||||||
|
|
||||||
if (topicSubscriptions.remove(listener)) {
|
if (topicSubscriptions.remove(listener)) {
|
||||||
logger.finer("Subscriber unsubscribed from topic (" + topic + "), subscriber count: " + topicSubscriptions.size());
|
logger.finer("Subscriber unsubscribed from topic " + topic + " (subscriber count: " + topicSubscriptions.size() + ")");
|
||||||
|
|
||||||
if (topicSubscriptions.isEmpty()) {
|
if (topicSubscriptions.isEmpty()) {
|
||||||
logger.fine("Removing empty topic: " + topic);
|
logger.finest("Removing empty topic: " + topic);
|
||||||
subscriptionListeners.remove(topic);
|
subscriptionListeners.remove(topic);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -172,7 +184,7 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
|
|
||||||
private boolean disconnected = false;
|
private boolean disconnected = false;
|
||||||
/** A message that should be sent in case the connection to client is abnormally disconnected */
|
/** A message that should be sent in case the connection to client is abnormally disconnected */
|
||||||
private MqttPacketHeader willPacket = null;
|
private MqttPacketPublish willPacket = null;
|
||||||
/** The maximum amount of time(seconds) to wait for activity from client, 0 means no timeout */
|
/** The maximum amount of time(seconds) to wait for activity from client, 0 means no timeout */
|
||||||
private int connectionTimeoutTime = 0;
|
private int connectionTimeoutTime = 0;
|
||||||
|
|
||||||
|
|
@ -200,6 +212,8 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
public void run() {
|
public void run() {
|
||||||
try {
|
try {
|
||||||
// Setup connection
|
// Setup connection
|
||||||
|
|
||||||
|
logger.fine("[" + socket.getInetAddress() + "] New MQTT client connected.");
|
||||||
MqttPacketHeader connectPacket = MqttPacket.read(in);
|
MqttPacketHeader connectPacket = MqttPacket.read(in);
|
||||||
handleConnect(connectPacket);
|
handleConnect(connectPacket);
|
||||||
|
|
||||||
|
|
@ -214,11 +228,12 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
}
|
}
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
logger.log(Level.SEVERE, null, e);
|
logger.log(Level.WARNING, "[" + socket.getInetAddress() + "] There was a issue with the client connection.", e);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
sendWillPacket();
|
sendWillPacket();
|
||||||
|
|
||||||
|
logger.fine("[" + socket.getInetAddress() + "] MQTT client disconnected.");
|
||||||
socket.close();
|
socket.close();
|
||||||
broker.unsubscribe(this);
|
broker.unsubscribe(this);
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
|
@ -266,9 +281,10 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
|
|
||||||
// Handle will message
|
// Handle will message
|
||||||
if (conn.flagWillFlag) {
|
if (conn.flagWillFlag) {
|
||||||
// TODO: Read will message from payload
|
logger.fine("[" + socket.getInetAddress() + "] Registered will packet for topic: " + conn.willTopic);
|
||||||
//willPacket = xxx
|
willPacket = new MqttPacketPublish();
|
||||||
//throw new UnsupportedOperationException("Will packet currently not supported.");
|
willPacket.topicName = conn.willTopic;
|
||||||
|
willPacket.payload = conn.willPayload;
|
||||||
} else {
|
} else {
|
||||||
willPacket = null;
|
willPacket = null;
|
||||||
}
|
}
|
||||||
|
|
@ -317,7 +333,7 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
|
|
||||||
// Close connection
|
// Close connection
|
||||||
default:
|
default:
|
||||||
logger.warning("Received unknown packet type: " + packet.type + " (" + packet.getClass() + ")");
|
logger.warning("[" + socket.getInetAddress() + "] Received unknown packet type: " + packet.type + " (" + packet.getClass() + ")");
|
||||||
sendWillPacket();
|
sendWillPacket();
|
||||||
/* FALLTHROUGH */
|
/* FALLTHROUGH */
|
||||||
case MqttPacketHeader.PACKET_TYPE_DISCONNECT:
|
case MqttPacketHeader.PACKET_TYPE_DISCONNECT:
|
||||||
|
|
@ -332,6 +348,7 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
if (publishPacket.getFlagQoS() != 0)
|
if (publishPacket.getFlagQoS() != 0)
|
||||||
throw new UnsupportedOperationException("QoS larger then 0 not supported.");
|
throw new UnsupportedOperationException("QoS larger then 0 not supported.");
|
||||||
|
|
||||||
|
logger.finer("[" + socket.getInetAddress() + "] Publishing to topic: " + publishPacket.topicName);
|
||||||
broker.publish(publishPacket.topicName, publishPacket.payload);
|
broker.publish(publishPacket.topicName, publishPacket.payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -340,6 +357,7 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
subscribeAckPacket.packetId = subscribePacket.packetId;
|
subscribeAckPacket.packetId = subscribePacket.packetId;
|
||||||
|
|
||||||
for (MqttSubscribePayload payload : subscribePacket.payloads) {
|
for (MqttSubscribePayload payload : subscribePacket.payloads) {
|
||||||
|
logger.finer("[" + socket.getInetAddress() + "] Subscribing to topic: " + payload.topicFilter);
|
||||||
broker.subscribe(payload.topicFilter, this);
|
broker.subscribe(payload.topicFilter, this);
|
||||||
|
|
||||||
// Prepare response
|
// Prepare response
|
||||||
|
|
@ -353,6 +371,7 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
|
|
||||||
private void handleUnsubscribe(MqttPacketUnsubscribe unsubscribePacket) throws IOException {
|
private void handleUnsubscribe(MqttPacketUnsubscribe unsubscribePacket) throws IOException {
|
||||||
for (MqttUnsubscribePayload payload : unsubscribePacket.payloads) {
|
for (MqttUnsubscribePayload payload : unsubscribePacket.payloads) {
|
||||||
|
logger.finer("[" + socket.getInetAddress() + "] Unsubscribing from topic: " + payload.topicFilter);
|
||||||
broker.unsubscribe(payload.topicFilter, this);
|
broker.unsubscribe(payload.topicFilter, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -370,6 +389,7 @@ public class MqttBroker extends ThreadedTCPNetworkServer {
|
||||||
|
|
||||||
private void sendWillPacket() throws IOException {
|
private void sendWillPacket() throws IOException {
|
||||||
if (willPacket != null) {
|
if (willPacket != null) {
|
||||||
|
logger.fine("[" + socket.getInetAddress() + "] Publishing will packet.");
|
||||||
sendPacket(willPacket);
|
sendPacket(willPacket);
|
||||||
willPacket = null;
|
willPacket = null;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue