001package arcommon; 002 003import java.io.File; 004import java.io.IOException; 005import java.io.InputStream; 006import java.io.OutputStream; 007import java.util.ArrayList; 008import java.util.Arrays; 009import java.util.Iterator; 010import java.util.List; 011 012public class ProcessUtil { 013 public static interface ProcessOutput { 014 public void output(String message, boolean err); 015 } 016 017 public static enum Priority {LOW, NORMAL, HIGH}; 018 019 public static class SimpleProcessOutput implements ProcessOutput { 020 public void output(String message, boolean err) { 021 message = message.replace("\r\r\n", "\r\n"); 022 if (err) { 023 System.err.print(message); 024 } else { 025 System.out.print(message); 026 } 027 } 028 }; 029 030 public static class FullProcessOutput implements ProcessOutput { 031 private StringBuilder messageStringBuilder = new StringBuilder(); 032 033 public void output(String message, boolean err) { 034 messageStringBuilder.append(message); 035 } 036 037 public String toString() { 038 return messageStringBuilder.toString(); 039 } 040 } 041 042 public static Process startCommand(String command, Priority priority) { 043 return startCommand(command, priority, (String[])null); 044 } 045 046 public static Process startCommand(String command, Priority priority, String ... parameters) { 047 if (!Util.isWindowsOS() && priority != Priority.NORMAL) { 048 throw new RuntimeException("Not supported"); 049 } 050 051 if (priority == Priority.NORMAL) { 052 return startCommand(command, parameters); 053 } 054 055 ArrayList<String> parameterList = new ArrayList<String>(); 056 parameterList.add("/c"); 057 parameterList.add("start"); 058 switch (priority) { 059 case LOW : 060 parameterList.add("/LOW"); 061 break; 062 case NORMAL : 063 parameterList.add("/NORMAL"); 064 break; 065 case HIGH : 066 parameterList.add("/HIGH"); 067 break; 068 default : 069 throw new RuntimeException("Unknown priority " + priority); 070 } 071 parameterList.add(command); 072 if (parameters != null) { 073 for (int i = 0; i < parameters.length; i++) { 074 if (parameters[i] == null) { 075 throw new NullPointerException("Parameter " + i + " is null. " + Arrays.toString(parameters)); 076 } 077 parameterList.add(parameters[i]); 078 } 079 } 080 String[] newParameters = parameterList.toArray(new String[parameterList.size()]); 081 return startCommand("cmd.exe", newParameters); 082 } 083 084 public static Process startCommand(String command) { 085 return startCommand(command, (String[])null); 086 } 087 088 public static Process startCommand(String command, String ... parameters) { 089 return startCommand(command, true, null, parameters); 090 } 091 092 public static Process startCommand(String command, boolean throwOnFail, File processStartDirectory, String ... parameters) { 093 return startCommand(command, throwOnFail, null, processStartDirectory, parameters); 094 } 095 096 public static Process startCommand(String command, boolean throwOnFail, String[] environmentVariables, File processStartDirectory, String ... parameters) { 097 try { 098 String[] parametersTemp = createParameters(command, parameters); 099 Process process = Runtime.getRuntime().exec(parametersTemp, environmentVariables, processStartDirectory); 100 return process; 101 } catch (Exception e) { 102 if (throwOnFail) { 103 throw new RuntimeException(e); 104 } 105 e.printStackTrace(); 106 return null; 107 } 108 } 109 110 private static String[] createParameters(String command, String ... parameters) { 111 ArrayList<String> parameterList = new ArrayList<String>(); 112 parameterList.add(command); 113 if (parameters != null) { 114 for (int i = 0; i < parameters.length; i++) { 115 if (parameters[i] == null) { 116 throw new NullPointerException("Parameter " + i + " is null. " + Arrays.toString(parameters)); 117 } 118 parameterList.add(parameters[i]); 119 } 120 } 121 return parameterList.toArray(new String[parameterList.size()]); 122 } 123 124 public static int executeCommandNoInputNoOutput(String command) { 125 return executeCommandNoInput(command, null, (String[])null); 126 } 127 128 public static int executeCommandNoInputNoOutput(String command, String ... parameters) { 129 return executeCommandNoInput(command, null, parameters); 130 } 131 132 public static int executeCommandNoInputNoOutput(String command, File processStartDirectory, String ... parameters) { 133 return executeCommandNoInput(command, null, processStartDirectory, parameters); 134 } 135 136 public static int executeCommandNoInputStdOutput(String command) { 137 return executeCommandNoInput(command, new SimpleProcessOutput(), (String[])null); 138 } 139 140 public static int executeCommandNoInputStdOutput(String command, String ... parameters) { 141 return executeCommandNoInput(command, new SimpleProcessOutput(), parameters); 142 } 143 144 public static int executeCommandNoInputStdOutput(String command, File processStartDirectory, String ... parameters) { 145 return executeCommand(command, false, new SimpleProcessOutput(), processStartDirectory, parameters); 146 } 147 148 public static int executeCommandStdInputNoOutput(String command) { 149 return executeCommand(command, true, null, null, (String[])null); 150 } 151 152 public static int executeCommandStdInputNoOutput(String command, String ... parameters) { 153 return executeCommand(command, true, null, null, parameters); 154 } 155 156 public static int executeCommandStdInputNoOutput(String command, File processStartDirectory, String ... parameters) { 157 return executeCommand(command, true, null, processStartDirectory, parameters); 158 } 159 160 public static int executeCommandStdInputStdOutput(String command) { 161 return executeCommand(command, true, new SimpleProcessOutput(), null, (String[])null); 162 } 163 164 public static int executeCommandStdInputStdOutput(String command, String ... parameters) { 165 return executeCommand(command, true, new SimpleProcessOutput(), null, parameters); 166 } 167 168 public static int executeCommandStdInputStdOutput(String command, File processStartDirectory, String ... parameters) { 169 return executeCommand(command, true, new SimpleProcessOutput(), processStartDirectory, parameters); 170 } 171 172 public static int executeCommandStdInput(String command, ProcessOutput processOutput) { 173 return executeCommandStdInput(command, processOutput, (String[])null); 174 } 175 176 public static int executeCommandStdInput(String command, ProcessOutput processOutput, String ... parameters) { 177 return executeCommand(command, true, processOutput, null, parameters); 178 } 179 180 public static int executeCommandStdInput(String command, ProcessOutput processOutput, File processStartDirectory, String ... parameters) { 181 return executeCommand(command, true, processOutput, processStartDirectory, parameters); 182 } 183 184 public static int executeCommandNoInput(String command, ProcessOutput processOutput) { 185 return executeCommandNoInput(command, processOutput, (String[])null); 186 } 187 188 public static int executeCommandNoInput(String command, ProcessOutput processOutput, String ... parameters) { 189 return executeCommand(command, false, processOutput, null, parameters); 190 } 191 192 public static int executeCommandNoInput(String command, ProcessOutput processOutput, File processStartDirectory, String ... parameters) { 193 return executeCommand(command, false, processOutput, processStartDirectory, parameters); 194 } 195 196 private static int executeCommand(String command, boolean stdInput, ProcessOutput processOutput, File processStartDirectory, String ... parameters) { 197 Process process = startCommand(command, true, processStartDirectory, parameters); 198 199 if (stdInput) { 200 attachStdInput(process); 201 } 202 203 return attachOutputAndWaitForExit(process, processOutput); 204 } 205 206 public static void attachStdInput(final Process process) { 207 try { 208 System.in.available(); 209 } catch (Exception e) { 210 System.out.println("Unable to attach standard input (" + e.getMessage() + ")"); 211 return ; 212 } 213 214 MyThread thread = new MyThread("Standard input read thread") { 215 @Override 216 public void run() { 217 OutputStream outputStream = process.getOutputStream(); 218 try { 219 while (true) { 220 String lineFromStdIn; 221 synchronized (ProcessUtil.class) { 222 while (System.in.available() == 0 && isProcessRunning(process)) { 223 Util.sleep(100); 224 } 225 if (!isProcessRunning(process)) { 226 break; 227 } 228 lineFromStdIn = Util.readLineFromStdIn(); 229 } 230 if (!isProcessRunning(process)) { 231 break; 232 } 233 outputStream.write(lineFromStdIn.getBytes()); 234 if (Util.isWindowsOS()) { 235 outputStream.write(13); 236 } 237 outputStream.write(10); 238 outputStream.flush(); 239 } 240 } catch (IOException e) { 241 throw new RuntimeException(e); 242 } 243 } 244 }; 245 thread.start(); 246 } 247 248 public static void attachStdOutput(Process process) { 249 attachOutput(process, new SimpleProcessOutput()); 250 } 251 252 public static void attachOutput(Process process, ProcessOutput processOutput) { 253 attachOutput(process, false, processOutput); 254 } 255 256 public static void attachOutput(final Process process, boolean daemonThread, final ProcessOutput processOutput) { 257 MyThread thread = new MyThread("Standard output write thread") { 258 @Override 259 public void run() { 260 attachOutputAndWaitForExit(process, processOutput); 261 }; 262 }; 263 if (daemonThread) { 264 thread.setDaemon(daemonThread); 265 } 266 thread.start(); 267 } 268 269 public static int attachOutputAndWaitForExit(Process process, ProcessOutput processOutput) { 270 if (process == null) { 271 throw new IllegalArgumentException("process == null"); 272 } 273 274 String encoding = System.getProperty("file.encoding"); 275 // Hack 276 if (Util.isWindowsOS()) { 277 encoding = "Cp1252"; 278 } else { 279 encoding = "UTF-8"; 280 } 281 282 try { 283 InputStream inputStream = process.getInputStream(); 284 InputStream errorStream = process.getErrorStream(); 285 boolean running = true; 286 int exitCode = -1; 287 do { 288 readBytesFromStream(inputStream, encoding, processOutput, false); 289 readBytesFromStream(errorStream, encoding, processOutput, true); 290 try { 291 exitCode = process.exitValue(); 292 running = false; 293 } catch (IllegalThreadStateException e) { 294 Util.sleep(DateUtil.SECOND_IN_MILLISECONDS / 10); 295 } 296 } while (running || inputStream.available() > 0 || errorStream.available() > 0); 297 return exitCode; 298 } catch (IOException e) { 299 throw new RuntimeException(e); 300 } 301 } 302 303 private static void readBytesFromStream(InputStream stream, String encoding, ProcessOutput processOutput, boolean err) { 304 try { 305 while (stream.available() > 0) { 306 byte[] buffer = new byte[1000]; 307 int length = stream.read(buffer); 308 if (length == -1) { 309 break; 310 } 311 if (length == 0) { 312 continue; 313 } 314 String message = new String(buffer, 0, length, encoding); 315 if (processOutput != null) { 316 processOutput.output(message, err); 317 } 318 } 319 } catch (IOException e) { 320 throw new RuntimeException(e); 321 } 322 } 323 324 public static int numberOfProcessesRunning(String processName) { 325 List<ProcessData> listProcess = listProcess(); 326 Iterator<ProcessData> i = listProcess.iterator(); 327 int result = 0; 328 while (i.hasNext()) { 329 ProcessData processData = i.next(); 330 if (processData.name.equals(processName)) { 331 result++; 332 } 333 } 334 return result; 335 } 336 337 public static boolean killProcess(String processName) { 338 if (!Util.isWindowsOS()) { 339 throw new RuntimeException("Not supported"); 340 } 341 int result = executeCommandNoInputNoOutput("taskkill", "/F", "/IM", processName); 342 return result == 0; 343 } 344 345 public static boolean isProcessRunning(Process process) { 346 try { 347 process.exitValue(); 348 return false; 349 } catch (IllegalThreadStateException e) { 350 return true; 351 } 352 } 353 354 public static boolean isProcessRunning(String processName) { 355 List<ProcessData> listProcess = listProcess(); 356 Iterator<ProcessData> i = listProcess.iterator(); 357 while (i.hasNext()) { 358 ProcessData processData = i.next(); 359 if (processData.name.startsWith(processName)) { 360 return true; 361 } 362 } 363 return false; 364 } 365 366 public static class ProcessData { 367 public String name; 368 public int pid; 369 public String sessionName; 370 public int sessionNumber; 371 public int memory; 372 373 public String toString() { 374 return name; 375 } 376 } 377 378 public static List<ProcessData> listProcess() { 379 switch (Util.getOSType()) { 380 case WINDOWS : 381 return listProcessWindows(); 382// break; 383 case LINUX : 384 return listProcessLinux(); 385// break; 386 case MAC : 387 throw new RuntimeException("Not supported"); 388// break; 389 default : 390 throw new RuntimeException("Unknown OS type: " + Util.getOSType()); 391 } 392 } 393 394 private static List<ProcessData> listProcessLinux() { 395 FullProcessOutput fullProcessOutput = new FullProcessOutput(); 396 executeCommandNoInput("ps", fullProcessOutput, "-eo", "%c"); 397 String output = fullProcessOutput.toString(); 398 String[] split = output.split("\n"); 399 List<ProcessData> result = new ArrayList<ProcessData>(); 400 for (int i = 1; i < split.length; i++) { 401 String name = split[i]; 402 ProcessData processData = new ProcessData(); 403 processData.name = name; 404 result.add(processData); 405 } 406 return result; 407 } 408 409 private static List<ProcessData> listProcessWindows() { 410 FullProcessOutput fullProcessOutput = new FullProcessOutput(); 411 executeCommandNoInput("tasklist", fullProcessOutput); 412 String output = fullProcessOutput.toString(); 413 String[] outputSplit = output.split("\r\n"); 414 List<ProcessData> result = new ArrayList<ProcessData>(); 415 for (int i = 4; i < outputSplit.length; i++) { 416 ProcessData processData = new ProcessData(); 417 /* 418Windows XP 419========================= ====== ================ ======== ============ 420 421Windows 10 422Image Name PID Session Name Session# Mem Usage 423========================= ======== ================ =========== ============ 424 1 2 3 4 5 6 7 8 42512345678901234567890123456789012345678901234567890123456789012345678901234567890 426 */ 427 if (Util.isWindowsXp()) { 428 // Windows XP 429 processData.name = outputSplit[i].substring(0, 25).trim(); 430 String number = outputSplit[i].substring(26, 32).trim(); 431 processData.pid = StringUtil.stringToInt(number); 432 processData.sessionName = outputSplit[i].substring(33, 49).trim(); 433 number = outputSplit[i].substring(50, 58).trim(); 434 processData.sessionNumber = StringUtil.stringToInt(number); 435 number = outputSplit[i].substring(59, 71 - 3).trim(); 436 number = StringUtil.replace(number, ".", ""); 437 processData.memory = StringUtil.stringToInt(number) * 1024; 438 } else { 439 // Windows 10 440 processData.name = outputSplit[i].substring(0, 25).trim(); 441 String number = outputSplit[i].substring(26, 34).trim(); 442 processData.pid = StringUtil.stringToInt(number); 443 processData.sessionName = outputSplit[i].substring(35, 51).trim(); 444 number = outputSplit[i].substring(52, 63).trim(); 445 processData.sessionNumber = StringUtil.stringToInt(number); 446 number = outputSplit[i].substring(65, 76 - 2).trim(); 447 processData.memory = (int)(StringUtil.stringToDouble(number) * 1024); 448 } 449 450 result.add(processData); 451 } 452 453 return result; 454 } 455}