Changeset 31591 for main/trunk/greenstone3/src/java/org/greenstone/gsdl3/build/GS2PerlConstructor.java
- 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/gsdl3/build/GS2PerlConstructor.java
r31590 r31591 18 18 import java.io.InputStreamReader; 19 19 import java.io.File; 20 import java.io.InputStream; 20 21 import java.io.IOException; 21 22 import java.util.ArrayList; … … 334 335 // http://www.cgi101.com/class/ch3/text.html 335 336 // setenv QUERY_STRING and REQUEST_METHOD = GET. 337 // Run the perl command as a simple process: no logging to the collection's build log 336 338 if (runPerlCommand(command_str, envvars, new File(cgi_directory))) 337 339 //new File(GlobalProperties.getGSDL3Home() + File.separator + "WEB-INF" + File.separator + "cgi"))) … … 372 374 } 373 375 374 /** returns true if completed correctly, false otherwise */ 375 protected boolean runPerlCommand(String[] command) { 376 return runPerlCommand(command, null, null); 377 } 378 379 380 protected boolean runPerlCommand(String[] command, String[] envvars, File dir) 381 { 382 boolean success = true; 383 376 protected SafeProcess createPerlProcess(String[] command, String[] envvars, File dir) { 384 377 int sepIndex = this.gsdl3home.lastIndexOf(File.separator); 385 378 String srcHome = this.gsdl3home.substring(0, sepIndex); … … 402 395 args.add(a + "=" + System.getenv(a)); 403 396 } 397 398 SafeProcess perlProcess 399 = new SafeProcess(command, args.toArray(new String[args.size()]), dir); // dir can be null 400 401 return perlProcess; 402 } 403 404 // ModifyMetadata operations call runSimplePerlCommand which produces no output in build log 405 protected boolean runSimplePerlCommand(String[] command) { 406 return runSimplePerlCommand(command, null, null); 407 } 408 409 protected boolean runSimplePerlCommand(String[] command, String[] envvars, File dir) { 410 boolean success = false; 404 411 405 412 String command_str = ""; … … 410 417 sendMessage(new ConstructionEvent(this, GSStatus.INFO, "command = " + command_str)); 411 418 412 //logger.info("### Runningcommand = " + command_str);419 logger.info("### Running simple command = " + command_str); 413 420 414 421 // This is where we create and run our perl process safely 415 SafeProcess perlProcess 416 = new SafeProcess(command, args.toArray(new String[args.size()]), dir); // dir can be null 417 422 SafeProcess perlProcess = createPerlProcess(command, envvars, dir); // dir can be null 423 424 perlProcess.setExceptionHandler(this); 425 426 sendProcessBegun(new ConstructionEvent(this, GSStatus.ACCEPTED, "starting")); 427 428 int exitVal = perlProcess.runProcess(); // uses default processing of the perl process' iostreams provided by SafeProcess 429 430 if (exitVal == 0) { 431 success = true; 432 sendProcessStatus(new ConstructionEvent(this, GSStatus.CONTINUING, "Success")); 433 } else { 434 sendProcessStatus(new ConstructionEvent(this, GSStatus.ERROR, "Failure")); 435 success = false; // explicit 436 } 437 438 return success; 439 } 440 441 442 /** returns true if completed correctly, false otherwise 443 * Building operations call runPerlCommand which sends build output to collect/log/build_log.#*.txt 444 */ 445 protected boolean runPerlCommand(String[] command) { 446 return runPerlCommand(command, null, null); 447 } 448 449 450 protected boolean runPerlCommand(String[] command, String[] envvars, File dir) 451 { 452 boolean success = true; 453 454 String command_str = ""; 455 for (int i = 0; i < command.length; i++) { 456 command_str = command_str + command[i] + " "; 457 } 458 459 sendMessage(new ConstructionEvent(this, GSStatus.INFO, "command = " + command_str)); 460 461 logger.info("### Running logged command = " + command_str); 462 463 // This is where we create and run our perl process safely 464 SafeProcess perlProcess = createPerlProcess(command, envvars, dir); // dir can be null 418 465 419 466 sendProcessBegun(new ConstructionEvent(this, GSStatus.ACCEPTED, "starting")); … … 428 475 BufferedWriter bw = null; 429 476 try { 430 bw = new BufferedWriter(new FileWriter(GSFile.collectDir(this.site_home) + File.separator + this.collection_name + File.separator + "log" + File.separator + "build_log." + (System.currentTimeMillis()) + ".txt")); 477 478 bw = new BufferedWriter(new FileWriter(new File(logDir, "build_log." + (System.currentTimeMillis()) + ".txt"))); 431 479 432 480 bw.write("Document Editor Build \n"); … … 434 482 435 483 // handle each incoming line from stdout and stderr streams, and any exceptions that occur then 436 SynchronizedProcessLineByLineHandler outLineByLineHandler 437 = new SynchronizedProcessLineByLineHandler(bw, SynchronizedProcessLineByLineHandler.STDOUT); 438 SynchronizedProcessLineByLineHandler errLineByLineHandler 439 = new SynchronizedProcessLineByLineHandler(bw, SynchronizedProcessLineByLineHandler.STDERR); 440 perlProcess.setStdOutLineByLineHandler(outLineByLineHandler); 441 perlProcess.setStdErrLineByLineHandler(errLineByLineHandler); 484 SafeProcess.CustomProcessHandler processOutHandler 485 = new SynchronizedProcessHandler(bw, SynchronizedProcessHandler.STDOUT); 486 SafeProcess.CustomProcessHandler processErrHandler 487 = new SynchronizedProcessHandler(bw, SynchronizedProcessHandler.STDERR); 442 488 443 489 // GS2PerlConstructor will do further handling of exceptions that may occur during the perl … … 450 496 // std in of java, as before. 451 497 452 perlProcess.runProcess( );498 perlProcess.runProcess(null, processOutHandler, processErrHandler); // use default procIn handling 453 499 454 500 // The original runPerlCommand() code had an ineffective check for whether the cmd had been cancelled … … 657 703 // Called when an exception happens during the running of our perl process. However, 658 704 // exceptions when reading from our perl process' stderr and stdout streams are handled by 659 // SynchronizedProcessLineByLineHandler.gotException() below. 705 // SynchronizedProcessHandler.gotException() below, since they happen in separate threads 706 // from this one (the ine from which the perl process is run). 660 707 public synchronized void gotException(Exception e) { 661 708 … … 664 711 e.printStackTrace(); 665 712 sendProcessStatus(new ConstructionEvent(this,GSStatus.ERROR, 666 "Exception occurred " + e.toString())); // atomic713 "Exception occurred " + e.toString())); 667 714 } 668 715 716 // Each instance of this class is run in its own thread by class SafeProcess.InputGobbler. 669 717 // This class deals with each incoming line from the perl process' stderr or stdout streams. One 670 // instance of this class for each stream. However, since multiple instances of this LineByLineHandler671 // could be (and in fact, are) writing to the same file in their own threads, the writer object needs672 // t o be made threadsafe.718 // instance of this class for each stream. However, since multiple instances of this CustomProcessHandler 719 // could be (and in fact, are) writing to the same file in their own threads, several objects, not just 720 // the bufferedwriter object, needed to be made threadsafe. 673 721 // This class also handles exceptions during the running of the perl process. 674 722 // The runPerlCommand code originally would do a sendProcessStatus on each exception, so we ensure 675 // we do that here too, to continue original behaviour. 676 protected class SynchronizedProcessLineByLineHandler implements SafeProcess.LineByLineHandler 723 // we do that here too, to continue original behaviour. These calls are also synchronized to make their 724 // use of the EventListeners threadsafe. 725 protected class SynchronizedProcessHandler implements SafeProcess.CustomProcessHandler 677 726 { 678 727 public static final int STDERR = 0; … … 683 732 684 733 685 public SynchronizedProcessLineByLineHandler(BufferedWriter bw, int src) { 686 this.bwHandle = bw; 734 public SynchronizedProcessHandler(BufferedWriter bw, int src) { 735 this.bwHandle = bw; // caller will close bw, since many more than one 736 // SynchronizedProcessHandlers are using it 687 737 this.source = src; // STDERR or STDOUT 688 738 } 689 739 690 public synchronized void gotLine(String line) { 691 //if(this.source == STDERR) { 692 ///System.err.println("ERROR: " + line); 693 //} else { 694 ///System.err.println("OUT: " + line); 695 //} 740 public void run(Closeable inputStream) { 741 InputStream is = (InputStream) inputStream; 742 743 BufferedReader br = null; 744 try { 745 br = new BufferedReader(new InputStreamReader(is, "UTF-8")); 746 String line=null; 747 while ( (line = br.readLine()) != null ) { 748 749 if(Thread.currentThread().isInterrupted()) { // should we not instead check if SafeProcess thread was interrupted? 750 System.err.println("Got interrupted when reading lines from process err/out stream."); 751 break; // will go to finally block 752 } 753 754 /// System.out.println("@@@ GOT LINE: " + line); 755 /// GS2PerlConstructor.logger.info("@@@ GOT LINE: " + line + " STDOUT=1: " + source); 756 757 //if(this.source == STDERR) { 758 ///System.err.println("ERROR: " + line); 759 //} else { 760 ///System.err.println("OUT: " + line); 761 //} 762 763 764 this.gotLine(line); // synchronized 765 766 /* 767 try { 768 synchronized(bwHandle) { // get a lock on the writer handle, then write 769 770 bwHandle.write(line + "\n"); 771 } 772 } catch(IOException ioe) { 773 String msg = (source == STDERR) ? "stderr" : "stdout"; 774 msg = "Exception when writing out a line read from perl process' " + msg + " stream."; 775 GS2PerlConstructor.logger.error(msg, ioe); 776 } 777 778 // this next method is thread safe since only synchronized methods are invoked. 779 // and only immutable (final) vars are used. 780 // NO, What about the listeners??? 781 sendProcessStatus(new ConstructionEvent(GS2PerlConstructor.this, GSStatus.CONTINUING, line)); 782 */ 783 } 784 } catch (IOException ioe) { // problem with reading in from process with BufferedReader br 785 786 String msg = (source == STDERR) ? "stderr" : "stdout"; 787 msg = "Got exception when processing the perl process' " + msg + " stream."; 788 GS2PerlConstructor.logger.error(msg, ioe); 789 // now do what the original runPerlCommand() code always did: 790 ioe.printStackTrace(); 791 logException(ioe); // synchronized 792 793 } catch (Exception e) { // problem with BufferedWriter bwHandle on processing each line 794 e.printStackTrace(); 795 logException(e); // synchronized 796 } finally { 797 SafeProcess.closeResource(br); 798 } 799 } 800 801 // trying to keep synchronized methods as short as possible 802 private synchronized void logException(Exception e) { 803 sendProcessStatus(new ConstructionEvent(this, GSStatus.ERROR, "Exception occurred " + e.toString())); 804 } 805 806 // trying to keep synchronized methods as short as possible 807 private synchronized void gotLine(String line) throws Exception { 696 808 697 809 // BufferedWriter writes may not be atomic … … 699 811 // Choosing to put try-catch outside of sync block, since it's okay to give up lock on exception 700 812 // http://stackoverflow.com/questions/14944551/it-is-better-to-have-a-synchronized-block-inside-a-try-block-or-a-try-block-insi 701 // "All methods on Logger are multi-thread safe", see 702 // http://stackoverflow.com/questions/14211629/java-util-logger-write-synchronization 703 704 try { 705 bwHandle.write(line + "\n"); 813 try { 814 bwHandle.write(line + "\n"); 815 816 /// System.out.println("@@@ WROTE LINE: " + line); 817 /// GS2PerlConstructor.logger.info("@@@ WROTE LINE: " + line); 818 819 // this next method is thread safe since only synchronized methods are invoked. 820 // and only immutable (final) vars are used. 821 sendProcessStatus(new ConstructionEvent(GS2PerlConstructor.this, GSStatus.CONTINUING, line)); 822 823 } catch(IOException ioe) { // can't throw Exceptions, but are forced to handle Exceptions here 824 // since our method definition doesn't specify a throws list. 825 // "All methods on Logger are multi-thread safe", see 826 // http://stackoverflow.com/questions/14211629/java-util-logger-write-synchronization 706 827 707 } catch(IOException ioe) {708 828 String msg = (source == STDERR) ? "stderr" : "stdout"; 709 msg = "Exception when writing out a line read from perl process' " + msg + " stream."; 710 GS2PerlConstructor.logger.error(msg, ioe); 711 } 712 713 // this next method is thread safe since only synchronized methods are invoked. 714 // and only immutable (final) vars are used. 715 sendProcessStatus(new ConstructionEvent(GS2PerlConstructor.this, GSStatus.CONTINUING, line)); 716 } 717 718 // This is called when we get an exception during the processing of a perl's 719 // input-, err- or output stream 720 public synchronized void gotException(Exception e) { 721 String msg = (source == STDERR) ? "stderr" : "stdout"; 722 msg = "Got exception when processing the perl process' " + msg + " stream."; 723 724 // now do what the original runPerlCommand() code always did: 725 e.printStackTrace(); 726 sendProcessStatus(new ConstructionEvent(this, GSStatus.ERROR, "Exception occurred " + e.toString())); // atomic 727 } 728 729 } // end inner class SynchronizedProcessLineByLineHandler 829 msg = "IOException when writing out a line read from perl process' " + msg + " stream."; 830 msg += "\nGot line: " + line + "\n"; 831 throw new Exception(msg, ioe); 832 } 833 } 834 835 } // end inner class SynchronizedProcessHandler 730 836 731 837 }
Note:
See TracChangeset
for help on using the changeset viewer.