I have implemented a websocket server which acts as observer for some events.
#ServerEndPoint
public class Server implements SomeObserver
I have implemented objectChanged() from SomeObserver class. The objectChanged() will execute when there is some event will be occur. It is common observer implemnetation.
The application logic is like this:
Clients connect to Websocket server and server sends appropriate events for appropriate clients.
I have coded it like this:
#ServerEndPoint
public class Server implements SomeObserver
{
Session clientSession = null;
#OnOpen
public void OnOpen(Session session}
{
clientSession = session;
}
//implemented OnMessage and OnClose, OnError methods
public void objectChanged(Event[] event)
{
clientSession.sendAsyncRemote().sendObject(someObjectInfo);
}
I never used any session identification. But surprisingly, server sends appropriate messages for respective session. Server does not send one sessions event to another session without any session authentication or identification.
Does anyone know why and how it happens in Tyrus API.
I want to know how Tyrus webocket support session identification.
clientSession.sendAsyncRemote().sendObject(someObjectInfo);
In the above line, the session object will be created per connection basis. It holds the reference socket object (per connection).
Hence, when message is sent, data will be transferred to the respective client.
Related
Could anyone tell me if the server-side implementation is using stomp WebSocket, is the client also expected to implement stomp?
I am trying to implement a spring boot application and I am confused if I should go with or without stomp implementation. From my research, I understand, if you want to scale the application, it is better to use stomp and embedded broker( RabbitMQ for eg.) as it will handle the sessions, heartbeat etc. instead of an in-memory broker.
The examples available online just shows implementations with and without stomp.
I am basically trying to get different datasets from the table upon client request and write to a WebSocket continuously.
Could anyone please confirm if my understanding so far is correct?
What are the essential things I will have to take care of if I go with stomp + websocket?
Updating the usecase below:
The mobile client would be displaying charts upon user login. There would be links in the left panel for eg. Sales, Discounts etc. which upon clicking, the request will reach server through websocket channel. Server will check the datatype in the request, generate the model using data from DB and write the data to the websocket.
Updating code - v1
MyWebSocketHandler:
#Component
public class MyWebSocketHandler extends TextWebSocketHandler {
Logger logger = LoggerFactory.getLogger(getClass());
#Autowired
DashboardUtil dashboardutil;
#Resource(name = "socketSessionsMap")
private Map<String, WebSocketSession> socketSessionsMap;
#Override
public void handleTextMessage(WebSocketSession session, TextMessage message)
throws InterruptedException, IOException {
try {
//Gets the socket session from map and writes a json to that socket - did for testing purpose.
socketSessionsMap.put("session", session);
//String payload = message.getPayload();
String jsonString = dashboardutil.getDataInJSON(); // gets hardcoded json model
session.sendMessage(new TextMessage(jsonString));
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
}
#Override
public void afterConnectionClosed(WebSocketSession session, CloseStatus status) throws Exception {
}
}
WebSecurityConfig:
#Configuration
#EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
#Autowired
private MyWebSocketHandler myWebSocketHandler;
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(myWebSocketHandler, "/socketHandler").setAllowedOrigins("*").withSockJS();
}
}
Could anyone tell me if the server-side implementation is using stomp
WebSocket, is the client also expected to implement stomp?
You can register multiple handlers in your web socket configuration. So in theory you can provide a handler for STOMP and another one for plain web socket. If you only provide a STOMP handler then the handshake from a standard web socket client will fail.
From my research, I understand, if you want to scale the application,
it is better to use stomp and embedded broker( RabbitMQ for eg.) as it
will handle the sessions, heartbeat etc. instead of an in-memory
broker.
That's correct. STOMP also offers a few more nice features especially the subscription to certain endpoints.
I am basically trying to get different datasets from the table upon
client request and write to a WebSocket continuously.
That's a really simple description ...
You should think about if you need to share sessions across multiple instances or if you need to send messages between web socket sessions.
From your description it sounds like you just accept a web socket connection and continuously push data to the client. If you want to scale this application you can just put a load balancer in front of your instances and you are good to go.
I have a requirement were some of the STOMP websocket connections needs to be handled synchronously.
Meaning I have a client (spring) subscribed to a topic ("/topic").
I have a server (spring) that has defined the broker ("/topic") also defined handlers ("/app/hello").
Now is it possible for the client to send a request to /app/hello and then wait for a response before sending the next request to /app/hello.
How do I return value on my sever (STOMP spec says about RECEIPT frames but I don't think this is something that can be manually controlled).
How do I wait for the value on my client after a send.
To connect a Java client to a websocket endpoint you can use the tyrus reference implementation of JSR356 - Websockets For Java.
Basically you will need to implement a client endpoint (javax.websocket.Endpoint) and a message handler (javax.websocket.MessageHandler). In the endpoint you register the message handler with the current session on open:
public class ClientEndpoint extends Endpoint {
...
#Override
public void onOpen(final Session aSession, final EndpointConfig aConfig) {
aSession.addMessageHandler(yourMessageHandler);
}
}
To connect to the server endpoint you can use the ClientManager:
final ClientManager clientManager = ClientManager.createClient();
clientManager.connectToServer(clientEndpoint, config, uriToServerEndpoint);
The message handler's onMessage method will be invoked, if the server endpoint sends something to the topic.
Depending on your needs you can either choose to implement the mentioned interfaces or use the corresponding annotations.
UPDATE:
The STOMP website lists several implementations of the STOMP protocol. For Java there are Gozirra and Stampy. I have no experience with these frameworks but the examples are pretty straight forward.
I am trying to fetch data through webservice and forward it to the browser through websocketing. So that, I can validate the response of webservice based on the individual websocket opened connection.
Basically, it would be
SERVER1 ---->WEBSERVICE CALL ----> SERVER TO VALIDATE DATA <====> open from client <----WEBSOCKET----> listens to IP through <====>CLIENT
The client is opening a connection to start listening for a particular data for a given MAC address.
I am facing a problem to bypass the data received from webservices to the listener port and IP.
So that, I am trying to persist it using JPA (ODB) objectDB, we could able to store into .odb, but whereas, when trying to make a request to fetch .odb from another application server(CLIENT) to the validator server(SERVER TO VALIDATE DATA). I am getting nothing.
I feel that might be because of lack of session handler among different webapps.
#ServerEndpoint("/echo") //websocket
#Path("/json/metallica") //webservice
public class JSONService {
#POST
#Path("/post")
#Consumes(MediaType.APPLICATION_JSON)
public Response createTrackInJSON(Track track) {
// where I am storing into db---------**** step
}
// connection OPENED from differnet **webapp**
#OnMessage
public void echoTextMessage(Session session, String msg, boolean last) {
if (session.isOpen()) {
//I couldn't able to fetch the data from db which I stored in ---------**** step.
}
}
I am getting empty results. Any suggestions where I am going wrong.
Thanks.
I am developing a websocket server and client which will handle multiple messages.
I am using JSON with decoders and encoders.
As we can have only one #OnMessage method per endpoint, I created one Marker interface called message. Now my #OnMessage method as parameters like void #OnMessage(Message message, Session session) in both Client and Server.
I am sending Register_Send object from #OnConnect of Client using Session.getAsyncRemote().sendObject. Server reads this message successfully and sends Register_Received object to client using Session.getAsyncRemote().sendObject.
Both Register_Send and Register_Received implements Message interface. Both objects are encoded and decoded as JSON objects.
But at client side void #OnMessage(Message message, Session session) method receives Register_Received object as Register_Send. Due to which, exception is thrown.
I am unable to resolve this issue,whether its fault in my code or in Tyrus 1.7 API.
Please suggest me solution for this problem.
I'm developing a application using Java RMI which enable clients to register topics they want to listen (zero or more) and topic (zero or one) they want to speak about. There is a central server which offers registration service. The communication of clients avoids server with the exception of initial registering of ListenerCallback or SpeakerCallback.
Clients and server work according to Observer pattern.
Callback interfaces:
public interface ListenerCallback extends Remote{
void notify(String topic, String msg) throws RemoteException;
}
public interface SpeakerCallback extends Remote{
Unregister accept(ListenerCallback listenerCallback) throws RemoteException;
}
Fragment of registration method on server, both speaker and listener are remote references:
for (SpeakerCallback speaker : registeredSpeakers){
try {
speaker.accept(listener);
} catch (RemoteException e){
//TODO should I unregister speaker?
}
}
As written above in //TODO, I suppose I should unregister speaker from my application registries, because as far as I know RemoteException indicates that the connection with client is broken.
The problem I'm struggling with is how should I manage abnormal client shutdown that only listen to some topic but speak about none. The server holds them in application registries, but has no way to determine whether they are still valid, because it doesn't call its notify() method.
Shoud I add some bogus method to ListenerCallback interface just for trying to determine whether client is still reachable?
Or should I implemented a protocol which would enable clients who speak about (these call notify() method) a certain topic notify server that some listening clients are no more available?
This is a job for the Remote Session pattern. Every client does a login step, which allocates and returns a new remote object which is really a session object, which in turn:
has a logout() method, which unexports the object
provides the other APIs the client needs, and
implements Unreferenced, with the unreferenced() method calling logout().
So if the client either calls logout() or dies the object will disappear; and whatever collateral actions need to happen can all happen in the logout() method.
If you get a remoteException, that does not mean the client is down, you will have to check the sub types of remoteEception like ConnectException etc which inform that there is no endpoint anymore, only then you can unregister the client.
For checking if the clients are alive you can implement some dummy API on the client side and use it for pinging the client in a timer task. You can optimize this ping interval based on the severity of the client registration's staleness.