Chapter 1. Getting Started

This chapter provides a quick introduction on how to get started building WebSocket services using Java API for WebSocket and Tyrus. The example described here presents how to implement simple websocket service as JavaEE web application that can be deployed on any servlet container supporting Servlet 3.1 and higher. It also discusses starting Tyrus in standalone mode.

1.1. WebSocket Services Using Java API for WebSocket

First, to use the Java API for WebSocket in your project you need to depend on the following artifact:

<dependency>
    <groupId>javax.websocket</groupId>
    <artifactId>javax.websocket-api</artifactId>
    <version>1.1</version>
</dependency>

1.1.1. Creating Annotated Server Endpoint

In this section we will create a simple server side websocket endpoint which will echo the received message back to the sender. We will deploy this endpoint on the container.

In Java API for WebSocket and Tyrus, there are two basic approaches how to create an endpoint - either annotated endpoint, or programmatic endpoint. By annotated endpoint we mean endpoint constructed by using annotations (javax.websocket.server.ServerEndpoint for server endpoint and javax.websocket.ClientEndpoint for client endpoint), like in "Annotated Echo Endpoint".

Example 1.1. Annotated Echo Endpoint

@ServerEndpoint(value = "/echo")
public class EchoEndpointAnnotated {
    @OnMessage
    public String onMessage(String message, Session session) {
        return message;
    }
}


The functionality of the EchoEndpointAnnotated is fairly simple - to send the received message back to the sender. To turn a POJO (Plain Old Java Object) to WebSocket server endpoint, the annotation @ServerEndpoint(value = "/echo") needs to be put on the POJO - see line 1. The URI path of the endpoint is "/echo". The annotation @OnMessage - line 3 on the method public String onMessage(String message, Session session) indicates that this method will be called whenever text message is received. On line 5 in this method the message is sent back to the user by returning it from the message.

The application containing only the EchoEndpointAnnotated class can be deployed to the container.

1.1.2. Client Endpoint

Let's create the client part of the application. The client part may be written in JavaScript or any other technology supporting WebSockets. We will use Java API for WebSocket and Tyrus to demonstrate how to develop programmatic client endpoint. The following code is used as a client part to communicate with the EchoEndpoint deployed on server using Tyrus and Java API for WebSocket.

The example "Client Endpoint" utilizes the concept of the programmatic endpoint. By programmatic endpoint we mean endpoint which is created by extending class javax.websocket.Endpoint. The example is standalone java application which needs to depend on some Tyrus artifacts to work correctly, see "Tyrus Standalone Mode". In the example first the CountDownLatch is initialized. It is needed as a bocking data structure - on line 31 it either waits for 100 seconds, or until it gets counted down (line 22). On line 9 the javax.websocket.ClientEndpointConfig is created - we will need it later to connect the endpoint to the server. On line 11 the org.glassfish.tyrus.client.ClientManager is created. it implements the javax.websocket.WebSocketContainer and is used to connect to server. This happens on next line. The client endpoint functionality is contained in the javax.websocket.Endpoint lazy instantiation. In the onOpen method new MessageHandler is registered (the received message is just printed on the console and the latch is counted down). After the registration the message is sent to the server (line 25).

Example 1.2. Client Endpoint

public class DocClient {
    private static CountDownLatch messageLatch;
    private static final String SENT_MESSAGE = "Hello World";

    public static void main(String [] args){
        try {
            messageLatch = new CountDownLatch(1);

            final ClientEndpointConfig cec = ClientEndpointConfig.Builder.create().build();

            ClientManager client = ClientManager.createClient();
            client.connectToServer(new Endpoint() {

                @Override
                public void onOpen(Session session, EndpointConfig config) {
                    try {
                        session.addMessageHandler(new MessageHandler.Whole<String>() {

                            @Override
                            public void onMessage(String message) {
                                System.out.println("Received message: "+message);
                                messageLatch.countDown();
                            }
                        });
                        session.getBasicRemote().sendText(SENT_MESSAGE);
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }, cec, new URI("ws://localhost:8025/websockets/echo"));
            messageLatch.await(100, TimeUnit.SECONDS);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}


1.1.3. Creating Server Endpoint Programmatically

Similarly to "Client Endpoint" the server registered endpoint may also be the programmatic one:

Example 1.3. Programmatic Echo Endpoint

public class EchoEndpointProgrammatic extends Endpoint {
    @Override
    public void onOpen(final Session session, EndpointConfig config) {
        session.addMessageHandler(new MessageHandler.Whole<String>() {
            @Override
            public void onMessage(String message) {
                try {
                    session.getBasicRemote().sendText(message);
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        });
    }
}


The functionality of the EchoEndpointProgrammatic is fairly simple - to send the received message back to the sender. The programmatic server endpoint needs to extend javax.websocket.Endpoint - line 1. Mehod public void onOpen(final Session session, EndpointConfig config) gets called once new connection to this endpoin0t is opened. In this method the MessageHandler is registered to the javax.websocket.Session instance, which opened the connection. Method public void onMessage(String message) gets called once the message is received. On line 8 the message is sent back to the sender.

To see how both annotated and programmatic endpoints may be deployed please check the section Deployment. In short: you need to put the server endpoint classes into WAR, deploy on server and the endpoints will be scanned by server and deployed.

1.1.4. Tyrus in Standalone Mode

To use Tyrus in standalone mode it is necessary to depend on correct Tyrus artifacts. The following artifacts need to be added to your pom to use Tyrus:

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-server</artifactId>
    <version>1.12</version>
</dependency>

<dependency>
    <groupId>org.glassfish.tyrus</groupId>
    <artifactId>tyrus-container-grizzly-server</artifactId>
    <version>1.12</version>
</dependency>

Let's use the very same example like for Java API for WebSocket and deploy the EchoEndpointAnnotated on the standalone Tyrus server on the hostname "localhost", port 8025 and path "/websockets", so the endpoint will be available at address "ws://localhost:8025/websockets/echo".

public void runServer() {
    Server server = new Server("localhost", 8025, "/websockets", null, EchoEndpoint.class);

    try {
        server.start();
        BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
        System.out.print("Please press a key to stop the server.");
        reader.readLine();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        server.stop();
    }
}