package ilarkesto.base; import ilarkesto.core.logging.Log; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Utility class for easy handling of external processes and executing commands. */ public final class Proc { public static void main(String[] args) { Proc proc = new Proc("sudo"); proc.addParameter("ls"); proc.start(); proc.getOutput(); } private static final Log LOG = Log.get(Proc.class); /** * Starts the process and waits until it ends. Returns output when return code is 0. Otherwise throws * Exception. */ public static String execute(String command, String... parameters) { return execute(null, command, parameters); } public static String execute(File workDir, String command, String... parameters) { Proc proc = new Proc(command); proc.setWorkingDir(workDir); for (String parameter : parameters) { proc.addParameter(parameter); } return proc.execute(); } /** * Starts the process and waits until it ends. Returns output when return code is 0. Otherwise throws * Exception. */ public String execute() { return execute(0); } public String execute(int... acceptableReturnCodes) { start(); int rc = getReturnCode(); boolean rcOk = false; for (int acceptableReturnCode : acceptableReturnCodes) { if (rc == acceptableReturnCode) { rcOk = true; continue; } } if (!rcOk) { StringBuilder cmdline = new StringBuilder(); cmdline.append(command); if (parameters != null) { for (String parameter : parameters) { cmdline.append(" ").append(parameter); } } throw new RuntimeException("Command rc=" + rc + ": " + cmdline + "\n" + getOutput()); } return getOutput(); } /** * Start the process. */ public synchronized void start() { if (process != null) throw new RuntimeException("Process already started."); int paramLen = parameters == null ? 0 : parameters.size(); String[] cmdarray = new String[paramLen + 1]; cmdarray[0] = command; if (paramLen > 0) System.arraycopy(parameters.toArray(), 0, cmdarray, 1, paramLen); if (LOG.isDebugEnabled()) { StringBuilder sb = new StringBuilder(); if (workingDir == null) { sb.append(">"); } else { sb.append(workingDir).append(">"); } for (String s : cmdarray) { sb.append(" ").append(s); } LOG.debug(sb.toString()); } try { process = Runtime.getRuntime().exec(cmdarray, getEnvParameters(), workingDir); } catch (IOException ex) { throw new RuntimeException(ex); } output = new StringBuffer(); new StreamGobbler(process.getInputStream()); new StreamGobbler(process.getErrorStream()); } public Process getProcess() { return process; } /** * Wait until the process is finishes. */ public void waitFor() { getReturnCode(); } /** * Gets the return code of the process. Waits until process finishes. */ public int getReturnCode() { if (returnCode == null) { if (process == null) throw new RuntimeException("Process not started yet."); try { process.waitFor(); } catch (InterruptedException ex) { throw new RuntimeException("Command interrupted: " + command, ex); } returnCode = process.exitValue(); LOG.debug(" " + command + ":", "rc:", returnCode); } return returnCode; } /** * Gets the standard output of the process. */ public String getOutput() { if (output == null) throw new RuntimeException("Process not started yet."); return output.toString().trim(); } private Process process; private StringBuffer output; private Integer returnCode; // --- static convinience methods --- // public static int execAndGetReturnCode(String command, String... parameters) { // Proc proc = new Proc(command); // proc.setParameters(parameters); // proc.start(); // return proc.getReturnCode(); // } // --- sub classes --- private class StreamGobbler extends Thread { private InputStream is; StreamGobbler(InputStream is) { this.is = is; setDaemon(true); super.start(); } @Override public void run() { try { InputStreamReader isr = new InputStreamReader(is); BufferedReader br = new BufferedReader(isr); String line = null; while ((line = br.readLine()) != null) { synchronized (output) { output.append(line).append("\n"); } } } catch (IOException ex) { throw new RuntimeException(ex); } } } public Proc addEnvironmentProperty(String name, String value) { if (environment == null) environment = new HashMap<String, String>(); environment.put(name, value); return this; } private String[] getEnvParameters() { if (environment == null || environment.size() == 0) return null; String[] env = new String[environment.size()]; int i = 0; for (Map.Entry<String, String> entry : environment.entrySet()) { env[i++] = entry.getKey() + "=" + entry.getValue(); } return env; } // --- dependencies --- private Map<String, String> environment; public void setEnvironment(Map<String, String> environment) { this.environment = environment; } public void addEnvironmentParameter(String name, String value) { if (environment == null) environment = new HashMap<String, String>(); environment.put(name, value); } private String command; public Proc(String command) { this.command = command; } private List<String> parameters; public Proc setParameters(List<String> parameters) { this.parameters = parameters; return this; } public Proc addParameter(String parameter) { if (parameters == null) parameters = new ArrayList<String>(1); parameters.add(parameter); return this; } public Proc addParameters(String... parameters) { for (String parameter : parameters) addParameter(parameter); return this; } private File workingDir; public Proc setWorkingDir(File workingDir) { this.workingDir = workingDir; return this; } }