- Timestamp:
- 2017-04-07T17:47:14+12:00 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone3/src/java/org/greenstone/util/SafeProcess.java
r31588 r31591 35 35 private int exitValue = -1; 36 36 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 41 38 private ExceptionHandler exceptionHandler = null; 42 39 … … 79 76 } 80 77 81 // register a handler whose gotLine() method will get called as each line is read from the process' stdout82 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' stderr87 public void setStdErrLineByLineHandler(LineByLineHandler err_lbl_handler) {88 errLineByLineHandler = err_lbl_handler;89 }90 91 78 // register a SafeProcess ExceptionHandler whose gotException() method will 92 79 // get called for each exception encountered … … 104 91 105 92 //***************** Copied from gli's gui/FormatConversionDialog.java *************// 93 106 94 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 { 108 102 Process prcs = null; 109 103 SafeProcess.OutputStreamGobbler inputGobbler = null; … … 112 106 113 107 try { 108 114 109 Runtime rt = Runtime.getRuntime(); 110 111 115 112 if(this.command != null) { 116 113 prcs = rt.exec(this.command); … … 119 116 120 117 // http://stackoverflow.com/questions/5283444/convert-array-of-strings-into-a-string-in-java 121 ///logger.info("SafeProcess running: " + Arrays.toString(command_args));118 logger.info("SafeProcess running: " + Arrays.toString(command_args)); 122 119 123 120 if(this.envp == null) { … … 136 133 } 137 134 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 } 135 logger.info("### Before creating ProcessInGobbler"); 136 137 // Create the streamgobblers and set any specified handlers on them 138 139 // PROC INPUT STREAM 140 if(procInHandler == null) { 141 // send inputStr to process. The following constructor can handle inputStr being null 142 inputGobbler = // WriterToProcessInputStream 143 new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), this.inputStr); 144 } else { // user will do custom handling of process' InputStream 145 inputGobbler = new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), procInHandler); 146 } 147 148 logger.info("### Before creating ProcessErrGobbler"); 149 150 // PROC ERR STREAM to monitor for any error messages or expected output in the process' stderr 151 if(procErrHandler == null) { 152 errorGobbler // ReaderFromProcessOutputStream 153 = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines); 154 } else { 155 errorGobbler 156 = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), procErrHandler); 157 } 158 159 logger.info("### Before creating ProcessOutGobbler"); 160 161 // PROC OUT STREAM to monitor for the expected std output line(s) 162 if(procOutHandler == null) { 163 outputGobbler 164 = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), splitStdOutputNewLines); 165 } else { 166 outputGobbler 167 = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), procOutHandler); 168 } 169 170 171 logger.info("### Before streamgobblers.start()"); 160 172 161 173 // kick off the stream gobblers … … 163 175 errorGobbler.start(); 164 176 outputGobbler.start(); 177 178 logger.info("### After streamgobblers.start() - before waitFor"); 165 179 166 180 // any error??? 167 this.exitValue = prcs.waitFor(); // can throw an InterruptedException if process did not terminate 181 this.exitValue = prcs.waitFor(); // can throw an InterruptedException if process did not terminate 182 183 logger.info("Process exitValue: " + exitValue); 184 185 logger.info("### Before streamgobblers.join()"); 186 168 187 // From the comments of 169 188 // http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2 … … 175 194 inputGobbler.join(); 176 195 196 logger.info("### After streamgobblers.join()"); 197 177 198 // set the variables the code that created a SafeProcess object may want to inspect 178 199 this.outputStr = outputGobbler.getOutput(); 179 200 this.errorStr = errorGobbler.getOutput(); 180 201 181 202 // Since we didn't have an exception, process should have terminated now (waitFor blocks until then) 182 203 // Set process to null so we don't forcibly terminate it below with process.destroy() … … 192 213 } 193 214 } catch(InterruptedException ie) { 215 194 216 if(exceptionHandler != null) { 195 217 exceptionHandler.gotException(ie); … … 197 219 logger.error("Process InterruptedException: " + ie.getMessage(), ie); 198 220 //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 221 ///ie.printStackTrace(); // an interrupt here is not an error, it can be a cancel action 222 } 202 223 203 224 // propagate interrupts to worker threads here? … … 237 258 } 238 259 } 239 260 240 261 return this.exitValue; 241 262 } … … 257 278 } 258 279 259 // When reading from a process' stdout or stderr stream, you can create a LineByLineHandler260 // to do something on a line by line basis, such as sending the line to a log261 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 line280 // write your own run() body for any StreamGobbler 281 // Make sure your implementation is threadsafe if you're sharing immutable objects between the threaded streams 282 // example implementation is in the GS2PerlConstructor.SynchronizedProcessHandler class. 283 public static interface CustomProcessHandler { 284 public void run(Closeable stream); //InputStream or OutputStream 264 285 } 265 286 … … 270 291 public static class InputStreamGobbler extends Thread 271 292 { 272 InputStream is = null;273 StringBuffer outputstr = new StringBuffer();274 boolean split_newlines = false;275 LineByLineHandler lineByLineHandler = null;276 293 private InputStream is = null; 294 private StringBuffer outputstr = new StringBuffer(); 295 private boolean split_newlines = false; 296 private CustomProcessHandler customHandler = null; 297 277 298 public InputStreamGobbler(InputStream is) 278 299 { 279 300 this.is = is; 280 split_newlines = false;301 this.split_newlines = false; 281 302 } 282 303 … … 287 308 } 288 309 289 public void setLineByLineHandler(LineByLineHandler lblHandler) { 290 lineByLineHandler = lblHandler; 291 } 292 293 294 public void run() 310 public InputStreamGobbler(InputStream is, CustomProcessHandler customHandler) 311 { 312 this.is = is; 313 this.customHandler = customHandler; 314 } 315 316 // default run() behaviour 317 public void runDefault() 295 318 { 296 319 BufferedReader br = null; … … 307 330 //System.out.println("@@@ GOT LINE: " + line); 308 331 outputstr.append(line); 309 310 332 if(split_newlines) { 311 333 outputstr.append(Misc.NEWLINE); // "\n" is system dependent (Win must be "\r\n") 312 334 } 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 } 335 } 336 } catch (IOException ioe) { 337 logger.error("Exception when reading from a process' stdout/stderr stream: ", ioe); 338 //System.err.println("Exception when reading from a process' stdout/stderr stream: "); 339 //ioe.printStackTrace(); 325 340 326 341 } finally { … … 329 344 } 330 345 346 public void runCustom() { 347 this.customHandler.run(is); 348 } 349 350 public void run() { 351 if(this.customHandler == null) { 352 runDefault(); 353 } else { 354 runCustom(); 355 } 356 } 357 331 358 public String getOutput() { 332 359 return outputstr.toString(); // implicit toString() call anyway. //return outputstr; … … 340 367 public static class OutputStreamGobbler extends Thread 341 368 { 342 OutputStream os = null;343 String inputstr = "";344 ExceptionHandler exceptionHandler = null;369 private OutputStream os = null; 370 private String inputstr = ""; 371 private CustomProcessHandler customHandler = null; 345 372 346 373 public OutputStreamGobbler(OutputStream os) { … … 353 380 this.inputstr = inputstr; 354 381 } 355 356 public void setExceptionHandler(ExceptionHandler eHandler) { 357 exceptionHandler = eHandler; 358 } 359 360 public void run() 361 { 382 383 public OutputStreamGobbler(OutputStream os, CustomProcessHandler customHandler) { 384 this.os = os; 385 this.customHandler = customHandler; 386 } 387 388 // default run() behaviour 389 public void runDefault() { 390 362 391 if (inputstr == null) { 363 392 return; … … 365 394 366 395 BufferedWriter osw = null; 367 try 396 try { 368 397 osw = new BufferedWriter(new OutputStreamWriter(os, "UTF-8")); 369 398 //System.out.println("@@@ SENDING LINE: " + inputstr); … … 385 414 */ 386 415 } 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 416 logger.error("Exception writing to SafeProcess' inputstream: ", ioe); 417 //System.err.println("Exception writing to SafeProcess' inputstream: "); 418 //ioe.printStackTrace(); 394 419 } finally { 395 420 SafeProcess.closeResource(osw); 396 421 } 422 } 423 424 // call the user's custom handler for the run() method 425 public void runCustom() { 426 this.customHandler.run(os); 427 } 428 429 public void run() 430 { 431 if(this.customHandler == null) { 432 runDefault(); 433 } else { 434 runCustom(); 435 } 436 397 437 } 398 438 } // end static inner class OutputStreamGobbler
Note:
See TracChangeset
for help on using the changeset viewer.