how to publish mqtt message with retained true in paho on android - java

I am using Paho java client library for my on android App. Code provided below.
MqttAndroidClient client_Panic = new MqttAndroidClient(this.getApplicationContext(), serverURL, CLIENT_ID);
try {
MqttConnectOptions options = new MqttConnectOptions();
options.setMqttVersion(MqttConnectOptions.MQTT_VERSION_3_1);
options.setCleanSession(false);
options.setKeepAliveInterval(90);
options.setConnectionTimeout(100);
IMqttToken token = client_Panic.connect(options);
//Few callbacks
} catch (MqttException e) {
e.printStackTrace();
}
And publishing messages, when required
String msg = "messages";
MqttMessage message = new MqttMessage();
message.setPayload(msg.getBytes());
try {
client_Panic.publish(topic, message);
} catch (MqttException e) {
e.printStackTrace();
}
It is working fine, but somehow incomplete. What I need is, whenever other client subscribed to same topic, should get the last retained message, which publisher might had published earlier.
For that I searched on their documentation, I got
protected void setWill(String topic,
MqttMessage msg,
int qos,
boolean retained)
So setWill as per documentation have the option to enable the retained option. So I tried with
options.setConnectionTimeout(100);
options.setWill(topic,null,2,true); // This place I added
IMqttToken token = client_Panic.connect(options);
But got error java.lang.IllegalArgumentException at org.eclipse.paho.client.mqttv3.MqttConnectOptions.validateWill on the line containing options.setWill.
Is setWill is the correct method for enabling retained true on android, if yes then what parameters need to be provided or else their is any other method for enabling it on android? TIA.

The Will is a very specific message that is only published if the client disconnects uncleanly from the broker (e.g. network drops).
You can not set a null message as the Will message which is what the error is about.
The retained state is specific to a given message so you do not set it globally, it is set on each message. To mark a message as retained when you just call the setRetained(boolean) e.g.
String msg = "messages";
MqttMessage message = new MqttMessage();
message.setRetained(true);
message.setPayload(msg.getBytes());
try {
client_Panic.publish(topic, message);
} catch (MqttException e) {
e.printStackTrace();
}

Related

Pubnub V4 Migration Callbacks

I am trying to update my Code from pubnub sdk v3 to v4 and I am stuck at callbacks.
I have following function which I would like to update:
void transmitMessage(String toID, JSONObject packet){
if (this.id==null){ .
mRtcListener.onDebug(new PnRTCMessage("Cannot transmit before calling Client.connect"));
}
try {
JSONObject message = new JSONObject();
message.put(PnRTCMessage.JSON_PACKET, packet);
message.put(PnRTCMessage.JSON_ID, "");
message.put(PnRTCMessage.JSON_NUMBER, this.id);
this.mPubNub.publish(toID, message, new Callback() {
#Override
public void successCallback(String channel, Object message, String timetoken) {
mRtcListener.onDebug(new PnRTCMessage((JSONObject)message));
}
#Override
public void errorCallback(String channel, PubNubError error) {
mRtcListener.onDebug(new PnRTCMessage(error.errorObject));
}
});
} catch (JSONException e){
e.printStackTrace();
}
}
The docs say one does not Need to instantiate com.pubnub.api.Callback and one should use the new SubscribeCallback class. I am not sure how to handle it, the SubscribeCallback contains These Methods: Status, message and presence, currently I have a successCallback method and a errorCallback.
The code at https://www.pubnub.com/docs/android-java/api-reference-publish-and-subscribe#listeners should help you with this.
You can create listeners using the code below:
pubnub.addListener(new SubscribeCallback() {
#Override
public void status(PubNub pubnub, PNStatus status) {
switch (status.getOperation()) {
// let's combine unsubscribe and subscribe handling for ease of use
case PNSubscribeOperation:
case PNUnsubscribeOperation:
// note: subscribe statuses never have traditional
// errors, they just have categories to represent the
// different issues or successes that occur as part of subscribe
switch (status.getCategory()) {
case PNConnectedCategory:
// this is expected for a subscribe, this means there is no error or issue whatsoever
case PNReconnectedCategory:
// this usually occurs if subscribe temporarily fails but reconnects. This means
// there was an error but there is no longer any issue
case PNDisconnectedCategory:
// this is the expected category for an unsubscribe. This means there
// was no error in unsubscribing from everything
case PNUnexpectedDisconnectCategory:
// this is usually an issue with the internet connection, this is an error, handle appropriately
case PNAccessDeniedCategory:
// this means that PAM does allow this client to subscribe to this
// channel and channel group configuration. This is another explicit error
default:
// More errors can be directly specified by creating explicit cases for other
// error categories of `PNStatusCategory` such as `PNTimeoutCategory` or `PNMalformedFilterExpressionCategory` or `PNDecryptionErrorCategory`
}
case PNHeartbeatOperation:
// heartbeat operations can in fact have errors, so it is important to check first for an error.
// For more information on how to configure heartbeat notifications through the status
// PNObjectEventListener callback, consult <link to the PNCONFIGURATION heartbeart config>
if (status.isError()) {
// There was an error with the heartbeat operation, handle here
} else {
// heartbeat operation was successful
}
default: {
// Encountered unknown status type
}
}
}
#Override
public void message(PubNub pubnub, PNMessageResult message) {
String messagePublisher = message.getPublisher();
System.out.println("Message publisher: " + messagePublisher);
System.out.println("Message Payload: " + message.getMessage());
System.out.println("Message Subscription: " + message.getSubscription());
System.out.println("Message Channel: " + message.getChannel());
System.out.println("Message timetoken: " + message.getTimetoken());
}
#Override
public void presence(PubNub pubnub, PNPresenceEventResult presence) {
}
});
Once you've subscribed to a channel like below, when a message or presence event is received the above listeners will be called.
pubnub.subscribe()
.channels(Arrays.asList("my_channel")) // subscribe to channels
.withPresence() // also subscribe to related presence information
.execute();
Please note that we have recently launched new features with new types of listeners as well, all of which are listed in the link above.

How to check if subscriber is valid to accept the message received for a published topic on MQTT

I'm newbie in MQTT.
I am implementing MQTT in java and I am using below code for publisher to publish to a particualr topic,
public void publish()
{
MqttClient myClient = null;
MqttConnectOptions connOpt;
try {
// Subscription with Brokers
connOpt = new MqttConnectOptions();
connOpt.setAutomaticReconnect(true);
connOpt.setCleanSession(true);//if your not setting cleanSession to false then subscriptions shouldn't be persisted.
String clientID = UUID.randomUUID().toString().replace("-", "");
System.out.println("clientID " + clientID);
myClient = new MqttClient("tcp://192.168.10.500:1883", clientID);
myClient.connect(connOpt);
String myTopic = "Device1";
MqttTopic topic = myClient.getTopic(myTopic);
int pubQoS = 0;
MqttMessage message = new MqttMessage("mqttMessage".getBytes());
message.setQos(pubQoS);
message.setRetained(false);
MqttDeliveryToken token = null;
token = topic.publish(message);
System.out.println("publish successful with the message :: " + message);
// Wait until the message has been delivered to the broker
token.waitForCompletion();
} catch (MqttException me) {
} catch (Exception e) {
}
}
And then I am using below code to read the published message for a particular topic as a subscriber,
public void subscribe()
{
try {
MqttConnectOptions connOpt;
// Subscription with mqttBrokerEndPoint
connOpt = new MqttConnectOptions();
connOpt.setAutomaticReconnect(true);
connOpt.setCleanSession(true);//if your not setting cleanSession to false then subscriptions shouldn't be persisted.
String clientID = UUID.randomUUID().toString().replace("-", "");
System.out.println("clientID " + clientID);
MqttSubscriber mqttConnection = new MqttSubscriber();
myClient = new MqttClient("tcp://192.168.10.500:1883" clientID);
myClient.setCallback(mqttConnection);
myClient.connect(connOpt);
myClient.subscribe("Device1");
} catch (MqttException e) {
}
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
try {
System.out.println(message);
boolean isValidClient = true;// Here i need to check if this is the valid subscriber for the message publised on topic "Device1"
//if(isValidClient) {
if(message != null) {
System.out.println("message" + message.toString());
}
myClient.unsubscribe("Device1");
myClient.disconnect();
//}
}
catch(Exception e){}
}
The above implementation is working fine as it is.
Since I am very new to mqtt I have some doubts with the above implementation.
1) Is Client id in both publisher and subscriber should be SAME for one particular flow ?
or should different in both publisher and subscriber as above : which can be randomly generated?
String clientID = UUID.randomUUID().toString().replace("-", "");
This randomly generated clientID is working fine with both subscribing and publishing.
But, If I use same client for both publisher and subscriber and validate subscriber?
I mean use "clientID" myClient = new MqttClient(mqttBrokerEndPoint, "clientID"); in subsriber and then same "clientID" myClient = new MqttClient(mqttBrokerEndPoint, "clientID"); in publisher
I am getting the below socket error in mqtt broker console(used windows version) ,
1549414715: Socket error on client 82, disconnecting.
1549414715: New client connected from 192.168.10.500 as clientID (c1, k60).
1549414715: No will message specified.
1549414715: Sending CONNACK to 82 (0, 0)
1549414716: New connection from 192.168.10.500 on port 1883.
1549414716: Client 82 already connected, closing old connection.
1549414716: Socket error on client 82, disconnecting.
1549414716: New client connected from 192.168.10.500 as clientID (c1, k60).
1549414716: No will message specified.
1549414716: Sending CONNACK to 82 (0, 0)
1549414716: New connection from 192.168.10.500 on port 1883.
1549414716: Client 82 already connected, closing old connection.
1549414716: Socket error on client 82, disconnecting.
1549414716: New client connected from 192.168.10.500 as clientID (c1, k60).
1549414716: No will message specified.
1549414716: Sending CONNACK to 82 (0, 0)
and the above program is not working.
Can't we use same clientID for for both subscriber and publisher? Why is it resulting in socket error and programs not working?
2) Is username and password mandatory while implementation? Or can we establish a connection without those 2 below properties?
connOpt.setUserName(USERNAME);
connOpt.setPassword(PASSWORD.toCharArray());
3) Is pubQoS is mandatory to be used for publisher? I am currently using it as zero '0' ?
MqttMessage message = new MqttMessage(mqttMessage.getBytes());
message.setQos(0);
message.setRetained(false);
Also is retained attribute is mandatory for publisher?
4) Is these 2 below attributes mandatory while subscribing? I am using as below in code.
connOpt.setAutomaticReconnect(true);
connOpt.setCleanSession(true);//if your not setting cleanSession to
false then subscriptions shouldn't be persisted.
5) Also, Once Message is received from MQTT publisher in to MessageArrived callback as below, how to validate if this is valid subscriber and proceed with further logic?
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
try {
System.out.println(message);
boolean isValidClient = true;// Here i need to check if this is the valid subscriber for the message publised on topic "Device1"
//if valid subscriber only i need to read message publised on the topic "Device1"
**//if(isValidClient) {**
if(message != null) {
System.out.println("message" + message.toString());
}
myClient.unsubscribe("Device1");
myClient.disconnect();
//}
}
catch(Exception e){}
I mean which attribute MQTT API to check that this message is only sent for this subscriber and he can proceed further to use the message received in message arrived callback?
I.e, which attribute of MQTT api can be used to check if the received message is related to current PROCESS/STEP.(In SUbscriber Program as below)
IS the topic is the only common attributes between subscriber and publisher to validate subscriber in messageArrived callback ? or do we have any other common attribute to check a valid contract between subscriber and publisher?
Or should we used clientID to validate subscriber? But if i use the same clientID for subscriber and publisher I am getting the socket error which i have mentioned in point number 1.
How to proceed further on this?
1) You cannot use same client id for two mqtt client. Client ids for mqtt must be unique. You can create different topic for handling different operations. You can refer to the below answer
Two paho.mqtt clients subscribing to the same client localy
2) Username and password is optional. If your mqtt server is configured to use username and password then your client also need to pass username and password to mqtt server. Refer to the below link for understanding the code usage
How can i connect a Java mqtt client with username and password to an emqttd(EMQ) broker?
If you want advanced level go for tls/ssl security
https://dzone.com/articles/secure-communication-with-tls-and-the-mosquitto-broker
3) QOS - The Quality of Service (QoS) level is an agreement between the sender of a message and the receiver of a message that defines the guarantee of delivery for a specific message. Refer to the below link for more information on qos
https://www.hivemq.com/blog/mqtt-essentials-part-6-mqtt-quality-of-service-levels/
4) Auto Reconnect (True) - If mqtt server is disconnected during run time then client tries to reconnect to the server.
Clean Session (True) - On reconnecting to the mqtt server all older sessions associated with same client id will be deleted.
Clean Session (False) - On reconnecting to the mqtt server all older sessions associated with same client id will be retained. Mqtt server in some cases retains messages based on QOS level.
5) Try to create multiple topics for multiple operations. In message arrived method you can check on which topic message has arrived. Then you can call different methods based on that. Below codes are one of the way. You can find out best way that suits your needs. Cheers !!!!!
#Override
public void deliveryComplete(IMqttDeliveryToken token)
{
try
{
if(token.getTopics()[0].equals("TOPIC_A"))
{
//Do something
}
else if(token.getTopics()[0].equals("TOPIC_B"))
{
//Do something
}
}
catch (Exception e)
{
MQTTLogger.logSevere(e);
}
}
Json Format for data
First message
{
"client-name":"client1"
"data":""
}
Second message
{
"client-name":"client2"
"data":""
}

