Changeset 31616
- Timestamp:
- 2017-04-20T19:38:44+12:00 (7 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
main/trunk/greenstone3/src/java/org/greenstone/util/SafeProcess.java
r31615 r31616 124 124 } 125 125 126 127 // no reading from or writing to Process' iostreams, just exec process and wait for it to return 128 public int runBasicProcess() { 129 Process prcs = null; 130 try { 131 prcs = doRuntimeExec(); 132 this.exitValue = prcs.waitFor(); 133 134 135 } catch(IOException ioe) { 136 if(exceptionHandler != null) { 137 exceptionHandler.gotException(ioe); 138 } else { 139 logger.error("IOException: " + ioe.getMessage(), ioe); 140 //System.err.println("IOException " + ioe.getMessage()); 141 //ioe.printStackTrace(); 142 } 143 } catch(InterruptedException ie) { 144 145 if(exceptionHandler != null) { 146 exceptionHandler.gotException(ie); 147 } else { 148 logger.error("Process InterruptedException: " + ie.getMessage(), ie); 149 //System.err.println("Process InterruptedException " + ie.getMessage()); 150 ///ie.printStackTrace(); // an interrupt here is not an error, it can be a cancel action 151 } 152 153 Thread.currentThread().interrupt(); 154 } finally { 155 156 if( prcs != null ) { 157 prcs.destroy(); // see runProcess() below 158 } 159 } 160 return this.exitValue; 161 } 162 163 public int runProcess() { 164 return runProcess(null, null, null); // use default processing of all 3 of the process' iostreams 165 } 166 167 //***************** Copied from gli's gui/FormatConversionDialog.java *************// 168 169 public int runProcess(CustomProcessHandler procInHandler, 170 CustomProcessHandler procOutHandler, 171 CustomProcessHandler procErrHandler) 172 { 173 Process prcs = null; 174 SafeProcess.OutputStreamGobbler inputGobbler = null; 175 SafeProcess.InputStreamGobbler errorGobbler = null; 176 SafeProcess.InputStreamGobbler outputGobbler = null; 177 178 try { 179 prcs = doRuntimeExec(); 180 181 182 // Create the streamgobblers and set any specified handlers on them 183 184 // PROC INPUT STREAM 185 if(procInHandler == null) { 186 // send inputStr to process. The following constructor can handle inputStr being null 187 inputGobbler = // WriterToProcessInputStream 188 new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), this.inputStr); 189 } else { // user will do custom handling of process' InputStream 190 inputGobbler = new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), procInHandler); 191 } 192 193 // PROC ERR STREAM to monitor for any error messages or expected output in the process' stderr 194 if(procErrHandler == null) { 195 errorGobbler // ReaderFromProcessOutputStream 196 = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines); 197 } else { 198 errorGobbler 199 = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), procErrHandler); 200 } 201 202 // PROC OUT STREAM to monitor for the expected std output line(s) 203 if(procOutHandler == null) { 204 outputGobbler 205 = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), splitStdOutputNewLines); 206 } else { 207 outputGobbler 208 = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), procOutHandler); 209 } 210 126 // Copied from gli's gui/FormatConversionDialog.java 127 private int waitForWithStreams(Process prcs, 128 SafeProcess.OutputStreamGobbler inputGobbler, 129 SafeProcess.InputStreamGobbler outputGobbler, 130 SafeProcess.InputStreamGobbler errorGobbler) 131 throws IOException, InterruptedException 132 { 211 133 212 134 // kick off the stream gobblers … … 237 159 // Set process to null so we don't forcibly terminate it below with process.destroy() 238 160 prcs = null; 161 162 return this.exitValue; 163 } 164 165 166 // Run a very basic process: with no reading from or writing to the Process' iostreams, 167 // this just execs the process and waits for it to return 168 public int runBasicProcess() { 169 Process prcs = null; 170 try { 171 // 1. create the process 172 prcs = doRuntimeExec(); 173 // 2. basic waitFor the process to finish 174 this.exitValue = prcs.waitFor(); 175 176 177 } catch(IOException ioe) { 178 if(exceptionHandler != null) { 179 exceptionHandler.gotException(ioe); 180 } else { 181 logger.error("IOException: " + ioe.getMessage(), ioe); 182 //System.err.println("IOException " + ioe.getMessage()); 183 //ioe.printStackTrace(); 184 } 185 } catch(InterruptedException ie) { 186 187 if(exceptionHandler != null) { 188 exceptionHandler.gotException(ie); 189 } else { 190 logger.error("Process InterruptedException: " + ie.getMessage(), ie); 191 //System.err.println("Process InterruptedException " + ie.getMessage()); 192 ///ie.printStackTrace(); // an interrupt here is not an error, it can be a cancel action 193 } 194 195 Thread.currentThread().interrupt(); 196 } finally { 197 198 if( prcs != null ) { 199 prcs.destroy(); // see runProcess() below 200 } 201 } 202 return this.exitValue; 203 } 204 205 // Runs a process with default stream processing 206 public int runProcess() { 207 return runProcess(null, null, null); // use default processing of all 3 of the process' iostreams 208 } 209 210 // Run a process with custom stream processing (any custom handlers passed in that are null 211 // will use the default stream processing) 212 public int runProcess(CustomProcessHandler procInHandler, 213 CustomProcessHandler procOutHandler, 214 CustomProcessHandler procErrHandler) 215 { 216 Process prcs = null; 217 SafeProcess.OutputStreamGobbler inputGobbler = null; 218 SafeProcess.InputStreamGobbler errorGobbler = null; 219 SafeProcess.InputStreamGobbler outputGobbler = null; 220 221 try { 222 // 1. get the Process object 223 prcs = doRuntimeExec(); 224 225 226 // 2. create the streamgobblers and set any specified handlers on them 227 228 // PROC INPUT STREAM 229 if(procInHandler == null) { 230 // send inputStr to process. The following constructor can handle inputStr being null 231 inputGobbler = // WriterToProcessInputStream 232 new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), this.inputStr); 233 } else { // user will do custom handling of process' InputStream 234 inputGobbler = new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), procInHandler); 235 } 236 237 // PROC ERR STREAM to monitor for any error messages or expected output in the process' stderr 238 if(procErrHandler == null) { 239 errorGobbler // ReaderFromProcessOutputStream 240 = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines); 241 } else { 242 errorGobbler 243 = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), procErrHandler); 244 } 245 246 // PROC OUT STREAM to monitor for the expected std output line(s) 247 if(procOutHandler == null) { 248 outputGobbler 249 = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), splitStdOutputNewLines); 250 } else { 251 outputGobbler 252 = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), procOutHandler); 253 } 254 255 256 // 3. kick off the stream gobblers 257 this.exitValue = waitForWithStreams(prcs, inputGobbler, outputGobbler, errorGobbler); 239 258 240 259 } catch(IOException ioe) { … … 296 315 } 297 316 298 299 //**************** Inner class definitions (stream gobblers copied from GLI) **********// 317 public int runProcess(LineByLineHandler outLineByLineHandler, LineByLineHandler errLineByLineHandler) 318 { 319 Process prcs = null; 320 SafeProcess.OutputStreamGobbler inputGobbler = null; 321 SafeProcess.InputStreamGobbler errorGobbler = null; 322 SafeProcess.InputStreamGobbler outputGobbler = null; 323 324 try { 325 // 1. get the Process object 326 prcs = doRuntimeExec(); 327 328 329 // 2. create the streamgobblers and set any specified handlers on them 330 331 // PROC INPUT STREAM 332 // send inputStr to process. The following constructor can handle inputStr being null 333 inputGobbler = // WriterToProcessInputStream 334 new SafeProcess.OutputStreamGobbler(prcs.getOutputStream(), this.inputStr); 335 336 // PROC ERR STREAM to monitor for any error messages or expected output in the process' stderr 337 errorGobbler // ReaderFromProcessOutputStream 338 = new SafeProcess.InputStreamGobbler(prcs.getErrorStream(), splitStdErrorNewLines); 339 // PROC OUT STREAM to monitor for the expected std output line(s) 340 outputGobbler 341 = new SafeProcess.InputStreamGobbler(prcs.getInputStream(), splitStdOutputNewLines); 342 343 344 // 3. register line by line handlers, if any were set, for the process stderr and stdout streams 345 if(outLineByLineHandler != null) { 346 outputGobbler.setLineByLineHandler(outLineByLineHandler); 347 } 348 if(errLineByLineHandler != null) { 349 errorGobbler.setLineByLineHandler(errLineByLineHandler); 350 } 351 352 353 // 4. kick off the stream gobblers 354 this.exitValue = waitForWithStreams(prcs, inputGobbler, outputGobbler, errorGobbler); 355 356 } catch(IOException ioe) { 357 if(exceptionHandler != null) { 358 exceptionHandler.gotException(ioe); 359 } else { 360 logger.error("IOexception: " + ioe.getMessage(), ioe); 361 //System.err.println("IOexception " + ioe.getMessage()); 362 //ioe.printStackTrace(); 363 } 364 } catch(InterruptedException ie) { 365 366 if(exceptionHandler != null) { 367 exceptionHandler.gotException(ie); 368 } else { 369 logger.error("Process InterruptedException: " + ie.getMessage(), ie); 370 //System.err.println("Process InterruptedException " + ie.getMessage()); 371 ///ie.printStackTrace(); // an interrupt here is not an error, it can be a cancel action 372 } 373 374 // propagate interrupts to worker threads here? 375 // unless the interrupt emanated from any of them in any join()... 376 // Only if the thread SafeProcess runs in was interrupted 377 // do we propagate the interrupt to the worker threads. 378 // http://stackoverflow.com/questions/2126997/who-is-calling-the-java-thread-interrupt-method-if-im-not 379 // "I know that in JCiP it is mentioned that you should never interrupt threads you do not own" 380 // But SafeProcess owns the worker threads, so it have every right to interrupt them 381 // Also read http://stackoverflow.com/questions/13623445/future-cancel-method-is-not-working?noredirect=1&lq=1 382 if(Thread.currentThread().isInterrupted()) { 383 inputGobbler.interrupt(); 384 errorGobbler.interrupt(); 385 outputGobbler.interrupt(); 386 } 387 388 // On catchingInterruptedException, re-interrupt the thread. 389 // This is just how InterruptedExceptions tend to be handled 390 // See also http://stackoverflow.com/questions/4906799/why-invoke-thread-currentthread-interrupt-when-catch-any-interruptexception 391 // and https://praveer09.github.io/technology/2015/12/06/understanding-thread-interruption-in-java/ 392 393 // http://stackoverflow.com/questions/3976344/handling-interruptedexception-in-java 394 // http://stackoverflow.com/questions/4906799/why-invoke-thread-currentthread-interrupt-when-catch-any-interruptexception 395 // "Only code that implements a thread's interruption policy may swallow an interruption request. General-purpose task and library code should never swallow interruption requests." 396 // Does that mean that since this code implements this thread's interruption policy, it's ok 397 // to swallow the interrupt this time and not let it propagate by commenting out the next line? 398 Thread.currentThread().interrupt(); // re-interrupt the thread - which thread? Infinite loop? 399 } finally { 400 401 // Moved into here from GS2PerlConstructor which said 402 // "I need to somehow kill the child process. Unfortunately Thread.stop() and Process.destroy() both fail to do this. But now, thankx to the magic of Michaels 'close the stream suggestion', it works fine." 403 // http://steveliles.github.io/invoking_processes_from_java.html 404 // http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2 405 // http://mark.koli.ch/leaky-pipes-remember-to-close-your-streams-when-using-javas-runtimegetruntimeexec 406 if( prcs != null ) { 407 prcs.destroy(); 408 } 409 } 410 411 return this.exitValue; 412 } 413 414 415 //******************** Inner class interface definitions ********************// 300 416 // Static inner classes can be instantiated without having to instantiate an object of the outer class first 301 417 … … 322 438 } 323 439 440 // When using the default stream processing to read from a process' stdout or stderr stream, 441 // you can create a LineByLineHandler for the process' err and out streams 442 // to do something on a line by line basis, such as sending the line to a log 443 public static interface LineByLineHandler { 444 public void gotLine(String line); 445 public void gotException(Exception e); // for when an exception occurs instead of getting a line 446 } 447 448 //**************** StreamGobbler Inner class definitions (stream gobblers copied from GLI) **********// 324 449 325 450 // http://www.javaworld.com/article/2071275/core-java/when-runtime-exec---won-t.html?page=2 … … 332 457 private boolean split_newlines = false; 333 458 private CustomProcessHandler customHandler = null; 459 private LineByLineHandler lineByLineHandler = null; 334 460 335 461 public InputStreamGobbler(InputStream is) … … 349 475 this.is = is; 350 476 this.customHandler = customHandler; 477 } 478 479 public void setLineByLineHandler(LineByLineHandler lblHandler) { 480 this.lineByLineHandler = lblHandler; 351 481 } 352 482 … … 370 500 outputstr.append(Misc.NEWLINE); // "\n" is system dependent (Win must be "\r\n") 371 501 } 372 } 373 } catch (IOException ioe) { 374 logger.error("Exception when reading from a process' stdout/stderr stream: ", ioe); 375 //System.err.println("Exception when reading from a process' stdout/stderr stream: "); 376 //ioe.printStackTrace(); 377 502 503 if(lineByLineHandler != null) { // let handler deal with newlines 504 lineByLineHandler.gotLine(line); 505 } 506 } 507 } catch (IOException ioe) { 508 if(lineByLineHandler != null) { 509 lineByLineHandler.gotException(ioe); 510 } else { 511 logger.error("Exception when reading from a process' stdout/stderr stream: ", ioe); 512 //System.err.println("Exception when reading from a process' stdout/stderr stream: "); 513 //ioe.printStackTrace(); 514 } 378 515 } finally { 379 516 SafeProcess.closeResource(br); … … 476 613 477 614 478 //**************** Copied from GLI's Utility.java ******************615 //**************** Useful static methods. Copied from GLI's Utility.java ****************** 479 616 // For safely closing streams/handles/resources. 480 617 // For examples of use look in the Input- and OutputStreamGobbler classes.
Note:
See TracChangeset
for help on using the changeset viewer.