package cz.nkp.differ.plugins.tools;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import org.apache.log4j.Logger;
public class CommandHelper extends Thread{
public static final class CommandInfo{
public String workingDir;
public String[] commands;
};
public static abstract class CommandMessageCallback{
public abstract void messageGenerated(String source, String message);
};
private static Logger LOGGER = Logger.getRootLogger();
private CommandMessageCallback callback;
private ProcessBuilder pb;
private StreamGobbler stdGobbler = null ,errorGobbler = null;
private boolean errorFlag = false;
private String name = "CommandHelper";
public CommandHelper(String name, CommandInfo info,CommandMessageCallback callback,Logger logger){
if(info == null || callback == null || logger == null){
throw new IllegalArgumentException("Cannot pass null parameters to CommandHelper");
}
LOGGER = logger;
this.callback = callback;
if(name != null){
this.name = name;
}
pb = new ProcessBuilder();
pb.directory(new File(info.workingDir));
pb.command(info.commands);
}
public void run(){
try {
Process proc = pb.start();
stdGobbler = new StreamGobbler(proc.getInputStream(),LOGGER);
stdGobbler.start();
errorGobbler = new StreamGobbler(proc.getErrorStream(),LOGGER);
errorGobbler.start();
try {
proc.waitFor();
} catch (InterruptedException e) {
LOGGER.error("["+ name +"]" + "Command process interrupted",e);
}
callback.messageGenerated(name,getMessage());
} catch (IOException e) {
LOGGER.error("["+ name +"]" + "Unable to run process",e);
errorFlag = true;
return;
}
}
private String getMessage() throws IOException{
if(errorFlag){
throw new IOException("The command was invalid and no message could be generated");
}
if(stdGobbler == null || errorGobbler == null){
throw new IOException("The command streams were not correctly created");
}
boolean errorStreamProcessed = false;
while(true){//infinite loop is ok because this is called from IO processing thread.
if(!errorStreamProcessed && errorGobbler.isReady()){
String errorMsg = errorGobbler.getMessage();
if(errorMsg != null && errorMsg.trim() != errorMsg){
LOGGER.error("["+ name +"][stderr]" + errorMsg);
}
errorStreamProcessed = true;
}
if(stdGobbler.isReady()){
return stdGobbler.getMessage();
}
}
}
}
class StreamGobbler extends Thread
{
private static Logger LOGGER = Logger.getRootLogger();
InputStream is;
private boolean isReady = false;
private String msg = "";
public StreamGobbler(InputStream is, Logger logger){
this.is = is;
LOGGER = logger;
}
public void run(){
InputStreamReader stream = null;
BufferedReader br = null;
try{
stream = new InputStreamReader(is);
br = new BufferedReader(stream);
String line = null;
while (true){
line = br.readLine();
if(line == null){
isReady = true;
break;
}else{
msg += line;
}
}
} catch (IOException e){
LOGGER.error("Gobbler had an error!",e);
} finally{
if(stream != null){
try {
stream.close();
} catch (IOException e) {
LOGGER.warn("Unable to close stream reader",e);
}
}
if(br != null){
try {
br.close();
} catch (IOException e) {
LOGGER.warn("Unable to close stream reader",e);
}
}
}
}
public boolean isReady(){
return isReady;
}
public String getMessage(){
if(isReady()){
return msg;
}
else return null;
}
}