diff --git a/MODULE.bazel b/MODULE.bazel index 5af5598e2bfa7..89621602b8c5d 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -181,11 +181,12 @@ maven.install( "com.google.code.findbugs:jsr305:3.0.2", "com.google.code.gson:gson:2.13.1", "com.google.guava:guava:33.4.8-jre", + "com.github.ben-manes.caffeine:caffeine:3.2.2", "com.google.auto:auto-common:1.2.2", "com.google.auto.service:auto-service:1.1.1", "com.google.auto.service:auto-service-annotations:1.1.1", - "com.google.googlejavaformat:google-java-format:1.27.0", - "com.graphql-java:graphql-java:22.3", + "com.google.googlejavaformat:google-java-format:1.28.0", + "com.graphql-java:graphql-java:24.1", "dev.failsafe:failsafe:3.3.2", "io.grpc:grpc-context:1.73.0", "io.lettuce:lettuce-core:6.7.1.RELEASE", @@ -209,7 +210,7 @@ maven.install( "net.bytebuddy:byte-buddy:1.17.6", "org.htmlunit:htmlunit-core-js:4.13.0", "org.apache.commons:commons-exec:1.5.0", - "org.apache.logging.log4j:log4j-core:2.25.0", + "org.apache.logging.log4j:log4j-core:2.25.1", "org.assertj:assertj-core:3.27.3", "org.bouncycastle:bcpkix-jdk18on:1.81", "org.eclipse.mylyn.github:org.eclipse.egit.github.core:2.1.5", @@ -232,9 +233,9 @@ maven.install( "uk.org.webcompere:system-stubs-core:2.1.8", ], boms = [ - "io.opentelemetry:opentelemetry-bom:1.51.0", + "io.opentelemetry:opentelemetry-bom:1.52.0", "io.netty:netty-bom:4.1.121.Final", - "org.junit:junit-bom:5.13.2", + "org.junit:junit-bom:5.13.4", ], excluded_artifacts = [ "org.hamcrest:hamcrest-all", # Replaced by hamcrest 2 diff --git a/java/maven_install.json b/java/maven_install.json index e95c7819e1a82..957632f1ab731 100644 --- a/java/maven_install.json +++ b/java/maven_install.json @@ -1,7 +1,7 @@ { "__AUTOGENERATED_FILE_DO_NOT_MODIFY_THIS_FILE_MANUALLY": "THERE_IS_NO_DATA_ONLY_ZUUL", - "__INPUT_ARTIFACTS_HASH": -1594008950, - "__RESOLVED_ARTIFACTS_HASH": 516955126, + "__INPUT_ARTIFACTS_HASH": -1641570764, + "__RESOLVED_ARTIFACTS_HASH": 1065430654, "artifacts": { "com.beust:jcommander": { "shasums": { @@ -66,6 +66,13 @@ }, "version": "2.18.2" }, + "com.github.ben-manes.caffeine:caffeine": { + "shasums": { + "jar": "c74a6c72221dfb76eb92f2bb40108ea561a7da2f315dc3b1e64afa8f077f210c", + "sources": "2ec9bc766e34375395ca88522105efcc82247ade006848ebd8decf21bead1d7d" + }, + "version": "3.2.2" + }, "com.github.javaparser:javaparser-core": { "shasums": { "jar": "11b0deeaeb29f2496e1704c8c6f7593f14901f7253a671b81bdaa531bead779f", @@ -138,10 +145,10 @@ }, "com.google.googlejavaformat:google-java-format": { "shasums": { - "jar": "e0ac64ebc57756b2c724a202aa9b896fd79b61766671ece6f807f84f6630e301", - "sources": "e9b8550f90b3f719b1f331b7b16bf43ed585e5ff8b19728ec3f6a8d4fca86a13" + "jar": "41dfe4d1012794ed15e0ffd70f89fd4fa65d5f15ce0bc0c70f8c2c127d6d010d", + "sources": "4f39e4c06d2fbbd7ad25a800c5ad9a70cb07bc56955e44d0e4f24f660f04ce51" }, - "version": "1.27.0" + "version": "1.28.0" }, "com.google.guava:failureaccess": { "shasums": { @@ -172,17 +179,17 @@ }, "com.graphql-java:graphql-java": { "shasums": { - "jar": "8828fef5d8133d3d5ad23cee262a9b3ab4ce95aedf5e3332bb577a9aa7c627e0", - "sources": "122d4adc1c1491f86f08f6ba6206aa9f05d14a02cf36c73baad7e1d8034160a7" + "jar": "a9a9ffbbb20493b7b2ee4e07879d530096ce1b5c5cfc697bd28b9ee50daf0b1b", + "sources": "b0391a0c89d0e1fa196c68be26c5b6993cb3af43e43d53fd2f4939c2e1cbf945" }, - "version": "22.3" + "version": "24.1" }, "com.graphql-java:java-dataloader": { "shasums": { - "jar": "08cec84ac76e32b53ea666260f288f10b3731c21c89f9199b109ced2361f78b8", - "sources": "cea71f74025c2ca95618113345f888c780a99bf3133621b54007e1babaef2e14" + "jar": "de05a85f5be5a35989877ba3e23504f41903ffc0c4f3432adf34a81b479f089c", + "sources": "447746999a3cec8b26729b2d12946feaebfe4cffa6fd406d65870d202f3c0c1a" }, - "version": "3.3.0" + "version": "5.0.0" }, "commons-codec:commons-codec": { "shasums": { @@ -333,80 +340,87 @@ }, "io.opentelemetry:opentelemetry-api": { "shasums": { - "jar": "ed88c2876e5a525ccbb56eb918d7955797b9a245f113d50b9798d1634a90951d", - "sources": "1616be544d1cc6eee2a883e6acc3f30afb617651e64e4d80a30006d2b29656c5" + "jar": "9aec8dffc7abb12fc3c6157cbc32d489a27872b51784d88164ff33c750f42c3f", + "sources": "edce50bee006b6f88c0962a40831d6622275b1ecd68b66a40188a132ada1a6ef" }, - "version": "1.51.0" + "version": "1.52.0" + }, + "io.opentelemetry:opentelemetry-common": { + "shasums": { + "jar": "e1d57f66a1b47496f3259390e746ecfa5d59bece36d0b050d3df40af7c9d828c", + "sources": "7d6fa3ab47d06e510d3d2d558d7d7d797a4026343ad11ff6dd8e7d33f83feaff" + }, + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-context": { "shasums": { - "jar": "df4e308883ef2a2f28415140c5629901f72223f9ec713063f93395cff11bf4a1", - "sources": "299e253743294fb0ca777cc0f19cbb8bb9ead3fe36a0659a0c588252acf198db" + "jar": "8331dbbbaad12a9d8204e62fc1ca8088a0a55e2c4ee2e2a3569b2c12f9d157f1", + "sources": "e19ba90acace2a30ef59523d25f9335f6c0c6d61b30e0b37abe4d6a04ae38fa7" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-exporter-logging": { "shasums": { - "jar": "00c6519cc34aca5d36d09ece3b828900a4d16f935770a40c348ab02d7d084b3c", - "sources": "49ba323d0b9b90f39b3933e0c75d3874a0e4a3986a78a1ef935262236e0cb50e" + "jar": "95f63f01ac89a7f4283200f954cde0cd07fc76c3ad09e013d85e7447ef0dec1f", + "sources": "89cee143beaa868fe3a381c2b3723f2f0ab056e7d1ea7c8fe3f3f9a3baef9251" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-sdk": { "shasums": { - "jar": "728550e918f454661b4990521dc16a4a603f09d6a2840d44ac8191d6a09c5a91", - "sources": "27e65bdbd0b08084c9b810bd8323eb88be3f59bd7fe7ffcfa3a2ee4156d3916c" + "jar": "0d46744a1819dab3497b8aa6f547747961d4da090c0f9656976cc5bb5439f868", + "sources": "849c3baa1c56fa53530e7b8001ba603e8c211982e99c3f77559deb3df2fc49db" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-sdk-common": { "shasums": { - "jar": "0454b7e14f09dbae3817b85c1b89bfe9ad9f3ae87f1aa8508689567ea5599921", - "sources": "8450f5b63609afe6c609150f6d21dc59b2a174d9959436b023fdd80d37d53a54" + "jar": "1688bbe9d1a3ac8df114b4d7664fc0958d2a744d850f7a8d524fc3a158614756", + "sources": "d2cd7fa57bee9de53f4aebfa99b71511fc514d1fb4a43b78ea061b060586dd41" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure": { "shasums": { - "jar": "8c3db344efb69a60a9cfb72ca51e06a0945440f361dfe002883c0ef447d0868e", - "sources": "6c816fd791d81a16c0319abfbb0defc846e4141d0070f8328475722cc8904ffe" + "jar": "63b6b0b5be43346ffc11af2f34be420e4ce8256ece281b933a7021acedb9ed88", + "sources": "d53a72eae17974ed4d1898f2664a4ed823834bb85e54bddf338c74fdad56196b" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi": { "shasums": { - "jar": "e910ce6aedb71cbb585dcf1666822c6dde47f46cbbc8dbf25b16f8c27eb56c34", - "sources": "c8eccf7d7e45d7405e611416f7606ceb1b35ab750b93a3dca89f4e07f913da02" + "jar": "43f31566973ac92958cdc44e8f875e5bc2c0af4f40fb450a4e1bb27178ab2cf7", + "sources": "d89970c106d9d7f0a1ccdb016f30cfcbd253a6f143df2ea46e48dc536ffe6908" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-sdk-logs": { "shasums": { - "jar": "841623859d6d3fb3035521cb665638d696b7845c8b7a65c9f48d667a0063b1e0", - "sources": "f596a3d87eebf9dff24712a216260d01c6329e8e78f5b9ecc880ff03484f4632" + "jar": "8f537c60bb068d7b8fe0e4abdd6ccbd2802c4fdde9f338f8db6f35c1970a5d23", + "sources": "68de4baefea9c130cc7a16b9d10a3fb72b9d6d8a65a3ee66a4595bfd8b7221ef" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-sdk-metrics": { "shasums": { - "jar": "77d78294a5d9861565164999c1881e75abf5af98d6901ff4c6d6731ce169c31c", - "sources": "8297d9ea8654022886fa4514f902b1e7ea11cccaf4f4cb28de9d23ada4251cea" + "jar": "e702509ae1c741afb3e120471eaa019f8f89fbe28b077a43f7cc44e9de226142", + "sources": "66023e9a27628459ad961bfc9843b456151763e71c1292f2c54ef81c854fbc95" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-sdk-testing": { "shasums": { - "jar": "b3d5efe1cff44c4da8cfcb55f918e3de6bbd75ba1ca3d1612d27046cc98e1cc4", - "sources": "7545648c8e72111613e4aa8cddc49f8fbfc6cedcf9992c160bc9bbffdb542691" + "jar": "3485d571bf7925700384129773114316bedf8a45874f6bbf02182934d38e614d", + "sources": "5cfa44ddd26e952a9f9b3ecf04e699914155f1cdbb777e0d4b0f1abb6f8232f3" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.opentelemetry:opentelemetry-sdk-trace": { "shasums": { - "jar": "5300c485d63e425925600f2daa9e7bbd9f81bd28dfc14a62922d9f46150fe730", - "sources": "8cd34f066fcc654c67082a597a0cb0af28b6fef988976221a4530f1f0281375a" + "jar": "10e634cc864b26926b89313b0afa5083f7477b5e00fd21e97ee5443c17fe7fed", + "sources": "b5b9246d4e78637f6c223c62be5dbf36053ee70f4a514e8e0b3a4cfe0f9fdc73" }, - "version": "1.51.0" + "version": "1.52.0" }, "io.projectreactor:reactor-core": { "shasums": { @@ -522,17 +536,17 @@ }, "org.apache.logging.log4j:log4j-api": { "shasums": { - "jar": "0393e32167240eb56597a2016446928755729f1a181046cab5d42a81d0e3d909", - "sources": "ee7c4c0666d2a68318235ad460b20167c1ef43f11d82102ff8efa24c3c6126e1" + "jar": "20b9c77c0a9e54d1063a39e551dcaf98c7d8e7a4994648f84d0b9e14c71f7215", + "sources": "bade3b617cb729fac9d3b82561b40f5e5e84a80ee3621f5351acbc9d35d0630d" }, - "version": "2.25.0" + "version": "2.25.1" }, "org.apache.logging.log4j:log4j-core": { "shasums": { - "jar": "05d3eecb9e509fd47117c0fb43c7b4b2989b28ecd5543ad5feff2e4903d3c921", - "sources": "04ef64e63c024f19b4e0e440974663eff64de85d9686923c7c49342d0897a425" + "jar": "78c232747855464b182f0abf78a99a22c88d4d270ff585343dab55576d7420e2", + "sources": "9a825f8687580e0a3ef46950d1aecc597cd0cbc6a2c667a8dc69fdf2ddc40251" }, - "version": "2.25.0" + "version": "2.25.1" }, "org.apiguardian:apiguardian-api": { "shasums": { @@ -620,52 +634,52 @@ }, "org.junit.jupiter:junit-jupiter-api": { "shasums": { - "jar": "b8be2faf8cd55b37063f7c57ca2bf4c0b5437706f838b2e4ff9d36f80da2ee93", - "sources": "fdbdad05b87c2fc2747e6a229055490453705f15eddafeb44a9d873a8f1d91b8" + "jar": "d1bb81abfd9e03418306b4e6a3390c8db52c58372e749c2980ac29f0c08278f1", + "sources": "c6d33325ffa47307b795c13cb227f002417eebf0927e40487159c53938f2793e" }, - "version": "5.13.2" + "version": "5.13.4" }, "org.junit.jupiter:junit-jupiter-engine": { "shasums": { - "jar": "4f923403fbc5322773233573ce9e85566870a0c85a8a06a8413e101dd044b16b", - "sources": "1c68d58437df1e3194ce2132f3db44a5248b1218561c9919f228c0160870cd93" + "jar": "027404a92fe618b72465792a257951495c503a7d5751e2791e0f51c87f67f5bc", + "sources": "14b5458d4bd2b103945f4b31daab17d66709b2b90efdb1556829adcff098beec" }, - "version": "5.13.2" + "version": "5.13.4" }, "org.junit.jupiter:junit-jupiter-params": { "shasums": { - "jar": "78ba43b19211c73b81e0e61f5f7b1740cc311f3bf11e781c6364c765f074fbc7", - "sources": "631a6579218482972d61bfa75d8e69b2189dbeefdc4fe3b59455c6daa85df050" + "jar": "3a8c6365716dbb698c0d49a05456c1e1ad05c406613c550f9dd50037872efc41", + "sources": "173be0fd56d5befb60e4ee812eb3e1faea05181ec948299661592222aef0e352" }, - "version": "5.13.2" + "version": "5.13.4" }, "org.junit.platform:junit-platform-commons": { "shasums": { - "jar": "81fbaa06a392448a01e59de1427cef27bb88485ec2d2ed64dc8a31f5440851c0", - "sources": "959e9410d65ca3547132c52c8f59d642854ec464a0f42e050dc8d18bc6d9ec67" + "jar": "1c25ca641ebaae44ff3ad21ca1b2ef68d0dd84bfeb07c4805ba7840899b77408", + "sources": "8bf2533dc967499bbb957a7b1cd0be471a0794d8d792fcb47c66393edfa66503" }, - "version": "1.13.2" + "version": "1.13.4" }, "org.junit.platform:junit-platform-engine": { "shasums": { - "jar": "a34d5c2f30c030cda538d53952fbd886d15b515ebeb23b3d155c185cfbafaf89", - "sources": "5627c372ce0522ed8a7208c8867bbdf3dc21d62130eda854c1ad3975be807f29" + "jar": "390c5f77b84283a64b644f88251b397e0b0debb80bdcc50f899881aecff43a5a", + "sources": "a460d1398df481d6bc6e8e41646fb2f71dfa6e1d3514a571c97ed3c86846f1ec" }, - "version": "1.13.2" + "version": "1.13.4" }, "org.junit.platform:junit-platform-launcher": { "shasums": { - "jar": "ed6443f731e8929eb8bca5619b535f33ffd19b3435396faca700d7dda87ef7bc", - "sources": "d47a3aafed3e9b559b9454c90f935ef5899d645aa763c24230b2aeeec68ce07a" + "jar": "0b0beaeb6880a31149641d2d848b863712885469670c12099586d7f798522564", + "sources": "58ac8333e2c8f414360f9e980c4d1b88f2bf82851632977f862baa490cecc2b8" }, - "version": "1.13.2" + "version": "1.13.4" }, "org.junit.platform:junit-platform-reporting": { "shasums": { - "jar": "642603d1d3a6162dd8b74cbf7b2941c0a1af4a5852bafe901e31051c1303de76", - "sources": "4caa415f007731c8dcd94bc287371f885a05cb8a63baef09f98dd8a514a06b0d" + "jar": "7ebeb4ad2d39a61507623e4c6185651c2bcf560dd378f13229ed2492847c21f6", + "sources": "4f69f617050be577f2f035dc66f500614a5a1cfdeaca6b4965482cd9e5428fa0" }, - "version": "1.13.2" + "version": "1.13.4" }, "org.mockito:mockito-core": { "shasums": { @@ -818,6 +832,7 @@ }, "conflict_resolution": { "com.google.errorprone:error_prone_annotations:2.36.0": "com.google.errorprone:error_prone_annotations:2.38.0", + "com.google.errorprone:error_prone_annotations:2.40.0": "com.google.errorprone:error_prone_annotations:2.38.0", "io.projectreactor:reactor-core:3.6.2": "io.projectreactor:reactor-core:3.6.6", "net.bytebuddy:byte-buddy-agent:1.17.4": "net.bytebuddy:byte-buddy-agent:1.17.5", "org.apache.commons:commons-lang3:3.14.0": "org.apache.commons:commons-lang3:3.17.0", @@ -844,6 +859,10 @@ "com.fasterxml.jackson.core:jackson-core", "com.fasterxml.jackson.core:jackson-databind" ], + "com.github.ben-manes.caffeine:caffeine": [ + "com.google.errorprone:error_prone_annotations", + "org.jspecify:jspecify" + ], "com.github.spotbugs:spotbugs": [ "com.github.spotbugs:spotbugs-annotations", "com.github.stephenc.jcip:jcip-annotations", @@ -888,10 +907,12 @@ ], "com.graphql-java:graphql-java": [ "com.graphql-java:java-dataloader", + "org.jspecify:jspecify", "org.reactivestreams:reactive-streams" ], "com.graphql-java:java-dataloader": [ - "org.slf4j:slf4j-api" + "org.jspecify:jspecify", + "org.reactivestreams:reactive-streams" ], "io.grpc:grpc-context": [ "io.grpc:grpc-api" @@ -980,6 +1001,9 @@ "io.opentelemetry:opentelemetry-api": [ "io.opentelemetry:opentelemetry-context" ], + "io.opentelemetry:opentelemetry-context": [ + "io.opentelemetry:opentelemetry-common" + ], "io.opentelemetry:opentelemetry-exporter-logging": [ "io.opentelemetry:opentelemetry-sdk", "io.opentelemetry:opentelemetry-sdk-extension-autoconfigure-spi" @@ -1252,6 +1276,10 @@ "com.fasterxml.jackson.datatype.jsr310.ser.key", "com.fasterxml.jackson.datatype.jsr310.util" ], + "com.github.ben-manes.caffeine:caffeine": [ + "com.github.benmanes.caffeine.cache", + "com.github.benmanes.caffeine.cache.stats" + ], "com.github.javaparser:javaparser-core": [ "com.github.javaparser", "com.github.javaparser.ast", @@ -1427,7 +1455,6 @@ "graphql.execution.instrumentation.dataloader", "graphql.execution.instrumentation.fieldvalidation", "graphql.execution.instrumentation.parameters", - "graphql.execution.instrumentation.threadpools", "graphql.execution.instrumentation.tracing", "graphql.execution.preparsed", "graphql.execution.preparsed.persisted", @@ -1441,6 +1468,7 @@ "graphql.language", "graphql.normalized", "graphql.normalized.incremental", + "graphql.normalized.nf", "graphql.org.antlr.v4.runtime", "graphql.org.antlr.v4.runtime.atn", "graphql.org.antlr.v4.runtime.dfa", @@ -1475,6 +1503,8 @@ "org.dataloader", "org.dataloader.annotations", "org.dataloader.impl", + "org.dataloader.instrumentation", + "org.dataloader.reactive", "org.dataloader.registries", "org.dataloader.scheduler", "org.dataloader.stats", @@ -1693,6 +1723,9 @@ "io.opentelemetry.api.trace.propagation", "io.opentelemetry.api.trace.propagation.internal" ], + "io.opentelemetry:opentelemetry-common": [ + "io.opentelemetry.common" + ], "io.opentelemetry:opentelemetry-context": [ "io.opentelemetry.context", "io.opentelemetry.context.internal.shaded", @@ -2988,6 +3021,8 @@ "com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:jar:sources", "com.fasterxml.jackson.datatype:jackson-datatype-jsr310", "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:jar:sources", + "com.github.ben-manes.caffeine:caffeine", + "com.github.ben-manes.caffeine:caffeine:jar:sources", "com.github.javaparser:javaparser-core", "com.github.javaparser:javaparser-core:jar:sources", "com.github.spotbugs:spotbugs", @@ -3065,6 +3100,8 @@ "io.netty:netty-transport:jar:sources", "io.opentelemetry:opentelemetry-api", "io.opentelemetry:opentelemetry-api:jar:sources", + "io.opentelemetry:opentelemetry-common", + "io.opentelemetry:opentelemetry-common:jar:sources", "io.opentelemetry:opentelemetry-context", "io.opentelemetry:opentelemetry-context:jar:sources", "io.opentelemetry:opentelemetry-exporter-logging", diff --git a/java/src/org/openqa/selenium/grid/graphql/BUILD.bazel b/java/src/org/openqa/selenium/grid/graphql/BUILD.bazel index 4fc0d84d5aa70..a9a9c0a7b5953 100644 --- a/java/src/org/openqa/selenium/grid/graphql/BUILD.bazel +++ b/java/src/org/openqa/selenium/grid/graphql/BUILD.bazel @@ -21,5 +21,6 @@ java_library( "//java/src/org/openqa/selenium/remote/http", artifact("com.google.guava:guava"), artifact("com.graphql-java:graphql-java"), + artifact("com.github.ben-manes.caffeine:caffeine"), ], ) diff --git a/java/src/org/openqa/selenium/grid/graphql/GraphqlHandler.java b/java/src/org/openqa/selenium/grid/graphql/GraphqlHandler.java index 3ab7a7385f701..3cef83ef69faf 100644 --- a/java/src/org/openqa/selenium/grid/graphql/GraphqlHandler.java +++ b/java/src/org/openqa/selenium/grid/graphql/GraphqlHandler.java @@ -28,8 +28,9 @@ import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE; import static org.openqa.selenium.remote.tracing.Tags.HTTP_RESPONSE_EVENT; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.Weigher; import graphql.ExecutionInput; import graphql.ExecutionResult; import graphql.GraphQL; @@ -43,10 +44,11 @@ import java.io.InputStream; import java.io.UncheckedIOException; import java.net.URI; +import java.nio.charset.StandardCharsets; +import java.time.Duration; import java.util.HashMap; import java.util.Map; import java.util.concurrent.CompletableFuture; -import java.util.concurrent.ExecutionException; import org.openqa.selenium.grid.distributor.Distributor; import org.openqa.selenium.grid.sessionqueue.NewSessionQueue; import org.openqa.selenium.internal.Require; @@ -61,17 +63,19 @@ import org.openqa.selenium.remote.tracing.Status; import org.openqa.selenium.remote.tracing.Tracer; -public class GraphqlHandler implements HttpHandler { +public class GraphqlHandler implements HttpHandler, AutoCloseable { public static final String GRID_SCHEMA = "/org/openqa/selenium/grid/graphql/selenium-grid-schema.graphqls"; public static final Json JSON = new Json(); + private static final long MAX_QUERY_SIZE_BYTES = 1024 * 1024; // 1MB limit private final Tracer tracer; private final Distributor distributor; private final NewSessionQueue newSessionQueue; private final URI publicUri; private final String version; private final GraphQL graphQl; + private final Cache> cache; public GraphqlHandler( Tracer tracer, @@ -85,31 +89,43 @@ public GraphqlHandler( this.version = Require.nonNull("GridVersion", version); this.tracer = Require.nonNull("Tracer", tracer); + // Container-aware cache sizing: 5% of heap memory + long maxMemory = Runtime.getRuntime().maxMemory(); + long cacheWeightLimit = (long) (maxMemory * 0.05); + + // Custom weigher to prevent single entries from exceeding 10% of cache weight + Weigher> weigher = + new QueryCacheWeigher(cacheWeightLimit); + + this.cache = + Caffeine.newBuilder() + .maximumWeight(cacheWeightLimit) + .weigher(weigher) + .expireAfterAccess(Duration.ofMinutes(30)) // Time-based eviction + .build(); + GraphQLSchema schema = new SchemaGenerator() .makeExecutableSchema(buildTypeDefinitionRegistry(), buildRuntimeWiring()); - Cache> cache = - CacheBuilder.newBuilder().maximumSize(1024).build(); - graphQl = GraphQL.newGraphQL(schema) .preparsedDocumentProvider( (executionInput, computeFunction) -> { - try { - return cache.get( - executionInput.getQuery(), - () -> - CompletableFuture.supplyAsync( - () -> computeFunction.apply(executionInput))); - } catch (ExecutionException e) { - if (e.getCause() instanceof RuntimeException) { - throw (RuntimeException) e.getCause(); - } else if (e.getCause() != null) { - throw new RuntimeException(e.getCause()); - } - throw new RuntimeException(e); + String query = executionInput.getQuery(); + + // Query size validation with bypass for oversized queries + if (query.getBytes(StandardCharsets.UTF_8).length > MAX_QUERY_SIZE_BYTES) { + // Bypass cache for oversized queries to prevent cache pollution + return CompletableFuture.supplyAsync( + () -> computeFunction.apply(executionInput)); } + + return cache.get( + query, + key -> + CompletableFuture.supplyAsync( + () -> computeFunction.apply(executionInput))); }) .build(); } @@ -189,6 +205,24 @@ public HttpResponse execute(HttpRequest req) throws UncheckedIOException { } } + @Override + public void close() { + // Cancel pending CompletableFutures + cache + .asMap() + .values() + .forEach( + future -> { + if (!future.isDone()) { + future.cancel(true); + } + }); + + // Invalidate and clean cache + cache.invalidateAll(); + cache.cleanUp(); + } + private RuntimeWiring buildRuntimeWiring() { GridData gridData = new GridData(distributor, newSessionQueue, publicUri, version); return RuntimeWiring.newRuntimeWiring() @@ -212,4 +246,29 @@ private TypeDefinitionRegistry buildTypeDefinitionRegistry() { throw new UncheckedIOException(e); } } + + // Custom weigher class for query cache + private static class QueryCacheWeigher + implements Weigher> { + + private final long maxSingleEntryWeight; + + public QueryCacheWeigher(long cacheWeightLimit) { + this.maxSingleEntryWeight = (long) (cacheWeightLimit * 0.1); // 10% limit + } + + @Override + public int weigh(String key, CompletableFuture value) { + // Estimate memory usage including CompletableFuture overhead + long keyWeight = key.length() * 2; // UTF-16 encoding + long futureOverhead = 200; // Estimated CompletableFuture overhead + long documentOverhead = 500; // Estimated PreparsedDocumentEntry overhead + + long totalWeight = keyWeight + futureOverhead + documentOverhead; + + // Bounds checking to prevent single entries from dominating cache and integer overflow + long boundedWeight = Math.min(totalWeight, maxSingleEntryWeight); + return (int) Math.min(boundedWeight, Integer.MAX_VALUE); + } + } } diff --git a/java/src/org/openqa/selenium/grid/node/local/BUILD.bazel b/java/src/org/openqa/selenium/grid/node/local/BUILD.bazel index b3a6839819e14..3a29f82adb381 100644 --- a/java/src/org/openqa/selenium/grid/node/local/BUILD.bazel +++ b/java/src/org/openqa/selenium/grid/node/local/BUILD.bazel @@ -28,5 +28,6 @@ java_library( "//java/src/org/openqa/selenium/json", "//java/src/org/openqa/selenium/remote", artifact("com.google.guava:guava"), + artifact("com.github.ben-manes.caffeine:caffeine"), ], ) 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 8561d77d2e2f5..91f52d16c31c5 100644 --- a/java/src/org/openqa/selenium/grid/node/local/LocalNode.java +++ b/java/src/org/openqa/selenium/grid/node/local/LocalNode.java @@ -31,13 +31,11 @@ import static org.openqa.selenium.remote.http.Contents.string; import static org.openqa.selenium.remote.http.HttpMethod.DELETE; +import com.github.benmanes.caffeine.cache.Cache; +import com.github.benmanes.caffeine.cache.Caffeine; +import com.github.benmanes.caffeine.cache.RemovalCause; +import com.github.benmanes.caffeine.cache.Ticker; import com.google.common.annotations.VisibleForTesting; -import com.google.common.base.Ticker; -import com.google.common.cache.Cache; -import com.google.common.cache.CacheBuilder; -import com.google.common.cache.RemovalCause; -import com.google.common.cache.RemovalListener; -import com.google.common.cache.RemovalNotification; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableMap; import java.io.Closeable; @@ -57,7 +55,6 @@ import java.util.Optional; import java.util.Set; import java.util.UUID; -import java.util.concurrent.ExecutionException; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @@ -201,35 +198,35 @@ protected LocalNode( // Do not clear this cache automatically using a timer. // It will be explicitly cleaned up, as and when "currentSessions" is auto cleaned. this.uploadsTempFileSystem = - CacheBuilder.newBuilder() + Caffeine.newBuilder() .removalListener( - (RemovalListener) - notification -> - Optional.ofNullable(notification.getValue()) - .ifPresent( - tempFS -> { - tempFS.deleteTemporaryFiles(); - tempFS.deleteBaseDir(); - })) + (SessionId key, TemporaryFilesystem tempFS, RemovalCause cause) -> { + Optional.ofNullable(tempFS) + .ifPresent( + fs -> { + fs.deleteTemporaryFiles(); + fs.deleteBaseDir(); + }); + }) .build(); // Do not clear this cache automatically using a timer. // It will be explicitly cleaned up, as and when "currentSessions" is auto cleaned. this.downloadsTempFileSystem = - CacheBuilder.newBuilder() + Caffeine.newBuilder() .removalListener( - (RemovalListener) - notification -> - Optional.ofNullable(notification.getValue()) - .ifPresent( - fs -> { - fs.deleteTemporaryFiles(); - fs.deleteBaseDir(); - })) + (SessionId key, TemporaryFilesystem tempFS, RemovalCause cause) -> { + Optional.ofNullable(tempFS) + .ifPresent( + fs -> { + fs.deleteTemporaryFiles(); + fs.deleteBaseDir(); + }); + }) .build(); this.currentSessions = - CacheBuilder.newBuilder() + Caffeine.newBuilder() .expireAfterAccess(sessionTimeout) .ticker(ticker) .removalListener(this::stopTimedOutSession) @@ -314,19 +311,17 @@ public void close() { shutdown.run(); } - private void stopTimedOutSession(RemovalNotification notification) { + private void stopTimedOutSession(SessionId id, SessionSlot slot, RemovalCause cause) { try (Span span = tracer.getCurrentContext().createSpan("node.stop_session")) { AttributeMap attributeMap = tracer.createAttributeMap(); attributeMap.put(AttributeKey.LOGGER_CLASS.getKey(), getClass().getName()); - if (notification.getKey() != null && notification.getValue() != null) { - SessionSlot slot = notification.getValue(); - SessionId id = notification.getKey(); + if (id != null && slot != null) { attributeMap.put("node.id", getId().toString()); attributeMap.put("session.slotId", slot.getId().toString()); attributeMap.put("session.id", id.toString()); attributeMap.put("session.timeout_in_seconds", getSessionTimeout().toSeconds()); - attributeMap.put("session.remove.cause", notification.getCause().name()); - if (notification.wasEvicted() && notification.getCause() == RemovalCause.EXPIRED) { + attributeMap.put("session.remove.cause", cause.name()); + if (cause == RemovalCause.EXPIRED) { // Session is timing out, stopping it by sending a DELETE LOG.log(Level.INFO, () -> String.format("Session id %s timed out, stopping...", id)); span.setStatus(Status.CANCELLED); @@ -335,7 +330,7 @@ private void stopTimedOutSession(RemovalNotification not LOG.log(Level.INFO, () -> String.format("Session id %s is stopping on demand...", id)); span.addEvent(String.format("Stopping the session %s on demand", id), attributeMap); } - if (notification.wasEvicted()) { + if (cause == RemovalCause.EXPIRED) { try { slot.execute(new HttpRequest(DELETE, "/session/" + id)); } catch (Exception e) { @@ -687,15 +682,11 @@ public Session getSession(SessionId id) throws NoSuchSessionException { @Override public TemporaryFilesystem getUploadsFilesystem(SessionId id) throws IOException { - try { - return uploadsTempFileSystem.get( - id, - () -> - TemporaryFilesystem.getTmpFsBasedOn( - TemporaryFilesystem.getDefaultTmpFS().createTempDir("session", id.toString()))); - } catch (ExecutionException e) { - throw new IOException(e); - } + return uploadsTempFileSystem.get( + id, + key -> + TemporaryFilesystem.getTmpFsBasedOn( + TemporaryFilesystem.getDefaultTmpFS().createTempDir("session", id.toString()))); } @Override @@ -863,10 +854,8 @@ public void stop(SessionId id) throws NoSuchSessionException { } private void stopAllSessions() { - if (currentSessions.size() > 0) { - LOG.info("Trying to stop all running sessions before shutting down..."); - currentSessions.invalidateAll(); - } + LOG.info("Trying to stop all running sessions before shutting down..."); + currentSessions.invalidateAll(); } private Session createExternalSession(