< prev index next >

src/jdk.scripting.nashorn/share/classes/jdk/nashorn/internal/runtime/CommandExecutor.java

Print this page




 232 
 233                 // Apply redirects.
 234                 pb.redirectInput(inputRedirect);
 235                 pb.redirectOutput(outputRedirect);
 236                 pb.redirectError(errorRedirect);
 237                 pb.redirectErrorStream(mergeError);
 238             }
 239         }
 240     }
 241 
 242     /**
 243      * The Piper class is responsible for copying from an InputStream to an
 244      * OutputStream without blocking the current thread.
 245      */
 246     private static class Piper implements java.lang.Runnable {
 247         // Stream to copy from.
 248         private final InputStream input;
 249         // Stream to copy to.
 250         private final OutputStream output;
 251 


 252         Piper(final InputStream input, final OutputStream output) {
 253             this.input = input;
 254             this.output = output;

 255         }
 256 
 257         /**
 258          * start - start the Piper in a new daemon thread

 259          */
 260         void start() {
 261             Thread thread = new Thread(this, "$EXEC Piper");
 262             thread.setDaemon(true);
 263             thread.start();

 264         }
 265 
 266         /**
 267          * run - thread action
 268          */
 269         @Override
 270         public void run() {
 271             try {
 272                 // Buffer for copying.
 273                 byte[] b = new byte[BUFFER_SIZE];
 274                 // Read from the InputStream until EOF.
 275                 int read;
 276                 while (-1 < (read = input.read(b, 0, b.length))) {
 277                     // Write available date to OutputStream.
 278                     output.write(b, 0, read);
 279                 }
 280             } catch (Exception e) {
 281                 // Assume the worst.
 282                 throw new RuntimeException("Broken pipe", e);
 283             } finally {
 284                 // Make sure the streams are closed.
 285                 try {
 286                     input.close();
 287                 } catch (IOException e) {
 288                     // Don't care.
 289                 }
 290                 try {
 291                     output.close();
 292                 } catch (IOException e) {
 293                     // Don't care.
 294                 }
 295             }
 296         }
 297 




 298         // Exit thread.
 299     }
 300 
 301     // Process exit statuses.
 302     static final int EXIT_SUCCESS  =  0;
 303     static final int EXIT_FAILURE  =  1;
 304 
 305     // Copy of environment variables used by all processes.
 306     private  Map<String, String> environment;
 307     // Input string if provided on CommandExecutor call.
 308     private String inputString;
 309     // Output string if required from CommandExecutor call.
 310     private String outputString;
 311     // Error string if required from CommandExecutor call.
 312     private String errorString;
 313     // Last process exit code.
 314     private int exitCode;
 315 
 316     // Input stream if provided on CommandExecutor call.
 317     private InputStream inputStream;


 604         for (ProcessBuilder pb : processBuilders) {
 605             try {
 606                 processes.add(pb.start());
 607             } catch (IOException ex) {
 608                 reportError("unknown.command", String.join(" ", pb.command()));
 609                 return;
 610             }
 611         }
 612 
 613         // Clear processBuilders for next command.
 614         processBuilders.clear();
 615 
 616         // Get first and last process.
 617         final Process firstProcess = processes.get(0);
 618         final Process lastProcess = processes.get(processes.size() - 1);
 619 
 620         // Prepare for string based i/o if no redirection or provided streams.
 621         ByteArrayOutputStream byteOutputStream = null;
 622         ByteArrayOutputStream byteErrorStream = null;
 623 


 624         // If input is not redirected.
 625         if (inputIsPipe) {
 626             // If inputStream other than System.in is provided.
 627             if (inputStream != null) {
 628                 // Pipe inputStream to first process output stream.
 629                 new Piper(inputStream, firstProcess.getOutputStream()).start();
 630             } else {
 631                 // Otherwise assume an input string has been provided.
 632                 new Piper(new ByteArrayInputStream(inputString.getBytes()), firstProcess.getOutputStream()).start();
 633             }
 634         }
 635 
 636         // If output is not redirected.
 637         if (outputIsPipe) {
 638             // If outputStream other than System.out is provided.
 639             if (outputStream != null ) {
 640                 // Pipe outputStream from last process input stream.
 641                 new Piper(lastProcess.getInputStream(), outputStream).start();
 642             } else {
 643                 // Otherwise assume an output string needs to be prepared.
 644                 byteOutputStream = new ByteArrayOutputStream(BUFFER_SIZE);
 645                 new Piper(lastProcess.getInputStream(), byteOutputStream).start();
 646             }
 647         }
 648 
 649         // If error is not redirected.
 650         if (errorIsPipe) {
 651             // If errorStream other than System.err is provided.
 652             if (errorStream != null) {
 653                 new Piper(lastProcess.getErrorStream(), errorStream).start();
 654             } else {
 655                 // Otherwise assume an error string needs to be prepared.
 656                 byteErrorStream = new ByteArrayOutputStream(BUFFER_SIZE);
 657                 new Piper(lastProcess.getErrorStream(), byteErrorStream).start();
 658             }
 659         }
 660 
 661         // Pipe commands in between.
 662         for (int i = 0, n = processes.size() - 1; i < n; i++) {
 663             final Process prev = processes.get(i);
 664             final Process next = processes.get(i + 1);
 665             new Piper(prev.getInputStream(), next.getOutputStream()).start();
 666         }
 667 
 668         // Wind up processes.
 669         try {
 670             // Get the user specified timeout.
 671             long timeout = envVarLongValue("JJS_TIMEOUT");
 672 
 673             // If user specified timeout (milliseconds.)
 674             if (timeout != 0) {
 675                 // Wait for last process, with timeout.
 676                 if (lastProcess.waitFor(timeout, TimeUnit.MILLISECONDS)) {
 677                     // Get exit code of last process.
 678                     exitCode = lastProcess.exitValue();
 679                 } else {
 680                     reportError("timeout", Long.toString(timeout));
 681                  }
 682             } else {
 683                 // Wait for last process and get exit code.
 684                 exitCode = lastProcess.waitFor();




 685             }
 686 
 687             // Accumulate the output and error streams.
 688             outputString += byteOutputStream != null ? byteOutputStream.toString() : "";
 689             errorString += byteErrorStream != null ? byteErrorStream.toString() : "";
 690         } catch (InterruptedException ex) {
 691             // Kill any living processes.
 692             processes.stream().forEach(p -> {
 693                 if (p.isAlive()) {
 694                     p.destroy();
 695                 }
 696 
 697                 // Get the first error code.
 698                 exitCode = exitCode == 0 ? p.exitValue() : exitCode;
 699             });
 700         }
 701 
 702         // If we got a non-zero exit code then possibly throw an exception.
 703         if (exitCode != 0 && envVarBooleanValue("JJS_THROW_ON_EXIT")) {
 704             throw rangeError("exec.returned.non.zero", ScriptRuntime.safeToString(exitCode));




 232 
 233                 // Apply redirects.
 234                 pb.redirectInput(inputRedirect);
 235                 pb.redirectOutput(outputRedirect);
 236                 pb.redirectError(errorRedirect);
 237                 pb.redirectErrorStream(mergeError);
 238             }
 239         }
 240     }
 241 
 242     /**
 243      * The Piper class is responsible for copying from an InputStream to an
 244      * OutputStream without blocking the current thread.
 245      */
 246     private static class Piper implements java.lang.Runnable {
 247         // Stream to copy from.
 248         private final InputStream input;
 249         // Stream to copy to.
 250         private final OutputStream output;
 251 
 252         private final Thread thread;
 253 
 254         Piper(final InputStream input, final OutputStream output) {
 255             this.input = input;
 256             this.output = output;
 257             this.thread = new Thread(this, "$EXEC Piper");
 258         }
 259 
 260         /**
 261          * start - start the Piper in a new daemon thread
 262          * @return this Piper
 263          */
 264         Piper start() {

 265             thread.setDaemon(true);
 266             thread.start();
 267             return this;
 268         }
 269 
 270         /**
 271          * run - thread action
 272          */
 273         @Override
 274         public void run() {
 275             try {
 276                 // Buffer for copying.
 277                 byte[] b = new byte[BUFFER_SIZE];
 278                 // Read from the InputStream until EOF.
 279                 int read;
 280                 while (-1 < (read = input.read(b, 0, b.length))) {
 281                     // Write available date to OutputStream.
 282                     output.write(b, 0, read);
 283                 }
 284             } catch (Exception e) {
 285                 // Assume the worst.
 286                 throw new RuntimeException("Broken pipe", e);
 287             } finally {
 288                 // Make sure the streams are closed.
 289                 try {
 290                     input.close();
 291                 } catch (IOException e) {
 292                     // Don't care.
 293                 }
 294                 try {
 295                     output.close();
 296                 } catch (IOException e) {
 297                     // Don't care.
 298                 }
 299             }
 300         }
 301 
 302         public void join() throws InterruptedException {
 303             thread.join();
 304         }
 305 
 306         // Exit thread.
 307     }
 308 
 309     // Process exit statuses.
 310     static final int EXIT_SUCCESS  =  0;
 311     static final int EXIT_FAILURE  =  1;
 312 
 313     // Copy of environment variables used by all processes.
 314     private  Map<String, String> environment;
 315     // Input string if provided on CommandExecutor call.
 316     private String inputString;
 317     // Output string if required from CommandExecutor call.
 318     private String outputString;
 319     // Error string if required from CommandExecutor call.
 320     private String errorString;
 321     // Last process exit code.
 322     private int exitCode;
 323 
 324     // Input stream if provided on CommandExecutor call.
 325     private InputStream inputStream;


 612         for (ProcessBuilder pb : processBuilders) {
 613             try {
 614                 processes.add(pb.start());
 615             } catch (IOException ex) {
 616                 reportError("unknown.command", String.join(" ", pb.command()));
 617                 return;
 618             }
 619         }
 620 
 621         // Clear processBuilders for next command.
 622         processBuilders.clear();
 623 
 624         // Get first and last process.
 625         final Process firstProcess = processes.get(0);
 626         final Process lastProcess = processes.get(processes.size() - 1);
 627 
 628         // Prepare for string based i/o if no redirection or provided streams.
 629         ByteArrayOutputStream byteOutputStream = null;
 630         ByteArrayOutputStream byteErrorStream = null;
 631 
 632         final List<Piper> piperThreads = new ArrayList<>();
 633 
 634         // If input is not redirected.
 635         if (inputIsPipe) {
 636             // If inputStream other than System.in is provided.
 637             if (inputStream != null) {
 638                 // Pipe inputStream to first process output stream.
 639                 piperThreads.add(new Piper(inputStream, firstProcess.getOutputStream()).start());
 640             } else {
 641                 // Otherwise assume an input string has been provided.
 642                 piperThreads.add(new Piper(new ByteArrayInputStream(inputString.getBytes()), firstProcess.getOutputStream()).start());
 643             }
 644         }
 645 
 646         // If output is not redirected.
 647         if (outputIsPipe) {
 648             // If outputStream other than System.out is provided.
 649             if (outputStream != null ) {
 650                 // Pipe outputStream from last process input stream.
 651                 piperThreads.add(new Piper(lastProcess.getInputStream(), outputStream).start());
 652             } else {
 653                 // Otherwise assume an output string needs to be prepared.
 654                 byteOutputStream = new ByteArrayOutputStream(BUFFER_SIZE);
 655                 piperThreads.add(new Piper(lastProcess.getInputStream(), byteOutputStream).start());
 656             }
 657         }
 658 
 659         // If error is not redirected.
 660         if (errorIsPipe) {
 661             // If errorStream other than System.err is provided.
 662             if (errorStream != null) {
 663                 piperThreads.add(new Piper(lastProcess.getErrorStream(), errorStream).start());
 664             } else {
 665                 // Otherwise assume an error string needs to be prepared.
 666                 byteErrorStream = new ByteArrayOutputStream(BUFFER_SIZE);
 667                 piperThreads.add(new Piper(lastProcess.getErrorStream(), byteErrorStream).start());
 668             }
 669         }
 670 
 671         // Pipe commands in between.
 672         for (int i = 0, n = processes.size() - 1; i < n; i++) {
 673             final Process prev = processes.get(i);
 674             final Process next = processes.get(i + 1);
 675             piperThreads.add(new Piper(prev.getInputStream(), next.getOutputStream()).start());
 676         }
 677 
 678         // Wind up processes.
 679         try {
 680             // Get the user specified timeout.
 681             final long timeout = envVarLongValue("JJS_TIMEOUT");
 682 
 683             // If user specified timeout (milliseconds.)
 684             if (timeout != 0) {
 685                 // Wait for last process, with timeout.
 686                 if (lastProcess.waitFor(timeout, TimeUnit.MILLISECONDS)) {
 687                     // Get exit code of last process.
 688                     exitCode = lastProcess.exitValue();
 689                 } else {
 690                     reportError("timeout", Long.toString(timeout));
 691                  }
 692             } else {
 693                 // Wait for last process and get exit code.
 694                 exitCode = lastProcess.waitFor();
 695             }
 696             // Wait for all piper threads to terminate
 697             for (final Piper piper : piperThreads) {
 698                 piper.join();
 699             }
 700 
 701             // Accumulate the output and error streams.
 702             outputString += byteOutputStream != null ? byteOutputStream.toString() : "";
 703             errorString += byteErrorStream != null ? byteErrorStream.toString() : "";
 704         } catch (InterruptedException ex) {
 705             // Kill any living processes.
 706             processes.stream().forEach(p -> {
 707                 if (p.isAlive()) {
 708                     p.destroy();
 709                 }
 710 
 711                 // Get the first error code.
 712                 exitCode = exitCode == 0 ? p.exitValue() : exitCode;
 713             });
 714         }
 715 
 716         // If we got a non-zero exit code then possibly throw an exception.
 717         if (exitCode != 0 && envVarBooleanValue("JJS_THROW_ON_EXIT")) {
 718             throw rangeError("exec.returned.non.zero", ScriptRuntime.safeToString(exitCode));


< prev index next >