1 /*
2 * Copyright (C) 2014 Cristian Sulea ( http://cristian.sulea.net )
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 *
14 * You should have received a copy of the GNU Lesser General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 */
17
18 package jatoo.exec;
19
20 import java.io.File;
21 import java.io.IOException;
22 import java.io.OutputStream;
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.List;
26
27 /**
28 * Handy class to ease the execution of operating system commands.
29 *
30 * TODO: WARNING: not tested on Linux
31 *
32 * @author <a href="http://cristian.sulea.net" rel="author">Cristian Sulea</a>
33 * @version 1.5, July 25, 2014
34 */
35 public class CommandExecutor {
36
37 private final List<String> commandPrefix;
38
39 public CommandExecutor() {
40
41 String osName = System.getProperty("os.name");
42
43 //
44 // Linux systems (WARNING: not tested)
45
46 if (osName.equals("Linux")) {
47 commandPrefix = new ArrayList<String>(0);
48 }
49
50 //
51 // old Windows systems
52
53 else if (osName.equals("Windows 95") || osName.equals("Windows 98") || osName.equalsIgnoreCase("Windows ME")) {
54 commandPrefix = Arrays.asList("command.com", "/C");
55 }
56
57 //
58 // modern (others) Windows systems
59
60 else {
61 commandPrefix = Arrays.asList("cmd.exe", "/C");
62 }
63 }
64
65 /**
66 * Handy method for {@link #exec(String, File, OutputStream, boolean)} running
67 * in working folder of JVM with no dump output stream.
68 *
69 * @param command
70 * the command to be executed
71 *
72 * @return the exit value of the process (by convention, the value
73 * <code>0</code> indicates normal termination)
74 *
75 * @throws IOException
76 * if an I/O error occurs
77 * @throws InterruptedException
78 * if the current thread is {@linkplain Thread#interrupt()
79 * interrupted} by another thread while it is waiting
80 */
81 public final int exec(final String command) throws IOException, InterruptedException {
82 return exec(command, null, null, false);
83 }
84
85 /**
86 * Handy method for {@link #exec(String, File, OutputStream, boolean)} with no
87 * dump output stream.
88 *
89 * @param command
90 * the command to be executed
91 * @param folder
92 * the working folder
93 *
94 * @return the exit value of the process (by convention, the value
95 * <code>0</code> indicates normal termination)
96 *
97 * @throws IOException
98 * if an I/O error occurs
99 * @throws InterruptedException
100 * if the current thread is {@linkplain Thread#interrupt()
101 * interrupted} by another thread while it is waiting
102 */
103 public final int exec(final String command, final File folder) throws IOException, InterruptedException {
104 return exec(command, folder, null, false);
105 }
106
107 /**
108 * Handy method for {@link #exec(String, File, OutputStream, boolean)} running
109 * in working folder of JVM with specified dump output stream (but no
110 * closing).
111 *
112 * @param command
113 * the command to be executed
114 * @param dumpOutputStream
115 * the stream where the process will dump (exhaust) his contents
116 *
117 * @return the exit value of the process (by convention, the value
118 * <code>0</code> indicates normal termination)
119 *
120 * @throws IOException
121 * if an I/O error occurs
122 * @throws InterruptedException
123 * if the current thread is {@linkplain Thread#interrupt()
124 * interrupted} by another thread while it is waiting
125 */
126 public final int exec(final String command, final OutputStream dumpOutputStream) throws IOException, InterruptedException {
127 return exec(command, null, dumpOutputStream, false);
128 }
129
130 /**
131 * Handy method for {@link #exec(String, File, OutputStream, boolean)} with
132 * specified dump output stream (but no closing).
133 *
134 * @param command
135 * the command to be executed
136 * @param folder
137 * the working folder
138 * @param dumpOutputStream
139 * the stream where the process will dump (exhaust) his contents
140 *
141 * @return the exit value of the process (by convention, the value
142 * <code>0</code> indicates normal termination)
143 *
144 * @throws IOException
145 * if an I/O error occurs
146 * @throws InterruptedException
147 * if the current thread is {@linkplain Thread#interrupt()
148 * interrupted} by another thread while it is waiting
149 */
150 public final int exec(final String command, final File folder, final OutputStream dumpOutputStream) throws IOException, InterruptedException {
151 return exec(command, folder, dumpOutputStream, false);
152 }
153
154 /**
155 * Executes the specified command.
156 *
157 * @param command
158 * the command to be executed
159 * @param folder
160 * the working folder
161 * @param dumpOutputStream
162 * the stream where the process will dump (exhaust) his contents
163 * @param closeDumpOutputStream
164 * <code>true</code> if the dump stream should be closed when the
165 * execution ends, <code>false</code> otherwise
166 *
167 * @return the exit value of the process (by convention, the value
168 * <code>0</code> indicates normal termination)
169 *
170 * @throws IOException
171 * if an I/O error occurs
172 * @throws InterruptedException
173 * if the current thread is {@linkplain Thread#interrupt()
174 * interrupted} by another thread while it is waiting
175 */
176 public final int exec(final String command, final File folder, final OutputStream dumpOutputStream, final boolean closeDumpOutputStream) throws IOException, InterruptedException {
177
178 //
179 // add the prefix to the command
180
181 List<String> commandList = new ArrayList<String>(commandPrefix.size() + 1);
182 commandList.addAll(commandPrefix);
183 commandList.add(command);
184
185 //
186 // create and start the process
187
188 Process process = new ProcessBuilder(commandList).directory(folder).start();
189
190 //
191 // exhaust both the standard error stream and the standard output stream
192
193 if (dumpOutputStream != null) {
194 new Thread(new InputStreamExhausterWithDumpStream(process.getInputStream(), dumpOutputStream, closeDumpOutputStream)).start();
195 new Thread(new InputStreamExhausterWithDumpStream(process.getErrorStream(), dumpOutputStream, closeDumpOutputStream)).start();
196 } else {
197 new Thread(new InputStreamExhauster(process.getInputStream())).start();
198 new Thread(new InputStreamExhauster(process.getErrorStream())).start();
199 }
200
201 //
202 // wait until the process has terminated
203
204 return process.waitFor();
205 }
206
207 }