# Using @OnReceive to Communicate via WebSockets Protocol

There is a simple, yet flexible way to communicate with a server via WebSockets protocol. The support can transfer any classes generated by @Model annotation and reuses already existing @OnReceive infrastructure - just defines detailed special behavior, which is described here.

### Define JSON Class

The first step in using WebSockets is to create a model classes to encapsulate communiation with the server. For example one for sending requests and one for receiving replies:

        @Model(className = "Comm", properties={})
        final class Communication {
            @Model(className = "Request", properties = {
                @Property(name = "msg", type = MsgType.class),
                @Property(name = "username", type = String.class),
                @Property(name = "password", type = String.class),
                @Property(name = "gameId", type = String.class),
                @Property(name = "color", type = Color.class),
                @Property(name = "from", type = String.class),
                @Property(name = "to", type = String.class),
                @Property(name = "observer", type = boolean.class),
            })
            static class RequestModel {
            }

            @Model(className = "Response", properties = {
                @Property(name = "msg", type = MsgType.class),
                @Property(name = "turn", type = Color.class),
                @Property(name = "color", type = Color.class),
                @Property(name = "gameId", type = String.class),
                @Property(name = "status", type = String.class),
                @Property(name = "moves", type = String.class, array = true),
                @Property(name = "from", type = String.class),
                @Property(name = "to", type = String.class),
            })
            static class ResponseModel {
            }

            enum MsgType {
                CreateGame, QueryGames, SendMove, JoinGame, UpdateGame;
            }
            enum Color {
                W, B;
            }
        }

And then it is just a matter of creating the communication end point. As usual with @OnReceive annotation one starts with defining the response handler:

        @OnReceive(
            data = Request.class,
            url = "{url}",
            method = "WebSocket",
            onError = "anErrorHappened"
        )
        static void queryServer(Comm c, Response r) {
            if (r == null) {
                // connection stablished!
                return;
            }
            // message arrived!
            switch (r.getMsg()) {
                case CreateGame: /* do something */ break;
                case QueryGames: /* do something */ break;
                case SendMove: /* do something */ break;
                case JoinGame: /* do something */ break;
                case UpdateGame: /* do something */ break;
            }
        }
        static void anErrorHappened(Comm c, Exception t) {
            if (t == null) {
                // OK, connection has been closed
            } else {
                // handle the error t somehow
            }
        }

The WebSockets specification usually defines what should happen onopen, onmessage, onclose and onerror. All these messages are supported in the previous example as well:

- onopen - the queryServer method is called with `null` message
- onmessage - the queryServer method is called with non-null message
- onclose - the anErrorHappened method is called with `null` exception
- onerror - the anErrorHappened method is called with non-null exception

Using the @OnReceive annotation instructs its associated annotation processor to add appropriate send method into the generated `Comm` class. One can use it to establish communication, send messages and close the communication channel. Here are three methods showing how to do it:

        static void connect(Comm c) {
          // open a websocket channel:
          c.queryServer("ws://server/path", null);
          // the method returns immediately and starts establishing the connection
          // once that is finished either onopen or onerror type of
          // message is delivered
        }

        static void sendMessage(Comm c, Request r) {
          // sends the message to already openned websocket channel:
          c.queryServer("ws://server/path", r);
        }

        static void disconnect(Comm c) {
          // sending null again, closes the connection
          c.queryServer("ws://server/path", null);
        }

One cannot change the URL while a connection is open otherwise one risks `IllegalStateException` runtime exceptions. To connect to different web socket server, one needs to close the connection first and only later open new one with different URL.

Enjoy WebSockets via @OnReceive!