Skip to content

Commit 9e21e4e

Browse files
authored
Use ProcessBuilder, not deprecated CommandLine (#278)
1 parent 554677c commit 9e21e4e

File tree

6 files changed

+580
-93
lines changed

6 files changed

+580
-93
lines changed

src/main/java/com/nordstrom/automation/selenium/examples/ExamplePage.java

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
11
package com.nordstrom.automation.selenium.examples;
22

3+
import java.io.IOException;
34
import java.net.URI;
45
import java.net.URISyntaxException;
56
import java.net.URL;
67
import java.util.Arrays;
78
import java.util.List;
89
import java.util.Map;
910

10-
import org.apache.http.client.utils.URIBuilder;
1111
import org.openqa.selenium.By;
1212
import org.openqa.selenium.SearchContext;
1313
import org.openqa.selenium.WebDriver;
@@ -20,6 +20,7 @@
2020
import com.nordstrom.automation.selenium.model.Page;
2121
import com.nordstrom.automation.selenium.model.RobustWebElement;
2222
import com.nordstrom.automation.selenium.servlet.ExamplePageLauncher;
23+
import com.nordstrom.common.uri.UriUtils;
2324

2425
@PageUrl("/grid/admin/ExamplePageServlet")
2526
public class ExamplePage extends Page {
@@ -265,15 +266,11 @@ public static URI setHubAsTarget() {
265266
} else {
266267
// get URL of Selenium Grid hub server
267268
URL hubUrl = config.getSeleniumGrid().getHubServer().getUrl();
268-
// assemble hub base URI
269-
targetUri = new URIBuilder()
270-
.setScheme(hubUrl.getProtocol())
271-
.setHost(hubUrl.getHost())
272-
.setPort(hubUrl.getPort())
273-
.build().normalize();
269+
// get base URI of grid hub server
270+
targetUri = UriUtils.uriForPath(hubUrl);
274271
}
275272
config.setTargetUri(targetUri);
276-
} catch (URISyntaxException eaten) {
273+
} catch (URISyntaxException | IOException eaten) {
277274
// nothing to do here
278275
}
279276
return targetUri;

src/main/java/com/nordstrom/automation/selenium/exceptions/GridServerLaunchFailedException.java

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.nordstrom.automation.selenium.exceptions;
22

3-
import java.io.IOException;
4-
53
/**
64
* Thrown if a Grid component process failed to start.
75
*/
@@ -16,7 +14,7 @@ public class GridServerLaunchFailedException extends RuntimeException {
1614
* @param role Grid server role specifier ({@code hub} or {@code node})
1715
* @param cause the cause of this exception
1816
*/
19-
public GridServerLaunchFailedException(final String role, final IOException cause) {
17+
public GridServerLaunchFailedException(final String role, final Throwable cause) {
2018
super(getMessage(role), cause);
2119
}
2220

src/main/java/com/nordstrom/automation/selenium/servlet/ExamplePageLauncher.java

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,46 @@
11
package com.nordstrom.automation.selenium.servlet;
22

33
import java.io.File;
4+
import java.io.IOException;
45
import java.net.MalformedURLException;
56
import java.net.URI;
67
import java.net.URL;
78
import java.util.ArrayList;
89
import java.util.List;
9-
import org.openqa.selenium.os.CommandLine;
1010

1111
import com.nordstrom.automation.selenium.core.GridUtility;
1212
import com.nordstrom.automation.selenium.examples.ServletContainer;
1313
import com.nordstrom.common.file.PathUtils;
1414
import com.nordstrom.common.jar.JarUtils;
1515

16-
@SuppressWarnings("deprecation")
1716
public class ExamplePageLauncher {
1817

1918
public enum Container {
2019
INSTANCE;
2120

22-
private final CommandLine process;
21+
private final ProcessBuilder builder;
22+
private Process process;
2323
private boolean hasStarted = false;
2424
private boolean isActive = false;
2525

2626
private Container() {
2727
List<String> argsList = new ArrayList<>();
28+
argsList.add(System.getProperty("java.home") + File.separator + "bin" + File.separator + "java");
2829
argsList.add("-cp");
2930
argsList.add(JarUtils.getContextPaths(ServletContainer.getDependencyContexts()).get(0));
3031
argsList.add(ServletContainer.class.getName());
3132

32-
String executable = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
33-
process = new CommandLine(executable, argsList.toArray(new String[0]));
34-
process.setEnvironmentVariable("PATH", PathUtils.getSystemPath());
33+
builder = new ProcessBuilder(argsList);
34+
builder.environment().put("PATH", PathUtils.getSystemPath());
3535
}
3636

3737
/**
3838
* Start the process associated with the example page servlet.
39+
* @throws IOException if an I/O error occurs
3940
*/
40-
public void start() {
41+
public void start() throws IOException {
4142
if (!hasStarted) {
42-
process.executeAsync();
43+
process = builder.start();
4344
hasStarted = true;
4445
}
4546
}
@@ -58,12 +59,14 @@ public boolean isActive() {
5859

5960
/**
6061
* Stop the example page servlet.
62+
* @throws InterruptedException if interrupted while awaiting shutdown
6163
*/
62-
public void shutdown() {
64+
public void shutdown() throws InterruptedException {
6365
if (isActive()) {
6466
process.destroy();
6567
hasStarted = false;
6668
isActive = false;
69+
process.waitFor();
6770
}
6871
}
6972

src/main/java/com/nordstrom/automation/selenium/plugins/AbstractAppiumPlugin.java renamed to src/selenium3/java/com/nordstrom/automation/selenium/plugins/AbstractAppiumPlugin.java

Lines changed: 11 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,13 @@
11
package com.nordstrom.automation.selenium.plugins;
22

3-
import static org.openqa.selenium.json.Json.MAP_TYPE;
4-
53
import java.io.File;
64
import java.io.FileNotFoundException;
75
import java.io.IOException;
8-
import java.io.Reader;
96
import java.lang.reflect.Constructor;
107
import java.lang.reflect.Field;
118
import java.lang.reflect.InvocationTargetException;
129
import java.lang.reflect.Method;
1310
import java.net.URL;
14-
import java.nio.file.Files;
1511
import java.nio.file.Path;
1612
import java.nio.file.Paths;
1713
import java.util.ArrayList;
@@ -25,8 +21,6 @@
2521
import org.openqa.selenium.Capabilities;
2622
import org.openqa.selenium.WebDriver;
2723
import org.openqa.selenium.WebElement;
28-
import org.openqa.selenium.grid.config.ConfigException;
29-
import org.openqa.selenium.json.Json;
3024
import org.openqa.selenium.net.PortProber;
3125
import org.openqa.selenium.os.CommandLine;
3226
import org.openqa.selenium.remote.RemoteWebDriver;
@@ -71,7 +65,6 @@
7165
* &lt;/exclusions&gt;
7266
*&lt;/dependency&gt;</pre>
7367
*/
74-
@SuppressWarnings("deprecation")
7568
public abstract class AbstractAppiumPlugin implements DriverPlugin {
7669

7770
private static final String[] DEPENDENCY_CONTEXTS = {};
@@ -119,7 +112,6 @@ public String[] getPropertyNames(String capabilities) {
119112
* {@inheritDoc}
120113
*/
121114
@Override
122-
@SuppressWarnings("unchecked")
123115
public LocalGridServer create(SeleniumConfig config, String launcherClassName, String[] dependencyContexts,
124116
URL hubUrl, Path workingPath, Path outputPath) throws IOException {
125117

@@ -184,35 +176,17 @@ public LocalGridServer create(SeleniumConfig config, String launcherClassName, S
184176
}
185177
}
186178

187-
// if target is Selenium 3
188-
if (config.getVersion() == 3) {
189-
// get 'localhost' and free port
190-
address = GridUtility.getLocalHost();
191-
portNum = PortProber.findFreePort();
192-
193-
// add 'base-path' argument
194-
argsList.add("--base-path");
195-
argsList.add("/wd/hub");
196-
197-
// add 'nodeconfig' path
198-
argsList.add("--nodeconfig");
199-
argsList.add(nodeConfigPath.toString());
200-
// otherwise (target is Selenium 4+)
201-
} else {
202-
// extract address and port from relay configuration
203-
try (Reader reader = Files.newBufferedReader(nodeConfigPath)) {
204-
Map<String, Object> nodeConfig = new Json().toType(reader, MAP_TYPE);
205-
Map<String, Object> relayOptions = (Map<String, Object>) nodeConfig.get("relay");
206-
address = (String) relayOptions.get("host");
207-
portNum = ((Long) relayOptions.get("port")).intValue();
208-
} catch (IOException e) {
209-
throw new ConfigException("Failed reading node configuration.", e);
210-
}
211-
212-
// add driver specification
213-
argsList.add("--use-drivers");
214-
argsList.add(getBrowserName().toLowerCase());
215-
}
179+
// get 'localhost' and free port
180+
address = GridUtility.getLocalHost();
181+
portNum = PortProber.findFreePort();
182+
183+
// add 'base-path' argument
184+
argsList.add("--base-path");
185+
argsList.add("/wd/hub");
186+
187+
// add 'nodeconfig' path
188+
argsList.add("--nodeconfig");
189+
argsList.add(nodeConfigPath.toString());
216190

217191
// specify server port
218192
argsList.add(0, portNum.toString());
@@ -266,8 +240,6 @@ public LocalGridServer create(SeleniumConfig config, String launcherClassName, S
266240
process = new CommandLine(findNodeBinary().getAbsolutePath(), argsList.toArray(new String[0]));
267241
}
268242

269-
// if target is Selenium 4+, store path to relay configuration in Appium process environment
270-
if (config.getVersion() > 3) process.setEnvironmentVariable("nodeConfigPath", nodeConfigPath.toString());
271243
return new AppiumGridServer(address, portNum, false, process, workingPath, outputPath);
272244
}
273245

@@ -453,17 +425,6 @@ public boolean shutdown(final boolean localOnly) throws InterruptedException {
453425
return true;
454426
}
455427

456-
/**
457-
* Get stored relay node configuration path. <br>
458-
* <b>NOTE</b>: A relay node is needed to connect the Appium server to a Selenium 4+ Grid hub.
459-
*
460-
* @return path to relay node configuration; may be {@code null}
461-
*/
462-
public Path getNodeConfigPath() {
463-
String nodeConfigPath = getEnvironment().get("nodeConfigPath");
464-
return (nodeConfigPath != null) ? Paths.get(nodeConfigPath) : null;
465-
}
466-
467428
/**
468429
* Get process environment from this AppiumGridServer object.
469430
*
@@ -541,7 +502,5 @@ public static boolean isAppiumWithPM2(URL nodeUrl) {
541502
}
542503
return appiumWithPM2;
543504
}
544-
545505
}
546-
547506
}

src/selenium4/java/com/nordstrom/automation/selenium/core/LocalSeleniumGrid.java

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
package com.nordstrom.automation.selenium.core;
22

33
import java.io.File;
4-
import java.io.FileNotFoundException;
5-
import java.io.FileOutputStream;
64
import java.io.IOException;
75
import java.net.MalformedURLException;
86
import java.net.URL;
@@ -16,7 +14,6 @@
1614
import java.util.ServiceConfigurationError;
1715
import java.util.concurrent.TimeoutException;
1816
import org.openqa.selenium.net.PortProber;
19-
import org.openqa.selenium.os.CommandLine;
2017

2118
import com.nordstrom.automation.selenium.AbstractSeleniumConfig.SeleniumSettings;
2219
import com.nordstrom.automation.selenium.DriverPlugin;
@@ -39,7 +36,6 @@
3936
* <b>NOTE</b>: If no test context is specified, the log file will be stored in the "current" directory of the parent
4037
* Java process.
4138
*/
42-
@SuppressWarnings("deprecation")
4339
public class LocalSeleniumGrid extends SeleniumGrid {
4440

4541
private static final String OPT_HOST = "--host";
@@ -178,7 +174,6 @@ public static SeleniumGrid create(SeleniumConfig config, final Path hubConfigPat
178174
* @param workingPath {@link Path} of working directory for server process; {@code null} for default
179175
* @param outputPath {@link Path} to output log file; {@code null} to decline log-to-file
180176
* @param propertyNames optional array of property names to propagate to server process
181-
*
182177
* @return {@link LocalGridServer} object for managing the server process
183178
* @throws GridServerLaunchFailedException If a Grid component process failed to start
184179
* @see #activate()
@@ -253,18 +248,19 @@ public static LocalGridServer create(final SeleniumConfig config, final String l
253248
argsList.add(0, "-agentlib:jdwp=transport=dt_socket,server=y,address=" + address);
254249
}
255250

256-
String executable = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
257-
CommandLine process = new CommandLine(executable, argsList.toArray(new String[0]));
258-
process.setEnvironmentVariable("PATH", PathUtils.getSystemPath());
259-
return new LocalGridServer(hostUrl, portNum, isHub, process, workingPath, outputPath);
251+
argsList.add(0, System.getProperty("java.home") + File.separator + "bin" + File.separator + "java");
252+
ProcessBuilder builder = new ProcessBuilder(argsList);
253+
builder.environment().put("PATH", PathUtils.getSystemPath());
254+
return new LocalGridServer(hostUrl, portNum, isHub, builder, workingPath, outputPath);
260255
}
261256

262257
/**
263258
* This class represents a single Selenium server (hub or node) belonging to a local Grid collection.
264259
*/
265260
public static class LocalGridServer extends GridServer {
266261

267-
private final CommandLine process;
262+
private final ProcessBuilder builder;
263+
private Process process = null;
268264
private boolean hasStarted = false;
269265
private boolean isActive = false;
270266
private final Map<String, String> personalities = new HashMap<>();
@@ -275,34 +271,39 @@ public static class LocalGridServer extends GridServer {
275271
* @param host IP address of local Grid server
276272
* @param port port of local Grid server
277273
* @param isHub role of Grid server being started ({@code true} = hub; {@code false} = node)
278-
* @param process {@link Process} of local Grid server
274+
* @param builder {@link ProcessBuilder} of local Grid server
279275
* @param workingPath {@link Path} of working directory for server process; {@code null} for default
280276
* @param outputPath {@link Path} to output log file; {@code null} to decline log-to-file
281277
*/
282-
public LocalGridServer(String host, Integer port, boolean isHub, CommandLine process, Path workingPath, Path outputPath) {
278+
public LocalGridServer(String host, Integer port, boolean isHub, ProcessBuilder builder, Path workingPath, Path outputPath) {
283279
super(getServerUrl(host, port), isHub);
284280

285281
if (workingPath != null) {
286-
process.setWorkingDirectory(workingPath.toString());
282+
builder.directory(workingPath.toFile());
287283
}
288284

289285
if (outputPath != null) {
290-
try {
291-
process.copyOutputTo(new FileOutputStream(outputPath.toFile()));
292-
} catch (FileNotFoundException e) {
293-
throw new GridServerLaunchFailedException(isHub ? "hub" : "node", e);
294-
}
286+
builder.redirectOutput(outputPath.toFile());
295287
}
296288

297-
this.process = process;
289+
this.builder = builder;
290+
}
291+
292+
/**
293+
* Get process environment of this local grid server.
294+
*
295+
* @return map of process environment variables
296+
*/
297+
public Map<String, String> getEnvironment() {
298+
return builder.environment();
298299
}
299300

300301
/**
301302
* Get process for this local Grid server.
302303
*
303304
* @return {@link Process} object
304305
*/
305-
public CommandLine getProcess() {
306+
public Process getProcess() {
306307
return process;
307308
}
308309

@@ -327,7 +328,7 @@ public Map<String, String> getPersonalities() {
327328
*/
328329
public void start() throws IOException, InterruptedException, TimeoutException {
329330
if (!hasStarted) {
330-
process.executeAsync();
331+
process = builder.start();
331332
hasStarted = true;
332333
}
333334
}
@@ -352,6 +353,7 @@ public boolean shutdown(final boolean localOnly) throws InterruptedException {
352353
getProcess().destroy();
353354
hasStarted = false;
354355
isActive = false;
356+
getProcess().waitFor();
355357
}
356358

357359
return true;

0 commit comments

Comments
 (0)