# SciJava Progress: an interrupt-based mechanism for progress reporting This component provides a mechanism for progress-recording operations to notify interested parties of updates to progress. ## The `Progress` class The `Progress` class is designed to be the middle-man between an operation that wishes to report its progress and a listener that wishes to be notified of progress updates. **Both** of these parties will interface with each other through `Progress` class. ### Accessing `Progress` as an operation Suppose we have a `Function` that does some heavy calculation on a `List`, and wants to notify callers when it finishes one element, before it moves to the next: ```java public class HeavyCalculator implements Function, List> { @Override public List apply(List in) { List out = new ArrayList<>(); for(var i = 0; i < in.size(); i++) { out.add(doTheComputation(in.get(i))); } return out; } } ``` Firstly, we add the bookkeeping steps: 1. Notify `Progress` that this Object wants to record its progress by calling `Progress.register(Object progressible)`. This can either be called within our `Function` (by passing `this`), or before the `apply` method is called (by passing our `HeavyCalculator` instance). 2. Define what total progress means using `Progress.defineTotalProgress(int numStages, int numSubTasks)`. We make the distinction between `numStages` and `numSubtasks`: * `numStages` lets `Progress` know how many stages of computation will be performed within the current task * `numSubTasks` lets `Progress` know how many progress-reporting tasks **will be called** by the current task. Since they will report their own progress to `Progress`, `Progress` will automatically update the progress of our current task as the subtasks progress. 3. For each stage, `Progress.setStageMax(long max)` must be called so that `Progress` knows when each stage is completed, and moves onto the next. 4. Once the computation is complete, notify `Progress` that the task has completed by calling `Progress.complete()`. Once these bookkeeping stages are added, we can then call `Progress.update`. Our `Function`, updating progress, would then look like: ```java public class HeavyCalculator implements Function, List> { @Override public List apply(List in) { Progress.register(this); Progress.defineTotalProgress(1, 0); Progress.setStageMax(in.size()); // compute List out = new ArrayList<>(); for(var i = 0; i < in.size(); i++) { out.add(doTheComputation(in.get(i))); Progress.update(); } Progress.complete(); return out; } } ``` Ops can also set their `status` through the `Progress` framework, using the method `Progress.setStatus(String status)`. In these situations, out `Function` would not need to call `Progress.defineTotalProgress()` or `Progress.setStageMax()`. Progressible code is, of course, allowed to set both status and progress. ### Accessing `Progress` as a listener Progress is accessed by listeners using the `Progress.addListener(Object progressible, Consumer l)` method. This method must be called **before** `progressible`'s code is executed, and all executions of `progressible` will then be sent to `l`. `l` can be written as a lambda (shown below), or as an explicit implementation of the `Consumer` interface. The functional method, `accept(Task t)`, is then called when **any execution** of `progressible` calls `Progress.register`, `Progress.complete`, `Progress.update()`, or `Progress.setStatus()`. Below is an example of how one might write a `Consumer` for `HeavyCalculator`: ```java HeavyCalculator calc = new HeavyCalculator(); // register a listener that prints progress to console Progress.addListener(calc, t -> System.out.println(t.progress())); // call HeavyCalculator calc.apply(Arrays.asList(1, 2, 3, 4); ```