Chapter 6. Endpoint Lifecycle, Sessions, Sending Messages

6.1. Endpoint Lifecycle

As mentioned before, the endpoint in Java API for WebSocket is represented either by instance of jakarta.websocket.Endpoint, or by class annotated with either jakarta.websocket.server.ServerEndpoint or jakarta.websocket.ClientEndpoint. Unless otherwise defined by developer provided configurator (defined in instance of jakarta.websocket.server.ServerEndpointConfig or jakarta.websocket.ClientEndpointConfig, Tyrus uses one endpoint instance per VM per connected peer. Therefore one endpoint instance typically handles connections from one peer.

6.2. jakarta.websocket.Session

The sequence of interactions between an endpoint instance and remote peer is in Java API for WebSocket modelled by jakarta.websocket.Session instance. This interaction starts by mandatory open notification, continues by 0 - n websocket messages and is finished by mandatory closing notification.

The jakarta.websocket.Session instance is passed by Tyrus to the user in the following methods for programmatic endpoints:

  • public void onOpen(Session session, EndpointConfig config)

  • public void onClose(Session session, CloseReason closeReason)

  • public void onError(Session session, Throwable thr)

The jakarta.websocket.Session instance is passed by Tyrus to the user in the methods annotated by following annotations for annotated endpoints:

  • method annotated with jakarta.websocket.OnOpen

  • method annotated with jakarta.websocket.OnMessage

  • method annotated with jakarta.websocket.OnClose

  • method annotated with jakarta.websocket.OnError

In each of the methods annotated with the preceeding annotations the user may use parameter of type jakarta.websocket.Session. In the following example the developer wants to send a message in the method annotated with jakarta.websocket.OnOpen. As we will demonstrate later, the developer needs the session instance to do so. According to Java API for WebSocket Session is one of the allowed parameters in methods annotated with jakarta.websocket.OnOpen. Once the annotated method gets called, Tyrus passes in the correct instance of jakarta.websocket.Session.

Example 6.1. Lifecycle echo sample

@ServerEndpoint("/echo")
public class EchoEndpoint {

    @OnOpen
    public void onOpen(Session session) throws IOException {
        session.getBasicRemote().sendText("onOpen");
    }

    @OnMessage
    public String echo(String message) {
        return message;
    }

    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }
}


6.3. Sending Messages

Generally there are two ways how to send message to the peer endpoint. First one is usable for annotated endpoints only. The user may send the message by returning the message content from the method annotated with jakarta.websocket.OnMessage. In the following example the message m is sent back to the remote endpoint.

Example 6.2. Sending message in @OnMessage

@OnMessage
public String echo(String m) {
    return m;                                                                                                                               
}


The other option how to send a message is to obtain the jakarta.websocket.RemoteEndpoint instance via the jakarta.websocket.Session instance. See the following example:

Example 6.3. Sending message via RemoteEndpoint.Basic instance

@OnMessage
public void echo(String message, Session session) {
    session.getBasicRemote().sendText(message);
}


6.4. RemoteEndpoint

The interface jakarta.websocket.RemoteEndpoint, part of Java API for WebSocket, is designed to represent the other end of the communication (related to the endpoint), so the developer uses it to send the message. There are two basic interfaces the user may use - jakarta.websocket.RemoteEndpoint$Basic and jakarta.websocket.RemoteEndpoint$Async.

6.4.1. jakarta.websocket.RemoteEndpoint.Basic

This representation of the peer of a web socket conversation is used to send synchronous messages. The point of completion of the send is defined when all the supplied data has been written to the underlying connection. The methods for sending messages on the jakarta.websocket.RemoteEndpoint$Basic block until this point of completion is reached, except for jakarta.websocket.RemoteEndpoint$Basic#getSendStream() and jakarta.websocket.RemoteEndpoint$Basic#getSendWriter() which present traditional blocking I/O streams to write messages. See the example "Sending message via RemoteEndpoint.Basic instance" to see how the whole text message is send. The following example demonstrates a method which sends the partial text method to the peer:

Example 6.4. Method for sending partial text message

public void sendPartialTextMessage(String message, Boolean isLast, Session session){
    try {
        session.getBasicRemote().sendText(message, isLast);
    } catch (IOException e) {
        e.printStackTrace();
    }
}


6.4.2. jakarta.websocket.RemoteEndpoint.Async

This representation of the peer of a web socket conversation has the ability to send messages asynchronously. The point of completion of the send is defined when all the supplied data has been written to the underlying connection. The completion handlers for the asynchronous methods are always called with a different thread from that which initiated the send.

Example 6.5. Sending mesage the async way using Future

public void sendWholeAsyncMessage(String message, Session session){
    Future<Void> future = session.getAsyncRemote().sendText(message);
}