Building an interactive application using WebSocket

Sample Number

453

Level

Advanced

Description

This sample demonstrates how to build an interactive application using WebSocket protocol implementation.

Use Case

I want to build an interactive application where a set of instructions will be executed based on the inputs received from the WebSocket clients.

453

As shown in the above diagram, assume that there are three WebSocket clients named Arya, Sansam and Joffrey connected to the UltraESB through the same subscriber path. Imagine a scenario where these three clients can only move along a straight line and when they change their position, they would transmit their new position to the UltraESB. Above is a snapshot taken at a particular instance where Arya is at position 3, Sansa is at position 10 and Joffrey is at position 19. What the application does is that based on the client’s input, it would notify the clients about the nearby clients. (within a distance of 10 units.)

What is a Subscriber path of a WebSocket Client?

Subscriber path of a WebSocket can be described as the resource path of the URL a particular WebSocket client has connected to. As an example, assume a particular WebSocket client has connected to 'ws://localhost:8887/helloworld' URL. Then the subscriber path of that WebSocket client would be 'helloworld'.

Sample Configuration

The configuration for this use case consists of a proxy service, exposed on the WebSocket transport. The proxy service execute the code within the FriendFinder class in inSequece.

The 'ws-endpoint' has the address 'ws://individualpeers' and notice the address type is 'prefix'. Hence, the suffix of the address is set within the inSequence.

Proxy service configuration

 1<u:proxy id="friendfinder" >
 2    <u:transport id="ws-listener">
 3    </u:transport>
 4    <u:target>
 5        <u:inSequence>
 6            <u:class name="samples.services.websocket.FriendFinder"/>
 7        </u:inSequence>
 8    </u:target>
 9</u:proxy>
10
11<u:endpoint id="ws-endpoint">
12    <u:address type="prefix">ws://individualpeers</u:address>
13</u:endpoint>

Below is the code block within the FriendFinder java class.The userLocationMap is used to store the WebSocketClients with their locations. The WebSocket client transmit its new location as an Integer to the UltraESB and it will be available within the proxy service as a WebSocketMessage with the opcode TEXT. The flow of the execute() method is as follows

  1. Obtain the ID of the WebSocket client who has sent the current message to the UltraESB (line 8)

  2. If the WebSocket client’s ID is null, then return (line 10-13)

  3. Obtain the opcode of the WebSocketMessage (line 16)

  4. If the opcode is TEXT read the client’s location and add/update the userLocationMap. (line 17-22)

  5. For every user in the userLocationMap calculate the distance between nearbyUserLocation and originalUserLocation and if that distance is less than '10', send appropriate messages to the original client. (line 25-47)
    Note that the suffix of the address is set in the lines 37 and 45. i.e. the prefix of address was 'ws://individualpeers' and the suffix will be the IDs of the individual message recipient clients. For more information about WebSocket addressing scheme, please refer WebSocket Transport Guide.

  6. If the opcode is CLOSING or TIMEOUT, that means the particular WebSocket client has disconnected. Hence, remove the client from the userLocationMap. (line 50-53)

Content of the FriendFinder java class

 1/* Stores the currently connected users with with their location */
 2ConcurrentMap<String, Integer> userLocationMap = new ConcurrentHashMap<>();
 3
 4@Override
 5public void execute(Message msg, Mediation mediation) throws Exception {
 6
 7    /* obtain the peerID of the message sender */
 8    final String originalUserID = mediation.getWebSocketSupport().getOriginPeerID(msg);
 9
10    if(originalUserID == null) {
11        /* invalid message type */
12        return;
13    }
14
15    /* obtain the opcode of the WebSocketMessage */
16    final WebSocketMessage.Opcode opcode = mediation.getWebSocketSupport().getOpcode(msg);
17    if (opcode == WebSocketMessage.Opcode.TEXT) {
18
19        /* obtain the location of the peer from the message */
20        final int originalUserLocation = Integer.parseInt(mediation.readFullPayloadAsString(msg));
21        /* add/update the location of the peer */
22        userLocationMap.put(originalUserID, originalUserLocation);
23
24        /* notify the other user/s and original message sender if a friend is near */
25        for (Map.Entry<String, Integer> entry : userLocationMap.entrySet()) {
26            final String nearbyUserID = entry.getKey();
27            final Integer nearbyUserLocation = entry.getValue();
28            final int distanceBetweenUsers = Math.abs(nearbyUserLocation - originalUserLocation);
29
30            if (!nearbyUserID.equals(originalUserID) && distanceBetweenUsers < 10) {
31                /* send a message to nearby user */
32                String textMessage = "Your friend " + originalUserID + " is nearby";
33                org.adroitlogic.ultraesb.core.format.WebSocketMessage payload =
34                        new org.adroitlogic.ultraesb.core.format.WebSocketMessage(textMessage);
35                final Message clonedMsg = msg.cloneMessage();
36                clonedMsg.setCurrentPayload(payload);
37                mediation.getWebSocketSupport().setRecipientPeers(clonedMsg, nearbyUserID);
38                mediation.sendToEndpoint(clonedMsg, "ws-endpoint");
39
40                /* send a message to original message sender*/
41                textMessage = "Your friend " + nearbyUserID + " is nearby";
42                org.adroitlogic.ultraesb.core.format.WebSocketMessage newPayload =
43                        new org.adroitlogic.ultraesb.core.format.WebSocketMessage(textMessage);
44                msg.setCurrentPayload(newPayload);
45                mediation.getWebSocketSupport().setRecipientPeers(msg, originalUserID);
46                mediation.sendToEndpoint(msg, "ws-endpoint");
47            }
48        }
49
50     } else if (opcode == WebSocketMessage.Opcode.CLOSING || opcode == WebSocketMessage.Opcode.TIMEOUT) {
51        /* close message or a session timeout message received and remove the connected peers map */
52        userLocationMap.remove(originalUserID);
53    }
54}
Note
For the simplicity the complete configuration is not displayed here, you may look at the complete configuration either from the binary distribution under samples/conf/ultra-sample-453.xml, or from the sample 453 configuration of the source tag.

In Action

To run the example, start the UltraESB sample configuration 453 via the ToolBox or on the command line as follows.

Running the sample from startup script

$ cd /opt/ultraesb-2.6.1/bin
$ ./ultraesb.sh -sample 453

Now open the friendfinder.html client at samples/resources/websocket/ in three browser tabs and give Arya, Sansa, and Joffrey as User ID and click connect button.

Browser Support
browser
You must open friendfinder.html file using a browser which has native WebSocket support such as Internet Explorer 10+, Mozilla Firefox 11+, Google Chrome 16+, Opera 12.10+ or Safari 6+.

Now send position '3' as Arya and position’10’ asn Sansa. Both 'Arya' and 'Sansa' will receive messages saying that they are nearby. Next Send position '19' as Joffrey and both Sansa and Joffrey will receive messages saying that they are nearby. Feel free to experiment with various other user positions and various number of users.

ff arya

Browser tab connected as 'Arya'

ff sansa

Browser tab connected as 'Sansa'

ff jof

Browser tab connected as 'Joffrey'

In this topic
In this topic
Contact Us