send message to single device using Firebase cloud with Java

I'm trying to send messages to single devices using their token from a Java application. I'm using the Firebase Admin SDK. Below is what I have
FileInputStream serviceAccount = null;
try {
serviceAccount = new FileInputStream("google-services.json");
} catch (FileNotFoundException e2) {
e2.printStackTrace();
}
FirebaseOptions options = null;
try {
options = new FirebaseOptions.Builder()
.setCredentials(GoogleCredentials.fromStream(serviceAccount))
.setDatabaseUrl("https://MYPROJECTID.firebaseio.com/")
.build();
} catch (IOException e1) {
e1.printStackTrace();
}
FirebaseApp.initializeApp(options);
String registrationToken = "MYDEVICETOKEN";
// See documentation on defining a message payload.
Message message = Message.builder().putData("time", "2:45").setToken(registrationToken)
.build();
// Send a message to the device corresponding to the provided
// registration token.
String response = null;
try {
response = FirebaseMessaging.getInstance().sendAsync(message).get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
// Response is a message ID string.
System.out.println("Successfully sent message: " + response);
But I get the following exception
java.io.IOException: Error reading credentials from stream, 'type' field not specified.
What am I doing wrong here?
Click on Generate new private key button.
The error means that your google-services.json file contains invalid data. GoogleCredentials class expects your file to have a type property, but it's not there.
Brief googling gave me this post regarding very similar problem. It says:
From the API Manager, just create select "Create credentials" >
"Service Account key" and generate a new key for the Service
that is associated to your Google Play account.

MQTT - Java Application Cannot see published message

I am working on an MQTT application in eclipse. I was earlier using mqtt-dashboard as the public broker and was able to see the messages that I was publishing on the dashboard. For some reason, this site is down so I switched to mosquitto. My code is same but still I am not able to publish messages to this broker. My code is as follows:
public static void main(String[] args) {
String topic = "home automation systems";
String content = "I am a test message";
int qos = 2;
String broker = "tcp://test.mosquitto.org:1883";
String clientId = "home automation";
MemoryPersistence persistence = new MemoryPersistence();
try {
MqttClient sampleClient = new MqttClient(broker, clientId, persistence);
MqttConnectOptions connOpts = new MqttConnectOptions();
connOpts.setCleanSession(true);
System.out.println("Connecting to broker: "+broker);
sampleClient.connect(connOpts);
System.out.println("Connected");
System.out.println("Publishing message: "+content);
MqttMessage message = new MqttMessage(content.getBytes());
message.setQos(qos);
sampleClient.publish(topic, message);
System.out.println("Message published");
sampleClient.disconnect();
System.out.println("Disconnected");
System.exit(0);
}
catch(MqttException me) {
System.out.println("reason "+me.getReasonCode());
System.out.println("msg "+me.getMessage());
System.out.println("loc "+me.getLocalizedMessage());
System.out.println("cause "+me.getCause());
System.out.println("excep "+me);
me.printStackTrace();
}
}
}
I am trying to see the published message on this dashboard: http://test-mosquitto.herokuapp.com/
but cannot see my message. Please correct me if I am missing something. I am new to it. Thanks.
If you expect a message to show up on that "dashboard", it would need to be published with the retained flag set - that web app can only show retained messages, not regular ephemeral ones.

