Index: main/trunk/gli/src/org/greenstone/gatherer/gui/DownloadPane.java
===================================================================
--- main/trunk/gli/src/org/greenstone/gatherer/gui/DownloadPane.java	(revision 31586)
+++ main/trunk/gli/src/org/greenstone/gatherer/gui/DownloadPane.java	(revision 31593)
@@ -280,4 +280,5 @@
 		// This time we expect XML to have come out of the process std error stream.
 		String errStreamOutput = process.getStdError();
+		///System.err.println("*********\nDownload Pane data, got:\n" + errStreamOutput + "\n**********\n");
 		StringReader xmlStrReader = new StringReader(errStreamOutput);
 		document = XMLTools.parseXML(xmlStrReader);
Index: main/trunk/gli/src/org/greenstone/gatherer/util/GS3ServerThread.java
===================================================================
--- main/trunk/gli/src/org/greenstone/gatherer/util/GS3ServerThread.java	(revision 31586)
+++ main/trunk/gli/src/org/greenstone/gatherer/util/GS3ServerThread.java	(revision 31593)
@@ -132,5 +132,4 @@
 	else {
 	    System.err.println("********** FAILED TO SUCCESSFULLY stop THE GS3 SERVER ON EXIT");
-	    //throw new Exception ("Failed to successfully stop the GS3 server on exit.");
 	}
 	
Index: main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java
===================================================================
--- main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java	(revision 31586)
+++ main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java	(revision 31593)
@@ -21,5 +21,5 @@
 public class SafeProcess {
 
-    //static Logger logger = Logger.getLogger(org.greenstone.util.SafeProcess.class.getName());
+    ///static Logger logger = Logger.getLogger(org.greenstone.util.SafeProcess.class.getName());
 
     // input to SafeProcess and initialising it
@@ -35,8 +35,5 @@
     private int exitValue = -1;
 
-    // user can write custom LineByLineHandler to deal with stdout lines as they come out one line at a time
-    // and stderr lines as they come out one at a time
-    private LineByLineHandler errLineByLineHandler = null;
-    private LineByLineHandler outLineByLineHandler = null;
+    // allow callers to process exceptions of the main process thread if they want
     private ExceptionHandler exceptionHandler = null;
 
@@ -79,14 +76,4 @@
     }
 
-    // register a handler whose gotLine() method will get called as each line is read from the process' stdout
-    public void setStdOutLineByLineHandler(LineByLineHandler out_lbl_handler) {
-	outLineByLineHandler = out_lbl_handler;
-    }
-
-    // register a handler whose gotLine() method will get called as each line is read from the process' stderr
-    public void setStdErrLineByLineHandler(LineByLineHandler err_lbl_handler) {
-	errLineByLineHandler = err_lbl_handler;
-    }
-
     // register a SafeProcess ExceptionHandler whose gotException() method will
     // get called for each exception encountered
@@ -104,6 +91,13 @@
 
 //***************** Copied from gli's gui/FormatConversionDialog.java *************//
