Commits

Bryan Turner  committed 1887e9d

Propagated ExternalProcessImpl.canceled to the ProcessHandler on complete
- Added boolean canceled to ProcessHandler.complete
- Added isCanceled() flag to ProcessHandler
- Revised PluggableProcessHandler.complete to only throw on non-zero exit code if the process was not canceled

  • Participants
  • Parent commits e4f888a
  • Branches 1.5.x

Comments (0)

Files changed (4)

File src/main/java/com/atlassian/utils/process/ExternalProcessImpl.java

                 }
 
                 int exitCode = wrapUpProcess();
-                handler.complete(exitCode, processException);
+                handler.complete(exitCode, canceled, processException);
             }
         } else {
-            handler.complete(-1, processException);
+            handler.complete(-1, false, processException);
         }
     }
 
                     // process finished
                     finished = true;
                     int exitCode = wrapUpProcess();
-                    handler.complete(exitCode, processException);
+                    handler.complete(exitCode, canceled, processException);
                 }
             }
             return finished;
         } else {
-            handler.complete(-1, processException);
+            handler.complete(-1, false, processException);
             return true;
         }
     }

File src/main/java/com/atlassian/utils/process/PluggableProcessHandler.java

 import java.io.OutputStream;
 
 /**
- * An implementation of a ProcessHandler where the processors for the process' IO streams can
- * be plugged in.
- *
+ * An implementation of a ProcessHandler where the {@link InputHandler} and {@link OutputHandler}s for the process's
+ * input, output and error streams can be plugged in.
  */
 public class PluggableProcessHandler extends BaseProcessHandler {
 
-    private int exitCode;
-    private ProcessException exception;
-
-    private OutputHandler outputHandler;
-    private OutputHandler errorHandler;
-    private InputHandler inputHandler;
-
-    private boolean complete;
-    private boolean throwOnNonZeroExit = true;
-
     private static final Logger LOGGER = Logger.getLogger(PluggableProcessHandler.class);
 
+    private boolean canceled;
+    private boolean complete;
+    private OutputHandler errorHandler;
+    private ProcessException exception;
+    private int exitCode;
+    private InputHandler inputHandler;
+    private OutputHandler outputHandler;
+    private boolean throwOnNonZeroExit;
+
     public PluggableProcessHandler() {
+        throwOnNonZeroExit = true;
     }
 
     public PluggableProcessHandler(OutputHandler outputHandler, OutputHandler errorHandler) {
+        this();
+
         this.outputHandler = outputHandler;
         this.errorHandler = errorHandler;
     }
         this.inputHandler = inputHandler;
     }
 
