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    
019    package org.apache.commons.exec;
020    
021    /**
022     * A default implementation of 'ExecuteResultHandler' used for asynchronous
023     * process handling.
024     */
025    public 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    }