Skip to content

Commit 438201c

Browse files
authored
Merge pull request #1164 from ably/ECO-5564/clipped-flag
feat: add support for clipped client ID lists and enhance aggregation handling
2 parents 19c2898 + d0f1060 commit 438201c

File tree

4 files changed

+141
-10
lines changed

4 files changed

+141
-10
lines changed

lib/src/main/java/io/ably/lib/types/Summary.java

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,12 @@ public class Summary {
3131

3232
private static final String TAG = Summary.class.getName();
3333

34+
private static final String TOTAL = "total";
35+
private static final String CLIENT_IDS = "clientIds";
36+
private static final String CLIPPED = "clipped";
37+
private static final String TOTAL_UNIDENTIFIED = "totalUnidentified";
38+
private static final String TOTAL_CLIENT_IDS = "totalClientIds";
39+
3440
/**
3541
* (TM2q1) The sdk MUST be able to cope with structures and aggregation types that have it does not yet know about
3642
* or have explicit support for, hence the loose (JsonObject) type.
@@ -59,27 +65,55 @@ public static Map<String, SummaryClientIdCounts> asSummaryMultipleV1(JsonObject
5965
for (Map.Entry<String, JsonElement> entry : jsonObject.entrySet()) {
6066
String key = entry.getKey();
6167
JsonObject value = entry.getValue().getAsJsonObject();
62-
int total = value.get("total").getAsInt();
68+
int total = value.get(TOTAL).getAsInt();
6369
Map<String, Integer> clientIds = new HashMap<>();
64-
for (Map.Entry<String, JsonElement> clientEntry: value.get("clientIds").getAsJsonObject().entrySet()) {
70+
for (Map.Entry<String, JsonElement> clientEntry: value.get(CLIENT_IDS).getAsJsonObject().entrySet()) {
6571
clientIds.put(clientEntry.getKey(), clientEntry.getValue().getAsInt());
6672
}
67-
summary.put(key, new SummaryClientIdCounts(total, clientIds));
73+
Integer totalUnidentified = tryReadIntField(value, TOTAL_UNIDENTIFIED);
74+
Integer totalClientIds = tryReadIntField(value, TOTAL_CLIENT_IDS);
75+
summary.put(key, new SummaryClientIdCounts(
76+
total,
77+
clientIds,
78+
totalUnidentified == null ? 0 : totalUnidentified,
79+
tryReadBooleanField(value, CLIPPED),
80+
totalClientIds == null ? total : totalClientIds
81+
));
6882
}
6983
return summary;
7084
}
7185

7286
public static SummaryClientIdList asSummaryFlagV1(JsonObject jsonObject) {
73-
int total = jsonObject.get("total").getAsInt();
74-
List<String> clientIds = Serialisation.gson.fromJson(jsonObject.get("clientIds"), List.class);
75-
return new SummaryClientIdList(total, clientIds);
87+
int total = jsonObject.get(TOTAL).getAsInt();
88+
List<String> clientIds = Serialisation.gson.fromJson(jsonObject.get(CLIENT_IDS), List.class);
89+
return new SummaryClientIdList(
90+
total,
91+
clientIds,
92+
tryReadBooleanField(jsonObject, CLIPPED)
93+
);
7694
}
7795

7896
public static SummaryTotal asSummaryTotalV1(JsonObject jsonObject) {
79-
int total = jsonObject.get("total").getAsInt();
97+
int total = jsonObject.get(TOTAL).getAsInt();
8098
return new SummaryTotal(total);
8199
}
82100

101+
private static boolean tryReadBooleanField(JsonObject jsonObject, String fieldName) {
102+
JsonElement fieldElement = jsonObject.get(fieldName);
103+
if (fieldElement != null && fieldElement.isJsonPrimitive() && fieldElement.getAsJsonPrimitive().isBoolean()) {
104+
return fieldElement.getAsBoolean();
105+
}
106+
return false;
107+
}
108+
109+
private static Integer tryReadIntField(JsonObject jsonObject, String fieldName) {
110+
JsonElement fieldElement = jsonObject.get(fieldName);
111+
if (fieldElement != null && fieldElement.isJsonPrimitive() && fieldElement.getAsJsonPrimitive().isNumber()) {
112+
return fieldElement.getAsInt();
113+
}
114+
return null;
115+
}
116+
83117
static Summary read(MessageUnpacker unpacker) {
84118
try {
85119
return read(Serialisation.msgpackToGson(unpacker.unpackValue()));

lib/src/main/java/io/ably/lib/types/SummaryClientIdCounts.java

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,45 @@
22

33
import java.util.Map;
44

5+
/**
6+
* The per-name value for the multiple.v1 aggregation method.
7+
*/
58
public class SummaryClientIdCounts {
9+
/**
10+
* The sum of the counts from all clients who have published an annotation with this name
11+
*/
612
public final int total; // TM7d1a
13+
/**
14+
* A list of the clientIds of all clients who have published an annotation with this
15+
* name, and the count each of them have contributed.
16+
*/
717
public final Map<String, Integer> clientIds; // TM7d1b
18+
/**
19+
* The sum of the counts from all unidentified clients who have published an annotation with this
20+
* name, and so who are not included in the clientIds list
21+
*/
22+
public final int totalUnidentified; // TM7d1d
23+
/**
24+
* Whether the list of clientIds has been clipped due to exceeding the maximum number of
25+
* clients.
26+
*/
27+
public final boolean clipped; // TM7d1c
28+
/**
29+
* The total number of distinct clientIds in the map (equal to length of map if clipped is false).
30+
*/
31+
public final int totalClientIds; // TM7d1e
832

9-
public SummaryClientIdCounts(int total, Map<String, Integer> clientIds) {
33+
public SummaryClientIdCounts(
34+
int total,
35+
Map<String, Integer> clientIds,
36+
int totalUnidentified,
37+
boolean clipped,
38+
int totalClientIds
39+
) {
1040
this.total = total;
1141
this.clientIds = clientIds;
42+
this.totalUnidentified = totalUnidentified;
43+
this.clipped = clipped;
44+
this.totalClientIds = totalClientIds;
1245
}
1346
}

lib/src/main/java/io/ably/lib/types/SummaryClientIdList.java

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,29 @@
22

33
import java.util.List;
44

5+
/**
6+
* The summary entry for aggregated annotations that use the flag.v1
7+
* aggregation method; also the per-name value for some other aggregation methods.
8+
*/
59
public class SummaryClientIdList {
10+
/**
11+
* The sum of the counts from all clients who have published an annotation with this name
12+
*/
613
public final int total; // TM7c1a
7-
public final List<String> clientIds; // TM7c1b
14+
/**
15+
* A list of the clientIds of all clients who have published an annotation with this name (or
16+
* type, depending on context).
17+
*/
18+
public final List<String> clientIds; // TM7
19+
/**
20+
* Whether the list of clientIds has been clipped due to exceeding the maximum number of
21+
* clients.
22+
*/
23+
public final boolean clipped; // TM7c1c
824

9-
public SummaryClientIdList(int total, List<String> clientIds) {
25+
public SummaryClientIdList(int total, List<String> clientIds, boolean clipped) {
1026
this.total = total;
1127
this.clientIds = clientIds;
28+
this.clipped = clipped;
1229
}
1330
}

lib/src/test/java/io/ably/lib/types/SummaryTest.java

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import java.util.Map;
88

99
import static org.junit.Assert.assertEquals;
10+
import static org.junit.Assert.assertFalse;
1011
import static org.junit.Assert.assertNotNull;
1112
import static org.junit.Assert.assertTrue;
1213
import static org.junit.Assert.fail;
@@ -126,6 +127,25 @@ public void testAsSummaryFlagV1_SingleEntry() {
126127
assertTrue(result.clientIds.contains("client1"));
127128
assertTrue(result.clientIds.contains("client2"));
128129
assertTrue(result.clientIds.contains("client3"));
130+
assertFalse(result.clipped);
131+
}
132+
133+
@Test
134+
public void testAsSummaryFlagV1_clippedTrue() {
135+
JsonObject entryValue = new JsonObject();
136+
entryValue.addProperty("total", 100);
137+
JsonArray clientIds = new JsonArray();
138+
clientIds.add("client1");
139+
entryValue.add("clientIds", clientIds);
140+
entryValue.addProperty("clipped", true);
141+
142+
SummaryClientIdList result = Summary.asSummaryFlagV1(entryValue);
143+
144+
assertNotNull(result);
145+
assertEquals(100, result.total);
146+
assertEquals(1, result.clientIds.size());
147+
assertTrue(result.clientIds.contains("client1"));
148+
assertTrue(result.clipped);
129149
}
130150

131151
@Test
@@ -196,13 +216,40 @@ public void testAsSummaryMultipleV1_MultipleEntries() {
196216
assertEquals(2, summaryA.clientIds.size());
197217
assertEquals(3, (int) summaryA.clientIds.get("clientA"));
198218
assertEquals(2, (int) summaryA.clientIds.get("clientB"));
219+
assertEquals(0, summaryA.totalUnidentified);
220+
assertEquals(5, summaryA.totalClientIds);
221+
assertFalse(summaryA.clipped);
199222

200223
SummaryClientIdCounts summaryB = result.get("👍️️️️️️");
201224
assertNotNull(summaryB);
202225
assertEquals(2, summaryB.total);
203226
assertEquals(2, summaryB.clientIds.size());
204227
assertEquals(1, (int) summaryB.clientIds.get("clientX"));
205228
assertEquals(1, (int) summaryB.clientIds.get("clientY"));
229+
assertEquals(0, summaryB.totalUnidentified);
230+
assertEquals(2, summaryB.totalClientIds);
231+
assertFalse(summaryA.clipped);
232+
}
233+
234+
@Test
235+
public void testAsSummaryMultipleV1_ClippedTrue() {
236+
JsonObject jsonObject = new JsonObject();
237+
238+
JsonObject entryValue1 = new JsonObject();
239+
entryValue1.addProperty("total", 5);
240+
JsonObject clientIds1 = new JsonObject();
241+
clientIds1.addProperty("clientA", 1);
242+
entryValue1.add("clientIds", clientIds1);
243+
entryValue1.addProperty("clipped", true);
244+
entryValue1.addProperty("totalClientIds", 1);
245+
jsonObject.add("😄️️️", entryValue1);
246+
247+
Map<String, SummaryClientIdCounts> result = Summary.asSummaryMultipleV1(jsonObject);
248+
SummaryClientIdCounts summary = result.get("😄️️️");
249+
assertEquals(5, summary.total);
250+
assertEquals(1, summary.totalClientIds);
251+
assertEquals(0, summary.totalUnidentified);
252+
assertTrue(summary.clipped);
206253
}
207254

208255
@Test

0 commit comments

Comments
 (0)