KURA : how to receive MQTT messages using the DataService? - osgi

How can I receive the MQTT messages published on a specific topic?
I can publish messages on the MQTT broker but I dont know how to receive messages?
Here is my component xml:
<?xml version="1.0" encoding="UTF-8"?>
<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="activate" deactivate="deactivate" name="arduinoCommunicator">
<implementation class="arduinoCommunicator.ArduinoCommunicator"/>
<reference bind="setDataService" cardinality="1..1" interface="org.eclipse.kura.data.DataService" name="DataService" policy="static" unbind="unsetDataService"/>
<service>
<provide interface="org.eclipse.kura.data.DataServiceListener"/>
</service>
</scr:component>
Here is my bundle activator class, I only kept the needed code, I implement the DataServiceListener, I subscribe to the topic on the onConnectionEstablished() and I imagine that I got the message on the function onMessageArrived, the problem is I don't see the logs that the subscription has been made and the function onMessageArrived() is not executed:
public class ArduinoCommunicator implements DataServiceListener {
public static DataService dataService;
#Override
public void onConnectionEstablished() {
String topic="egmkey/device2/cmd/PING";
System.out.println("connection has been established");
try {
ArduinoCommunicator.dataService.subscribe(topic, 1);//egmkey/device2/cmd/PING
System.out.println("subscription done to topic"+topic);
} catch (KuraException e) {
System.out.println("failed to subscribe: "+ e);
}
}
#Override
public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {
System.out.println("message received!!!!!!!!!!!!!!!!!!!!!!:"+topic);
}
}
What have I missed to be able to receive MQTT messages using DataService on KURA? Thanks.

You are not correctly injecting the DataService service into your component. The code below should be closer to what you actually need:
public class ArduinoCommunicator implements DataServiceListener {
public DataService dataService;
protected setDataService(DataService dataService) {
this.dataService = dataService;
}
#Override
public void onConnectionEstablished() {
String topic = "egmkey/device2/cmd/PING";
System.out.println("connection has been established");
try {
dataService.subscribe(topic, 1);//egmkey/device2/cmd/PING
System.out.println("subscription done to topic" + topic);
} catch (KuraException e) {
System.out.println("failed to subscribe: " + e);
}
}
#Override
public void onMessageArrived(String topic, byte[] payload, int qos, boolean retained) {
System.out.println("message received!!!!!!!!!!!!!!!!!!!!!!:" + topic);
}
}

Related

spring websocket client does not detect network connection loss

