Real Time Web Application with Netty-SocketIO

Web browser communications protocol is limited to the HTTP request and response paradigm – i.e. the browser requests and the server responds. For real time web application  we want to perform duplex communication – i.e. where the server sends a request and the browser responds and the vice versa. There are variety of transport options to achieve this like WebSocket, XHR polling, etc.

Socket.IO is a JavaScript library that uses a variety of transport (WebSocket, XHR polling, etc) to allow you to develop real-time web application. Socket.IO hides the underlying transport mechanism by figuring out what is the best transport to use between the browser and the server. It performs a handshake to determine this. Most Socket.IO servers are written in JavaScript running in node.js.

We can integrate a Socket.IO client to Java EE 7 using the new WebSocket API (JSR-356). It provides bi-directional, full-duplex communications channels, over a single Transmission Control Protocol (TCP) socket. In addition, because WebSockets can co-exist with other HTTP traffic over port 80 and 443, firewalls will not have to be re-configured.

Mainly there are two server side Java implementation of Socket.IO. They are Netty-SocketIO and Socket.IO-Java. Socket.IO-Java is a J2EE Servlet based Socket.IO server implementation and runs on top of Jetty leveraging its WebSocket and continuation support. Netty-SocketIO is based on Red Hat’s Netty(a non-blocking I/O (NIO) client-server framework).  It supports latest protocol of Socket.IO server.

We could get the Netty-SocketIO library here. And you could familiarize the API by just running this demo.

Lately I have integrated Netty-SocketIO into my servlet. You could find the code below. All you have to do is start your SocektServerIO in servlet init method in port 80 or 443.
HelloWorld.java – Servlet

package com.vaisakh.servlet;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import com.corundumstudio.socketio.*;
import com.corundumstudio.socketio.listener.DataListener;

@WebServlet("/HelloWorld")
public class HelloWorld extends HttpServlet {
	private static final long serialVersionUID = 1L;
	
	SocketIOServer socketIOServer = null;


	public HelloWorld() {
		super();
	}

	public void init(ServletConfig config) throws ServletException {
		Configuration configuration = new Configuration();
		configuration.setHostname("localhost");
		configuration.setPort(80);

		socketIOServer = new SocketIOServer(configuration);

		socketIOServer.addEventListener("chatevent", ChatObject.class,
				new DataListener<ChatObject>() {

					@Override
					public void onData(SocketIOClient client, ChatObject data,
							AckRequest ackRequest) throws Exception {
						socketIOServer.getBroadcastOperations().sendEvent("chatevent", data);
					}
				});

		socketIOServer.start();
	}

	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
		request.getRequestDispatcher("/WEB-INF/home.jsp").forward(request,
				response);

	}

	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
	
	}
	
	public void destroy() {
		socketIOServer.stop();
	}

}

ChatObject.java – Model class

package com.vaisakh.servlet;

public class ChatObject {
	
	private String userName;
	private String message;
	
	public ChatObject() {
		super();
	}
	public ChatObject(String userName, String message) {
		super();
		this.userName = userName;
		this.message = message;
	}
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
	public String getMessage() {
		return message;
	}
	public void setMessage(String message) {
		this.message = message;
	}
}

home.jsp – View

<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
	pageEncoding="ISO-8859-1"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>Chat App</title>
<link href="bootstrap.css" rel="stylesheet">

<style type="text/css">
body {
	padding: 20px;
}

#console {
	height: 400px;
	overflow: auto;
}

.username-msg {
	color: orange;
}

.connect-msg {
	color: green;
}

.disconnect-msg {
	color: red;
}

.send-msg {
	color: #888
}
</style>

<script type="text/javascript" src="js/socket.io/socket.io.js"></script>
<script type="text/javascript" src="js/moment.min.js"></script>
<script type="text/javascript"
	src="http://code.jquery.com/jquery-1.10.1.min.js"></script>

<script type="text/javascript">
	var userName = 'user' + Math.floor((Math.random() * 1000) + 1);

	var socket = io.connect('http://localhost:80');

	socket
			.on(
					'connect',
					function() {
						output('<span class="connect-msg">Client has connected to the server!</span>');
					});

	socket.on('chatevent', function(data) {
		output('<span class="username-msg">' + data.userName + ':</span> '
				+ data.message);
	});

	socket.on('disconnect', function() {
		output('<span class="disconnect-msg">The Client(' + userName
				+ ') has disconnected!</span>');
	});

	function sendDisconnect() {
		socket.disconnect();
	}

	function sendMessage() {
		var message = $('#msg').val();
		$('#msg').val(' ');

		var jsonObject = {
			userName : userName,
			message : message
		};

		socket.emit('chatevent', jsonObject);
	}

	function output(message) {
		var currentTime = "<span class='time'>"
				+ moment().format('HH:mm:ss.SSS') + "</span>";
		var element = $("<div>" + currentTime + " " + message + "</div>");
		$('#console').prepend(element);
	}
</script>
</head>
<body>

	<h1>My Chat App</h1>
	<br />

	<div id="console" class="well"></div>

	<form class="well form-inline" onsubmit="return false;">
		<input id="msg" class="input-xlarge" type="text"/>
		<button type="button" onClick="sendMessage()" class="btn">Send</button>
		<button type="button" onClick="sendDisconnect()" class="btn">Disconnect</button>
	</form>
</body>
</html>

You need to add Netty-SocketIO library to class path. Also the javascript libraries refereed in the view