Skip to content

Commit 3f799b8

Browse files
committed
[java] Synchronizing access to listener list to avoid concurrent modification exceptions.
1 parent 36f0c85 commit 3f799b8

File tree

1 file changed

+38
-32
lines changed

1 file changed

+38
-32
lines changed

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

Lines changed: 38 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -111,11 +111,15 @@ public <X> void addListener(Event<X> event, Consumer<X> handler) {
111111
Objects.requireNonNull(event);
112112
Objects.requireNonNull(handler);
113113

114-
eventCallbacks.put(event, handler);
114+
synchronized (eventCallbacks) {
115+
eventCallbacks.put(event, handler);
116+
}
115117
}
116118

117119
public void clearListeners() {
118-
eventCallbacks.clear();
120+
synchronized (eventCallbacks) {
121+
eventCallbacks.clear();
122+
}
119123
}
120124

121125
@Override
@@ -159,41 +163,43 @@ public void onText(CharSequence data) {
159163
} else if (raw.get("method") instanceof String && raw.get("params") instanceof Map) {
160164
LOG.fine("Seen: " + raw);
161165

162-
// TODO: Also only decode once.
163-
eventCallbacks.keySet().stream()
164-
.filter(event -> raw.get("method").equals(event.getMethod()))
165-
.forEach(event -> {
166-
// TODO: This is grossly inefficient. I apologise, and we should fix this.
167-
try (StringReader reader = new StringReader(asString);
168-
JsonInput input = JSON.newInput(reader)) {
169-
Object value = null;
170-
input.beginObject();
171-
while (input.hasNext()) {
172-
switch (input.nextName()) {
173-
case "params":
174-
value = event.getMapper().apply(input);
175-
break;
176-
177-
default:
178-
input.skipValue();
179-
break;
166+
synchronized (eventCallbacks) {
167+
// TODO: Also only decode once.
168+
eventCallbacks.keySet().stream()
169+
.filter(event -> raw.get("method").equals(event.getMethod()))
170+
.forEach(event -> {
171+
// TODO: This is grossly inefficient. I apologise, and we should fix this.
172+
try (StringReader reader = new StringReader(asString);
173+
JsonInput input = JSON.newInput(reader)) {
174+
Object value = null;
175+
input.beginObject();
176+
while (input.hasNext()) {
177+
switch (input.nextName()) {
178+
case "params":
179+
value = event.getMapper().apply(input);
180+
break;
181+
182+
default:
183+
input.skipValue();
184+
break;
185+
}
180186
}
181-
}
182-
input.endObject();
187+
input.endObject();
183188

184-
if (value == null) {
185-
// Do nothing.
186-
return;
187-
}
189+
if (value == null) {
190+
// Do nothing.
191+
return;
192+
}
188193

189-
final Object finalValue = value;
194+
final Object finalValue = value;
190195

191-
for (Consumer<?> action : eventCallbacks.get(event)) {
192-
@SuppressWarnings("unchecked") Consumer<Object> obj = (Consumer<Object>) action;
193-
obj.accept(finalValue);
196+
for (Consumer<?> action : eventCallbacks.get(event)) {
197+
@SuppressWarnings("unchecked") Consumer<Object> obj = (Consumer<Object>) action;
198+
obj.accept(finalValue);
199+
}
194200
}
195-
}
196-
});
201+
});
202+
}
197203
} else {
198204
LOG.warning("Unhandled type: " + data);
199205
}

0 commit comments

Comments
 (0)