WebSockets
The Wikipedia definitions is "WebSocket is a protocol providing full-duplex communications channels over a single TCP connection". This simple interface of TCP connection in javascript enables to push data from server to client as and when data is available instead of clients polling for it. For example if you want to tail the server logs in the browser, you can read log files, buffer logs and push log data to browser. For reading appended data to log file you can use Apache Tailer.
Server Side
1. We need to implement an Endpoint on the server side. This endpoint class will be invoked when a connection is opened or closed from the client. The endpoint class can be marked by annotation or by extending Endpoint. Following is a sample
public class SimpleEndpoint extends Endpoint {
public void onOpen(Session session, EndpointConfig endpointConfig) {
RemoteEndpoint.Basic remoteEndpointBasic = session.getBasicRemote();
//Save endpoint remoteEndpointBasic to be used later for pushing data.
}
public void onClose(Session session, CloseReason closeReason) {
super.onClose(session, closeReason);
}
public void onError(Session session, Throwable throwable) {
super.onError(session, throwable);
}
}
public class SimpleConfig implements ServerApplicationConfig {
public Set<ServerEndpointConfig> getEndpointConfigs( Set<Class<? extends Endpoint>> scanned) {
Set<ServerEndpointConfig> result = new HashSet<ServerEndpointConfig>();
if (scanned.contains(SimpleEndpoint.class)) {
//Adding SimpleEndpoint
result.add(ServerEndpointConfig.Builder.create( SimpleEndpoint.class, "/websocket").build());
}
return result;
}
public Set<Class<?>> getAnnotatedEndpointClasses(Set<Class<?>> scanned) {
Set<Class<?>> results = new HashSet<Class<?>>();
return results;
}
}
3. Data from server can be pushed using RemoteEndpoint.Basic object that we saved in step 1.
RemoteEndpoint.Basic r = getMyEndpoint();
try {
r.sendText("Your Text Data Goes Here");
}
catch(IOException e){
//discard endpoint
}
SimpleMessageHandler implements MessageHandler.Whole<String> {
SimpleMessageHandler(RemoteEndpoint.Basic remoteEndpointBasic) {
}
public void onMessage(String message) {
//I got this --> message
}
}
and register message handler with the websocket session.
public void onOpen(Session session, EndpointConfig endpointConfig) {
session.addMessageHandler(new SimpleMessageHandler(remoteEndpointBasic));
}
Client Side
1. Javascript part is made very easy. We just need to create WebSocket object using target url, as follows
var target = getTargetUrl();
var ws = null;
if ('WebSocket' in window) {
ws = new WebSocket(target);
}
else if ('MozWebSocket' in window) {
ws = new MozWebSocket(target);
}
else {
alert('WebSocket is not supported by this browser.');
return;
}
2. Callback methods can be registered.
ws.onopen = function () {
//Connection opened with server
};
ws.onmessage = function (event) {
//message received from server, message data is in
//event.data
};
ws.onclose = function (event) {
//Connection Closed with server
};
Tomcat
Tomcat 7 onward websockets are supported. Just make sure that a http based Connector is configured. An AJP connector will not do because AJP doesn't support websockets protocol. Http connector can be configured in server.xml file as follows
<Connector port="8009" address="0.0.0.0" protocol="HTTP/1.1" connectionTimeout="20000" maxPostSize="10485760" redirectPort="8443" URIEncoding="UTF-8"/>
Apache Web Server
Apache Web Server (Httpd) added support for websockets handling in 2.4 version. For supporting websocket you need to load and configure proxy modules. In the httpd.conf file load proxy modules using following configuration
LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_wstunnel_module modules/mod_proxy_wstunnel.so
<IfModule mod_proxy_ajp.c>
Include conf/my-mod_proxy.conf
</IfModule>
in my-mod_proxy.conf file configure proxy using following commands:
<Proxy /myapp/*>
Require all granted
</Proxy>
#below is to configure reverse proxy
ProxyRequests Off
#provide mapping between client url and tomcat accepted url.
ProxyPass /myapp/websocket ws://127.0.0.1:8009/myapp/websocket
Open Question
I was running tomcat on 8009 port and apache on port 80. Before using websockets my tomcat was running AJP based connector. For using websockets I changed my connector for HTTP, but now with http based connector tomcat got exposed. I found no good way to limit Tomcat Connector to Apache and posted this question on StackOverflow. But so far I have not received any satisfying answer.