Java EE 7 WebSocket example

1. Createa a Java EE Web application called MyWebSocket for example.
2. In index.html:

<!DOCTYPE html>
<html>
    <head>
        <title>Start Page</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <script language="javascript">
            var ws;
            function connect() {
                ws = new WebSocket("ws://localhost:8080/MyWebSocket/sockOne");
                ws.onmessage = onMessage;
            }
            function onMessage(evt) {
                var dataarr = evt.data;
                document.getElementById("valueElement").innerHTML = dataarr;
            }
            window.addEventListener("load", connect, false);
        </script>
    </head>
    <body>
        <h1>Hello World!</h1>
        <b>Value: </b>
        <b id="valueElement">no data yet</b>
    </body>
</html>

2. Create a class Called WebSocketEndpoint. Here the most important annotations are @ServerEndpoint, @OnOpen, @OnClose and @OnError, in these methods you put whatever you want to get executed when these events happen:

package com.vvirlan.websocket;

import java.io.IOException;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

/**
 *
 * @author vvirlan
 */
@ServerEndpoint("/sockOne")
public class WebSocketEndpoint {

    private static final Logger LOGGER = Logger.getLogger("WebSocketEndpoint");
    private static Queue<Session> sessionQueue = new ConcurrentLinkedQueue<>();

    public static void send(double number) {
        String toSend = String.format("%f", number);
        try {
            for (Session session : sessionQueue) {
                session.getBasicRemote().sendText(toSend);
                LOGGER.log(Level.INFO, "Sent: {0}", toSend);
            }
        } catch (IOException e) {
            LOGGER.log(Level.SEVERE, e.toString());
        }
    }

    @OnOpen
    public void openConnection(Session session) {
        sessionQueue.add(session);
        LOGGER.log(Level.INFO, "Connection opened");
    }

    @OnClose
    public void closeConnection(Session session) {
        sessionQueue.remove(session);
        LOGGER.log(Level.INFO, "Connection closed");
    }

    @OnError
    public void error(Session session, Throwable th) {
        sessionQueue.remove(session);
        LOGGER.log(Level.WARNING, "Connection errorred");
        LOGGER.log(Level.WARNING, th.toString());

    }
}

3. The bean which will produce our fake data. It gets injected a TimerService as a @Resource and when @Timeout happens it invokes the send method of our endpoint:

package com.vvirlan.websocket;

import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.ejb.Timeout;
import javax.ejb.TimerConfig;
import javax.ejb.TimerService;

/**
 *
 * @author vvirlan
 * Generates a double every second and calls the endpoint for updating the clients
 */
@Startup
@Singleton
public class GeneratorBean {
    @Resource TimerService timerService;
    private Random random;
    private volatile double number = 777.0;
    private static final Logger logger = Logger.getLogger("GeneratorBean");
    
    @PostConstruct
    public void init() {
        logger.log(Level.INFO, "Initializing EJB");
        random = new Random();
        timerService.createIntervalTimer(1000, 1000, new TimerConfig());
    }
    
    @Timeout
    public void timeout() {
        number = 1.5 * (random.nextInt(100));
        WebSocketEndpoint.send(number);
    }
}