ActiveMQ Queue And consumers

I am having a scenerio that , i am having more than 4 clients and i want to send a single queue messages to all of that clients. I didnt acknowledge for the client side. So anyone can get that messages from the queue. But the case is that i want to know the number of consumers who consumed that message. Can anyone help me to get the consumer count.
Here below is code that i wrote.
public static boolean sendMessage(String messageText)
{
try {
StompConnection connection = new StompConnection();
HashMap<String, String> header = new HashMap<String, String>();
header.put(PERSISTENT, "true");
connection.open(URLhost, port);
connection.connect("", "");
connection.begin("MQClient");
Thread.sleep(100);
connection.send(queuePath, messageText, "MQClient", header);
connection.commit("MQClient");
connection.disconnect();
return true;
} catch (Exception e) {
throw new BasicException(AppLocal.getIntString("ActiveMQ service ERROR"), e);
}
}
public static String receiveMessage() {
try {
StompConnection connection = new StompConnection();
connection.open(URLhost, port);
connection.connect("", "");
connection.subscribe(queuePath, Subscribe.AckModeValues.INDIVIDUAL);
connection.begin("MQClient");
Thread.sleep(1000);//below not a good NO DATA test .. worked by making thread sleep a while
if (connection.getStompSocket().getInputStream().available() > 1)
{
StompFrame message = connection.receive();
connection.commit("MQClient");
connection.disconnect();
return message.getBody();
}
else
return "";
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
If you are writing to a Queue, then exactly one consumer will receive the message. The whole goal of point-to-point messaging is that only one of the consumers will receive the message.
If you want to send a message and have it be received by all of the consumers, then you'd want to use a Topic instead of a Queue.
If you switch to a topic, multiple clients can consume that same message.
You can probably figure out how many consumed your message by subscribing to the ActiveMQ.Advisory.MessageConsumed.Topic

Categories

Resources