Skip to content

Commit 07c4f2b

Browse files
committed
refactor: Migrate to new Selenium API for process management
1 parent 735e9fb commit 07c4f2b

File tree

1 file changed

+17
-54
lines changed

1 file changed

+17
-54
lines changed

src/main/java/io/appium/java_client/service/local/AppiumDriverLocalService.java

Lines changed: 17 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,9 @@
1717
package io.appium.java_client.service.local;
1818

1919
import com.google.common.annotations.VisibleForTesting;
20-
import io.appium.java_client.internal.ReflectionHelpers;
2120
import lombok.SneakyThrows;
2221
import org.openqa.selenium.net.UrlChecker;
23-
import org.openqa.selenium.os.CommandLine;
22+
import org.openqa.selenium.os.ExternalProcess;
2423
import org.openqa.selenium.remote.service.DriverService;
2524
import org.slf4j.Logger;
2625
import org.slf4j.LoggerFactory;
@@ -49,6 +48,7 @@
4948
import static io.appium.java_client.service.local.AppiumServiceBuilder.BROADCAST_IP4_ADDRESS;
5049
import static io.appium.java_client.service.local.AppiumServiceBuilder.BROADCAST_IP6_ADDRESS;
5150
import static java.util.Objects.requireNonNull;
51+
import static java.util.Optional.ofNullable;
5252
import static org.slf4j.event.Level.DEBUG;
5353
import static org.slf4j.event.Level.INFO;
5454

@@ -70,7 +70,7 @@ public final class AppiumDriverLocalService extends DriverService {
7070
private final URL url;
7171
private String basePath;
7272

73-
private CommandLine process = null;
73+
private ExternalProcess process = null;
7474

7575
AppiumDriverLocalService(String ipAddress, File nodeJSExec,
7676
int nodeJSPort, Duration startupTimeout,
@@ -126,7 +126,7 @@ public URL getUrl() {
126126
public boolean isRunning() {
127127
lock.lock();
128128
try {
129-
if (process == null || !process.isRunning()) {
129+
if (process == null || !process.isAlive()) {
130130
return false;
131131
}
132132

@@ -172,17 +172,15 @@ public void start() throws AppiumServerHasNotBeenStartedLocallyException {
172172
}
173173

174174
try {
175-
process = new CommandLine(
176-
this.nodeJSExec.getCanonicalPath(),
177-
nodeJSArgs.toArray(new String[]{})
178-
);
179-
process.setEnvironmentVariables(nodeJSEnvironment);
180-
process.copyOutputTo(stream);
181-
process.executeAsync();
175+
ExternalProcess.Builder processBuilder = ExternalProcess.builder()
176+
.command(this.nodeJSExec.getCanonicalPath(), nodeJSArgs)
177+
.copyOutputTo(stream);
178+
nodeJSEnvironment.forEach(processBuilder::environment);
179+
process = processBuilder.start();
182180
ping(startupTimeout);
183181
} catch (Exception e) {
184-
final Optional<String> output = Optional.ofNullable(process)
185-
.map(CommandLine::getStdOut)
182+
final Optional<String> output = ofNullable(process)
183+
.map(ExternalProcess::getOutput)
186184
.filter(o -> !isNullOrEmpty(o));
187185
destroyProcess();
188186
List<String> errorLines = new ArrayList<>();
@@ -227,47 +225,16 @@ public void stop() {
227225
}
228226
}
229227

230-
/**
231-
* Destroys the service if it is running.
232-
*
233-
* @param timeout The maximum time to wait before the process will be force-killed.
234-
* @return The exit code of the process or zero if the process was not running.
235-
*/
236-
private int destroyProcess(Duration timeout) {
237-
if (process == null || !process.isRunning()) {
238-
return 0;
239-
}
240-
241-
// This all magic is necessary, because Selenium does not publicly expose
242-
// process killing timeouts. By default a process is killed forcibly if
243-
// it does not exit after two seconds, which is in most cases not enough for
244-
// Appium
245-
try {
246-
Object osProcess = ReflectionHelpers.getPrivateFieldValue(
247-
process.getClass(), process, "process", Object.class
248-
);
249-
Object watchdog = ReflectionHelpers.getPrivateFieldValue(
250-
osProcess.getClass(), osProcess, "executeWatchdog", Object.class
251-
);
252-
Process nativeProcess = ReflectionHelpers.getPrivateFieldValue(
253-
watchdog.getClass(), watchdog, "process", Process.class
254-
);
255-
nativeProcess.destroy();
256-
nativeProcess.waitFor(timeout.toMillis(), TimeUnit.MILLISECONDS);
257-
} catch (Exception e) {
258-
LOG.warn("No explicit timeout could be applied to the process termination", e);
259-
}
260-
261-
return process.destroy();
262-
}
263-
264228
/**
265229
* Destroys the service.
266-
* This methods waits up to `DESTROY_TIMEOUT` seconds for the Appium service
230+
* This method waits up to `DESTROY_TIMEOUT` seconds for the Appium service
267231
* to exit gracefully.
268232
*/
269233
private void destroyProcess() {
270-
destroyProcess(DESTROY_TIMEOUT);
234+
if (process == null || !process.isAlive()) {
235+
return;
236+
}
237+
process.shutdown(DESTROY_TIMEOUT);
271238
}
272239

273240
/**
@@ -277,11 +244,7 @@ private void destroyProcess() {
277244
*/
278245
@Nullable
279246
public String getStdOut() {
280-
if (process != null) {
281-
return process.getStdOut();
282-
}
283-
284-
return null;
247+
return ofNullable(process).map(ExternalProcess::getOutput).orElse(null);
285248
}
286249

287250
/**

0 commit comments

Comments
 (0)