--- old/src/java.base/share/classes/java/lang/ProcessBuilder.java 2015-04-14 15:58:55.565617995 +0200 +++ new/src/java.base/share/classes/java/lang/ProcessBuilder.java 2015-04-14 15:58:55.508617860 +0200 @@ -25,10 +25,13 @@ package java.lang; +import sun.nio.ch.SelChImpl; + import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.nio.channels.Pipe; import java.util.Arrays; import java.util.ArrayList; import java.util.List; @@ -459,6 +462,29 @@ * @since 1.7 */ public static abstract class Redirect { + + private static final boolean PIPE_CHANNEL_SUPPORTED; + + static { + boolean supported = false; + try { + Pipe p = Pipe.open(); + supported = (p.sink() instanceof SelChImpl) && + (p.source() instanceof SelChImpl); + try { p.sink().close(); } catch (IOException e) {} + try { p.source().close(); } catch (IOException e) {} + } catch (IOException e) { + // ignore + } + PIPE_CHANNEL_SUPPORTED = supported; + } + + final void checkSupported() throws UnsupportedOperationException { + if (this == PIPE_CHANNEL && !PIPE_CHANNEL_SUPPORTED) { + throw new UnsupportedOperationException("Unsupported SelectorProvider"); + } + } + /** * The type of a {@link Redirect}. */ @@ -469,6 +495,11 @@ PIPE, /** + * The type of {@link Redirect#PIPE_CHANNEL Redirect.PIPE_CHANNEL}. + */ + PIPE_CHANNEL, + + /** * The type of {@link Redirect#INHERIT Redirect.INHERIT}. */ INHERIT, @@ -515,6 +546,24 @@ public String toString() { return type().toString(); }}; /** + * Indicates that subprocess I/O will be connected to the + * current Java process over a pipe and that the communication + * will be performed via {@link java.nio.channels.Pipe.SourceChannel} + * or {@link java.nio.channels.Pipe.SinkChannel}. + ** + *

It will always be true that + *

 {@code
+         * Redirect.PIPE_CHANNEL.file() == null &&
+         * Redirect.PIPE_CHANNEL.type() == Redirect.Type.PIPE_CHANNEL
+         * }
+ * + * @since 1.9 + */ + public static final Redirect PIPE_CHANNEL = new Redirect() { + public Type type() { return Type.PIPE_CHANNEL; } + public String toString() { return type().toString(); }}; + + /** * Indicates that subprocess I/O source or destination will be the * same as those of the current process. This is the normal * behavior of most operating system command interpreters (shells). @@ -687,6 +736,14 @@ * {@link Process#getOutputStream()} will return a * null output stream. * + *

If the source is {@link Redirect#PIPE_CHANNEL Redirect.PIPE_CHANNEL}, + * then the standard input of a subprocess can be written to + * using the output channel returned by + * {@link Process#getOutputChannel()} which, unlike the output stream + * above, must be obtained and closed by the user. + * If the source is set to any other value, then + * {@link Process#getOutputChannel()} will return {@code null}. + * * @param source the new standard input source * @return this process builder * @throws IllegalArgumentException @@ -694,6 +751,10 @@ * of data, that is, has type * {@link Redirect.Type#WRITE WRITE} or * {@link Redirect.Type#APPEND APPEND} + * @throws UnsupportedOperationException if the redirect has type + * {@link Redirect.Type#PIPE_CHANNEL PIPE_CHANNEL} and the + * platform is configured with unsupported + * {@link java.nio.channels.spi.SelectorProvider} * @since 1.7 */ public ProcessBuilder redirectInput(Redirect source) { @@ -701,6 +762,7 @@ source.type() == Redirect.Type.APPEND) throw new IllegalArgumentException( "Redirect invalid for reading: " + source); + source.checkSupported(); redirects()[0] = source; return this; } @@ -719,18 +781,30 @@ * {@link Process#getInputStream()} will return a * null input stream. * + *

If the destination is {@link Redirect#PIPE_CHANNEL Redirect.PIPE_CHANNEL}, + * then the standard output of a subprocess can be read using the input + * channel returned by {@link Process#getInputChannel()}. which, + * unlike the input stream above, must be obtained and closed by the user. + * If the destination is set to any other value, then + * {@link Process#getInputChannel()} will return {@code null}. + * * @param destination the new standard output destination * @return this process builder * @throws IllegalArgumentException * if the redirect does not correspond to a valid * destination of data, that is, has type * {@link Redirect.Type#READ READ} + * @throws UnsupportedOperationException if the redirect has type + * {@link Redirect.Type#PIPE_CHANNEL PIPE_CHANNEL} and the + * platform is configured with unsupported + * {@link java.nio.channels.spi.SelectorProvider} * @since 1.7 */ public ProcessBuilder redirectOutput(Redirect destination) { if (destination.type() == Redirect.Type.READ) throw new IllegalArgumentException( "Redirect invalid for writing: " + destination); + destination.checkSupported(); redirects()[1] = destination; return this; } @@ -759,12 +833,17 @@ * if the redirect does not correspond to a valid * destination of data, that is, has type * {@link Redirect.Type#READ READ} + * @throws UnsupportedOperationException if the redirect has type + * {@link Redirect.Type#PIPE_CHANNEL PIPE_CHANNEL} and the + * platform is configured with unsupported + * {@link java.nio.channels.spi.SelectorProvider} * @since 1.7 */ public ProcessBuilder redirectError(Redirect destination) { if (destination.type() == Redirect.Type.READ) throw new IllegalArgumentException( "Redirect invalid for writing: " + destination); + destination.checkSupported(); redirects()[2] = destination; return this; } @@ -897,7 +976,8 @@ * generated by subprocesses subsequently started by this object's * {@link #start()} method will be merged with the standard * output, so that both can be read using the - * {@link Process#getInputStream()} method. This makes it easier + * {@link Process#getInputStream()} or {@link Process#getInputChannel()} + * methods. This makes it easier * to correlate error messages with the corresponding output. * The initial value is {@code false}. * @@ -914,7 +994,8 @@ * generated by subprocesses subsequently started by this object's * {@link #start()} method will be merged with the standard * output, so that both can be read using the - * {@link Process#getInputStream()} method. This makes it easier + * {@link Process#getInputStream()} or {@link Process#getInputChannel()} + * methods. This makes it easier * to correlate error messages with the corresponding output. * The initial value is {@code false}. *