Mercurial > hg > blitz_stable
comparison src/EDU/oswego/cs/dl/util/concurrent/misc/SwingWorker.java @ 0:3dc0c5604566
Initial checkin of blitz 2.0 fcs - no installer yet.
author | Dan Creswell <dan.creswell@gmail.com> |
---|---|
date | Sat, 21 Mar 2009 11:00:06 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:3dc0c5604566 |
---|---|
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 } |