View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   https://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.commons.exec;
21  
22  import java.time.Duration;
23  import java.time.Instant;
24  
25  /**
26   * A default implementation of 'ExecuteResultHandler' used for asynchronous process handling.
27   */
28  public class DefaultExecuteResultHandler implements ExecuteResultHandler {
29  
30      /** The interval polling the result. */
31      private static final int SLEEP_TIME_MS = 50;
32  
33      /** Keep track if the process is still running. */
34      private volatile boolean hasResult;
35  
36      /** The exit value of the finished process. */
37      private volatile int exitValue;
38  
39      /** Any offending exception. */
40      private volatile ExecuteException exception;
41  
42      /**
43       * Constructs a new instance.
44       */
45      public DefaultExecuteResultHandler() {
46          this.hasResult = false;
47          this.exitValue = Executor.INVALID_EXITVALUE;
48      }
49  
50      /**
51       * Gets the {@code exception} causing the process execution to fail.
52       *
53       * @return the exception.
54       * @throws IllegalStateException if the process has not exited yet.
55       */
56      public ExecuteException getException() {
57          if (!hasResult) {
58              throw new IllegalStateException("The process has not exited yet therefore no result is available ...");
59          }
60          return exception;
61      }
62  
63      /**
64       * Gets the {@code exitValue} of the process.
65       *
66       * @return the exitValue.
67       * @throws IllegalStateException if the process has not exited yet.
68       */
69      public int getExitValue() {
70          if (!hasResult) {
71              throw new IllegalStateException("The process has not exited yet therefore no result is available ...");
72          }
73          return exitValue;
74      }
75  
76      /**
77       * Tests whether the process exited and a result is available, i.e. exitCode or exception?
78       *
79       * @return true whether a result of the execution is available.
80       */
81      public boolean hasResult() {
82          return hasResult;
83      }
84  
85      /**
86       * @see org.apache.commons.exec.ExecuteResultHandler#onProcessComplete(int)
87       */
88      @Override
89      public void onProcessComplete(final int exitValue) {
90          this.exitValue = exitValue;
91          this.exception = null;
92          this.hasResult = true;
93      }
94  
95      /**
96       * @see org.apache.commons.exec.ExecuteResultHandler#onProcessFailed(org.apache.commons.exec.ExecuteException)
97       */
98      @Override
99      public void onProcessFailed(final ExecuteException e) {
100         this.exitValue = e.getExitValue();
101         this.exception = e;
102         this.hasResult = true;
103     }
104 
105     /**
106      * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated.
107      * If the process has not yet terminated, the calling thread will be blocked until the process exits.
108      *
109      * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is
110      *                              ended and an {@link InterruptedException} is thrown.
111      */
112     public void waitFor() throws InterruptedException {
113         while (!hasResult()) {
114             Thread.sleep(SLEEP_TIME_MS);
115         }
116     }
117 
118     /**
119      * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated.
120      * If the process has not yet terminated, the calling thread will be blocked until the process exits.
121      *
122      * @param timeout the maximum time to wait.
123      * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is
124      *                              ended and an {@link InterruptedException} is thrown.
125      * @since 1.4.0
126      */
127     public void waitFor(final Duration timeout) throws InterruptedException {
128         final Instant until = Instant.now().plus(timeout);
129         while (!hasResult() && Instant.now().isBefore(until)) {
130             Thread.sleep(SLEEP_TIME_MS);
131         }
132     }
133 
134     /**
135      * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated.
136      * If the process has not yet terminated, the calling thread will be blocked until the process exits.
137      *
138      * @param timeoutMillis the maximum time to wait in milliseconds.
139      * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is
140      *                              ended and an {@link InterruptedException} is thrown.
141      * @deprecated Use {@link #waitFor(Duration)}.
142      */
143     @Deprecated
144     public void waitFor(final long timeoutMillis) throws InterruptedException {
145         final long untilMillis = System.currentTimeMillis() + timeoutMillis;
146         while (!hasResult() && System.currentTimeMillis() < untilMillis) {
147             Thread.sleep(SLEEP_TIME_MS);
148         }
149     }
150 
151 }