From 299002184b1a85f1ab010a99dd2121a277938184 Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Wed, 20 Aug 2025 11:37:21 +0530 Subject: [PATCH 1/3] [grid] Replace Guava map,list and set with Java equivalent for Node --- .../openqa/selenium/grid/graphql/Grid.java | 6 +- .../grid/node/CapabilityResponseEncoder.java | 21 +++--- .../grid/node/CustomLocatorHandler.java | 14 ++-- .../selenium/grid/node/GetNodeSession.java | 4 +- .../selenium/grid/node/IsSessionOwner.java | 4 +- .../selenium/grid/node/NewNodeSession.java | 4 +- .../org/openqa/selenium/grid/node/Node.java | 9 ++- .../grid/node/ProxyNodeWebsockets.java | 6 +- .../selenium/grid/node/StatusHandler.java | 8 +-- .../grid/node/config/NodeOptions.java | 69 ++++++++++-------- .../config/SessionCapabilitiesMutator.java | 5 +- .../grid/node/docker/DockerOptions.java | 72 ++++++++++--------- .../grid/node/httpd/DefaultNodeConfig.java | 5 +- .../selenium/grid/node/httpd/NodeServer.java | 3 +- .../selenium/grid/node/k8s/OneShotNode.java | 13 ++-- .../selenium/grid/node/local/LocalNode.java | 37 +++++----- .../grid/node/local/LocalNodeFactory.java | 7 +- .../grid/node/relay/RelayOptions.java | 49 +++++++------ .../selenium/grid/node/remote/RemoteNode.java | 6 +- 19 files changed, 178 insertions(+), 164 deletions(-) diff --git a/java/src/org/openqa/selenium/grid/graphql/Grid.java b/java/src/org/openqa/selenium/grid/graphql/Grid.java index a6eb03cb6e35d..1549e92e0b1b4 100644 --- a/java/src/org/openqa/selenium/grid/graphql/Grid.java +++ b/java/src/org/openqa/selenium/grid/graphql/Grid.java @@ -17,10 +17,10 @@ package org.openqa.selenium.grid.graphql; -import com.google.common.collect.ImmutableList; import java.net.URI; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -68,7 +68,7 @@ public String getVersion() { } public List getNodes() { - ImmutableList.Builder toReturn = ImmutableList.builder(); + List toReturn = new ArrayList<>(); for (NodeStatus status : distributorStatus.getNodes()) { Map stereotypes = new HashMap<>(); @@ -105,7 +105,7 @@ public List getNodes() { osInfo)); } - return toReturn.build(); + return Collections.unmodifiableList(toReturn); } public int getNodeCount() { diff --git a/java/src/org/openqa/selenium/grid/node/CapabilityResponseEncoder.java b/java/src/org/openqa/selenium/grid/node/CapabilityResponseEncoder.java index b093c58e5dcd6..4ad0476f6d0c0 100644 --- a/java/src/org/openqa/selenium/grid/node/CapabilityResponseEncoder.java +++ b/java/src/org/openqa/selenium/grid/node/CapabilityResponseEncoder.java @@ -19,7 +19,8 @@ import static java.nio.charset.StandardCharsets.UTF_8; -import com.google.common.collect.ImmutableMap; +import java.util.Collections; +import java.util.HashMap; import java.util.Map; import java.util.function.BiFunction; import java.util.function.Function; @@ -85,7 +86,7 @@ public byte[] apply(Session session, Map metadata) { @Override public byte[] apply(Session session) { - return apply(session, ImmutableMap.of()); + return apply(session, Map.of()); } /** Create a UTF-8 encoded response for a given dialect for use with the New Session command. */ @@ -108,14 +109,14 @@ private static byte[] encodeAsResponse( private static Map encodeW3C( SessionId id, Capabilities capabilities, Map metadata) { - return ImmutableMap.builder() - .putAll(metadata) - .put( - "value", - ImmutableMap.of( - "sessionId", id, - "capabilities", capabilities)) - .build(); + Map encodedResult = new HashMap<>(metadata); + encodedResult.put( + "value", + Map.of( + "sessionId", id, + "capabilities", capabilities)); + + return Collections.unmodifiableMap(encodedResult); } } } diff --git a/java/src/org/openqa/selenium/grid/node/CustomLocatorHandler.java b/java/src/org/openqa/selenium/grid/node/CustomLocatorHandler.java index f8950dea4d50c..e120ec31b375e 100644 --- a/java/src/org/openqa/selenium/grid/node/CustomLocatorHandler.java +++ b/java/src/org/openqa/selenium/grid/node/CustomLocatorHandler.java @@ -21,8 +21,6 @@ import static org.openqa.selenium.json.Json.MAP_TYPE; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import java.io.IOException; import java.io.UncheckedIOException; import java.util.Map; @@ -72,7 +70,7 @@ class CustomLocatorHandler implements Routable { new UrlTemplate("/session/{sessionId}/element/{elementId}/elements"); // These are derived from the w3c webdriver spec private static final Set W3C_STRATEGIES = - ImmutableSet.of("css selector", "link text", "partial link text", "tag name", "xpath"); + Set.of("css selector", "link text", "partial link text", "tag name", "xpath"); private final HttpHandler toNode; private final Map> extraLocators; @@ -119,9 +117,9 @@ public HttpResponse execute(HttpRequest req) throws UncheckedIOException { .setStatus(HTTP_BAD_REQUEST) .setContent( Contents.asJson( - ImmutableMap.of( + Map.of( "value", - ImmutableMap.of( + Map.of( "error", "invalid argument", "message", "Unable to determine element locating strategy", "stacktrace", "")))); @@ -138,9 +136,9 @@ public HttpResponse execute(HttpRequest req) throws UncheckedIOException { .setStatus(HTTP_BAD_REQUEST) .setContent( Contents.asJson( - ImmutableMap.of( + Map.of( "value", - ImmutableMap.of( + Map.of( "error", "invalid argument", "message", "Unable to determine element locator arguments", "stacktrace", "")))); @@ -224,7 +222,7 @@ public HttpResponse execute(HttpRequest req) throws UncheckedIOException { toReturn = context.findElement(by); } - return new HttpResponse().setContent(Contents.asJson(ImmutableMap.of("value", toReturn))); + return new HttpResponse().setContent(Contents.asJson(Map.of("value", toReturn))); } private static class NodeWrappingExecutor implements CommandExecutor { diff --git a/java/src/org/openqa/selenium/grid/node/GetNodeSession.java b/java/src/org/openqa/selenium/grid/node/GetNodeSession.java index cd0b0915a4e5e..93b32a94a50d4 100644 --- a/java/src/org/openqa/selenium/grid/node/GetNodeSession.java +++ b/java/src/org/openqa/selenium/grid/node/GetNodeSession.java @@ -19,8 +19,8 @@ import static org.openqa.selenium.remote.http.Contents.asJson; -import com.google.common.collect.ImmutableMap; import java.io.UncheckedIOException; +import java.util.Map; import org.openqa.selenium.grid.data.Session; import org.openqa.selenium.internal.Require; import org.openqa.selenium.remote.SessionId; @@ -42,6 +42,6 @@ class GetNodeSession implements HttpHandler { public HttpResponse execute(HttpRequest req) throws UncheckedIOException { Session session = node.getSession(id); - return new HttpResponse().setContent(asJson(ImmutableMap.of("value", session))); + return new HttpResponse().setContent(asJson(Map.of("value", session))); } } diff --git a/java/src/org/openqa/selenium/grid/node/IsSessionOwner.java b/java/src/org/openqa/selenium/grid/node/IsSessionOwner.java index cc9bbafa44f30..bd9f85e5140b6 100644 --- a/java/src/org/openqa/selenium/grid/node/IsSessionOwner.java +++ b/java/src/org/openqa/selenium/grid/node/IsSessionOwner.java @@ -19,8 +19,8 @@ import static org.openqa.selenium.remote.http.Contents.asJson; -import com.google.common.collect.ImmutableMap; import java.io.UncheckedIOException; +import java.util.Map; import org.openqa.selenium.internal.Require; import org.openqa.selenium.remote.SessionId; import org.openqa.selenium.remote.http.HttpHandler; @@ -39,6 +39,6 @@ class IsSessionOwner implements HttpHandler { @Override public HttpResponse execute(HttpRequest req) throws UncheckedIOException { - return new HttpResponse().setContent(asJson(ImmutableMap.of("value", node.isSessionOwner(id)))); + return new HttpResponse().setContent(asJson(Map.of("value", node.isSessionOwner(id)))); } } diff --git a/java/src/org/openqa/selenium/grid/node/NewNodeSession.java b/java/src/org/openqa/selenium/grid/node/NewNodeSession.java index dcbb8b8771b55..c8843c3367bdd 100644 --- a/java/src/org/openqa/selenium/grid/node/NewNodeSession.java +++ b/java/src/org/openqa/selenium/grid/node/NewNodeSession.java @@ -20,9 +20,9 @@ import static org.openqa.selenium.remote.http.Contents.asJson; import static org.openqa.selenium.remote.http.Contents.string; -import com.google.common.collect.ImmutableMap; import java.io.UncheckedIOException; import java.util.HashMap; +import java.util.Map; import org.openqa.selenium.WebDriverException; import org.openqa.selenium.grid.data.CreateSessionRequest; import org.openqa.selenium.grid.data.CreateSessionResponse; @@ -58,7 +58,7 @@ public HttpResponse execute(HttpRequest req) throws UncheckedIOException { WebDriverException exception = result.left(); response.put( "exception", - ImmutableMap.of( + Map.of( "error", exception.getClass(), "message", exception.getMessage())); } diff --git a/java/src/org/openqa/selenium/grid/node/Node.java b/java/src/org/openqa/selenium/grid/node/Node.java index 6a8627fd23ffe..d01c7a429fa8a 100644 --- a/java/src/org/openqa/selenium/grid/node/Node.java +++ b/java/src/org/openqa/selenium/grid/node/Node.java @@ -25,7 +25,6 @@ import static org.openqa.selenium.remote.http.Route.matching; import static org.openqa.selenium.remote.http.Route.post; -import com.google.common.collect.ImmutableMap; import java.io.IOException; import java.net.URI; import java.time.Duration; @@ -125,7 +124,7 @@ public abstract class Node implements HasReadyState, Routable { private static final Logger LOG = Logger.getLogger(Node.class.getName()); private static final BuildInfo INFO = new BuildInfo(); - private static final ImmutableMap OS_INFO = loadOsInfo(); + private static final Map OS_INFO = loadOsInfo(); protected final Tracer tracer; private final NodeId id; private final URI uri; @@ -206,8 +205,8 @@ protected Node( get("/status").to(() -> new StatusHandler(this)).with(spanDecorator("node.status"))); } - private static ImmutableMap loadOsInfo() { - return ImmutableMap.of( + private static Map loadOsInfo() { + return Map.of( "arch", System.getProperty("os.arch"), "name", System.getProperty("os.name"), "version", System.getProperty("os.version")); @@ -233,7 +232,7 @@ public String getNodeVersion() { return String.format("%s (revision %s)", INFO.getReleaseLabel(), INFO.getBuildRevision()); } - public ImmutableMap getOsInfo() { + public Map getOsInfo() { return OS_INFO; } diff --git a/java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java b/java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java index d347dbfb4b059..3e2f960cde763 100644 --- a/java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java +++ b/java/src/org/openqa/selenium/grid/node/ProxyNodeWebsockets.java @@ -20,11 +20,11 @@ import static org.openqa.selenium.internal.Debug.getDebugLogLevel; import static org.openqa.selenium.remote.http.HttpMethod.GET; -import com.google.common.collect.ImmutableSet; import java.net.URI; import java.net.URISyntaxException; import java.util.Objects; import java.util.Optional; +import java.util.Set; import java.util.function.BiFunction; import java.util.function.Consumer; import java.util.logging.Level; @@ -53,8 +53,8 @@ public class ProxyNodeWebsockets private static final UrlTemplate FWD_TEMPLATE = new UrlTemplate("/session/{sessionId}/se/fwd"); private static final UrlTemplate VNC_TEMPLATE = new UrlTemplate("/session/{sessionId}/se/vnc"); private static final Logger LOG = Logger.getLogger(ProxyNodeWebsockets.class.getName()); - private static final ImmutableSet CDP_ENDPOINT_CAPS = - ImmutableSet.of("goog:chromeOptions", "ms:edgeOptions"); + private static final Set CDP_ENDPOINT_CAPS = + Set.of("goog:chromeOptions", "ms:edgeOptions"); private final HttpClient.Factory clientFactory; private final Node node; private final String gridSubPath; diff --git a/java/src/org/openqa/selenium/grid/node/StatusHandler.java b/java/src/org/openqa/selenium/grid/node/StatusHandler.java index 7dc157a378e9e..523c54b61940a 100644 --- a/java/src/org/openqa/selenium/grid/node/StatusHandler.java +++ b/java/src/org/openqa/selenium/grid/node/StatusHandler.java @@ -19,8 +19,8 @@ import static org.openqa.selenium.remote.http.Contents.asJson; -import com.google.common.collect.ImmutableMap; import java.io.UncheckedIOException; +import java.util.Map; import org.openqa.selenium.grid.data.NodeStatus; import org.openqa.selenium.internal.Require; import org.openqa.selenium.remote.http.HttpHandler; @@ -39,10 +39,10 @@ class StatusHandler implements HttpHandler { public HttpResponse execute(HttpRequest req) throws UncheckedIOException { NodeStatus status = node.getStatus(); - ImmutableMap report = - ImmutableMap.of( + Map report = + Map.of( "value", - ImmutableMap.of( + Map.of( "ready", status.hasCapacity(), "message", diff --git a/java/src/org/openqa/selenium/grid/node/config/NodeOptions.java b/java/src/org/openqa/selenium/grid/node/config/NodeOptions.java index 5afc047497960..62aa927f20291 100644 --- a/java/src/org/openqa/selenium/grid/node/config/NodeOptions.java +++ b/java/src/org/openqa/selenium/grid/node/config/NodeOptions.java @@ -20,11 +20,6 @@ import static org.openqa.selenium.remote.CapabilityType.ENABLE_DOWNLOADS; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Multimap; import java.io.File; import java.io.StringReader; import java.lang.reflect.Method; @@ -35,6 +30,7 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.HashMap; import java.util.List; @@ -42,6 +38,7 @@ import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Function; import java.util.logging.Level; @@ -95,8 +92,8 @@ public class NodeOptions { private static final Logger LOG = Logger.getLogger(NodeOptions.class.getName()); private static final Json JSON = new Json(); private static final Platform CURRENT_PLATFORM = Platform.getCurrent(); - private static final ImmutableSet SINGLE_SESSION_DRIVERS = - ImmutableSet.of("safari", "safari technology preview"); + private static final Set SINGLE_SESSION_DRIVERS = + Set.of("safari", "safari technology preview"); private final Config config; private final AtomicBoolean vncEnabled = new AtomicBoolean(); @@ -249,15 +246,14 @@ public Map> getSessionFactories( Map> allDrivers = discoverDrivers(maxSessions, factoryFactory); - ImmutableMultimap.Builder sessionFactories = - ImmutableMultimap.builder(); + Map> sessionFactories = new HashMap<>(); addDriverFactoriesFromConfig(sessionFactories); addDriverConfigs(factoryFactory, sessionFactories, maxSessions); addSpecificDrivers(allDrivers, sessionFactories); addDetectedDrivers(allDrivers, sessionFactories); - return sessionFactories.build().asMap(); + return Collections.unmodifiableMap(sessionFactories); } public int getMaxSessions() { @@ -333,7 +329,7 @@ int noVncPort() { } private void addDriverFactoriesFromConfig( - ImmutableMultimap.Builder sessionFactories) { + Map> sessionFactories) { config .getAll(NODE_SECTION, "driver-factories") .ifPresent( @@ -353,7 +349,9 @@ private void addDriverFactoriesFromConfig( (clazz, config) -> { Capabilities stereotype = JSON.toType(config, Capabilities.class); SessionFactory sessionFactory = createSessionFactory(clazz, stereotype); - sessionFactories.put(stereotype, sessionFactory); + sessionFactories + .computeIfAbsent(stereotype, k -> new ArrayList<>()) + .add(sessionFactory); }); }); } @@ -392,10 +390,10 @@ private SessionFactory createSessionFactory(String clazz, Capabilities stereotyp private void addDriverConfigs( Function> factoryFactory, - ImmutableMultimap.Builder sessionFactories, + Map> sessionFactories, int maxSessions) { - Multimap driverConfigs = HashMultimap.create(); + Map> driverConfigs = new HashMap<>(); // get all driver configuration settings config @@ -523,24 +521,32 @@ private void addDriverConfigs( new ImmutableCapabilities(stereotype); int maxDriverSessions = getDriverMaxSessions(info, driverMaxSessions); for (int i = 0; i < maxDriverSessions; i++) { - driverConfigs.putAll( - driverInfoConfig, factoryFactory.apply(immutable)); + driverConfigs + .computeIfAbsent(driverInfoConfig, k -> new ArrayList<>()) + .addAll(factoryFactory.apply(immutable)); } }); }); }); - driverConfigs.asMap().entrySet().stream() + driverConfigs.entrySet().stream() .peek(this::report) .forEach( entry -> - sessionFactories.putAll( - entry.getKey().getCanonicalCapabilities(), entry.getValue())); + entry + .getValue() + .forEach( + factory -> + sessionFactories + .computeIfAbsent( + entry.getKey().getCanonicalCapabilities(), + k -> new ArrayList<>()) + .add(factory))); } private void addDetectedDrivers( Map> allDrivers, - ImmutableMultimap.Builder sessionFactories) { + Map> sessionFactories) { if (!config.getBool(NODE_SECTION, "detect-drivers").orElse(DEFAULT_DETECT_DRIVERS)) { return; } @@ -556,10 +562,12 @@ private void addDetectedDrivers( entry -> { Capabilities capabilities = enhanceStereotype(entry.getKey().getCanonicalCapabilities()); - sessionFactories.putAll(capabilities, entry.getValue()); + sessionFactories + .computeIfAbsent(capabilities, k -> new ArrayList<>()) + .addAll(entry.getValue()); }); - if (sessionFactories.build().isEmpty()) { + if (sessionFactories.isEmpty()) { String logMessage = "No drivers have been configured or have been found on PATH"; LOG.warning(logMessage); throw new ConfigException(logMessage); @@ -568,7 +576,7 @@ private void addDetectedDrivers( private void addSpecificDrivers( Map> allDrivers, - ImmutableMultimap.Builder sessionFactories) { + Map> sessionFactories) { if (config.getAll(NODE_SECTION, "driver-implementation").isEmpty()) { return; } @@ -617,7 +625,9 @@ private void addSpecificDrivers( entry -> { Capabilities capabilities = enhanceStereotype(entry.getKey().getCanonicalCapabilities()); - sessionFactories.putAll(capabilities, entry.getValue()); + sessionFactories + .computeIfAbsent(capabilities, k -> new ArrayList<>()) + .addAll(entry.getValue()); }); } @@ -625,7 +635,7 @@ private Map> discoverDrivers( int maxSessions, Function> factoryFactory) { if (!config.getBool(NODE_SECTION, "detect-drivers").orElse(DEFAULT_DETECT_DRIVERS)) { - return ImmutableMap.of(); + return Collections.emptyMap(); } // We don't expect duplicates, but they're fine @@ -656,7 +666,8 @@ private Map> discoverDrivers( List> builders = new ArrayList<>(); ServiceLoader.load(DriverService.Builder.class).forEach(builders::add); - Multimap toReturn = HashMultimap.create(); + Map> toReturn = new HashMap<>(); + infos.forEach( info -> { Capabilities caps = enhanceStereotype(info.getCanonicalCapabilities()); @@ -668,12 +679,14 @@ private Map> discoverDrivers( ImmutableCapabilities immutable = new ImmutableCapabilities(caps); int maxDriverSessions = getDriverMaxSessions(info, maxSessions); for (int i = 0; i < maxDriverSessions; i++) { - toReturn.putAll(info, factoryFactory.apply(immutable)); + toReturn + .computeIfAbsent(info, k -> new ArrayList<>()) + .addAll(factoryFactory.apply(immutable)); } }); }); - return toReturn.asMap(); + return toReturn; } private WebDriverInfo createConfiguredDriverInfo( diff --git a/java/src/org/openqa/selenium/grid/node/config/SessionCapabilitiesMutator.java b/java/src/org/openqa/selenium/grid/node/config/SessionCapabilitiesMutator.java index 79a03e7bcee25..1d3431d779ab4 100644 --- a/java/src/org/openqa/selenium/grid/node/config/SessionCapabilitiesMutator.java +++ b/java/src/org/openqa/selenium/grid/node/config/SessionCapabilitiesMutator.java @@ -17,7 +17,6 @@ package org.openqa.selenium.grid.node.config; -import com.google.common.collect.ImmutableMap; import java.util.ArrayList; import java.util.HashMap; import java.util.List; @@ -31,8 +30,8 @@ public class SessionCapabilitiesMutator implements Function { - private static final ImmutableMap BROWSER_OPTIONS = - ImmutableMap.of( + private static final Map BROWSER_OPTIONS = + Map.of( "chrome", "goog:chromeOptions", "firefox", "moz:firefoxOptions", "microsoftedge", "ms:edgeOptions"); diff --git a/java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java b/java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java index 2ec4040428ec2..5df7c47035e2c 100644 --- a/java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java +++ b/java/src/org/openqa/selenium/grid/node/docker/DockerOptions.java @@ -20,9 +20,6 @@ import static org.openqa.selenium.Platform.WINDOWS; import static org.openqa.selenium.docker.Device.device; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; import java.net.URI; import java.net.URISyntaxException; import java.time.Duration; @@ -30,6 +27,7 @@ import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -143,7 +141,8 @@ public Map> getDockerSessionFactories( List hostConfigKeys = config.getAll(DOCKER_SECTION, "host-config-keys").orElseGet(Collections::emptyList); - Multimap kinds = HashMultimap.create(); + Map> kinds = new HashMap<>(); + int configsCount = allConfigs.size(); for (int i = 0; i < configsCount; i++) { String imageName = allConfigs.get(i); @@ -154,7 +153,7 @@ public Map> getDockerSessionFactories( Capabilities stereotype = options.enhanceStereotype(JSON.toType(allConfigs.get(i), Capabilities.class)); - kinds.put(imageName, stereotype); + kinds.computeIfAbsent(imageName, k -> new ArrayList<>()).add(stereotype); } List devicesMapping = getDevicesMapping(); @@ -180,36 +179,41 @@ public Map> getDockerSessionFactories( Math.min( config.getInt("node", "max-sessions").orElse(DEFAULT_MAX_SESSIONS), DEFAULT_MAX_SESSIONS); - ImmutableMultimap.Builder factories = ImmutableMultimap.builder(); + Map> factories = new HashMap<>(); + kinds.forEach( - (name, caps) -> { - Image image = docker.getImage(name); - for (int i = 0; i < maxContainerCount; i++) { - factories.put( - caps, - new DockerSessionFactory( - tracer, - clientFactory, - options.getSessionTimeout(), - getServerStartTimeout(), - docker, - getDockerUri(), - image, - caps, - devicesMapping, - videoImage, - assetsPath, - networkName, - info.isPresent(), - capabilities -> options.getSlotMatcher().matches(caps, capabilities), - hostConfig, - hostConfigKeys)); - } - LOG.info( - String.format( - "Mapping %s to docker image %s %d times", caps, name, maxContainerCount)); - }); - return factories.build().asMap(); + (name, capsCollection) -> + capsCollection.forEach( + caps -> { + Image image = docker.getImage(name); + for (int i = 0; i < maxContainerCount; i++) { + factories + .computeIfAbsent(caps, k -> new ArrayList<>()) + .add( + new DockerSessionFactory( + tracer, + clientFactory, + options.getSessionTimeout(), + getServerStartTimeout(), + docker, + getDockerUri(), + image, + caps, + devicesMapping, + videoImage, + assetsPath, + networkName, + info.isPresent(), + capabilities -> + options.getSlotMatcher().matches(caps, capabilities), + hostConfig, + hostConfigKeys)); + } + LOG.info( + String.format( + "Mapping %s to docker image %s %d times", caps, name, maxContainerCount)); + })); + return Collections.unmodifiableMap(factories); } protected List getDevicesMapping() { diff --git a/java/src/org/openqa/selenium/grid/node/httpd/DefaultNodeConfig.java b/java/src/org/openqa/selenium/grid/node/httpd/DefaultNodeConfig.java index fb410a05c0cae..7bb00974ee263 100644 --- a/java/src/org/openqa/selenium/grid/node/httpd/DefaultNodeConfig.java +++ b/java/src/org/openqa/selenium/grid/node/httpd/DefaultNodeConfig.java @@ -18,19 +18,20 @@ package org.openqa.selenium.grid.node.httpd; import com.google.common.collect.ImmutableMap; +import java.util.Map; import org.openqa.selenium.grid.config.MapConfig; class DefaultNodeConfig extends MapConfig { DefaultNodeConfig() { super( - ImmutableMap.of( + Map.of( "node", ImmutableMap.of( // We use this instead of setting the default ports for // the publish and subscribe ports of the event bus so // that people can use the `--hub` flag safely. "hub", "http://0.0.0.0:4444"), - "server", ImmutableMap.of("port", 5555))); + "server", Map.of("port", 5555))); } } diff --git a/java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java b/java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java index fcac8ce89c3e5..dd93d481b4f7d 100644 --- a/java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java +++ b/java/src/org/openqa/selenium/grid/node/httpd/NodeServer.java @@ -26,7 +26,6 @@ import static org.openqa.selenium.remote.http.Route.get; import com.google.auto.service.AutoService; -import com.google.common.collect.ImmutableSet; import com.google.common.net.MediaType; import dev.failsafe.Failsafe; import dev.failsafe.RetryPolicy; @@ -90,7 +89,7 @@ public String getDescription() { @Override public Set getConfigurableRoles() { - return ImmutableSet.of(EVENT_BUS_ROLE, HTTPD_ROLE, NODE_ROLE); + return Set.of(EVENT_BUS_ROLE, HTTPD_ROLE, NODE_ROLE); } @Override diff --git a/java/src/org/openqa/selenium/grid/node/k8s/OneShotNode.java b/java/src/org/openqa/selenium/grid/node/k8s/OneShotNode.java index 8781e7b1a0efa..b781bd2f02e70 100644 --- a/java/src/org/openqa/selenium/grid/node/k8s/OneShotNode.java +++ b/java/src/org/openqa/selenium/grid/node/k8s/OneShotNode.java @@ -23,8 +23,6 @@ import static org.openqa.selenium.json.Json.MAP_TYPE; import static org.openqa.selenium.remote.http.HttpMethod.DELETE; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import java.lang.reflect.Field; import java.net.URI; import java.net.URISyntaxException; @@ -34,6 +32,7 @@ import java.util.Map; import java.util.Optional; import java.util.ServiceLoader; +import java.util.Set; import java.util.UUID; import java.util.concurrent.atomic.AtomicInteger; import java.util.logging.Logger; @@ -213,9 +212,9 @@ public Either newSession( LOG.info( "Encoded response: " + JSON.toJson( - ImmutableMap.of( + Map.of( "value", - ImmutableMap.of( + Map.of( "sessionId", sessionId, "capabilities", capabilities)))); @@ -225,9 +224,9 @@ public Either newSession( new CreateSessionResponse( getSession(sessionId), JSON.toJson( - ImmutableMap.of( + Map.of( "value", - ImmutableMap.of( + Map.of( "sessionId", sessionId, "capabilities", capabilities))) .getBytes(UTF_8))); @@ -397,7 +396,7 @@ public NodeStatus getStatus() { getId(), getUri(), 1, - ImmutableSet.of( + Set.of( new Slot( new SlotId(getId(), slotId), stereotype, diff --git a/java/src/org/openqa/selenium/grid/node/local/LocalNode.java b/java/src/org/openqa/selenium/grid/node/local/LocalNode.java index 91f52d16c31c5..6ee707540f112 100644 --- a/java/src/org/openqa/selenium/grid/node/local/LocalNode.java +++ b/java/src/org/openqa/selenium/grid/node/local/LocalNode.java @@ -17,7 +17,6 @@ package org.openqa.selenium.grid.node.local; -import static com.google.common.collect.ImmutableSet.toImmutableSet; import static org.openqa.selenium.concurrent.ExecutorServices.shutdownGracefully; import static org.openqa.selenium.grid.data.Availability.DOWN; import static org.openqa.selenium.grid.data.Availability.DRAINING; @@ -36,8 +35,6 @@ import com.github.benmanes.caffeine.cache.RemovalCause; import com.github.benmanes.caffeine.cache.Ticker; import com.google.common.annotations.VisibleForTesting; -import com.google.common.collect.ImmutableList; -import com.google.common.collect.ImmutableMap; import java.io.Closeable; import java.io.File; import java.io.IOException; @@ -48,7 +45,9 @@ import java.time.Clock; import java.time.Duration; import java.time.Instant; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -175,7 +174,7 @@ protected LocalNode( this.maxSessionCount = Math.min(Require.positive("Max session count", maxSessionCount), factories.size()); this.heartbeatPeriod = heartbeatPeriod; - this.factories = ImmutableList.copyOf(factories); + this.factories = List.copyOf(factories); Require.nonNull("Registration secret", registrationSecret); this.configuredSessionCount = drainAfterSessionCount; this.drainAfterSessions = this.configuredSessionCount > 0; @@ -580,8 +579,8 @@ private boolean managedDownloadsRequested(Capabilities capabilities) { private Capabilities setDownloadsDirectory(TemporaryFilesystem downloadsTfs, Capabilities caps) { File tempDir = downloadsTfs.createTempDir("download", ""); if (Browser.CHROME.is(caps) || Browser.EDGE.is(caps)) { - ImmutableMap map = - ImmutableMap.of( + Map map = + Map.of( "download.prompt_for_download", false, "download.default_directory", @@ -592,8 +591,8 @@ private Capabilities setDownloadsDirectory(TemporaryFilesystem downloadsTfs, Cap return appendPrefs(caps, optionsKey, map); } if (Browser.FIREFOX.is(caps)) { - ImmutableMap map = - ImmutableMap.of( + Map map = + Map.of( "browser.download.folderList", 2, "browser.download.dir", tempDir.getAbsolutePath()); return appendPrefs(caps, "moz:firefoxOptions", map); } @@ -744,8 +743,8 @@ public HttpResponse downloadFile(HttpRequest req, SessionId id) { Arrays.stream(Optional.ofNullable(downloadsDirectory.listFiles()).orElse(new File[] {})) .map(File::getName) .collect(Collectors.toList()); - ImmutableMap data = ImmutableMap.of("names", collected); - ImmutableMap> result = ImmutableMap.of("value", data); + Map data = Map.of("names", collected); + Map> result = Map.of("value", data); return new HttpResponse().setContent(asJson(result)); } if (req.getMethod().equals(HttpMethod.DELETE)) { @@ -786,11 +785,11 @@ public HttpResponse downloadFile(HttpRequest req, SessionId id) { String.format("Expected there to be only 1 file. There were: %s.", allFiles.length)); } String content = Zip.zip(allFiles[0]); - ImmutableMap data = - ImmutableMap.of( + Map data = + Map.of( "filename", filename, "contents", content); - ImmutableMap> result = ImmutableMap.of("value", data); + Map> result = Map.of("value", data); return new HttpResponse().setContent(asJson(result)); } catch (IOException e) { throw new UncheckedIOException(e); @@ -829,7 +828,7 @@ public HttpResponse uploadFile(HttpRequest req, SessionId id) { String.format("Expected there to be only 1 file. There were: %s", allFiles.length)); } - ImmutableMap result = ImmutableMap.of("value", allFiles[0].getAbsolutePath()); + Map result = Map.of("value", allFiles[0].getAbsolutePath()); return new HttpResponse().setContent(asJson(result)); } @@ -971,7 +970,7 @@ public NodeStatus getStatus() { lastStarted, session); }) - .collect(toImmutableSet()); + .collect(Collectors.toUnmodifiableSet()); Availability availability = isDraining() ? DRAINING : UP; @@ -1063,7 +1062,7 @@ private boolean decrementSessionCount() { } private Map toJson() { - return ImmutableMap.of( + return Map.of( "id", getId(), "uri", externalUri, "maxSessions", maxSessionCount, @@ -1079,7 +1078,7 @@ public static class Builder { private final URI uri; private final URI gridUri; private final Secret registrationSecret; - private final ImmutableList.Builder factories; + private final List factories; private int maxSessions = NodeOptions.DEFAULT_MAX_SESSIONS; private int drainAfterSessionCount = NodeOptions.DEFAULT_DRAIN_AFTER_SESSION_COUNT; private boolean cdpEnabled = NodeOptions.DEFAULT_ENABLE_CDP; @@ -1097,7 +1096,7 @@ private Builder(Tracer tracer, EventBus bus, URI uri, URI gridUri, Secret regist this.uri = Require.nonNull("Remote node URI", uri); this.gridUri = Require.nonNull("Grid URI", gridUri); this.registrationSecret = Require.nonNull("Registration secret", registrationSecret); - this.factories = ImmutableList.builder(); + this.factories = new ArrayList<>(); } public Builder add(Capabilities stereotype, SessionFactory factory) { @@ -1163,7 +1162,7 @@ public LocalNode build() { ticker, sessionTimeout, heartbeatPeriod, - factories.build(), + Collections.unmodifiableList(factories), registrationSecret, managedDownloadsEnabled, connectionLimitPerSession); diff --git a/java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java b/java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java index 600f516b02992..b0f4f7b6301cb 100644 --- a/java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java +++ b/java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java @@ -17,11 +17,12 @@ package org.openqa.selenium.grid.node.local; -import com.google.common.collect.ImmutableList; + import java.io.File; import java.time.Duration; import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; import java.util.Comparator; import java.util.List; import java.util.ServiceLoader; @@ -110,7 +111,7 @@ private static Collection createSessionFactory( List> builders, ImmutableCapabilities stereotype, SlotMatcher slotMatcher) { - ImmutableList.Builder toReturn = ImmutableList.builder(); + List toReturn = new ArrayList<>(); String webDriverExecutablePath = String.valueOf(stereotype.asMap().getOrDefault("se:webDriverExecutable", "")); @@ -146,6 +147,6 @@ private static Collection createSessionFactory( driverServiceBuilder)); }); - return toReturn.build(); + return Collections.unmodifiableList(toReturn); } } diff --git a/java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java b/java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java index 0f36f1a30c706..b7640feb79476 100644 --- a/java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java +++ b/java/src/org/openqa/selenium/grid/node/relay/RelayOptions.java @@ -20,14 +20,14 @@ import static org.openqa.selenium.remote.http.Contents.string; import static org.openqa.selenium.remote.http.HttpMethod.GET; -import com.google.common.collect.HashMultimap; -import com.google.common.collect.ImmutableMultimap; -import com.google.common.collect.Multimap; import java.net.URI; import java.net.URISyntaxException; import java.net.http.HttpClient.Version; import java.time.Duration; +import java.util.ArrayList; import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; @@ -152,7 +152,7 @@ public Map> getSessionFactories( .orElseThrow( () -> new ConfigException("Unable to find configs for " + getServiceUri())); - Multimap parsedConfigs = HashMultimap.create(); + Map> parsedConfigs = new HashMap<>(); int configsCount = allConfigs.size(); for (int i = 0; i < configsCount; i++) { int maxSessions; @@ -167,29 +167,32 @@ public Map> getSessionFactories( } Capabilities stereotype = JSON.toType(extractConfiguredValue(allConfigs.get(i)), Capabilities.class); - parsedConfigs.put(maxSessions, stereotype); + parsedConfigs.computeIfAbsent(maxSessions, k -> new ArrayList<>()).add(stereotype); } - ImmutableMultimap.Builder factories = ImmutableMultimap.builder(); + Map> factories = new HashMap<>(); LOG.info(String.format("Adding relay configs for %s", getServiceUri())); parsedConfigs.forEach( - (maxSessions, stereotype) -> { - ImmutableCapabilities immutable = new ImmutableCapabilities(stereotype); - for (int i = 0; i < maxSessions; i++) { - factories.put( - immutable, - new RelaySessionFactory( - tracer, - clientFactory, - sessionTimeout, - getServiceUri(), - getServiceStatusUri(), - getServiceProtocolVersion(), - immutable)); - } - LOG.info(String.format("Mapping %s, %d times", immutable, maxSessions)); - }); - return factories.build().asMap(); + (maxSessions, stereotypeList) -> + stereotypeList.forEach( + stereotype -> { + ImmutableCapabilities immutable = new ImmutableCapabilities(stereotype); + for (int i = 0; i < maxSessions; i++) { + factories + .computeIfAbsent(immutable, k -> new ArrayList<>()) + .add( + new RelaySessionFactory( + tracer, + clientFactory, + sessionTimeout, + getServiceUri(), + getServiceStatusUri(), + getServiceProtocolVersion(), + immutable)); + } + LOG.info(String.format("Mapping %s, %d times", immutable, maxSessions)); + })); + return Collections.unmodifiableMap(factories); } private String extractConfiguredValue(String keyValue) { diff --git a/java/src/org/openqa/selenium/grid/node/remote/RemoteNode.java b/java/src/org/openqa/selenium/grid/node/remote/RemoteNode.java index 947ee18e79978..01914a0ee89fe 100644 --- a/java/src/org/openqa/selenium/grid/node/remote/RemoteNode.java +++ b/java/src/org/openqa/selenium/grid/node/remote/RemoteNode.java @@ -29,8 +29,6 @@ import static org.openqa.selenium.remote.http.HttpMethod.GET; import static org.openqa.selenium.remote.http.HttpMethod.POST; -import com.google.common.collect.ImmutableMap; -import com.google.common.collect.ImmutableSet; import java.io.Closeable; import java.io.IOException; import java.io.Reader; @@ -91,7 +89,7 @@ public RemoteNode( Collection capabilities) { super(tracer, id, externalUri, registrationSecret, sessionTimeout); this.externalUri = Require.nonNull("External URI", externalUri); - this.capabilities = ImmutableSet.copyOf(capabilities); + this.capabilities = Set.copyOf(capabilities); ClientConfig clientConfig = defaultConfig().readTimeout(this.getSessionTimeout()).baseUrl(fromUri(externalUri)); @@ -301,7 +299,7 @@ public void drain() { @SuppressWarnings("unused") private Map toJson() { - return ImmutableMap.of( + return Map.of( "id", getId(), "uri", externalUri, "capabilities", capabilities); From da8fc6354baa7734ae2cb263aa1193fbc5a1c4a6 Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Fri, 22 Aug 2025 15:15:07 +0530 Subject: [PATCH 2/3] Ensure set maintain insertion order --- java/src/org/openqa/selenium/grid/node/local/LocalNode.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/java/src/org/openqa/selenium/grid/node/local/LocalNode.java b/java/src/org/openqa/selenium/grid/node/local/LocalNode.java index 6ee707540f112..f2a6ea9e4149a 100644 --- a/java/src/org/openqa/selenium/grid/node/local/LocalNode.java +++ b/java/src/org/openqa/selenium/grid/node/local/LocalNode.java @@ -49,6 +49,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Optional; @@ -970,7 +971,10 @@ public NodeStatus getStatus() { lastStarted, session); }) - .collect(Collectors.toUnmodifiableSet()); + .collect( + Collectors.collectingAndThen( + Collectors.toCollection(LinkedHashSet::new), + set -> Collections.unmodifiableSet(new LinkedHashSet<>(set)))); Availability availability = isDraining() ? DRAINING : UP; From 2038c01c90d3f8bf18b9c9647329d1ff6bd703a5 Mon Sep 17 00:00:00 2001 From: Puja Jagani Date: Fri, 22 Aug 2025 16:12:47 +0530 Subject: [PATCH 3/3] Fix formatting --- .../org/openqa/selenium/grid/node/local/LocalNodeFactory.java | 1 - 1 file changed, 1 deletion(-) diff --git a/java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java b/java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java index b0f4f7b6301cb..d21eca5d31563 100644 --- a/java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java +++ b/java/src/org/openqa/selenium/grid/node/local/LocalNodeFactory.java @@ -17,7 +17,6 @@ package org.openqa.selenium.grid.node.local; - import java.io.File; import java.time.Duration; import java.util.ArrayList;