java external process
EditWhen Runtime.exec() won’t
Java Pitfalls: Excuting an external program using Runtime.exec() method or ProcessBuilder class
http://devdaily.com/java/edu/pj/pj010016/
http://www.rgagnon.com/javadetails/java-0014.html
방법
http://blog.art-of-coding.eu/executing-operating-system-commands-from-java/
import java.io.IOException;
import java.io.InputStream;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
public class ShellTest {
String[] command = new String[]{"ls","-al"};
@Test
public void withProcessBuilder() throws IOException, InterruptedException {
ProcessBuilder builder = new ProcessBuilder(command);
Process process = builder.start();
printStream(process);
}
@Test
public void withRunetime() throws IOException, InterruptedException {
Runtime runtime = Runtime.getRuntime();
Process process = runtime.exec(command);
printStream(process);
}
private void printStream(Process process) throws IOException, InterruptedException {
process.waitFor();
InputStream stream = process.getInputStream();
IOUtils.copy(stream, System.out);
IOUtils.closeQuietly(stream);
}
}
예제
public class StreamConverter implements Runnable {
private StringBuilder message =null;
private InputStream input = null;
public StreamConverter(InputStream input){
this.input = input;
this.message = new StringBuilder();
}
public void run() {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
String line= null;
try {
while( (line = reader.readLine())!=null){
message.append(line);
}
} catch (IOException e) {
throw new IllegalStateException("cann not read stream",e);
}
}
public StringBuilder getMessage() {
return message;
}
}
waitFor는 무한대기 될 수도 있다…
public static void main(String[] args) throws IOException, InterruptedException{
Process pc = Runtime.getRuntime().exec("java");
InputStream input = pc.getInputStream();
IOUtils.copy(input, System.out);
int exitCode = pc.waitFor();
System.out.println(exitCode);
}
멈추는 코드
public static void main(String[] args) throws IOException, InterruptedException{
Process pc = Runtime.getRuntime().exec("javac");
InputStream input = pc.getInputStream();
IOUtils.copy(input, System.out);
int exitCode = pc.waitFor();
System.out.println(exitCode);
}
그런데 위의 코드를 Runtime.exec("javac")를 실행시키는 코드로 바꾸어보면, 이 호출은 영원히 끝나지 않게 됩니다.
javaworld에 올라온 고전이자 최고의 글
- You cannot obtain an exit status from an external process until it has exited
- You must immediately handle the input, output, and error streams from your spawned external process
- You must use Runtime.exec() to execute programs
- You cannot use Runtime.exec() like a command line
Alvin Alexander의 글
- Running system commands in Java applications : 스트림 처리 제대로 암함
- http://alvinalexander.com/java/java-exec-processbuilder-process-1 : 개선판
- http://alvinalexander.com/java/java-exec-processbuilder-process-2
- http://alvinalexander.com/java/java-exec-processbuilder-process-3
참고할만한 구현체
- 분산처리 프레임워크 JPPF의 ProcessWrapper
- Alvin Alexander가 Java exec - execute system processes with Java ProcessBuilder and Process 글에 공유한 소스
- SystemCommandExecutor : shell 실행 전담 클래스
- ThreadedStreamHandler : 스트림처리 클래스
- ProcessBuilderExample : SystemCommandExecutor를 사용하는 예제
- Ant Exec Task의 PumpStreamHandler
- Apache-commons-exec의 PumpStreamHandler (Ant의 것과 패키지는 다르나 같은 코드)
- Exec-maven-plugin의 ExecMojo (Apache-commons-exec를 활용)
부모 프로세스의 메모리 복제
Apache Exec
http://commons.apache.org/exec
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-exec</artifactId>
<version>1.1</version>
</dependency>