All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.softicar.platform.common.io.command.ShellCommandExecutor Maven / Gradle / Ivy

Go to download

The SoftiCAR Platform is a lightweight, Java-based library to create interactive business web applications.

There is a newer version: 50.0.0
Show newest version
package com.softicar.platform.common.io.command;

import com.softicar.platform.common.io.file.line.FileLineIterator;
import java.io.File;
import java.io.IOException;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * Executes a shell command in a separate process.
 *
 * @author Alexander Schmidt
 */
public class ShellCommandExecutor {

	private static final String DEFAULT_SHELL = "sh";
	private static final String DEFAULT_SHELL_COMMAND_ARGUMENT = "-c";
	private static final long DEFAULT_TIMEOUT = 0;

	private String shell;
	private String shellCommandArgument;
	private long timeout;
	private TimeUnit timeoutTimeUnit;
	private StringBuilder executionOutput;
	private boolean executionSuccessful;
	private boolean executionTimedOut;

	public ShellCommandExecutor() {

		this.shell = DEFAULT_SHELL;
		this.shellCommandArgument = DEFAULT_SHELL_COMMAND_ARGUMENT;
		this.timeout = DEFAULT_TIMEOUT;
		this.timeoutTimeUnit = null;
		resetExecutionResults();
	}

	/**
	 * Specifies the name of the shell binary which shall be used to invoke the
	 * command.
	 * 

* Typical examples include "sh" and "bash". *

* By default, {@value #DEFAULT_SHELL} is used. * * @param shell * the name of the shell binary to use (never null) * @return this {@link ShellCommandExecutor} */ public ShellCommandExecutor setShell(String shell) { this.shell = Objects.requireNonNull(shell); return this; } /** * Specifies the name of the shell argument which is required to make the * shell binary expect a command from a passed argument, rather than from * standard input. *

* Typically, "-c" is required here. *

* By default, {@value #DEFAULT_SHELL_COMMAND_ARGUMENT} is used. * * @param shellCommandArgument * the command mode argument of the shell binary (never * null) * @return this {@link ShellCommandExecutor} * @see #setShell(String) */ public ShellCommandExecutor setShellCommandArgument(String shellCommandArgument) { this.shellCommandArgument = Objects.requireNonNull(shellCommandArgument); return this; } /** * Defines the amount of time to wait for the shell command to return. *

* If the given timeout value is 0, the current thread will wait * upon command execution, until the created {@link Process} has terminated. *

* By default, a timeout of {@value #DEFAULT_TIMEOUT} is used. * * @param timeout * the maximum time to wait for the shell command to return (at * least 0) * @param timeoutTimeUnit * the {@link TimeUnit} that qualifies the waiting time (never * null) * @return this {@link ShellCommandExecutor} * @throws IllegalArgumentException * if the given timeout value is <0 */ public ShellCommandExecutor setTimeout(long timeout, TimeUnit timeoutTimeUnit) { if (timeout < 0) { throw new IllegalArgumentException(); } this.timeout = timeout; this.timeoutTimeUnit = Objects.requireNonNull(timeoutTimeUnit); return this; } /** * Executes the given shell command in a separate process. *

* Records the output of the command (with the error output being redirected * to the standard output), for subsequent retrieval via * {@link #getOutput()}. * * @param command * the shell command to execute (never null) */ public void execute(String command) { try { resetExecutionResults(); ProcessBuilder processBuilder = new ProcessBuilder(new String[] { shell, shellCommandArgument, command }); processBuilder.directory(new File(".")); processBuilder.redirectErrorStream(true); Process process = processBuilder.start(); try (FileLineIterator iterator = FileLineIterator.readUtf8(process::getInputStream)) { for (String line: iterator) { executionOutput.append(line + "\n"); } } if (isTimeoutDefined()) { this.executionSuccessful = process.waitFor(timeout, timeoutTimeUnit); this.executionTimedOut = !executionSuccessful; } else { this.executionSuccessful = process.waitFor() == 0; this.executionTimedOut = false; } } catch (IOException | InterruptedException exception) { throw new RuntimeException(exception); } } /** * Retrieves the output of the most recently executed command. * * @return the output of the command (never null) */ public String getOutput() { return executionOutput.toString(); } /** * Determines whether the command terminated normally. *

* That is, if the exit value was 0 and if it terminated before the * defined timeout (if any) was encountered. * * @return true if the command terminated normally; false * otherwise */ public boolean isExecutionSuccessful() { return executionSuccessful; } /** * Determines whether a timeout was encountered while waiting for the * termination of the command. * * @return true if a timeout was encountered; false otherwise */ public boolean isExecutionTimedOut() { return executionTimedOut; } private boolean isTimeoutDefined() { return timeout > 0 && timeoutTimeUnit != null; } private void resetExecutionResults() { this.executionOutput = new StringBuilder(); this.executionSuccessful = false; this.executionTimedOut = false; } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy