Spring Boot - Websockets - How to see subscribers - spring-boot

I'm working on a websocket application where I'm trying to have one websocket that feeds information in, and then outputs to subscribers to the endpoint. I've figure that out, but I'm wondering if there is a way to see what subscribers are subscribed and to what path?
Here is a code sample of what I'm working on.
#Autowired
private SimpMessagingTemplate template;
#MessageMapping("/{companyId}/{departmentId}")
#SendTo("/{companyId}/{departmentId}")
public void companyInformation(#DestinationVariable String companyId, #DestinationVariable String departmentId, CompanyMessage companyMessage){
String destination = "/" + companyId + "/" + departmentId;
template.convertAndSend(
destination, processCompanyMessage(companyMessage, departmentId));
}
The idea is that the information poster sends companyMessage object to the #MessageMapping endpoint, the companyId and departmentId are retrieved from this mapping.
This message is then processed based on what the departmentId is and is posted to every department that has an active subscriber to the #SendTo path.
e.g.
There are 3 websocket subscribers,
/smallCompany/booking, /smallCompany/sales, /smallCompany/inventory.
#MessageMapping gets a message from /smallCompany/sales. The method processes the message based on the departmentId and posts to EVERY subscriber with the same /{companyId}, even if the /{departmentId} differs.
Any ideas if this is possible, and if not, any ideas to push me in the right direction would be great.

I know it's too late to answer! but I saw this question now!
So, to guide others that will see this question, I should say:
You have several solutions:
1- SimpUserRegistry:
#Autowired private SimpUserRegistry simpUserRegistry;
public Set<SimpUser> getUsers() {
return simpUserRegistry.getUsers();
}
Check this link:
Is there a Spring WebSocketSession repository?
2- Global list:
You've certainly configured the web-socket in spring boot, so, probably you have a derived class from WebSocketMessageBrokerConfigurer, with override configureClientInboundChannel to call setInterceptors...
You should implement custom interceptor derived from ChannelInterceptorAdapter and override preSend to access MessageHeaderAccessor.getAccessor(...).command
These commands defined in StompCommand (CONNECT, DISCONNECT, SUBSCRIBE, UNSUBSCRIBE,...)
By checking accessor.command with StompCommand.SUBSCRIBE/UNSUBSCRIBE you can create and sync a global static list of subscribers, and use it everywhere you need.
3- Other solution:
Check this link:
how to capture subscribe event in my webSocket server with Spring 4

Related

guava eventbus post after transaction/commit

I am currently playing around with guava's eventbus in spring and while the general functionality is working fine so far i came across the following problem:
When a user want's to change data on a "Line" entity this is handled as usual in a backend service. In this service the data will be persisted via JPA first and after that I create a "NotificationEvent" with a reference to the changed entity. Via the EventBus I send the reference of the line to all subscribers.
public void notifyUI(String lineId) {
EventBus eventBus = getClientEventBus();
eventBus.post(new LineNotificationEvent(lineId));
}
the eventbus itself is created simply using new EventBus() in the background.
now in this case my subscribers are on the frontend side, outside of the #Transactional realm. so when I change my data, post the event and let the subscribers get all necessary updates from the database the actual transaction is not committed yet, which makes the subscribers fetch the old data.
the only quick fix i can think of is handling it asynchronously and wait for a second or two. But is there another way to post the events using guava AFTER the transaction has been committed?
I don't think guava is "aware" of spring at all, and in particular not with its "#Transactional" stuff.
So you need a creative solution here. One solution I can think about is to move this code to the place where you're sure that the transaction has finished.
One way to achieve that is using TransactionSyncrhonizationManager:
TransactionSynchronizationManager.registerSynchronization(new TransactionSynchronization(){
void afterCommit(){
// do what you want to do after commit
// in this case call the notifyUI method
}
});
Note, that if the transaction fails (rolls back) the method won't be called, in this case you'll probably need afterCompletion method. See documentation
Another possible approach is refactoring your application to something like this:
#Service
public class NonTransactionalService {
#Autowired
private ExistingService existing;
public void entryPoint() {
String lineId = existing.invokeInTransaction(...);
// now you know for sure that the transaction has been committed
notifyUI(lineId);
}
}
#Service
public class ExistingService {
#Transactional
public String invokeInTransaction(...) {
// do your stuff that you've done before
}
}
One last thing I would like to mention here, is that Spring itself provides an events mechanism, that you might use instead of guava's one.
See this tutorial for example

Spring Boot - Camel - Tracking an exchange all the way through

We are trying to setup a very simple auditing database table for a very complex Spring Boot, Camel application with many routes (mostly internal routes using seda://)...the idea being we record in the database table each route's processing outcome. Then when issues arise we can login to the database, query the table and pinpoint exactly where the issue happened. I thought I could just use the exchange-id as the unique tracking identifier, but quickly learned that all the seda:// routes make new exchanges, or at least that's what I'm seeing (camel version 2.24.3). Frankly, I don't care what we use for the unique identifier...I can generate a UUID easily enough and the use the exchange.setProperty("id-unique", UUID).
I did manage to get something to work using the exchange.setProperty("id-exchange", exchange.getExchangeId()) and have it persist the unique identifier thru the routes...(I did read that certain pre-defined route prefixes such as jms:// will not persist exchange properties though). The thought being, the very first Processor places the exchangeId (unique-id) on the exchange properties, my tracking logic is in a processor that I can include as part of the Route's definition :
#Override
public void configure() throws Exception {
// EVENTS : Collect statistics from Camel events
this.getContext().getManagementStrategy().addEventNotifier(this.camelEventNotifier);
// INITIAL : ${body} exchange coming from a simple URL endpoint
// POST request with an XML Message...simulates an MQ
// message from Central MQ. The Web/UI service places the
// message onto the camel route using producerTemplate.
from("direct:" + Globals.ROUTEID_LBR_INTAKE_MQ)
.routeId(Globals.ROUTEID_LBR_INTAKE_MQ)
.description("Loss Backup Reports MQ XML inbound messages")
.autoStartup(false)
.process(processor)
.process(getTrackingProcessor())
.to("seda:" + Globals.ROUTEID_LBR_VALIDATION)
.end();
}
This Proof-of-Concept (POC) allowed me to at least get things tracking like we want...note multiple rows with the same unique identifier :
ID_ROW ID_EXCHANGE PROCESS_GROUP PROCESS_STEP RESULTS_STEP RESULTS_MESSAGE
1 ID-LIBP45P-322256M-1603188596161-4-6 Loss Backup Reports lbr-intake-mq add lbr-intake-mq
2 ID-LIBP45P-322256M-1603188596161-4-6 Loss Backup Reports lbr-validation add lbr-intake-mq
Thing is, this POC is proving to be rigid and difficult to record outcomes such as SUCCESS versus EXCEPTION.
My question is, has anyone done anything like this? And if so, how was it implemented? Or is there a fancy way in Camel to handle this that I just couldn't find on the web?
My other ideas were :
Set an old fashion Abstract TrackerProcessor class that all my tracked Processors extend. Then just have a handful of methods in there to create, update, etc... Each processor then just calls inherited methods to create and manage the audit entries. The advantage here being the exchange is readily available with all the data involved to store in the database table.
#Component
public abstract class ProcessorAbstractTracker implements Processor {
#Override
abstract public void process(Exchange exchange) throws Exception;
public void createTracker ( Exchange exchange ) {
}
public void updateTracker ( Exchange exchange, String theResultsMessage, String theResultsStep ) {
}
}
Set an #Autowired Bean that every tracked Camel Processor wires in and put the tracking logic in the bean. This seems to be simple and clean. My only concern/question here is how to scope the bean (maybe prototype)...since there would be many routes utilizing the bean concurrently, is there any chance we get mixed processing values...
#Autowired
ProcessorTracker tracker;
Other ideas?
tia, adym

How to write webSockets for Rest calls in Spring-boot?

I'm new to web socket programming. I have more than 10 methods annotated with #GetMapping, where the returned data is read from a MySQL database.
Can anyone help me to know how to write WebSockets.
My WebRestController.java looks like the below:
#CrossOrigin(origins = "http://localhost:4200", allowedHeaders="*")
#RestController
#RequestMapping("/api")
public class WebRestController {
#GetMapping("/summary")
public String Summary() { /* ... */}
#GetMapping("/erday")
public String Erday(String erday) { /* ... */}
#GetMapping("/count")
public String Count(#RequestParam Map<String,String> queryParam,
String date, String target) { /* ... */}
#GetMapping("/details")
public String Details(#RequestParam Map<String,String> queryParam,
String date, String target) { /* ... */}
#GetMapping("/devmawah")
public String DevMawah(#RequestParam Map<String,String> queryParam,
String date, String target) { /* ... */}
// ....
}
I tried before many times in internet to find the solution, but couldn't find it. All I found are examples for Chat applications, which have 2 endpoints to send and receive.
WebSockets are used for bi-directional communication, not really for REST style services (where HTTP is superior in my opinion). The core difference being that HTTP is fundamentally a request-reply protocol, which fits very well to REST whereas WebSocket is centred around messages. Of course, you can argue that request-reply is a specialisation of message-based communication.
There are several articles on this topic (google REST over WebSocket) and even some StackOverflow questions which detail the pros and cons, for example Is ReST over websockets possible?.
The only way that I know of which allows you to do something resembling REST over WebSocket without having to re-write the RestController is swagger-socket, but I would not recommend using it as the project seems to be inactive now and it seems to not have been used extensively.
Alternatively, you can replace your #RequestMapping or #GetMapping annotations with #MessageMapping annotations and model your API through messages (e.g. the client sends a "GET" message to a given destination, and you send back a message containing the resources).
I can say 99% of reasons that brings us to the idea of Rest Over Websocket is just because we are looking at the problems from wrong direction.
But I wrote such library because I am going to need it in another dummy project I will write later, and you can check it out.
Basically what it does is to scan your controllers, and create a websocket handler that can pass data to those controllers, depending on path, method, and inputs. But there is a lot more it handles internally to achieve this goal.
I havent started the docs yet, so, you can check the sample from website for now.
Well... Just my little contribution...
First you you should code your websocket handler (taking into account the potential size the payload). Then, you should create a config class to register your hander (I am thinking not in a stomp version).
In your handler, after you stablish the connection with the websocket server, you should have a custom component to hold the sessions (maybe a map of usernames and a session wrapper). This is useful, as you you could send messages not only through the ws connection but also through a rest api endpoint (you could hit an endpoint or using an scheduler tasks to periodically send messages to certain users upon certain conditions). Will post again a link later

Unable to get message in priority sequence Spring camel rabbitmq

I am a beginner in using spring camel rabbitmq.
I am able to set message priority in message header by setting it in exchange out headers on the producer side, like this :
exchange.getOut().setHeader("rabbitmq.PRIORITY", 1);
BUT while consuming the messages they dont come in there order of priority. HELP !!
I can see in web interface of rabbitmq that priority header in appropriately set
Please carefully read the "Interaction with consumers" section of this document. You should also search for an answer on the RabbitMQ Users List or post your question there if it has not been asked.
got the issue.
problem was that I was not able to set x-max-priority using camel endpoints.
Need to add it in queueArgsConfigurer option in queue.
To do this we need to implement ArgsConfigurer interface like this :
#Component(value="QueueArgsConfigurer")
public class QueueArgsConfigurer implements ArgsConfigurer {
#Override
public void configurArgs(Map<String, Object> map) {
map.put("x-max-priority", 3);
}
}
And add to queue endpoint queueArgsConfigurer option like this:
queueArgsConfigurer=#QueueArgsConfigurer
Since I am using spring I get the QueueArgsConfigurer by its bean name.

Changing dependency in running spring application

How to change dependency in already deployed application. So when application starts it send notification through email, but at some moment we should be able to change to send notification through sms.
How to do that in Spring Boot?
thats a work for a strategy pattern, it does not have anything to do with spring itself
You should have 2 strategies one for email and one for sms, in each strategy you will autowired the needed bean.
check this link for strategy implementation
https://www.tutorialspoint.com/design_pattern/strategy_pattern.htm
You can define a property in a Singleton bean? let's call it notificationMethod and assign by default EMAIL. (the property could be enum or string or int no matter).
You need a controller method to change the property.
#Autowired
private MyNotificationMethodHolderService service;
#RequestMapping(value = "/changeNotificationMethod")
#ResponseBody
public String change(#RequestParam("methodName") String methodName) {
service.setNotificationMethod (methodName);
}
Your notification service checks the property and sends notification according to the value (Strategy pattern according to comments).
If you need to change method you invoke
<HOST>:<PORT>/context/changeNotificationMethod?methodName=SMS

Resources