Over a million developers have joined DZone.

Building a Samlple Java WebSocket Client

Learn more about creating Java-based WebSocket clients, including code for the server side WebSocket application and the corresponding JavaScript/HTML client.

· Integration Zone

Learn how API management supports better integration in Achieving Enterprise Agility with Microservices and API Management, brought to you in partnership with 3scale

Java-Based WebSocket Client Implementation

During my Google search for a Java WebSocket client, I ended up with valuable info on several blogs and presentation slides. Generally, the samples are on the implementation of a server side WebSocket application, but the client side is JavaScript/HTML.  

In this article, I will present a Java based WebSocket client, but for the sake of completeness I will also provide the code for the server side WebSocket application [and the corresponding JavaScript/HTML client as a bonus.

Configuration

Please note the 4 key-points for configuring both the server-side and the client-side.

  1. For the WebSocket server implementation: Java API for WebSocket (JSR-356) is a new standard coming in JavaEE 7, so check your application server support for JavaEE7 on running the WebSocket server sample.

    I generally use WebSphere, but the WAS Liberty 8.5.5 did not run this since it is JavaEE 6 so I ran the server on GlassFish 4.0 (build 89).

    Just deploy the single class provided in a WAR or EAR file. No need to configure the web.xml/deployment descriptor since the annotation based approach is used.


  2. For the Java client implementation: JavaSE7 does not include WebSocket so you should add the necessary jar files yourself.

    I used Tyrus as the WebSocket API implementation.
      Use javax.websocket-api.jar and tyrus-standalone-client-1.3.3.jar from https://tyrus.java.net/

  3. For the Java client implementation: The Java client should have a file named javax.websocket.ContainerProvider in the MEFA-INF/services folder with the content org.glassfish.tyrus.client.ClientManager to introduce Tyrus to the JavaSE7 environment as a WebSocketContainer provider. (see ServiceLoader API for details)

  4. For the JavaScript/HTML bonus implementation: IE9 does not support WebSocket. IE version must be at least 10. For Firefox and Chrome...they have been supporting WebSocket for a very long time so it won't be a problem. See http://caniuse.com for more info

The Application

The sample WebSocket server application is a virtual USD Exchange rate publishing server. A new exchange rate becomes available every 2 seconds and it is published to all registered clients.

 The WebSocket client consumes the new USD rate immediately as it becomes available.

The Server Side

In order to keep things simple and easy to copy and organize in your IDE, the server application is a provided as a single class. This single class contains an anonymous inner class which serves as the Thread to generate and publish the new USD rate every 2 seconds, and the class itself does the WebSocket 'magic' .

package websocket.server;

import java.text.DecimalFormat;
import java.util.*;
import java.util.concurrent.*;
import javax.websocket.*;
import javax.websocket.server.*;

@ServerEndpoint("/ratesrv")
public class CustomEndPoint {
 //queue holds the list of connected clients
 private static Queue<Session> queue = new ConcurrentLinkedQueue<Session>();
 private static Thread rateThread ; //rate publisher thread

 static
 {
//rate publisher thread, generates a new value for USD rate every 2 seconds.
  rateThread=new Thread(){
   public void run() {
    DecimalFormat df = new DecimalFormat("#.####");
    while(true)
    {
     double d=2+Math.random();     
     if(queue!=null)
      sendAll("USD Rate: "+df.format(d));    
     try {
      sleep(2000);
     } catch (InterruptedException e) {      
     }
    }
   };
  } ;
  rateThread.start();
 }

 @OnMessage
 public void onMessage(Session session, String msg) {
//provided for completeness, in out scenario clients don't send any msg.
  try {   
   System.out.println("received msg "+msg+" from "+session.getId());
  } catch (Exception e) {
   e.printStackTrace();
  }
 }

@OnOpen
 public void open(Session session) {
  queue.add(session);
  System.out.println("New session opened: "+session.getId());
 }

  @OnError
 public void error(Session session, Throwable t) {
  queue.remove(session);
  System.err.println("Error on session "+session.getId());  
 }

 @OnClose
 public void closedConnection(Session session) { 
  queue.remove(session);
  System.out.println("session closed: "+session.getId());
 }

 private static void sendAll(String msg) {
  try {
   /* Send the new rate to all open WebSocket sessions */  
   ArrayList<Session > closedSessions= new ArrayList<>();
   for (Session session : queue) {
    if(!session.isOpen())
    {
     System.err.println("Closed session: "+session.getId());
     closedSessions.add(session);
    }
    else
    {
 session.getBasicRemote().sendText(msg);
    }    
   }
   queue.removeAll(closedSessions);
   System.out.println("Sending "+msg+" to "+queue.size()+" clients");
  } catch (Throwable e) {
   e.printStackTrace();
  }
 }
}

The long promised Java based client implementation

The client application connects to the websocket server and consumes new USD rates.

package websocket.client;

import java.net.URI;
import javax.websocket.*;

@ClientEndpoint
public class WSClient  {
    private static Object waitLock = new Object();

@OnMessage
    public void onMessage(String message) {
//the new USD rate arrives from the websocket server side.
       System.out.println("Received msg: "+message);        
    }

 private static void  wait4TerminateSignal()
 {
  synchronized(waitLock)
  {try {
    waitLock.wait();
   } catch (InterruptedException e) {    
   }}}

public static void main(String[] args) {
WebSocketContainer container=null;//
     Session session=null;
  try{
   //Tyrus is plugged via ServiceLoader API. See notes above
   container = ContainerProvider.getWebSocketContainer(); 

//WS1 is the context-root of my web.app 
//ratesrv is the  path given in the ServerEndPoint annotation on server implementation
session=container.connectToServer(WSClient.class, URI.create("ws://localhost:8080/WS1/ratesrv")); 

   wait4TerminateSignal();
  } catch (Exception e) {
   e.printStackTrace();
  }
  finally{
   if(session!=null){
    try {
 session.close();
    } catch (Exception e) {     
     e.printStackTrace();
    }
   }         
  } 
 }
}


The JavaScript client

The bonus:)

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Client</title>
 <script type="text/javascript">

      var wsocket;      
      function connect() {         
 wsocket = new WebSocket("ws://localhost:8080/WS1/ratesrv");       
          wsocket.onmessage = onMessage;          
      }

      function onMessage(evt) {             
         document.getElementById("rate").innerHTML=evt.data;          
      }

 window.addEventListener("load", connect, false);
  </script>
</head>
<body>

<table>
<tr>
<td> <label id="rateLbl">Current Rate:</label></td>
<td> <label id="rate">0</label></td>
</tr>
</table>
</body>
</html>




Unleash the power of your APIs with future-proof API management - Create your account and start your free trial today, brought to you in partnership with 3scale.

Topics:
enterprise-integration ,j2ee ,websockets ,tyrus ,integration

Published at DZone with permission of Ulas Ergin. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}