/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package Tools;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
*
* @author Stephane Martin <stephane@stephanemartin.fr>
*/
public class ExecTools {
private static final Logger LOG = Logger.getLogger(ExecTools.class.getName());
/**
* Launch a command and wait the terminaison. If the return number of
* command is not 0 then display all stream in warning LOG.
*
* @param command the command to be launch
* @param currentDirectory Current working directory for the command
* @throws IOException
* @throws InterruptedException
* @return The return value of process
*/
public static int launchAndWait(String command, String currentDirectory, int timeout) throws IOException, TimeoutException {
LOG.log(Level.INFO, "command line : {0}", command);
Process p = Runtime.getRuntime().exec(command, new String[0], new File(currentDirectory));
WaitForProcess watch = new WaitForProcess(p);
ThreadReader output=new ThreadReader(p.getInputStream());
ThreadReader error=new ThreadReader(p.getErrorStream());
try {
watch.waitFor(timeout);
} catch (InterruptedException ex) {
}
if (LOG.isLoggable(Level.WARNING) && p.exitValue() != 0) {
LOG.log(Level.WARNING, "command existed with error code : {0}", p.exitValue());
LOG.log(Level.WARNING, "error : {0}", error);
LOG.log(Level.WARNING, "output : {0}", output);
} else if (LOG.isLoggable(Level.INFO)) {
LOG.log(Level.WARNING, "error : {0}", error);
LOG.log(Level.INFO, "output : {0}", output);
LOG.log(Level.INFO, "{0} finished ", command);
}
return p.exitValue();
}
/**
* This class read an InputStream in separated thread
* The thread termine when the inputstream is closed
* It can be read with to string function.
*/
static class ThreadReader implements Runnable {
StringBuilder str = new StringBuilder();
InputStream s;
Thread th;
public ThreadReader(InputStream s) {
this.s = s;
lauch();
}
private void lauch(){
th=new Thread(this);
th.start();
}
/**
* reads the stream and appens the string.
*/
@Override
public void run() {
try {
int c;
while ((c = s.read()) > -1) {
str.append((char) c);
}
} catch (IOException ex) {
Logger.getLogger(ExecTools.class.getName()).log(Level.SEVERE, null, ex);
}
}
/**
*
* @return Stream in String format
*/
@Override
public String toString(){
return this.str.toString();
}
}
/**
* This class wait the end of process or the end of a time out.
* It create a thread with waitfor to wait end of process
* and join this thread with timout.
* And check what is the first
*/
static class WaitForProcess implements Runnable {
private Process process;
private int returnValue = -1;
private boolean finished = false;
private Thread thread;
/**
*
* @param process to wait
*/
public WaitForProcess(Process process) {
this.process = process;
}
/**
* Wait the process with mili of time out.
*
* @param milliS is waiting time in millisecond 0 is infinite
* @return the return of processus if no timeoutException was throwed
* @throws InterruptedException If any thread was interupted
* @throws TimeoutException If the processus time has depassed the time
*/
int waitFor(long milliS) throws InterruptedException, TimeoutException {
LOG.log(Level.INFO, "Waitfor {0}ms", milliS);
thread = new Thread(this);
thread.start();
thread.join(milliS);
synchronized (this) {
if (!this.finished) {
LOG.info("processus timeout");
process.destroy();
throw new TimeoutException();
}
return this.returnValue;
}
}
/**
* Wait the processus end inform that is ended.
*/
@Override
public void run() {
try {
returnValue = process.waitFor();
finished = true;
LOG.log(Level.INFO, "Processus is in time and return {0}", returnValue);
} catch (InterruptedException ex) {
LOG.info("Watchdog interupted");
}
}
/**
*
* @return the return value of processus.
*/
public int getReturnValue() {
return returnValue;
}
/**
*
* @return if processus is not timed out
*/
public boolean isFinished() {
return finished;
}
}
}