diff --git a/jdk/make/java/java/mapfile-vers b/jdk/make/java/java/mapfile-vers
index 4599570449e..38f9e126d82 100644
--- a/jdk/make/java/java/mapfile-vers
+++ b/jdk/make/java/java/mapfile-vers
@@ -85,7 +85,6 @@ SUNWprivate_1.1 {
Java_java_io_FileOutputStream_close0;
Java_java_io_FileOutputStream_initIDs;
Java_java_io_FileOutputStream_open;
- Java_java_io_FileOutputStream_openAppend;
Java_java_io_FileOutputStream_write;
Java_java_io_FileOutputStream_writeBytes;
Java_java_io_FileSystem_getFileSystem;
diff --git a/jdk/src/share/classes/java/io/FileInputStream.java b/jdk/src/share/classes/java/io/FileInputStream.java
index 8575e6d9397..a37c69c6239 100644
--- a/jdk/src/share/classes/java/io/FileInputStream.java
+++ b/jdk/src/share/classes/java/io/FileInputStream.java
@@ -48,15 +48,15 @@ public
class FileInputStream extends InputStream
{
/* File Descriptor - handle to the open file */
- private FileDescriptor fd;
+ private final FileDescriptor fd;
private FileChannel channel = null;
- private Object closeLock = new Object();
+ private final Object closeLock = new Object();
private volatile boolean closed = false;
- private static ThreadLocal
* This constructor does not throw an exception if
@@ -100,8 +96,8 @@ class FileOutputStream extends OutputStream
}
/**
- * Creates an output file stream to write to the file with the specified
- *
@@ -223,7 +214,7 @@ class FileOutputStream extends OutputStream
* is thrown.
*
* This constructor does not throw an exception if The methods that create processes may not work well for special
* processes on certain native platforms, such as native windowing
* processes, daemon processes, Win16/DOS processes on Microsoft
- * Windows, or shell scripts. The created subprocess does not have
- * its own terminal or console. All its standard I/O (i.e. stdin,
- * stdout, stderr) operations will be redirected to the parent process
- * through three streams
- * ({@link #getOutputStream()},
- * {@link #getInputStream()},
- * {@link #getErrorStream()}).
+ * Windows, or shell scripts.
+ *
+ * By default, the created subprocess does not have its own terminal
+ * or console. All its standard I/O (i.e. stdin, stdout, stderr)
+ * operations will be redirected to the parent process, where they can
+ * be accessed via the streams obtained using the methods
+ * {@link #getOutputStream()},
+ * {@link #getInputStream()}, and
+ * {@link #getErrorStream()}.
* The parent process uses these streams to feed input to and get output
* from the subprocess. Because some native platforms only provide
* limited buffer size for standard input and output streams, failure
* to promptly write the input stream or read the output stream of
- * the subprocess may cause the subprocess to block, and even deadlock.
+ * the subprocess may cause the subprocess to block, or even deadlock.
+ *
+ * Where desired,
+ * subprocess I/O can also be redirected
+ * using methods of the {@link ProcessBuilder} class.
*
* The subprocess is not killed when there are no more references to
* the {@code Process} object, but rather the subprocess
@@ -62,16 +68,22 @@ import java.io.*;
* Process} object execute asynchronously or concurrently with respect
* to the Java process that owns the {@code Process} object.
*
- * @author unascribed
- * @see ProcessBuilder
+ * As of 1.5, {@link ProcessBuilder#start()} is the preferred way
+ * to create a {@code Process}.
+ *
* @since JDK1.0
*/
public abstract class Process {
/**
* Returns the output stream connected to the normal input of the
* subprocess. Output to the stream is piped into the standard
- * input stream of the process represented by this {@code Process}
- * object.
+ * input of the process represented by this {@code Process} object.
+ *
+ * If the standard input of the subprocess has been redirected using
+ * {@link ProcessBuilder#redirectInput(Redirect)
+ * ProcessBuilder.redirectInput}
+ * then this method will return a
+ * null output stream.
*
* Implementation note: It is a good idea for the returned
* output stream to be buffered.
@@ -84,30 +96,47 @@ public abstract class Process {
/**
* Returns the input stream connected to the normal output of the
* subprocess. The stream obtains data piped from the standard
- * output stream of the process represented by this {@code
- * Process} object.
+ * output of the process represented by this {@code Process} object.
+ *
+ * If the standard output of the subprocess has been redirected using
+ * {@link ProcessBuilder#redirectOutput(Redirect)
+ * ProcessBuilder.redirectOutput}
+ * then this method will return a
+ * null input stream.
+ *
+ * Otherwise, if the standard error of the subprocess has been
+ * redirected using
+ * {@link ProcessBuilder#redirectErrorStream(boolean)
+ * ProcessBuilder.redirectErrorStream}
+ * then the input stream returned by this method will receive the
+ * merged standard output and the standard error of the subprocess.
*
* Implementation note: It is a good idea for the returned
* input stream to be buffered.
*
* @return the input stream connected to the normal output of the
* subprocess
- * @see ProcessBuilder#redirectErrorStream()
*/
abstract public InputStream getInputStream();
/**
- * Returns the input stream connected to the error output stream of
- * the subprocess. The stream obtains data piped from the error
- * output stream of the process represented by this {@code Process}
- * object.
+ * Returns the input stream connected to the error output of the
+ * subprocess. The stream obtains data piped from the error output
+ * of the process represented by this {@code Process} object.
+ *
+ * If the standard error of the subprocess has been redirected using
+ * {@link ProcessBuilder#redirectError(Redirect)
+ * ProcessBuilder.redirectError} or
+ * {@link ProcessBuilder#redirectErrorStream(boolean)
+ * ProcessBuilder.redirectErrorStream}
+ * then this method will return a
+ * null input stream.
*
* Implementation note: It is a good idea for the returned
* input stream to be buffered.
*
- * @return the input stream connected to the error output stream of
+ * @return the input stream connected to the error output of
* the subprocess
- * @see ProcessBuilder#redirectErrorStream()
*/
abstract public InputStream getErrorStream();
diff --git a/jdk/src/share/classes/java/lang/ProcessBuilder.java b/jdk/src/share/classes/java/lang/ProcessBuilder.java
index 32895a5baab..be24e8d8235 100644
--- a/jdk/src/share/classes/java/lang/ProcessBuilder.java
+++ b/jdk/src/share/classes/java/lang/ProcessBuilder.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2003-2006 Sun Microsystems, Inc. All Rights Reserved.
+ * Copyright 2003-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@@ -27,6 +27,10 @@ package java.lang;
import java.io.File;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileOutputStream;
+import java.util.Arrays;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@@ -34,7 +38,7 @@ import java.util.Map;
/**
* This class is used to create operating system processes.
*
- * Each Each {@code ProcessBuilder} instance manages a collection
* of process attributes. The {@link #start()} method creates a new
* {@link Process} instance with those attributes. The {@link
* #start()} method can be invoked repeatedly from the same instance
@@ -59,19 +63,64 @@ import java.util.Map;
*
* If the value is set to {@code true}, then:
+ *
+ * Note that this class is not synchronized.
- * If multiple threads access a Starting a new process which uses the default working directory
* and environment is easy:
*
- * Here is an example that starts a process with a modified working
- * directory and environment:
+ * directory and environment, and redirects standard output and error
+ * to be appended to a log file:
*
- * To start a process with an explicit set of environment
* variables, first call {@link java.util.Map#clear() Map.clear()}
* before adding environment variables.
*
+ * @author Martin Buchholz
* @since 1.5
*/
@@ -124,20 +182,19 @@ public final class ProcessBuilder
private File directory;
private MapfdObj
- * is {link java.io.FileDescriptor#valid() invalid}.
+ * is {@link java.io.FileDescriptor#valid() invalid}.
* However, if the methods are invoked on the resulting stream to attempt
* I/O on the stream, an IOException is thrown.
*
@@ -389,7 +389,7 @@ class FileInputStream extends InputStream
* @see java.io.FileInputStream#close()
*/
protected void finalize() throws IOException {
- if ((fd != null) && (fd != fd.in)) {
+ if ((fd != null) && (fd != FileDescriptor.in)) {
/*
* Finalizer should not release the FileDescriptor if another
diff --git a/jdk/src/share/classes/java/io/FileOutputStream.java b/jdk/src/share/classes/java/io/FileOutputStream.java
index 695f43150fe..f252237d89f 100644
--- a/jdk/src/share/classes/java/io/FileOutputStream.java
+++ b/jdk/src/share/classes/java/io/FileOutputStream.java
@@ -52,20 +52,16 @@ public
class FileOutputStream extends OutputStream
{
/**
- * The system dependent file descriptor. The value is
- * 1 more than actual file descriptor. This means that
- * the default value 0 indicates that the file is not open.
+ * The system dependent file descriptor.
*/
- private FileDescriptor fd;
+ private final FileDescriptor fd;
private FileChannel channel= null;
- private boolean append = false;
-
- private Object closeLock = new Object();
+ private final Object closeLock = new Object();
private volatile boolean closed = false;
- private static ThreadLocalFileDescriptor object is
* created to represent this file connection.
* name. If the second argument is true, then
+ * Creates a file output stream to write to the file with the specified
+ * name. If the second argument is true, then
* bytes will be written to the end of the file rather than the beginning.
* A new FileDescriptor object is created to represent this
* file connection.
@@ -202,16 +198,11 @@ class FileOutputStream extends OutputStream
}
fd = new FileDescriptor();
fd.incrementAndGetUseCount();
- this.append = append;
- if (append) {
- openAppend(name);
- } else {
- open(name);
- }
+ open(name, append);
}
/**
- * Creates an output file stream to write to the specified file
+ * Creates a file output stream to write to the specified file
* descriptor, which represents an existing connection to an actual
* file in the file system.
* fdObj
- * is {link java.io.FileDescriptor#valid() invalid}.
+ * is {@link java.io.FileDescriptor#valid() invalid}.
* However, if the methods are invoked on the resulting stream to attempt
* I/O on the stream, an IOException is thrown.
*
@@ -252,16 +243,12 @@ class FileOutputStream extends OutputStream
}
/**
- * Opens a file, with the specified name, for writing.
+ * Opens a file, with the specified name, for overwriting or appending.
* @param name name of file to be opened
+ * @param append whether the file is to be opened in append mode
*/
- private native void open(String name) throws FileNotFoundException;
-
- /**
- * Opens a file, with the specified name, for appending.
- * @param name name of file to be opened
- */
- private native void openAppend(String name) throws FileNotFoundException;
+ private native void open(String name, boolean append)
+ throws FileNotFoundException;
/**
* Writes the specified byte to this file output stream. Implements
@@ -385,7 +372,7 @@ class FileOutputStream extends OutputStream
public FileChannel getChannel() {
synchronized (this) {
if (channel == null) {
- channel = FileChannelImpl.open(fd, false, true, this, append);
+ channel = FileChannelImpl.open(fd, false, true, this);
/*
* Increment fd's use count. Invoking the channel's close()
@@ -408,7 +395,7 @@ class FileOutputStream extends OutputStream
*/
protected void finalize() throws IOException {
if (fd != null) {
- if (fd == fd.out || fd == fd.err) {
+ if (fd == FileDescriptor.out || fd == FileDescriptor.err) {
flush();
} else {
diff --git a/jdk/src/share/classes/java/lang/Process.java b/jdk/src/share/classes/java/lang/Process.java
index fe4045ab25f..88010fd555d 100644
--- a/jdk/src/share/classes/java/lang/Process.java
+++ b/jdk/src/share/classes/java/lang/Process.java
@@ -41,18 +41,24 @@ import java.io.*;
* ProcessBuilder instance manages a collection
+ * user.dir.
+ * named by the system property {@code user.dir}.
+ *
+ *
+ *
+ *
+ *
+ *
*
* false, meaning that the standard output and error
+ * is {@code false}, meaning that the standard output and error
* output of a subprocess are sent to two separate streams, which can
* be accessed using the {@link Process#getInputStream()} and {@link
- * Process#getErrorStream()} methods. If the value is set to
- * true, the standard error is merged with the standard
- * output. This makes it easier to correlate error messages with the
- * corresponding output. In this case, the merged data can be read
- * from the stream returned by {@link Process#getInputStream()}, while
- * reading from the stream returned by {@link
- * Process#getErrorStream()} will get an immediate end of file.
+ * Process#getErrorStream()} methods.
+ *
+ *
+ *
*
*
*
@@ -87,34 +136,43 @@ import java.util.Map;
* is invoked.
*
* ProcessBuilder instance
+ * If multiple threads access a {@code ProcessBuilder} instance
* concurrently, and at least one of the threads modifies one of the
* attributes structurally, it must be synchronized externally.
*
*
+ * }
*
*
+ *
{@code
* Process p = new ProcessBuilder("myCommand", "myArg").start();
- *
+ * assert pb.redirectInput() == Redirect.PIPE;
+ * assert pb.redirectOutput().file() == log;
+ * assert p.getInputStream().read() == -1;
+ * }
*
*
- * ProcessBuilder pb = new ProcessBuilder("myCommand", "myArg1", "myArg2");
- * Map<String, String> env = pb.environment();
+ * {@code
+ * ProcessBuilder pb =
+ * new ProcessBuilder("myCommand", "myArg1", "myArg2");
+ * Mapcommand list. Subsequent
+ * make a copy of the {@code command} list. Subsequent
* updates to the list will be reflected in the state of the
* process builder. It is not checked whether
- * command corresponds to a valid operating system
- * command.null
+ * @param command the list containing the program and its arguments
+ * @throws NullPointerException if the argument is null
*/
public ProcessBuilder(Listcommand
+ * list containing the same strings as the {@code command}
* array, in the same order. It is not checked whether
- * command corresponds to a valid operating system
- * command.command list. Subsequent updates to the list will
+ * {@code command} list. Subsequent updates to the list will
* be reflected in the state of the process builder. It is not
- * checked whether command corresponds to a valid
- * operating system command.
null
+ * @throws NullPointerException if the argument is null
*/
public ProcessBuilder command(Listcommand array, in the same order. It is not
- * checked whether command corresponds to a valid
- * operating system command.
+ * {@code command} array, in the same order. It is not
+ * checked whether {@code command} corresponds to a valid
+ * operating system command.
*
- * @param command A string array containing the program and its arguments
- * @return This process builder
+ * @param command a string array containing the program and its arguments
+ * @return this process builder
*/
public ProcessBuilder command(String... command) {
this.command = new ArrayListThe returned object may be modified using ordinary {@link
* java.util.Map Map} operations. These modifications will be
* visible to subprocesses started via the {@link #start()}
- * method. Two ProcessBuilder instances always
+ * method. Two {@code ProcessBuilder} instances always
* contain independent process environments, so changes to the
* returned map will never be reflected in any other
- * ProcessBuilder instance or the values returned by
+ * {@code ProcessBuilder} instance or the values returned by
* {@link System#getenv System.getenv}.
*
*
If the system does not support environment variables, an @@ -262,25 +318,24 @@ public final class ProcessBuilder *
The returned map is typically case-sensitive on all platforms. * *
If a security manager exists, its
- * {@link SecurityManager#checkPermission checkPermission}
- * method is called with a
- * {@link RuntimePermission}("getenv.*")
- * permission. This may result in a {@link SecurityException} being
- * thrown.
+ * {@link SecurityManager#checkPermission checkPermission} method
+ * is called with a
+ * {@link RuntimePermission}{@code ("getenv.*")} permission.
+ * This may result in a {@link SecurityException} being thrown.
*
*
When passing information to a Java subprocess, * system properties - * are generally preferred over environment variables.
+ * are generally preferred over environment variables. * - * @return This process builder's environment + * @return this process builder's environment * - * @throws SecurityException - * If a security manager exists and its - * {@link SecurityManager#checkPermission checkPermission} - * method doesn't allow access to the process environment + * @throws SecurityException + * if a security manager exists and its + * {@link SecurityManager#checkPermission checkPermission} + * method doesn't allow access to the process environment * - * @see Runtime#exec(String[],String[],java.io.File) - * @see System#getenv() + * @see Runtime#exec(String[],String[],java.io.File) + * @see System#getenv() */ public Mapnull -- this means to use
+ * The returned value may be {@code null} -- this means to use
* the working directory of the current Java process, usually the
- * directory named by the system property user.dir,
- * as the working directory of the child process.
+ * directory named by the system property {@code user.dir},
+ * as the working directory of the child process.
*
- * @return This process builder's working directory
+ * @return this process builder's working directory
*/
public File directory() {
return directory;
@@ -344,50 +399,522 @@ public final class ProcessBuilder
*
* Subprocesses subsequently started by this object's {@link
* #start()} method will use this as their working directory.
- * The argument may be null -- this means to use the
+ * The argument may be {@code null} -- this means to use the
* working directory of the current Java process, usually the
- * directory named by the system property user.dir,
- * as the working directory of the child process.
+ * directory named by the system property {@code user.dir},
+ * as the working directory of the child process.
*
- * @param directory The new working directory
- * @return This process builder
+ * @param directory the new working directory
+ * @return this process builder
*/
public ProcessBuilder directory(File directory) {
this.directory = directory;
return this;
}
+ // ---------------- I/O Redirection ----------------
+
+ /**
+ * Implements a null input stream.
+ */
+ static class NullInputStream extends InputStream {
+ public int read() { return -1; }
+ public int available() { return 0; }
+ }
+
+ /**
+ * Implements a null output stream.
+ */
+ static class NullOutputStream extends OutputStream {
+ public void write(int b) throws IOException {
+ throw new IOException("Stream closed");
+ }
+ }
+
+ /**
+ * Represents a source of subprocess input or a destination of
+ * subprocess output.
+ *
+ * Each {@code Redirect} instance is one of the following:
+ *
+ * Each of the above categories has an associated unique + * {@link Type Type}. + * + * @since 1.7 + */ + public static abstract class Redirect { + /** + * The type of a {@link Redirect}. + */ + public enum Type { + /** + * The type of {@link Redirect#PIPE Redirect.PIPE}. + */ + PIPE, + + /** + * The type of {@link Redirect#INHERIT Redirect.INHERIT}. + */ + INHERIT, + + /** + * The type of redirects returned from + * {@link Redirect#from Redirect.from(File)}. + */ + READ, + + /** + * The type of redirects returned from + * {@link Redirect#to Redirect.to(File)}. + */ + WRITE, + + /** + * The type of redirects returned from + * {@link Redirect#appendTo Redirect.appendTo(File)}. + */ + APPEND + }; + + /** + * Returns the type of this {@code Redirect}. + * @return the type of this {@code Redirect} + */ + public abstract Type type(); + + /** + * Indicates that subprocess I/O will be connected to the + * current Java process over a pipe. + * + * This is the default handling of subprocess standard I/O. + * + *
It will always be true that + *
{@code
+ * Redirect.PIPE.file() == null &&
+ * Redirect.PIPE.type() == Redirect.Type.PIPE
+ * }
+ */
+ public static final Redirect PIPE = new Redirect() {
+ public Type type() { return Type.PIPE; }
+ 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).
+ *
+ * It will always be true that + *
{@code
+ * Redirect.INHERIT.file() == null &&
+ * Redirect.INHERIT.type() == Redirect.Type.INHERIT
+ * }
+ */
+ public static final Redirect INHERIT = new Redirect() {
+ public Type type() { return Type.INHERIT; }
+ public String toString() { return type().toString(); }};
+
+ /**
+ * Returns the {@link File} source or destination associated
+ * with this redirect, or {@code null} if there is no such file.
+ *
+ * @return the file associated with this redirect,
+ * or {@code null} if there is no such file
+ */
+ public File file() { return null; }
+
+ FileOutputStream toFileOutputStream() throws IOException {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns a redirect to read from the specified file.
+ *
+ * It will always be true that + *
{@code
+ * Redirect.from(file).file() == file &&
+ * Redirect.from(file).type() == Redirect.Type.READ
+ * }
+ *
+ * @throws NullPointerException if the specified file is null
+ * @return a redirect to read from the specified file
+ */
+ public static Redirect from(final File file) {
+ if (file == null)
+ throw new NullPointerException();
+ return new Redirect() {
+ public Type type() { return Type.READ; }
+ public File file() { return file; }
+ public String toString() {
+ return "redirect to read from file \"" + file + "\"";
+ }
+ };
+ }
+
+ /**
+ * Returns a redirect to write to the specified file.
+ * If the specified file exists when the subprocess is started,
+ * its previous contents will be discarded.
+ *
+ * It will always be true that + *
{@code
+ * Redirect.to(file).file() == file &&
+ * Redirect.to(file).type() == Redirect.Type.WRITE
+ * }
+ *
+ * @throws NullPointerException if the specified file is null
+ * @return a redirect to write to the specified file
+ */
+ public static Redirect to(final File file) {
+ if (file == null)
+ throw new NullPointerException();
+ return new Redirect() {
+ public Type type() { return Type.WRITE; }
+ public File file() { return file; }
+ public String toString() {
+ return "redirect to write to file \"" + file + "\"";
+ }
+ FileOutputStream toFileOutputStream() throws IOException {
+ return new FileOutputStream(file, false);
+ }
+ };
+ }
+
+ /**
+ * Returns a redirect to append to the specified file.
+ * Each write operation first advances the position to the
+ * end of the file and then writes the requested data.
+ * Whether the advancement of the position and the writing
+ * of the data are done in a single atomic operation is
+ * system-dependent and therefore unspecified.
+ *
+ * It will always be true that + *
{@code
+ * Redirect.appendTo(file).file() == file &&
+ * Redirect.appendTo(file).type() == Redirect.Type.APPEND
+ * }
+ *
+ * @throws NullPointerException if the specified file is null
+ * @return a redirect to append to the specified file
+ */
+ public static Redirect appendTo(final File file) {
+ if (file == null)
+ throw new NullPointerException();
+ return new Redirect() {
+ public Type type() { return Type.APPEND; }
+ public File file() { return file; }
+ public String toString() {
+ return "redirect to append to file \"" + file + "\"";
+ }
+ FileOutputStream toFileOutputStream() throws IOException {
+ return new FileOutputStream(file, true);
+ }
+ };
+ }
+
+ /**
+ * Compares the specified object with this {@code Redirect} for
+ * equality. Returns {@code true} if and only if the two
+ * objects are identical or both objects are {@code Redirect}
+ * instances of the same type associated with non-null equal
+ * {@code File} instances.
+ */
+ public boolean equals(Object obj) {
+ if (obj == this)
+ return true;
+ if (! (obj instanceof Redirect))
+ return false;
+ Redirect r = (Redirect) obj;
+ if (r.type() != this.type())
+ return false;
+ assert this.file() != null;
+ return this.file().equals(r.file());
+ }
+
+ /**
+ * Returns a hash code value for this {@code Redirect}.
+ * @return a hash code value for this {@code Redirect}
+ */
+ public int hashCode() {
+ File file = file();
+ if (file == null)
+ return super.hashCode();
+ else
+ return file.hashCode();
+ }
+
+ /**
+ * No public constructors. Clients must use predefined
+ * static {@code Redirect} instances or factory methods.
+ */
+ private Redirect() {}
+ }
+
+ private Redirect[] redirects() {
+ if (redirects == null)
+ redirects = new Redirect[] {
+ Redirect.PIPE, Redirect.PIPE, Redirect.PIPE
+ };
+ return redirects;
+ }
+
+ /**
+ * Sets this process builder's standard input source.
+ *
+ * Subprocesses subsequently started by this object's {@link #start()}
+ * method obtain their standard input from this source.
+ *
+ * If the source is {@link Redirect#PIPE Redirect.PIPE} + * (the initial value), then the standard input of a + * subprocess can be written to using the output stream + * returned by {@link Process#getOutputStream()}. + * If the source is set to any other value, then + * {@link Process#getOutputStream()} will return a + * null output stream. + * + * @param source the new standard input source + * @return this process builder + * @throws IllegalArgumentException + * if the redirect does not correspond to a valid source + * of data, that is, has type + * {@link Redirect.Type#WRITE WRITE} or + * {@link Redirect.Type#APPEND APPEND} + * @since 1.7 + */ + public ProcessBuilder redirectInput(Redirect source) { + if (source.type() == Redirect.Type.WRITE || + source.type() == Redirect.Type.APPEND) + throw new IllegalArgumentException( + "Redirect invalid for reading: " + source); + redirects()[0] = source; + return this; + } + + /** + * Sets this process builder's standard output destination. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method send their standard output to this destination. + * + *
If the destination is {@link Redirect#PIPE Redirect.PIPE} + * (the initial value), then the standard output of a subprocess + * can be read using the input stream returned by {@link + * Process#getInputStream()}. + * If the destination is set to any other value, then + * {@link Process#getInputStream()} will return a + * null input stream. + * + * @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} + * @since 1.7 + */ + public ProcessBuilder redirectOutput(Redirect destination) { + if (destination.type() == Redirect.Type.READ) + throw new IllegalArgumentException( + "Redirect invalid for writing: " + destination); + redirects()[1] = destination; + return this; + } + + /** + * Sets this process builder's standard error destination. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method send their standard error to this destination. + * + *
If the destination is {@link Redirect#PIPE Redirect.PIPE} + * (the initial value), then the error output of a subprocess + * can be read using the input stream returned by {@link + * Process#getErrorStream()}. + * If the destination is set to any other value, then + * {@link Process#getErrorStream()} will return a + * null input stream. + * + *
If the {@link #redirectErrorStream redirectErrorStream} + * attribute has been set {@code true}, then the redirection set + * by this method has no effect. + * + * @param destination the new standard error 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} + * @since 1.7 + */ + public ProcessBuilder redirectError(Redirect destination) { + if (destination.type() == Redirect.Type.READ) + throw new IllegalArgumentException( + "Redirect invalid for writing: " + destination); + redirects()[2] = destination; + return this; + } + + /** + * Sets this process builder's standard input source to a file. + * + *
This is a convenience method. An invocation of the form + * {@code redirectInput(file)} + * behaves in exactly the same way as the invocation + * {@link #redirectInput(Redirect) redirectInput} + * {@code (Redirect.from(file))}. + * + * @param file the new standard input source + * @return this process builder + * @since 1.7 + */ + public ProcessBuilder redirectInput(File file) { + return redirectInput(Redirect.from(file)); + } + + /** + * Sets this process builder's standard output destination to a file. + * + *
This is a convenience method. An invocation of the form + * {@code redirectOutput(file)} + * behaves in exactly the same way as the invocation + * {@link #redirectOutput(Redirect) redirectOutput} + * {@code (Redirect.to(file))}. + * + * @param file the new standard output destination + * @return this process builder + * @since 1.7 + */ + public ProcessBuilder redirectOutput(File file) { + return redirectOutput(Redirect.to(file)); + } + + /** + * Sets this process builder's standard error destination to a file. + * + *
This is a convenience method. An invocation of the form + * {@code redirectError(file)} + * behaves in exactly the same way as the invocation + * {@link #redirectError(Redirect) redirectError} + * {@code (Redirect.to(file))}. + * + * @param file the new standard error destination + * @return this process builder + * @since 1.7 + */ + public ProcessBuilder redirectError(File file) { + return redirectError(Redirect.to(file)); + } + + /** + * Returns this process builder's standard input source. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method obtain their standard input from this source. + * The initial value is {@link Redirect#PIPE Redirect.PIPE}. + * + * @return this process builder's standard input source + * @since 1.7 + */ + public Redirect redirectInput() { + return (redirects == null) ? Redirect.PIPE : redirects[0]; + } + + /** + * Returns this process builder's standard output destination. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method redirect their standard output to this destination. + * The initial value is {@link Redirect#PIPE Redirect.PIPE}. + * + * @return this process builder's standard output destination + * @since 1.7 + */ + public Redirect redirectOutput() { + return (redirects == null) ? Redirect.PIPE : redirects[1]; + } + + /** + * Returns this process builder's standard error destination. + * + * Subprocesses subsequently started by this object's {@link #start()} + * method redirect their standard error to this destination. + * The initial value is {@link Redirect#PIPE Redirect.PIPE}. + * + * @return this process builder's standard error destination + * @since 1.7 + */ + public Redirect redirectError() { + return (redirects == null) ? Redirect.PIPE : redirects[2]; + } + + /** + * Sets the source and destination for subprocess standard I/O + * to be the same as those of the current Java process. + * + *
This is a convenience method. An invocation of the form + *
{@code
+ * pb.inheritIO()
+ * }
+ * behaves in exactly the same way as the invocation
+ * {@code
+ * pb.redirectInput(Redirect.INHERIT)
+ * .redirectOutput(Redirect.INHERIT)
+ * .redirectError(Redirect.INHERIT)
+ * }
+ *
+ * This gives behavior equivalent to most operating system
+ * command interpreters, or the standard C library function
+ * {@code system()}.
+ *
+ * @return this process builder
+ * @since 1.7
+ */
+ public ProcessBuilder inheritIO() {
+ Arrays.fill(redirects(), Redirect.INHERIT);
+ return this;
+ }
+
/**
* Tells whether this process builder merges standard error and
* standard output.
*
- * If this property is true, then any error output
+ *
If this property is {@code true}, then any error output
* 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
* to correlate error messages with the corresponding output.
- * The initial value is false.
redirectErrorStream property
+ * @return this process builder's {@code redirectErrorStream} property
*/
public boolean redirectErrorStream() {
return redirectErrorStream;
}
/**
- * Sets this process builder's redirectErrorStream property.
+ * Sets this process builder's {@code redirectErrorStream} property.
*
- * If this property is true, then any error output
+ *
If this property is {@code true}, then any error output
* 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
* to correlate error messages with the corresponding output.
- * The initial value is false.
If there is a security manager, its
* {@link SecurityManager#checkExec checkExec}
* method is called with the first component of this object's
- * command array as its argument. This may result in
+ * {@code command} array as its argument. This may result in
* a {@link SecurityException} being thrown.
*
*
Starting an operating system process is highly system-dependent. @@ -426,26 +953,42 @@ public final class ProcessBuilder * subclass of {@link IOException}. * *
Subsequent modifications to this process builder will not - * affect the returned {@link Process}.
+ * affect the returned {@link Process}. * - * @return A new {@link Process} object for managing the subprocess + * @return a new {@link Process} object for managing the subprocess * - * @throws NullPointerException - * If an element of the command list is null + * @throws NullPointerException + * if an element of the command list is null * - * @throws IndexOutOfBoundsException - * If the command is an empty list (has size0)
+ * @throws IndexOutOfBoundsException
+ * if the command is an empty list (has size {@code 0})
*
- * @throws SecurityException
- * If a security manager exists and its
- * {@link SecurityManager#checkExec checkExec}
- * method doesn't allow creation of the subprocess
+ * @throws SecurityException
+ * if a security manager exists and
+ * FileInputStream or FileOutputStream to
- * contain it.
- * - * Applications should not create their own file descriptors. + * to the underlying machine-specific structure representing an + * open file, an open socket, or another source or sink of bytes. + * The main practical use for a file descriptor is to create a + * {@link FileInputStream} or {@link FileOutputStream} to contain it. + * + *
Applications should not create their own file descriptors.
*
* @author Pavani Diwanji
- * @see java.io.FileInputStream
- * @see java.io.FileOutputStream
* @since JDK1.0
*/
public final class FileDescriptor {
@@ -81,6 +78,14 @@ public final class FileDescriptor {
public int get(FileDescriptor obj) {
return obj.fd;
}
+
+ public void setHandle(FileDescriptor obj, long handle) {
+ obj.handle = handle;
+ }
+
+ public long getHandle(FileDescriptor obj) {
+ return obj.handle;
+ }
}
);
}
@@ -88,7 +93,7 @@ public final class FileDescriptor {
/**
* A handle to the standard input stream. Usually, this file
* descriptor is not used directly, but rather via the input stream
- * known as System.in.
+ * known as {@code System.in}.
*
* @see java.lang.System#in
*/
@@ -97,7 +102,7 @@ public final class FileDescriptor {
/**
* A handle to the standard output stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
- * known as System.out.
+ * known as {@code System.out}.
* @see java.lang.System#out
*/
public static final FileDescriptor out = standardStream(1);
@@ -105,7 +110,7 @@ public final class FileDescriptor {
/**
* A handle to the standard error stream. Usually, this file
* descriptor is not used directly, but rather via the output stream
- * known as System.err.
+ * known as {@code System.err}.
*
* @see java.lang.System#err
*/
@@ -114,9 +119,9 @@ public final class FileDescriptor {
/**
* Tests if this file descriptor object is valid.
*
- * @return true if the file descriptor object represents a
+ * @return {@code true} if the file descriptor object represents a
* valid, open file, socket, or other active I/O connection;
- * false otherwise.
+ * {@code false} otherwise.
*/
public boolean valid() {
return ((handle != -1) || (fd != -1));
diff --git a/jdk/src/windows/classes/java/lang/ProcessImpl.java b/jdk/src/windows/classes/java/lang/ProcessImpl.java
index 9db29772571..910575c4447 100644
--- a/jdk/src/windows/classes/java/lang/ProcessImpl.java
+++ b/jdk/src/windows/classes/java/lang/ProcessImpl.java
@@ -25,7 +25,16 @@
package java.lang;
-import java.io.*;
+import java.io.IOException;
+import java.io.File;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.FileDescriptor;
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.lang.ProcessBuilder.Redirect;
/* This class is for the exclusive use of ProcessBuilder.start() to
* create new processes.
@@ -35,30 +44,82 @@ import java.io.*;
*/
final class ProcessImpl extends Process {
+ private static final sun.misc.JavaIOFileDescriptorAccess fdAccess
+ = sun.misc.SharedSecrets.getJavaIOFileDescriptorAccess();
// System-dependent portion of ProcessBuilder.start()
static Process start(String cmdarray[],
java.util.Map