Executing a Command Line Executable From Java
Join the DZone community and get the full member experience.
Join For FreeIn this post we'll deal with a common need for Java developers. Execute and manage an external process from within Java. Since this task is quite common we set out to find a Java library to help us accomplish it.
The requirements from such a library are:
- Execute the process asynchronously.
- Ability to abort the process execution.
- Ability to wait for process completion.
- On process output notifications.
- Ability to kill the process in case it hung.
- Get the process exit code.
Here is the method signature we expose:
public static Future<Long> runProcess(final CommandLine commandline, final ProcessExecutorHandler handler, final long watchdogTimeout) throws IOException;
- It returns a Future<Long>. This covers section 1,2,3,6.
- Instance of ProcessExecutorHandler is passed to the function. This instance is actually a listener for any process output. This covers section 4 in our requirement.
- Last but not least you supply a timeout. If the process execution takes more than said timeout you assume the process hung and you will end it. In that case the error code returned by the process will be -999.
import org.apache.commons.exec.*; import org.apache.commons.exec.Executor; import java.io.IOException; import java.util.concurrent.*; public class ProcessExecutor { public static final Long WATCHDOG_EXIST_VALUE = -999L; public static Future<Long> runProcess(final CommandLine commandline, final ProcessExecutorHandler handler, final long watchdogTimeout) throws IOException{ ExecutorService executor = Executors.newSingleThreadExecutor(); Future<Long> result = executor.submit(new ProcessCallable(watchdogTimeout, handler, commandline)); executor.shutdown(); return result; } private static class ProcessCallable implements Callable<Long>{ private long watchdogTimeout; private ProcessExecutorHandler handler; private CommandLine commandline; private ProcessCallable(long watchdogTimeout, ProcessExecutorHandler handler, CommandLine commandline) { this.watchdogTimeout = watchdogTimeout; this.handler = handler; this.commandline = commandline; } @Override public Long call() throws Exception { Executor executor = new DefaultExecutor(); executor.setProcessDestroyer(new ShutdownHookProcessDestroyer()); ExecuteWatchdog watchDog = new ExecuteWatchdog(watchdogTimeout); executor.setWatchdog(watchDog); executor.setStreamHandler(new PumpStreamHandler(new MyLogOutputStream(handler, true),new MyLogOutputStream(handler, false))); Long exitValue; try { exitValue = new Long(executor.execute(commandline)); } catch (ExecuteException e) { exitValue = new Long(e.getExitValue()); } if(watchDog.killedProcess()){ exitValue =WATCHDOG_EXIST_VALUE; } return exitValue; } } private static class MyLogOutputStream extends LogOutputStream{ private ProcessExecutorHandler handler; private boolean forewordToStandardOutput; private MyLogOutputStream(ProcessExecutorHandler handler, boolean forewordToStandardOutput) { this.handler = handler; this.forewordToStandardOutput = forewordToStandardOutput; } @Override protected void processLine(String line, int level) { if (forewordToStandardOutput){ handler.onStandardOutput(line); } else{ handler.onStandardError(line); } } } } // interface. public interface ProcessExecutorHandler { public void onStandardOutput(String msg); public void onStandardError(String msg); }
import org.apache.commons.exec.*;
import org.apache.commons.exec.Executor;
import java.io.IOException;
import java.util.concurrent.*;
public class ProcessExecutor {
public static final Long WATCHDOG_EXIST_VALUE = -999L;
public static Future runProcess(final CommandLine commandline, final ProcessExecutorHandler handler, final long watchdogTimeout) throws IOException{
ExecutorService executor = Executors.newSingleThreadExecutor();
return executor.submit(new ProcessCallable(watchdogTimeout, handler, commandline));
}
private static class ProcessCallable implements Callable{
private long watchdogTimeout;
private ProcessExecutorHandler handler;
private CommandLine commandline;
private ProcessCallable(long watchdogTimeout, ProcessExecutorHandler handler, CommandLine commandline) {
this.watchdogTimeout = watchdogTimeout;
this.handler = handler;
this.commandline = commandline;
}
@Override
public Long call() throws Exception {
Executor executor = new DefaultExecutor();
executor.setProcessDestroyer(new ShutdownHookProcessDestroyer());
ExecuteWatchdog watchDog = new ExecuteWatchdog(watchdogTimeout);
executor.setWatchdog(watchDog);
executor.setStreamHandler(new PumpStreamHandler(new MyLogOutputStream(handler, true),new MyLogOutputStream(handler, false)));
Long exitValue;
try {
exitValue = new Long(executor.execute(commandline));
} catch (ExecuteException e) {
exitValue = new Long(e.getExitValue());
}
if(watchDog.killedProcess()){
exitValue =WATCHDOG_EXIST_VALUE;
}
return exitValue;
}
}
private static class MyLogOutputStream extends LogOutputStream{
private ProcessExecutorHandler handler;
private boolean forewordToStandardOutput;
private MyLogOutputStream(ProcessExecutorHandler handler, boolean forewordToStandardOutput) {
this.handler = handler;
this.forewordToStandardOutput = forewordToStandardOutput;
}
@Override
protected void processLine(String line, int level) {
if (forewordToStandardOutput){
handler.onStandardOutput(line);
}
else{
handler.onStandardError(line);
}
}
}
}
// interface.
public interface ProcessExecutorHandler {
public void onStandardOutput(String msg);
public void onStandardError(String msg);
}
Opinions expressed by DZone contributors are their own.
Comments