| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * https://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package org.apache.commons.exec; |
| |
| import java.time.Duration; |
| import java.time.Instant; |
| |
| /** |
| * A default implementation of 'ExecuteResultHandler' used for asynchronous process handling. |
| */ |
| public class DefaultExecuteResultHandler implements ExecuteResultHandler { |
| |
| /** The interval polling the result. */ |
| private static final int SLEEP_TIME_MS = 50; |
| |
| /** Keep track if the process is still running. */ |
| private volatile boolean hasResult; |
| |
| /** The exit value of the finished process. */ |
| private volatile int exitValue; |
| |
| /** Any offending exception. */ |
| private volatile ExecuteException exception; |
| |
| /** |
| * Constructs a new instance. |
| */ |
| public DefaultExecuteResultHandler() { |
| this.hasResult = false; |
| this.exitValue = Executor.INVALID_EXITVALUE; |
| } |
| |
| /** |
| * Gets the {@code exception} causing the process execution to fail. |
| * |
| * @return the exception. |
| * @throws IllegalStateException if the process has not exited yet. |
| */ |
| public ExecuteException getException() { |
| if (!hasResult) { |
| throw new IllegalStateException("The process has not exited yet therefore no result is available ..."); |
| } |
| return exception; |
| } |
| |
| /** |
| * Gets the {@code exitValue} of the process. |
| * |
| * @return the exitValue. |
| * @throws IllegalStateException if the process has not exited yet. |
| */ |
| public int getExitValue() { |
| if (!hasResult) { |
| throw new IllegalStateException("The process has not exited yet therefore no result is available ..."); |
| } |
| return exitValue; |
| } |
| |
| /** |
| * Tests whether the process exited and a result is available, i.e. exitCode or exception? |
| * |
| * @return true whether a result of the execution is available. |
| */ |
| public boolean hasResult() { |
| return hasResult; |
| } |
| |
| /** |
| * @see org.apache.commons.exec.ExecuteResultHandler#onProcessComplete(int) |
| */ |
| @Override |
| public void onProcessComplete(final int exitValue) { |
| this.exitValue = exitValue; |
| this.exception = null; |
| this.hasResult = true; |
| } |
| |
| /** |
| * @see org.apache.commons.exec.ExecuteResultHandler#onProcessFailed(org.apache.commons.exec.ExecuteException) |
| */ |
| @Override |
| public void onProcessFailed(final ExecuteException e) { |
| this.exitValue = e.getExitValue(); |
| this.exception = e; |
| this.hasResult = true; |
| } |
| |
| /** |
| * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated. |
| * If the process has not yet terminated, the calling thread will be blocked until the process exits. |
| * |
| * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is |
| * ended and an {@link InterruptedException} is thrown. |
| */ |
| public void waitFor() throws InterruptedException { |
| while (!hasResult()) { |
| Thread.sleep(SLEEP_TIME_MS); |
| } |
| } |
| |
| /** |
| * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated. |
| * If the process has not yet terminated, the calling thread will be blocked until the process exits. |
| * |
| * @param timeout the maximum time to wait. |
| * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is |
| * ended and an {@link InterruptedException} is thrown. |
| * @since 1.4.0 |
| */ |
| public void waitFor(final Duration timeout) throws InterruptedException { |
| final Instant until = Instant.now().plus(timeout); |
| while (!hasResult() && Instant.now().isBefore(until)) { |
| Thread.sleep(SLEEP_TIME_MS); |
| } |
| } |
| |
| /** |
| * Causes the current thread to wait, if necessary, until the process has terminated. This method returns immediately if the process has already terminated. |
| * If the process has not yet terminated, the calling thread will be blocked until the process exits. |
| * |
| * @param timeoutMillis the maximum time to wait in milliseconds. |
| * @throws InterruptedException if the current thread is {@linkplain Thread#interrupt() interrupted} by another thread while it is waiting, then the wait is |
| * ended and an {@link InterruptedException} is thrown. |
| * @deprecated Use {@link #waitFor(Duration)}. |
| */ |
| @Deprecated |
| public void waitFor(final long timeoutMillis) throws InterruptedException { |
| final long untilMillis = System.currentTimeMillis() + timeoutMillis; |
| while (!hasResult() && System.currentTimeMillis() < untilMillis) { |
| Thread.sleep(SLEEP_TIME_MS); |
| } |
| } |
| |
| } |