001/* 
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 *  contributor license agreements.  See the NOTICE file distributed with
004 *  this work for additional information regarding copyright ownership.
005 *  The ASF licenses this file to You under the Apache License, Version 2.0
006 *  (the "License"); you may not use this file except in compliance with
007 *  the License.  You may obtain a copy of the License at
008 *
009 *      http://www.apache.org/licenses/LICENSE-2.0
010 *
011 *  Unless required by applicable law or agreed to in writing, software
012 *  distributed under the License is distributed on an "AS IS" BASIS,
013 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 *  See the License for the specific language governing permissions and
015 *  limitations under the License.
016 *
017 */
018
019package org.apache.commons.exec;
020
021/**
022 * A default implementation of 'ExecuteResultHandler' used for asynchronous
023 * process handling.
024 */
025public class DefaultExecuteResultHandler implements ExecuteResultHandler {
026
027    /** the interval polling the result */
028    private static final int SLEEP_TIME_MS = 50;
029
030    /** Keep track if the process is still running */
031    private volatile boolean hasResult;
032
033    /** The exit value of the finished process */
034    private volatile int exitValue;
035
036    /** Any offending exception */
037    private volatile ExecuteException exception;
038
039    /**
040     * Constructor.
041     */
042    public DefaultExecuteResultHandler() {
043        this.hasResult = false;
044        this.exitValue = Executor.INVALID_EXITVALUE;
045    }
046
047    /**
048     * @see org.apache.commons.exec.ExecuteResultHandler#onProcessComplete(int)
049     */
050    public void onProcessComplete(int exitValue) {
051        this.exitValue = exitValue;
052        this.exception = null;
053        this.hasResult = true;
054    }
055
056    /**
057     * @see org.apache.commons.exec.ExecuteResultHandler#onProcessFailed(org.apache.commons.exec.ExecuteException)
058     */
059    public void onProcessFailed(ExecuteException e) {
060        this.exitValue = e.getExitValue();            
061        this.exception = e;
062        this.hasResult = true;
063    }
064
065    /**
066     * Get the <code>exception<code> causing the process execution to fail.
067     *
068     * @return Returns the exception.
069     * @throws IllegalStateException if the process has not exited yet
070     */
071    public ExecuteException getException() {
072
073        if(!hasResult) {
074            throw new IllegalStateException("The process has not exited yet therefore no result is available ...");
075        }
076
077        return exception;
078    }
079
080    /**
081     * Get the <code>exitValue<code> of the process.
082     *
083     * @return Returns the exitValue.
084     * @throws IllegalStateException if the process has not exited yet
085     */
086    public int getExitValue() {
087
088        if(!hasResult) {
089            throw new IllegalStateException("The process has not exited yet therefore no result is available ...");
090        }
091
092        return exitValue;
093    }
094
095    /**
096     * Has the process exited and a result is available, i.e. exitCode or exception?
097     *
098     * @return true if a result of the execution is available
099     */
100    public boolean hasResult() {
101        return hasResult;
102    }
103
104    /**
105     * Causes the current thread to wait, if necessary, until the
106     * process has terminated. This method returns immediately if
107     * the process has already terminated. If the process has
108     * not yet terminated, the calling thread will be blocked until the
109     * process exits.
110     *
111     * @exception  InterruptedException if the current thread is
112     *             {@linkplain Thread#interrupt() interrupted} by another
113     *             thread while it is waiting, then the wait is ended and
114     *             an {@link InterruptedException} is thrown.
115     */
116    public void waitFor() throws InterruptedException {
117
118        while (!hasResult()) {
119            Thread.sleep(SLEEP_TIME_MS);
120        }
121    }
122
123    /**
124     * Causes the current thread to wait, if necessary, until the
125     * process has terminated. This method returns immediately if
126     * the process has already terminated. If the process has
127     * not yet terminated, the calling thread will be blocked until the
128     * process exits.
129     *
130     * @param timeout the maximum time to wait in milliseconds
131     * @exception  InterruptedException if the current thread is
132     *             {@linkplain Thread#interrupt() interrupted} by another
133     *             thread while it is waiting, then the wait is ended and
134     *             an {@link InterruptedException} is thrown.
135     */
136    public void waitFor(long timeout) throws InterruptedException {
137
138        long until = System.currentTimeMillis() + timeout;
139
140        while (!hasResult() && (System.currentTimeMillis() < until)) {
141            Thread.sleep(SLEEP_TIME_MS);
142        }
143    }
144}