package au.edu.mq.comp.common;
import java.io.IOException;
import java.util.Timer;
import au.edu.mq.comp.common.concurrency.InterruptTimerTask;
import au.edu.mq.comp.common.concurrency.StreamReader;
/**
*
* @author Pongsak Suvanpong (psksvp@gmail.com)
* This class spawn a new process to run a java class.
*/
public class JavaClassRunner extends Object
{
public static final int kWaitForProcessTimeout = -98989;
////////////////////////////////////////
private String outputString = "";
private String errorString = "";
private String pathToClass;
private java.util.ArrayList<String> classLibraryPathList = new java.util.ArrayList<String>();
/**
* constructor
* @param pathToClass string represents path(case sensitive) the directory where the target class files to run
*/
public JavaClassRunner(String pathToClass)
{
this.pathToClass = new String(pathToClass);
}
/**
* append class path needed by the target class files to run
* @param path
*/
public void appendLibraryClassPath(String path)
{
this.classLibraryPathList.add(path);
}
/**
*
* @return string to output stream from the spawn process
*/
public String outputString()
{
return this.outputString;
}
/**
*
* @return string to error stream from the spawn process
*/
public String errorString()
{
return this.errorString;
}
/**
* build a String of class path, to be passed to java command.
* @return String String of class path, to be passed to java command
*/
private String makeClassPathAsString()
{
StringBuffer output = new StringBuffer();
for(String path : this.classLibraryPathList)
{
output.append((new java.io.File(path)).getAbsolutePath());
output.append(OS.classPathSeperator());
}
output.append(".");
return output.toString();
}
/**
* spawn a new process to run a java class specified in className parameter.
* @param className - String of java class name to run.
* @param timeOutInMillisec - Int time out value, to specify how long this class should wait before killing the the spawned process, specify 0 to wait until the spawned process has finished
* @return Int value return from the spawned process or kWaitForProcessTimeout if timeout has occured.
* @throws IOException
* @throws InterruptedException
*/
public int runAndWait(String className, long timeOutInMillisec) throws IOException, InterruptedException
{
java.util.ArrayList<String> command = new java.util.ArrayList<String>();
command.add(OS.pathToClassInterpreter());
if(0 < this.classLibraryPathList.size())
{
command.add("-classpath");
command.add(this.makeClassPathAsString());
}
command.add(className);
java.lang.ProcessBuilder pb = new java.lang.ProcessBuilder(command);
pb.directory(new java.io.File(this.pathToClass));
//System.out.println("going to run java class with command -->" + command);
//System.out.println("current working dir for command is -->" + this.pathToClass);
java.lang.Process p = pb.start();
int exitCode = -1;
StreamReader outputStreamReader = new StreamReader(p.getInputStream());
StreamReader errorStreamReader = new StreamReader(p.getErrorStream());
outputStreamReader.start();
errorStreamReader.start();
if(timeOutInMillisec > 0)
{
Timer timer = null;
try
{
timer = new Timer(true);
InterruptTimerTask interrupter = new InterruptTimerTask(Thread.currentThread());
timer.schedule(interrupter, timeOutInMillisec);
exitCode = p.waitFor();
}
catch(InterruptedException e)
{
// do something to handle the timeout here
Log.message("going to kill process with hashcode " + p.hashCode());
p.destroy();
exitCode = JavaClassRunner.kWaitForProcessTimeout;
Log.message("process with hashcode " + p.hashCode() + " killed");
}
finally
{
timer.cancel();
Thread.interrupted();
}
}
else
{
exitCode = p.waitFor();
}
this.outputString = outputStreamReader.toString();
this.errorString = errorStreamReader.toString();
return exitCode;
}
}