messageArrived never called in mqtt paho client - java

I have a program running using mqtt paho version MqttConnectOptions.MQTT_VERSION_3_1_1 . I subscribe to topic "device/+/publish" and message from hardware is received at my program. Till yesterday it was running good, today I got an issue that code was not proceeding after the subscribe line. I changed my mqttclient object to MqttAsyncClient. and subscribe code as
mqttClient.subscribe("device/+/publish", 0 , new IMqttMessageListener() {
#Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
// TODO Auto-generated method stub
System.out.println(
"---------------------------------------------------------------------------------------------------");
processMessage(mqttMessage, collarTopic, identity);
}
});
messageArrived is also written in MqttCallbackExtended() like
mqttClient.setCallback(new MqttCallbackExtended() {
#Override
public void messageArrived(String topic, MqttMessage mqttMessage) throws Exception {
// TODO Auto-generated method stub
System.out.println(
"---------------------------------------------------------------------------------------------------");
processMessage(mqttMessage, collarTopic, identity);
}
But this is never called in my program. I can see the message received with same subscription in MQTTBox but not in my program.
Can anyone help?

Related

MqttAndroidClient not able to connect to mosquitto

I have a mosquitto broker running on my computer with mosquitto -v and I'm trying to connect to it from my android app. What I am doing is
public void connect() {
mqttAndroidClient = new MqttAndroidClient(context, "mqtt://192.168.1.198:1883", clientId);
mqttAndroidClient.setCallback(callback);
mqttConnectOptions = new MqttConnectOptions();
mqttConnectOptions.setAutomaticReconnect(true);
mqttConnectOptions.setCleanSession(false);
mqttAndroidClient.connect(mqttConnectOptions, context, new IMqttActionListener() {
#Override
public void onSuccess(IMqttToken asyncActionToken) {
DisconnectedBufferOptions disconnectedBufferOptions = new DisconnectedBufferOptions();
disconnectedBufferOptions.setBufferEnabled(true);
disconnectedBufferOptions.setBufferSize(100);
disconnectedBufferOptions.setPersistBuffer(false);
disconnectedBufferOptions.setDeleteOldestMessages(false);
mqttAndroidClient.setBufferOpts(disconnectedBufferOptions);
Log.i(LOG_TAG, "Connected to the broker");
}
#Override
public void onFailure(IMqttToken asyncActionToken, Throwable exception) {
Log.e(LOG_TAG, "Not able to connect to the broker");
}
});
while(!mqttAndroidClient.isConnected()) {}
try {
mqttAndroidClient.subscribe("notify/new", 0);
} catch (MqttException ex) {
System.err.println("Exception whilst subscribing");
ex.printStackTrace();
}
}
But it never connects, because I don't see the "Connected to the broker" message and it gets in stuck in the while loop. What am I doing wrong?
As covered in the comments, the tight while loop checking if the client is connected is redundant as there is already a callback onSuccess() that can be used for that test.
The call to subscribe() should be moved into the callback.
The best way to handle subscribing to topics after the client is connected is to gate the call to subscribe() in an if block that checks the connected status. If that test fails add the topic to a global array, and call connect() again. The subscribe() in the onSuccess() callback should use the version that takes an array of topics

Java Mqtt Client disconnects after one message received by the callback

in my code, there are four classes: mainProgram, Coordinator class, Client Class and Callback Class.
The mainProgram, which contains the main method of the program, creates an instance of the Coordinator Class and calls its start() method.
The later creates two instances of the Client Class, a publisher and a subscriber, connects both of them and subscribes one of the instances, the subscriber, to multiple topics.
The Client Class contains everything what has to do with mqtt and concerning the Callback for the subscribe-method, I've created an own class for this, the Callback Class which receives in the messageArrived method the incoming mqtt messages.
This is the code of the main:
public class mainProgram throws MqttException {
public static void main(String[] args) {
Coordinator coordinator=new Coordinator();
coordinator.start();
}}
this is the code of the Coordinator class:
public class Coordinator {
Client publisher;
Client subscriber;
public Coordinator() {
// TODO Auto-generated constructor stub
}
public void start() throws MqttException {
Client publisher=new Client("publisher","tcp://192.168.0.10",0);
publisher.connect();
Client subscriber=new Client("subscriber","tcp://192.168.0.10",0);
subscriber.connect();
subscriber.subscribeToTopic(new String [] {"home/Sensor2","home/Sensor3"});
}
public void getMessage(String message) throws MqttPersistenceException, MqttException {
publisher.publish("home/Sensor4", message);
}}
This is the Client Class:
public class Client {
String brokerAddress;
String clientId;
int qos;
MqttClient mqttClient;
MqttConnectOptions conOpt;
MemoryPersistence persistence;
Coordinator coordinator;
public Client(String clientId, String brokerAddress, int qos) {
this.clientId=clientId;
this.brokerAddress=brokerAddress;
this.qos=qos;
this.setConOpt();
}
public void setConOpt() {
conOpt=new MqttConnectOptions();
conOpt.setKeepAliveInterval(30);
conOpt.setAutomaticReconnect(false);
}
public void connect() throws MqttException {
mqttClient=new MqttClient(brokerAddress,clientId,persistence);
this.mqttClient.setCallback(new Callback(this));
this.mqttClient.connect(this.conOpt);
while(this.mqttClient.isConnected()==false) {
System.out.println("Connecting");
System.out.println("...");
}
if(this.mqttClient.isConnected()==true){
System.out.println("Der Mqttclient "+this.mqttClient.getClientId()+" is now connected!");
}
}
public void subscribeToTopic(String [] topics) throws MqttException {
for(int i=0;i<topics.length;i++) {
this.mqttClient.subscribe(topics[i]);
}
}
public void publish(String topic, String message) throws MqttPersistenceException, MqttException {
MqttMessage mqttMessage=new MqttMessage(message.getBytes());
this.mqttClient.publish(topic, mqttMessage);
}
}
This is the Callback Class:
public class Callback implements MqttCallback{
Client client;
public Callback(Client client) {
// TODO Auto-generated constructor stub
this.client=client;
}
#Override
public void connectionLost(Throwable arg0) {
// TODO Auto-generated method stub
System.out.println("Connection to server's lost");
}
#Override
public void deliveryComplete(IMqttDeliveryToken arg0) {
// TODO Auto-generated method stub
System.out.println("Message's delivered");
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
String ingoingMsg=message.toString();
System.out.println("until here all's fine");
Coordinator coordinator=new Coordinator();
coordinator.getMessage(ingoingMsg);
}
}
The program starts, creates the clients and when I publish via MQTTfx a message to the above mentionned topics, in the console this shows up:
The program ends and the connection of the client "subscriber" ends when I call the method "coordinator.getMessage()" and nothing is published.
At the end, the program should behave like this:
create clients
connect clients
subscribe the subscriber client
Listen and if a message to the topic subscribed is published: Call the getMessage of the coordinator class to publish something
while and after publishing the listening to further messages should not end and the programm is "in a loop" until the user breaks it up.
I searched everywhere for a solution, but there are not quite the same problems that I have on the web.
Maybe you have some illuminating tips for me ...

netty proxy server transaction

i'm new to netty and i would like to create a proxy server using netty that does the following :
_ upon receiving data from a client, the proxy server does some business logic that will possibly modify the data, and then forward it to the remote server, this business logic belongs to a transaction.
_ if the remote server return a success response then proxy server commit the transaction, otherwise the proxy server rollback the transaction.
Data flow diagram
I have taken a look at the proxy example at https://netty.io/4.1/xref/io/netty/example/proxy/package-summary.html but i havent figured out a good and simple way to implement the transaction logic mentioned above.
I should mention that i have create a separate thread pool to execute this business transaction to avoid blocking the Nio thread, my current solution is to actually use 2 thread pool with the same amount of threads : 1 on the frontendHandler and 1 on the backendHandler, the one at frontend will use wait() to wait for the response from the backend thread.
Here is my current code for the frontend handler:
#Override
public void channelActive(ChannelHandlerContext ctx) {
final Channel inboundChannel = ctx.channel();
// Start the connection attempt.
Bootstrap b = new Bootstrap();
b.group(inboundChannel.eventLoop())
.channel(ctx.channel().getClass())
.handler(new ServerBackendHandler(inboundChannel, response))
.option(ChannelOption.AUTO_READ, false);
ChannelFuture f = b.connect(remoteHost, remotePort);
outboundChannel = f.channel();
f.addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// connection complete start to read first data
inboundChannel.read();
} else {
// Close the connection if the connection attempt has failed.
inboundChannel.close();
}
}
});
}
#Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) {
if (outboundChannel.isActive()) {
//Executing business logic within a different thread pool to avoid blocking asynchronous i/o operation
frontendThreadPool.execute(new Runnable(){
#Override
public void run() {
//System.out.println("Starting business logic operation at front_end for message :" + m);
synchronized(response) {
//sleeping this thread to simulate business operation, insert business logic here.
int randomNum = ThreadLocalRandom.current().nextInt(1000, 2001);
try {
Thread.currentThread().sleep(randomNum);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
outboundChannel.writeAndFlush(msg).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
// was able to flush out data, start to read the next chunk
ctx.channel().read();
} else {
future.channel().close();
}
}
});
System.out.println("Blank response : " + response.getResponse());
//wait for response from remote server
try {
response.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Returned response from back end: " + response.getResponse());
//another piece of business logic here, if the remote server returned success then commit the transaction, if the remote server returned failure then throw exception to rollback
//stop current thread since we are done with it
Thread.currentThread().interrupt();
}
}
});
}
}
and for the backendHandler :
#Override
public void channelRead(final ChannelHandlerContext ctx, Object msg) {
ByteBuf m = (ByteBuf) msg;
m = safeBuffer(m, ctx.alloc());
String str = m.toString(Charset.forName("UTF-8"));
backendThreadPool.execute(new Runnable() {
#Override
public void run() {
//System.out.println("Starting business logic operation at back_end.");
synchronized(response) {
int randomNum = ThreadLocalRandom.current().nextInt(1000, 2001);
try {
Thread.currentThread().sleep(randomNum);
} catch (InterruptedException e1) {
e1.printStackTrace();
}
response.setResponse(str);
System.out.println("Finished at back_end.");
response.notify();
Thread.currentThread().interrupt();
}
}
});
String s = "Message returned from remote server through proxy : " + str;
byte[] b = s.getBytes(Charset.forName("UTF-8"));
defaultResponse.writeBytes(b);
inboundChannel.writeAndFlush(defaultResponse).addListener(new ChannelFutureListener() {
public void operationComplete(ChannelFuture future) throws Exception {
if (future.isSuccess()) {
ctx.channel().read();
} else {
future.channel().close();
}
}
});
}
this solution is not at all optimized since the server have to use 2 threads to execute one transaction. So i guess my questions are :
_ Can i (and if i can, should i) use Spring #Transactional on the channelRead method ?
_ how can i implement the logic explained above in a simple way using netty ?
I have also used JMeter to test out the code above but it doesn't seem to be very stable, lots of requests didn't even have a response with the above code at around 2000 connections and 250 max threads in each thread pool
Thanks in advance

