0
# Modern Process Management
1
2
Modern, builder-pattern-based external process execution with improved resource management, flexible configuration, and robust error handling. The `ExternalProcess` API is the recommended approach for new implementations.
3
4
## Capabilities
5
6
### ExternalProcess Builder
7
8
Creates and configures external processes using a fluent builder pattern with comprehensive configuration options.
9
10
```java { .api }
11
/**
12
* Creates a new builder instance for constructing ExternalProcess
13
* @return Builder instance for fluent configuration
14
*/
15
public static ExternalProcess.Builder builder();
16
17
public static class Builder {
18
/**
19
* Set the executable command with arguments
20
* @param executable the executable to run
21
* @param arguments the arguments to pass
22
* @return this instance for chaining
23
*/
24
public Builder command(String executable, List<String> arguments);
25
26
/**
27
* Set the executable command with arguments
28
* @param command the executable followed by arguments
29
* @return this instance for chaining
30
*/
31
public Builder command(List<String> command);
32
33
/**
34
* Set the executable command with arguments
35
* @param command the executable followed by arguments
36
* @return this instance for chaining
37
*/
38
public Builder command(String... command);
39
40
/**
41
* Get the current command configuration
42
* @return unmodifiable list of command and arguments
43
*/
44
public List<String> command();
45
46
/**
47
* Set a single environment variable
48
* @param name environment variable name (must not be null)
49
* @param value environment variable value (must not be null)
50
* @return this instance for chaining
51
* @throws IllegalArgumentException if name or value is null
52
*/
53
public Builder environment(String name, String value);
54
55
/**
56
* Get the environment variables map
57
* @return editable map of environment variables
58
*/
59
public Map<String, String> environment();
60
61
/**
62
* Get the working directory
63
* @return current working directory or null if not set
64
*/
65
public File directory();
66
67
/**
68
* Set the working directory from string path
69
* @param directory path to working directory
70
* @return this instance for chaining
71
*/
72
public Builder directory(String directory);
73
74
/**
75
* Set the working directory
76
* @param directory working directory File object
77
* @return this instance for chaining
78
*/
79
public Builder directory(File directory);
80
81
/**
82
* Copy output to additional stream
83
* @param stream where to copy combined stdout and stderr
84
* @return this instance for chaining
85
*/
86
public Builder copyOutputTo(OutputStream stream);
87
88
/**
89
* Set output buffer size
90
* @param toKeep number of bytes to buffer (default 32768)
91
* @return this instance for chaining
92
*/
93
public Builder bufferSize(int toKeep);
94
95
/**
96
* Build and start the external process
97
* @return ExternalProcess instance
98
* @throws UncheckedIOException if process creation fails
99
*/
100
public ExternalProcess start() throws UncheckedIOException;
101
}
102
```
103
104
**Usage Examples:**
105
106
```java
107
import org.openqa.selenium.os.ExternalProcess;
108
import java.io.ByteArrayOutputStream;
109
import java.io.File;
110
import java.util.Arrays;
111
112
// Basic process execution
113
ExternalProcess process = ExternalProcess.builder()
114
.command("echo", Arrays.asList("Hello", "World"))
115
.start();
116
117
// Advanced configuration
118
ByteArrayOutputStream output = new ByteArrayOutputStream();
119
ExternalProcess process = ExternalProcess.builder()
120
.command("java", Arrays.asList("-jar", "myapp.jar", "--config", "prod.yml"))
121
.environment("JAVA_OPTS", "-Xmx2g")
122
.environment("LOG_LEVEL", "DEBUG")
123
.directory(new File("/opt/myapp"))
124
.copyOutputTo(output)
125
.bufferSize(16384)
126
.start();
127
```
128
129
### ExternalProcess Management
130
131
Manages running external processes with lifecycle control, output retrieval, and graceful shutdown capabilities.
132
133
```java { .api }
134
public class ExternalProcess {
135
/**
136
* Get combined stdout and stderr as String in default charset
137
* @return buffered output as String
138
*/
139
public String getOutput();
140
141
/**
142
* Get combined stdout and stderr as String in specified encoding
143
* @param encoding the charset to use for decoding
144
* @return buffered output as String in specified encoding
145
*/
146
public String getOutput(Charset encoding);
147
148
/**
149
* Check if the process is still running
150
* @return true if process is alive, false if terminated
151
*/
152
public boolean isAlive();
153
154
/**
155
* Wait for process completion within timeout
156
* @param duration maximum time to wait
157
* @return true if process completed within timeout, false if timeout occurred
158
* @throws InterruptedException if current thread is interrupted
159
*/
160
public boolean waitFor(Duration duration) throws InterruptedException;
161
162
/**
163
* Get the exit code of the completed process
164
* @return process exit code
165
* @throws IllegalStateException if process is still running
166
*/
167
public int exitValue();
168
169
/**
170
* Initiate graceful shutdown with 4-second timeout
171
*/
172
public void shutdown();
173
174
/**
175
* Initiate shutdown with custom timeout
176
* @param timeout maximum time to wait for graceful shutdown before force kill
177
*/
178
public void shutdown(Duration timeout);
179
}
180
```
181
182
**Usage Examples:**
183
184
```java
185
import org.openqa.selenium.os.ExternalProcess;
186
import java.time.Duration;
187
import java.nio.charset.StandardCharsets;
188
189
// Start and wait for process
190
ExternalProcess process = ExternalProcess.builder()
191
.command("curl", Arrays.asList("-s", "https://api.example.com/status"))
192
.start();
193
194
// Wait with timeout
195
boolean completed = process.waitFor(Duration.ofSeconds(30));
196
if (completed) {
197
int exitCode = process.exitValue();
198
String output = process.getOutput(StandardCharsets.UTF_8);
199
200
if (exitCode == 0) {
201
System.out.println("API Response: " + output);
202
} else {
203
System.err.println("Command failed with exit code: " + exitCode);
204
System.err.println("Error output: " + output);
205
}
206
} else {
207
System.err.println("Process timed out, shutting down...");
208
process.shutdown(Duration.ofSeconds(5));
209
}
210
211
// Check if still running
212
if (process.isAlive()) {
213
System.err.println("Process still running after shutdown attempt");
214
}
215
```
216
217
### Process Lifecycle Management
218
219
Best practices for managing external process lifecycles with proper resource cleanup and error handling.
220
221
**Process States:**
222
- **Starting**: Process is being created and initialized
223
- **Running**: Process is actively executing (`isAlive()` returns true)
224
- **Completed**: Process has finished execution (exit code available)
225
- **Shutdown**: Process is being terminated gracefully or forcibly
226
227
**Shutdown Behavior:**
228
1. Normal termination attempted using `ProcessHandle.destroy()`
229
2. Wait for graceful shutdown within specified timeout
230
3. Force termination using `ProcessHandle.destroyForcibly()` if still running
231
4. Worker thread cleanup and resource deallocation
232
233
**Error Scenarios:**
234
- `UncheckedIOException`: Process creation fails (invalid executable, permission issues)
235
- `InterruptedException`: Thread interrupted during wait operations
236
- Output buffer overflow: Handled automatically with circular buffering
237
238
**Resource Management:**
239
- Output streams are automatically managed and cleaned up
240
- Worker threads are daemon threads that don't prevent JVM shutdown
241
- Process handles are properly closed on completion or shutdown