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

com.databasesandlife.util.Executor Maven / Gradle / Ivy

There is a newer version: 21.0.1
Show newest version
package com.databasesandlife.util;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.LoggerFactory;

import javax.annotation.Nonnull;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.charset.StandardCharsets;
import java.util.function.Consumer;

/**
 * @author This source is copyright Adrian Smith and licensed under the LGPL 3.
 * @see Project on GitHub
 */
public class Executor {

    /** 
     * @param command can be String or String[]
     * @param currentDirectoryOrNull if not null, what should the 'current directory' of the new process be? 
     */
    protected static void run(Object command, File currentDirectoryOrNull) {
        try {
            final String commandForLog;
            final Process p;
            if (command instanceof String) {
                commandForLog = (String)command;
                p = Runtime.getRuntime().exec((String)command, null, currentDirectoryOrNull);
            }
            else if (command instanceof String[]) {
                commandForLog = StringUtils.join((String[])command, " ");
                p = Runtime.getRuntime().exec((String[])command, null, currentDirectoryOrNull);
            }
            else throw new RuntimeException("comamnd must be String or String[], is " + command.getClass());
            
            var log = LoggerFactory.getLogger(ProcessStreamReaderRunnable.class);
            var stdoutThread = spawnFor(new ProcessStreamReaderRunnable(p.getInputStream(), log::info));
            var stderrThread = spawnFor(new ProcessStreamReaderRunnable(p.getErrorStream(), log::error));
            stdoutThread.start();
            stderrThread.start();
            var returnCode = p.waitFor();
            if (returnCode != 0) {
                throw new ReturnCodeNotZeroException("Return code for command '" + commandForLog + "' is '" + returnCode + "'");
            }
        } catch (IOException | InterruptedException e) {
            throw new RuntimeException(e);
        }
    }
    
    public static void run(String[] command, File currentDirectoryOrNull) { run((Object)command, currentDirectoryOrNull); }
    public static void run(String command, File currentDirectoryOrNull) { run((Object)command, currentDirectoryOrNull); }
    public static void run(String[] command) { run(command, null); }
    public static void run(String command) { run(command, null); }
    
    private static Thread spawnFor(Runnable r) {
        var t = new Thread(r);
        t.setDaemon(true);
        return t;
    }

    public static class ProcessStreamReaderRunnable implements Runnable {

        private final InputStream stream;
        private final @Nonnull Consumer log;

        public ProcessStreamReaderRunnable(InputStream stream, @Nonnull Consumer log) {
            this.stream = stream;
            this.log = log;
        }

        @Override
        public void run() {
            try (var reader = new BufferedReader(new InputStreamReader(stream, StandardCharsets.UTF_8))) {
                String line;
                while ((line = reader.readLine()) != null) {
                    log.accept(line);
                }
            } catch (IOException e) {
                throw new RuntimeException(e);
            }

        }
    }

    public static class ReturnCodeNotZeroException extends RuntimeException {
        public ReturnCodeNotZeroException(String message) {
            super(message);
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy