How to write webSockets for Rest calls in Spring-boot? - 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

Related

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

Spring Boot - Websockets - How to see subscribers

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

Store data not in database

I want to implement simple chat but store them only during server work. I don't want to store them in database, just like in List or Map. How to?
This solution works for "Simple" chat as you explained.
There isn't much information on how you had built this before so I'm just going to explain how to have an Application scoped bean that can be injected into other beans to handle storing chat.
You can configure a Service to store this information.
ChatHistoryService.java
#Service
#Scope("application")//This is the key this will keep the chatHistory alive for the length of the running application(As long as you don't have multiple instances deployed(But as you said it's simple so it shouldn't)
public class ChatHistoryService {
List<String> chatHistory = new LinkedList<>();//Use LinkedList to maintain order of input
public void storeChatMessage(String chatString) {
chatHistory.add(chatString);
}
public List<String> getChatHistory() {
//I would highly suggest creating a defensive copy of the chat here so it can't be modified.
return Collections.unmodifiableList(chatHistory);
}
}
YourChatController.java
#Controller
public class YourChatController {
#Autowired
ChatHistoryService historyService;
...I'm assuming you already have chat logic but you aren't storing the chat here is where that would go
...When chat comes in call historyService.storeChatMessage(chatMessage);
...When you want your chat call historyService.getChatHistory();
}
Once again keep in mind that this really only works for a simple application. If it's distributed there will be different chat histories per instance of the application at that point you could look into a distributed cache.
In any case don't go beyond simple with this implementation.
If you look here it will give you an idea of several caches that work with spring boot.
https://github.com/spring-projects/spring-boot/tree/master/spring-boot-autoconfigure/src/main/java/org/springframework/boot/autoconfigure/cache

Is it possible to have an async message receiver in Spring AMQP that handles multiple content types?

I'm using an asyncronous message receiver in Spring-AMQP to receive messages. Currently only messages with JSON content are handled, but I have a requirement to also handle messages with XML content. My current implementation of MessageListener has a MessageConverter injected and uses it in onMessage(Message), like this:
MyMessage myMessage = (MyMessage) jsonConverter.fromMessage(message);
In order to support different content types I could obviously use the MessageProperties to interrogate the content-type header and manually select a converter to use. But that seems like a lot of work, like Spring should provide some better support for this scenario. I was hoping to find a generic MessageConverter implementation that would map from content-types to specific converters, but there doesn't seem to be such a thing.
Is my best option to write a delegating converter like that? Or is there a way to configure the ListenerContainer to support both async receiving and multiple converters that are automatically used as needed?
We have an open JIRA issue requesting support for a CompositeMessageConverter.
The listener container doesn't support conversion but we do have the MessageListenerAdapter which does support them (but just one, and has other stuff like handling replies).
Using the adapter means you can use a POJO method on your listener...
public void handleMessage(MyObject foo) {...}
If you put a delegating converter (one that delegates to either the json or marshalling converter) into the MLA, and both converters create the same object type, this will work fine. Otherwise the signature would have to take an Object and you'd have to do instanceof tests.
At some point, I'd like to make the adapter a bit smarter so it can choose the method based on the object type created by the converter...
public void handleMessage(Foo foo) {...}
public void handleMessage(Bar bar) {...}
... but that's really a different issue.
If you come up with a useful converter that you would like to contribute to the framework, the guidelines are on the project wiki.

Jetty : websocket extended Custom Servlet

I am working on a Existing Jetty based WebSocket code .
In the existing code , in that servlet there are two methods implemented
1. public WebSocket doWebSocketConnect()
2.protected void doGet(HttpServletRequest request, HttpServletResponse response)
As these are callback methods
Could anybody please let me know what method is called first (I mean the method order )
Thanks in advance .
The WebSocketServlet in jetty-7, and jetty-8 (note: this has changed in jetty-9), has a few requirements for you.
The doWebSocketConnect(HttpServletRequest,String) needs to be implemented by you to create a WebSocket object (of your design) based on the information you can find in the HttpServletRequest. (such as host, paths, authentication, etc ...)
You can see an example of a Servlet in the test cases.
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/helper/WebSocketCaptureServlet.java
This creates a CaptureSocket, stores it in the Servlet instance for tracking, and returns it.
The CaptureSocket just stores the incoming Messages so that the test cases can validate the expectations.
This isn't a particularly exciting Servlet/Socket impl.
An example of a few flavors of Echo sockets can also be found in the TestServer (also found in the test cases).
http://git.eclipse.org/c/jetty/org.eclipse.jetty.project.git/tree/jetty-websocket/src/test/java/org/eclipse/jetty/websocket/TestServer.java#n53

Resources