-
-
Notifications
You must be signed in to change notification settings - Fork 16
Expand file tree
/
Copy pathProcessHelper.java
More file actions
86 lines (73 loc) · 2.86 KB
/
ProcessHelper.java
File metadata and controls
86 lines (73 loc) · 2.86 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.github.stickerifier.stickerify.process;
import static java.nio.charset.StandardCharsets.UTF_8;
import static java.util.concurrent.TimeUnit.MINUTES;
import com.github.stickerifier.stickerify.exception.ProcessException;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.Semaphore;
public final class ProcessHelper {
static final boolean IS_WINDOWS = System.getProperty("os.name").toLowerCase().contains("windows");
private static final int MAX_CONCURRENT_PROCESSES = IS_WINDOWS ? 4 : 5;
private static final Semaphore SEMAPHORE = new Semaphore(MAX_CONCURRENT_PROCESSES);
/**
* Executes passed-in command and ensures it completed successfully.
* Based on the operating system, the method limits the number of processes running concurrently:
* on Windows they will be at most 4, on every other system they will be at most 5.
*
* @param command the command to be executed
* @return the output of the command
* @throws ProcessException either if:
* <ul>
* <li>the command was unsuccessful
* <li>the waiting time elapsed
* <li>an unexpected failure happened running the command
* </ul>
*/
public static String executeCommand(final String[] command) throws ProcessException {
Process process = null;
try {
SEMAPHORE.acquire();
process = new ProcessBuilder(command).start();
var processExited = process.waitFor(1, MINUTES);
if (!processExited || process.exitValue() != 0) {
var reason = processExited ? "successfully" : "in time";
var output = readStream(process.getErrorStream());
throw new ProcessException("The command {} couldn't complete {}\n{}", command[0], reason, output);
}
return readProcessOutput(process);
} catch (IOException | InterruptedException e) {
throw new ProcessException(e);
} finally {
SEMAPHORE.release();
if (process != null) {
process.destroy();
}
}
}
/**
* Processes the content of the stream and retrieves its UTF-8 string representation.
*
* @param stream the stream to be decoded
* @return the UTF-8 representation of passed-in stream
* @throws IOException if an error occurs reading stream's bytes
*/
private static String readStream(InputStream stream) throws IOException {
return new String(stream.readAllBytes(), UTF_8);
}
/**
* Reads the content of the input stream.
* If the input stream is empty, the content of the error stream is returned.
*
* @param process the process
* @return the output of the process
* @throws IOException if an error occurs reading stream's bytes
*/
private static String readProcessOutput(Process process) throws IOException {
var inputStream = readStream(process.getInputStream());
var output = inputStream.isEmpty() ? readStream(process.getErrorStream()) : inputStream;
return output.trim();
}
private ProcessHelper() {
throw new UnsupportedOperationException();
}
}