alluxio.shell.ShellCommand Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of alluxio-core-common Show documentation
Show all versions of alluxio-core-common Show documentation
Common utilities shared in Alluxio core modules
/*
* The Alluxio Open Foundation licenses this work under the Apache License, version 2.0
* (the "License"). You may not use this work except in compliance with the License, which is
* available at www.apache.org/licenses/LICENSE-2.0
*
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
* either express or implied, as more fully set forth in the License.
*
* See the NOTICE file distributed with this work for information regarding copyright ownership.
*/
package alluxio.shell;
import alluxio.util.ShellUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.Charset;
import java.util.Arrays;
import javax.annotation.concurrent.NotThreadSafe;
/**
* Object representation of a shell command.
*/
@NotThreadSafe
public class ShellCommand {
private static final Logger LOG = LoggerFactory.getLogger(ShellCommand.class);
private final String[] mCommand;
/**
* Creates a ShellCommand object with the command to exec.
*
* @param execString shell command
*/
public ShellCommand(String[] execString) {
mCommand = execString.clone();
}
/**
* Runs a command and returns its stdout on success.
* Stderr is redirected to stdout.
*
* @return the output
* @throws IOException if the command returns a non-zero exit code
*/
public String run() throws IOException {
Process process = new ProcessBuilder(mCommand).redirectErrorStream(true).start();
BufferedReader inReader =
new BufferedReader(new InputStreamReader(process.getInputStream(),
Charset.defaultCharset()));
try {
// read the output of the command
StringBuilder output = new StringBuilder();
String line = inReader.readLine();
while (line != null) {
output.append(line);
output.append("\n");
line = inReader.readLine();
}
// wait for the process to finish and check the exit code
int exitCode = process.waitFor();
if (exitCode != 0) {
throw new ShellUtils.ExitCodeException(exitCode, output.toString());
}
return output.toString();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
} finally {
// close the input stream
try {
// JDK 7 tries to automatically drain the input streams for us
// when the process exits, but since close is not synchronized,
// it creates a race if we close the stream first and the same
// fd is recycled. the stream draining thread will attempt to
// drain that fd!! it may block, OOM, or cause bizarre behavior
// see: https://bugs.openjdk.java.net/browse/JDK-8024521
// issue is fixed in build 7u60
InputStream stdout = process.getInputStream();
synchronized (stdout) {
inReader.close();
}
} catch (IOException e) {
LOG.warn(String.format("Error while closing the input stream of process %s: %s",
process, e.getMessage()));
}
process.destroy();
}
}
/**
* Runs a command and returns its output and exit code in Object.
* Preserves the output when the execution fails.
* If the command execution fails (not by an interrupt),
* try to wrap the Exception in the {@link CommandReturn}.
* Stderr is redirected to stdout.
*
* @return {@link CommandReturn} object representation of stdout, stderr and exit code
*/
public CommandReturn runWithOutput() throws IOException {
Process process = null;
BufferedReader inReader = null;
try {
process = new ProcessBuilder(mCommand).redirectErrorStream(true).start();
inReader =
new BufferedReader(new InputStreamReader(process.getInputStream()));
// read the output of the command
StringBuilder stdout = new StringBuilder();
String outLine = inReader.readLine();
while (outLine != null) {
stdout.append(outLine);
stdout.append("\n");
outLine = inReader.readLine();
}
// wait for the process to finish and check the exit code
int exitCode = process.waitFor();
if (exitCode != 0) {
// log error instead of throwing exception
LOG.warn(String.format("Non-zero exit code (%d) from command %s",
exitCode, Arrays.toString(mCommand)));
}
CommandReturn cr = new CommandReturn(exitCode, mCommand, stdout.toString());
// destroy the process
if (process != null) {
process.destroy();
}
return cr;
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new IOException(e);
} catch (Exception e) {
return new CommandReturn(1, String.format("Command %s failed, exception is %s",
Arrays.toString(mCommand), e.getMessage()));
} finally {
if (inReader != null) {
inReader.close();
}
if (process != null) {
process.destroy();
}
}
}
/**
* Converts the command to string repr.
*
* @return the shell command
* */
public String toString() {
return Arrays.toString(mCommand);
}
/**
* Gets the command. The original array is immutable.
*
* @return a copy of the command string array
* */
public String[] getCommand() {
return Arrays.copyOfRange(mCommand, 0, mCommand.length);
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy