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 }