Index: /main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java
===================================================================
--- /main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java	(revision 31629)
+++ /main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java	(revision 31630)
@@ -21,4 +21,8 @@
 public class SafeProcess {
 
+    public static final int STDERR = 0;
+    public static final int STDOUT = 1;
+    public static final int STDIN = 2;    
+
     ///static Logger logger = Logger.getLogger(org.greenstone.util.SafeProcess.class.getName());
 
@@ -95,4 +99,6 @@
 	
 	if(this.command != null) {
+	    //logger.info("SafeProcess running: " + command);
+	    System.err.println("SafeProcess running: " + command_args);
 	    prcs = rt.exec(this.command);
 	}
@@ -204,5 +210,5 @@
     }
 
-    // Runs a process with default stream processing
+    // Runs a process with default stream processing. Returns the exitValue
     public int runProcess() {
 	return runProcess(null, null, null); // use default processing of all 3 of the process' iostreams
@@ -210,5 +216,6 @@
 
     // Run a process with custom stream processing (any custom handlers passed in that are null
-    // will use the default stream processing)
+    // will use the default stream processing). 
+    // Returns the exitValue from running the Process
     public int runProcess(CustomProcessHandler procInHandler,
 			   CustomProcessHandler procOutHandler,
@@ -239,5 +246,5 @@
 	    if(procErrHandler == null) {
 		errorGobbler // ReaderFromProcessOutputStream
-		    = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines);		
+		    = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines);
 	    } else {
 		errorGobbler
@@ -414,5 +421,5 @@
 
 
-//******************** Inner class interface definitions ********************//
+//******************** Inner class and interface definitions ********************//
 // Static inner classes can be instantiated without having to instantiate an object of the outer class first
 
@@ -423,27 +430,45 @@
 public static interface ExceptionHandler {
 
-    // SHOULD I DECLARE THIS SYNCHRONIZED?
-    // It ends up being thread safe for the particular instance I'm using it for, but that doesn't
-    // make it future proof...
-    public void gotException(Exception e);
+    // when implementing ExceptionHandler.gotException(), if it manipulates anything that's
+    // not threadsafe, declare gotException() as a synchronized method to ensure thread safety
+    public void gotException(Exception e); // can't declare as synchronized in interface method declaration
 }
 
 // Write your own run() body for any StreamGobbler. You need to create an instance of a class
-// implementing CustomProcessHandler for EACH IOSTREAM of the process that you want to handle.
+// extending CustomProcessHandler for EACH IOSTREAM of the process that you want to handle.
 // Do not create a single CustomProcessHandler instance and reuse it for all three streams,
 // i.e. don't call SafeProcess' runProcess(x, x, x); It should be runProcess(x, y, z).
 // Make sure your implementation is threadsafe if you're sharing immutable objects between the threaded streams
 // example implementation is in the GS2PerlConstructor.SynchronizedProcessHandler class.
-public static interface CustomProcessHandler {
-    public void run(Closeable stream); //InputStream or OutputStream
+// CustomProcessHandler is made an abstract class instead of an interface to force classes that want
+// to use a CustomProcessHandler to create a separate class that extends CustomProcessHandler, rather than
+// that the classes that wish to use it "implementing" the CustomProcessHandler interface itself: the
+// CustomProcessHandler.run() method may then be called in the major thread from which the Process is being
+// executed, rather than from the individual threads that deal with each iostream of the Process.
+public static abstract class CustomProcessHandler {
+
+    protected final int source;
+
+    protected CustomProcessHandler(int src) {
+	this.source = src; // STDERR or STDOUT or STDIN
+    }
+    
+    public abstract void run(Closeable stream); //InputStream or OutputStream
 }
 
-// When using the default stream processing to read from a process' stdout or stderr stream,
-// you can create a LineByLineHandler for the process' err and out streams
+// When using the default stream processing to read from a process' stdout or stderr stream, you can
+// create a class extending LineByLineHandler for the process' err stream and one for its output stream
 // to do something on a line by line basis, such as sending the line to a log
-public static interface LineByLineHandler {
-    public void gotLine(String line);
-    public void gotException(Exception e); // for when an exception occurs instead of getting a line
+public static abstract class LineByLineHandler {
+    protected final int source;
+
+    protected LineByLineHandler(int src) {
+	this.source = src; // STDERR or STDOUT
+    }
+
+    public abstract void gotLine(String line); // first non-null line
+    public abstract void gotException(Exception e); // for when an exception occurs instead of getting a line
 }
+
 
 //**************** StreamGobbler Inner class definitions (stream gobblers copied from GLI) **********//
