001/* A Future implementation that just waits until its result value/exception is available.
002
003Copyright (c) 2014-2016 The Regents of the University of California; iSencia Belgium NV.
004All rights reserved.
005
006Permission is hereby granted, without written agreement and without
007license or royalty fees, to use, copy, modify, and distribute this
008software and its documentation for any purpose, provided that the above
009copyright notice and the following two paragraphs appear in all copies
010of this software.
011
012IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA LIABLE TO ANY PARTY
013FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
014ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
015THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
016SUCH DAMAGE.
017
018THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
019INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
020MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
021PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
022CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
023ENHANCEMENTS, OR MODIFICATIONS.
024
025PT_COPYRIGHT_VERSION_2
026COPYRIGHTENDKEY
027*/
028package org.ptolemy.commons;
029
030import java.io.Serializable;
031import java.util.concurrent.CancellationException;
032import java.util.concurrent.ExecutionException;
033import java.util.concurrent.Future;
034import java.util.concurrent.TimeUnit;
035import java.util.concurrent.TimeoutException;
036
037/**
038 * A Future implementation that just waits until its result value/exception is available.
039 *
040 * @author ErwinDL
041 * @version $Id$
042 * @since Ptolemy II 11.0
043 * @Pt.ProposedRating Yellow (ErwinDL)
044 * @Pt.AcceptedRating Yellow (ErwinDL)
045 */
046@SuppressWarnings("serial")
047public class FutureValue<V> implements Future<V>, Serializable {
048
049    /**
050     * Creates a future that will be waiting for its result.
051     */
052    public FutureValue() {
053    }
054
055    /**
056     * Creates a future that is immediately set with its result value.
057     * @param value the future's result
058     */
059    public FutureValue(V value) {
060        set(value);
061    }
062
063    @Override
064    public synchronized boolean isCancelled() {
065        return _state == CANCELLED;
066    }
067
068    @Override
069    public synchronized boolean isDone() {
070        return _completedOrCancelled();
071    }
072
073    /**
074     * @param mayInterruptIfRunning ignored in this simple value-based implementation
075     */
076    @Override
077    public boolean cancel(boolean mayInterruptIfRunning) {
078        synchronized (this) {
079            if (_completedOrCancelled()) {
080                return false;
081            }
082            _state = CANCELLED;
083            notifyAll();
084        }
085        _done();
086        return true;
087    }
088
089    @Override
090    public synchronized V get()
091            throws InterruptedException, ExecutionException {
092        _waitFor();
093        return _getResult();
094    }
095
096    @Override
097    public synchronized V get(long timeout, TimeUnit unit)
098            throws InterruptedException, ExecutionException, TimeoutException {
099        _waitFor(unit.toNanos(timeout));
100        return _getResult();
101    }
102
103    /**
104     * Sets the result of this Future to the given value unless this future has already been set or has been cancelled.
105     *
106     * @param v
107     *          the value
108     */
109    public void set(V v) {
110        _setCompleted(v);
111    }
112
113    /**
114     * Causes this future to report an <tt>ExecutionException</tt> with the given throwable as its cause,
115     * unless this Future has already been set or has been cancelled.
116     *
117     * @param t
118     *          the cause of failure
119     */
120    public void setException(Throwable t) {
121        _setFailed(t);
122    }
123
124    @Override
125    public String toString() {
126        if (!isDone()) {
127            return "waiting";
128        } else {
129            // FindBugs reports "toString method may return null".  So we return the empty string instead.
130            return _result != null ? _result.toString() : "" /*null*/;
131        }
132    }
133
134    // protected things
135
136    /**
137    * Protected method invoked when this task transitions to state <tt>isDone</tt> (whether normally or via cancellation).
138    *
139    * The default implementation does nothing. Subclasses may override this method to invoke completion callbacks or perform bookkeeping.
140    */
141    protected void _done() {
142    }
143
144    // private things
145
146    /** State value representing that future is still waiting for the result */
147    private static final int WAITING = 1;
148    /** State value representing that future has obtained its result */
149    private static final int COMPLETED = 2;
150    /** State value representing that future was cancelled */
151    private static final int CANCELLED = 4;
152
153    /** The result to return from get() */
154    private V _result;
155    /** The exception to throw from get() */
156    private Throwable _exception;
157    /** The current state of the future */
158    private int _state = WAITING;
159
160    /**
161     * Assumes that a lock is owned on this future instance!
162     * @return true if the state is COMPLETED or CANCELLED
163     */
164    private boolean _completedOrCancelled() {
165        return (_state & (COMPLETED | CANCELLED)) != 0;
166    }
167
168    /**
169     * Marks the future's underlying task as completed with the given result value.
170     *
171     * @param result
172     *          the result of a task.
173     */
174    private void _setCompleted(V result) {
175        synchronized (this) {
176            if (_completedOrCancelled()) {
177                return;
178            }
179            this._state = COMPLETED;
180            this._result = result;
181            notifyAll();
182        }
183
184        // invoking callbacks *after* setting future as completed and
185        // outside the synchronization block makes it safe to call
186        // interrupt() from within callback code (in which case it will be
187        // ignored rather than cause deadlock / illegal state exception)
188        _done();
189    }
190
191    /**
192     * Marks the future's underlying task as failed, with the given exception as failure cause.
193     *
194     * @param exception
195     *          the cause of the task failure.
196     */
197    private void _setFailed(Throwable exception) {
198        synchronized (this) {
199            if (_completedOrCancelled()) {
200                return;
201            }
202            this._state = COMPLETED;
203            this._exception = exception;
204            notifyAll();
205        }
206
207        // invoking callbacks *after* setting future as completed and
208        // outside the synchronization block makes it safe to call
209        // interrupt() from within callback code (in which case it will be
210        // ignored rather than cause deadlock / illegal state exception)
211        _done();
212    }
213
214    /**
215     * Waits for the task to complete.
216     * Assumes that a lock is owned on this future instance!
217     */
218    private void _waitFor() throws InterruptedException {
219        while (!isDone()) {
220            wait();
221        }
222    }
223
224    /**
225     * Waits for the task to complete for timeout nanoseconds or throw TimeoutException if still not completed after that
226     * Assumes that a lock is owned on this future instance!
227     */
228    private void _waitFor(long nanos)
229            throws InterruptedException, TimeoutException {
230        if (nanos < 0) {
231            throw new IllegalArgumentException();
232        }
233        if (isDone()) {
234            return;
235        }
236        long deadline = System.nanoTime() + nanos;
237        while (nanos > 0) {
238            TimeUnit.NANOSECONDS.timedWait(this, nanos);
239            if (isDone()) {
240                return;
241            }
242            nanos = deadline - System.nanoTime();
243        }
244        throw new TimeoutException();
245    }
246
247    /**
248     * Gets the result of the future's underlying task.
249     *
250     * Assumes that a lock is owned on this future instance!
251     */
252    private V _getResult() throws ExecutionException {
253        if (_state == CANCELLED) {
254            throw new CancellationException();
255        }
256        if (_exception != null) {
257            throw new ExecutionException(_exception);
258        }
259        return _result;
260    }
261}