package br.usp.ime.academicdevoir.infra;
import java.io.*;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeoutException;
/**
* Entidade responsável pela execução de programas.
*
* O código foi adaptado do projeto http://dl.dropbox.com/u/10977140/Aulas.rar
*
*/
public class ExecutorDeProgramas {
private long timeout = Long.MAX_VALUE;
private String stdOut = "";
private String stdErr = "";
public String getStdOut() {
return stdOut;
}
public String getStdErr() {
return stdErr;
}
/**
* Construdor padrão - Timeout vale Long.MAX_VALUE
*/
public ExecutorDeProgramas() {
// Do nothing
}
/**
* Construtor
*
* @param timeout
* Tempo máximo de execução
*/
public ExecutorDeProgramas(long timeout) {
this.timeout = timeout;
}
/**
* Executa programa gerado por código Java
* @param diretorio
* @param nomeDaClasse
* @return mensagem informando se houve algum problema durante a execução.
* @throws Exception
*/
public static String executaProgramaJava (String diretorio,
String nomeDaClasse) throws Exception {
ExecutorDeProgramas r = new ExecutorDeProgramas(3000);
String resp = "";
// Linux
if (diretorio.startsWith("/"))
resp = r.executa("java -cp " + diretorio +
" -Djava.security.manager " + nomeDaClasse, null);
// Windows
else
resp = r.executa("java -cp \"" + diretorio +
";\" -Djava.security.manager " + nomeDaClasse,
null);
return resp;
}
/**
* Executa um processo
*
* @param comando String com o comando a ser executado
* @param env variáveis do ambiente
* @return saida do processo
* @throws IOException
* @throws TimeoutException processo excedeu timeout
*/
public String executa(String comando, String[] env) throws Exception {
Process p;
System.setProperty("file.encoding", "cp850");
if (env == null) {
p = Runtime.getRuntime().exec(comando, env);
} else {
p = Runtime.getRuntime().exec(comando);
}
StreamGobbler stdin = new StreamGobbler ("stdin", p.getInputStream());
StreamGobbler stderr = new StreamGobbler ("stderr", p.getErrorStream());
stdin.start();
stderr.start();
// Estabelece um "timer" caso o programa não tenha terminado de executar
// após o tempo estabelecido pelo timeout
Timer timer = new Timer();
timer.schedule(new InterrompeEscalonador(Thread.currentThread()), this.timeout);
try {
p.waitFor();
} catch (InterruptedException e) {
p.destroy();
Runtime.getRuntime().runFinalization();
stdin.interrupt();
stderr.interrupt();
return "O programa excedeu o tempo limite de execucao (" +
this.timeout + " milisegundos)";
} finally {
timer.cancel();
}
stdOut = stdin.getText();
stdErr = stderr.getText();
if (!stdin.getText().equals("")) {
return stdin.getText();
} else {
return stderr.getText();
}
}
private class InterrompeEscalonador extends TimerTask {
Thread target = null;
public InterrompeEscalonador(Thread target) {
this.target = target;
}
@Override
public void run() {
target.interrupt();
}
}
private class StreamGobbler implements Runnable {
String name;
InputStream is;
Thread thread;
StringBuilder buffer = new StringBuilder();
public StreamGobbler(String name, InputStream is) {
this.name = name;
this.is = is;
}
public void start() {
thread = new Thread(this);
thread.start();
}
public void interrupt() {
thread.interrupt();
}
public void run() {
try {
InputStreamReader isr = new InputStreamReader(is);
BufferedReader br = new BufferedReader(isr);
while (true) {
String s = br.readLine();
if (s == null)
break;
//System.out.println("[" + name + "] " + s);
buffer.append(s + "\n");
}
is.close();
} catch (Exception ex) {
System.out.println("Problem reading stream " + name + "... :" + ex);
ex.printStackTrace();
}
}
public String getText() {
return this.buffer.toString();
}
}
}