-    public void processOutput(InputStream processOutput) throws ProcessException {
-        if (outputHandler == null) {
-            throw new IllegalStateException("Process output received with no handler");
-        }
-        outputHandler.setWatchdog(getWatchdog());
-        outputHandler.process(processOutput);
-    }
-
-    public void processError(InputStream processError) throws ProcessException {
-        if (errorHandler == null) {
-            throw new IllegalStateException("Process error output received with no handler");
-        }
-        errorHandler.setWatchdog(getWatchdog());
-        errorHandler.process(processError);
-    }
-
-    public boolean hasInput() {
-        return inputHandler != null;
-    }
-
-    public void provideInput(OutputStream processInput) {
-        if (!hasInput()) {
-            throw new IllegalStateException("Attempt to read input without an input handler");
-        }
-        inputHandler.setWatchdog(getWatchdog());
-        inputHandler.process(processInput);
-    }
-
-    public void complete(int code, ProcessException pe) {
+    public void complete(int code, boolean canceled, ProcessException pe) {
+        this.canceled = canceled;
+        this.exception = pe;
         this.exitCode = code;
-        this.exception = pe;
         if (outputHandler != null) {
             try {
                 outputHandler.complete();
             }
         }
 
-        if (pe == null && code != 0 && throwOnNonZeroExit) {
+        if (pe == null && throwOnNonZeroExit && !(canceled || code == 0)) {
             setException(new ProcessException("Non-zero exit code: " + code, code));
         }
         complete = true;
     }
 
+    public String getError() {
+        return null;
+    }
+
+    public OutputHandler getErrorHandler() {
+        return errorHandler;
+    }
+
+    public ProcessException getException() {
+        return exception;
+    }
+
     public int getExitCode() {
         return exitCode;
     }
 
-    public ProcessException getException() {
-        return exception;
+    public InputHandler getInputHandler() {
+        return inputHandler;
+    }
+
+    public OutputHandler getOutputHandler() {
+        return outputHandler;
+    }
+
+    public boolean hasInput() {
+        return inputHandler != null;
+    }
+
+    public boolean isCanceled() {
+        return canceled;
+    }
+
+    public boolean isComplete() {
+        return complete;
+    }
+
+    public boolean isThrowOnNonZeroExit() {
+        return throwOnNonZeroExit;
+    }
+
+    public void processError(InputStream processError) throws ProcessException {
+        if (errorHandler == null) {
+            throw new IllegalStateException("Process error output received with no handler");
+        }
+        errorHandler.setWatchdog(getWatchdog());
+        errorHandler.process(processError);
+    }
+
+    public void processOutput(InputStream processOutput) throws ProcessException {
+        if (outputHandler == null) {
+            throw new IllegalStateException("Process output received with no handler");
+        }
+        outputHandler.setWatchdog(getWatchdog());
+        outputHandler.process(processOutput);
+    }
+
+    public void provideInput(OutputStream processInput) {
+        if (!hasInput()) {
+            throw new IllegalStateException("Attempt to read input without an input handler");
+        }
+        inputHandler.setWatchdog(getWatchdog());
+        inputHandler.process(processInput);
+    }
+
+    public void reset() {
+        canceled = false;
+        complete = false;
+        exception = null;
+        exitCode = 0;
+    }
+
+    public boolean succeeded() {
+        return exception == null;
+    }
+
+    public void setErrorHandler(OutputHandler errorHandler) {
+        this.errorHandler = errorHandler;
     }
 
     public void setException(Throwable e) {
         }
     }
 
-    public String getError() {
-        return null;
+    public void setInputHandler(InputHandler inputHandler) {
+        this.inputHandler = inputHandler;
     }
 
     public void setOutputHandler(OutputHandler outputHandler) {
         this.outputHandler = outputHandler;
     }
 
-    public void setErrorHandler(OutputHandler errorHandler) {
-        this.errorHandler = errorHandler;
-    }
-
-    public void setInputHandler(InputHandler inputHandler) {
-        this.inputHandler = inputHandler;
-    }
-
-    public OutputHandler getOutputHandler() {
-        return outputHandler;
-    }
-
-    public OutputHandler getErrorHandler() {
-        return errorHandler;
-    }
-
-    public InputHandler getInputHandler() {
-        return inputHandler;
-    }
-
-    public boolean succeeded() {
-        return exception == null;
-    }
-
-    public void reset() {
-        exitCode = 0;
-        exception = null;
-        complete = false;
-    }
-
-    public boolean isComplete() {
-        return complete;
-    }
-
-    public boolean isThrowOnNonZeroExit() {
-        return throwOnNonZeroExit;
-    }
-
     public void setThrowOnNonZeroExit(boolean throwOnNonZeroExit) {
         this.throwOnNonZeroExit = throwOnNonZeroExit;
     }

File src/main/java/com/atlassian/utils/process/ProcessHandler.java

  * @see com.atlassian.utils.process.ExternalProcess
  */
 public interface ProcessHandler {
-    /**
-     * Process the process stdout stream
-     *
-     * @param output the external process' output stream (available as an input to this class)
-     * @throws ProcessException if there is a problem processing the output
-     */
-    void processOutput(InputStream output) throws ProcessException;
-
-    /**
-     * Process the process stderr stream
-     *
-     * @param error the external process' standard error stream (available as an input to this class)
-     * @throws ProcessException if there is a problem processing the output
-     */
-    void processError(InputStream error) throws ProcessException;
-
-    /**
-     * Indicate if this handler has input to provide to the process
-     *
-     * @return true if input is available
-     */
-    boolean hasInput();
-
-    /**
-     * Provide input to the external process. Input is provided by writing the content to the
-     * given output stream. This method will only be called if hasInput() returns true
-     *
-     * @param input the output stream representing standard input to the external process
-     * @throws IllegalStateException if no input has been configured.
-     */
-    void provideInput(OutputStream input);
 
     /**
      * Called when the external process has completed
      *
      * @param exitCode the exit code of the external process
+     * @param canceled {@code true} to indicate the process was canceled, otherwise {@code false} if the process was
+     *                 allowed to run to completion
      * @param exception any process exceptions that were thrown within the VM when handling the
      *        external process
      */
-    void complete(int exitCode, ProcessException exception);
-
-    /**
-     * Indicate if the process has completed
-     *
-     * @return true if complete has been called.
-     */
-    boolean isComplete();
-
-    /**
-     * Set the watchdog associated with this handler. The watchdog should be called at regular intervals
-     * to prevent the external process being terminated. Typically this is done in the IO handling methods
-     *
-     * @return the handler's watchdog instance
-     */
-    void setWatchdog(Watchdog watchdog);
-
-    /**
-     * Indicate if the process execution has been considered successful.
-     *
-     * @return true if the process execution completed without error
-     */
-    boolean succeeded();
-
-    /**
-     * Called if the process is to be re-executed.
-     */
-    void reset();
+    void complete(int exitCode, boolean canceled, ProcessException exception);
 
     /**
      * Get any processing exception associated with this handler
      * @return process exit code
      */
     int getExitCode();
+
+    /**
+     * Indicate if this handler has input to provide to the process
+     *
+     * @return true if input is available
+     */
+    boolean hasInput();
+
+    /**
+     * Retrieves a flag indicating whether the process was allowed to run to completion or was canceled.
+     * <p/>
+     * Note: This flag only has meaning when {@link #isComplete()} returns {@code true}. If the process has not yet
+     * completed, it is undefined whether or not the process has been canceled. Therefore, this method may return
+     * {@code true} or {@code false} inconsistently for incomplete processes.
+     *
+     * @return {@code true} if the process was canceled; otherwise, {@code false} if it ran to completion
+     */
+    boolean isCanceled();
+
+    /**
+     * Indicate if the process has completed
+     *
+     * @return true if complete has been called.
+     */
+    boolean isComplete();
+
+    /**
+     * Process the process stderr stream
+     *
+     * @param error the external process' standard error stream (available as an input to this class)
+     * @throws ProcessException if there is a problem processing the output
+     */
+    void processError(InputStream error) throws ProcessException;
+
+    /**
+     * Process the process stdout stream
+     *
+     * @param output the external process' output stream (available as an input to this class)
+     * @throws ProcessException if there is a problem processing the output
+     */
+    void processOutput(InputStream output) throws ProcessException;
+
+    /**
+     * Provide input to the external process. Input is provided by writing the content to the
+     * given output stream. This method will only be called if hasInput() returns true
+     *
+     * @param input the output stream representing standard input to the external process
+     * @throws IllegalStateException if no input has been configured.
+     */
+    void provideInput(OutputStream input);
+
+    /**
+     * Called if the process is to be re-executed.
+     */
+    void reset();
+
+    /**
+     * Set the watchdog associated with this handler. The watchdog should be called at regular intervals
+     * to prevent the external process being terminated. Typically this is done in the IO handling methods
+     *
+     * @param watchdog the watchdog for the process
+     */
+    void setWatchdog(Watchdog watchdog);
+
+    /**
+     * Indicate if the process execution has been considered successful.
+     *
+     * @return true if the process execution completed without error
+     */
+    boolean succeeded();
 }
 

File src/main/java/com/atlassian/utils/process/StringProcessHandler.java

 package com.atlassian.utils.process;
 
 /**
- * A ProcessHandler implementation which collects process output into strings and, optionally,
+ * A {@link ProcessHandler} implementation which collects process output into strings and, optionally,
  * provides input from a string.
  */
 public class StringProcessHandler extends PluggableProcessHandler {