/** * Copyright (c) 2014-2017 by the respective copyright holders. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.smarthome.io.net.exec; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.util.Arrays; import org.apache.commons.exec.CommandLine; import org.apache.commons.exec.DefaultExecuteResultHandler; import org.apache.commons.exec.DefaultExecutor; import org.apache.commons.exec.ExecuteException; import org.apache.commons.exec.ExecuteWatchdog; import org.apache.commons.exec.Executor; import org.apache.commons.exec.PumpStreamHandler; import org.apache.commons.lang.StringUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Some common methods to execute commands on command line. * * @author Pauli Anttila - Initial contribution * @author Kai Kreuzer - added exception logging */ public class ExecUtil { private static final String CMD_LINE_DELIMITER = "@@"; /** * <p> * Executes <code>commandLine</code>. Sometimes (especially observed on MacOS) the commandLine isn't executed * properly. In that cases another exec-method is to be used. To accomplish this please use the special delimiter ' * <code>@@</code>'. If <code>commandLine</code> contains this delimiter it is split into a String[] array and the * special exec-method is used. * </p> * <p> * A possible {@link IOException} gets logged but no further processing is done. * </p> * * @param commandLine * the command line to execute * @see http://www.peterfriese.de/running-applescript-from-java/ */ public static void executeCommandLine(String commandLine) { Logger logger = LoggerFactory.getLogger(ExecUtil.class); try { if (commandLine.contains(CMD_LINE_DELIMITER)) { String[] cmdArray = commandLine.split(CMD_LINE_DELIMITER); Runtime.getRuntime().exec(cmdArray); logger.info("executed commandLine '{}'", Arrays.asList(cmdArray)); } else { Runtime.getRuntime().exec(commandLine); logger.info("executed commandLine '{}'", commandLine); } } catch (IOException e) { logger.error("couldn't execute commandLine '" + commandLine + "'", e); } } /** * <p> * Executes <code>commandLine</code>. Sometimes (especially observed on MacOS) the commandLine isn't executed * properly. In that cases another exec-method is to be used. To accomplish this please use the special delimiter ' * <code>@@</code>'. If <code>commandLine</code> contains this delimiter it is split into a String[] array and the * special exec-method is used. * </p> * <p> * A possible {@link IOException} gets logged but no further processing is done. * </p> * * @param commandLine * the command line to execute * @param timeout * timeout for execution in milliseconds * @return response data from executed command line */ public static String executeCommandLineAndWaitResponse(String commandLine, int timeout) { String retval = null; CommandLine cmdLine = null; if (commandLine.contains(CMD_LINE_DELIMITER)) { String[] cmdArray = commandLine.split(CMD_LINE_DELIMITER); cmdLine = new CommandLine(cmdArray[0]); for (int i = 1; i < cmdArray.length; i++) { cmdLine.addArgument(cmdArray[i], false); } } else { cmdLine = CommandLine.parse(commandLine); } DefaultExecuteResultHandler resultHandler = new DefaultExecuteResultHandler(); ExecuteWatchdog watchdog = new ExecuteWatchdog(timeout); Executor executor = new DefaultExecutor(); ByteArrayOutputStream stdout = new ByteArrayOutputStream(); PumpStreamHandler streamHandler = new PumpStreamHandler(stdout); executor.setExitValues(null); executor.setStreamHandler(streamHandler); executor.setWatchdog(watchdog); Logger logger = LoggerFactory.getLogger(ExecUtil.class); try { executor.execute(cmdLine, resultHandler); logger.debug("executed commandLine '{}'", commandLine); } catch (ExecuteException e) { logger.warn("couldn't execute commandLine '" + commandLine + "'", e); } catch (IOException e) { logger.warn("couldn't execute commandLine '" + commandLine + "'", e); } // some time later the result handler callback was invoked so we // can safely request the exit code try { resultHandler.waitFor(); int exitCode = resultHandler.getExitValue(); retval = StringUtils.chomp(stdout.toString()); if (resultHandler.getException() != null) { logger.warn(resultHandler.getException().getMessage()); } else { logger.debug("exit code '{}', result '{}'", exitCode, retval); } } catch (InterruptedException e) { logger.warn("Timeout occurred when executing commandLine '" + commandLine + "'", e); } return retval; } }