WebSocket and Java EE 7 - Getting Ready for JSR 356 (TOTD #181)
Posted
by arungupta
on Oracle Blogs
See other posts from Oracle Blogs
or by arungupta
Published on Mon, 18 Jun 2012 23:51:42 +0000
Indexed on
2012/06/19
3:20 UTC
Read the original article
Hit count: 744
/General
WebSocket is developed as part of HTML 5 specification and provides a bi-directional, full-duplex communication channel over a single TCP socket. It provides dramatic improvement over the traditional approaches of Polling, Long-Polling, and Streaming for two-way communication. There is no latency from establishing new TCP connections for each HTTP message.
There is a WebSocket API and the WebSocket Protocol. The Protocol defines "handshake" and "framing". The handshake defines how a normal HTTP connection can be upgraded to a WebSocket connection. The framing defines wire format of the message. The design philosophy is to keep the framing minimum to avoid the overhead. Both text and binary data can be sent using the API.
WebSocket may look like a competing technology to Server-Sent Events (SSE), but they are not. Here are the key differences:
- WebSocket can send and receive data from a client. A typical
example of WebSocket is a two-player game or a chat application.
Server-Sent Events can only push data data to the client. A
typical example of SSE is stock ticker or news feed. With SSE,
XMLHttpRequest can be used to send data to the server.
- For server-only updates, WebSockets has an extra overhead and programming can be unecessarily complex. SSE provides a simple and easy-to-use model that is much better suited.
- SSEs are sent over traditional HTTP and so no modification is required on the server-side. WebSocket require servers that understand the protocol.
- SSE have several features that are missing from WebSocket such as automatic reconnection, event IDs, and the ability to send arbitrary events.
- The client automatically tries to reconnect if the
connection is closed. The default wait before trying to
reconnect is 3 seconds and can be configured by including
"retry: XXXX\n" header where XXXX is the milliseconds to wait
before trying to reconnect.
- Event stream can include a unique event identifier. This allows the server to determine which events need to be fired to each client in case the connection is dropped in between.
- The data can span multiple lines and can be of any text
format as long as EventSource message handler can process it.
- WebSockets provide true real-time updates, SSE can be
configured to provide close to real-time by setting appropriate
timeouts.
websocket-sdk and GlassFish 4.0 is here to help!
The complete source code shown in this project can be downloaded here.
On the server-side, the WebSocket SDK converts a POJO into a WebSocket endpoint using simple annotations. Here is how a WebSocket endpoint will look like:
@WebSocket(path="/echo")In this code
public class EchoBean {
@WebSocketMessage
public String echo(String message) {
return message + " (from your server)";
}
}
- "@WebSocket" is a class-level annotation that declares a POJO to accept WebSocket messages. The path at which the messages are accepted is specified in this annotation.
- "@WebSocketMessage" indicates the Java method that is invoked
when the endpoint receives a message. This method implementation
echoes the received message concatenated with an additional
string.
The client-side HTML page looks like
<div style="text-align: center;">
<form action="">
<input onclick="send_echo()" value="Press me" type="button">
<input id="textID" name="message" value="Hello WebSocket!" type="text"><br>
</form>
</div>
<div id="output"></div>
WebSocket allows a full-duplex communication. So the client, a browser in this case, can send a message to a server, a WebSocket endpoint in this case. And the server can send a message to the client at the same time. This is unlike HTTP which follows a "request" followed by a "response". In this code, the "send_echo" method in the JavaScript is invoked on the button click. There is also a <div> placeholder to display the response from the WebSocket endpoint.
The JavaScript looks like:
<script language="javascript" type="text/javascript">
var wsUri = "ws://localhost:8080/websockets/echo";
var websocket = new WebSocket(wsUri);
websocket.onopen = function(evt) { onOpen(evt) };
websocket.onmessage = function(evt) { onMessage(evt) };
websocket.onerror = function(evt) { onError(evt) };
function init() {
output = document.getElementById("output");
}
function send_echo() {
websocket.send(textID.value);
writeToScreen("SENT: " + textID.value);
}
function onOpen(evt) {
writeToScreen("CONNECTED");
}
function onMessage(evt) {
writeToScreen("RECEIVED: " + evt.data);
}
function onError(evt) {
writeToScreen('<span style="color: red;">ERROR:</span> ' + evt.data);
}
function writeToScreen(message) {
var pre = document.createElement("p");
pre.style.wordWrap = "break-word";
pre.innerHTML = message;
output.appendChild(pre);
}
window.addEventListener("load", init, false);
</script>
In this code
- The URI to connect to on the server side is of the format
ws://<HOST>:<PORT>/websockets/<PATH>
"ws" is a new URI scheme introduced by the WebSocket protocol. <PATH> is the path on the endpoint where the WebSocket messages are accepted. In our case, it is
ws://localhost:8080/websockets/echo
WEBSOCKET_SDK-1 will ensure that context root is included in the URI as well.
- WebSocket is created as a global object so that the connection
is created only once. This object establishes a connection with
the given host, port and the path at which the endpoint is
listening.
- The WebSocket API
defines several callbacks that can be registered on specific
events. The "onopen", "onmessage", and "onerror" callbacks are
registered in this case. The callbacks print a message on the
browser indicating which one is called and additionally also
prints the data sent/received.
- On the button click, the WebSocket object is used to transmit
text data to the endpoint. Binary data can be sent as one blob
or using buffering.
GET ws://localhost:8080/websockets/echo HTTP/1.1
Origin: http://localhost:8080
Connection: Upgrade
Sec-WebSocket-Extensions: x-webkit-deflate-frame
Host: localhost:8080
Sec-WebSocket-Key: mDbnYkAUi0b5Rnal9/cMvQ==
Upgrade: websocket
Sec-WebSocket-Version: 13
And the response headers received are
Connection:Upgrade
Sec-WebSocket-Accept:q4nmgFl/lEtU2ocyKZ64dtQvx10=
Upgrade:websocket
(Challenge Response):00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
The headers are shown in Chrome as shown below:
The complete source code shown in this project can be downloaded here.
The builds from websocket-sdk
are integrated in GlassFish 4.0 builds. Would you like to live on
the bleeding edge ? Then follow the instructions below to check
out the workspace and install the latest SDK:
- Check out the source code
svn checkout https://svn.java.net/svn/websocket-sdk~source-code-repository - Build and install the trunk in your local repository as:
mvn install
- Copy
"./bundles/websocket-osgi/target/websocket-osgi-0.3-SNAPSHOT.jar"
to "glassfish3/glassfish/modules/websocket-osgi.jar" in your GlassFish
4 latest promoted build. Notice, you need to overwrite the
JAR file.
This work will also feed into JSR 356 - Java API for WebSocket.
On a lighter side, there seems to be less agreement on the name. Here are some of the options that are prevalent:
- WebSocket (W3C API, the URL is www.w3.org/TR/websockets
though)
- Web Socket (HTML5 Demos - html5demos.com/web-socket)
- Websocket (Jenkins Plugin - wiki.jenkins-ci.org/display/JENKINS/Websocket%2BPlugin)
- WebSockets (Used by Mozilla - developer.mozilla.org/en/WebSockets,
but use WebSocket as well)
- Web sockets (HTML5 Working Group - www.whatwg.org/specs/web-apps/current-work/multipage/network.html)
- Web Sockets (Chrome Blog - blog.chromium.org/2009/12/web-sockets-now-available-in-google.html)
© Oracle Blogs or respective owner