/**
* The contents of this file are subject to the license and copyright
* detailed in the LICENSE file at the root of the source
* tree and available online at
*
* https://github.com/keeps/roda
*/
package org.roda.core.util;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;
import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* System command utility.
*
* @author Rui Castro
* @author Luis Faria
*/
public class CommandUtility {
private static final Logger LOGGER = LoggerFactory.getLogger(CommandUtility.class);
private CommandUtility() {
// do nothing
}
/**
* Execute the given command line.
*
* @param args
* the command line as a list of arguments.
*
* @return a {@link String} with the output of the command.
*
* @throws CommandException
*/
public static String execute(String... args) throws CommandException {
return execute(true, args);
}
/**
* Execute the given command line.
*
* @param args
* the command line as a list of arguments.
*
* @return a {@link String} with the output of the command.
*
* @throws CommandException
*/
public static String execute(boolean withErrorStream, String... args) throws CommandException {
int exitValue = 0;
String output;
try {
StringBuilder builder = new StringBuilder();
for (String arg : args) {
builder.append(arg + " ");
}
LOGGER.debug("Executing {}", builder);
// create and execute process
ProcessBuilder processBuilder = new ProcessBuilder(args);
processBuilder.redirectErrorStream(withErrorStream);
Process process = processBuilder.start();
// Get process output
InputStream is = process.getInputStream();
CaptureOutputThread captureOutputThread = new CaptureOutputThread(is);
synchronized (is) {
captureOutputThread.start();
// Wait until the CaptureOutputThread notifies that is finished
// reading the input stream.
LOGGER.debug("Waiting until CaptureOutputThread notifies");
is.wait();
}
LOGGER.debug("CaptureOutputThread notified. Getting output...");
output = captureOutputThread.output;
// Get process exit value
exitValue = process.waitFor();
IOUtils.closeQuietly(is);
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Command {} terminated with value {}", Arrays.toString(args), exitValue);
}
if (exitValue == 0) {
return output;
} else {
throw new CommandException("Command " + Arrays.toString(args) + " terminated with error code " + exitValue,
exitValue, output);
}
} catch (IOException | InterruptedException e) {
if (LOGGER.isDebugEnabled()) {
LOGGER.debug("Error executing command {}", Arrays.toString(args), e);
}
throw new CommandException("Error executing command " + Arrays.toString(args) + " - " + e.getMessage(), e);
}
}
/**
* Execute the given command line.
*
* @param args
* the command line as a list of arguments.
*
* @return a {@link String} with the output of the command.
*
* @throws CommandException
*/
public static String execute(List<String> args) throws CommandException {
return execute(args, true);
}
public static String execute(List<String> args, boolean withErrorStream) throws CommandException {
return execute(withErrorStream, args.toArray(new String[args.size()]));
}
}
class CaptureOutputThread extends Thread {
private static final Logger logger = LoggerFactory.getLogger(CaptureOutputThread.class);
InputStream is;
String output;
public CaptureOutputThread(InputStream is) {
this.is = is;
}
@Override
public void run() {
StringBuilder outputBuffer = new StringBuilder();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = reader.readLine()) != null) {
outputBuffer.append(line + System.lineSeparator());
logger.trace(line);
}
} catch (IOException e) {
logger.error("Exception reading from inputstream", e);
}
output = outputBuffer.toString();
synchronized (is) {
is.notify();
}
}
}