WebSockets in Helidon MP

Santiago Pericas-Geertsen
Helidon
Published in
3 min readJun 25, 2020

Helidon integrates with Tyrus to provide support for the Jakarta WebSocket API . The WebSocket API enables Java applications to participate in WebSocket interactions as servers or clients.

Helidon MP support is centered around annotations and bean discovery using CDI. Developers can choose between annotated and programmatic endpoints or use any combination of them. Using annotated endpoints is recommended in MP as they usually result in more succinct and easier-to-read code.

Project Dependencies

To use the WebSocket extension in your Helidon MP application, simply add the following dependency to your POM file:

WebSockets Dependency in MP

Example

This section describes the implementation of a simple application that uses a REST resource to push messages into a shared queue, and a WebSocket endpoint to download messages from the queue, one at a time, over a connection. The example will show how REST and WebSocket connections can be seamlessly combined into a Helidon application.

The Helidon MP application shown here takes full advantage of CDI and class scanning and does not require any additional code given that all the necessary information is available from the code annotations.

The REST endpoint is implemented as a JAX-RS resource, and the queue is directly injected as show next:

MessageQueueResource Class

There is a single instance ofMessageQueue in application scope that will be shared between the REST and WebSocket endpoints. The REST endpoint pushes messages into the queue and the WebSocket endpoint pulls them out of it.

Let us now explore the implementation of the WebSocket endpoint using the annotated API:

MessageBoardEndpoint Class

The annotation @ServerEndpoint anchors the endpoint to the /websocket path and defines a message encoder (more about this later). Since MessageBoardEndpoint is just a POJO, it uses additional annotations for event handlers such as @OnMessage. One advantage of this approach, much like in the JAX-RS API, is that method signatures are not fixed. In the code snippet above, the parameters (which could be specified in any order) include the WebSocket session and the message received that triggered the call.

The implementation of onMessage waits for the string message SEND and, once received, it empties the queue sending each entry as a separate WebSocket message over the connection.

WebSocket endpoints can specify zero or more message encoders and decoders. These codecs are triggered before messages are routed to endpoints (decoders) and after messages are sent from endpoints (encoders). In this example, UppercaseEncoder changes every message sent to the client to uppercase.

UppercaseEncoder Class

So what else is needed to run this Helidon MP app? Nothing else other than the supporting class MessageQueue. Helidon MP declares both @Path and @ServerEndpoint as CDI bean defining annotations, so all that is needed is for CDI discovery to be enabled --which is typically done in your beans.xml file.

By default, both JAX-RS resources and WebSocket endpoints will be available under the root path "/". This default value can be overridden by providing subclasses/implementations for jakarta.ws.rs.Application and jakarta.websocket.server.ServerApplicationConfig, respectively. JAX-RS uses @ApplicationPath on application subclasses to provide this root path, but since there is no equivalent in the WebSocket API, Helidon MP uses its own annotation @RoutingPath on jakarta.websocket.server.ServerApplicationConfig implementations.

All endpoint methods in Helidon MP are executed in a separate thread pool, independently of Netty. Therefore, there is no need to create additional threads for blocking or long-running operations as these will not affect Netty’s ability to process networking data.

For more information about using Websockets in Helidon MP, try the examples at https://github.com/oracle/helidon/tree/master/examples/microprofile/websocket

--

--