1 /* 2 * Copyright (c) 2010, 2014, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.concurrent; 27 28 import javafx.application.Platform; 29 import javafx.beans.property.BooleanProperty; 30 import javafx.beans.property.DoubleProperty; 31 import javafx.beans.property.ObjectProperty; 32 import javafx.beans.property.ReadOnlyBooleanProperty; 33 import javafx.beans.property.ReadOnlyDoubleProperty; 34 import javafx.beans.property.ReadOnlyObjectProperty; 35 import javafx.beans.property.ReadOnlyStringProperty; 36 import javafx.beans.property.SimpleBooleanProperty; 37 import javafx.beans.property.SimpleDoubleProperty; 38 import javafx.beans.property.SimpleObjectProperty; 39 import javafx.beans.property.SimpleStringProperty; 40 import javafx.beans.property.StringProperty; 41 import javafx.event.Event; 42 import javafx.event.EventDispatchChain; 43 import javafx.event.EventHandler; 44 import javafx.event.EventTarget; 45 import javafx.event.EventType; 46 import java.util.concurrent.Callable; 47 import java.util.concurrent.FutureTask; 48 import java.util.concurrent.atomic.AtomicReference; 49 import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_CANCELLED; 50 import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_FAILED; 51 import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_RUNNING; 52 import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_SCHEDULED; 53 import static javafx.concurrent.WorkerStateEvent.WORKER_STATE_SUCCEEDED; 54 55 /** 56 * <p> 57 * A fully observable implementation of a {@link FutureTask}. Tasks exposes 58 * additional state and observable properties useful for programming asynchronous 59 * tasks in JavaFX, as defined in the {@link Worker} interface. An implementation 60 * of Task must override the {@link javafx.concurrent.Task#call()} method. This method 61 * is invoked on the background thread. Any state which is used in this method 62 * must be safe to read and write from a background thread. For example, manipulating 63 * a live scene graph from this method is unsafe and will result in runtime 64 * exceptions. 65 * </p> 66 * <p> 67 * Tasks are flexible and extremely useful for the encapsulation of "work". Because 68 * {@link Service} is designed to execute a Task, any Tasks defined by the application 69 * or library code can easily be used with a Service. Likewise, since Task extends 70 * from FutureTask, it is very easy and natural to use a Task with the java concurrency 71 * {@link java.util.concurrent.Executor} API. Since a Task is Runnable, you 72 * can also call it directly (by invoking the {@link javafx.concurrent.Task#run()} method) 73 * from another background thread. This allows for composition of work, or pass it to 74 * a new Thread constructed and executed manually. Finally, since you can 75 * manually create a new Thread, passing it a Runnable, it is possible to use 76 * the following idiom: 77 * <pre><code> 78 * Thread th = new Thread(task); 79 * th.setDaemon(true); 80 * th.start(); 81 * </code></pre> 82 * Note that this code sets the daemon flag of the Thread to true. If you 83 * want a background thread to prevent the VM from existing after the last 84 * stage is closed, then you would want daemon to be false. However, if 85 * you want the background threads to simply terminate after all the 86 * stages are closed, then you must set daemon to true. 87 * </p> 88 * <p> 89 * Although {@link java.util.concurrent.ExecutorService} defines several methods which 90 * take a Runnable, you should generally limit yourself to using the <code>execute</code> 91 * method inherited from {@link java.util.concurrent.Executor}. 92 * </p> 93 * <p> 94 * As with FutureTask, a Task is a one-shot class and cannot be reused. See {@link Service} 95 * for a reusable {@link Worker}. 96 * </p> 97 * <p> 98 * Because the Task is designed for use with JavaFX GUI applications, it ensures 99 * that every change to its public properties, as well as change notifications 100 * for state, errors, and for event handlers, all occur on the main JavaFX application 101 * thread. Accessing these properties from a background thread (including the 102 * {@link #call()} method) will result in runtime exceptions being raised. The only exception 103 * to this, is when initially configuring a Task, which may safely be done 104 * from any thread. However, once the Task has been initialized and 105 * started, it may only thereafter be used from the FX thread (except for those methods clearly 106 * marked as being appropriate for the subclass to invoke from the background thread). 107 * </p> 108 * <p> 109 * It is <strong>strongly encouraged</strong> that all Tasks be initialized with 110 * immutable state upon which the Task will operate. This should be done by providing 111 * a Task constructor which takes the parameters necessary for execution of the Task. 112 * Immutable state makes it easy and safe to use from any thread and ensures 113 * correctness in the presence of multiple threads. 114 * </p> 115 * <p> 116 * In Java there is no reliable way to "kill" a thread in process. However, 117 * when <code>cancel</code> is called on a Task, it is important that 118 * the Task stop processing. A "run-away" Task might continue processing 119 * and updating the message, text, and progress properties even after the 120 * Task has been cancelled! In Java, cancelling a Task is a cooperative 121 * endeavor. The user of the Task will request that it be cancelled, and 122 * the author of the Task must check whether is has been cancelled within 123 * the body of the <code>call</code> method. There are two ways this can 124 * be done. First, the Task author may check the isCancelled method, 125 * inherited from <code>FutureTask</code>, to see whether the Task has 126 * been cancelled. Second, if the Task implementation makes use of any 127 * blocking calls (such as NIO InterruptibleChannels or Thread.sleep) and 128 * the task is cancelled while in such a blocking call, an 129 * InterruptedException is thrown. Task implementations which have blocking 130 * calls should recognize that an interrupted thread may be the signal for 131 * a cancelled task and should double check the isCancelled method to ensure 132 * that the InterruptedException was thrown due to the cancellation of the 133 * Task. 134 * </p> 135 * <h2>Examples</h2> 136 * <p> 137 * The following set of examples demonstrate some of the most common uses of 138 * Tasks. 139 * </p> 140 * 141 * <h3>A Simple Loop</h3> 142 * 143 * <p> 144 * The first example is a simple loop that does nothing particularly useful, 145 * but demonstrates the fundamental aspects of writing a Task correctly. This 146 * example will simply loop and print to standard out on each loop iteration. 147 * When it completes, it returns the number of times it iterated. 148 * </p> 149 * 150 * <pre><code> 151 * Task<Integer> task = new Task<Integer>() { 152 * @Override protected Integer call() throws Exception { 153 * int iterations; 154 * for (iterations = 0; iterations < 100000; iterations++) { 155 * if (isCancelled()) { 156 * break; 157 * } 158 * System.out.println("Iteration " + iterations); 159 * } 160 * return iterations; 161 * } 162 * }; 163 * </code></pre> 164 * 165 * <p> 166 * First, we define what type of value is returned from this Task. In this 167 * case, we want to return the number of times we iterated, so we will 168 * specify the Task to be of type Integer by using generics. Then, within 169 * the implementation of the <code>call</code> method, we iterate from 170 * 0 to 100000. On each iteration, we check to see whether this Task has 171 * been cancelled. If it has been, then we break out of the loop and return 172 * the number of times we iterated. Otherwise a message is printed to 173 * the console and the iteration count increased and we continue looping. 174 * </p> 175 * 176 * <p> 177 * Checking for isCancelled() in the loop body is critical, otherwise the 178 * developer may cancel the task, but the task will continue running 179 * and updating both the progress and returning the incorrect result 180 * from the end of the <code>call</code> method. A correct implementation 181 * of a Task will always check for cancellation. 182 * </p> 183 * 184 * <h3>A Simple Loop With Progress Notification</h3> 185 * 186 * <p> 187 * Similar to the previous example, except this time we will modify the 188 * progress of the Task in each iteration. Note that we have a choice 189 * to make in the case of cancellation. Do we want to set the progress back 190 * to -1 (indeterminate) when the Task is cancelled, or do we want to leave 191 * the progress where it was at? In this case, lets leave the progress alone 192 * and only update the message on cancellation, though updating the 193 * progress after cancellation is a perfectly valid choice. 194 * </p> 195 * 196 * <pre><code> 197 * Task<Integer> task = new Task<Integer>() { 198 * @Override protected Integer call() throws Exception { 199 * int iterations; 200 * for (iterations = 0; iterations < 10000000; iterations++) { 201 * if (isCancelled()) { 202 * updateMessage("Cancelled"); 203 * break; 204 * } 205 * updateMessage("Iteration " + iterations); 206 * updateProgress(iterations, 10000000); 207 * } 208 * return iterations; 209 * } 210 * }; 211 * </code></pre> 212 * 213 * <p> 214 * As before, within the for loop we check whether the Task has been 215 * cancelled. If it has been cancelled, we will update the Task's 216 * message to indicate that it has been cancelled, and then break as 217 * before. If the Task has not been cancelled, then we will update its 218 * message to indicate the current iteration and then update the 219 * progress to indicate the current progress. 220 * </p> 221 * 222 * <h3>A Simple Loop With Progress Notification And Blocking Calls</h3> 223 * 224 * <p> 225 * This example adds to the previous examples a blocking call. Because a 226 * blocking call may thrown an InterruptedException, and because an 227 * InterruptedException may occur as a result of the Task being cancelled, 228 * we need to be sure to handle the InterruptedException and check on the 229 * cancel state. 230 * </p> 231 * 232 * <pre><code> 233 * Task<Integer> task = new Task<Integer>() { 234 * @Override protected Integer call() throws Exception { 235 * int iterations; 236 * for (iterations = 0; iterations < 1000; iterations++) { 237 * if (isCancelled()) { 238 * updateMessage("Cancelled"); 239 * break; 240 * } 241 * updateMessage("Iteration " + iterations); 242 * updateProgress(iterations, 1000); 243 * 244 * // Now block the thread for a short time, but be sure 245 * // to check the interrupted exception for cancellation! 246 * try { 247 * Thread.sleep(100); 248 * } catch (InterruptedException interrupted) { 249 * if (isCancelled()) { 250 * updateMessage("Cancelled"); 251 * break; 252 * } 253 * } 254 * } 255 * return iterations; 256 * } 257 * }; 258 * </code></pre> 259 * 260 * <p> 261 * Here we have added to the body of the loop a <code>Thread.sleep</code> 262 * call. Since this is a blocking call, I have to handle the potential 263 * InterruptedException. Within the catch block, I will check whether 264 * the Task has been cancelled, and if so, update the message accordingly 265 * and break out of the loop. 266 * </p> 267 * 268 * <h3>A Task Which Takes Parameters</h3> 269 * 270 * <p> 271 * Most Tasks require some parameters in order to do useful work. For 272 * example, a DeleteRecordTask needs the object or primary key to delete 273 * from the database. A ReadFileTask needs the URI of the file to be read. 274 * Because Tasks operate on a background thread, care must be taken to 275 * make sure the body of the <code>call</code> method does not read or 276 * modify any shared state. There are two techniques most useful for 277 * doing this: using final variables, and passing variables to a Task 278 * during construction. 279 * </p> 280 * 281 * <p> 282 * When using a Task as an anonymous class, the most natural way to pass 283 * parameters to the Task is by using final variables. In this example, 284 * we pass to the Task the total number of times the Task should iterate. 285 * </p> 286 * 287 * <pre><code> 288 * final int totalIterations = 9000000; 289 * Task<Integer> task = new Task<Integer>() { 290 * @Override protected Integer call() throws Exception { 291 * int iterations; 292 * for (iterations = 0; iterations < totalIterations; iterations++) { 293 * if (isCancelled()) { 294 * updateMessage("Cancelled"); 295 * break; 296 * } 297 * updateMessage("Iteration " + iterations); 298 * updateProgress(iterations, totalIterations); 299 * } 300 * return iterations; 301 * } 302 * }; 303 * </code></pre> 304 * 305 * <p> 306 * Since <code>totalIterations</code> is final, the <code>call</code> 307 * method can safely read it and refer to it from a background thread. 308 * </p> 309 * 310 * <p> 311 * When writing Task libraries (as opposed to specific-use implementations), 312 * we need to use a different technique. In this case, I will create an 313 * IteratingTask which performs the same work as above. This time, since 314 * the IteratingTask is defined in its own file, it will need to have 315 * parameters passed to it in its constructor. These parameters are 316 * assigned to final variables. 317 * </p> 318 * 319 * <pre><code> 320 * public class IteratingTask extends Task<Integer> { 321 * private final int totalIterations; 322 * 323 * public IteratingTask(int totalIterations) { 324 * this.totalIterations = totalIterations; 325 * } 326 * 327 * @Override protected Integer call() throws Exception { 328 * int iterations = 0; 329 * for (iterations = 0; iterations < totalIterations; iterations++) { 330 * if (isCancelled()) { 331 * updateMessage("Cancelled"); 332 * break; 333 * } 334 * updateMessage("Iteration " + iterations); 335 * updateProgress(iterations, totalIterations); 336 * } 337 * return iterations; 338 * } 339 * } 340 * </code></pre> 341 * 342 * <p>And then when used:</p> 343 * 344 * <pre><code> 345 * IteratingTask task = new IteratingTask(8000000); 346 * </code></pre> 347 * 348 * <p>In this way, parameters are passed to the IteratingTask in a safe 349 * manner, and again, are final. Thus, the <code>call</code> method can 350 * safely read this state from a background thread.</p> 351 * 352 * <p>WARNING: Do not pass mutable state to a Task and then operate on it 353 * from a background thread. Doing so may introduce race conditions. In 354 * particular, suppose you had a SaveCustomerTask which took a Customer 355 * in its constructor. Although the SaveCustomerTask may have a final 356 * reference to the Customer, if the Customer object is mutable, then it 357 * is possible that both the SaveCustomerTask and some other application code 358 * will be reading or modifying the state of the Customer from different 359 * threads. Be very careful in such cases, that while a mutable object such 360 * as this Customer is being used from a background thread, that it is 361 * not being used also from another thread. In particular, if the background 362 * thread is reading data from the database and updating the Customer object, 363 * and the Customer object is bound to scene graph nodes (such as UI 364 * controls), then there could be a violation of threading rules! For such 365 * cases, modify the Customer object from the FX Application Thread rather 366 * than from the background thread.</p> 367 * 368 * <pre><code> 369 * public class UpdateCustomerTask extends Task<Customer> { 370 * private final Customer customer; 371 * 372 * public UpdateCustomerTask(Customer customer) { 373 * this.customer = customer; 374 * } 375 * 376 * @Override protected Customer call() throws Exception { 377 * // pseudo-code: 378 * // query the database 379 * // read the values 380 * 381 * // Now update the customer 382 * Platform.runLater(new Runnable() { 383 * @Override public void run() { 384 * customer.setF setFirstName(rs.getString("FirstName")); 385 * // etc 386 * } 387 * }); 388 * 389 * return customer; 390 * } 391 * } 392 * </code></pre> 393 * 394 * <h3>A Task Which Returns No Value</h3> 395 * 396 * <p> 397 * Many, if not most, Tasks should return a value upon completion. For 398 * CRUD Tasks, one would expect that a "Create" Task would return the newly 399 * created object or primary key, a "Read" Task would return the read 400 * object, an "Update" task would return the number of records updated, 401 * and a "Delete" task would return the number of records deleted. 402 * </p> 403 * 404 * <p> 405 * However sometimes there just isn't anything truly useful to return. 406 * For example, I might have a Task which writes to a file. Task has built 407 * into it a mechanism for indicating whether it has succeeded or failed 408 * along with the number of bytes written (the progress), and thus there is 409 * nothing really for me to return. In such a case, you can use the Void 410 * type. This is a special type in the Java language which can only be 411 * assigned the value of <code>null</code>. You would use it as follows: 412 * </p> 413 * 414 * <pre><code> 415 * final String filePath = "/foo.txt"; 416 * final String contents = "Some contents"; 417 * Task<Void> task = new Task<Void>() { 418 * @Override protected Void call() throws Exception { 419 * File file = new File(filePath); 420 * FileOutputStream out = new FileOutputStream(file); 421 * // ... and other code to write the contents ... 422 * 423 * // Return null at the end of a Task of type Void 424 * return null; 425 * } 426 * }; 427 * </code></pre> 428 * 429 * <h3>A Task Which Returns An ObservableList</h3> 430 * 431 * <p>Because the ListView, TableView, and other UI controls and scene graph 432 * nodes make use of ObservableList, it is common to want to create and return 433 * an ObservableList from a Task. When you do not care to display intermediate 434 * values, the easiest way to correctly write such a Task is simply to 435 * construct an ObservableList within the <code>call</code> method, and then 436 * return it at the conclusion of the Task.</p> 437 * 438 * <pre><code> 439 * Task<ObservableList<Rectangle>> task = new Task<ObservableList<Rectangle>>() { 440 * @Override protected ObservableList<Rectangle> call() throws Exception { 441 * updateMessage("Creating Rectangles"); 442 * ObservableList<Rectangle> results = FXCollections.observableArrayList(); 443 * for (int i=0; i<100; i++) { 444 * if (isCancelled()) break; 445 * Rectangle r = new Rectangle(10, 10); 446 * r.setX(10 * i); 447 * results.add(r); 448 * updateProgress(i, 100); 449 * } 450 * return results; 451 * } 452 * }; 453 * </code></pre> 454 * 455 * <p>In the above example, we are going to create 100 rectangles and return 456 * them from this task. An ObservableList is created within the 457 * <code>call</code> method, populated, and then returned.</p> 458 * 459 * <h3>A Task Which Returns Partial Results</h3> 460 * 461 * <p>Sometimes you want to create a Task which will return partial results. 462 * Perhaps you are building a complex scene graph and want to show the 463 * scene graph as it is being constructed. Or perhaps you are reading a large 464 * amount of data over the network and want to display the entries in a 465 * TableView as the data is arriving. In such cases, there is some shared state 466 * available both to the FX Application Thread and the background thread. 467 * Great care must be taken to <strong>never update shared state from any 468 * thread other than the FX Application Thread</strong>.</p> 469 * 470 * <p>The easiest way to do this is to take advantage of the {@link #updateValue(Object)} method. 471 * This method may be called repeatedly from the background thread. Updates are coalesced to 472 * prevent saturation of the FX event queue. This means you can call it as frequently as 473 * you like from the background thread but only the most recent set is ultimately set.</p> 474 * 475 * <pre><code> 476 * Task<Long> task = new Task<Long>() { 477 * @Override protected Long call() throws Exception { 478 * long a=0; 479 * long b=1; 480 * for (long i = 0; i < Long.MAX_VALUE; i++){ 481 * updateValue(a); 482 * a += b; 483 * b = a - b; 484 * } 485 * return a; 486 * } 487 * }; 488 * </code></pre> 489 * 490 * <p>Another way to do this is to expose a new property on the Task 491 * which will represent the partial result. Then make sure to use 492 * <code>Platform.runLater</code> when updating the partial result.</p> 493 * 494 * <pre><code> 495 * Task<Long> task = new Task<Long>() { 496 * @Override protected Long call() throws Exception { 497 * long a=0; 498 * long b=1; 499 * for (long i = 0; i < Long.MAX_VALUE; i++){ 500 * final long v = a; 501 * Platform.runLater(new Runnable() { 502 * @Override public void run() { 503 * updateValue(v); 504 * } 505 * } 506 * a += b; 507 * b = a - b; 508 * } 509 * return a; 510 * } 511 * }; 512 * </code></pre> 513 * 514 * <p>Suppose instead of updating a single value, you want to populate an ObservableList 515 * with results as they are obtained. One approach is to expose a new property on the Task 516 * which will represent the partial result. Then make sure to use 517 * <code>Platform.runLater</code> when adding new items to the partial 518 * result.</p> 519 * 520 * <pre><code> 521 * public class PartialResultsTask extends Task<ObservableList<Rectangle>> { 522 * // Uses Java 7 diamond operator 523 * private ReadOnlyObjectWrapper<ObservableList<Rectangle>> partialResults = 524 * new ReadOnlyObjectWrapper<>(this, "partialResults", 525 * FXCollections.observableArrayList(new ArrayList<Rectangle>())); 526 * 527 * public final ObservableList<Rectangle> getPartialResults() { return partialResults.get(); } 528 * public final ReadOnlyObjectProperty<ObservableList<Rectangle>> partialResultsProperty() { 529 * return partialResults.getReadOnlyProperty(); 530 * } 531 * 532 * @Override protected ObservableList<Rectangle> call() throws Exception { 533 * updateMessage("Creating Rectangles..."); 534 * for (int i=0; i<100; i++) { 535 * if (isCancelled()) break; 536 * final Rectangle r = new Rectangle(10, 10); 537 * r.setX(10 * i); 538 * Platform.runLater(new Runnable() { 539 * @Override public void run() { 540 * partialResults.get().add(r); 541 * } 542 * }); 543 * updateProgress(i, 100); 544 * } 545 * return partialResults.get(); 546 * } 547 * } 548 * </code></pre> 549 * 550 * <h3>A Task Which Modifies The Scene Graph</h3> 551 * 552 * <p>Generally, Tasks should not interact directly with the UI. Doing so 553 * creates a tight coupling between a specific Task implementation and a 554 * specific part of your UI. However, when you do want to create such a 555 * coupling, you must ensure that you use <code>Platform.runLater</code> 556 * so that any modifications of the scene graph occur on the 557 * FX Application Thread.</p> 558 * 559 * <pre><code> 560 * final Group group = new Group(); 561 * Task<Void> task = new Task<Void>() { 562 * @Override protected Void call() throws Exception { 563 * for (int i=0; i<100; i++) { 564 * if (isCancelled()) break; 565 * final Rectangle r = new Rectangle(10, 10); 566 * r.setX(10 * i); 567 * Platform.runLater(new Runnable() { 568 * @Override public void run() { 569 * group.getChildren().add(r); 570 * } 571 * }); 572 * } 573 * return null; 574 * } 575 * }; 576 * </code></pre> 577 * 578 * <h3>Reacting To State Changes Generically</h3> 579 * 580 * <p>Sometimes you may want to write a Task which updates its progress, 581 * message, text, or in some other way reacts whenever a state change 582 * happens on the Task. For example, you may want to change the status 583 * message on the Task on Failure, Success, Running, or Cancelled state changes. 584 * </p> 585 * <pre><code> 586 * Task<Integer> task = new Task<Integer>() { 587 * @Override protected Integer call() throws Exception { 588 * int iterations = 0; 589 * for (iterations = 0; iterations < 100000; iterations++) { 590 * if (isCancelled()) { 591 * break; 592 * } 593 * System.out.println("Iteration " + iterations); 594 * } 595 * return iterations; 596 * } 597 * 598 * @Override protected void succeeded() { 599 * super.succeeded(); 600 * updateMessage("Done!"); 601 * } 602 * 603 * @Override protected void cancelled() { 604 * super.cancelled(); 605 * updateMessage("Cancelled!"); 606 * } 607 * 608 * @Override protected void failed() { 609 * super.failed(); 610 * updateMessage("Failed!"); 611 * } 612 * }; 613 * </code></pre> 614 * @since JavaFX 2.0 615 */ 616 public abstract class Task<V> extends FutureTask<V> implements Worker<V>, EventTarget { 617 /** 618 * Used to send workDone updates in a thread-safe manner from the subclass 619 * to the FX application thread and workDone related properties. AtomicReference 620 * is used so as to coalesce updates such that we don't flood the event queue. 621 */ 622 private AtomicReference<ProgressUpdate> progressUpdate = new AtomicReference<>(); 623 624 /** 625 * Used to send message updates in a thread-safe manner from the subclass 626 * to the FX application thread. AtomicReference is used so as to coalesce 627 * updates such that we don't flood the event queue. 628 */ 629 private AtomicReference<String> messageUpdate = new AtomicReference<>(); 630 631 /** 632 * Used to send title updates in a thread-safe manner from the subclass 633 * to the FX application thread. AtomicReference is used so as to coalesce 634 * updates such that we don't flood the event queue. 635 */ 636 private AtomicReference<String> titleUpdate = new AtomicReference<>(); 637 638 /** 639 * Used to send value updates in a thread-safe manner from the subclass 640 * to the FX application thread. AtomicReference is used so as to coalesce 641 * updates such that we don't flood the event queue. 642 */ 643 private AtomicReference<V> valueUpdate = new AtomicReference<>(); 644 645 /** 646 * This is used so we have a thread-safe way to ask whether the task was 647 * started in the checkThread() method. 648 */ 649 private volatile boolean started = false; 650 651 /** 652 * Creates a new Task. 653 */ 654 public Task() { 655 this(new TaskCallable<V>()); 656 } 657 658 /** 659 * This bit of construction trickery is necessary because otherwise there is 660 * no way for the main constructor to both create the callable and maintain 661 * a reference to it, which is necessary because an anonymous callable construction 662 * cannot reference the implicit "this". We leverage an internal Callable 663 * so that all the pre-built semantics around cancel and so forth are 664 * handled correctly. 665 * 666 * @param callableAdapter non-null implementation of the 667 * TaskCallable adapter 668 */ 669 private Task(final TaskCallable<V> callableAdapter) { 670 super(callableAdapter); 671 callableAdapter.task = this; 672 } 673 674 /** 675 * Invoked when the Task is executed, the call method must be overridden and 676 * implemented by subclasses. The call method actually performs the 677 * background thread logic. Only the updateProgress, updateMessage, updateValue and 678 * updateTitle methods of Task may be called from code within this method. 679 * Any other interaction with the Task from the background thread will result 680 * in runtime exceptions. 681 * 682 * @return The result of the background work, if any. 683 * @throws Exception an unhandled exception which occurred during the 684 * background operation 685 */ 686 protected abstract V call() throws Exception; 687 688 private ObjectProperty<State> state = new SimpleObjectProperty<>(this, "state", State.READY); 689 final void setState(State value) { // package access for the Service 690 checkThread(); 691 final State s = getState(); 692 if (s != State.CANCELLED) { 693 this.state.set(value); 694 // Make sure the running flag is set 695 setRunning(value == State.SCHEDULED || value == State.RUNNING); 696 697 // Invoke the event handlers, and then call the protected methods. 698 switch (state.get()) { 699 case CANCELLED: 700 fireEvent(new WorkerStateEvent(this, WORKER_STATE_CANCELLED)); 701 cancelled(); 702 break; 703 case FAILED: 704 fireEvent(new WorkerStateEvent(this, WORKER_STATE_FAILED)); 705 failed(); 706 break; 707 case READY: 708 // This even can never meaningfully occur, because the 709 // Task begins life as ready and can never go back to it! 710 break; 711 case RUNNING: 712 fireEvent(new WorkerStateEvent(this, WORKER_STATE_RUNNING)); 713 running(); 714 break; 715 case SCHEDULED: 716 fireEvent(new WorkerStateEvent(this, WORKER_STATE_SCHEDULED)); 717 scheduled(); 718 break; 719 case SUCCEEDED: 720 fireEvent(new WorkerStateEvent(this, WORKER_STATE_SUCCEEDED)); 721 succeeded(); 722 break; 723 default: throw new AssertionError("Should be unreachable"); 724 } 725 } 726 } 727 @Override public final State getState() { checkThread(); return state.get(); } 728 @Override public final ReadOnlyObjectProperty<State> stateProperty() { checkThread(); return state; } 729 730 /** 731 * The onSchedule event handler is called whenever the Task state 732 * transitions to the SCHEDULED state. 733 * 734 * @return the onScheduled event handler property 735 * @since JavaFX 2.1 736 */ 737 public final ObjectProperty<EventHandler<WorkerStateEvent>> onScheduledProperty() { 738 checkThread(); 739 return getEventHelper().onScheduledProperty(); 740 } 741 742 /** 743 * The onSchedule event handler is called whenever the Task state 744 * transitions to the SCHEDULED state. 745 * 746 * @return the onScheduled event handler, if any 747 * @since JavaFX 2.1 748 */ 749 public final EventHandler<WorkerStateEvent> getOnScheduled() { 750 checkThread(); 751 return eventHelper == null ? null : eventHelper.getOnScheduled(); 752 } 753 754 /** 755 * The onSchedule event handler is called whenever the Task state 756 * transitions to the SCHEDULED state. 757 * 758 * @param value the event handler, can be null to clear it 759 * @since JavaFX 2.1 760 */ 761 public final void setOnScheduled(EventHandler<WorkerStateEvent> value) { 762 checkThread(); 763 getEventHelper().setOnScheduled(value); 764 } 765 766 /** 767 * A protected convenience method for subclasses, called whenever the 768 * state of the Task has transitioned to the SCHEDULED state. 769 * This method is invoked on the FX Application Thread after the Task has been fully transitioned to 770 * the new state. 771 * @since JavaFX 2.1 772 */ 773 protected void scheduled() { } 774 775 /** 776 * The onRunning event handler is called whenever the Task state 777 * transitions to the RUNNING state. 778 * 779 * @return the onRunning event handler property 780 * @since JavaFX 2.1 781 */ 782 public final ObjectProperty<EventHandler<WorkerStateEvent>> onRunningProperty() { 783 checkThread(); 784 return getEventHelper().onRunningProperty(); 785 } 786 787 /** 788 * The onRunning event handler is called whenever the Task state 789 * transitions to the RUNNING state. 790 * 791 * @return the onRunning event handler, if any 792 * @since JavaFX 2.1 793 */ 794 public final EventHandler<WorkerStateEvent> getOnRunning() { 795 checkThread(); 796 return eventHelper == null ? null : eventHelper.getOnRunning(); 797 } 798 799 /** 800 * The onRunning event handler is called whenever the Task state 801 * transitions to the RUNNING state. 802 * 803 * @param value the event handler, can be null to clear it 804 * @since JavaFX 2.1 805 */ 806 public final void setOnRunning(EventHandler<WorkerStateEvent> value) { 807 checkThread(); 808 getEventHelper().setOnRunning(value); 809 } 810 811 /** 812 * A protected convenience method for subclasses, called whenever the 813 * state of the Task has transitioned to the RUNNING state. 814 * This method is invoked on the FX Application Thread after the Task has been fully transitioned to 815 * the new state. 816 * @since JavaFX 2.1 817 */ 818 protected void running() { } 819 820 /** 821 * The onSucceeded event handler is called whenever the Task state 822 * transitions to the SUCCEEDED state. 823 * 824 * @return the onSucceeded event handler property 825 * @since JavaFX 2.1 826 */ 827 public final ObjectProperty<EventHandler<WorkerStateEvent>> onSucceededProperty() { 828 checkThread(); 829 return getEventHelper().onSucceededProperty(); 830 } 831 832 /** 833 * The onSucceeded event handler is called whenever the Task state 834 * transitions to the SUCCEEDED state. 835 * 836 * @return the onSucceeded event handler, if any 837 * @since JavaFX 2.1 838 */ 839 public final EventHandler<WorkerStateEvent> getOnSucceeded() { 840 checkThread(); 841 return eventHelper == null ? null : eventHelper.getOnSucceeded(); 842 } 843 844 /** 845 * The onSucceeded event handler is called whenever the Task state 846 * transitions to the SUCCEEDED state. 847 * 848 * @param value the event handler, can be null to clear it 849 * @since JavaFX 2.1 850 */ 851 public final void setOnSucceeded(EventHandler<WorkerStateEvent> value) { 852 checkThread(); 853 getEventHelper().setOnSucceeded(value); 854 } 855 856 /** 857 * A protected convenience method for subclasses, called whenever the 858 * state of the Task has transitioned to the SUCCEEDED state. 859 * This method is invoked on the FX Application Thread after the Task has been fully transitioned to 860 * the new state. 861 * @since JavaFX 2.1 862 */ 863 protected void succeeded() { } 864 865 /** 866 * The onCancelled event handler is called whenever the Task state 867 * transitions to the CANCELLED state. 868 * 869 * @return the onCancelled event handler property 870 * @since JavaFX 2.1 871 */ 872 public final ObjectProperty<EventHandler<WorkerStateEvent>> onCancelledProperty() { 873 checkThread(); 874 return getEventHelper().onCancelledProperty(); 875 } 876 877 /** 878 * The onCancelled event handler is called whenever the Task state 879 * transitions to the CANCELLED state. 880 * 881 * @return the onCancelled event handler, if any 882 * @since JavaFX 2.1 883 */ 884 public final EventHandler<WorkerStateEvent> getOnCancelled() { 885 checkThread(); 886 return eventHelper == null ? null : eventHelper.getOnCancelled(); 887 } 888 889 /** 890 * The onCancelled event handler is called whenever the Task state 891 * transitions to the CANCELLED state. 892 * 893 * @param value the event handler, can be null to clear it 894 * @since JavaFX 2.1 895 */ 896 public final void setOnCancelled(EventHandler<WorkerStateEvent> value) { 897 checkThread(); 898 getEventHelper().setOnCancelled(value); 899 } 900 901 /** 902 * A protected convenience method for subclasses, called whenever the 903 * state of the Task has transitioned to the CANCELLED state. 904 * This method is invoked on the FX Application Thread after the Task has been fully transitioned to 905 * the new state. 906 * @since JavaFX 2.1 907 */ 908 protected void cancelled() { } 909 910 /** 911 * The onFailed event handler is called whenever the Task state 912 * transitions to the FAILED state. 913 * 914 * @return the onFailed event handler property 915 * @since JavaFX 2.1 916 */ 917 public final ObjectProperty<EventHandler<WorkerStateEvent>> onFailedProperty() { 918 checkThread(); 919 return getEventHelper().onFailedProperty(); 920 } 921 922 /** 923 * The onFailed event handler is called whenever the Task state 924 * transitions to the FAILED state. 925 * 926 * @return the onFailed event handler, if any 927 * @since JavaFX 2.1 928 */ 929 public final EventHandler<WorkerStateEvent> getOnFailed() { 930 checkThread(); 931 return eventHelper == null ? null : eventHelper.getOnFailed(); 932 } 933 934 /** 935 * The onFailed event handler is called whenever the Task state 936 * transitions to the FAILED state. 937 * 938 * @param value the event handler, can be null to clear it 939 * @since JavaFX 2.1 940 */ 941 public final void setOnFailed(EventHandler<WorkerStateEvent> value) { 942 checkThread(); 943 getEventHelper().setOnFailed(value); 944 } 945 946 /** 947 * A protected convenience method for subclasses, called whenever the 948 * state of the Task has transitioned to the FAILED state. 949 * This method is invoked on the FX Application Thread after the Task has been fully transitioned to 950 * the new state. 951 * @since JavaFX 2.1 952 */ 953 protected void failed() { } 954 955 private final ObjectProperty<V> value = new SimpleObjectProperty<>(this, "value"); 956 private void setValue(V v) { checkThread(); value.set(v); } 957 @Override public final V getValue() { checkThread(); return value.get(); } 958 @Override public final ReadOnlyObjectProperty<V> valueProperty() { checkThread(); return value; } 959 960 private final ObjectProperty<Throwable> exception = new SimpleObjectProperty<>(this, "exception"); 961 private void _setException(Throwable value) { checkThread(); exception.set(value); } 962 @Override public final Throwable getException() { checkThread(); return exception.get(); } 963 @Override public final ReadOnlyObjectProperty<Throwable> exceptionProperty() { checkThread(); return exception; } 964 965 private final DoubleProperty workDone = new SimpleDoubleProperty(this, "workDone", -1); 966 private void setWorkDone(double value) { checkThread(); workDone.set(value); } 967 @Override public final double getWorkDone() { checkThread(); return workDone.get(); } 968 @Override public final ReadOnlyDoubleProperty workDoneProperty() { checkThread(); return workDone; } 969 970 private final DoubleProperty totalWork = new SimpleDoubleProperty(this, "totalWork", -1); 971 private void setTotalWork(double value) { checkThread(); totalWork.set(value); } 972 @Override public final double getTotalWork() { checkThread(); return totalWork.get(); } 973 @Override public final ReadOnlyDoubleProperty totalWorkProperty() { checkThread(); return totalWork; } 974 975 private final DoubleProperty progress = new SimpleDoubleProperty(this, "progress", -1); 976 private void setProgress(double value) { checkThread(); progress.set(value); } 977 @Override public final double getProgress() { checkThread(); return progress.get(); } 978 @Override public final ReadOnlyDoubleProperty progressProperty() { checkThread(); return progress; } 979 980 private final BooleanProperty running = new SimpleBooleanProperty(this, "running", false); 981 private void setRunning(boolean value) { checkThread(); running.set(value); } 982 @Override public final boolean isRunning() { checkThread(); return running.get(); } 983 @Override public final ReadOnlyBooleanProperty runningProperty() { checkThread(); return running; } 984 985 private final StringProperty message = new SimpleStringProperty(this, "message", ""); 986 @Override public final String getMessage() { checkThread(); return message.get(); } 987 @Override public final ReadOnlyStringProperty messageProperty() { checkThread(); return message; } 988 989 private final StringProperty title = new SimpleStringProperty(this, "title", ""); 990 @Override public final String getTitle() { checkThread(); return title.get(); } 991 @Override public final ReadOnlyStringProperty titleProperty() { checkThread(); return title; } 992 993 @Override public final boolean cancel() { 994 return cancel(true); 995 } 996 997 @Override public boolean cancel(boolean mayInterruptIfRunning) { 998 // Delegate to the super implementation to actually attempt to cancel this thing 999 boolean flag = super.cancel(mayInterruptIfRunning); 1000 // If cancel succeeded (according to the semantics of the Future cancel method), 1001 // then we need to make sure the State flag is set appropriately 1002 if (flag) { 1003 // If this method was called on the FX application thread, then we can 1004 // just update the state directly and this will make sure that after 1005 // the cancel method was called, the state will be set correctly 1006 // (otherwise it would be indeterminate). However if the cancel method was 1007 // called off the FX app thread, then we must use runLater, and the 1008 // state flag will not be readable immediately after this call. However, 1009 // that would be the case anyway since these properties are not thread-safe. 1010 if (isFxApplicationThread()) { 1011 setState(State.CANCELLED); 1012 } else { 1013 runLater(() -> setState(State.CANCELLED)); 1014 } 1015 } 1016 // return the flag 1017 return flag; 1018 } 1019 1020 /** 1021 * Updates the <code>workDone</code>, <code>totalWork</code>, 1022 * and <code>progress</code> properties. Calls to updateProgress 1023 * are coalesced and run later on the FX application thread, and calls 1024 * to updateProgress, even from the FX Application thread, may not 1025 * necessarily result in immediate updates to these properties, and 1026 * intermediate workDone values may be coalesced to save on event 1027 * notifications. <code>max</code> becomes the new value for 1028 * <code>totalWork</code>. 1029 * <p> 1030 * <em>This method is safe to be called from any thread.</em> 1031 * </p> 1032 * 1033 * @param workDone A value from Long.MIN_VALUE up to max. If the value is greater 1034 * than max, then it will be clamped at max. 1035 * If the value passed is negative then the resulting percent 1036 * done will be -1 (thus, indeterminate). 1037 * @param max A value from Long.MIN_VALUE to Long.MAX_VALUE. 1038 * @see #updateProgress(double, double) 1039 */ 1040 protected void updateProgress(long workDone, long max) { 1041 updateProgress((double)workDone, (double)max); 1042 } 1043 1044 /** 1045 * Updates the <code>workDone</code>, <code>totalWork</code>, 1046 * and <code>progress</code> properties. Calls to updateProgress 1047 * are coalesced and run later on the FX application thread, and calls 1048 * to updateProgress, even from the FX Application thread, may not 1049 * necessarily result in immediate updates to these properties, and 1050 * intermediate workDone values may be coalesced to save on event 1051 * notifications. <code>max</code> becomes the new value for 1052 * <code>totalWork</code>. 1053 * <p> 1054 * <em>This method is safe to be called from any thread.</em> 1055 * </p> 1056 * 1057 * @param workDone A value from Double.MIN_VALUE up to max. If the value is greater 1058 * than max, then it will be clamped at max. 1059 * If the value passed is negative, or Infinity, or NaN, 1060 * then the resulting percentDone will be -1 (thus, indeterminate). 1061 * @param max A value from Double.MIN_VALUE to Double.MAX_VALUE. Infinity and NaN are treated as -1. 1062 * @since JavaFX 2.2 1063 */ 1064 protected void updateProgress(double workDone, double max) { 1065 // Adjust Infinity / NaN to be -1 for both workDone and max. 1066 if (Double.isInfinite(workDone) || Double.isNaN(workDone)) { 1067 workDone = -1; 1068 } 1069 1070 if (Double.isInfinite(max) || Double.isNaN(max)) { 1071 max = -1; 1072 } 1073 1074 if (workDone < 0) { 1075 workDone = -1; 1076 } 1077 1078 if (max < 0) { 1079 max = -1; 1080 } 1081 1082 // Clamp the workDone if necessary so as not to exceed max 1083 if (workDone > max) { 1084 workDone = max; 1085 } 1086 1087 if (isFxApplicationThread()) { 1088 _updateProgress(workDone, max); 1089 } else if (progressUpdate.getAndSet(new ProgressUpdate(workDone, max)) == null) { 1090 runLater(() -> { 1091 final ProgressUpdate update = progressUpdate.getAndSet(null); 1092 _updateProgress(update.workDone, update.totalWork); 1093 }); 1094 } 1095 } 1096 1097 private void _updateProgress(double workDone, double max) { 1098 setTotalWork(max); 1099 setWorkDone(workDone); 1100 if (workDone == -1) { 1101 setProgress(-1); 1102 } else { 1103 setProgress(workDone / max); 1104 } 1105 } 1106 1107 /** 1108 * Updates the <code>message</code> property. Calls to updateMessage 1109 * are coalesced and run later on the FX application thread, so calls 1110 * to updateMessage, even from the FX Application thread, may not 1111 * necessarily result in immediate updates to this property, and 1112 * intermediate message values may be coalesced to save on event 1113 * notifications. 1114 * <p> 1115 * <em>This method is safe to be called from any thread.</em> 1116 * </p> 1117 * 1118 * @param message the new message 1119 */ 1120 protected void updateMessage(String message) { 1121 if (isFxApplicationThread()) { 1122 this.message.set(message); 1123 } else { 1124 // As with the workDone, it might be that the background thread 1125 // will update this message quite frequently, and we need 1126 // to throttle the updates so as not to completely clobber 1127 // the event dispatching system. 1128 if (messageUpdate.getAndSet(message) == null) { 1129 runLater(new Runnable() { 1130 @Override public void run() { 1131 final String message = messageUpdate.getAndSet(null); 1132 Task.this.message.set(message); 1133 } 1134 }); 1135 } 1136 } 1137 } 1138 1139 /** 1140 * Updates the <code>title</code> property. Calls to updateTitle 1141 * are coalesced and run later on the FX application thread, so calls 1142 * to updateTitle, even from the FX Application thread, may not 1143 * necessarily result in immediate updates to this property, and 1144 * intermediate title values may be coalesced to save on event 1145 * notifications. 1146 * <p> 1147 * <em>This method is safe to be called from any thread.</em> 1148 * </p> 1149 * 1150 * @param title the new title 1151 */ 1152 protected void updateTitle(String title) { 1153 if (isFxApplicationThread()) { 1154 this.title.set(title); 1155 } else { 1156 // As with the workDone, it might be that the background thread 1157 // will update this title quite frequently, and we need 1158 // to throttle the updates so as not to completely clobber 1159 // the event dispatching system. 1160 if (titleUpdate.getAndSet(title) == null) { 1161 runLater(new Runnable() { 1162 @Override public void run() { 1163 final String title = titleUpdate.getAndSet(null); 1164 Task.this.title.set(title); 1165 } 1166 }); 1167 } 1168 } 1169 } 1170 1171 /** 1172 * Updates the <code>value</code> property. Calls to updateValue 1173 * are coalesced and run later on the FX application thread, so calls 1174 * to updateValue, even from the FX Application thread, may not 1175 * necessarily result in immediate updates to this property, and 1176 * intermediate values may be coalesced to save on event 1177 * notifications. 1178 * <p> 1179 * <em>This method is safe to be called from any thread.</em> 1180 * </p> 1181 * 1182 * @param value the new value 1183 * @since JavaFX 8.0 1184 */ 1185 protected void updateValue(V value) { 1186 if (isFxApplicationThread()) { 1187 this.value.set(value); 1188 } else { 1189 // As with the workDone, it might be that the background thread 1190 // will update this value quite frequently, and we need 1191 // to throttle the updates so as not to completely clobber 1192 // the event dispatching system. 1193 if (valueUpdate.getAndSet(value) == null) { 1194 runLater(() -> Task.this.value.set(valueUpdate.getAndSet(null))); 1195 } 1196 } 1197 } 1198 1199 /* 1200 * IMPLEMENTATION 1201 */ 1202 private void checkThread() { 1203 if (started && !isFxApplicationThread()) { 1204 throw new IllegalStateException("Task must only be used from the FX Application Thread"); 1205 } 1206 } 1207 1208 // This method exists for the sake of testing, so I can subclass and override 1209 // this method in the test and not actually use Platform.runLater. 1210 void runLater(Runnable r) { 1211 Platform.runLater(r); 1212 } 1213 1214 // This method exists for the sake of testing, so I can subclass and override 1215 // this method in the test and not actually use Platform.isFxApplicationThread. 1216 boolean isFxApplicationThread() { 1217 return Platform.isFxApplicationThread(); 1218 } 1219 1220 /*************************************************************************** 1221 * * 1222 * Event Dispatch * 1223 * * 1224 **************************************************************************/ 1225 1226 private EventHelper eventHelper = null; 1227 private EventHelper getEventHelper() { 1228 if (eventHelper == null) { 1229 eventHelper = new EventHelper(this); 1230 } 1231 return eventHelper; 1232 } 1233 1234 /** 1235 * Registers an event handler to this task. Any event filters are first 1236 * processed, then the specified onFoo event handlers, and finally any 1237 * event handlers registered by this method. As with other events 1238 * in the scene graph, if an event is consumed, it will not continue 1239 * dispatching. 1240 * 1241 * @param <T> the specific event class of the handler 1242 * @param eventType the type of the events to receive by the handler 1243 * @param eventHandler the handler to register 1244 * @throws NullPointerException if the event type or handler is null 1245 * @since JavaFX 2.1 1246 */ 1247 public final <T extends Event> void addEventHandler( 1248 final EventType<T> eventType, 1249 final EventHandler<? super T> eventHandler) { 1250 checkThread(); 1251 getEventHelper().addEventHandler(eventType, eventHandler); 1252 } 1253 1254 /** 1255 * Unregisters a previously registered event handler from this task. One 1256 * handler might have been registered for different event types, so the 1257 * caller needs to specify the particular event type from which to 1258 * unregister the handler. 1259 * 1260 * @param <T> the specific event class of the handler 1261 * @param eventType the event type from which to unregister 1262 * @param eventHandler the handler to unregister 1263 * @throws NullPointerException if the event type or handler is null 1264 * @since JavaFX 2.1 1265 */ 1266 public final <T extends Event> void removeEventHandler( 1267 final EventType<T> eventType, 1268 final EventHandler<? super T> eventHandler) { 1269 checkThread(); 1270 getEventHelper().removeEventHandler(eventType, eventHandler); 1271 } 1272 1273 /** 1274 * Registers an event filter to this task. Registered event filters get 1275 * an event before any associated event handlers. 1276 * 1277 * @param <T> the specific event class of the filter 1278 * @param eventType the type of the events to receive by the filter 1279 * @param eventFilter the filter to register 1280 * @throws NullPointerException if the event type or filter is null 1281 * @since JavaFX 2.1 1282 */ 1283 public final <T extends Event> void addEventFilter( 1284 final EventType<T> eventType, 1285 final EventHandler<? super T> eventFilter) { 1286 checkThread(); 1287 getEventHelper().addEventFilter(eventType, eventFilter); 1288 } 1289 1290 /** 1291 * Unregisters a previously registered event filter from this task. One 1292 * filter might have been registered for different event types, so the 1293 * caller needs to specify the particular event type from which to 1294 * unregister the filter. 1295 * 1296 * @param <T> the specific event class of the filter 1297 * @param eventType the event type from which to unregister 1298 * @param eventFilter the filter to unregister 1299 * @throws NullPointerException if the event type or filter is null 1300 * @since JavaFX 2.1 1301 */ 1302 public final <T extends Event> void removeEventFilter( 1303 final EventType<T> eventType, 1304 final EventHandler<? super T> eventFilter) { 1305 checkThread(); 1306 getEventHelper().removeEventFilter(eventType, eventFilter); 1307 } 1308 1309 /** 1310 * Sets the handler to use for this event type. There can only be one such 1311 * handler specified at a time. This handler is guaranteed to be called 1312 * first. This is used for registering the user-defined onFoo event 1313 * handlers. 1314 * 1315 * @param <T> the specific event class of the handler 1316 * @param eventType the event type to associate with the given eventHandler 1317 * @param eventHandler the handler to register, or null to unregister 1318 * @throws NullPointerException if the event type is null 1319 * @since JavaFX 2.1 1320 */ 1321 protected final <T extends Event> void setEventHandler( 1322 final EventType<T> eventType, 1323 final EventHandler<? super T> eventHandler) { 1324 checkThread(); 1325 getEventHelper().setEventHandler(eventType, eventHandler); 1326 } 1327 1328 /** 1329 * Fires the specified event. Any event filter encountered will 1330 * be notified and can consume the event. If not consumed by the filters, 1331 * the event handlers on this task are notified. If these don't consume the 1332 * event either, then all event handlers are called and can consume the 1333 * event. 1334 * <p> 1335 * This method must be called on the FX user thread. 1336 * 1337 * @param event the event to fire 1338 * @since JavaFX 2.1 1339 */ 1340 public final void fireEvent(Event event) { 1341 checkThread(); 1342 getEventHelper().fireEvent(event); 1343 } 1344 1345 @Override 1346 public EventDispatchChain buildEventDispatchChain(EventDispatchChain tail) { 1347 checkThread(); 1348 return getEventHelper().buildEventDispatchChain(tail); 1349 } 1350 1351 /** 1352 * A struct like class that contains the last workDone update information. 1353 * What we do when updateProgress is called, is we create a new ProgressUpdate 1354 * object and store it. If it was null, then we fire off a new Runnable 1355 * using RunLater, which will eventually read the latest and set it to null 1356 * atomically. If it was not null, then we simply update it. 1357 */ 1358 private static final class ProgressUpdate { 1359 private final double workDone; 1360 private final double totalWork; 1361 1362 private ProgressUpdate(double p, double m) { 1363 this.workDone = p; 1364 this.totalWork = m; 1365 } 1366 } 1367 1368 /** 1369 * TaskCallable actually implements the Callable contract as defined for 1370 * the FutureTask class, and is necessary so as to allow us to intercept 1371 * the call() operation to update state on the Task as appropriate. 1372 * @param <V> 1373 */ 1374 private static final class TaskCallable<V> implements Callable<V> { 1375 /** 1376 * The Task that is going to use this TaskCallable 1377 */ 1378 private Task<V> task; 1379 1380 /** 1381 * Create a TaskCallable. The concurrent and other fields MUST be set 1382 * immediately after creation. 1383 */ 1384 private TaskCallable() { } 1385 1386 /** 1387 * Invoked by the system when it is time to run the client code. This 1388 * implementation is where we modify the state and other properties 1389 * and from which we invoke the events. 1390 * 1391 * @return The result of the Task call method 1392 * @throws Exception any exception which occurred 1393 */ 1394 @Override public V call() throws Exception { 1395 // If the Task is sent to an ExecutorService for execution, then we 1396 // will need to make sure that we transition first to the SCHEDULED 1397 // state before then transitioning to the RUNNING state. If the 1398 // Task was executed by a Service, then it will have already been 1399 // in the SCHEDULED state and setting it again here has no negative 1400 // effect. But we must ensure that SCHEDULED is visited before RUNNING 1401 // in all cases so that developer code can be consistent. 1402 task.started = true; 1403 task.runLater(() -> { 1404 task.setState(State.SCHEDULED); 1405 task.setState(State.RUNNING); 1406 }); 1407 // Go ahead and delegate to the wrapped callable 1408 try { 1409 final V result = task.call(); 1410 if (!task.isCancelled()) { 1411 // If it was not cancelled, then we take the return 1412 // value and set it as the result. 1413 task.runLater(() -> { 1414 // The result must be set first, so that when the 1415 // SUCCEEDED flag is set, the value will be available 1416 // The alternative is not the case, because you 1417 // can assume if the result is set, it has 1418 // succeeded. 1419 task.updateValue(result); 1420 task.setState(State.SUCCEEDED); 1421 }); 1422 return result; 1423 } else { 1424 // Since cancelled Future/FutureTask doesn't return any value, 1425 // the returned value is going to be trashed, so we can jus return null 1426 return null; 1427 } 1428 } catch (final Throwable th) { 1429 // Be sure to set the state after setting the cause of failure 1430 // so that developers handling the state change events have a 1431 // throwable to inspect when they get the FAILED state. Note 1432 // that the other way around is not important -- when a developer 1433 // observes the causeOfFailure is set to a non-null value, even 1434 // though the state has not yet been updated, he can infer that 1435 // it will be FAILED because it can be nothing other than FAILED 1436 // in that circumstance. 1437 task.runLater(() -> { 1438 task._setException(th); 1439 task.setState(State.FAILED); 1440 }); 1441 // Some error occurred during the call (it might be 1442 // an exception (either runtime or checked), or it might 1443 // be an error. In any case, we capture the throwable, 1444 // record it as the causeOfFailure, and then rethrow. However 1445 // since the Callable interface requires that we throw an 1446 // Exception (not Throwable), we have to wrap the exception 1447 // if it is not already one. 1448 if (th instanceof Exception) { 1449 throw (Exception) th; 1450 } else { 1451 throw new Exception(th); 1452 } 1453 } 1454 } 1455 } 1456 }