package com.laytonsmith.PureUtilities; import com.laytonsmith.PureUtilities.Common.StreamUtils; import com.laytonsmith.PureUtilities.Common.StringUtils; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Contains utilities to execute an external process and retrieve various * results from it. * */ public class CommandExecutor { /** * If you're in a hurry, and all you want is to get the output of System.out * from a process started with a string, this will do it for you. * @param command * @return */ public static String Execute(String command) throws InterruptedException, IOException{ return Execute(StringToArray(command)); } /** * If you're in a hurry, and all you want is to get the output of System.out * from a process started with a list of arguments, this will do it for you. * @param args * @return */ public static String Execute(String [] args) throws InterruptedException, IOException{ final List<Byte> output = new ArrayList<Byte>(); CommandExecutor c = new CommandExecutor(args); OutputStream os = new BufferedOutputStream(new OutputStream() { @Override public void write(int next) throws IOException { output.add((byte)next); } }); c.setSystemOut(os); c.start(); c.waitFor(); Byte[] Bytes = new Byte[output.size()]; byte[] bytes = new byte[output.size()]; Bytes = output.toArray(Bytes); for(int i = 0; i < Bytes.length; i++){ bytes[i] = Bytes[i]; } return new String(bytes, "UTF-8"); } private static String [] StringToArray(String s){ List<String> argList = StringUtils.ArgParser(s); String [] args = new String[argList.size()]; args = argList.toArray(args); return args; } public CommandExecutor(String command){ this(StringToArray(command)); } private String [] args; private Process process; private InputStream in; private OutputStream out; private OutputStream err; private File workingDir = null; private Thread outThread; private Thread errThread; private Thread inThread; public CommandExecutor(String [] command){ args = command; } /** * Starts this CommandExecutor. Afterwards, you can call .waitFor to wait * until the process has finished. * @return * @throws IOException */ public CommandExecutor start() throws IOException{ ProcessBuilder builder = new ProcessBuilder(args); builder.directory(workingDir); process = builder.start(); outThread = new Thread(new Runnable() { @Override public void run() { InputStream bout = new BufferedInputStream(process.getInputStream()); int ret; try { while((ret = bout.read()) != -1){ if(out != null){ out.write(ret); } } if(out != null){ out.flush(); } } catch (IOException ex) { Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex); } finally { if(out != null){ try { out.close(); } catch (IOException ex) { Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex); } } } } }, Arrays.toString(args) + "-output"); outThread.start(); errThread = new Thread(new Runnable() { @Override public void run() { InputStream berr = new BufferedInputStream(process.getErrorStream()); int ret; try { while((ret = berr.read()) != -1){ if(err != null){ err.write(ret); } } if(err != null){ err.flush(); } } catch (IOException ex) { Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex); } finally { if(err != null){ try { err.close(); } catch (IOException ex) { Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex); } } } } }, Arrays.toString(args) + "-error"); errThread.start(); if(in != null){ inThread = new Thread(new Runnable() { @Override public void run() { OutputStream bin = new BufferedOutputStream(process.getOutputStream()); int ret; try { while((ret = in.read()) != -1){ bin.write(ret); } } catch (IOException ex) { Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex); } finally { if(in != null){ try { in.close(); } catch (IOException ex) { Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex); } } } } }, Arrays.toString(args) + "-input"); inThread.start(); } return this; } public CommandExecutor setSystemIn(InputStream input){ if(process != null){ throw new RuntimeException("Process is already started! Cannot set a new InputStream!"); } in = input; return this; } public CommandExecutor setSystemOut(OutputStream output){ if(process != null){ throw new RuntimeException("Process is already started! Cannot set a new InputStream!"); } out = output; return this; } public CommandExecutor setSystemErr(OutputStream error){ if(process != null){ throw new RuntimeException("Process is already started! Cannot set a new OutputStream!"); } err = error; return this; } public InputStream getSystemIn(){ return in; } public OutputStream getSystemOut(){ return out; } public OutputStream getSystemErr(){ return err; } public CommandExecutor setWorkingDir(File workingDir){ if(process != null){ throw new RuntimeException("Process is already started! Cannot set a new working directory!"); } this.workingDir = workingDir; return this; } public int waitFor() throws InterruptedException { int ret = process.waitFor(); if(out != null){ try { out.flush(); } catch (IOException ex) { Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex); } } if(err != null){ try { err.flush(); } catch (IOException ex) { Logger.getLogger(CommandExecutor.class.getName()).log(Level.SEVERE, null, ex); } } outThread.join(); errThread.join(); return ret; } /** * Sets the inputs and outputs to be System.in, System.out, and StreamUtils.GetSystemErr(). * @return */ public CommandExecutor setSystemInputsAndOutputs(){ setSystemOut(StreamUtils.GetSystemOut()); setSystemErr(StreamUtils.GetSystemErr()); setSystemIn(System.in); return this; } }