Use JAVA to connect Azure Web Pub Sub Service to make a simple MQ Demo
Tags: java, azure, pubsub
Published: 2022-08-24 04:12:00

# Overview
Develop web applications with real-time messaging using Azure Web PubSub, a fully managed service that supports native and serverless WebSockets. Use the publish-subscribe messaging pattern to create loosely coupled, scalable applications - including chat, live streaming, and IoT dashboards. Developers can focus on functionality while Web PubSub manages the flow of data and content to your web pages and mobile applications.

# concept

## connect
A connection, also known as a client or client connection, represents a single WebSocket connection to a Web PubSub service. After a successful connection, the Web PubSub service assigns a unique connection ID to the connection.

## hub
 
A hub is a logical concept for a set of client connections. Usually you use a hub for one purpose, for example, a chat hub or a notification hub. When a client connects, it connects to a hub, and for the life of its life, it belongs to that hub. Once a client connects to the hub, the hub exists. Different applications can share an Azure Web PubSub service using different hub names.

## Group
A group is a subset of connections to a hub. You can add client connections to or remove client connections from a group at any time. For example, when a customer joins a chat room, or when a customer leaves the chat room, the chat room can be considered a group. A client can join multiple groups, and a group can contain multiple clients. A group is like a group "conversation", a group conversation is created once someone joins the group, and the conversation disappears when there is no one in the group.

## user
A connection to Web PubSub can belong to a user. A user may have multiple connections, such as when a user connects across multiple devices or multiple browser tabs.

## message
When a client connects, it can send messages to, or receive messages from, upstream applications over the WebSocket connection.

# work process
1. The client connects to the service/client endpoint using the WebSocket transport. The service forwards each WebSocket frame to the configured upstream (server). WebSocket connections can connect with any custom subprotocol for server processing, or with the subprotocol json.webpubsub.azure.v1 supported by the service, which enables clients to pub/sub directly. Details are described in Client Protocol.
2. The service calls the server using the CloudEvents HTTP protocol on different client events. CloudEvents is a standardized, protocol-agnostic definition of the structure and metadata description of events hosted by the Cloud Native Computing Foundation (CNCF). Details are described in the server protocol.
3. The server can use the REST API to call services to send messages to clients or manage connected clients. Details are described in the server protocol

# Create a web pub sub service

## Connect to webPubSubServiceClient

### Import maven

```
<dependency>
    <groupId>com.azure</groupId>
    <artifactId>azure-messaging-webpubsub</artifactId>
    <version>1.1.4</version>
</dependency>
```

### Get connectionString from Azure and determine Hub

```
WebPubSubServiceClient webPubSubServiceClient = new WebPubSubServiceClientBuilder()
        .connectionString(" ")
        .hub(" ")
        .buildClient();
```


## Connect to webSocket

### Create token

```
GetClientAccessTokenOptions getClientAccessTokenOptions = new GetClientAccessTokenOptions();
getClientAccessTokenOptions.addRole("webpubsub.sendToGroup");
getClientAccessTokenOptions.addRole("webpubsub.joinLeaveGroup");
WebPubSubClientAccessToken token = webPubSubServiceClient.getClientAccessToken(getClientAccessTokenOptions);
```

### Create a WebSocket and determine the data transfer protocol used

```
String url = token.getUrl();
ws = HttpClient.newHttpClient().newWebSocketBuilder().subprotocols("json.webpubsub.azure.v1")
        .buildAsync(URI.create(url), new WebSocketClient()).join();
```

### Implement WebSocket message listener (depending on the WebSocket used, the implementation method is also different)

```
private static final class WebSocketClient implements WebSocket.Listener {
    private WebSocketClient() {
    }

    @Override
    public void onOpen(WebSocket webSocket) {
        log.info("subscriber open");
        WebSocket.Listener.super.onOpen(webSocket);
    }

    @Override
    public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
        log.info("Message received:{}", data);
        return WebSocket.Listener.super.onText(webSocket, data, last);
    }

    @Override
    public void onError(WebSocket webSocket, Throwable error) {
        System.out.println("Bad day! " + webSocket.toString());
        WebSocket.Listener.super.onError(webSocket, error);
    }
}

```

## Information

### AckId
When using ackId, you can receive an acknowledgment response message when your request is processed. You can choose to omit the ackId in fire-and-forget scenarios.
The Web PubSub service will send an ack response for each request with an ackId.

```
public class AckResponseMessage {
    private String type;
    private String ackId;
    private boolean success;
    private Error error;

    public static class Error{
        private String name;
        private String message;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getMessage() {
            return message;
        }

        public void setMessage(String message) {
            this.message = message;
        }
    }
}

```

### Send to group

```
public class SendGroupMessage {
    public final String type = "sendToGroup";
    public String data;
    public int ackId;
    public String group;
    public boolean noEcho;
    public DataType dataType;

    public SendGroupMessage(String data, int ackId, String group, boolean noEcho, DataType dataType) {
        this.data = data;
        this.ackId = ackId;
        this.group = group;
        this.noEcho = noEcho;
        this.dataType = dataType;
    }
}

```

### Join a group

```
public class JoinGroupMessage {
    public int ackId;
    public final String type = "joinGroup";
    public String group;

    public JoinGroupMessage(int ackId, String group){
        this.ackId = ackId;
        this.group = group;
    }
}
```

### Leave a Group

```
public class LeaveGroupMessage {
    public int ackId;
    public final String type = "leaveGroup";
    public String group;

    public LeaveGroupMessage(int ackId, String group){
        this.ackId = ackId;
        this.group = group;
    }
}
```

### Receiving messages from groups

```
public class ReceivedGroupMessage {
    private String type;
    private String from;
    private String fromUserId;
    private String group;
    private DataType dataType;
    private String data;
}
```

### Receiving a message from the server

```
public class ReceivedServerMessage {
    private String type;
    private String from;
    private DataType dataType;
    private String data;
}
```

### System response

```
public class ConnectedSystemMessage {
    private String type;
    private String event;
    private String userId;
    private String connectionId;
}

public class DisConnectedSystemMessage {
     private String type;
     private String event;
     private String message;
}
```

### Publish and subscribe
Publish

```
public void sendToGroup(String data,String group) {
     ++ackId;
     GroupMessage groupMessage = new GroupMessage(data, ackId, group);
     String string = null;
     try {
         string = objectMapper.writeValueAsString(groupMessage);
     } catch (JsonProcessingException e) {
         e.printStackTrace();
     }
     ws.sendText(string,true);
}
```

Subscribe

```
@Override
public CompletionStage<?> onText(WebSocket webSocket, CharSequence data, boolean last) {
     try {
         String message = String.valueOf(data);
         handleData(message);
     } catch (Exception e) {
         log.warn("e:{}", e.getMessage());
     }
     return WebSocket.Listener.super.onText(webSocket, data, last);
}
```