KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > Task


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.util;
20
21 import java.util.HashSet JavaDoc;
22 import java.util.Iterator JavaDoc;
23 import java.util.logging.Level JavaDoc;
24
25
26 /** A task that may be executed in a separate thread and permits examination of its status.
27 * Other threads can check if it is finished or wait for it
28 * to finish.
29 * <P>
30 * For example:
31 * <p><code><PRE>
32 * Runnable r = new Runnable () {
33 * public void run () {
34 * // do something
35 * }
36 * };
37 * Task task = new Task (r);
38 * RequestProcessor.postRequest (task);
39 * </PRE></code>
40 * <p>In a different thread one can then test <CODE>task.isFinished ()</CODE>
41 * or wait for it with <CODE>task.waitFinished ()</CODE>.
42 *
43 * @author Jaroslav Tulach
44 */

45 public class Task extends Object JavaDoc implements Runnable JavaDoc {
46     /** Dummy task which is already finished. */
47     public static final Task EMPTY = new Task();
48
49     static {
50         EMPTY.finished = true;
51     }
52
53     /** map of subclasses to booleans whether they override waitFinished() or not
54      */

55     private static java.util.WeakHashMap JavaDoc<Class JavaDoc, Boolean JavaDoc> overrides;
56
57     /** request processor for workarounding compatibility problem with
58      * classes that do not override waitFinished (long)
59      */

60     private static RequestProcessor RP;
61
62     /** what to run */
63     final Runnable JavaDoc run;
64
65     /** flag if we have finished */
66     private boolean finished;
67
68     /** listeners for the finish of task (TaskListener) */
69     private HashSet JavaDoc<TaskListener> list;
70
71     /** Create a new task.
72     * The runnable should provide its own error-handling, as
73     * by default thrown exceptions are simply logged and not rethrown.
74     * @param run runnable to run that computes the task
75     */

76     public Task(Runnable JavaDoc run) {
77         this.run = run;
78
79         if (run == null) {
80             finished = true;
81         }
82     }
83
84     /** Constructor for subclasses that wants to control whole execution
85     * itself.
86     * @since 1.5
87     */

88     protected Task() {
89         this.run = null;
90     }
91
92     /** Test whether the task has finished running.
93     * @return <code>true</code> if so
94     */

95     public final boolean isFinished() {
96         synchronized (this) {
97             return finished;
98         }
99     }
100
101     /** Wait until the task is finished.
102     * Changed not to be <code>final</code> in version 1.5
103     */

104     public void waitFinished() {
105         synchronized (this) {
106             while (!finished) {
107                 try {
108                     wait();
109                 } catch (InterruptedException JavaDoc ex) {
110                 }
111             }
112         }
113     }
114
115     /** Wait until the task is finished, but only a given time.
116     * @param milliseconds time in milliseconds to wait for the result
117     * @exception InterruptedException when the waiting has been interrupted
118     * @return true if the task is really finished, or false if the time out
119     * has been exceeded
120     * @since 5.0
121     */

122     public boolean waitFinished(long milliseconds) throws InterruptedException JavaDoc {
123         synchronized (this) {
124             if (overridesTimeoutedWaitFinished()) {
125                 // the the task overrides waitFinished (timeout) or is
126
// one of the basic tasks, then we can just simply do our bese
127
// code. Otherwise we have to execute threading workaround
128
if (finished) {
129                     return true;
130                 }
131
132                 long expectedEnd = System.currentTimeMillis() + milliseconds;
133
134                 for (;;) {
135                     wait(milliseconds);
136
137                     if (finished) {
138                         return true;
139                     }
140
141                     long now = System.currentTimeMillis();
142
143                     if (expectedEnd <= now) {
144                         return false;
145                     }
146
147                     milliseconds = expectedEnd - now;
148                 }
149             }
150         }
151
152         // as we know that RequestProcessor implements the waitFinished(long)
153
// correctly we just post a task for waitFinished() into some
154
// of its threads and wait just the given milliseconds time
155
// for the result, by that we can guarantee the semantics
156
// of the call
157
class Run implements Runnable JavaDoc {
158             public void run() {
159                 Task.this.waitFinished();
160             }
161         }
162
163         RequestProcessor.Task task = RP.post(new Run());
164
165         return task.waitFinished(milliseconds);
166     }
167
168     /** Changes the state of the task to be running. Any call after this
169     * one and before notifyFinished to waitFinished blocks.
170     * @since 1.5
171     */

172     protected final void notifyRunning() {
173         synchronized (this) {
174             if (RequestProcessor.logger().isLoggable(Level.FINE)) {
175                 RequestProcessor.logger().fine("notifyRunning: " + this); // NOI18N
176
}
177             this.finished = false;
178             notifyAll();
179         }
180     }
181
182     /** Notify all waiters that this task has finished.
183     * @see #run
184     */

185     protected final void notifyFinished() {
186         Iterator JavaDoc it;
187
188         synchronized (this) {
189             finished = true;
190             if (RequestProcessor.logger().isLoggable(Level.FINE)) {
191                 RequestProcessor.logger().fine("notifyFinished: " + this); // NOI18N
192
}
193             notifyAll();
194
195             // fire the listeners
196
if (list == null) {
197                 return;
198             }
199
200             it = ((HashSet JavaDoc) list.clone()).iterator();
201         }
202
203         while (it.hasNext()) {
204             TaskListener l = (TaskListener) it.next();
205             l.taskFinished(this);
206         }
207     }
208
209     /** Start the task.
210     * When it finishes (even with an exception) it calls
211     * {@link #notifyFinished}.
212     * Subclasses may override this method, but they
213     * then need to call {@link #notifyFinished} explicitly.
214     * <p>Note that this call runs synchronously, but typically the creator
215     * of the task will call this method in a separate thread.
216     */

217     public void run() {
218         try {
219             notifyRunning();
220
221             if (run != null) {
222                 run.run();
223             }
224         } finally {
225             notifyFinished();
226         }
227     }
228
229     /** Add a listener to the task.
230     * @param l the listener to add
231     */

232     public synchronized void addTaskListener(TaskListener l) {
233         if (list == null) {
234             list = new HashSet JavaDoc<TaskListener>();
235         }
236
237         list.add(l);
238
239         if (finished) {
240             l.taskFinished(this);
241         }
242     }
243
244     /** Remove a listener from the task.
245     * @param l the listener to remove
246     */

247     public synchronized void removeTaskListener(TaskListener l) {
248         if (list == null) {
249             return;
250         }
251
252         list.remove(l);
253     }
254
255     public String JavaDoc toString() {
256         return "task " + run; // NOI18N
257
}
258
259     /** Checks whether the class overrides wait finished.
260      */

261     private boolean overridesTimeoutedWaitFinished() {
262         // yes we implement it corretly
263
if (getClass() == Task.class) {
264             return true;
265         }
266
267         // RequestProcessor.Task overrides correctly
268
if (getClass() == RequestProcessor.Task.class) {
269             return true;
270         }
271
272         java.util.WeakHashMap JavaDoc<Class JavaDoc,Boolean JavaDoc> m;
273         Boolean JavaDoc does;
274
275         synchronized (Task.class) {
276             if (overrides == null) {
277                 overrides = new java.util.WeakHashMap JavaDoc<Class JavaDoc, Boolean JavaDoc>();
278                 RP = new RequestProcessor("Timeout waitFinished compatibility processor", 255); // NOI18N
279
}
280
281             m = overrides;
282
283             does = m.get(getClass());
284
285             if (does != null) {
286                 return does.booleanValue();
287             }
288
289             try {
290                 java.lang.reflect.Method JavaDoc method = getClass().getMethod("waitFinished", new Class JavaDoc[] { Long.TYPE }); // NOI18N
291
does = Boolean.valueOf(method.getDeclaringClass() != Task.class);
292                 m.put(getClass(), does);
293
294                 return does.booleanValue();
295             } catch (Exception JavaDoc ex) {
296                 Exceptions.printStackTrace(ex);
297
298                 return true;
299             }
300         }
301     }
302
303     /** Reveal the identity of the worker runnable.
304      * Used for debugging from RequestProcessor.
305      */

306     String JavaDoc debug() {
307         return (run == null) ? "null" : run.getClass().getName();
308     }
309 }
310
Popular Tags