Created
September 29, 2016 07:58
-
-
Save nobuoka/2ad1d5d3468cbd83d8799080c288281e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package info.vividcode; | |
import java.io.BufferedInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.util.List; | |
import java.util.concurrent.TimeUnit; | |
/** | |
* すぐに実行終了するコマンド (外部プロセス) を実行するクラス。 | |
*/ | |
public class CommandProcessRunner { | |
private static boolean readOutputToBufferIfAvailable(BufferedInputStream out, ByteArrayOutputStream outBuf, byte[] buf) throws IOException { | |
int available = out.available(); | |
if (available > 0) { | |
int numReadBytes = out.read(buf); | |
if (numReadBytes > 0) { | |
outBuf.write(buf, 0, numReadBytes); | |
return true; | |
} | |
} | |
return false; | |
} | |
private static void readOutputToBufferWhileAvailable(BufferedInputStream out, ByteArrayOutputStream outBuf, byte[] buf) throws IOException, InterruptedException { | |
while (true) { | |
if (Thread.currentThread().isInterrupted()) throw new InterruptedException(); | |
boolean read = readOutputToBufferIfAvailable(out, outBuf, buf); | |
if (!read) break; | |
} | |
} | |
private static void readOutputToBufferUntilTerminated(BufferedInputStream out, ByteArrayOutputStream outBuf, byte[] buf) throws IOException, InterruptedException { | |
while (true) { | |
if (Thread.currentThread().isInterrupted()) throw new InterruptedException(); | |
int numReadBytes = out.read(buf); | |
if (numReadBytes == -1) break; | |
outBuf.write(buf, 0, numReadBytes); | |
} | |
} | |
/** | |
* 引数で指定されたプロセスを起動し、標準出力とエラー出力を読み込みながらプロセスの終了を待つ。 | |
* 終了コードと標準出力とエラー出力をまとめたオブジェクトを結果として返す。 | |
* @param command 実行するコマンドとその引数。 | |
* @return コマンドの実行結果。 | |
* @throws IOException プロセスとのやり取りで IO エラーが発生した場合に、そのエラーがそのまま投げられる。 | |
* @throws InterruptedException 実行中のスレッドが中断された場合に発生する。 | |
*/ | |
public static CommandProcessRunner.Result execute(List<String> command) throws IOException, InterruptedException { | |
byte[] buf = new byte[1024]; | |
ByteArrayOutputStream stdOutBuf = new ByteArrayOutputStream(); | |
ByteArrayOutputStream errOutBuf = new ByteArrayOutputStream(); | |
ProcessBuilder pb = new ProcessBuilder(command); | |
Process process = pb.start(); | |
try { | |
try ( | |
BufferedInputStream stdOut = new BufferedInputStream(process.getInputStream()); | |
BufferedInputStream errOut = new BufferedInputStream(process.getErrorStream()) | |
) { | |
while (true) { | |
readOutputToBufferWhileAvailable(stdOut, stdOutBuf, buf); | |
readOutputToBufferWhileAvailable(errOut, errOutBuf, buf); | |
boolean hasExited; | |
try { | |
hasExited = process.waitFor(10, TimeUnit.MICROSECONDS); | |
} catch (InterruptedException e) { | |
Thread.currentThread().interrupt(); | |
throw e; | |
} | |
if (hasExited) break; | |
} | |
readOutputToBufferUntilTerminated(stdOut, stdOutBuf, buf); | |
readOutputToBufferUntilTerminated(errOut, errOutBuf, buf); | |
} | |
return new Result(process.exitValue(), stdOutBuf.toByteArray(), errOutBuf.toByteArray()); | |
} finally { | |
if (process.isAlive()) { | |
process.destroyForcibly(); | |
if (!Thread.currentThread().isInterrupted()) { | |
process.waitFor(); | |
} | |
} | |
} | |
} | |
public static class Result { | |
public final int exitValue; | |
public final byte[] standardOutput; | |
public final byte[] errorOutput; | |
public Result(int exitValue, byte[] standardOutput, byte[] errorOutput) { | |
this.exitValue = exitValue; | |
this.standardOutput = standardOutput; | |
this.errorOutput = errorOutput; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package info.vividcode; | |
import java.nio.charset.Charset; | |
import java.util.Arrays; | |
import java.util.concurrent.*; | |
public class Main { | |
/** | |
* Windows マシンでスリープコマンドを実行する例。 | |
*/ | |
public static void main(String[] args) throws InterruptedException, ExecutionException, TimeoutException { | |
ExecutorService executorService = Executors.newSingleThreadExecutor(); | |
try { | |
Future<CommandProcessRunner.Result> resultFuture = executorService.submit(() -> | |
CommandProcessRunner.execute(Arrays.asList("powershell", "-Command", "Start-Sleep -Seconds 5"))); | |
CommandProcessRunner.Result result; | |
try { | |
result = resultFuture.get(6, TimeUnit.SECONDS); | |
} catch (TimeoutException e) { | |
// 待ち時間を過ぎても終了しなかった場合はキャンセルする。 | |
resultFuture.cancel(true); | |
throw e; | |
} | |
System.out.println("終了コード: " + result.exitValue); | |
System.out.println("標準出力 : " + new String(result.standardOutput, Charset.forName("Shift_JIS"))); | |
System.out.println("エラー出力 : " + new String(result.errorOutput, Charset.forName("Shift_JIS"))); | |
} finally { | |
executorService.shutdown(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment