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.
Join the DZone community and get the full member experience.
Join For FreeJava-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.
- 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. - 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/ - 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)
- 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>
Published at DZone with permission of Ulas Ergin. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments