iXora Custom Software Development Blog

Read | Practice | Advance

WebSocket Programming

Posted by on in Blog
  • Font size: Larger Smaller
  • Hits: 296
  • 0 Comments
  • Print

What Is WebSocket?

  • WebSocket is an advanced technology that makes it possible to open an interactive communication session between the user's browser and a server. With this API, you can send messages to a server and receive event-driven responses without having to poll the server for a reply. 
  • WebSocket is a different TCP protocol from HTTP.
  • Both protocols are located at layer 7 in the OSI model and, as such, depend on TCP at layer 4.

How WebSocket Works?

b2ap3_thumbnail_Screenshot_1.png

 

When WebSocket Used?

  • Real-time applications
  • Chat apps
  • IoT (Internet of Things)
  • Online multiplayer games

When we should avoid using WebSockets?

Don’t think you will need a real-time app if you are building a simple CMS, unless you want some kind of a specific real-time feature. For a RESTful-API I would advise not using Web Sockets as HTTP GET, POST, DELETE, PUT and many other requests are awesome for that.

Browser Supports

b2ap3_thumbnail_Screenshot_2.png

 

Lets do some real life example with Java

Steps:

  1. Create a Dynamic Web Project. In Eclipse Go File>New>Other and choose "Dynamic Web Project" under Web.
  2. Add files shown in the following image. Content of each of the file will be discussed later.b2ap3_thumbnail_Project_Structure.png

Task.java

package com.ixora.model;

public class Task {
	private int id;
    private String name;
    private String status;
    

    public Task() {
    }
    
    public int getId() {
        return id;
    }
    
    public String getName() {
        return name;
    }

    public String getStatus() {
        return status;
    }
   
    public void setId(int id) {
        this.id = id;
    }
    
    public void setName(String name) {
        this.name = name;
    }

    public void setStatus(String status) {
        this.status = status;
    }
   
}

 TaskSessionHandler.java

package com.ixora.websocket;

import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.json.JsonObject;
import javax.json.spi.JsonProvider;
import javax.websocket.Session;

import com.ixora.model.Task;

@ApplicationScoped
public class TaskSessionHandler {
	private int taskId = 0;
	private final Set<Session> sessions = new HashSet<>();
	private final Set<Task> tasks = new HashSet<>();

	public void addSession(Session session) {
		sessions.add(session);
		for (Task task : tasks) {
			JsonObject addMessage = createAddMessage(task);
			sendToSession(session, addMessage);
		}
	}

	public void removeSession(Session session) {
		sessions.remove(session);
	}

	public List<Task> getTasks() {
		return new ArrayList<>(tasks);
	}

	public void addTask(Task task) {
		task.setId(taskId);
		tasks.add(task);
		taskId++;
		JsonObject addMessage = createAddMessage(task);
		sendToAllConnectedSessions(addMessage);
	}

	public void removeTask(int id) {
		Task task = getTaskById(id);
		if (task != null) {
			tasks.remove(task);
			JsonProvider provider = JsonProvider.provider();
			JsonObject removeMessage = provider.createObjectBuilder().add("action", "remove").add("id", id).build();
			sendToAllConnectedSessions(removeMessage);
		}
	}

	public void toggleDevice(int id) {
		JsonProvider provider = JsonProvider.provider();
		Task task = getTaskById(id);
		if (task != null) {
			if ("Open".equals(task.getStatus())) {
				task.setStatus("Close");
			} else {
				task.setStatus("Open");
			}
			JsonObject updateDevMessage = provider.createObjectBuilder().add("action", "toggle")
					.add("id", task.getId()).add("status", task.getStatus()).build();
			sendToAllConnectedSessions(updateDevMessage);
		}
	}

	private Task getTaskById(int id) {
		for (Task task : tasks) {
			if (task.getId() == id) {
				return task;
			}
		}
		return null;
	}

	private JsonObject createAddMessage(Task task) {
		JsonProvider provider = JsonProvider.provider();
		JsonObject addMessage = provider.createObjectBuilder().add("action", "add").add("id", task.getId())
				.add("name", task.getName()).add("status", task.getStatus()).build();
		return addMessage;
	}

	private void sendToAllConnectedSessions(JsonObject message) {
		for (Session session : sessions) {
			sendToSession(session, message);
		}
	}

	private void sendToSession(Session session, JsonObject message) {
		try {
			session.getBasicRemote().sendText(message.toString());
		} catch (IOException ex) {
			sessions.remove(session);
			Logger.getLogger(TaskSessionHandler.class.getName()).log(Level.SEVERE, null, ex);
		}
	}
}

 

TaskWebSocketServer.java

package com.ixora.websocket;

import java.io.StringReader;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.json.Json;
import javax.json.JsonObject;
import javax.json.JsonReader;
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;

import com.ixora.model.Task;

@ApplicationScoped
@ServerEndpoint("/actions")
public class TaskWebSocketServer {

	@Inject
	private TaskSessionHandler sessionHandler;

	@OnOpen
	public void open(Session session) {
		sessionHandler.addSession(session);
	}

	@OnClose
	public void close(Session session) {
		sessionHandler.removeSession(session);
	}

	@OnError
	public void onError(Throwable error) {
		Logger.getLogger(TaskWebSocketServer.class.getName()).log(Level.SEVERE, null, error);
	}

	@OnMessage
	public void handleMessage(String message, Session session) {
		try (JsonReader reader = Json.createReader(new StringReader(message))) {
			JsonObject jsonMessage = reader.readObject();

			if ("add".equals(jsonMessage.getString("action"))) {
				Task task = new Task();
				task.setName(jsonMessage.getString("name"));				
				task.setStatus("Open");
				sessionHandler.addTask(task);
			}

			if ("remove".equals(jsonMessage.getString("action"))) {
				int id = (int) jsonMessage.getInt("id");
				sessionHandler.removeTask(id);
			}

			if ("toggle".equals(jsonMessage.getString("action"))) {
				int id = (int) jsonMessage.getInt("id");
				sessionHandler.toggleDevice(id);
			}
		}
	}
}

index.html

<!DOCTYPE html>
<html>
    <head>
        <title></title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script src="/websocket.js"></script>
        <link rel="stylesheet" type="text/css" href="/style.css">
    </head>
    <body>

        <div id="wrapper">
            <h1>Java Websocket</h1>
            <p>Click the Add a task button to start adding Tasks.</p>
            <br />
            <div id="addTask">
                <div class="button"> <a href="#" OnClick="showForm()">Add a task</a> </div>
                <form id="addTaskForm">
                    <h3>Add a new task</h3>
                    <span>Name: <input type="text" name="task_name" id="task_name"></span>
                    <input type="button" class="button" value="Add" onclick=formSubmit()>
                    <input type="reset" class="button" value="Cancel" onclick=hideForm()>
                </form>
            </div>
            <br />
            <h3>Currently showing tasks:</h3>
            <div id="content">
            </div>
        </div>
    </body>
</html>

 

style.css

body {
    font-family: Arial, Helvetica, sans-serif;
    font-size: 80%;
    background-color: #1f1f1f;
}

#wrapper {
    width: 960px;
    margin: auto;
    text-align: left;
    color: #d9d9d9;
}

p {
    text-align: left;
}

.button {
    display: inline;
    color: #fff;
    background-color: #f2791d;
    padding: 8px;
    margin: auto;
    border-radius: 8px;
    -moz-border-radius: 8px;
    -webkit-border-radius: 8px;
    box-shadow: none;
    border: none;
}

.button:hover {
    background-color: #ffb15e;
}
.button a, a:visited, a:hover, a:active {
    color: #fff;
    text-decoration: none;
}

#addTask {
    text-align: center;
    width: 960px;
    margin: auto;
    margin-bottom: 10px;
}

#addTaskForm {
    text-align: left;
    width: 400px;
    margin: auto;
    padding: 10px;
}

#addTaskForm span {
    display: block;
}

#content {
    margin: auto;
    width: 960px;
}

.task {
    padding-right: 10px;
    display: inline-block;
}

.task.open {
    text-decoration: none;
}

.task.close {    
    text-decoration: line-through;
}

.task span {
    display: block;
}

.taskName {
    text-align: center;
    font-weight: bold;
    margin-bottom: 12px;
}

.removeTask {
    margin-top: 12px;
    text-align: center;
}

.task a {
    text-decoration: none;
}

.task a:visited, a:active, a:hover {
    color: #fff;
}

.task a:hover {
    text-decoration: underline;
}

 

websocket.js

window.onload = init;
var socket = new WebSocket("ws://localhost:8080/WebSocket/actions");
socket.onmessage = onMessage;

function onMessage(event) {
	var task = JSON.parse(event.data);
	if (task.action === "add") {
		printTaskElement(task);
	}
	if (task.action === "remove") {
		document.getElementById(task.id).remove();
	}
	if (task.action === "toggle") {
		var node = document.getElementById(task.id);
		var nameText = node.children[0];
		var statusText = node.children[1];
		if (task.status === "Open") {
			nameText.setAttribute("class", "task open");
			statusText.innerHTML = "(<a href=\"#\" OnClick=toggleTask(" + task.id
			+ ")>Close</a>)";
		} else if (task.status === "Close") {
			nameText.setAttribute("class", "task close");
			statusText.innerHTML = " (<a href=\"#\" OnClick=toggleTask(" + task.id
			+ ")>Open</a>)";
		}	

	}
}

function addTask(name) {
	var taskAction = {
		action : "add",
		name : name
	};
	socket.send(JSON.stringify(taskAction));
}

function removeTask(element) {
	var id = element;
	var taskAction = {
		action : "remove",
		id : id
	};
	socket.send(JSON.stringify(taskAction));
}

function toggleTask(element) {
	var id = element;
	var taskAction = {
		action : "toggle",
		id : id
	};
	socket.send(JSON.stringify(taskAction));
}

function printTaskElement(task) {
	var content = document.getElementById("content");

	var taskDiv = document.createElement("div");
	taskDiv.setAttribute("id", task.id);
	content.appendChild(taskDiv);

	var taskName = document.createElement("span");	
	taskName.innerHTML = task.name;	

	var taskStatus = document.createElement("span");
	if (task.status === "Open") {
		taskName.setAttribute("class", "task open");
		taskStatus.innerHTML = "(<a href=\"#\" OnClick=toggleTask(" + task.id
				+ ")>Close</a>)";
	} else if (task.status === "Close") {
		taskName.setAttribute("class", "task close");
		taskStatus.innerHTML = " (<a href=\"#\" OnClick=toggleTask(" + task.id
				+ ")>Open</a>)";
	}
	
	taskDiv.appendChild(taskName);
	taskDiv.appendChild(taskStatus);

	var removeTask = document.createElement("span");
	removeTask.setAttribute("class", "removeTask");
	removeTask.innerHTML = "<a href=\"#\" OnClick=removeTask(" + task.id
			+ ")>Remove task</a>";
	taskDiv.appendChild(removeTask);
}

function showForm() {
	document.getElementById("addTaskForm").style.display = '';
}

function hideForm() {
	document.getElementById("addTaskForm").style.display = "none";
}

function formSubmit() {
	var form = document.getElementById("addTaskForm");
	var name = form.elements["task_name"].value;
	hideForm();
	document.getElementById("addTaskForm").reset();
	addTask(name);
}

function init() {
	hideForm();
}

 

I have used Glass Fish Server to run this application. After running the application into the server the out put will be as below.

Screenshot_1_20180527-092627_1.png

You can open multiple browser window to see the effect when task status(close/open) is changed or task is removed.

Rate this blog entry:
0

Mohammad Shafiqul Islam has not set their biography yet

Author's recent posts

Comments

  • No comments made yet. Be the first to submit a comment

Leave your comment

Guest
Guest Sunday, 21 October 2018