Source code: com/virtuosotechnologies/lib/asyncjob/AbstractAsyncJobRunner.java
1 /*
2 ================================================================================
3
4 FILE: AbstractAsyncJobRunner.java
5
6 PROJECT:
7
8 Virtuoso Utilities
9
10 CONTENTS:
11
12 Abstract base class for AsyncJobRunner
13
14 PROGRAMMERS:
15
16 Daniel Azuma (DA) <dazuma@kagi.com>
17
18 COPYRIGHT:
19
20 Copyright (C) 2003 Daniel Azuma (dazuma@kagi.com)
21
22 This program is free software; you can redistribute it and/or
23 modify it under the terms of the GNU General Public License as
24 published by the Free Software Foundation; either version 2
25 of the License, or (at your option) any later version.
26
27 This program is distributed in the hope that it will be useful,
28 but WITHOUT ANY WARRANTY; without even the implied warranty of
29 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 GNU General Public License for more details.
31
32 You should have received a copy of the GNU General Public
33 License along with this program; if not, write to
34 Free Software Foundation, Inc.
35 59 Temple Place, Suite 330
36 Boston, MA 02111-1307 USA
37
38 ================================================================================
39 */
40
41
42 package com.virtuosotechnologies.lib.asyncjob;
43
44
45 import com.virtuosotechnologies.lib.util.EventBroadcastHelper;
46
47
48 /**
49 * Abstract base class for AsyncJobRunner
50 */
51 public abstract class AbstractAsyncJobRunner
52 implements AsyncJobRunner
53 {
54 private EventBroadcastHelper broadcaster_;
55
56
57 /**
58 * Constructor
59 */
60 protected AbstractAsyncJobRunner()
61 {
62 broadcaster_ = new EventBroadcastHelper(AsyncJobListener.class);
63 }
64
65
66 /**
67 * Add a job listener.
68 *
69 * @param listener listener to add
70 */
71 public void addAsyncJobListener(
72 AsyncJobListener listener)
73 {
74 broadcaster_.addListenerWeak(listener);
75 }
76
77
78 /**
79 * Remove a job listener.
80 *
81 * @param listener listener to remove
82 */
83 public void removeAsyncJobListener(
84 AsyncJobListener listener)
85 {
86 broadcaster_.removeListener(listener);
87 }
88
89
90 /**
91 * Run a job synchronously
92 *
93 * @param execution job to run
94 */
95 protected void runJobSynchronously(
96 final ExecutionImpl execution)
97 {
98 if (execution.isStarted())
99 {
100 throw new IllegalStateException("Can't reuse an ExecutionImpl.");
101 }
102 final AsyncJob job = execution.getAsyncJob();
103 AsyncJobStartedEvent sev = new AsyncJobStartedEvent(this, job, execution);
104 broadcaster_.fireEvent(AsyncJobListener.JOB_STARTED_METHOD, sev);
105 execution.start(sev);
106 try
107 {
108 Object result = job.run(
109 new AsyncJobProgressReporter()
110 {
111 public void updateProgress(
112 float fractionDone,
113 String progressString)
114 {
115 AsyncJobProgressEvent ev = new AsyncJobProgressEvent(
116 AbstractAsyncJobRunner.this, job,
117 fractionDone, progressString);
118 broadcaster_.fireEvent(
119 AsyncJobListener.JOB_PROGRESSED_METHOD, ev);
120 execution.update(ev);
121 }
122 });
123 AsyncJobCompletedEvent ev = new AsyncJobCompletedEvent(this, job, result);
124 broadcaster_.fireEvent(AsyncJobListener.JOB_COMPLETED_METHOD, ev);
125 execution.succeed(ev);
126 }
127 catch (AsyncJobException ex)
128 {
129 AsyncJobFailedEvent ev = new AsyncJobFailedEvent(this, job, ex);
130 broadcaster_.fireEvent(AsyncJobListener.JOB_FAILED_METHOD, ev);
131 execution.fail(ev);
132 }
133 catch (Throwable th)
134 {
135 AsyncJobException ex = new AsyncJobException(th);
136 AsyncJobFailedEvent ev = new AsyncJobFailedEvent(this, job, ex);
137 broadcaster_.fireEvent(AsyncJobListener.JOB_FAILED_METHOD, ev);
138 execution.fail(ev);
139 if (th instanceof Error || th instanceof RuntimeException)
140 {
141 th.printStackTrace();
142 }
143 }
144 }
145
146
147 /**
148 * Execution tracker implementation
149 */
150 protected class ExecutionImpl
151 implements AsyncJobExecution
152 {
153 private AsyncJob job_;
154 private EventBroadcastHelper broadcaster_;
155 private boolean started_;
156 private boolean finished_;
157 private Object result_;
158 private AsyncJobException exception_;
159
160
161 /**
162 * Subclass-visible constructor
163 */
164 protected ExecutionImpl(
165 AsyncJob job)
166 {
167 job_ = job;
168 broadcaster_ = new EventBroadcastHelper(AsyncJobListener.class);
169 finished_ = false;
170 result_ = null;
171 exception_ = null;
172 }
173
174
175 /**
176 * Get the runner running this job
177 *
178 * @return the AsyncJobRunner
179 */
180 public AsyncJobRunner getAsyncJobRunner()
181 {
182 return AbstractAsyncJobRunner.this;
183 }
184
185
186 /**
187 * Get the job being run
188 *
189 * @return the AsyncJob
190 */
191 public AsyncJob getAsyncJob()
192 {
193 return job_;
194 }
195
196
197 /**
198 * Wait until the job is finished.
199 *
200 * @return true if the job succeeded, false if it failed
201 */
202 public synchronized boolean waitForCompletion()
203 throws
204 InterruptedException
205 {
206 if (!finished_)
207 {
208 wait();
209 }
210 return exception_ == null;
211 }
212
213
214 /**
215 * Has the job started yet?
216 *
217 * @return true if the job has started
218 */
219 public boolean isStarted()
220 {
221 return started_;
222 }
223
224
225 /**
226 * Has the job finished yet?
227 *
228 * @return true if the job has finished
229 */
230 public synchronized boolean isFinished()
231 {
232 return finished_;
233 }
234
235
236 /**
237 * Get the job result value.
238 *
239 * @return the result value (which may be null) or null if the job is
240 * not finished or failed.
241 */
242 public synchronized Object getResult()
243 {
244 return result_;
245 }
246
247
248 /**
249 * Get the job failure exception.
250 *
251 * @return the exception with which the job failed, or null if the job is
252 * not finished or did not fail.
253 */
254 public synchronized AsyncJobException getException()
255 {
256 return exception_;
257 }
258
259
260 /**
261 * Add an execution listener.
262 *
263 * @param listener listener to add
264 */
265 public void addAsyncJobListener(
266 AsyncJobListener listener)
267 {
268 broadcaster_.addListenerWeak(listener);
269 }
270
271
272 /**
273 * Remove an execution listener.
274 *
275 * @param listener listener to remove
276 */
277 public void removeAsyncJobListener(
278 AsyncJobListener listener)
279 {
280 broadcaster_.removeListener(listener);
281 }
282
283
284 private void start(
285 AsyncJobStartedEvent ev)
286 {
287 synchronized(this)
288 {
289 started_ = true;
290 }
291 broadcaster_.fireEvent(AsyncJobListener.JOB_STARTED_METHOD, ev);
292 }
293
294
295 private void update(
296 AsyncJobProgressEvent ev)
297 {
298 broadcaster_.fireEvent(AsyncJobListener.JOB_PROGRESSED_METHOD, ev);
299 }
300
301
302 private void succeed(
303 AsyncJobCompletedEvent ev)
304 {
305 synchronized(this)
306 {
307 result_ = ev.getResult();
308 finished_ = true;
309 notifyAll();
310 }
311 broadcaster_.fireEvent(AsyncJobListener.JOB_COMPLETED_METHOD, ev);
312 }
313
314
315 private void fail(
316 AsyncJobFailedEvent ev)
317 {
318 synchronized(this)
319 {
320 result_ = ev.getException();
321 finished_ = true;
322 notifyAll();
323 }
324 broadcaster_.fireEvent(AsyncJobListener.JOB_FAILED_METHOD, ev);
325 }
326 }
327 }