Cytoscape 2.6.2 (c) 2006,2007 ISB, MSKCC, UCSD

Package cytoscape.task

Cytoscape Task Framework.

See:
          Description

Interface Summary
Haltable A hook for requesting that a running process be halted.
Task Represents a task that can be terminated prematurely by the same entity that started the task - tasks are started with Task.run() and tasks are terminated prematurely [and asynchronously] with Task.halt().
TaskMonitor Interface for monitoring the progress of a task.
 

Package cytoscape.task Description

Cytoscape Task Framework.

Overview

The task package is a convenient framework for building, running and visually monitoring long-term tasks within Cytoscape.

The main goal of the task package is to improve the perceived performance of Cytoscape:

Often the subjective speed of your application has little to do with how quickly it actually executes its code. To the user, an application that starts up rapidly, repaints quickly, and provides continuous feedback feels "snappier" than an application that just "hangs up" while it churns through its work. [1]

By using the task framework, core developers and plugin developers can provide continuous feedback to the end-user, and we can all make Cytoscape a "snappier" application.

Basic Definitions

Task: A Task is any long-running process that can be canceled by the end-user. A long-running task may take several seconds or several minutes to complete. For example, retrieving data from a remote database, or running a layout algorithm, are all examples of tasks. For the specific purposes of the task framework, we define a task as any class which implements the Task interface.

JTask: JTask is Swing dialog box provided by the task framework. It mainly includes a progress bar for monitoring tasks, but it can also be configured to show additional details, such as total time elapsed, estimated time remaining, etc. In the event that a task encounters an error and ends prematurely, the JTask dialog box will also present a nicely formatted error message to the user.

Advantages of a Common Task Framework

If you are a core developer or a plugin writer, you should consider using the task framework for any long-term processes that you build. You could, of course just build your own task framework and your own progress bar dialog box, but there are certain advantages to using the task framework:

How to Create a New Task (with Sample Code)

To create a new task, your task code must impelement the Task interface. The interface defines four methods:

Creating a new task is best illustrated with an example. The code below defines a simple task for counting from 0 to max, and is defined in SampleTask:

SampleTask.java
package cytoscape.task.sample;

import cytoscape.task.Task;
import cytoscape.task.TaskMonitor;

import java.io.IOException;

/**
 * Sample Task, used to illustrate the Task Framework.
 * This tasks counts from 0 to maxValue.
 */
public class SampleTask implements Task {
    private static final int MIN_VALUE = 0;
    private int maxValue;
    private long countDelay;
    private TaskMonitor taskMonitor = null;
    private boolean interrupted = false;
    private int exceptionIndex = Integer.MAX_VALUE;

    /**
     * Constructor.
     *
     * @param max        Max Count Value.
     * @param countDelay Delay between each count (in milliseconds).
     */
    public SampleTask(int max, long countDelay) {
        this.maxValue = max;
        this.countDelay = countDelay;
    }

    /**
     * Constructor.
     * Provides a test of Exception Handling.
     * The Task will throw a NullPointerException when it reaches the
     * exceptionIndex value.
     *
     * @param max            Max Count Value.
     * @param countDelay     Delay between each count (in milliseconds).
     * @param exceptionIndex The Task will throw a NullPointerException
     *                       when it reaches the exceptionIndex
     *                       value.
     */
    public SampleTask(int max, long countDelay, int exceptionIndex) {
        this.maxValue = max;
        this.countDelay = countDelay;
        this.exceptionIndex = exceptionIndex;
    }

