DefaultExecuteResultHandler.java

  1. /*
  2.  * Licensed to the Apache Software Foundation (ASF) under one or more
  3.  *  contributor license agreements.  See the NOTICE file distributed with
  4.  *  this work for additional information regarding copyright ownership.
  5.  *  The ASF licenses this file to You under the Apache License, Version 2.0
  6.  *  (the "License"); you may not use this file except in compliance with
  7.  *  the License.  You may obtain a copy of the License at
  8.  *
  9.  *      https://www.apache.org/licenses/LICENSE-2.0
  10.  *
  11.  *  Unless required by applicable law or agreed to in writing, software
  12.  *  distributed under the License is distributed on an "AS IS" BASIS,
  13.  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14.  *  See the License for the specific language governing permissions and
  15.  *  limitations under the License.
  16.  */

  17. package org.apache.commons.exec;

  18. import java.time.Duration;
  19. import java.time.Instant;

  20. /**
  21.  * A default implementation of 'ExecuteResultHandler' used for asynchronous process handling.
  22.  */
  23. public class DefaultExecuteResultHandler implements ExecuteResultHandler {

  24.     /** The interval polling the result. */
  25.     private static final int SLEEP_TIME_MS = 50;

  26.     /** Keep track if the process is still running. */
  27.     private volatile boolean hasResult;

  28.     /** The exit value of the finished process. */
  29.     private volatile int exitValue;

  30.     /** Any offending exception. */
  31.     private volatile ExecuteException exception;

  32.     /**
  33.      * Constructs a new instance.
  34.      */
  35.     public DefaultExecuteResultHandler() {
  36.         this.hasResult = false;
  37.         this.exitValue = Executor.INVALID_EXITVALUE;
  38.     }

  39.     /**
  40.      * Gets the {@code exception} causing the process execution to fail.
  41.      *
  42.      * @return the exception.
  43.      * @throws IllegalStateException if the process has not exited yet.
  44.      */
  45.     public ExecuteException getException() {
  46.         if (!hasResult) {
  47.             throw new IllegalStateException("The process has not exited yet therefore no result is available ...");
  48.         }
  49.         return exception;
  50.     }

  51.     /**
  52.      * Gets the {@code exitValue} of the process.
  53.      *
  54.      * @return the exitValue.
  55.      * @throws IllegalStateException if the process has not exited yet.
  56.      */
  57.     public int getExitValue() {
  58.         if (!hasResult) {
  59.             throw new IllegalStateException("The process has not exited yet therefore no result is available ...");
  60.         }
  61.         return exitValue;
  62.     }

  63.     /**
  64.      * Tests whether the process exited and a result is available, i.e. exitCode or exception?
  65.      *
  66.      * @return true whether a result of the execution is available.
  67.      */
  68.     public boolean hasResult() {
  69.         return hasResult;
  70.     }

  71.     /**
  72.      * @see org.apache.commons.exec.ExecuteResultHandler#onProcessComplete(int)
  73.      */
  74.     @Override
  75.     public void onProcessComplete(final int exitValue) {
  76.         this.exitValue = exitValue;
  77.         this.exception = null;
  78.         this.hasResult = true;
  79.     }

  80.     /**
  81.      * @see org.apache.commons.exec.ExecuteResultHandler#onProcessFailed(org.apache.commons.exec.ExecuteException)
  82.      */
  83.     @Override
  84.     public void onProcessFailed(final ExecuteException e) {
  85.         this.exitValue = e.getExitValue();
  86.         this.exception = e;
  87.         this.hasResult = true;
  88.     }

  89.     /**
  90.      * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated.
  91.      * If the process has not yet terminated, the calling thread will be blocked until the process exits.
  92.      *
  93.      * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is
  94.      *                              ended and an {@link InterruptedException} is thrown.
  95.      */
  96.     public void waitFor() throws InterruptedException {
  97.         while (!hasResult()) {
  98.             Thread.sleep(SLEEP_TIME_MS);
  99.         }
  100.     }

  101.     /**
  102.      * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated.
  103.      * If the process has not yet terminated, the calling thread will be blocked until the process exits.
  104.      *
  105.      * @param timeout the maximum time to wait.
  106.      * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is
  107.      *                              ended and an {@link InterruptedException} is thrown.
  108.      * @since 1.4.0
  109.      */
  110.     public void waitFor(final Duration timeout) throws InterruptedException {
  111.         final Instant until = Instant.now().plus(timeout);
  112.         while (!hasResult() && Instant.now().isBefore(until)) {
  113.             Thread.sleep(SLEEP_TIME_MS);
  114.         }
  115.     }

  116.     /**
  117.      * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated.
  118.      * If the process has not yet terminated, the calling thread will be blocked until the process exits.
  119.      *
  120.      * @param timeoutMillis the maximum time to wait in milliseconds.
  121.      * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is
  122.      *                              ended and an {@link InterruptedException} is thrown.
  123.      * @deprecated Use {@link #waitFor(Duration)}.
  124.      */
  125.     @Deprecated
  126.     public void waitFor(final long timeoutMillis) throws InterruptedException {
  127.         final long untilMillis = System.currentTimeMillis() + timeoutMillis;
  128.         while (!hasResult() && System.currentTimeMillis() < untilMillis) {
  129.             Thread.sleep(SLEEP_TIME_MS);
  130.         }
  131.     }

  132. }