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}