After showing some problems with the synchronous solutions like Foxtrot or Spin. Now I want to talk about Swing Application Framework’s TaskService or a small own solution.
The Swing Application Framework uses annotated methods which can be executed as during the actionPerformed() method of an Action. The method can return a task to indicate that it needs to be executed in the background. This Task object is handed over to the TaskService which executes it in a background thread, like a SwingWorker. The Task object might have a blocking scope that defines how much of the user interface is blocked during execution. This is quite easy and works very well.
My problem is the Task class which not only contains information about how to block, but also the responsibility to create the blocker and a reference to the task service. If there are multiple tasks it might be possible that two blockers show a dialog 😦 . I would like to have a Task which is small and easy, like a command object from the command pattern. The command or task should then be handed over to the so called TaskService and this one should execute it.
First the Task needs to be simplified. Therefore the responsibility of creating and maintaining the InputBlocker moves over to the TaskService. The service has a single input blocker which is used in the complete application. So it has a unique interface and can also show a list of running tasks like the ProgressView of Eclipse. The service also should implement the Executor interface which makes it possible that even Runnable objects can be executed over this service. The service distinguishes between a Runnable object and a Task and can use a default blocking behavior like blocking the complete application. If the TaskService extends ThreadPoolExecutor it is easy to implement input blocking by blocking either in execute() or beforeExecute() and unblocking in afterExecute().
The Task class is then a simple extension of SwingWorker with some visual attributes like title and description, running time. An important BlockingScope that defines how much is blocked and an optional source from which the input blocker is able to block the user interface.
The image shows possible classes for the simplified service. I renamed the Task to SwingWorkerExt because it is a simple extension of SwingWorker. The enumeration BlockingScope and the interface InputBlocker stays as in the SwingApplicationFramework. But instead of having an association between InputBlocker and SwingWorkerExt, the input blocker only works together with the executor. In this case the SwingThreadPoolExecutor is the service used to execute background operations. introducing events when a command is added, removed, executed or rejected also helps the application to better react in extrem conditions.