LinuxCommandExecutor

Linux Command Executor

Linux Command Executor

Utility class to run linux commands from java application

ProcessExecutor.java
package com.codergists.util;

import com.codergists.exception.ProcessExecutionException;
import lombok.extern.slf4j.Slf4j;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;

import static java.lang.String.join;
import static java.util.concurrent.TimeUnit.SECONDS;
import static org.apache.logging.log4j.util.Strings.isEmpty;

/**
 * ProcessExecutor to run list of commands and return success response.
 * <p>
 * This Singleton class executes array of commands on {@link Runtime} and wait for specified Time Period to get the
 * response back.
 * <p>
 *
 * @author tvajjala = ProcessExecutor.getInstance().execute("whoami");
 */
@Slf4j
public final class ProcessExecutor {

    /**
     * runtime
     */
    private static final Runtime RUNTIME = Runtime.getRuntime();
    /**
     * process execution
     */
    private static final ProcessExecutor _INSTANCE = new ProcessExecutor();

    /**
     * private constructor
     */
    private ProcessExecutor() {
    }

    /**
     * Return instance of {@link ProcessExecutor}
     *
     * @return CommandExecutor
     */
    public static ProcessExecutor getInstance() {
        return _INSTANCE;
    }

    /**
     * Execute commands and return response with default TimeoutPeriod ( 3 seconds)
     *
     * @param commands arrays of commands to be executed
     * @return success response as string
     */
    public String execute(final String... commands) {
        return execute(60L, commands);
    }

    /**
     * Execute commands and return response with specific timeOutPeriod in seconds
     *
     * @param timeOutInSeconds timeOutInSeconds
     * @param commands         arrays of commands to be executed
     * @return success response as string
     */
    public String execute(final long timeOutInSeconds, final String... commands) {

        Process process = null;
        String command = join(" ", commands);//delimiter must be space.
        try (ByteArrayOutputStream errorOutputStream = new ByteArrayOutputStream();
                ByteArrayOutputStream successOutputStream = new ByteArrayOutputStream()) {
            log.info("Executing command [{}]", command);
            process = RUNTIME.exec(new String[] { "/bin/sh", "-c", command });
            asyncStreamReader(process.getErrorStream(), errorOutputStream);
            asyncStreamReader(process.getInputStream(), successOutputStream);

            log.debug("Waiting process to be completed");
            process.waitFor(timeOutInSeconds, SECONDS);
            int exitCode = process.exitValue();

            final String successResponse = new String(successOutputStream.toByteArray()).trim();
            final String errorResponse = new String(errorOutputStream.toByteArray()).trim();

            //FAILURE-CASE:exitCode=0, with errorResponse
            if (!isEmpty(errorResponse)) {
                log.warn("Received errorResponse {}", errorResponse);
                throw new ProcessExecutionException(errorResponse, exitCode);
            }

            //FAILURE-CASE:exitCode!=0
            if (exitCode != 0) {
                String errorMsg = successResponse + errorResponse;
                log.warn("Received exitCode {} with response {}", exitCode, errorMsg);
                throw new ProcessExecutionException(errorMsg, exitCode);
            }

            //SUCCESS-CASE: for exitCode==0
            log.info("Received successResponse {}", successResponse);
            return successResponse;
        } catch (final ProcessExecutionException processExecutionException) {
            //don't log as error, caller will decide whether error or not
            log.warn("Failed to execute command [{}]", command, processExecutionException);
            throw processExecutionException;
        } catch (final Exception unknownException) {
            //don't log as error, caller will decide whether error or not
            log.warn("Unknown exception while running command [{}]", command);
            throw new ProcessExecutionException(unknownException.getMessage(), unknownException);
        } finally {
            try {
                if (null != process) {
                    process.destroy();
                }
                log.debug("Process destroyed successfully");
            } catch (final Exception processCloseException) {
                log.warn("Failed to destroy the process", processCloseException);
            }
        }
    }

    private void asyncStreamReader(final InputStream inputStream, OutputStream outputStream) {
        new Thread(() -> {
            try (final BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream));
                    BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(outputStream))) {
                String input;
                while ((input = reader.readLine()) != null) {
                    writer.write(input);
                    writer.newLine();
                    writer.flush();
                }
            } catch (final IOException ioException) {
                log.warn("Unable to read the stream", ioException);
                throw new ProcessExecutionException("Unable to read the stream", ioException);
            }
        }).start();
    }

}

Comments

Popular posts from this blog

IBM Datapower GatewayScript

Spring boot Kafka Integration

Spring boot SOAP Web Service Performance