001: /*
002: File: FutureResult.java
003:
004: Originally written by Doug Lea and released into the public domain.
005: This may be used for any purposes whatsoever without acknowledgment.
006: Thanks for the assistance and support of Sun Microsystems Labs,
007: and everyone contributing, testing, and using this code.
008:
009: History:
010: Date Who What
011: 30Jun1998 dl Create public version
012: */
013:
014: package org.logicalcobwebs.concurrent;
015:
016: import java.lang.reflect.InvocationTargetException;
017:
018: /**
019: * A class maintaining a single reference variable serving as the result
020: * of an operation. The result cannot be accessed until it has been set.
021: * <p>
022: * <b>Sample Usage</b> <p>
023: * <pre>
024: * class ImageRenderer { Image render(byte[] raw); }
025: * class App {
026: * Executor executor = ...
027: * ImageRenderer renderer = ...
028: * void display(byte[] rawimage) {
029: * try {
030: * FutureResult futureImage = new FutureResult();
031: * Runnable command = futureImage.setter(new Callable() {
032: * public Object call() { return renderer.render(rawImage); }
033: * });
034: * executor.execute(command);
035: * drawBorders(); // do other things while executing
036: * drawCaption();
037: * drawImage((Image)(futureImage.get())); // use future
038: * }
039: * catch (InterruptedException ex) { return; }
040: * catch (InvocationTargetException ex) { cleanup(); return; }
041: * }
042: * }
043: * </pre>
044: * <p>[<a href="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
045: * @see Executor
046: **/
047:
048: public class FutureResult {
049: /** The result of the operation **/
050: protected Object value_ = null;
051:
052: /** Status -- true after first set **/
053: protected boolean ready_ = false;
054:
055: /** the exception encountered by operation producing result **/
056: protected InvocationTargetException exception_ = null;
057:
058: /**
059: * Create an initially unset FutureResult
060: **/
061: public FutureResult() {
062: }
063:
064: /**
065: * Return a Runnable object that, when run, will set the result value.
066: * @param function - a Callable object whose result will be
067: * held by this FutureResult.
068: * @return A Runnable object that, when run, will call the
069: * function and (eventually) set the result.
070: **/
071:
072: public Runnable setter(final Callable function) {
073: return new Runnable() {
074: public void run() {
075: try {
076: set(function.call());
077: } catch (Throwable ex) {
078: setException(ex);
079: }
080: }
081: };
082: }
083:
084: /** internal utility: either get the value or throw the exception **/
085: protected Object doGet() throws InvocationTargetException {
086: if (exception_ != null)
087: throw exception_;
088: else
089: return value_;
090: }
091:
092: /**
093: * Access the reference, waiting if necessary until it is ready.
094: * @return current value
095: * @exception InterruptedException if current thread has been interrupted
096: * @exception InvocationTargetException if the operation
097: * producing the value encountered an exception.
098: **/
099: public synchronized Object get() throws InterruptedException,
100: InvocationTargetException {
101: while (!ready_)
102: wait();
103: return doGet();
104: }
105:
106: /**
107: * Wait at most msecs to access the reference.
108: * @return current value
109: * @exception TimeoutException if not ready after msecs
110: * @exception InterruptedException if current thread has been interrupted
111: * @exception InvocationTargetException if the operation
112: * producing the value encountered an exception.
113: **/
114: public synchronized Object timedGet(long msecs)
115: throws TimeoutException, InterruptedException,
116: InvocationTargetException {
117: long startTime = (msecs <= 0) ? 0 : System.currentTimeMillis();
118: long waitTime = msecs;
119: if (ready_)
120: return doGet();
121: else if (waitTime <= 0)
122: throw new TimeoutException(msecs);
123: else {
124: for (;;) {
125: wait(waitTime);
126: if (ready_)
127: return doGet();
128: else {
129: waitTime = msecs
130: - (System.currentTimeMillis() - startTime);
131: if (waitTime <= 0)
132: throw new TimeoutException(msecs);
133: }
134: }
135: }
136: }
137:
138: /**
139: * Set the reference, and signal that it is ready. It is not
140: * considered an error to set the value more than once,
141: * but it is not something you would normally want to do.
142: * @param newValue The value that will be returned by a subsequent get();
143: **/
144: public synchronized void set(Object newValue) {
145: value_ = newValue;
146: ready_ = true;
147: notifyAll();
148: }
149:
150: /**
151: * Set the exception field, also setting ready status.
152: * @param ex The exception. It will be reported out wrapped
153: * within an InvocationTargetException
154: **/
155: public synchronized void setException(Throwable ex) {
156: exception_ = new InvocationTargetException(ex);
157: ready_ = true;
158: notifyAll();
159: }
160:
161: /**
162: * Get the exception, or null if there isn't one (yet).
163: * This does not wait until the future is ready, so should
164: * ordinarily only be called if you know it is.
165: * @return the exception encountered by the operation
166: * setting the future, wrapped in an InvocationTargetException
167: **/
168: public synchronized InvocationTargetException getException() {
169: return exception_;
170: }
171:
172: /**
173: * Return whether the reference or exception have been set.
174: * @return true if has been set. else false
175: **/
176: public synchronized boolean isReady() {
177: return ready_;
178: }
179:
180: /**
181: * Access the reference, even if not ready
182: * @return current value
183: **/
184: public synchronized Object peek() {
185: return value_;
186: }
187:
188: /**
189: * Clear the value and exception and set to not-ready,
190: * allowing this FutureResult to be reused. This is not
191: * particularly recommended and must be done only
192: * when you know that no other object is depending on the
193: * properties of this FutureResult.
194: **/
195: public synchronized void clear() {
196: value_ = null;
197: exception_ = null;
198: ready_ = false;
199: }
200:
201: }
|