Skip to content

Action Queues

William Wood edited this page Apr 11, 2021 · 1 revision

Action Queues

For the purposes of queuing actions to run sequentially, JISA provides the ActionQueue class.

Creating an ActionQueue

To create an action queue, you just need to instantiate an ActionQueue object like so:

ActionQueue queue = new ActionQueue();

Adding Action objects

Adding actions to the queue is done by creating Action objects and using the addAction(...) method. Action itself is an interface, so you cannot directly instantiate an Action object. However, JISA provides a few simple implementations of Action. Before we cover that though, it's important to note that Action also has a generic type, that is we should actually be writing Action<...>. This is because Action object can return an object as "data" by using the getData() method. The type of object it returns is up to the implementation of Action<...> that is used hence the need for a generic.

The simplest is SimpleAction which just takes a runnable to define the action it should run. It returns no data, hence the generic type is Action<Void>. For instance, if we wanted to add an action that just waits for 30 seconds we could write:

SimpleAction action1 = new SimpleAction("Wait 30s", () -> Thread.sleep(30000));

Alternatively, if we have a Measurement object called measurement to run and we want it to be run as part of our queue, we can wrap it in a MeasurementAction object. These return ResultTable objects as data hence their generic type is Action<ResultTable>.

MeasurementAction action2 = new MeasurementAction(measurement);

After creating our Action objects, we can add them to the queue like so:

// One at a time
queue.addAction(action1);
queue.addAction(action2);

// Or both together
queue.addActions(action1, action2);

Now, when we run the queue by calling start() like so:

queue.start();

It will first wait 30 seconds then perform the measurement.

Modifying the queue

You can alter the queue in a number of different ways. The most straight-forward is removing actions. This can be done using the removeAction(...), removeActions(...) and clear() methods respectively:

// Remove one action
queue.removeAction(action);

// Remove multiple actions
queue.removeActions(action1, action2, action3);

// Remove all actions
queue.clear();

The other alteration that can be performed is changing the order of actions. This can be done by swapping the positions of two actions at a time by use of the swapActions(...) method like so:

queue.swapActions(actionA, actionB);

where actionA and actionB are either the Action objects to be swapped themselves, or their integer indices in the queue.

Running a queue

To run a queue we use the start() method. This will not return until the queue has finished executing. The result of the execution is then returned as a ActionQueue.Result object:

ActionQueue.Result result = queue.start();

swtich(result) {

    case SUCCESS:
        // All completed with no error

    case INTERRUPTED:
        // The queue ended early because stop() was called

    case ERROR:
        // One or more of the actions ended in error

}

To make a queue end early (from another thread) you can call stop() on it:

queue.stop();

This functionality only really makes sense when using a GUI since the queue will be running on a separate thread to that which the user interacts with meaning user interaction and the running of the thread can happen simultaneously. For example:

Grid        grid  = new Grid("Experiment");
ActionQueue queue = new ActionQueue();

...

grid.addToolbarButton("Start Queue", () -> {

    ActionQueue.Result result = queue.start();

    switch(result) {

        case SUCCESS:
            GUI.infoAlert("Queue completed successfully");
            break;

        case INTERRUPTED:
            GUI.warningAlert("Queue was ended early");
            break;

        case ERROR:
            GUI.errorAlert("Queue completed with error(s)");
            break;

    }

});

grid.addToolbarButton("Stop Queue", queue::stop);

grid.show();

If a queue was previously interrupted, you can resume it from the last interrupted item by calling resume() instead of start():

ActionQueue.Result result;

if (queue.isInterrupted()) {
    result = queue.resume();
} else {
    result = queue.start();
}
Clone this wiki locally