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

com.athaydes.osgiaas.api.env.ProcessRunner Maven / Gradle / Ivy

The newest version!
package com.athaydes.osgiaas.api.env;

import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * A Simple wrapper around {@link ProcessBuilder} to make it easy to run native commands,
 * redirecting the output to provided {@link PrintStream}s.
 */
public class ProcessRunner {

    private final ExecutorService executorService = Executors.newFixedThreadPool( 2 );

    /**
     * Run the given command, redirecting its process output to the provided streams.
     *
     * @param commands         command + its arguments.
     * @param workingDirectory process working directory
     * @param out              regular output stream
     * @param err              error output stream
     * @return the status code returned by the process
     * @throws IOException          if some problem occurs when running the process.
     * @throws InterruptedException if the process gets interrupted.
     */
    public int run( List commands,
                    File workingDirectory,
                    PrintStream out,
                    PrintStream err ) throws IOException, InterruptedException {
        Process process = new ProcessBuilder( commands )
                .directory( workingDirectory )
                .redirectInput( ProcessBuilder.Redirect.INHERIT )
                .start();

        CountDownLatch latch = new CountDownLatch( 2 );

        consume( process.getInputStream(), out, err, latch );
        consume( process.getErrorStream(), err, err, latch );

        int exitValue = process.waitFor();

        boolean noTimeout = latch.await( 5, TimeUnit.SECONDS );

        if ( !noTimeout ) {
            err.println( "Process timeout! Killing it forcefully" );
            process.destroyForcibly();
        }

        return exitValue;
    }

    /**
     * Shutdown the executor used internally. After a call to this method, this instance must
     * NOT be used again.
     */
    public void shutdown() {
        executorService.shutdownNow();
    }

    private void consume( InputStream stream,
                          PrintStream writer,
                          PrintStream err,
                          CountDownLatch latch ) {
        executorService.submit( () -> {
            BufferedReader reader = new BufferedReader(
                    new InputStreamReader( stream, StandardCharsets.UTF_8 ), 1024 );

            String nextLine;
            try {
                while ( ( nextLine = reader.readLine() ) != null ) {
                    writer.println( nextLine );
                }
            } catch ( Throwable e ) {
                e.printStackTrace( err );
            } finally {
                // done!
                latch.countDown();
            }
        } );
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy