Send message to all connected web socket clients - java

I'm using Jooby's MVC routes for an API. I have also set up a websocket, to which a few clients connect. What I'm trying to do is send a message to all connected websocket clients whenever a specific http request is received in the server. This is how my route method looks like:
#Path("/player")
#Produces("application/json")
public class PlayerRoute {
#POST
public Result newPlayer(Request req, #Body Player player) {
//do some process here
//this is what I'm trying to achieve..
allWebsocketSessions.foreach(session ->
session.send("a new player has been created")
);
return Results.ok();
}
}
I've read jooby's documentation but can't figure out how to do it.
Thanks in advance.

It seems for "session you can call "set" and "get" methods only. Method "send" you can call for "response".

Related

How do you retrieve the request body of a POST when creating an HTTP server using the java Apache httpcore5 framework

I am creating an HTTP server using the Apache httpcore5 framework. I am implementing an AsyncServerRequestHandler. The method I implement is
public void handle(Message<HttpRequest, ?> message, ResponseTrigger responseTrigger, HttpContext httpContext)
Unfortunately, the message I am passed returns null if I call getBody() . I need that body because it contains the CGI arguments of a POST.
(edit): my prepare() method looks like
public AsyncRequestConsumer<Message<HttpRequest, Void>> prepare(HttpRequest request, HttpContext context)
// throws HttpException
{
return new BasicRequestConsumer<Void>(new NoopEntityConsumer());
}
For people who are speed-reading this: I am the server. I am not asking how a client performs a POST. I am asking how a server gains access to the POST body so it can properly respond.
How do I get that message body?
Thomas Kelley's question led me to figure out the problem. By switching toimplements AsyncServerRequestHandler<Message<HttpRequest, byte[]>>
and rewriting my prepare() as
public AsyncRequestConsumer<Message<HttpRequest, byte[]>> prepare(HttpRequest request, HttpContext context)
{
if (request.getMethod().equals("GET"))
return new BasicRequestConsumer(new NoopEntityConsumer()); // is that one client bananas?
AsyncEntityConsumer<byte[]> dataConsumer = new BasicAsyncEntityConsumer();
return new BasicRequestConsumer<>(dataConsumer);
}
I was able to gain access to the POST request body using message.getBody(). The GET branch of the if is to work around an embedded HTTP client that seems to fail if I use a BasicAsyncEntityConsumer with a GET.

Push notifications using rabbitmq

I want to send notifications to mobile application using rabbitmq, the problem is that i never used amqp protocol, so i need some advices
1) As i read from here http://www.rabbitmq.com/alarms.html if i send message all cosumers will get it, do i need to create separate queue for each user?
2)I want to send push using GCM only when mobile application is turn off, can i do it using this structure(spring boot)?
#Controller
public class SampleController {
Logger logger = Logger.getLogger(SampleController.class);
#Autowired
RabbitTemplate template;
#RequestMapping("/")
#ResponseBody
String home() {
return "Empty mapping";
}
#RequestMapping("/process/{message}")
#ResponseBody
String error(#PathVariable("message") String message) {
logger.info(String.format("Emit '%s'",message));
String response = (String) template.convertSendAndReceive("query-example-2",message);
logger.info(String.format("Received on producer '%s'",response));
if(response==null) {
sendPushViaGCM(message);
}
return String.valueOf("returned from worker : " + response);
}
3) If mobile appliction is turn off and i send push using gcm how to delete message from rabbitmq queue to avoid double push when application is turn on
4)As i suggested, when client connect to my rabbitmq service all others will don't have permission to listen other queues until first one is not finished. Am i right?
Some code examples will be grateful

Basic websocket with Spring without STOMP and SockJS

I have implemented the following websocket endpoint
#MessageMapping("/socket/{myId}/")
#SendTo("/queue/myqueue")
public MyObject getObject(#DestinationVariable String myId) throws Exception {
return new MyObject("MyId:" + myId);
}
Now how can I send message to that endpoint from one of my service.java class?
There will be front-end client as well, which will read the message from websocket once the service.java class's method send some message to websocket endpoint. I am a little confused that how can I do that?
Any help would be appreciated
When using a raw websocket(without STOMP), the message sent lacks of information to make Spring route it to a specific message handler method (we don't have any messaging protocol), so instead of annotating your controller, you'll have to implement a WebSocketHandler by extending TextWebSocketHandler
public void handleTextMessage(WebSocketSession session, TextMessage message){
}
Checkout an example here spring boot websocket without STOMP and SockJs
You should take a look at SimpMessagingTemplate.
For example, if you want to send a message for a specific user from your service class:
#Autowired
private SimpMessagingTemplate messagingTemplate;
public void sendMessage(User user, String message) {
Objects.requireNonNull(user);
Objects.requireNonNull(message);
messagingTemplate.convertAndSendToUser(user.getUsername(), "/queue/myqueue", message);
}

Where "user" comes from in convertAndSendToUser works in SockJS+Spring Websocket?

I would like to understand how convertAndSendToUser works in Spring SockJS+Websocket framework.
In client, we would connect as
stompClient.connect(login, password, callback())
which will result in connect request with "Stomp credentials" of login and password, that can be seen e.g. if we handle SessionConnectEvent http://www.sergialmar.com/2014/03/detect-websocket-connects-and-disconnects-in-spring-4/
But it remains unclear to me whether this will be the "user" meant in server-side send operation to a queue:
simpMessagingTemplate.convertAndSendToUser(username, "/queue/reply", message);
The closest I can get is to read this thread Sending message to specific user on Spring Websocket, answer by Thanh Nguyen Van, but it is still unclear.
Basically what I need to do, is to subscribe some clients to same topic, but on server, send them different data. Client may supply user identifier.
We know we can send messages to the client from a stomp server using the topic prefixes that he is subscribed to e.g. /topic/hello. We also know we can send messages to a specific user because spring provides the convertAndSendToUser(username, destination, message) API. It accepts a String username which means if we somehow have a unique username for every connection, we should be able to send messages to specific users subscribed to a topic.
What's less understood is, where does this username come from ?
This username is part of a java.security.Principal interface. Each StompHeaderAccessor or WebSocketSession object has instance of this principal and you can get the user name from it. However, as per my experiments, it is not generated automatically. It has to be generated manually by the server for every session.
To use this interface first you need to implement it.
class StompPrincipal implements Principal {
String name
StompPrincipal(String name) {
this.name = name
}
#Override
String getName() {
return name
}
}
Then you can generate a unique StompPrincipal for every connection by overriding the DefaultHandshakeHandler. You can use any logic to generate the username. Here is one potential logic which uses UUID :
class CustomHandshakeHandler extends DefaultHandshakeHandler {
// Custom class for storing principal
#Override
protected Principal determineUser(
ServerHttpRequest request,
WebSocketHandler wsHandler,
Map<String, Object> attributes
) {
// Generate principal with UUID as name
return new StompPrincipal(UUID.randomUUID().toString())
}
}
Lastly, you need to configure your websockets to use your custom handshake handler.
#Override
void registerStompEndpoints(StompEndpointRegistry stompEndpointRegistry) {
stompEndpointRegistry
.addEndpoint("/stomp") // Set websocket endpoint to connect to
.setHandshakeHandler(new CustomHandshakeHandler()) // Set custom handshake handler
.withSockJS() // Add Sock JS support
}
That's It. Now your server is configured to generate a unique principal name for every connection. It will pass that principal as part of StompHeaderAccessor objects that you can access through connection event listeners, MessageMapping functions etc...
From event listeners :
#EventListener
void handleSessionConnectedEvent(SessionConnectedEvent event) {
// Get Accessor
StompHeaderAccessor sha = StompHeaderAccessor.wrap(event.getMessage())
}
From Message Mapped APIs
#MessageMapping('/hello')
protected void hello(SimpMessageHeaderAccessor sha, Map message) {
// sha available in params
}
One last note about using convertAndSendToUser(...). When sending messages to a user, you will use something like this
convertAndSendToUser(sha.session.principal.name, '/topic/hello', message)
However, for subscribing the client, you will use
client.subscribe('/user/topic/hello', callback)
If you subscribe the client to /topic/hello you will only receive broadcasted messages.
I did not do any specific configuration and I can just do this:
#MessageMapping('/hello')
protected void hello(Principal principal, Map message) {
String username = principal.getName();
}
Similar to Wenneguen I was able to do just by injecting Principal in the MessageMapping method
public void processMessageFromClient(#Payload String message, Principal principal) {
the principal.getName() implementation is from org.springframework.security.authentication.UsernamePasswordAuthenticationToken
class

java web services - request, acknowledgment and response

I have to develop a Java web service that get a request and sends immediately an acknowledgment (synchronous), so that far, it is simple.
Next, the web service has to do multiple checks on the request, then send a response according to that (synchronous too, because i don't have a callback endpoint from the client).
The problem is that i can send the ackowledgment, and i launch the multiple checks in another thread, but when the checks are done, the client already recieved his response, and i can't send another one.
Here's what i did for now:
#WebService
public class Configuration {
#Resource WebServiceContext context;
#WebMethod
public ReqAckType configure(#XmlElement(required = true) #WebParam(name = "reqType")
ReqType req) {
ReqAckType ack = new ReqAckType();
ack.setReceptionTime(Calendar.getInstance());
ChecksScheduler cs = ChecksScheduler.getInstance();
Checks checks = cs.schedule(req);
ack.setInternalId(checks.getId());
return ack;
}
}
If anyone can help me figure out how to send two separate message (ack and response), knowing that i have to send them separately and the checks take too much time (it's because of that, that i have to send and ack), i would be thankful.
I am using Oracle Fusion Middleware (Weblogic, JDeveloper, ..)

Categories

Resources