Skip to content

Commit 9cd26d5

Browse files
authored
[java] Fix concurrency issue in Selenium Manager (#16315)
#16314 fix concurrency issue in Selenium Manager ... when executed by 2+ processes simultaneously on a machine with empty Selenium cache. Every process sees the file created by another process only when the file is fully completed.
1 parent fde053a commit 9cd26d5

File tree

1 file changed

+29
-4
lines changed

1 file changed

+29
-4
lines changed

java/src/org/openqa/selenium/manager/SeleniumManager.java

Lines changed: 29 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616
// under the License.
1717
package org.openqa.selenium.manager;
1818

19+
import static java.nio.file.StandardCopyOption.REPLACE_EXISTING;
20+
import static java.util.Objects.requireNonNull;
21+
import static java.util.UUID.randomUUID;
1922
import static org.openqa.selenium.Platform.LINUX;
2023
import static org.openqa.selenium.Platform.MAC;
2124
import static org.openqa.selenium.Platform.UNIX;
@@ -213,11 +216,10 @@ private synchronized Path getBinary() {
213216
}
214217

215218
binary = getBinaryInCache(SELENIUM_MANAGER + extension);
216-
if (!binary.toFile().exists()) {
217-
String binaryPathInJar = String.format("%s/%s%s", folder, SELENIUM_MANAGER, extension);
218-
try (InputStream inputStream = this.getClass().getResourceAsStream(binaryPathInJar)) {
219+
if (!Files.exists(binary)) {
220+
try (InputStream inputStream = findBinaryInClasspath(folder, extension)) {
219221
Files.createDirectories(binary.getParent());
220-
Files.copy(inputStream, binary);
222+
saveToFileSafely(inputStream, binary);
221223
}
222224
}
223225
} catch (Exception e) {
@@ -233,6 +235,29 @@ private synchronized Path getBinary() {
233235
return binary;
234236
}
235237

238+
/**
239+
* Protect from concurrency issue when executed by 2+ processes simultaneously. Every process sees
240+
* the file created by another process only when the file is fully completed.
241+
*/
242+
private void saveToFileSafely(InputStream inputStream, Path target) throws IOException {
243+
Path temporaryFile = target.resolveSibling(target.getFileName() + "." + randomUUID() + ".tmp");
244+
Files.copy(inputStream, temporaryFile);
245+
try {
246+
if (!Files.exists(target)) {
247+
Files.move(temporaryFile, target, REPLACE_EXISTING);
248+
}
249+
} finally {
250+
Files.deleteIfExists(temporaryFile);
251+
}
252+
}
253+
254+
private InputStream findBinaryInClasspath(String folder, String extension) {
255+
String binaryPathInJar = String.format("%s/%s%s", folder, SELENIUM_MANAGER, extension);
256+
return requireNonNull(
257+
getClass().getResourceAsStream(binaryPathInJar),
258+
() -> "Resource not found in classpath: " + binaryPathInJar);
259+
}
260+
236261
/**
237262
* Executes Selenium Manager to get the locations of the requested assets
238263
*

0 commit comments

Comments
 (0)