+
     public int runProcess() {
-
+	return runProcess(null, null, null); // use default processing of all 3 of the process' iostreams
+    }
+
+    public int runProcess(CustomProcessHandler procInHandler,
+			   CustomProcessHandler procOutHandler,
+			   CustomProcessHandler procErrHandler)
+    {
 	Process prcs = null;
 	SafeProcess.OutputStreamGobbler inputGobbler = null;
@@ -112,5 +106,8 @@
 
 	try {	    
+	    
 	    Runtime rt = Runtime.getRuntime();	    
+	    
+	    
 	    if(this.command != null) {
 		prcs = rt.exec(this.command);
@@ -126,9 +123,9 @@
 		    
 		    if(this.dir == null) {
-			System.err.println("\twith: " + Arrays.toString(this.envp));
+			///System.err.println("\twith: " + Arrays.toString(this.envp));
 			prcs = rt.exec(this.command_args, this.envp);
 		    } else {
-			System.err.println("\tfrom directory: " + this.dir);
-			System.err.println("\twith: " + Arrays.toString(this.envp));
+			//System.err.println("\tfrom directory: " + this.dir);
+			//System.err.println("\twith: " + Arrays.toString(this.envp));
 			prcs = rt.exec(this.command_args, this.envp, this.dir);
 		    }
@@ -136,34 +133,44 @@
 	    }
 
-	    // send inputStr to process. The following constructor can handle inputStr being null
-	    inputGobbler = // WriterToProcessInputStream
-		new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), this.inputStr);
-	    
-	    // monitor for any error messages
-            errorGobbler // ReaderFromProcessOutputStream
-		= new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines);
-
-            // monitor for the expected std output line(s)
-            outputGobbler
-		= new SafeProcess.InputStreamGobbler(prcs.getInputStream(), splitStdOutputNewLines);
-	                
-	    // register line by line handlers, if any were set, for the process stderr and stdout streams
-	    if(this.outLineByLineHandler != null) {
-		outputGobbler.setLineByLineHandler(this.outLineByLineHandler);
-	    }
-	    if(this.errLineByLineHandler != null) {
-		errorGobbler.setLineByLineHandler(this.errLineByLineHandler);
-	    }
-	    if(this.exceptionHandler != null) {
-		inputGobbler.setExceptionHandler(this.exceptionHandler);
-	    }	    
-
+	    // Create the streamgobblers and set any specified handlers on them
+
+	    // PROC INPUT STREAM
+	    if(procInHandler == null) {
+		// send inputStr to process. The following constructor can handle inputStr being null
+		inputGobbler = // WriterToProcessInputStream
+		    new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), this.inputStr);
+	    } else { // user will do custom handling of process' InputStream 
+		inputGobbler = new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), procInHandler);
+	    }
+
+	    // PROC ERR STREAM to monitor for any error messages or expected output in the process' stderr
+	    if(procErrHandler == null) {
+		errorGobbler // ReaderFromProcessOutputStream
+		    = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines);		
+	    } else {
+		errorGobbler
+		    = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), procErrHandler);
+	    }
+
+            // PROC OUT STREAM to monitor for the expected std output line(s)
+	    if(procOutHandler == null) {
+		outputGobbler
+		    = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), splitStdOutputNewLines);
+	    } else {
+		outputGobbler
+		    = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), procOutHandler);
+	    }
+
+	    
             // kick off the stream gobblers
             inputGobbler.start();
             errorGobbler.start();
             outputGobbler.start();
-                                    
+
             // any error???
-            this.exitValue = prcs.waitFor(); // can throw an InterruptedException if process did not terminate	    	    
+            this.exitValue = prcs.waitFor(); // can throw an InterruptedException if process did not terminate
+
+            ///System.err.println("Process exitValue: " + exitValue);
+
 	    // From the comments of 
 	    // http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2
@@ -175,8 +182,9 @@
 	    inputGobbler.join(); 
 	    
+
 	    // set the variables the code that created a SafeProcess object may want to inspect
 	    this.outputStr = outputGobbler.getOutput();
 	    this.errorStr = errorGobbler.getOutput();
-
+	    
 	    // Since we didn't have an exception, process should have terminated now (waitFor blocks until then)
 	    // Set process to null so we don't forcibly terminate it below with process.destroy()
@@ -192,4 +200,5 @@
 	    }
 	} catch(InterruptedException ie) {
+
 	    if(exceptionHandler != null) {
 		exceptionHandler.gotException(ie);
@@ -197,7 +206,6 @@
 		//logger.error("Process InterruptedException: " + ie.getMessage(), ie);
 		System.err.println("Process InterruptedException " + ie.getMessage());
-		//ie.printStackTrace(); // an interrupt here is not an error, it can be a cancel action
-	    }
-
+		///ie.printStackTrace(); // an interrupt here is not an error, it can be a cancel action
+	    }
 
 	    // propagate interrupts to worker threads here?
@@ -237,5 +245,5 @@
 	    }
 	}
-
+	
 	return this.exitValue;
     }
@@ -257,9 +265,9 @@
 }
 
-// When reading from a process' stdout or stderr stream, you can create a LineByLineHandler
-// 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
+// write your own run() body for any StreamGobbler
+// 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
 }
 