How to offload blocking operation to a worker Verticle using websockets and async request

I implementing websockets using Vert.x 3.
The scenario is simple: opening socket from client doing some 'blocking' work at the vertex verticle worker and when finish response with the answer to the client(via the open socket)
Please tell me if I am doing it right:
Created VertxWebsocketServerVerticle. as soon as the websocket is opening and request coming from the client I am using eventBus and passing the message to
EventBusReceiverVerticle. there I am doing blocking operation.
how I am actually sending back the response back to VertxWebsocketServerVerticle and sending it back to the client?
code:
Main class:
public static void main(String[] args) throws InterruptedException {
Vertx vertx = Vertx.vertx();
vertx.deployVerticle(new EventBusReceiverVerticle("R1"),new DeploymentOptions().setWorker(true));
vertx.deployVerticle(new VertxWebsocketServerVerticle());
}
VertxWebsocketServerVerticle:
public class VertxWebsocketServerVerticle extends AbstractVerticle {
public void start() {
vertx.createHttpServer().websocketHandler(webSocketHandler -> {
System.out.println("Connected!");
Buffer buff = Buffer.buffer().appendInt(12).appendString("foo");
webSocketHandler.writeFinalBinaryFrame(buff);
webSocketHandler.handler(buffer -> {
String inputString = buffer.getString(0, buffer.length());
System.out.println("inputString=" + inputString);
vertx.executeBlocking(future -> {
vertx.eventBus().send("anAddress", inputString, event -> System.out.printf("got back from reply"));
future.complete();
}, res -> {
if (res.succeeded()) {
webSocketHandler.writeFinalTextFrame("output=" + inputString + "_result");
}
});
});
}).listen(8080);
}
#Override
public void stop() throws Exception {
super.stop();
}
}
EventBusReceiverVerticle :
public class EventBusReceiverVerticle extends AbstractVerticle {
private String name = null;
public EventBusReceiverVerticle(String name) {
this.name = name;
}
public void start(Future<Void> startFuture) {
vertx.eventBus().consumer("anAddress", message -> {
System.out.println(this.name +
" received message: " +
message.body());
try {
//doing some looong work..
Thread.sleep(10000);
System.out.printf("finished waiting\n");
startFuture.complete();
} catch (InterruptedException e) {
e.printStackTrace();
}
});
}
}
I always get:
WARNING: Message reply handler timed out as no reply was received - it will be removed
github project at: https://github.com/IdanFridman/VertxAndWebSockets
thank you,
ray.
Since you are blocking your websocket handler until it receives a reply for the sent message to the EventBus, which will not, in fact, be received until the set up delay of 10s laps, you certainly will get warning since the reply handler of the event bus will timeout -> Message sent but no response received before the timeout delay.
Actually I don't know if you are just experimenting the Vert.x toolkit or you are trying to fulfill some requirement, but certainly you have to adapt your code to match in the Vert.x spirit:
First you should better not block until a message is received in your websocket handler, keep in mind that everything is asynchrounous when it comes to Vert.x.
In order to sleep for some time, use the Vert.x way and not the Thread.sleep(delay), i.e. vertx.setTimer(...).

