This exercise will help you to understand Java Web Sockets API and write a sample client server code to create , connect to and send full duplex messages to a Web Socket .
Pre requisites for this java exercise :
1. Install Oracle Weblogic Server 12.1.3 only since this exercise has been done with WLS 12.1.3. Do not try this exercise with Oracle WLS 12.1.2 since the API's are only supported for 12.1.3.2. Create a domain on the WLS and a managed_server to deploy the Web Socket web application.
3. Your admin server , managed server should be up and running .
If the above are not done , go back and do the needful .
Let's briefly understand Web Sockets
Understanding the WebSocket Protocol
WebSocket is an application protocol that provides simultaneous two-way communication over a single TCP connection between a client and a server. The WebSocket protocol enables the client and the server to send data independently. The WebSocket Protocol is supported by most browsers. A browser that supports the WebSocket protocol provides a JavaScript API to connect to endpoints, send messages, and assign callback methods for WebSocket events (such as opened connections, received messages, and closed connections).
For general information about the WebSocket Protocol, see this .
Why WebSocket ???
Obviously this question why go for WebSocket when the request-response model of HTTP is available . Let's see below .In the traditional request-response model used in HTTP, the client requests resources and the server provides responses. The exchange is always initiated by the client; the server cannot send any data without the client requesting it first. This model worked well for the World Wide Web when clients made occasional requests for documents that changed infrequently, but the limitations of this approach are increasingly apparent as content changes quickly and users expect a more interactive experience on the web.
The WebSocket protocol addresses these limitations by providing a full-duplex communication channel between the client and the server. Combined with other client technologies, such as JavaScript and HTML5, WebSocket enables web applications to deliver a richer user experience.
Let's Begin Hands On :
Now I won't waste much of your time in theory and since this is a crash course let's quickly move on to some coding . I will be using WebLogic Server WebSocket implementation in this tutorial and will be explaining the parts of code in place .
There are three parts of this exercise (I) write a WebSocket server application , (ii) write a javascript WebSocket client to connect to (I) and (iii) write a Java WebSocket client to connect to (I) .
WebSocket Server code
Create a dynamic Web Project in Eclipse and give it a nice name e.g. wsServer , create a package WebSocket .server and add a class to the package Serverex1.java . I will be explaining this piece of code in comments section.
Required : javax.websocket-api-1.1.jar , can be downloaded and be placed in lib directory in WEB_INF of your project or provided as a maven dependency in your pom.xml. Click here .
package websocket.server;
import java.io.IOException;import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import javax.websocket.CloseReason;
import javax.websocket.EndpointConfig;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;
// Create an Annotated Endpoint , mark the annotation ServerEndPoint ; Creating an
// annotated endpoint enables you to handle life cycle events for a WebSocket connection
// by annotating methods of the endpoint class. An annotated endpoint is deployed
// automatically with the application.This annotation denotes that the class represents
// a WebSocket server endpoint. Set the value element of the ServerEndpoint annotation to
// the relative path to which the endpoint is to be deployed. The path must begin with a
// forward slash (/) .
@ServerEndpoint("/echo")
public class Serverex1 {// queue holds all the sessions connected to this WebSocket . A
Session
object represents a // conversation between a pair of WebSocket endpoints .
private static Queue<Session> queue = new ConcurrentLinkedQueue<Session>();
// this static block runs a new Thread and send a message to all the clients connected to this
// WebSocket .
static {
new Thread(new Runnable() {public void run() {
DecimalFormat df = new DecimalFormat("#.####");
while (true) {
double d = 2 + Math.random();
if (queue != null) {
sendAll("USD Rate : " + df.format(d));
}
try {Thread.currentThread().sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void sendAll(String string) {
ArrayList<Session> closedSessions = new ArrayList<>();for (Session session : queue) {
if (!session.isOpen()) {
System.out.println("Session " + session.getId()
+ " is closed");
closedSessions.add(session);
} else {
try {
Session
parameter represents a conversation between this // endpoint and the remote endpoint and the
getBasicRemote
// method returns an object that represents the remote
// endpoint.
session.getBasicRemote().sendText(string);
} catch (IOException e) {e.printStackTrace();
}
}
queue.removeAll(closedSessions);System.out.println("Sending Message " + string
+ " to " + queue.size() + " clients");
}}
}).start();
}
public Serverex1() {}
// Annotate the method with OnMessage to denote the lifecycle method
// in a WebSocket endpoint; the OnMessage method can take three
// types of message type text , binary and pong (pong is a response
// message frame for ping)
@OnMessage
public void message(Session session, String str) {
try {
// When a remote client , the ClientEndPoint will send a
// message to this WebSocket , this method will be invoked
// upon the receival of message the following logic will be
// invoked , here the same text is sent back to the
// clientEndPoint and also to each of the opent
// ClientEndPoints
// upon the receival of message the following logic will be
// invoked , here the same text is sent back to the
// clientEndPoint and also to each of the opent
// ClientEndPoints
session.getBasicRemote().sendText(str);
for (Session sess : session.getOpenSessions()) {sess.getBasicRemote().sendText(str);
}
} catch (Exception ex) {
ex.printStackTrace();
}
System.out.println("Received Message " + str + " from Client ");
}
// To handle a connection opened event, annotate the method for handling the event with the
//
OnOpen
annotation.
@OnOpen
public void open(Session session, EndpointConfig config) {queue.add(session);
System.out.println("New Session Opened " + session.getId());
System.out.println(config.getClass());
}
// You need handle a connection closed event only if you require
// some special processing before the connection is closed, for// example, retrieving session attributes such as the ID, or any
// application data that the session holds before the data becomes
// unavailable after the connection is closed.To handle a connection
// closed event, annotate the method for handling the event with the
//
OnClose
annotation.
@OnClose
public void close(Session session, CloseReason reason) {queue.remove(session);
System.out.println("Session closed " + session.getId());
System.out.println(reason.getReasonPhrase());
}
// You need handle only error events that are not modeled in the
// WebSocket protocol, for example:
- // Connection problems
- // Runtime errors from message handlers
- // Conversion errors in the decoding of messages
// event with the
OnError
annotation.
@OnError
public void error(Session session, Throwable t) {queue.remove(session);
System.out.println("Error on session " + session.getId());
}
}// Create a war out of the above class file , do not include a deployment descriptor .xml file since the
// annotations will take care of everything . Deploy the war as a web application on weblogic
// managed server , I am doing it on my WLS server managed_server-1 at port 7002 . Once the war is
// deployed , you are ready to write clients to connect to this WebSocket.
JavaScript WebSocket Client
A browser-based WebSocket client application is typically a composite of HTML5 technologies, including HTML markup, CSS3, and JavaScript that makes use of the WebSocket JavaScript API. Most browsers support the W3C WebSocket API that can be used to create and work with the WebSocket protocol.
This API provides an implementation of the standard W3C WebSocket API. The API also provides a mechanism for using an alternative transport for WebSocket messaging when the WebSocket protocol is not supported
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>WebSocket Client</title>
<script type="text/javascript">
var wsocket;
function connect() {
<!-- The client opens a WebSocket connection to the-->
<!-- server hosting the WebSocket endpoint, using the-->
<!-- ws: // or ws:/// protocol -->
wsocket =
new WebSocket("ws://localhost:7002/wsserver/echo");
wsocket.onmessage = onMessage;
}
<!--The client registers listeners with the WebSocket -->
<!--object to respond to events, such as opening, -->
<!--closing and receiving messages. Based on the event -->
<!-- and the information received, the client performs -->
<!-- appropriate action. -->
function onMessage(evt) {
document.getElementById("rate").innerHTML = evt.data;
}
<!-- The client sends messages to the server over the-->
<!--WebSocket object as needed by the application.-->
function sendMsg() {
<!--Check if connection is open before sending-->
if (wsocket == null || wsocket.readyState != 1) {
document.getElementById("reason").innerHTML =
"Not connected can't send msg"
} else {
wsocket.send(document.getElementById("name").value);
}
}
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>
Enter text to send to Server
<input type="text" id="name"/>
<input id="send_button" class="button" type="button" value="send" onclick="sendMsg()" />
</body>
</html>
Java WebSocket client
The javax.websocket package contains annotations, classes, interfaces, and exceptions that are common to client and server endpoints. Use the APIs in this package for writing a Java WebSocket client in the same way as for writing a server.
To Connecting a Java WebSocket Client to a Server Endpoint
Let's see how to do this in CodeCreate a Java Project in Eclipse and give it a name e.g. wsClient , create a package webSocket.client and add a class to the package Clientex1.java .
package websocket.client;
import java.io.IOException;
import java.net.URI;
import javax.websocket.ClientEndpoint;
import javax.websocket.ClientEndpointConfig;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.OnMessage;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;
// This annotation denotes that the class represents a WebSocket client endpoint.
@ClientEndpoint
public class Clientex1 {
private static Object waitLock = new Object();
@OnMessage
public void onMessage(String string) {
System.out.println("Received Message " + string);
}
public static void main(String[] args) {
WebSocketContainer wsc = null;
Session session = null;
// 1.Invoke the
// javax.websocket.ContainerProvider.getWebSocketContainer()
// static method to obtain the client's
// javax.websocket.WebSocketContainer
// instance.
wsc = ContainerProvider.getWebSocketContainer();
try {
// 2.Invoke the overloaded connectToServer method on the
// WebSocketContainer object that you obtained in the
// previous step.In the invocation of the connectToServer
// method, provide the following information as params
// to the method:
◦// The client WebSocket endpoint
◦// The complete path to the server WebSocket
// endpoint
session = wsc.connectToServer(Clientex1.class,
URI.create("ws://localhost:7002/wsserver/echo"));
session.getBasicRemote().sendText("SENT THIS MESSAGE");
} catch (DeploymentException | IOException e) {
e.printStackTrace();
} finally {
if (session != null) {
try {
session.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Sample Output :
Server logs while calling from index.html
New Session Opened e81cb8ee-ced5-4d59-970a-d4d554a50541
class javax.websocket.server.DefaultServerEndpointConfig
Sending Message USD Rate : 2.0751 to 1 clients
Sending Message USD Rate : 2.9263 to 1 clients
Sending Message USD Rate : 2.303 to 1 clients
Output on .html
Current Rate:
USD Rate : 2.3716
Output of java Client
Received Message SENT THIS MESSAGE
Received Message SENT THIS MESSAGE
Received Message USD Rate : 2.4786
Output on Server Logs :
New Session Opened fc560861-cebc-4499-839b-0f4d41a9bf6b
class javax.websocket.server.DefaultServerEndpointConfig
Received Message SENT THIS MESSAGE from Client
Sending Message USD Rate : 2.4786 to 2 clients
Sending Message USD Rate : 2.4786 to 2 clients
Sending Message USD Rate : 2.2093 to 2 clients
Hope You enjoyed it and learned something new today .
Happy Coding
Wow. Great read it was
ReplyDelete