Chapter 14. Creating Jakarta WebSocket applications

The Jakarta WebSocket protocol provides two-way communication between web clients and servers. Communications between clients and the server are event-based, allowing for faster processing and smaller bandwidth compared with polling-based methods. Jakarta WebSocket is available for use in web applications using a JavaScript API and by client Jakarta WebSocket endpoints using the Jakarta WebSocket specification.

A connection is first established between client and server as an HTTP connection. The client then requests a Jakarta WebSocket connection using the Upgrade header. All communications are then full-duplex over the same TCP/IP connection, with minimal data overhead. Because each message does not include unnecessary HTTP header content, Jakarta WebSocket communications require smaller bandwidth. The result is a low latency communications path suited to applications, which require real-time responsiveness.

The JBoss EAP Jakarta WebSocket implementation provides full dependency injection support for server endpoints, however, it does not provide Contexts and Dependency Injection services for client endpoints.

A Jakarta WebSocket application requires the following components and configuration changes:

  • A Java client or a Jakarta WebSocket enabled HTML client. You can verify HTML client browser support at this location: http://caniuse.com/#feat=websockets
  • A Jakarta WebSocket server endpoint class.
  • Project dependencies configured to declare a dependency on the Jakarta WebSocket API.

Create the Jakarta WebSocket Application

The code examples that follow are taken from the websocket-hello quickstart that ships with JBoss EAP. It is a simple example of a Jakarta WebSocket application that opens a connection, sends a message, and closes a connection. It does not implement any other functions or include any error handling, which would be required for a real world application.

  1. Create the JavaScript HTML client.

    The following is an example of a Jakarta WebSocket client. It contains these JavaScript functions:

    • connect(): This function creates the Jakarta WebSocket connection passing the Jakarta WebSocket URI. The resource location matches the resource defined in the server endpoint class. This function also intercepts and handles the Jakarta WebSocket onopen, onmessage, onerror, and onclose.
    • sendMessage(): This function gets the name entered in the form, creates a message, and sends it using a WebSocket.send() command.
    • disconnect(): This function issues the WebSocket.close() command.
    • displayMessage(): This function sets the display message on the page to the value returned by the Jakarta WebSocket endpoint method.
    • displayStatus(): This function displays the Jakarta WebSocket connection status.

      Example: Application index.html Code

      <html>
        <head>
          <title>WebSocket: Say Hello</title>
          <link rel="stylesheet" type="text/css" href="resources/css/hello.css" />
          <script type="text/javascript">
            var websocket = null;
            function connect() {
              var wsURI = 'ws://' + window.location.host + '/websocket-hello/websocket/helloName';
              websocket = new WebSocket(wsURI);
              websocket.onopen = function() {
                  displayStatus('Open');
                  document.getElementById('sayHello').disabled = false;
                  displayMessage('Connection is now open. Type a name and click Say Hello to send a message.');
              };
              websocket.onmessage = function(event) {
                  // log the event
                  displayMessage('The response was received! ' + event.data, 'success');
              };
              websocket.onerror = function(event) {
                  // log the event
                  displayMessage('Error! ' + event.data, 'error');
              };
              websocket.onclose = function() {
                  displayStatus('Closed');
                  displayMessage('The connection was closed or timed out. Please click the Open Connection button to reconnect.');
                  document.getElementById('sayHello').disabled = true;
              };
            }
            function disconnect() {
              if (websocket !== null) {
                  websocket.close();
                  websocket = null;
              }
              message.setAttribute("class", "message");
              message.value = 'WebSocket closed.';
              // log the event
            }
            function sendMessage() {
              if (websocket !== null) {
                  var content = document.getElementById('name').value;
                  websocket.send(content);
              } else {
                  displayMessage('WebSocket connection is not established. Please click the Open Connection button.', 'error');
              }
            }
            function displayMessage(data, style) {
              var message = document.getElementById('hellomessage');
              message.setAttribute("class", style);
              message.value = data;
            }
            function displayStatus(status) {
              var currentStatus = document.getElementById('currentstatus');
              currentStatus.value = status;
            }
          </script>
        </head>
        <body>
          <div>
            <h1>Welcome to Red Hat JBoss Enterprise Application Platform!</h1>
            <div>This is a simple example of a Jakarta WebSocket implementation.</div>
            <div id="connect-container">
              <div>
                <fieldset>
                  <legend>Connect or disconnect using websocket :</legend>
                  <input type="button" id="connect" onclick="connect();" value="Open Connection" />
                  <input type="button" id="disconnect" onclick="disconnect();" value="Close Connection" />
                </fieldset>
              </div>
              <div>
                  <fieldset>
                    <legend>Type your name below, then click the `Say Hello` button :</legend>
                    <input id="name" type="text" size="40" style="width: 40%"/>
                    <input type="button" id="sayHello" onclick="sendMessage();" value="Say Hello" disabled="disabled"/>
                  </fieldset>
              </div>
              <div>Current WebSocket Connection Status: <output id="currentstatus" class="message">Closed</output></div>
              <div>
                <output id="hellomessage" />
              </div>
            </div>
          </div>
        </body>
      </html>

  2. Create the Jakarta WebSocket server endpoint.

    You can create a Jakarta WebSocket server endpoint using either of the following methods.

    • Programmatic Endpoint: The endpoint extends the Endpoint class.
    • Annotated Endpoint: The endpoint class uses annotations to interact with the Jakarta WebSocket events. It is simpler to code than the programmatic endpoint.

    The code example below uses the annotated endpoint approach and handles the following events.

    • The @ServerEndpoint annotation identifies this class as a Jakarta WebSocket server endpoint and specifies the path.
    • The @OnOpen annotation is triggered when the Jakarta WebSocket connection is opened.
    • The @OnMessage annotation is triggered when a message is received.
    • The @OnClose annotation is triggered when the Jakarta WebSocket connection is closed.

      Example: Jakarta WebSocket Endpoint Code

      package org.jboss.as.quickstarts.websocket_hello;
      
      import javax.websocket.CloseReason;
      import javax.websocket.OnClose;
      import javax.websocket.OnMessage;
      import javax.websocket.OnOpen;
      import javax.websocket.Session;
      import javax.websocket.server.ServerEndpoint;
      
      @ServerEndpoint("/websocket/helloName")
      public class HelloName {
      
          @OnMessage
          public String sayHello(String name) {
              System.out.println("Say hello to '" + name + "'");
              return ("Hello" + name);
          }
      
          @OnOpen
          public void helloOnOpen(Session session) {
              System.out.println("WebSocket opened: " + session.getId());
          }
      
          @OnClose
          public void helloOnClose(CloseReason reason) {
              System.out.println("WebSocket connection closed with CloseCode: " + reason.getCloseCode());
          }
      }

  3. Declare the Jakarta WebSocket API dependency in your project POM file.

    If you use Maven, you add the following dependency to the project pom.xml file.

    Example: Maven Dependency

    <dependency>
      <groupId>org.jboss.spec.javax.websocket</groupId>
      <artifactId>jboss-websocket-api_1.1_spec</artifactId>
      <scope>provided</scope>
    </dependency>

The quickstarts that ship with JBoss EAP include additional Jakarta WebSocket client and endpoint code examples.