Spring #ClientEndpoint websocket client does not detect network disconnect due to cable unplug. I also have implemented a ping/pong mechanism. Can someone please help me out with what's going on?
However I see following exception after reconnecting the cable, FYI, all setting are into default. Also I am connecting to a 3rd party remote endpoint where do not have any control.
xxxxxException: closed with code : CLOSED_ABNORMALLY reason: CloseReason: code [1006], reason [java.io.IOException: Connection reset by peer]
at xxxxxx.onClose(WSClient.java:xx)
#ClientEndpoint
public class WSClient {
private Session session;
private int i = 0;
#OnOpen
public void open(Session session) {
System.out.println("Connected to the server");
this.session = session;
}
#OnClose
public void close(Session session, CloseReason closeReason) {
System.out.println("connection closed " + closeReason.getReasonPhrase());
}
#OnError
public void error(Session session, Throwable t) {
System.out.println(session.getId());
System.out.println("Error in connection " + t.getMessage());
}
#OnMessage
public void message(Session session, String message) {
System.out.println("message received: " + message + " " + i++);
}
public void send(String message){
try {
if(session.isOpen()) {
this.session.getBasicRemote().sendPing(ByteBuffer.wrap(message.getBytes()));
System.out.println("socket is open " + i++);
} else {
System.out.println("socket closed");
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
#Component
public class ClientApp implements ApplicationListener<ApplicationReadyEvent> {
private void startConnection() throws Exception {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
WSClient client = new WSClient();
container.connectToServer(client, new URI("ws://wshost:8080/ping"));
while (true) {
client.send("ping");
TimeUnit.SECONDS.sleep(3);
}
}
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
try {
startConnection();
} catch (Exception e) {
System.out.println(e);
}
}
}
This issue can be resolved by adding below code to WSClient.
#OnMessage
public void pongMessage(Session session, PongMessage msg) {
LOGGER.debug("Pong message received: " + Instant.now());
//schedule a timeout task, and raise an event or so if timed out.
}
The above snippet will be invoked when remote endpoint sends a pong message as a respond to the ping message sent. Basically there will be two methods annotated with #OnMessage, one to received the user message payload and another pong message payload sent by the framework.

Stop RabbitMQ-Connection in Spring-Boot

I have a spring-boot application that pulls all the messages from a RabbitMQ-queue and then terminates. I use rabbitTemplate from the package spring-boot-starter-amqp (version 2.4.0), namely receiveAndConvert(). Somehow, I cannot get my application to start and stop again. When the rabbitConnectionFactory is created, it will never stop.
According to Google and other stackoverflow-questions, calling stop() or destroy() on the rabbitTemplate should do the job, but that doesn't work.
The rabbitTemplate is injected in the constructor.
Here is some code:
rabbitTemplate.setMessageConverter(new Jackson2JsonMessageConverter());
Object msg = getMessage();
while (msg != null) {
try {
String name = ((LinkedHashMap) msg).get(propertyName).toString();
//business logic
logger.debug("added_" + name);
} catch (Exception e) {
logger.error("" + e.getMessage());
}
msg = getMessage();
}
rabbitTemplate.stop();
private Object getMessage() {
try {
return rabbitTemplate.receiveAndConvert(queueName);
} catch (Exception e) {
logger.error("" + e.getMessage());
return null;
}
}
So, how do you terminate the connection to RabbitMQ properly?
Thanks for your inquiry.
You can call resetConnection() on the CachingConnectionFactory to close the connection.
Or close() the application context.
If I were to do it , I would use #RabbitListener to receive the messages and RabbitListenerEndpointRegistry to start and stop the listener. Sample Code is given below
#EnableScheduling
#SpringBootApplication
public class Application implements ApplicationRunner {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
public static final String queueName = "Hello";
#Bean
public Queue hello() {
return new Queue(queueName);
}
#Autowired
private RabbitTemplate template;
#Scheduled(fixedDelay = 1000, initialDelay = 500)
public void send() {
String message = "Hello World!";
this.template.convertAndSend(queueName, message);
System.out.println(" [x] Sent '" + message + "'");
}
#Autowired
RabbitListenerEndpointRegistry registry;
#Override
public void run(ApplicationArguments args) throws Exception {
registry.getListenerContainer( Application.queueName).start();
Thread.sleep(10000L);
registry.getListenerContainer( Application.queueName).stop();
}
}
#Component
class Receiver {
#RabbitListener(id= Application.queueName,queues = Application.queueName)
public void receive(String in) {
System.out.println(" [x] Received '" + in + "'");
}
}

ControllerAdvice is not triggered in my springboot application?

Actually I am working in a Kafka streams application using Spring Boot.
So here I am trying to handle exceptions globally using #ControllerAdvice but it is not working for me.
Is it possible to use #ControllerAdvice in my application.
Is this controller advice is only works when the error is coming from controller.
Note: I am not having any controller / rest controller endpoints in my application.
Can we achieve the same in some other ways?
Please share your valuable thoughts!
Main Stream:
#Autowired
private XyzTransformer xyztransformer;
#Bean
public KStream<String, ABC> processMember(#Qualifier("defaultKafkaStreamsBuilder") StreamsBuilder streamsBuilder) {
try {
LOGGER.info("streaming started...");
KStream<String, Xyz> xyStream = streamsBuilder.stream(appProperty.kafkaStreamsTopicInput)
.transformValues(() -> xyztransformer)
xyStream.to(appProperty.kafkaStreamsTopicOutput);
return memberStream;
} catch (Exception ex) {
LOGGER.error("Exception occurred in Streams " + Arrays.toString(ex.getStackTrace()));
throw ex;
}
}
TransformerClass:
#Component
public class XyzTransformer implements ValueTransformer<Xyz, Abc> {
#Override
public void close() {
}
#Override
public void init(ProcessorContext processorContext) {
}
#SneakyThrows
#Override
public Abc transform(Xyz data) {
String[] dataSourceTables = new String[]{"abc"};
try {
return Abc.builder()
.name(data.getName())
.build();
} catch (Exception ex) {
System.out.println("catched and throwing");
throw new CustomTesException("test 1");
}
}
}
ControllerAdvice:
#ControllerAdvice
public class Advice extends ResponseEntityExceptionHandler {
#ExceptionHandler(NullPointerException.class)
public final void handleAllExceptions(NullPointerException ex) {
System.out.println("it is in the handler");
System.out.println(ex.getMessage());
}
#ExceptionHandler(Exception.class)
public final void handleAllException(Exception ex) {
System.out.println("it is in the exception handler");
System.out.println(ex.getMessage());
}
#ExceptionHandler(CustomTesException.class)
public final void handleAllExceptio(CustomTesException ex) {
System.out.println("it is in the exception handler");
System.out.println(ex.getMessage());
}
}

PubSub with spring: know the message is publish or not?

My publisher code look like this:
public abstract class PubSubPublisher {
private static final Logger LOGGER = LoggerFactory.getLogger(PubSubPublisher.class);
private final PubSubTemplate pubSubTemplate;
protected PubSubPublisher(PubSubTemplate pubSubTemplate) {
this.pubSubTemplate = pubSubTemplate;
}
protected abstract String topic(String topicName);
public void publish(String topicName, String message) throws StatusRuntimeException {
LOGGER.info("Publishing to topic [{}]. Message: [{}]", topicName, message);
pubSubTemplate.publish(topicName, message);
}
}
My Component
#Component
public class HelloPubSubPublisher extends PubSubPublisher {
#Autowired
public HelloPubSubPublisher(PubSubTemplate pubSubTemplate) throws StatusRuntimeException{
super(pubSubTemplate);
}
#Override
protected String topic(String topicName) {
return topicName;
}
}
Now on my service layer how do i get weather i successful publish the message to topic or not, note all the google api are async which i am using.
try {
publisher.publish(topicName, payload);
}catch (Exception e) {
LOGGER.error("ioException occured: "+e);
throw new TopicNotFoundException();
}
Unfortunately, I am not able to capture the any error, program cursor is not going into the catch block.
Ultimately, I wanted to know weather the code is push the message into topic if not then I have to log it and throw that error to client, which is not happen with my current code with proper exception handling.
Any help or guidance is appreciated, thanks.
Using the function publish() you should be able to capture a future where you can check if the message was published or not.
You have an example of it on Google's PubSub documentation:
// Once published, returns a server-assigned message id (unique within the topic)
ApiFuture<String> future = publisher.publish(pubsubMessage);
// Add an asynchronous callback to handle success / failure
ApiFutures.addCallback(
future,
new ApiFutureCallback<String>() {
#Override
public void onFailure(Throwable throwable) {
if (throwable instanceof ApiException) {
ApiException apiException = ((ApiException) throwable);
// details on the API exception
System.out.println(apiException.getStatusCode().getCode());
System.out.println(apiException.isRetryable());
}
System.out.println("Error publishing message : " + message);
}
#Override
public void onSuccess(String messageId) {
// Once published, returns server-assigned message ids (unique within the topic)
System.out.println(messageId);
}
},
MoreExecutors.directExecutor());

Require assistance with simple pure Java 11 WebSocket client example

There appears to be very little Java 11 (pure Java non framework based) WebSocket client code examples on the web so I'm hoping StackOverflow can come to the rescue for me once again.
This is the closest I've found, but unfortunately to my (novice) eyes, it doesn't appear to be a complete solution in showing how to consume the data from the WebSocket listener.
Looking at the WebSocket.Listener implementation, the onText callback method I presume would provide what I need, but I'm struggling to figure out how to return the CompletionStage object and some sort of string data from the socket.
This is some test code I have so far.
Would appreciate assistance. Thanks
public class Main {
public static void main(String[] args) {
WebSocketClient wsc = new WebSocketClient();
wsc.startSocket("ws://demos.kaazing.com/echo");
int i = 0;
// Bad, very bad
do {} while (i == 0);
}
}
public class WebSocketClient implements WebSocket.Listener {
#Override
public void onOpen(WebSocket webSocket) {
//...
System.out.println("Go...Open".concat(
webSocket.getSubprotocol()));
}
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
//...
System.out.println(data.toString());
// How do I return the CompletionStage object
// return CompletionStage<String>
}
#Override
public void onError(WebSocket webSocket, Throwable error) {
//..
System.out.println("Bad day! ".concat(webSocket.toString()));
}
void startSocket(String connection) {
CompletableFuture<WebSocket> server_cf = HttpClient.
newHttpClient().
newWebSocketBuilder().
buildAsync(URI.create(connection),
new WebSocketClient());
WebSocket server = server_cf.join();
server.sendText("Hello!", true);
}
}
Below you find a working example. I have made some changes to your code above:
onOpen needs to invoke request(1) on the websocket (invoking the default implementation) in order to receive further invocations.
moved method startSocket into the main method
replaced busy waiting with a count down latch
declared class WebSocketClient as a (static) inner class
but beyond these (cosmetic) changes the program follows your idea, i.e. first a websocket connection is build and after successful construction the text Hello! is sent to the echo server. This could also be done in method onOpen directly.
import java.net.URI;
import java.net.http.HttpClient;
import java.net.http.WebSocket;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.CountDownLatch;
public class Main {
public static void main(String[] args) throws Exception {
CountDownLatch latch = new CountDownLatch(1);
WebSocket ws = HttpClient
.newHttpClient()
.newWebSocketBuilder()
.buildAsync(URI.create("ws://demos.kaazing.com/echo"), new WebSocketClient(latch))
.join();
ws.sendText("Hello!", true);
latch.await();
}
private static class WebSocketClient implements WebSocket.Listener {
private final CountDownLatch latch;
public WebSocketClient(CountDownLatch latch) { this.latch = latch; }
#Override
public void onOpen(WebSocket webSocket) {
System.out.println("onOpen using subprotocol " + webSocket.getSubprotocol());
WebSocket.Listener.super.onOpen(webSocket);
}
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
System.out.println("onText received " + data);
latch.countDown();
return WebSocket.Listener.super.onText(webSocket, data, last);
}
#Override
public void onError(WebSocket webSocket, Throwable error) {
System.out.println("Bad day! " + webSocket.toString());
WebSocket.Listener.super.onError(webSocket, error);
}
}
}
Btw, no supprotocol was negotiated, therefore method webSocket.getSubprotocol() returns an empty string. The output in the console is
onOpen using subprotocol
onText received Hello!
The pattern for managing a WebSocket response returning a CompletionStage is:
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
// return inmmediately but response is geenrated lazyly.
return CompletableFuture.supplyAsync(() -> {
String response = "Received ...";
// do slow task. Access to database or access to a server.
return response;
});
}
This simple implementation only is recommended when the response is generated quickly.
#Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
// fast response.
String response = "The text has " + data.length() + " chars";
return CompletableFuture.completedFuture(response);
}
I have had some trouble getting various examples working. Specifically, I had trouble finding examples that actually showed how to open, send, and receive simple text messages. One important piece was having a server to which to connect. Here is what I managed to make work.
package webSockets;
import java.io.IOException;
import java.net.URI;
import javax.websocket.CloseReason;
import javax.websocket.ContainerProvider;
import javax.websocket.Endpoint;
import javax.websocket.EndpointConfig;
import javax.websocket.MessageHandler;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
public class SimpleWebsocketClient extends Endpoint {
private Session session;
public SimpleWebsocketClient() {}
public SimpleWebsocketClient(URI endpointURI) {
try {
WebSocketContainer container = ContainerProvider.getWebSocketContainer();
container.connectToServer(this, endpointURI);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
#Override
public void onClose(Session session, CloseReason reason){
System.out.println("Disconnected as a result of "+ reason.getReasonPhrase());
}
#Override
public void onError(Session session, Throwable error){
System.out.println("Error communicating with server: " + error.getMessage());
}
#Override
public void onOpen(Session s, EndpointConfig config) {
System.out.println("Session opened");
session = s;
session.addMessageHandler(new MessageHandler.Whole<String>() {
#Override
public void onMessage(String msg) {
System.out.println("Text Message Received:" + msg);
}
});
try {
session.getBasicRemote().sendText("Hello there.");
session.getBasicRemote().sendText("Hope you are well!");
} catch (IOException ex) {
throw new RuntimeException(ex);
}
}
public static void main(String...arg) {
URI uri = URI.create("ws://connect.websocket.in/v3/1?api_key=oCdCMcMPQpbvNjUIzqtvF1d2X2okWpDQj4AwARJuAgtjhzKxVEjQU6IdCjwm&notify_self");
new SimpleWebsocketClient(uri);
while(true) {}
}
}

Resources