Over a million developers have joined DZone.
{{announcement.body}}
{{announcement.title}}

Handling ‘State’ in Java WebSocket Applications

DZone's Guide to

Handling ‘State’ in Java WebSocket Applications

State is a concept dealt with in several facets of application development. With the newer paradigm of WebSockets, how do you handle state here?

· Java Zone
Free Resource

Try Okta to add social login, MFA, and OpenID Connect support to your Java app in minutes. Create a free developer account today and never build auth again.

By and large, there are two kinds of states in a WebSocket application

  • User/client specific: related to a connected user/Session e.g. user ID, list of subscriptions, last message received, etc.
  • Global: state which is relevant across your application and something which all connected users/Sessions might be able to use.

User Specific State

This can be handled using getUserProperties method on the Session object – this exposes a Map, which you can use to store anything (Object type) using a String type key:

@OnOpen
public void opened(@PathParam("userid") String id, Session peer){
    peer.getUserProperties().put("USER_ID" , id); //it's possible to store the ID as a member variable as well.. this is just an example
}

@OnMessage
public void helloUser(Session peer, String message){
    String id = (String) peer.getUserProperties().get("USER_ID");
    peer.getBasicRemote().sendText("Hello "+ id + "! You sent "+ message);
}


Global State

There are multiple options here as well. Please note that these are scoped to a specific Endpoint

getUserProperties in EndpointConfig – it exposes the same Map interface as the one in Session. Since the WebSocket runtime creates a single instance of an EndpointConfig object per Endpoint , it can be used a global state store:

private EndpointCondig epCfg;
private static List<Session> peers = ...;

@OnOpen
public void open(@PathParam("userid") String id, Session peer, EndpointConfig epCfg){
    this.epCfg = epCfg;
    peers.add(peer);
    this.epCfg.getUserProperties().put(peer.getId(), id); //store mapping of WebSocket Session ID to user ID
}

@OnMessage
public void broadcast(Session from, String msg){
    String senderID = (String) this.epCfg.getUserProperties().get(from.getID()); //check the mapping
    for(Session peer : peers) { //loop over ALL connected clients
        if(peer.isOpen()){
            peer.getBasicRemote().sendText("Message from User "+ senderID + " - " + msg);
        }
    }
}


Another option is to encapsulate some of the common/global logic in a custom Configurator implementation, which can be accessed and used within the endpoint logic:

//custom Configurator implementation which maps (authenticated) user name to a token (sent via HTTP header)

public class TokenStore extends ServerEndpointConfig.Configurator {
    Map<String, String> userTokens;

    public TokenStore() {
        userTokens = new ConcurrentHashMap<>();
    }

    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        String token = request.getHeaders().get("token").get(0);
        String name = request.getUserPrincipal().getName();
        userTokens.put(name, token);
    }

    public Map<String, String> getUserTokens(){
        return Collections.unmodifiableMap(userTokens);
    }

}

//the WebSocket (server) endpoint implementation which makes use of the token store

@ServerEndpoint(value = "/service/{id}",configurator = TokenStore.class)
public class BroadcastService {
    private String token;

    @OnOpen
    public void test(@PathParam("id") String id, EndpointConfig cfg) { //injeted config by runtime
        ServerEndpoint sCfg = (ServerEndpoint) cfg; //cast
        TokenStore store = sCfg.getConfigurator(); //get custom implementation instance
        token = cfgur.getUserTokens().get(id); //extract token and store as a member variable
    }
}


Further Reading

Cheers!

Build and launch faster with Okta’s user management API. Register today for the free forever developer edition!

Topics:
java ,websocket ,state ,java ee ,tutorial

Published at DZone with permission of Abhishek Gupta, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}