001: /* Licensed to the Apache Software Foundation (ASF) under one or more
002: * contributor license agreements. See the NOTICE file distributed with
003: * this work for additional information regarding copyright ownership.
004: * The ASF licenses this file to You under the Apache License, Version 2.0
005: * (the "License"); you may not use this file except in compliance with
006: * the License. You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package java.lang;
018:
019: import java.io.File;
020: import java.io.IOException;
021: import java.util.ArrayList;
022: import java.util.List;
023: import java.util.Map;
024:
025: /**
026: * <p>
027: * A builder for creating OS-specific processes.
028: * </p>
029: *
030: * @since 1.5
031: */
032: public final class ProcessBuilder {
033:
034: private List<String> command;
035:
036: private File directory;
037:
038: private Map<String, String> environment;
039:
040: private boolean redirectErrorStream;
041:
042: /**
043: * <p>
044: * Constructs an instance with the given command.
045: * </p>
046: *
047: * @param command
048: * The program and arguments.
049: */
050: public ProcessBuilder(String... command) {
051: this (toList(command));
052: }
053:
054: /**
055: * <p>
056: * Constructs an instance with the given command.
057: * </p>
058: *
059: * @param command
060: * The program and arguments.
061: * @throws NullPointerException
062: * if <code>command</code> is <code>null</code>.
063: */
064: public ProcessBuilder(List<String> command) {
065: super ();
066: if (command == null) {
067: throw new NullPointerException();
068: }
069: this .command = command;
070: this .environment = new org.apache.harmony.luni.platform.Environment.EnvironmentMap(
071: System.getenv());
072: }
073:
074: /**
075: * <p>
076: * The builder's current program and arguments. The returned value is
077: * considered live and modifications to it will change the state of the
078: * instance.
079: * </p>
080: *
081: * @return The program and arguments currently set.
082: */
083: public List<String> command() {
084: return command;
085: }
086:
087: /**
088: * <p>
089: * Changes the program and arguments to the command given.
090: * </p>
091: *
092: * @param command
093: * The program and arguments.
094: * @return A reference to this instance.
095: */
096: public ProcessBuilder command(String... command) {
097: return command(toList(command));
098: }
099:
100: /**
101: * <p>
102: * Changes the program and arguments to the command given. The list passed
103: * is not copied, so any subsequent updates to it are reflected in this
104: * instance's state.
105: * </p>
106: *
107: * @param command
108: * The program and arguments.
109: * @return A reference to this instance.
110: * @throws NullPointerException
111: * if <code>command</code> is <code>null</code>.
112: */
113: public ProcessBuilder command(List<String> command) {
114: if (command == null) {
115: throw new NullPointerException();
116: }
117: this .command = command;
118: return this ;
119: }
120:
121: /**
122: * <p>
123: * The working directory that's currently set. If this value is
124: * <code>null</code>, then the working directory of the Java process is
125: * used.
126: * </p>
127: *
128: * @return The current working directory, which may be <code>null</code>.
129: */
130: public File directory() {
131: return directory;
132: }
133:
134: /**
135: * <p>
136: * Changes the working directory to the directory given. If the given
137: * directory is <code>null</code>, then the working directory of the Java
138: * process is used when a process is started.
139: * </p>
140: *
141: * @param directory
142: * The working directory to set.
143: * @return A reference to this instance.
144: */
145: public ProcessBuilder directory(File directory) {
146: this .directory = directory;
147: return this ;
148: }
149:
150: /**
151: * <p>
152: * The builder's current environment. When an instance is created, the
153: * environment is populated with a copy of the environment, as returned by
154: * {@link System#getenv()}. The Map returned is live and any changes made
155: * to it are reflected in this instance's state.
156: * </p>
157: *
158: * @return The Map of the current environment variables.
159: */
160: public Map<String, String> environment() {
161: return environment;
162: }
163:
164: /**
165: * <p>
166: * Indicates whether or not the standard error should be redirected to
167: * standard output. If redirected, the {@link Process#getErrorStream()} will
168: * always return end of stream and standard error is written to
169: * {@link Process#getInputStream()}.
170: * </p>
171: *
172: * @return Indicates whether or not standard error is redirected.
173: */
174: public boolean redirectErrorStream() {
175: return redirectErrorStream;
176: }
177:
178: /**
179: * <p>
180: * Changes the state of whether or not standard error is redirected.
181: * </p>
182: *
183: * @param redirectErrorStream
184: * <code>true</code> to redirect standard error,
185: * <code>false</code> if not.
186: * @return A reference to this instance.
187: */
188: public ProcessBuilder redirectErrorStream(
189: boolean redirectErrorStream) {
190: this .redirectErrorStream = redirectErrorStream;
191: return this ;
192: }
193:
194: /**
195: * <p>
196: * Starts a new process based on the current state of the builder.
197: * </p>
198: *
199: * @return The new process that was started.
200: * @throws NullPointerException
201: * if any of the elements of {@link #command()} are
202: * <code>null</code>.
203: * @throws IndexOutOfBoundsException
204: * if {@link #command()} is empty.
205: * @throws SecurityException
206: * if {@link SecurityManager#checkExec(String)} doesn't allow
207: * process creation.
208: * @throws IOException
209: * if an I/O error happens.
210: */
211: public Process start() throws IOException {
212: if (command.isEmpty()) {
213: throw new IndexOutOfBoundsException();
214: }
215: String[] cmdArray = new String[command.size()];
216: for (int i = 0; i < cmdArray.length; i++) {
217: if ((cmdArray[i] = command.get(i)) == null) {
218: throw new NullPointerException();
219: }
220: }
221: String[] envArray = new String[environment.size()];
222: int i = 0;
223: for (Map.Entry<String, String> entry : environment.entrySet()) {
224: envArray[i++] = entry.getKey() + "=" + entry.getValue(); //$NON-NLS-1$
225: }
226: Process process = Runtime.getRuntime().exec(cmdArray, envArray,
227: directory);
228: // TODO implement support for redirectErrorStream
229: return process;
230: }
231:
232: private static List<String> toList(String[] strings) {
233: ArrayList<String> arrayList = new ArrayList<String>(
234: strings.length);
235: for (String string : strings) {
236: arrayList.add(string);
237: }
238: return arrayList;
239: }
240: }
|