15

This is probably obvious, but I am new to this paradigm. I create a Jetty Server and register my websocket class as follows:

        Server server = new Server(8080);
        WebSocketHandler wsHandler = new WebSocketHandler()
        {
            @Override
            public void configure(WebSocketServletFactory factory)
            {
                factory.register(MyEchoSocket.class);
            }
        };
        server.setHandler(wsHandler);

The websocket receives messages fine. I would like to also be able to send messages out from the server without having first received a message from the client. How do I access the MyEchoSocket instance that's created when the connection opens? Or, more generally, how do I send messages on the socket outside of the onText method in MyEchoSocket?

Alex Pritchard
  • 4,260
  • 5
  • 33
  • 48
  • That's not exactly a server then. It wouldn't make sense to start sending from that point since you don't know who you are connected to, unless you are responding to (serving) someone. – Sotirios Delimanolis Mar 26 '13 at 20:02
  • The reason I am working with WebSockets is that I thought they were a good choice for situations in which you want to push from the server side. MyEchoSocket can keep track of its own WebSocketConnections through its onConnect() method. I just don't know how to access the instance of MyEchoSocket once the program is running. – Alex Pritchard Mar 26 '13 at 20:14
  • Who are you trying to push to though? If it's after someone has connected to you, then maybe spawn some asynchronous handler to do the pushing. – Sotirios Delimanolis Mar 26 '13 at 20:17
  • Okay, that makes sense. Basically I want to be able to send messages to anyone who has connected to me, whenever certain other events occur. – Alex Pritchard Mar 26 '13 at 20:22
  • I'm not well versed in `jetty`, but that's how I would do it. When you receive a request, you retain a reference to the socket and spawn a handler to do the pushing you're talking about. Careful that jetty doesn't close the socket after the `onText` or whatever server handler method returns. – Sotirios Delimanolis Mar 26 '13 at 20:24

1 Answers1

37

Two common techniques, presented here in a super simplified chatroom concept.

Option #1: Have WebSocket report back its state to a central location

@WebSocket
public class ChatSocket {
    public Session session;

    @OnWebSocketConnect
    public void onConnect(Session session) {
        this.session = session;
        ChatRoom.getInstance().join(this);
    }

    @OnWebSocketMessage
    public void onText(String message) {
        ChatRoom.getInstance().writeAllMembers("Hello all");
    }

    @OnWebSocketClose
    public void onClose(int statusCode, String reason) {
        ChatRoom.getInstance().part(this);
    }
}

public class ChatRoom {
    private static final ChatRoom INSTANCE = new ChatRoom();

    public static ChatRoom getInstance()
    {
        return INSTANCE;
    }

    private List<ChatSocket> members = new ArrayList<>();

    public void join(ChatSocket socket) 
    {
        members.add(socket);
    }

    public void part(ChatSocket socket) 
    {
        members.remove(socket);
    }

    public void writeAllMembers(String message) 
    {
        for(ChatSocket member: members)
        {
            member.session.getRemote().sendStringByFuture(message);
        }
    }

    public void writeSpecificMember(String memberName, String message) 
    {
        ChatSocket member = findMemberByName(memberName);
        member.session.getRemote().sendStringByFuture(message);
    }

    public ChatSocket findMemberByName(String memberName) 
    {
        // left as exercise to reader
    }
}

Then simply use the central location to talk to the websockets of your choice.

ChatRoom.getInstance().writeSpecificMember("alex", "Hello");

// or

ChatRoom.getInstance().writeAllMembers("Hello all");

Option #2: Have WebSocket be created manually with WebSocketCreator

@WebSocket
public class ChatSocket {
    public ChatRoom chatroom;

    public ChatSocket(ChatRoom chatroom)
    {
        this.chatroom = chatroom;
    }

    @OnWebSocketConnect
    public void onConnect(Session session) {
        chatroom.join(this);
    }

    @OnWebSocketMessage
    public void onText(String message) {
        chatroom.writeAllMembers(message);
    }

    @OnWebSocketClose
    public void onClose(int statusCode, String reason) {
        chatroom.part(this);
    }
}

public class ChatCreator implements WebSocketCreator
{
    private ChatRoom chatroom;

    public ChatCreator(ChatRoom chatroom)
    {
        this.chatroom = chatroom;
    }

    public Object createWebSocket(UpgradeRequest request, 
                                  UpgradeResponse response)
    {
        // We want to create the Chat Socket and associate
        // it with our chatroom implementation
        return new ChatSocket(chatroom);
    }
}

public class ChatHandler extends WebSocketHandler
{
    private ChatRoom chatroom = new ChatRoom();

    @Override
    public void configure(WebSocketServletFactory factory)
    {
        factory.setCreator(new ChatCreator(chatroom));
    }
}

At this point you can use the same techniques as above to talk to the websockets of your choice.

Joakim Erdfelt
  • 46,896
  • 7
  • 86
  • 136