    /**
     * Run the Task.
     */
    public void run() {
        if (taskMonitor == null) {
            throw new IllegalStateException("Task Monitor is not set.");
        }
        try {
            //  Count from 0 to maxValue with a countDelay
            //  Counting from 0..100 with a 50 ms delay should take ~5 seconds

            //  Make sure to check the interrupt flag.
            int i = MIN_VALUE;
            while (i <= maxValue && !interrupted) {

                // Calculate Percentage.  This must be a value between 0..100.
                int percentComplete = (int) (((double) i / maxValue) * 100);

                //  Estimate Time Remaining
                long totalTime = maxValue * countDelay;
                long timeElapsed = i * countDelay;
                long timeRemaining = totalTime - timeElapsed;

                //  Update the Task Monitor.
                //  This automatically updates the UI Component w/ progress bar.
                if (taskMonitor != null) {
                    taskMonitor.setPercentCompleted(percentComplete);
                    taskMonitor.setStatus("Counting:  " + i);
                    taskMonitor.setEstimatedTimeRemaining(timeRemaining);
                }

                //  Illustrates how to Handle/Report Exceptions within a Task.
                //  When this IOException is thrown, the task will stop
                //  execution and report the error to the Task Monitor.
                //  This causes the UI Component to automatically display
                //  an error dialog box to the end-user.
                if (i == this.exceptionIndex) {
                    throw new IOException("This is a Fake IO Exception");
                }

                // Artificial Delay
                Thread.sleep(countDelay);
                i++;
            }
        } catch (InterruptedException e) {
            taskMonitor.setException(e, "Counting cancelled");
        } catch (IOException e) {
            taskMonitor.setException(e, "Counting aborted by fake exception");
        }
    }

    /**
     * Non-blocking call to interrupt the task.
     */
    public void halt() {
        this.interrupted = true;
    }

    /**
     * Sets the Task Monitor.
     *
     * @param taskMonitor TaskMonitor Object.
     */
    public void setTaskMonitor(TaskMonitor taskMonitor) {
        if (this.taskMonitor != null) {
            throw new IllegalStateException("Task Monitor is already set.");
        }
        this.taskMonitor = taskMonitor;
    }

    /**
     * Gets the Task Title.
     *
     * @return human readable task title.
     */
    public String getTitle() {
        return new String("Counting Task");
    }
}

Note: If your task cannot accurately report percentage of work complete, use TaskMonitor setPercentCompleted(-1). This will cause the JTask UI component to display the appropriate indeterminate progress bar.

Tips for Creating Swing-Safe Tasks

According to Sun:

"Once a Swing component has been realized, all code that might affect or depend on the state of that component should be executed in the event-dispatching thread." [2]

If your task must modify a UI component, you are advised to use one of the javax.swing.SwingUtilities:

For additional information on creating Swing safe tasks, refer to the following resources:
How to Run a Task via the TaskManager (with Sample Code)

Once you have created a Task, you can run it via the TaskManager utility class. This class will automatically create a new thread for your task, start the thread, and pop-open a JTask dialog box for monitoring the task.

Here is a complete example, taken from RunBareBones.

RunBareBones.java
package cytoscape.task.sample;

import cytoscape.task.Task;
import cytoscape.task.util.TaskManager;
import cytoscape.task.ui.JTaskConfig;
import cytoscape.task.ui.JTask;

/**
 * Illustrates How to Execute a Sample Task via the TaskManager.
 */
public class RunBareBones {

    /**
     * Executes the Sample Task.
     *
     * @param args Command Line Arguments.
     */
    public static void main(String[] args) {

        //  Create a Sample Task
        Task task = new SampleTask (100, 100);

        //  Configure JTask
        JTaskConfig config = new JTaskConfig();

        //  Show Cancel/Close Buttons
        config.displayUserButtons(true);

        //  Execute Task via TaskManager
        //  This automatically pops-open a JTask Dialog Box.
        //  This method will block until the JTask Dialog Box is disposed.
        boolean success = TaskManager.executeTask(task, config);
    }
}

How to Customize the JTask Dialog Box (with Screen Shots)

By default, the JTask Dialog box will look like this (as seen on Mac OS X):

However, you can customize the look and feel of JTask via JTaskConfig. For example, here is a fully customized JTask Dialog box. It now shows a status message, time elapsed, and estimated time remaining. It also provides cancel/ close buttons.

Sample screenshots of error messages provided to users are provided below:

References

[1] Optimizing Perceived Speed, MSDN Network.
[2] Threads and Swing, Sun Microsystems, Inc.


www.cytoscape.org