Netty Encoder Not Being Called

Using Netty 4.0.27 & Java 1.8.0_20
So I am attempting to learn how Netty works by building a simple chat server (the typical networking tutorial program, I guess?). Designing my own simple protocol, called ARC (Andrew's Relay Chat)... so that's why you see ARC in the code a lot. K, so here's the issue.
So here I start the server and register the various handlers...
public void start()
{
System.out.println("Registering handlers...");
ArcServerInboundHandler inboundHandler = new ArcServerInboundHandler(this);
EventLoopGroup bossGroup = new NioEventLoopGroup();
EventLoopGroup workerGroup = new NioEventLoopGroup();
try
{
ServerBootstrap bootstrap = new ServerBootstrap();
bootstrap.group(bossGroup, workerGroup).channel(NioServerSocketChannel.class).childHandler(new ChannelInitializer<SocketChannel>()
{
#Override
public void initChannel(SocketChannel ch) throws Exception
{
ch.pipeline().addLast(new ArcDecoder(), inboundHandler);
ch.pipeline().addLast(new ArcEncoder());
}
}).option(ChannelOption.SO_BACKLOG, 128).childOption(ChannelOption.SO_KEEPALIVE, true);
try
{
System.out.println("Starting Arc Server on port " + port);
ChannelFuture f = bootstrap.bind(port).sync();
f.channel().closeFuture().sync();
}
catch(InterruptedException e)
{
e.printStackTrace();
}
}
finally
{
workerGroup.shutdownGracefully();
bossGroup.shutdownGracefully();
}
}
My "inboundHandler" does get called when the user connects.
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception
{
System.out.println("CLIENT CONNECTED"); // THIS PRINTS, REACHES THIS POINT
ArcPacket packet = new ArcPacket();
packet.setArc("PUBLIC_KEY");
packet.setField("KEY", Crypto.bytesToHex(server.getRsaKeys().getPublic().getEncoded()));
ctx.writeAndFlush(packet);
}
This is my encoder, which does not seem to get called at all...
public class ArcEncoder extends MessageToByteEncoder<ArcPacket>
{
#Override
protected void encode(ChannelHandlerContext ctx, ArcPacket msg, ByteBuf out) throws Exception
{
System.out.println("ENCODE"); // NEVER GETS HERE
String message = ArcPacketFactory.encode(msg);
byte[] data = message.getBytes("UTF-8");
out.writeBytes(data);
System.out.println("WROTE");
}
#Override
public boolean acceptOutboundMessage(Object msg) throws Exception
{
System.out.println("ACCEPT OUTBOUND MESSAGE"); // NEVER GETS HERE
return msg instanceof ArcPacket;
}
}
So,
The code that calls ctx.writeAndFlush(packet); is run, but it doesn't seem to invoke the encoder at any point. Am I missing something obvious? Perhaps I'm adding the encoder incorrectly? Though it looks right when I compare it to other examples I've seen.
Thanks for any help.
Your encoder (ArcEncoder) is placed after your inbound handler. It means, the ctx.*() method calls will never be evaluated by the encoder. To fix your problem, you have to move the ArcEncoder before the inbound handler:
ch.pipeline().addLast(new ArcDecoder(), new ArcEncoder(), inboundHandler);
For more information about the event evaluation order, please read the API documentation of ChannelPipeline.
I think the problem is that you're using the ChannelHandlerContext to write to the Channel. What this does is to insert the message in the pipeline at the point of your handler, going outbound. But since your decoder is added before your encoder in the pipeline this means that anything you write using the decoder context will be inserted after the encoder in the pipeline.
The correct way to do it to ensure that the encoder is called is to call:
ctx.channel.writeAndFlush()

Categories

Resources