Java - Play2 Are Actors required for WebSockets implementation?
Asked Answered
M

1

12

I am trying to implement a WebSockets based solution with Play2 and Java. Currently I'm not using Actor Model for concurrency management. Instead, it's just handling the WebSockets using callbacks.

The problem is the server is unable to 'broadcast' the messages across to multiple clients. For example, I need all the active browser sessions to receive a simple notification after an action is triggered through a client. Instead, I'm just able to simulate this for a single client session. In effect, it just acts as a regular Ajax request/response scenario.

My guess is the WebSockets solution with Play2 & Java with simple callbacks isn't able to broadcast the messages to all of the connected client browsers.

Callback server code

public static WebSocket<String> heartUpdate() {
        return new WebSocket<String>() {
            public void onReady(final WebSocket.In<String> in,
                    WebSocket.Out<String> out) {
                in.onMessage(new Callback<String>() {
                    @Override
                    public void invoke(String event) throws Throwable {
                        Product product = Product.find.byId(Long.decode(event));
                        // Other business stuff
                        out.write(entity.id + " " + decimalValue);
                    }
                });
                in.onClose(new Callback0() {
                    @Override
                    public void invoke() throws Throwable {

                    }
                });
                out.write(DELIM_USERID_REP);
            }
        };
    }

Routes entry

GET /repsocket   controllers.Application.heartUpdate

Client side

<script>
    // Onto the WebSockets now
    var WS = window['MozWebSocket'] ? MozWebSocket : WebSocket;
    var socket = new WS("@routes.Application.heartUpdate.webSocketURL(request)");

    var receiveEvent = function(event) {
        alert(event.data);
        // Notification badge visible with a common text
        $('#notify').text(event.data);
        $('#notify').addClass('visible');
    }
        $('#heart').click(function(e) {
            e.preventDefault();
            socket.send(@product.id);
        });
    socket.onmessage = receiveEvent;
    </script>

In the above case, the action triggering client is the one that successfully receives the message from the server, while any other browser sessions do not.

I failed to find any documentation aligned with Play2 with Java & WebSockets that suggests a mandatory use of Actors to maintain a consistent communication with all connected active clients.

Question: Should WebSockets in Play2 with Java be implemented with Actor Model to broadcast the message to all active client sessions?

Edit: The screenshot below reflects the 2 states of browsers to which I have logged in to using 2 valid user credentials.

Ideally, WebSockets' response from the server should create the same notification badges on both the browsers.

enter image description here

Medievalist answered 5/10, 2015 at 16:41 Comment(5)
What error do you have?Sergeant
@nikpon No errors, the message from the server is just reflected in 1 browser session - that triggered the request & not in any other connected client sessionsMedievalist
how did you get a session of the browser?Sergeant
@nikpon logged-on to the system using 2 browsers with valid user credentials. Please refer to the edit.Medievalist
For the clear experiment better use the browsers of the same manufacturer like FF e.g.Sergeant
O
5

Looking at the code you posted, it seems the problem is that you are not saving a reference to each connection, so you can later broadcast messages. Something like this:

// Just an example: does not deal with concurrency problems
private static final Set<WebSocket.Out<String>> SOCKETS = new HashSet<>();

public static WebSocket<String> heartUpdate() {
    return new WebSocket<String>() {
        public void onReady(final WebSocket.In<String> in,
                    final WebSocket.Out<String> out) {
            SOCKETS.add(out);
            in.onMessage(new Callback<String>() {
                @Override
                public void invoke(String event) throws Throwable {
                    for(WebSocket.Out<String> s: SOCKETS) {
                        s.write("SOME MESSAGE");    
                    }
                }
            });
            in.onClose(new Callback0() {
                @Override
                public void invoke() throws Throwable {
                    SOCKETS.remove(out);
                }
            });
        }
    };
}

You can also use actors to model this problem: having an actor responsible to keep track of the connections and to deal with new sockets connection/close.

If you want to use Akka there are some activator templates to get you started.

Outrank answered 5/10, 2015 at 20:18 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.