Changeset 31593


Ignore:
Timestamp:
2017-04-07T18:38:05+12:00 (7 years ago)
Author:
ak19
Message:

Porting the modifications for SafeProcess.java from GS3 src code to GLI. Now GLI also uses the new SafeProcess.CustomProcessHandler instead of the LineByLineHandler whose process flow may have been less transparent to developers. GLI's updated SafeProcess.java has now been tested successfully against DownloadPane, GS3ServerThread and FormatConversionDialog all of which use SafeProcess.java since yesterday. Things that worked still work.

Location:
main/trunk/gli/src/org/greenstone/gatherer
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • main/trunk/gli/src/org/greenstone/gatherer/gui/DownloadPane.java

    r31585 r31593  
    280280        // This time we expect XML to have come out of the process std error stream.
    281281        String errStreamOutput = process.getStdError();
     282        ///System.err.println("*********\nDownload Pane data, got:\n" + errStreamOutput + "\n**********\n");
    282283        StringReader xmlStrReader = new StringReader(errStreamOutput);
    283284        document = XMLTools.parseXML(xmlStrReader);
  • main/trunk/gli/src/org/greenstone/gatherer/util/GS3ServerThread.java

    r31584 r31593  
    132132    else {
    133133        System.err.println("********** FAILED TO SUCCESSFULLY stop THE GS3 SERVER ON EXIT");
    134         //throw new Exception ("Failed to successfully stop the GS3 server on exit.");
    135134    }
    136135   
  • main/trunk/gli/src/org/greenstone/gatherer/util/SafeProcess.java

    r31586 r31593  
    2121public class SafeProcess {
    2222
    23     //static Logger logger = Logger.getLogger(org.greenstone.util.SafeProcess.class.getName());
     23    ///static Logger logger = Logger.getLogger(org.greenstone.util.SafeProcess.class.getName());
    2424
    2525    // input to SafeProcess and initialising it
     
    3535    private int exitValue = -1;
    3636
    37     // user can write custom LineByLineHandler to deal with stdout lines as they come out one line at a time
    38     // and stderr lines as they come out one at a time
    39     private LineByLineHandler errLineByLineHandler = null;
    40     private LineByLineHandler outLineByLineHandler = null;
     37    // allow callers to process exceptions of the main process thread if they want
    4138    private ExceptionHandler exceptionHandler = null;
    4239
     
    7976    }
    8077
    81     // register a handler whose gotLine() method will get called as each line is read from the process' stdout
    82     public void setStdOutLineByLineHandler(LineByLineHandler out_lbl_handler) {
    83     outLineByLineHandler = out_lbl_handler;
    84     }
    85 
    86     // register a handler whose gotLine() method will get called as each line is read from the process' stderr
    87     public void setStdErrLineByLineHandler(LineByLineHandler err_lbl_handler) {
    88     errLineByLineHandler = err_lbl_handler;
    89     }
    90 
    9178    // register a SafeProcess ExceptionHandler whose gotException() method will
    9279    // get called for each exception encountered
     
    10491
    10592//***************** Copied from gli's gui/FormatConversionDialog.java *************//
     93
    10694    public int runProcess() {
    107 
     95    return runProcess(null, null, null); // use default processing of all 3 of the process' iostreams
     96    }
     97
     98    public int runProcess(CustomProcessHandler procInHandler,
     99               CustomProcessHandler procOutHandler,
     100               CustomProcessHandler procErrHandler)
     101    {
    108102    Process prcs = null;
    109103    SafeProcess.OutputStreamGobbler inputGobbler = null;
     
    112106
    113107    try {       
     108       
    114109        Runtime rt = Runtime.getRuntime();     
     110       
     111       
    115112        if(this.command != null) {
    116113        prcs = rt.exec(this.command);
     
    126123           
    127124            if(this.dir == null) {
    128             System.err.println("\twith: " + Arrays.toString(this.envp));
     125            ///System.err.println("\twith: " + Arrays.toString(this.envp));
    129126            prcs = rt.exec(this.command_args, this.envp);
    130127            } else {
    131             System.err.println("\tfrom directory: " + this.dir);
    132             System.err.println("\twith: " + Arrays.toString(this.envp));
     128            //System.err.println("\tfrom directory: " + this.dir);
     129            //System.err.println("\twith: " + Arrays.toString(this.envp));
    133130            prcs = rt.exec(this.command_args, this.envp, this.dir);
    134131            }
     
    136133        }
    137134
    138         // send inputStr to process. The following constructor can handle inputStr being null
    139         inputGobbler = // WriterToProcessInputStream
    140         new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), this.inputStr);
    141        
    142         // monitor for any error messages
    143             errorGobbler // ReaderFromProcessOutputStream
    144         = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines);
    145 
    146             // monitor for the expected std output line(s)
    147             outputGobbler
    148         = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), splitStdOutputNewLines);
    149                    
    150         // register line by line handlers, if any were set, for the process stderr and stdout streams
    151         if(this.outLineByLineHandler != null) {
    152         outputGobbler.setLineByLineHandler(this.outLineByLineHandler);
    153         }
    154         if(this.errLineByLineHandler != null) {
    155         errorGobbler.setLineByLineHandler(this.errLineByLineHandler);
    156         }
    157         if(this.exceptionHandler != null) {
    158         inputGobbler.setExceptionHandler(this.exceptionHandler);
    159         }       
    160 
     135        // Create the streamgobblers and set any specified handlers on them
     136
     137        // PROC INPUT STREAM
     138        if(procInHandler == null) {
     139        // send inputStr to process. The following constructor can handle inputStr being null
     140        inputGobbler = // WriterToProcessInputStream
     141            new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), this.inputStr);
     142        } else { // user will do custom handling of process' InputStream
     143        inputGobbler = new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), procInHandler);
     144        }
     145
     146        // PROC ERR STREAM to monitor for any error messages or expected output in the process' stderr
     147        if(procErrHandler == null) {
     148        errorGobbler // ReaderFromProcessOutputStream
     149            = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines);     
     150        } else {
     151        errorGobbler
     152            = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), procErrHandler);
     153        }
     154
     155            // PROC OUT STREAM to monitor for the expected std output line(s)
     156        if(procOutHandler == null) {
     157        outputGobbler
     158            = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), splitStdOutputNewLines);
     159        } else {
     160        outputGobbler
     161            = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), procOutHandler);
     162        }
     163
     164       
    161165            // kick off the stream gobblers
    162166            inputGobbler.start();
    163167            errorGobbler.start();
    164168            outputGobbler.start();
    165                                    
     169
    166170            // any error???
    167             this.exitValue = prcs.waitFor(); // can throw an InterruptedException if process did not terminate             
     171            this.exitValue = prcs.waitFor(); // can throw an InterruptedException if process did not terminate
     172
     173            ///System.err.println("Process exitValue: " + exitValue);
     174
    168175        // From the comments of
    169176        // http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2
     
    175182        inputGobbler.join();
    176183       
     184
    177185        // set the variables the code that created a SafeProcess object may want to inspect
    178186        this.outputStr = outputGobbler.getOutput();
    179187        this.errorStr = errorGobbler.getOutput();
    180 
     188       
    181189        // Since we didn't have an exception, process should have terminated now (waitFor blocks until then)
    182190        // Set process to null so we don't forcibly terminate it below with process.destroy()
     
    192200        }
    193201    } catch(InterruptedException ie) {
     202
    194203        if(exceptionHandler != null) {
    195204        exceptionHandler.gotException(ie);
     
    197206        //logger.error("Process InterruptedException: " + ie.getMessage(), ie);
    198207        System.err.println("Process InterruptedException " + ie.getMessage());
    199         //ie.printStackTrace(); // an interrupt here is not an error, it can be a cancel action
    200         }
    201 
     208        ///ie.printStackTrace(); // an interrupt here is not an error, it can be a cancel action
     209        }
    202210
    203211        // propagate interrupts to worker threads here?
     
    237245        }
    238246    }
    239 
     247   
    240248    return this.exitValue;
    241249    }
     
    257265}
    258266
    259 // When reading from a process' stdout or stderr stream, you can create a LineByLineHandler
    260 // to do something on a line by line basis, such as sending the line to a log
    261 public static interface LineByLineHandler {
    262     public void gotLine(String line);
    263     public void gotException(Exception e); // for when an exception occurs instead of getting a line
     267// write your own run() body for any StreamGobbler
     268// Make sure your implementation is threadsafe if you're sharing immutable objects between the threaded streams
     269// example implementation is in the GS2PerlConstructor.SynchronizedProcessHandler class.
     270public static interface CustomProcessHandler {
     271    public void run(Closeable stream); //InputStream or OutputStream
    264272}
    265273
     
    270278public static class InputStreamGobbler extends Thread
    271279{
    272     InputStream is = null;
    273     StringBuffer outputstr = new StringBuffer();
    274     boolean split_newlines = false;
    275     LineByLineHandler lineByLineHandler = null;
    276    
     280    private InputStream is = null;
     281    private StringBuffer outputstr = new StringBuffer();
     282    private boolean split_newlines = false;
     283    private CustomProcessHandler customHandler = null;
     284
    277285    public InputStreamGobbler(InputStream is)
    278286    {
    279287    this.is = is;
    280     split_newlines = false;
     288    this.split_newlines = false;
    281289    }
    282290   
     
    287295    }
    288296   
    289     public void setLineByLineHandler(LineByLineHandler lblHandler) {
    290     lineByLineHandler = lblHandler;
    291     }
    292 
    293 
    294     public void run()
     297    public InputStreamGobbler(InputStream is, CustomProcessHandler customHandler)
     298    {
     299    this.is = is;
     300    this.customHandler = customHandler;
     301    }
     302
     303    // default run() behaviour
     304    public void runDefault()
    295305    {
    296306    BufferedReader br = null;
     
    307317        //System.out.println("@@@ GOT LINE: " + line);
    308318        outputstr.append(line);
    309        
    310319        if(split_newlines) {
    311320            outputstr.append(Utility.NEWLINE); // "\n" is system dependent (Win must be "\r\n")
    312321        }
    313 
    314         if(lineByLineHandler != null) { // let handler deal with newlines
    315             lineByLineHandler.gotLine(line);
    316         }       
    317         }
    318     } catch (IOException ioe) {
    319         if(lineByLineHandler != null) {
    320         lineByLineHandler.gotException(ioe);
    321         } else {
    322         //logger.error("Exception when reading from a process' stdout/stderr stream: ", ioe);
    323         ioe.printStackTrace();
    324         }
     322        }
     323    } catch (IOException ioe) {     
     324        //logger.error("Exception when reading from a process' stdout/stderr stream: ", ioe);
     325        System.err.println("Exception when reading from a process' stdout/stderr stream: ");
     326        ioe.printStackTrace(); 
    325327       
    326328    } finally {
     
    329331    }
    330332   
     333    public void runCustom() {
     334    this.customHandler.run(is);
     335    }
     336   
     337    public void run() {
     338    if(this.customHandler == null) {
     339        runDefault();
     340    } else {
     341        runCustom();
     342    }
     343    }
     344
    331345    public String getOutput() {
    332346    return outputstr.toString(); // implicit toString() call anyway. //return outputstr;
     
    340354public static class OutputStreamGobbler extends Thread
    341355{
    342     OutputStream os = null;
    343     String inputstr = "";
    344     ExceptionHandler exceptionHandler = null;
     356    private OutputStream os = null;
     357    private String inputstr = "";
     358    private CustomProcessHandler customHandler = null;
    345359
    346360    public OutputStreamGobbler(OutputStream os) {
     
    353367    this.inputstr = inputstr;
    354368    }
    355    
    356     public void setExceptionHandler(ExceptionHandler eHandler) {
    357     exceptionHandler = eHandler;
    358     }
    359 
    360     public void run()
    361     {   
     369
     370    public OutputStreamGobbler(OutputStream os, CustomProcessHandler customHandler) {
     371    this.os = os;
     372    this.customHandler = customHandler;
     373    }
     374
     375    // default run() behaviour
     376    public void runDefault() {
     377   
    362378    if (inputstr == null) {
    363379        return;
     
    365381   
    366382    BufferedWriter osw = null;
    367     try {
     383    try {
    368384        osw = new BufferedWriter(new OutputStreamWriter(os, "UTF-8"));
    369385        //System.out.println("@@@ SENDING LINE: " + inputstr);
     
    385401        */
    386402    } catch (IOException ioe) {
    387         if (this.exceptionHandler != null) {
    388         this.exceptionHandler.gotException(ioe);
    389         } else {
    390         //logger.error("Exception writing to SafeProcess' inputstream: ", ioe);     
    391         ioe.printStackTrace();
    392         }       
    393        
     403        //logger.error("Exception writing to SafeProcess' inputstream: ", ioe);
     404        System.err.println("Exception writing to SafeProcess' inputstream: ");
     405        ioe.printStackTrace(); 
    394406    } finally {
    395407        SafeProcess.closeResource(osw);
    396408    }
     409    }
     410
     411    // call the user's custom handler for the run() method
     412    public void runCustom() {
     413    this.customHandler.run(os);
     414    }
     415
     416    public void run()
     417    {
     418    if(this.customHandler == null) {
     419        runDefault();
     420    } else {
     421        runCustom();
     422    }
     423
    397424    }   
    398425} // end static inner class OutputStreamGobbler
Note: See TracChangeset for help on using the changeset viewer.