View Javadoc
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    *      http://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  
18  package org.apache.commons.exec;
19  
20  import java.time.Duration;
21  import java.time.Instant;
22  
23  /**
24   * A default implementation of 'ExecuteResultHandler' used for asynchronous process handling.
25   */
26  public class DefaultExecuteResultHandler implements ExecuteResultHandler {
27  
28      /** The interval polling the result. */
29      private static final int SLEEP_TIME_MS = 50;
30  
31      /** Keep track if the process is still running. */
32      private volatile boolean hasResult;
33  
34      /** The exit value of the finished process. */
35      private volatile int exitValue;
36  
37      /** Any offending exception. */
38      private volatile ExecuteException exception;
39  
40      /**
41       * Constructs a new instance.
42       */
43      public DefaultExecuteResultHandler() {
44          this.hasResult = false;
45          this.exitValue = Executor.INVALID_EXITVALUE;
46      }
47  
48      /**
49       * Gets the {@code exception} causing the process execution to fail.
50       *
51       * @return the exception.
52       * @throws IllegalStateException if the process has not exited yet.
53       */
54      public ExecuteException getException() {
55          if (!hasResult) {
56              throw new IllegalStateException("The process has not exited yet therefore no result is available ...");
57          }
58          return exception;
59      }
60  
61      /**
62       * Gets the {@code exitValue} of the process.
63       *
64       * @return the exitValue.
65       * @throws IllegalStateException if the process has not exited yet.
66       */
67      public int getExitValue() {
68          if (!hasResult) {
69              throw new IllegalStateException("The process has not exited yet therefore no result is available ...");
70          }
71          return exitValue;
72      }
73  
74      /**
75       * Tests whether the process exited and a result is available, i.e. exitCode or exception?
76       *
77       * @return true whether a result of the execution is available.
78       */
79      public boolean hasResult() {
80          return hasResult;
81      }
82  
83      /**
84       * @see org.apache.commons.exec.ExecuteResultHandler#onProcessComplete(int)
85       */
86      @Override
87      public void onProcessComplete(final int exitValue) {
88          this.exitValue = exitValue;
89          this.exception = null;
90          this.hasResult = true;
91      }
92  
93      /**
94       * @see org.apache.commons.exec.ExecuteResultHandler#onProcessFailed(org.apache.commons.exec.ExecuteException)
95       */
96      @Override
97      public void onProcessFailed(final ExecuteException e) {
98          this.exitValue = e.getExitValue();
99          this.exception = e;
100         this.hasResult = true;
101     }
102 
103     /**
104      * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated.
105      * If the process has not yet terminated, the calling thread will be blocked until the process exits.
106      *
107      * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is
108      *                              ended and an {@link InterruptedException} is thrown.
109      */
110     public void waitFor() throws InterruptedException {
111         while (!hasResult()) {
112             Thread.sleep(SLEEP_TIME_MS);
113         }
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 timeout the maximum time to wait.
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      * @since 1.4.0
124      */
125     public void waitFor(final Duration timeout) throws InterruptedException {
126         final Instant until = Instant.now().plus(timeout);
127         while (!hasResult() && Instant.now().isBefore(until)) {
128             Thread.sleep(SLEEP_TIME_MS);
129         }
130     }
131 
132     /**
133      * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated.
134      * If the process has not yet terminated, the calling thread will be blocked until the process exits.
135      *
136      * @param timeoutMillis the maximum time to wait in milliseconds.
137      * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is
138      *                              ended and an {@link InterruptedException} is thrown.
139      * @deprecated Use {@link #waitFor(Duration)}.
140      */
141     @Deprecated
142     public void waitFor(final long timeoutMillis) throws InterruptedException {
143         final long untilMillis = System.currentTimeMillis() + timeoutMillis;
144         while (!hasResult() && System.currentTimeMillis() < untilMillis) {
145             Thread.sleep(SLEEP_TIME_MS);
146         }
147     }
148 
149 }