In Java EE 7, the Java package javax.websocket
is the root for WebSockets. There is one package underneath this one for server endpoints: javax.websocket.server
.
The server-side endpoint in Java represents one end of the peers. Java applications with WebSocket endpoints are created through programming directly against the library. Otherwise, the endpoints are determined by annotations in the JSR 356 specification.
The annotation javax.websocket.server.ServerEndpoint
is applied to classes that execute an endpoint on the server. The annotation requires a URL pattern fragment similar to the Servlet 3.1 annotation @javax.servlet.WebServlet
, which determines how the implementation provider routes an incoming WebSockets request to the endpoint.
We can annotate a POJO so that it will be registered as a server-side WebSocket endpoint, but how can we receive messages from the client? The answer is annotation: @javax.websocket.OnMessage
. This annotation declares a particular method to receive messages that arrive on the WebSocket connection.
Let's take a look at a simple echo server example:
package je7hb.websocket.basic; import javax.websocket.OnMessage; import javax.websocket.server.ServerEndpoint; @ServerEndpoint("/echo") public class EchoWebSocketServer { @OnMessage public String doListen(String message) { return "Echo: Got your message (" + message + "). Thanks"; } }
This is, perhaps, the simplest Java WebSocket server that one can write. The @ServerEndpoint
annotation declares the class EchoWebSocketServer
as a server-side endpoint in that it is capable of receiving connection requests from clients. The URL pattern "/echo"
declares how the WebSocket implementation routes the request to the endpoint.
The method doListen()
is annotated with @OnMessage
and declares to the implementation what method to invoke when a message has been received on the connection. Note that the return type of the method doListen()
is String
. It is possible to return a message to the client directly, which is of course exactly the function of the method.
Let's look at the annotations in detail; here is the table of attributes for the annotations for @javax.websocket.server.ServerEndpoint
:
Here is the table of attributes for the @javax.websocket.OnMessage
:
Attribute |
Type |
Description |
Default Value |
---|---|---|---|
|
|
Specifies the maximum size in bytes for the incoming message. |
None |
There is only one attribute allowed. The maxMessageType
attribute sets the maximum size of the message following the successful completion of the initial handshake.
We can define a Java WebSocket endpoint on the server side. There would be no point in defining the WebSocket unless there was a way of calling it. We only require a simple HTML5 and JavaScript web page to do this. WebSockets are supported by most of the modern web browsers: Mozilla Firefox, Google Chrome, Apple Safari, and Microsoft Internet Explorer.
The page that invokes the EchoWebSocketServer
looks like the following:
<!DOCTYPE html> <head> <meta charset="utf-8"/> <title>Echo Server Side WebSocket Test</title> <script language="javascript" type="text/javascript"> var wsUri = "ws://localhost:8080/mywebapp/echo"; var output; function init() { output = document.getElementById("output"); testWebSocket(); } function testWebSocket() { websocket = new WebSocket(wsUri); websocket.onopen = function (evt) { onOpen(evt) }; websocket.onclose = function (evt) { onClose(evt) }; websocket.onmessage = function (evt) { onMessage(evt) }; websocket.onerror = function (evt) { onError(evt) }; } function onOpen(evt) { writeToScreen("CONNECTED"); doSend("HTML5 Java WebSockets Rocks!"); } function onClose(evt) { writeToScreen("DISCONNECTED"); } function onMessage(evt) { writeToScreen('<span style="color: blue;">RESPONSE:' + evt.data + '</span>'), websocket.close(); } function onError(evt) { writeToScreen('<span style="color: red;">ERROR:</span>' + evt.data); } function doSend(message) { writeToScreen("SENT: " + message); websocket.send(message); } 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> <head> <body> <h2>WebSocket Test</h2> <div id="output"></div> </body> </html>
This is mostly an adaption of the code that exists on the HTML5 community website: http://websocket.org/. It is about as simple as it can get for a Hello World example for WebSockets.
The page is mostly JavaScript. There is one h2
header and a div
layer element with an id
of "output". An event handler init()
is registered on the page, as soon as it is loaded with the browser. The first action of the function init()
finds the output
div layer in the Document Object Model. The second invokes the testWebSocket()
function.
The function testWebSocket()
creates a WebSocket
and then registers callback functions on it on various events. On the JavaScript side, one listens for when the web sockets are opened or closed, or when a message is received, and if there is an error on the channel.
The function onOpen()
is a callback function in JavaScript, which is invoked when the WebSocket successfully makes a connection to the remote endpoint, which is in our case the EchoWebSocketServer
. The function sends a message down the channel to the server by calling the helper function doSend()
.
Upon reception of the message on the WebSocket, the JavaScript function onMessage()
is invoked. This function appends a new text element with the message to the output div layer by calling the helper function writeToScreen()
.
The code that deploys the WebSocket is exactly the same as the EmbeddedRunner
in the Servlet chapter. The only difference is the name of the WAR file. We use an embedded GlassFish server instance and deploy a WAR file to it with the WebSockets endpoint. The open source project
Tyrus (on Java .Nethttps://java.net/projects/tyrus) is the reference implementation of the Java WebSockets specification inside the GlassFish project. Tyrus is responsible for creating WebSocket endpoints by scanning the WAR file for the appropriate @ServerEndpoint
annotations. Once it finds them, the implementation validates the class and then generates configuration around each endpoint, which intercepts the URI template, and then activates the WebSocket for service.
3.22.74.160