///////////////////////////////////////////////////////////////////////////////

    Copyright (c) 2020 Oracle and/or its affiliates.

    Licensed under the Apache License, Version 2.0 (the "License");
    you may not use this file except in compliance with the License.
    You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing, software
    distributed under the License is distributed on an "AS IS" BASIS,
    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    See the License for the specific language governing permissions and
    limitations under the License.

///////////////////////////////////////////////////////////////////////////////

= WebSocket Introduction
:pagename: websocket-introduction
:description: Helidon WebSocket Introduction
:keywords: helidon, webserver, websocket, se

Helidon integrates with Tyrus [1] to provide support for the Jakarta WebSocket API [2].
The WebSocket API enables Java applications to participate in WebSocket interactions
as both servers and clients. The server API supports two flavors: annotated and
programmatic endpoints.

Annotated endpoints, as suggested by their name, use Java annotations to provide
the necessary meta-data to define WebSocket handlers; programmatic endpoints
implement API interfaces and are annotation free. Annotated endpoints tend to be
more flexible since they allow different method signatures depending on the
application needs, whereas programmatic endpoints must implement an interface
and are, therefore, bounded to its definition.

Helidon SE support is based on the `TyrusSupport` class which is
akin to `JerseySupport`, and enables Helidon application to
defined both annotated and programmatic WebSocket endpoints.

== Helidon SE Example

This section describes the implementation of a simple application
that uses a REST resource to push messages into a shared queue and a
programmatic 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 complete Helidon SE example is available here [3]. Let us start by
looking at `MessageQueueService`:

[source,java]
----
public class MessageQueueService implements Service {

    private final MessageQueue messageQueue = MessageQueue.instance();

    @Override
    public void update(Routing.Rules routingRules) {
        routingRules.post("/board", this::handlePost);
    }

    private void handlePost(ServerRequest request, ServerResponse response) {
        request.content().as(String.class).thenAccept(messageQueue::push);
        response.status(204).send();
    }
}
----

This class exposes a REST resource where messages can be posted. Upon
receiving a message, it simply pushes it into a shared queue and
returns 204 (No Content).

Messages pushed into the queue can be obtained by opening a WebSocket
connection served by `MessageBoardEndpoint`:

[source,java]
----
public class MessageBoardEndpoint extends Endpoint {

    private final MessageQueue messageQueue = MessageQueue.instance();

    @Override
    public void onOpen(Session session, EndpointConfig endpointConfig) {
        session.addMessageHandler(new MessageHandler.Whole<String>() {
            @Override
            public void onMessage(String message) {
                try {
                    if (message.equals("SEND")) {
                        while (!messageQueue.isEmpty()) {
                            session.getBasicRemote().sendObject(messageQueue.pop());
                        }
                    }
                } catch (Exception e) {
                    // ...
                }
            }
        });
    }
}
----

This is an example of a programmatic endpoint that extends `Endpoint`. The method
`onOpen` will be invoked for every new connection. In this example, the application
registers a message handler for strings, and when the special `SEND` message
is received, it empties the shared queue sending messages one at a time over
the WebSocket connection.

In Helidon SE, REST and WebSocket classes need to be manually registered into
the web server. This is accomplished via a `Routing` builder:

[source,java]
----
    List<Class<? extends Encoder>> encoders =
           Collections.singletonList(UppercaseEncoder.class);

    Routing.builder()
           .register("/rest", new MessageQueueService())
           .register("/websocket",
                TyrusSupport.builder().register(
                        ServerEndpointConfig.Builder.create(
                                MessageBoardEndpoint.class, "/board").encoders(
                                        encoders).build()).build())
                .build();
[source,java]
----

This code snippet uses multiple builders for `Routing`, `TyrusSupport` and `ServerEndpointConfig`.
In particular, it registers `MessageBoardEndpoint.class` at `"/websocket/board"` and associates
with it a _message encoder_. For more information on message encoders and decoders the
reader is referred to [2]; in this example, `UppercaseEncoder.class` simply uppercases every
message sent from the server [3].

Endpoint methods in Helidon SE are executed in Netty's worker thread pool. Threads in this
pool are intended to be _non-blocking_, thus it is recommended for any blocking or
long-running operation triggered by an endpoint method to be executed using a separate
thread pool. See the documentation for `io.helidon.common.configurable.ThreadPoolSupplier`.

- [1] https://projects.eclipse.org/projects/ee4j.tyrus
- [2] https://projects.eclipse.org/projects/ee4j.websocket
- [3] https://github.com/oracle/helidon/tree/master/examples/webserver/websocket
