2020-08-06 11:07:25 +02:00
Executor
========
2017-11-26 18:02:57 +01:00
2020-08-06 11:07:25 +02:00
###### [![Dorkbox](https://badge.dorkbox.com/dorkbox.svg "Dorkbox")](https://git.dorkbox.com/dorkbox/Executor) [![Github](https://badge.dorkbox.com/github.svg "Github")](https://github.com/dorkbox/Executor) [![Gitlab](https://badge.dorkbox.com/gitlab.svg "Gitlab")](https://gitlab.com/dorkbox/Executor)
2019-03-17 23:16:27 +01:00
2021-01-26 01:18:18 +01:00
Shell, JVM, and remote SSH command execution on Linux, MacOS, or Windows for Java 8 (no process PID information) and Java 9+ (with PID
information)
2017-11-26 18:02:57 +01:00
2020-08-06 11:07:25 +02:00
Ironically, there are a considerable number of issues when launching shell/JVM processes via Java. This library solves problems
with:
2017-11-28 21:25:15 +01:00
1. Redirecting in/out/err streams correctly
2020-08-06 11:07:25 +02:00
1. Enable reading a single-character from the console input-stream
1. Correctly reading out/err process output streams to prevent memory and threading issues
1. Executing a JVM process using the same JVM as is currently running
1. Executing remote processes via SSH
1. Using and supporting kotlin co-routines for thread suspension
2021-01-26 01:18:18 +01:00
1. Getting process PID information (Java 9+ only)
2017-11-26 18:02:57 +01:00
2021-01-26 01:18:18 +01:00
- This is for cross-platform use, specifically - linux 32/64, mac 32/64, and windows 32/64. Java 8+, kotlin.
2020-08-06 11:07:25 +02:00
This project is powerful but still simple to use. By using a single class **Executor**
2020-08-09 13:30:42 +02:00
the user gets the functionality from both **java.lang.ProcessBuilder** and [Apache Commons Exec ](http://commons.apache.org/proper/commons-exec/ ), along with the ability to fork the currently running JVM process and remotely execute commands via SSH.
2017-11-26 18:02:57 +01:00
Release Notes
---------
2020-08-06 11:07:25 +02:00
## Examples (these are written in kotlin)
2020-08-09 13:31:18 +02:00
* Easiest, and simplest way to get UTF8 output from running an application. This is VERY simple, and designed for quickly running, small-output applications. For anything just a hint that it might be MORE complex, use the builder pattern with the appropriate configuration.
2020-08-06 11:07:25 +02:00
```java
val output = Executor.run("java", "-version")
```
2020-08-09 13:31:18 +02:00
< hr / >
2020-08-06 11:07:25 +02:00
* Output is pumped to NullOutputStream
```java
Executor().command("java", "-version").start()
```
< hr / >
* Returning the exit code
* Output is pumped to NullOutputStream
```java
2020-08-09 13:32:50 +02:00
val exit = Executor().command("java", "-version").startBlocking().getExitValue()
2020-08-06 11:07:25 +02:00
```
< hr / >
* Return output as UTF8 String
```java
2020-08-10 23:35:09 +02:00
val output = Executor().command("java", "-version").enableRead().startBlocking().output.utf8()
2020-08-06 11:07:25 +02:00
```
< hr / >
* Pumping the output to a logger
```java
Executor().command("java", "-version")
.redirectOutput(Slf4jStream.asInfo(LoggerFactory.getLogger(javaClass.name + ".MyProcess")))
.start()
```
< hr / >
* Pumping the output to a logger (short form for previous)
```java
Executor()
.command("java", "-version")
.redirectOutput(Slf4jStream.asInfo())
.start()
```
< hr / >
* Pumping the output to the logger of the caller class
```java
Executor()
.command("java", "-version")
.redirectOutput(Slf4jStream.asInfo())
.start()
```
< hr / >
* Pumping the output to a logger
* Returning output as UTF8 String
```java
val output = Executor()
.command("java", "-version")
.redirectOutput(Slf4jStream.asInfo())
2020-08-10 23:35:09 +02:00
.enableRead()
2020-08-06 11:07:25 +02:00
.start()
.output.utf8()
```
< hr / >
* Pumping the stderr to a logger
* Returning the output as UTF8 String
```java
val output = Executor()
.command("java", "-version")
.redirectError(Slf4jStream.asInfo())
2020-08-10 23:35:09 +02:00
.enableRead()
2020-08-06 11:07:25 +02:00
.start()
.output.utf8()
```
< hr / >
* Running with a timeout of **60** seconds
* Output pumped to NullOutputStream
```java
try {
runBlocking {
Executor()
.command("java", "-version")
.timeout(60, TimeUnit.SECONDS)
.start()
}
} catch (e: TimeoutException) {
// process is automatically destroyed
}
```
< hr / >
* Pumping output to another OutputStream
```java
Executor()
.command("java", "-version")
.redirectOutput(out)
.start()
```
< hr / >
* Handling output line-by-line while process is running (Version 1)
```java
runBlocking {
Executor()
.command("java", "-version")
.redirectOutput(object : LogOutputStream() {
override fun processLine(line: String) {
// ...
}
})
.start()
}
```
< hr / >
* Handling output line-by-line while process is running (Version 2)
```java
val result = Executor()
.command("java", "-version")
2020-08-10 23:35:09 +02:00
.enableRead()
2020-08-06 11:07:25 +02:00
.startAsync()
runBlocking {
val fullOutput = mutableListOf< String > ()
val output = result.output
while (output.isOpen) {
fullOutput.add(output.utf8())
}
val outputString: String = fullOutput.joinToString()
Assert.assertFalse(outputString.isEmpty())
}
```
< hr / >
* Destroy the running process when VM exits
* Output pumped to NullOutputStream
```java
Executor().command("java", "-version").destroyOnExit().start()
```
< hr / >
* Run process with a specific environment variable
* Output pumped to NullOutputStream
```java
Executor().command("java", "-version").environment("foo", "bar").start()
```
< hr / >
* Run process with a specific environment
* Output pumped to NullOutputStream
```java
val env = mapOf< String , String > (...)
Executor()
.command("java", "-version")
.environment(env)
.start()
```
< hr / >
* Throw exception when wrong exit code
* Output is pumped to NullOutputStream
```java
try {
runBlocking {
Executor()
.command("java", "-version")
.exitValues(3)
.start()
}
} catch (e: InvalidExitValueException) {
println("Process exited with " + e.exitValue)
}
```
< hr / >
* Throw exception when wrong exit code
* Return output as UTF8 String
```java
var output: String
try {
output = runBlocking {
Executor()
.command("java", "-version")
2020-08-10 23:35:09 +02:00
.enableRead()
2020-08-06 11:07:25 +02:00
.exitValues(3)
.start()
.output.utf8()
}
} catch (e: InvalidExitValueException) {
println("Process exited with " + e.exitValue)
output = (e.result as SyncProcessResult).output.utf8()
}
```
< hr / >
* Starting process in the background
* Output is pumped to NullOutputStream
```java
val deferredProcess = Executor()
.command("java", "-version")
.startAsync()
//do some stuff..
deferredProcess.awaitBlocking(60, TimeUnit.SECONDS)
```
< hr / >
* Start process in the background
* Return output as UTF8 String
```java
val deferredProcess = Executor()
.command("java", "-version")
2020-08-10 23:35:09 +02:00
.enableRead()
2020-08-06 11:07:25 +02:00
.startAsync()
//do some stuff
deferredProcess.awaitBlocking(60, TimeUnit.SECONDS)
return runBlocking {
deferredProcess.output.utf8()
}
```
2017-11-26 18:02:57 +01:00
Maven Info
---------
2021-01-26 23:08:23 +01:00
```
2017-11-26 18:02:57 +01:00
< dependencies >
...
< dependency >
< groupId > com.dorkbox< / groupId >
2020-08-06 11:07:25 +02:00
< artifactId > Executor< / artifactId >
2022-01-07 07:33:50 +01:00
< version > 3.5< / version >
2017-11-26 18:02:57 +01:00
< / dependency >
< / dependencies >
2021-01-26 23:08:23 +01:00
```
2017-11-26 18:02:57 +01:00
2018-08-18 20:57:00 +02:00
Gradle Info
---------
2021-01-26 23:08:23 +01:00
```
2018-08-18 20:57:00 +02:00
dependencies {
...
2022-01-07 07:33:50 +01:00
implementation("com.dorkbox:Executor:3.5")
2018-08-18 20:57:00 +02:00
}
2021-01-26 23:08:23 +01:00
```
2018-08-18 20:57:00 +02:00
2017-11-28 21:25:15 +01:00
2017-11-26 18:02:57 +01:00
License
---------
2021-04-09 12:40:20 +02:00
This project is © 2021 dorkbox llc, with modifications from software copyright 2014 ZeroTurnaround, and 2014 The Apache Software
2020-08-06 11:07:25 +02:00
Foundation.
This project is distributed under the terms of the Apache v2.0 License. See file "LICENSE" for further references.
2017-11-26 18:02:57 +01:00