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

com.github.davidmoten.rx.Processes Maven / Gradle / Ivy

package com.github.davidmoten.rx;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import com.github.davidmoten.util.Optional;

import rx.Observable;
import rx.Observable.OnSubscribe;
import rx.Subscriber;
import rx.functions.Action1;
import rx.functions.Func0;
import rx.functions.Func1;
import rx.schedulers.Schedulers;

public final class Processes {

    public static void main(String[] args) throws IOException, InterruptedException {
        execute("ls").map(new Func1() {

            @Override
            public String call(byte[] bytes) {
                return new String(bytes);
            }
        });
    }

    public static Observable execute(String... command) {
        return execute(
                new Parameters(Arrays.asList(command), Optional.> absent(),
                        true, new File("."), Optional. absent()));
    }

    public static Observable execute(final Parameters parameters) {
        Func0 resourceFactory = new Func0() {

            @Override
            public Process call() {
                ProcessBuilder b = new ProcessBuilder(parameters.command());
                if (parameters.env().isPresent()) {
                    if (parameters.appendEnv())
                        b.environment().clear();
                    b.environment().putAll(parameters.env().get());
                }
                b.directory(parameters.directory());
                b.redirectErrorStream(true);
                try {
                    return b.start();
                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            }
        };

        Func1> factory = new Func1>() {
            @Override
            public Observable call(final Process process) {
                InputStream is = process.getInputStream();
                Observable output;
                if (is != null)
                    output = Bytes.from(is);
                else
                    output = Observable.empty();
                Observable completion = Observable.create(new OnSubscribe() {
                    @Override
                    public void call(Subscriber sub) {
                        try {
                            // TODO waitFor does not exist pre 1.8 with timeout!
                            // parameters.waitForMs().get(),TimeUnit.MILLISECONDS);

                            if (parameters.waitForMs().isPresent()) {
                                // boolean finished = process.waitFor(
                                // parameters.waitForMs().get(),
                                // TimeUnit.MILLISECONDS);
                                // if (!finished) {
                                // sub.onError(new TimeoutException("process
                                // timed out"));
                                // return;
                                // }
                                sub.onError(new IllegalArgumentException("not implemented yet"));
                            } else {
                                int exitCode = process.waitFor();
                                if (exitCode != 0)
                                    sub.onError(new ProcessException(exitCode));
                                return;
                            }
                            sub.onCompleted();
                        } catch (InterruptedException e) {
                            sub.onError(e);
                        }
                    }
                }).subscribeOn(Schedulers.io());
                return output.concatWith(completion);
            }
        };
        Action1 disposeAction = new Action1() {
            @Override
            public void call(Process process) {
                process.destroy();
            }
        };
        return Observable.using(resourceFactory, factory, disposeAction);
    }

    public static class ProcessException extends RuntimeException {
        private static final long serialVersionUID = 722422557667123473L;

        private final int exitCode;

        public ProcessException(int exitCode) {
            super("process returned exitCode " + exitCode);
            this.exitCode = exitCode;
        }

        public int exitCode() {
            return exitCode;
        }

    }

    public static final class Parameters {
        private final List command;
        private final Optional> env;
        private final boolean appendEnv;
        private final File directory;
        private final Optional waitForMs;

        public Parameters(List command, Optional> env,
                boolean appendEnv, File directory, Optional waitForMs) {
            this.command = command;
            this.env = env;
            this.appendEnv = appendEnv;
            this.directory = directory;
            this.waitForMs = waitForMs;
        }

        public Optional waitForMs() {
            return waitForMs;
        }

        public File directory() {
            return directory;
        }

        public List command() {
            return command;
        }

        public Optional> env() {
            return env;
        }

        public boolean appendEnv() {
            return appendEnv;
        }

    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy