package org.archstudio.sysutils;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Hashtable;
public class NativeProcess extends Thread {
protected Process p;
protected Object lock = new Object();
protected InputStream processStdin;
protected long stdinLen = -1;
protected ByteArrayOutputStream processStdout;
protected ByteArrayOutputStream processStderr;
protected boolean hasExited;
protected int exitCode;
protected boolean hasJavaError;
protected Throwable javaError;
protected boolean terminateNow = false;
protected Hashtable<String, Object> properties = new Hashtable<String, Object>();
public NativeProcess(Process p) {
this.p = p;
processStdout = new ByteArrayOutputStream();
processStderr = new ByteArrayOutputStream();
hasExited = false;
exitCode = -1;
hasJavaError = false;
javaError = null;
}
protected NativeProcess(Process p, InputStream stdin) {
this(p);
this.processStdin = stdin;
}
public NativeProcess(Process p, InputStream stdin, long stdinLen) {
this(p, stdin);
this.stdinLen = stdinLen;
}
public NativeProcess(Process p, String processInput) {
//this(p, new ByteArrayInputStream(processInput.getBytes()), processInput.getBytes().length);
this(p, new ByteArrayInputStream(processInput.getBytes()), processInput.getBytes().length);
}
public void setProperty(String name, Object value) {
properties.put(name, value);
}
public Object getProperty(String name) {
return properties.get(name);
}
public boolean hasExited() {
return hasExited;
}
public int getExitCode() {
return exitCode;
}
public boolean hasJavaError() {
return hasJavaError;
}
public Throwable getJavaError() {
return javaError;
}
public String getStdout() {
return new String(processStdout.toByteArray());
}
public String getStderr() {
return new String(processStderr.toByteArray());
}
@Override
public void destroy() {
terminateNow = true;
}
public static synchronized int blt_noblock(InputStream is, OutputStream os) throws IOException {
if (os == null) {
throw new RuntimeException("OutputStream was null in blt_noblock.");
}
byte[] buf = new byte[512];
int lenMoved = 0;
while (is.available() > 0) {
int len = is.read(buf);
if (len == -1) {
break;
}
//System.out.write(buf, 0, len);
os.write(buf, 0, len);
lenMoved += len;
}
return lenMoved;
}
@Override
public void run() {
long bytesLeft = stdinLen;
InputStream in = null;
InputStream err = null;
OutputStream out = null;
//BufferedOutputStream bout = null;
try {
int exitValue = -1; // returned to caller when p is finished
if (processStdin != null) {
out = p.getOutputStream();
}
in = p.getInputStream();
err = p.getErrorStream();
boolean finished = false; // Set to true when p is finished
while (!finished) {
try {
if (terminateNow) {
throw new InterruptedException();
}
if (processStdin != null) {
while (processStdin.available() > 0) {
int bytesRead = blt_noblock(processStdin, out);
bytesLeft -= bytesRead;
//System.out.println("bytesLeft = " + bytesLeft);
if (bytesLeft == 0) {
processStdin.close();
out.flush();
out.close();
}
}
}
while (in.available() > 0) {
blt_noblock(in, processStdout);
}
if (terminateNow) {
throw new InterruptedException();
}
while (err.available() > 0) {
blt_noblock(err, processStderr);
}
if (terminateNow) {
throw new InterruptedException();
}
// Ask the process for its exitValue. If the process
// is not finished, an IllegalThreadStateException
// is thrown. If it is finished, we fall through and
// the variable finished is set to true.
exitValue = p.exitValue();
finished = true;
}
catch (IllegalThreadStateException e) {
// Process is not finished yet;
// Sleep a little to save on CPU cycles
try {
Thread.sleep(250);
}
catch (InterruptedException ie) {
}
}
}
//Grab any leftovers.
while (in.available() > 0) {
blt_noblock(in, processStdout);
}
while (err.available() > 0) {
blt_noblock(err, processStderr);
}
in.close();
err.close();
processStdout.close();
processStderr.close();
exitCode = exitValue;
hasExited = true;
notifyOfCompletion();
}
catch (IOException e) {
hasExited = true;
hasJavaError = true;
javaError = e;
notifyOfCompletion();
}
catch (InterruptedException e) {
hasExited = true;
p.destroy();
hasJavaError = true;
javaError = e;
notifyOfCompletion();
}
finally {
if (in != null) {
try {
in.close();
}
catch (IOException e1) {
}
}
if (err != null) {
try {
err.close();
}
catch (IOException e2) {
}
}
notifyOfCompletion();
}
}
public void waitForCompletion() {
synchronized (lock) {
while (!hasExited) {
try {
lock.wait();
}
catch (InterruptedException e) {
}
}
}
}
public void notifyOfCompletion() {
synchronized (lock) {
lock.notifyAll();
}
}
}