WatcherThread.java

/* $Id$ */
package emissary.util;

import emissary.util.io.ReadOutput;

import java.io.IOException;
import java.io.PrintStream;
import java.time.Instant;
import javax.annotation.Nullable;

public class WatcherThread extends Thread {
    @Nullable
    private Process proc = null;
    private int delay = 1000;
    private boolean flag = true;

    public WatcherThread() {}

    public WatcherThread(Process pp) {
        proc = pp;
    }

    public void setDelay(int nn) {
        delay = nn;
    }

    public void setProcess(Process pp) {
        proc = pp;
    }

    public void killMe() {
        flag = false;
    }

    /**
     * I've chosen to use an internal flag (called flag) to represent the state of the running thread. Since this thread
     * spends most of its time sleeping, this will work fine. Otherwise, we'd have to use the interrupt method of the
     * thread.
     */
    @Override
    public void run() {
        int nTries = 10;
        int partialDelay = delay / nTries;
        int ii = 0;

        while (flag && (ii++ < nTries)) {
            if (proc != null) {
                try {
                    sleep(partialDelay);

                    if (ii == nTries) {
                        try {
                            proc.exitValue();
                        } catch (IllegalThreadStateException itsx) {
                            proc.destroy();
                            proc = null;
                            flag = false;
                        }
                    }
                } catch (InterruptedException ix) {
                    Thread.currentThread().interrupt();
                }
            }
        }
    }

    @SuppressWarnings("SystemOut")
    public static void main(String[] args) throws IOException {
        WatcherThread wt = new WatcherThread();
        String name = wt.getClass().getName();

        if (args.length != 2) {
            System.out.println("usage: " + name + " time cmd");

            return;
        }

        wt.setDelay(Integer.parseInt(args[0]));

        System.out.println(name + " begins at " + Instant.now());

        Process proc = Runtime.getRuntime().exec(args[1]);

        wt.setProcess(proc);

        PrintStream out = System.out;
        PrintStream err = System.err;

        Thread t1 = new Thread(new ReadOutput(proc.getInputStream(), name, out));
        Thread t2 = new Thread(new ReadOutput(proc.getErrorStream(), name, err));

        wt.start();
        t1.start();
        t2.start();

        try {
            proc.waitFor();
            wt.killMe();
            t1.join();
            t2.join();
        } catch (InterruptedException ix) {
            Thread.currentThread().interrupt();
        }

        System.out.println(name + " ends at " + Instant.now());


    }
}