First Time Java API for WebSocket

Java API for WebSocket 1.0 is one of the major developments in Java EE 7. Here is a sample code to run our first websocket chatting app.

java-api-websocket

Objectives:

  • How to build websocket app using Java API?
  • Build websocket server
  • Build websocket desktop “console” client in Java
  • Build webscoket web client using  Webscoket JS object.

Environment & Tools:

Libraries:

  • javaee-api-7.0-b82
  • tyrus-client
  • tyrus-container-grizzly

( 1 ) Websocket Server

<dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0-b82</version>
            <scope>provided</scope>
        </dependency>
  • src/main/java/com/hmkcode/MyServerEndpoint.java
package com.hmkcode;

import java.io.IOException;
import java.util.LinkedList;
import javax.websocket.EncodeException;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint(value="/websocket/{client-id}")
public class MyServerEndpoint {

    private static final LinkedList<Session> clients = new LinkedList<Session>();

    @OnOpen
    public void onOpen(Session session) {
        clients.add(session);
    }
    @OnMessage
    public void onMessage(String message,@PathParam("client-id") String clientId) {
        for (Session client : clients) {
            try {
                client.getBasicRemote().sendObject(clientId+": "+message);            

            } catch (IOException e) {
                e.printStackTrace();
            } catch (EncodeException e) {
                e.printStackTrace();
            }
        }
    }
    @OnClose
    public void onClose(Session peer) {
        clients.remove(peer);
    }
}
  • @ServerEndpoint(value=”/websocket/{client-id}”) defines the URL to the server, {client-id} is a parameter to be passed by the client. Client needs the URL connect to the server e.g. : ws://localhost:8080/websocket-glassfish-server/websocket/desktop-client. client-id = “desktop-client”
  • @onOpen: is annotating the method that will be executed when a new client connects to the server. Here we are keeping reference to the client to use later.
  • @onMessage: annotating method that will be called upon receiving a new message from a client. Here we are taking the message received and forward it to all clients.
  • @onClose: annotating the method that will be called when a the connection with a client is closed.

( 2 ) Websocket Clients (desktop and web)

Here we have two different type of clients, first one is a desktop “native” console java app and the other one is a web “HTML5/jQuery/twitter-bootstrap” client.

Desktop Java Client

We will have this client in a separate project

<dependency>
            <groupId>javax</groupId>
            <artifactId>javaee-api</artifactId>
            <version>7.0-b82</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.tyrus</groupId>
            <artifactId>tyrus-client</artifactId>
            <version>1.0-rc3</version>
        </dependency>
        <dependency>
            <groupId>org.glassfish.tyrus</groupId>
            <artifactId>tyrus-container-grizzly</artifactId>
            <version>1.0-rc3</version>
        </dependency>
  • src/main/java/com/hmkcode/MyClient.java
package com.hmkcode;

import java.io.IOException;
import javax.websocket.ClientEndpoint;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;

@ClientEndpoint
public class MyClient {
    @OnOpen
    public void onOpen(Session session) {
        System.out.println("Connected to endpoint: " + session.getBasicRemote());
        try {
            session.getBasicRemote().sendText("Hello");
        } catch (IOException ex) {
        }
    }

    @OnMessage
    public void onMessage(String message) {
        System.out.println(message);
    }

    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }
}
  • src/main/java/com/hmkcode/App.java
package com.hmkcode;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URI;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.Session;
import javax.websocket.WebSocketContainer;

public class App {

	public Session session;

    protected void start()
             {

            WebSocketContainer container = ContainerProvider.getWebSocketContainer();

            String uri = "ws://localhost:8080/websocket-glassfish-server/websocket/desktop-client";
            System.out.println("Connecting to " + uri);
            try {
				session = container.connectToServer(MyClient.class, URI.create(uri));
			} catch (DeploymentException e) {
				e.printStackTrace();
			} catch (IOException e) {
				e.printStackTrace();
			}             

    }
    public static void main(String args[]){
    	App client = new App();
    	client.start();

    	BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    	String input = "";
    	try {
    		do{
    			input = br.readLine();
    			if(!input.equals("exit"))
    				client.session.getBasicRemote().sendText(input);

    		}while(!input.equals("exit"));

		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
    }
}

Web Client

This is part of the server project, it will be under webapp folder

  • /src/main/webapp/index.htm

Just simple html structure for web client.

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">

<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Java API for WebSocket (JSR-356)</title>
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet" type="text/css" />
<script src="http://code.jquery.com/jquery-1.9.1.js"></script>
<script src="websocket.js" type="text/javascript"></script>
</head>
<body>
	<div class="container">
		<h1>Java API for WebSocket (JSR-356)</h1>
		<div>
			<span id="status" class="label label-important">Not Connected</span> 
		</div>	
		<br/>

		<label style="display:inline-block">Message: </label><input type="text" id="message"  />
		<button id="send" class="btn btn-primary" onclick="sendMessage()">Send</button>

		<table id="received_messages" class="table table-striped">
	   		<tr>
	   			<th>#</th>
	   			<th>Sender</th>
	   			<th>Message</th>
	   		</tr>
	    </table>
	</div>
</body>
</html>
  • /src/main/webapp/websocket.js

The webscoket client logic is here.

var URL = "ws://localhost:8080/websocket-glassfish-server/websocket/web-client";
var websocket;

$(document).ready(function(){
	connect();	
});

function connect(){
	 	websocket = new WebSocket(URL);
	 	websocket.onopen = function(evnt) { onOpen(evnt) };
		websocket.onmessage = function(evnt) { onMessage(evnt) };
		websocket.onerror = function(evnt) { onError(evnt) };
}
function sendMessage() {
    websocket.send($("#message").val());
}
function onOpen() {
	updateStatus("connected")
}
function onMessage(evnt) {
    if (typeof evnt.data == "string") {

    	$("#received_messages").append(
                		$('<tr/>')
                		.append($('<td/>').text("1"))
                		.append($('<td/>').text(evnt.data.substring(0,evnt.data.indexOf(":"))))
                		.append($('<td/>').text(evnt.data.substring(evnt.data.indexOf(":")+1))));
    } 
}
function onError(evnt) {
    alert('ERROR: ' + evnt.data);
}
function updateStatus(status){
	if(status == "connected"){
		$("#status").removeClass (function (index, css) {
		   return (css.match (/\blabel-\S+/g) || []).join(' ')
		});
		$("#status").text(status).addClass("label-success");
	}
}

( 3 ) Run the example

The websocket server along with websocket web client should be deployed on the GlassFish server b89. If this is your first time with GlassFish “like me” it will be a little bit long deployment process.

Deployment instructions:

  • Download GlassFish server
  • Unzip the file
  • Go to [Your-Directory]\glassfish4\glassfish\bin
  • Run the server, double click on startserv
  • Now, open the browser type: http://localhost:4848, It will take you to the admin console
  • Click “Application” from the left menu, Then “Deploy…”
  • Now, can deploy the war file or the open folder.

You need to run Maven package command to generate the deployable war file or open folder, they can be found under target folder

./websocket-glassfish-server>mvn package
  • After selecting the war file or the open folder make sure that context root and application name are “websocket-glassfish-server”

  • Click OK
  • Lunch
  • Go to http://localhost:8080/websocket-glassfish-server/index.htm

java-api-websocket

  • Run Java desktop console client App.java
  • Now you should be able to send messages from each client to the other.

Source Code @ GitHub

3 thoughts on “First Time Java API for WebSocket

  1. Red1kissi

    Hello,
    First of all, thank you for your interesting article.
    I am a beginner with WebSocket. The Websocket Java API is not very well documented till now and I find that it hard to understand how does it work.
    I started like usually with the oracle Java EE 7 tutorial but I blocked with the first example:
    EchoEndpoint

    public class EchoEndpoint extends Endpoint {
    @Override
    public void onOpen(final Session session, EndpointConfig config) {
    session.addMessageHandler(new MessageHandler.Whole() {
    @Override
    public void onMessage(String msg) {
    try {
    session.getBasicRemote().sendText(msg);
    } catch (IOException e) { ... }
    }
    });
    }
    }

    I think the way to deploy a websocket on the server is not clear. I’d like to have more documentation if you had.
    concerning your example I have this when I run the App.java :

    Connecting to ws://localhost:8080/websocket-glassfish-server/websocket/desktop-client
    javax.websocket.DeploymentException: Class javax.websocket.ClientEndpointConfig$Configurator couldn't be instantiated

    at org.glassfish.tyrus.core.ErrorCollector.composeComprehensiveException(ErrorCollector.java:83)
    at org.glassfish.tyrus.client.ClientManager.connectToServer(ClientManager.java:275)
    at org.glassfish.tyrus.client.ClientManager.connectToServer(ClientManager.java:158)
    at com.hmkcode.App.start(App.java:23)
    at com.hmkcode.App.main(App.java:34)

    Could you help me please to resolve this.
    Thanks in advance.

  2. Angel

    Same problem here:

    javax.websocket.DeploymentException: Class javax.websocket.ClientEndpointConfig$Configurator couldn’t be instantiated

    at org.glassfish.tyrus.core.ErrorCollector.composeComprehensiveException(ErrorCollector.java:83)
    at org.glassfish.tyrus.client.ClientManager.connectToServer(ClientManager.java:275)
    at org.glassfish.tyrus.client.ClientManager.connectToServer(ClientManager.java:158)
    at com.hmkcode.App.start(App.java:25)
    at com.hmkcode.App.main(App.java:35)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)

    Any suggestion?

Comments are closed.