@@ -270,13 +278,13 @@
 public static class InputStreamGobbler extends Thread
 {
-    InputStream is = null;
-    StringBuffer outputstr = new StringBuffer();
-    boolean split_newlines = false;
-    LineByLineHandler lineByLineHandler = null;
-    
+    private InputStream is = null;
+    private StringBuffer outputstr = new StringBuffer();
+    private boolean split_newlines = false;
+    private CustomProcessHandler customHandler = null;
+
     public InputStreamGobbler(InputStream is)
     {
 	this.is = is;
-	split_newlines = false;
+	this.split_newlines = false;
     }
     
@@ -287,10 +295,12 @@
     }
     
-    public void setLineByLineHandler(LineByLineHandler lblHandler) {
-	lineByLineHandler = lblHandler;
-    }
-
-
-    public void run()
+    public InputStreamGobbler(InputStream is, CustomProcessHandler customHandler)
+    {
+	this.is = is;
+	this.customHandler = customHandler;
+    }
+
+    // default run() behaviour
+    public void runDefault()
     {
 	BufferedReader br = null;
@@ -307,20 +317,12 @@
 		//System.out.println("@@@ GOT LINE: " + line);
 		outputstr.append(line);
-		
 		if(split_newlines) {
 		    outputstr.append(Utility.NEWLINE); // "\n" is system dependent (Win must be "\r\n")
 		}
-
-		if(lineByLineHandler != null) { // let handler deal with newlines
-		    lineByLineHandler.gotLine(line);
-		}		
-	    }
-	} catch (IOException ioe) {
-	    if(lineByLineHandler != null) {
-		lineByLineHandler.gotException(ioe);
-	    } else {
-		//logger.error("Exception when reading from a process' stdout/stderr stream: ", ioe);
-		ioe.printStackTrace();
-	    }
+	    }
+	} catch (IOException ioe) {	    
+	    //logger.error("Exception when reading from a process' stdout/stderr stream: ", ioe);
+	    System.err.println("Exception when reading from a process' stdout/stderr stream: ");
+	    ioe.printStackTrace();  
 	    
 	} finally {
@@ -329,4 +331,16 @@
     }
     
+    public void runCustom() {
+	this.customHandler.run(is);
+    }
+    
+    public void run() {
+	if(this.customHandler == null) {
+	    runDefault();
+	} else {
+	    runCustom();
+	}
+    }
+
     public String getOutput() { 
 	return outputstr.toString(); // implicit toString() call anyway. //return outputstr; 
@@ -340,7 +354,7 @@
 public static class OutputStreamGobbler extends Thread
 {
-    OutputStream os = null;
-    String inputstr = "";
-    ExceptionHandler exceptionHandler = null;
+    private OutputStream os = null;
+    private String inputstr = "";
+    private CustomProcessHandler customHandler = null;
 
     public OutputStreamGobbler(OutputStream os) {
@@ -353,11 +367,13 @@
 	this.inputstr = inputstr;
     }
-    
-    public void setExceptionHandler(ExceptionHandler eHandler) {
-	exceptionHandler = eHandler;
-    }
-
-    public void run()
-    {	
+
+    public OutputStreamGobbler(OutputStream os, CustomProcessHandler customHandler) {
+	this.os = os;
+	this.customHandler = customHandler;
+    }
+
+    // default run() behaviour
+    public void runDefault() {
+	
 	if (inputstr == null) {
 		return;
@@ -365,5 +381,5 @@
 	
 	BufferedWriter osw = null;
-	try	{
+	try {
 	    osw = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
 	    //System.out.println("@@@ SENDING LINE: " + inputstr);
@@ -385,14 +401,25 @@
 	    */
 	} catch (IOException ioe) {
-	    if (this.exceptionHandler != null) {
-		this.exceptionHandler.gotException(ioe);
-	    } else {
-		//logger.error("Exception writing to SafeProcess' inputstream: ", ioe);	    
-		ioe.printStackTrace();
-	    }	    
-	    
+	    //logger.error("Exception writing to SafeProcess' inputstream: ", ioe);
+	    System.err.println("Exception writing to SafeProcess' inputstream: ");
+	    ioe.printStackTrace();	
 	} finally {
 	    SafeProcess.closeResource(osw);
 	}
+    }
+
+    // call the user's custom handler for the run() method
+    public void runCustom() {
+	this.customHandler.run(os);	
+    }
+
+    public void run()
+    {
+	if(this.customHandler == null) {
+	    runDefault();
+	} else {
+	    runCustom();
+	}
+
     }	
 } // end static inner class OutputStreamGobbler
