Search code examples
javaeclipse-plugineclipse-rcpprocessbuilder

Cancel eclipse plugin job


I run in a eclipse plugin Job a process that performs long operations without much output.
I want to be able to cancel the Job if users request it, but with the implementation bellow, the Job is not stopping unless the process prints something to the output stream.

Process process = new ProcessBuilder(args).start();
Scanner scanner = new Scanner(
                (new InputStreamReader(
                        process.getInputStream(), UTF_8_CHARSET)));

while (scanner.hasNext())
{

    if (monitor.isCanceled() {
        // user canceled the job, destroy the process to return
        process.destroy();
        break;
    }

    CONSOLE.getStream().println(scanner.nextLine());

}

try {
    process.waitFor();

} catch (InterruptedException e) {

    Activator.log(ERROR, e.getMessage(), e);

} finally {
    process.destroyForcibly();
}

Do I have other options to handle the cancelling of the job and to stop the process faster instead of waiting for a new line feed?


Solution

  • You should put the code reading the process output stream in to a separate thread and in your main loop just wait for the process to end with a short timeout so you can check for canceled.

    So the main code would be something like:

    Process process = new ProcessBuilder(args).start();
    
    // Read standard output
    new StreamConsumer(process.getInputStream()).start();
    
    // You should also always read stderr
    new StreamConsumer(process.getErrorStream()).start();
    
    // Wait for process to end and check for cancel
    
    while (!process.waitFor(100, TimeUnit.MILLISECONDS) {
      if (monitor.isCanceled() {
        // user canceled the job, destroy the process to return
        process.destroy();
        break;
      }
    }
    

    And StreamConsumer is something like:

    public class StreamConsumer extends Thread
    {
      private final InputStream _input;
    
      public StreamConsumer(final InputStream inputStream)
      {
        super();
    
        _input = inputStream;
    
        setDaemon(true);
      }
    
    
      @Override
      public void run()
      {
        // TODO your code to read the stream
      }
    }