Skip to content

Commit 978a2d6

Browse files
joerg1985diemol
andauthored
[java] allow a DevTools listener to determinate the order of handler calls (#13921)
Co-authored-by: Diego Molina <[email protected]>
1 parent 768cb3d commit 978a2d6

File tree

2 files changed

+34
-7
lines changed

2 files changed

+34
-7
lines changed

java/src/org/openqa/selenium/devtools/Connection.java

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.util.concurrent.locks.Lock;
4444
import java.util.concurrent.locks.ReadWriteLock;
4545
import java.util.concurrent.locks.ReentrantReadWriteLock;
46+
import java.util.function.BiConsumer;
4647
import java.util.function.Consumer;
4748
import java.util.logging.Level;
4849
import java.util.logging.Logger;
@@ -70,11 +71,12 @@ public class Connection implements Closeable {
7071
return thread;
7172
});
7273
private static final AtomicLong NEXT_ID = new AtomicLong(1L);
74+
private static final AtomicLong NEXT_SEQUENCE = new AtomicLong(1L);
7375
private WebSocket socket;
7476
private final Map<Long, Consumer<Either<Throwable, JsonInput>>> methodCallbacks =
7577
new ConcurrentHashMap<>();
7678
private final ReadWriteLock callbacksLock = new ReentrantReadWriteLock(true);
77-
private final Map<Event<?>, List<Consumer<?>>> eventCallbacks = new HashMap<>();
79+
private final Map<Event<?>, List<BiConsumer<Long, ?>>> eventCallbacks = new HashMap<>();
7880
private HttpClient client;
7981
private final String url;
8082
private final AtomicBoolean isClosed;
@@ -196,7 +198,7 @@ public <X> X sendAndWait(SessionID sessionId, Command<X> command, Duration timeo
196198
}
197199
}
198200

199-
public <X> void addListener(Event<X> event, Consumer<X> handler) {
201+
public <X> void addListener(Event<X> event, BiConsumer<Long, X> handler) {
200202
Require.nonNull("Event to listen for", event);
201203
Require.nonNull("Handler to call", handler);
202204

@@ -230,10 +232,11 @@ private class Listener implements WebSocket.Listener {
230232

231233
@Override
232234
public void onText(CharSequence data) {
235+
long sequence = NEXT_SEQUENCE.getAndIncrement();
233236
EXECUTOR.execute(
234237
() -> {
235238
try {
236-
handle(data);
239+
handle(sequence, data);
237240
} catch (Throwable t) {
238241
LOG.log(Level.WARNING, "Unable to process: " + data, t);
239242
throw new DevToolsException(t);
@@ -242,7 +245,7 @@ public void onText(CharSequence data) {
242245
}
243246
}
244247

245-
private void handle(CharSequence data) {
248+
private void handle(long sequence, CharSequence data) {
246249
// It's kind of gross to decode the data twice, but this lets us get started on something
247250
// that feels nice to users.
248251
// TODO: decode once, and once only
@@ -335,14 +338,14 @@ private void handle(CharSequence data) {
335338
return;
336339
}
337340

338-
for (Consumer<?> action : event.getValue()) {
341+
for (BiConsumer<Long, ?> action : event.getValue()) {
339342
@SuppressWarnings("unchecked")
340-
Consumer<Object> obj = (Consumer<Object>) action;
343+
BiConsumer<Long, Object> obj = (BiConsumer<Long, Object>) action;
341344
LOG.log(
342345
getDebugLogLevel(),
343346
"Calling callback for {0} using {1} being passed {2}",
344347
new Object[] {event.getKey(), obj, params});
345-
obj.accept(params);
348+
obj.accept(sequence, params);
346349
}
347350
}
348351
});

java/src/org/openqa/selenium/devtools/DevTools.java

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import java.util.concurrent.CompletableFuture;
2727
import java.util.concurrent.ExecutionException;
2828
import java.util.concurrent.TimeoutException;
29+
import java.util.function.BiConsumer;
2930
import java.util.function.Consumer;
3031
import java.util.function.Function;
3132
import java.util.logging.Level;
@@ -89,10 +90,33 @@ public <X> X send(Command<X> command) {
8990
return connection.sendAndWait(cdpSession, command, timeout);
9091
}
9192

93+
/**
94+
* Register a handler to the given event.
95+
*
96+
* @param event the event to listen to
97+
* @param handler the handler to register
98+
* @param <X> type of the data generated by the event
99+
*/
92100
public <X> void addListener(Event<X> event, Consumer<X> handler) {
93101
Require.nonNull("Event to listen for", event);
94102
Require.nonNull("Handler to call", handler);
95103

104+
connection.addListener(event, (sequence, x) -> handler.accept(x));
105+
}
106+
107+
/**
108+
* Register a handler to the given event, this handler will receive a sequence number to
109+
* determinate the order of the data generated by the event. The sequence number might have gaps
110+
* when other events are raised in between.
111+
*
112+
* @param event the event to listen to
113+
* @param handler the handler to register
114+
* @param <X> type of the data generated by the event
115+
*/
116+
public <X> void addListener(Event<X> event, BiConsumer<Long, X> handler) {
117+
Require.nonNull("Event to listen for", event);
118+
Require.nonNull("Handler to call", handler);
119+
96120
connection.addListener(event, handler);
97121
}
98122

0 commit comments

Comments
 (0)