Code - Class EDU.oswego.cs.dl.util.concurrent.misc.SwingWorker


1 /*
2   File: SwingWorker.java
3
4   Originally written by Joseph Bowbeer and released into the public domain.
5   This may be used for any purposes whatsoever without acknowledgment.
6  
7   Originally part of jozart.swingutils.
8   Adapted for util.concurrent by Joseph Bowbeer.
9
10 */

11
12 package EDU.oswego.cs.dl.util.concurrent.misc;
13
14 import java.lang.reflect.InvocationTargetException;
15 import javax.swing.SwingUtilities;
16
17 import EDU.oswego.cs.dl.util.concurrent.*;
18
19 /**
20  * An abstract class that you subclass to perform GUI-related work
21  * in a dedicated thread.
22  * <p>
23  * This class was adapted from the SwingWorker written by Hans Muller
24  * and presented in "Using a Swing Worker Thread" in the Swing Connection
25  * - http://java.sun.com/products/jfc/tsc/articles/threads/threads2.html
26  * <p>
27  * A closely related version of this class is described in
28  * "The Last Word in Swing Threads" in the Swing Connection
29  * - http://java.sun.com/products/jfc/tsc/articles/threads/threads3.html
30  * <p>
31  * This SwingWorker is a ThreadFactoryUser and implements Runnable. The
32  * default thread factory creates low-priority worker threads. A special
33  * constructor is provided for enabling a timeout. When the timeout
34  * expires, the worker thread is interrupted.
35  * <p>
36  * Note: Using a timeout of <code>Long.MAX_VALUE</code> will not impose a
37  * timeout but will create an additional thread of control that will respond
38  * to an interrupt even if the <code>construct</code> implementation ignores
39  * them.
40  * <p>
41  * <b>Sample Usage</b> <p>
42  * <pre>
43  * import EDU.oswego.cs.dl.util.concurrent.TimeoutException;
44  * import EDU.oswego.cs.dl.util.concurrent.misc.SwingWorker;
45  *
46  * public class SwingWorkerDemo extends javax.swing.JApplet {
47  *
48  * private static final int TIMEOUT = 5000; // 5 seconds
49  * private javax.swing.JLabel status;
50  * private javax.swing.JButton start;
51  * private SwingWorker worker;
52  *
53  * public SwingWorkerDemo() {
54  * status = new javax.swing.JLabel("Ready");
55  * status.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
56  * getContentPane().add(status, java.awt.BorderLayout.CENTER);
57  * start = new javax.swing.JButton("Start");
58  * getContentPane().add(start, java.awt.BorderLayout.SOUTH);
59  *
60  * start.addActionListener(new java.awt.event.ActionListener() {
61  * public void actionPerformed(java.awt.event.ActionEvent evt) {
62  * if (start.getText().equals("Start")) {
63  * start.setText("Stop");
64  * status.setText("Working...");
65  * worker = new DemoSwingWorker(TIMEOUT);
66  * worker.start();
67  * } else {
68  * worker.interrupt();
69  * }
70  * }
71  * });
72  * }
73  *
74  * private class DemoSwingWorker extends SwingWorker {
75  * private static final java.util.Random RAND = new java.util.Random();
76  * public DemoSwingWorker(long msecs) {
77  * super(msecs);
78  * }
79  * protected Object construct() throws InterruptedException {
80  * // Take a random nap. If we oversleep, the worker times out.
81  * Thread.sleep(RAND.nextInt(2*TIMEOUT));
82  * return "Success";
83  * }
84  * protected void finished() {
85  * start.setText("Start");
86  * try {
87  * Object result = get();
88  * status.setText((String) result);
89  * }
90  * catch (java.lang.reflect.InvocationTargetException e) {
91  * Throwable ex = e.getTargetException();
92  * if (ex instanceof TimeoutException) {
93  * status.setText("Timed out.");
94  * } else if (ex instanceof InterruptedException) {
95  * status.setText("Interrupted.");
96  * } else {
97  * status.setText("Exception: " + ex);
98  * }
99  * }
100  * catch (InterruptedException ex) {
101  * // event-dispatch thread won't be interrupted
102  * throw new IllegalStateException(ex+"");
103  * }
104  * }
105  * }
106  * }
107  * </pre>
108  *
109  * @author Joseph Bowbeer
110  * @author Hans Muller
111  * @version 3.0
112  *
113  * <p>[<a HREF="http://gee.cs.oswego.edu/dl/classes/EDU/oswego/cs/dl/util/concurrent/intro.html"> Introduction to this package. </a>]
114  */

115 public abstract class SwingWorker extends ThreadFactoryUser
116 implements Runnable {
117
118     /** Default thread factory. Creates low priority worker threads. */
119     private static final ThreadFactory FACTORY = new ThreadFactory() {
120         public Thread newThread(Runnable command) {
121             Thread t = new Thread(command);
122             t.setPriority(Thread.MIN_PRIORITY+1);
123             return t;
124         }
125     };
126
127     /** Holds the value to be returned by the <code>get</code> method. */
128     private final FutureResult result = new FutureResult();
129
130     /** Maximum time to wait for worker to complete. */
131     private final long timeout;
132     
133     /** Worker thread. */
134     private Thread thread;
135
136     /** Creates new SwingWorker with no timeout. */
137     public SwingWorker() {
138         this(FACTORY, 0);
139     }
140     
141     /**
142      * Creates new SwingWorker with specified timeout.
143      * @param msecs timeout in milliseconds, or <code>0</code>
144      * for no time limit.
145      */

146     public SwingWorker(long msecs) {
147         this(FACTORY, msecs);
148     }
149     
150     /**
151      * Creates new SwingWorker with specified thread factory and timeout.
152      * @param factory factory for worker threads.
153      * @param msecs timeout in milliseconds, or <code>0</code>
154      * for no time limit.
155      */

156     protected SwingWorker(ThreadFactory factory, long msecs) {
157         setThreadFactory(factory);
158         if (msecs < 0) {
159             throw new IllegalArgumentException("timeout="+msecs);
160         }
161         timeout = msecs;
162     }
163
164     /**
165      * Computes the value to be returned by the <code>get</code> method.
166      */

167     protected abstract Object construct() throws Exception;
168
169     /**
170      * Called on the event dispatching thread (not on the worker thread)
171      * after the <code>construct</code> method has returned.
172      */

173     protected void finished() { }
174
175     /**
176      * Returns timeout period in milliseconds. Timeout is the
177      * maximum time to wait for worker to complete. There is
178      * no time limit if timeout is <code>0</code> (default).
179      */

180     public long getTimeout() {
181         return timeout;
182     }
183
184     /**
185      * Calls the <code>construct</code> method to compute the result,
186      * and then invokes the <code>finished</code> method on the event
187      * dispatch thread.
188      */

189     public void run() {
190
191         Callable function = new Callable() {
192             public Object call() throws Exception {
193                 return construct();
194             }
195         };
196
197         Runnable doFinished = new Runnable() {
198             public void run() {
199                 finished();
200             }
201         };
202
203         /* Convert to TimedCallable if timeout is specified. */
204         long msecs = getTimeout();
205         if (msecs != 0) {
206             TimedCallable tc = new TimedCallable(function, msecs);
207             tc.setThreadFactory(getThreadFactory());
208             function = tc;
209         }
210
211         result.setter(function).run();
212         SwingUtilities.invokeLater(doFinished);
213     }
214
215     /**
216      * Starts the worker thread.
217      */

218     public synchronized void start() {
219         if (thread == null) {
220             thread = getThreadFactory().newThread(this);
221         }
222         thread.start();
223     }
224
225     /**
226      * Stops the worker and sets the exception to InterruptedException.
227      */

228     public synchronized void interrupt() {
229         if (thread != null) {
230             /* Try-catch is workaround for JDK1.2 applet security bug.
231                On some platforms, a security exception is thrown if an
232                applet interrupts a thread that is no longer alive. */

233             try { thread.interrupt(); } catch (Exception ex) { }
234         }
235         result.setException(new InterruptedException());
236     }
237
238     /**
239      * Return the value created by the <code>construct</code> method,
240      * waiting if necessary until it is ready.
241      *
242      * @return the value created by the <code>construct</code> method
243      * @exception InterruptedException if current thread was interrupted
244      * @exception InvocationTargetException if the constructing thread
245      * encountered an exception or was interrupted.
246      */

247     public Object get()
248     throws InterruptedException, InvocationTargetException {
249         return result.get();
250     }
251
252     /**
253      * Wait at most msecs to access the constructed result.
254      * @return current value
255      * @exception TimeoutException if not ready after msecs
256      * @exception InterruptedException if current thread has been interrupted
257      * @exception InvocationTargetException if the constructing thread
258      * encountered an exception or was interrupted.
259      */

260     public Object timedGet(long msecs)
261     throws TimeoutException, InterruptedException, InvocationTargetException {
262         return result.timedGet(msecs);
263     }
264
265     /**
266      * Get the exception, or null if there isn't one (yet).
267      * This does not wait until the worker is ready, so should
268      * ordinarily only be called if you know it is.
269      * @return the exception encountered by the <code>construct</code>
270      * method wrapped in an InvocationTargetException
271      */

272     public InvocationTargetException getException() {
273         return result.getException();
274     }
275
276     /**
277      * Return whether the <code>get</code> method is ready to
278      * return a value.
279      *
280      * @return true if a value or exception has been set. else false
281      */

282     public boolean isReady() {
283         return result.isReady();
284     }
285
286 }
287

Java API By Example, From Geeks To Geeks. | Conditions of Use | About Us © 2002 - 2005, KickJava.com, or its affiliates