From cb42537d97718d4f0988e2d24cb60d96d8942499 Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Mon, 13 Jul 2026 12:00:15 +0530 Subject: [PATCH 1/2] [java][bidi] Allow passing subscription parameters for events --- java/src/org/openqa/selenium/bidi/BiDi.java | 13 +++++ java/src/org/openqa/selenium/bidi/Handle.java | 4 ++ java/src/org/openqa/selenium/bidi/Module.java | 5 ++ .../selenium/bidi/SubscriptionScope.java | 56 +++++++++++++++++++ 4 files changed, 78 insertions(+) create mode 100644 java/src/org/openqa/selenium/bidi/SubscriptionScope.java diff --git a/java/src/org/openqa/selenium/bidi/BiDi.java b/java/src/org/openqa/selenium/bidi/BiDi.java index 5343718c25a1e..75ed8b5867d59 100644 --- a/java/src/org/openqa/selenium/bidi/BiDi.java +++ b/java/src/org/openqa/selenium/bidi/BiDi.java @@ -21,6 +21,7 @@ import java.io.Closeable; import java.time.Duration; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; @@ -116,6 +117,18 @@ public String addListener( return subscriptionId; } + String addListener(Event event, Consumer handler, SubscriptionScope scope) { + Require.nonNull("Event to listen for", event); + Require.nonNull("Handler to call", handler); + Require.nonNull("Subscription scope", scope); + + Map params = new HashMap<>(scope.toMap()); + params.put("events", List.of(event.getMethod())); + String subscriptionId = subscribe(params); + connection.addListener(subscriptionId, event, handler); + return subscriptionId; + } + // The subscription id returned by the browser is the sole identifier we need to unsubscribe // later: it is unique regardless of whether the subscription was scoped to events, contexts, or // user contexts, so there is no need to separately track how a listener was subscribed. diff --git a/java/src/org/openqa/selenium/bidi/Handle.java b/java/src/org/openqa/selenium/bidi/Handle.java index 3363648221fe6..9c40f16860d80 100644 --- a/java/src/org/openqa/selenium/bidi/Handle.java +++ b/java/src/org/openqa/selenium/bidi/Handle.java @@ -45,6 +45,10 @@ String subscribe(Event event, Consumer handler) { return bidi.addListener(event, handler); } + String subscribe(Event event, Consumer handler, SubscriptionScope scope) { + return bidi.addListener(event, handler, scope); + } + void unsubscribe(String subscriptionId) { bidi.removeListener(subscriptionId); } diff --git a/java/src/org/openqa/selenium/bidi/Module.java b/java/src/org/openqa/selenium/bidi/Module.java index f23b013e6adbc..00f43272c2c43 100644 --- a/java/src/org/openqa/selenium/bidi/Module.java +++ b/java/src/org/openqa/selenium/bidi/Module.java @@ -49,6 +49,11 @@ protected final String subscribe(Event event, Consumer handler) { return handle.subscribe(event, handler); } + protected final String subscribe( + Event event, Consumer handler, SubscriptionScope scope) { + return handle.subscribe(event, handler, scope); + } + protected final void unsubscribe(String subscriptionId) { handle.unsubscribe(subscriptionId); } diff --git a/java/src/org/openqa/selenium/bidi/SubscriptionScope.java b/java/src/org/openqa/selenium/bidi/SubscriptionScope.java new file mode 100644 index 0000000000000..516c26f89d162 --- /dev/null +++ b/java/src/org/openqa/selenium/bidi/SubscriptionScope.java @@ -0,0 +1,56 @@ +// Licensed to the Software Freedom Conservancy (SFC) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The SFC licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. + +package org.openqa.selenium.bidi; + +import java.util.HashMap; +import java.util.Map; +import java.util.Set; +import org.openqa.selenium.Beta; +import org.openqa.selenium.internal.Require; + +/** + * Where a subscription applies: globally, or scoped to browsing contexts and/or user contexts. Part + * of the transport layer, not generated — the remote end decides which combinations are valid. + */ +@Beta +public final class SubscriptionScope { + + private Set contexts = Set.of(); + private Set userContexts = Set.of(); + + public SubscriptionScope contexts(Set contexts) { + this.contexts = Require.nonNull("Browsing context ids", contexts); + return this; + } + + public SubscriptionScope userContexts(Set userContexts) { + this.userContexts = Require.nonNull("User context ids", userContexts); + return this; + } + + Map toMap() { + Map params = new HashMap<>(); + if (!contexts.isEmpty()) { + params.put("contexts", contexts); + } + if (!userContexts.isEmpty()) { + params.put("userContexts", userContexts); + } + return params; + } +} From 0c9782a095e07d19136bdea7606af084a0590e3d Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Mon, 13 Jul 2026 12:37:25 +0530 Subject: [PATCH 2/2] Address comments --- .../selenium/bidi/SubscriptionScope.java | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/java/src/org/openqa/selenium/bidi/SubscriptionScope.java b/java/src/org/openqa/selenium/bidi/SubscriptionScope.java index 516c26f89d162..e6c15212ba9fc 100644 --- a/java/src/org/openqa/selenium/bidi/SubscriptionScope.java +++ b/java/src/org/openqa/selenium/bidi/SubscriptionScope.java @@ -26,6 +26,12 @@ /** * Where a subscription applies: globally, or scoped to browsing contexts and/or user contexts. Part * of the transport layer, not generated — the remote end decides which combinations are valid. + * + *

This class is intentionally limited to the scope of a subscription, not the full set of + * subscribe parameters. + * + * @see + * session.SubscriptionParameters */ @Beta public final class SubscriptionScope { @@ -33,13 +39,25 @@ public final class SubscriptionScope { private Set contexts = Set.of(); private Set userContexts = Set.of(); + /** + * Scopes the subscription to the given browsing contexts. + * + * @param contexts the browsing context ids to scope the subscription to + * @return this scope, for chaining + */ public SubscriptionScope contexts(Set contexts) { - this.contexts = Require.nonNull("Browsing context ids", contexts); + this.contexts = Set.copyOf(Require.nonNull("Browsing context ids", contexts)); return this; } + /** + * Scopes the subscription to the given user contexts. + * + * @param userContexts the user context ids to scope the subscription to + * @return this scope, for chaining + */ public SubscriptionScope userContexts(Set userContexts) { - this.userContexts = Require.nonNull("User context ids", userContexts); + this.userContexts = Set.copyOf(Require.nonNull("User context ids", userContexts)); return this; }