Difference: WritingTasks (1 vs. 50)

Revision 502014-02-14 - AlvarGarcia

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 70 to 70
 mvln = MyVeryLongNameTask() # New instance
Changed:
<
<
The TaskUtil class offers the isValidName method to check a task name and getDefaultName to generate a default name.
>
>
The TaskUtil class offers the isValidName method to check a task name and getDefaultName to generate a default name.
  Naming style: given a new functionality for a task, there are 2 options: * Role naming: This is how most old task are named, it is object-oriented but is ill suited for functions. (Ex fitsReader, asciiTableReader)
Changed:
<
<
* action-target naming: This is how we recommend to name new tasks as the action comes first and then (optionally) the target. (Ex readFits, readTable, openFile, sortTable, save, restore, pause ...). This is better suited to the functional style that tasks support.
>
>
  • Action-target naming: This is how we recommend to name new tasks as the action comes first and then (optionally) the target. (Ex readFits, readTable, openFile, sortTable, save, restore, pause ...). This is better suited to the functional style that tasks support.
 

Task parameters

Changed:
<
<
Every task has parameters, defined by the TaskParameter class. Task parameters have the following features:
>
>
Every task has parameters, defined by the TaskParameter class. Task parameters have the following features:
 
  • They can be of three kinds: input (IN), output (OUT) or input-output (IO). Use an input-output parameter if your task needs to modify (or replace) the passed object. To set a parameter type:
Line: 121 to 121
 JYTHON: myParameter = TaskParameter("data", valueType = TableDataset, defaultValue=null, ...) JAVA: TaskParameter myParameter = new TaskParameter("data", TableDataset.class);
Changed:
<
<
Note that in Jython you can pass most configuration with the call to create the parameter. In Java, you can use TaskUtil.buildParameter to set most of them in just one step. From a usability POV, the configuration (most members except value) of a task parameter should be constants: a user will not be able to make sense of the system if, under some circumstances, a parameter changes from being mandatory to optional, for example. The way to properly understand this is that we are configuring by code (and data) extended functions definitions.
>
>
Note that in Jython you can pass most configuration with the call to create the parameter. In Java, you can use TaskUtil.buildParameter to set most of them in just one step. From a usability POV, the configuration (most members except value) of a task parameter should be constant: a user will not be able to make sense of the system if, under some circumstances, a parameter changes from being mandatory to optional, for example. The way to properly understand this is that we are configuring by code (and data) extended functions definitions.
  Do not try to reuse reserved words for parameter names (for , if , print ...), otherwise Jython will not be able to understand your task call.
Line: 173 to 173
 
  • The task will not be registered.
  • The task will not even appear in the All folder of the Tasks view.
Changed:
<
<
This means that users can only invoke the task via the command line, either in a script or at the prompt in the Console view. (The root cause is that the Task View (and ToolRegistry) require a primary input).
>
>
This means that users can only invoke the task via the command line, either in a script or at the prompt in the Console view. (The root cause is that the Task View, and ToolRegistry, require a primary input).
  There were two such tasks in the core HIPE software: pause and resume, both in the ia.toolbox.util package, but they are now defined as plain functions.
Line: 185 to 185
  For example, this is a task whose primary input accepts String, Integer and Product:
Changed:
<
<
.public class CombinedTask extends Task {
>
>
public class CombinedTask extends Task {
  private static final String TASKNAME = "combined"; private static final String PRIME = "input"; /** Jython doc string */
Line: 245 to 245
 The framework cleans the data from parameters after executing a task.

Warning, important CHANGES FOR JYTHON CALLS TO TASKS THAT HAVE MULTIPLE OUTPUTS

Changed:
<
<
The way client code retrieves the outputs for tasks than have multiple output is changing. The current way was not Python-like and could bound to generate memory leaks (and even dependencies from previous executions in the case of IO (INOUT) parameters).
>
>
The way client code retrieves the outputs for tasks that have multiple outputs is changing. The current way was not Python-like and could generate memory leaks (and even dependencies from previous executions in the case of IO (INOUT) parameters).
 This will only affect tasks with multiple outputs. When the transition is complete, in the case of multiple outputs, all outputs will be returned as a list (and thus the signature will be cleaned just after execution in all cases). var1, var2 = myTask(). The migration to this new style has been staged as follows:
  • HIPE 11
    • To enable the new syntax you have to add __list__=True to the task call: var1, var2 = myTask(arg=1, ..., __list__=True). If you do not use this form the system will issue a warning every time the task is called. Note that this means that if you just put a variable in the left side of the assignment (var= myTask(arg=1, ..., __list__=True)), var will be a list with all outputs if there is more than one defined (remember that INOUTs are outputs too!).
  • HIPE 12
    • The default syntax will be the new one and you no longer need to add __list__=True. var1, var2 = myTask() will work as is (given that myTask has two outputs defined, of course).
Added:
>
>
  • HIPE 13 or later
    • __list__ is no longer a valid optional parameter in HIPE 13 or later.
 
Changed:
<
<
Note that tasks with multiple outputs will have more restrictions regarding changes in their outputs (order is fixed, adding or removing outputs may result in syntax errors ...). If you want to keep the flexibility to evolve your task it is recommended that you evaluate moving to a task with just one compound output. The best time to do it is now (HIPE 11 development), as users will have to modify their calls, anyway. Also note that it is impossible for the task framework to know how the task has been called wrt the left side of an assignment (the framework just 'sees' the right hand side, i.e. see INFO Task perform: [Full Call] log messages).
>
>
Note that tasks with multiple outputs will have more restrictions regarding changes in their outputs (order is fixed, adding or removing outputs may result in syntax errors ...). If you want to keep the flexibility to evolve your task it is recommended that you evaluate moving to a task with just one compound output. The best time to do it was during HIPE 11 development but it is never too late. Also note that it is impossible for the task framework to know how the task has been called with respect to the left side of an assignment (the framework just 'sees' the right hand side, i.e. see INFO Task perform: [Full Call] log messages).
 
Changed:
<
<
This is why most parameters are cleaned (reset to their default values) after a task is executed in Jython:
>
>
This is why most parameters are cleared (reset to their default values) after a task is executed in Jython:
 
Changed:
<
<
  • The first output parameter is cleaned after execution of the task. You should store the value of this parameter into a variable when you execute the task: var = myTask().
  • IN DEPRECATION: The second and additional output (or input-output) parameters are kept in memory until they are accessed, then they are cleaned: var2 = myTask.output2.
  • Input parameters are cleaned after the task is executed.
>
>
  • The first output parameter is cleared after execution of the task. You should store the value of this parameter into a variable when you execute the task: var = myTask().
  • IN DEPRECATION: The second and additional output (or input-output) parameters are kept in memory until they are accessed, then they are cleared: var2 = myTask.output2.
  • Input parameters are cleared after the task is executed.
 
Changed:
<
<
Try to use a single output parameter per task, so that there are no leftover values after a task execution. If you need to return multiple values you can use collections or define an appropriate type that contains all outputs (check herschel.ia.dataset.Metadata, a general Dictionary-like (map or hash) class).
>
>
Try to use a single output parameter per task, so that there are no leftover values after a task execution. If you need to return multiple values you can use collections or define an appropriate type that contains all outputs (check herschel.ia.dataset.Metadata, a general Dictionary-like class with map and hash implementations).
 
Changed:
<
<
If you execute tasks from Java code, there is no automatic cleanup. You need to clean the outputs manually like this:
>
>
If you execute tasks from Java code, there is no automatic cleanup. You need to reset the outputs manually like this:
 
myTask.perform();
Line: 271 to 273
 myTask.reset();
Changed:
<
<
Of course, if myTask is going to be garbage collected there is no need to clean it up. Note that the task instances already available in HIPE are not going to be garbage collected.
>
>
Of course, if myTask is going to be garbage collected there is no need to clear it up. Note that the task instances already available in HIPE are not going to be garbage collected.
 

Running a task in the HIPE Console view

Changed:
<
<
The Task framework offers different ways to execute the task as well: Calling the execute method using "positional parameters" and "named parameters". Suppose that a task expects three input parameters: One image parameter called 'img', one float indicating a rotation angle 'angle', and one boolean (true or false) called 'takeNeg' indicating whether the negative of the image shall be products.
>
>
The Task framework offers different ways to execute the task as well: Calling the execute method using "positional parameters" and "named parameters". Suppose that a task expects three input parameters: One image parameter called 'img', one float indicating a rotation angle 'angle', and one boolean (true or false) called 'takeNeg' indicating whether the negative of the image shall be produced.
  If you call the execute methods using positional parameters, then the simple order of the parameters tells the Task which is the image, which is the angle and which is the boolean. If you use named parameters, then you are allowed to use any order for the parameters, but every parameter you add after the first named one must be a named parameter too (If you were allowed to put positional parameters after a named one their positions would not be evident).
Line: 288 to 290
 Tasks should be included in HIPE such that they can be accessed directly from its user interface, in particular the Tasks View.

In short, including a task in HIPE comprises:

Changed:
<
<
  • Adding the task to HIPE registry. It is also possible to specify a specific category for your task, such that the task will be available for a specific type of variable.
>
>
  • Adding the task to HIPE registry. It is also possible to specify a specific category for your task, such that the task will be available for a specific type of variable.
 
  • Optionally setting validation requirements for a specific parameter, using a ParameterValidator. See Validating prime input.
Added:
>
>
  • Optionally provide a custom task dialog. HIPE automatically provides a default Task dialog panel for the registered tasks.
 
Changed:
<
<
  • Optionally provide a custom task dialog. HIPE automatically provides a default Task dialog panel for the registered tasks.

Please refer to the detailed instructions for a full explanation.

>
>
Please refer to the detailed instructions for a full explanation.
 

Handling exceptions in tasks

Changed:
<
<
If an error occurs during execution of the task, and the task cannot recover from it, an exception should be raised. This exception should be derived from TaskException (a RuntimeException ). The Task API does not declare any exception (Task.perform), so we can't use checked exceptions. If you must raise a checked exception, use the initCause() method of a TaskException (or subclass thereof).
>
>
If an error occurs during execution of the task, and the task cannot recover from it, an exception should be raised. This exception should be derived from TaskException (a RuntimeException ). The Task API does not declare any exception (Task.perform), so we can't use checked exceptions. If you must raise a checked exception, use the initCause() method of a TaskException (or subclass thereof).
 

Interrupting the execution of a task

Line: 363 to 361
  Now, when the task perform method is called, its Status is automatically changed to the RUNNING value and it will keep this value until its successful conclusion ( SUCCESS ), an error is found ( FAILED ) or it happens to be interrupted before finish (INTERRUPTED).
Changed:
<
<
This transitions between states are automatically registered into the Status field by the default implementation. The developer can use this information as a quick feedback to the user about the final result of the task. Also, the developer can update the StatusMessage field during the execution of the task as a way to notify the user of current stage into a time consuming task.
>
>
These transitions between states are automatically registered into the Status field by the default implementation. The developer can use this information as a quick feedback to the user about the final result of the task. Also, the developer can update the StatusMessage field during the execution of the task as a way to notify the user of current stage into a time consuming task.
 

Showing task execution progress

Changed:
<
<
The Progress field marks the advance in the execution of a given task as a integer value between 0 and 100 . This provide a way to show the user how a single task is performing and how much time is expected this task to last until its conclusion. The developer can update this value at any time during the execution process and the The Task package includes a bean to easily display this value on the screen as the typical progress bar.
>
>
The Progress field marks the advance in the execution of a given task as a integer value between 0 and 100 . This provide a way to show the user how a single task is performing and how much time is expected this task to last until its conclusion. The developer can update this value at any time during the execution process and the Task package includes a bean to easily display this value on the screen as the typical progress bar.
  The Progress parameter is accessible via the name Signature.PROGRESS and can be used as in the following example.
Line: 421 to 419
 

Task compliance checklist

Changed:
<
<
Developing a task that looks native involves quite a few steps. We have provided a list with the qualities a task should hold: ChecklistTask
>
>
Developing a task that looks native involves quite a few steps. We have provided a list with the qualities a task should hold: ChecklistTask (this is a TWiki page only for internal developers).
 

Revision 492014-02-14 - AlvarGarcia

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 17 to 17
 This page includes information on developing HIPE tasks.
Changed:
<
<
If you are just interested in running HIPE tasks, rather than developing them, read the Running tasks chapter of the Scripting and Data Mining guide.
>
>
If you are just interested in running HIPE tasks, rather than developing them, read the Running tasks chapter of the Scripting Guide.
  This page assumes some familiarity with task development. If you are just starting out, please read these tutorials on the HIPE community website:

Revision 482013-04-16 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 225 to 225
 }
Added:
>
>
In Jython:
        # ...
        p = TaskParameter('input', mandatory = 1, valueType = java.lang.Object)
        p.description = " A desc 4"
        p.parameterValidator= InstanceOfAnyValidator(String, Integer, Product)
        self.addTaskParameter(p)
        # ...

 
  • Use multiple optional parameters (not recommended, too many parameters)

Cleaning of parameters after execution

Revision 472013-02-22 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 182 to 182
 You cannot set multiple data types for a parameter, but you can achieve the same effect by using one of the following workarounds:

  • Use a more general data type, then define a validator doing additional checks.
Changed:
<
<
  • Register your task several times with different primary inputs. CURRENTLY BROKEN
  • Use multiple optional parameters.
>
>
For example, this is a task whose primary input accepts String, Integer and Product:
.public class CombinedTask extends Task {
        private static final String TASKNAME = "combined";
        private static final String PRIME = "input";
        /** Jython doc string */
        public static PyString __doc__;

        /**Constructor*/
        public CombinedTask() {
            super(TASKNAME);
            addTaskParameter(TaskUtil.buildParameter(PRIME, Object.class, INPUT, MANDATORY, null, NULL_NOT_ALLOWED,
                    "String, Integer or Product"));

            getParameter(PRIME).setParameterValidator(new ParameterValidatorAdapter() {
                @Override
                public void validate(Object value) throws ParameterValidationException {
                    if (value instanceof String || value instanceof Integer || value instanceof Product) {
                        return;
                    }
                    throw new ParameterValidationException("Not String, Integer or Product but " + value.getClass());
                }
            });
            setDescription("task to test object parameters");
            __doc__ = TaskUtil.makeDoc(this);
        }


        @Override
        public void execute() {
            Object prime = getValue(PRIME);
            if (prime instanceof String) {
                System.out.println("A String " + prime);
            } else if (prime instanceof Integer) {
                System.out.println("An Integer " + prime);
            } else {
                System.out.println("A Product " + prime);
            }
        }
}

  • Use multiple optional parameters (not recommended, too many parameters)
 

Cleaning of parameters after execution

Revision 462013-02-08 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 199 to 199
 
  • HIPE 12
    • The default syntax will be the new one and you no longer need to add __list__=True. var1, var2 = myTask() will work as is (given that myTask has two outputs defined, of course).
Changed:
<
<
Note that tasks with multiple outputs will have more restrictions regarding changes in their outputs (order is fixed, adding or removing outputs may result in syntax errors ...). If you want to keep the flexibility to evolve your task it is recommended that you evaluate moving to a task with just one compound output. The best time to do it is now (HIPE 11 development), as users will have to modify their calls, anyway. Also note that it is impossible for the task framework to know how the task has been called wrt the left side of an assignment (the framework just 'sees" the right hand side, i.e. see INFO Task perform: [Full Call] log messages).
>
>
Note that tasks with multiple outputs will have more restrictions regarding changes in their outputs (order is fixed, adding or removing outputs may result in syntax errors ...). If you want to keep the flexibility to evolve your task it is recommended that you evaluate moving to a task with just one compound output. The best time to do it is now (HIPE 11 development), as users will have to modify their calls, anyway. Also note that it is impossible for the task framework to know how the task has been called wrt the left side of an assignment (the framework just 'sees' the right hand side, i.e. see INFO Task perform: [Full Call] log messages).
  This is why most parameters are cleaned (reset to their default values) after a task is executed in Jython:

Revision 452013-02-07 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 192 to 192
  Warning, important CHANGES FOR JYTHON CALLS TO TASKS THAT HAVE MULTIPLE OUTPUTS
The way client code retrieves the outputs for tasks than have multiple output is changing. The current way was not Python-like and could bound to generate memory leaks (and even dependencies from previous executions in the case of IO (INOUT) parameters).
Changed:
<
<
This will only affect tasks with multiple outputs. When the transition is complete, in the case of multiple outputs, all outputs will be returned as a list (and thus the signature will be cleaned just after execution in all cases). var1, var2 = myTask()
>
>
This will only affect tasks with multiple outputs. When the transition is complete, in the case of multiple outputs, all outputs will be returned as a list (and thus the signature will be cleaned just after execution in all cases). var1, var2 = myTask(). The migration to this new style has been staged as follows:
  • HIPE 11
    • To enable the new syntax you have to add __list__=True to the task call: var1, var2 = myTask(arg=1, ..., __list__=True). If you do not use this form the system will issue a warning every time the task is called. Note that this means that if you just put a variable in the left side of the assignment (var= myTask(arg=1, ..., __list__=True)), var will be a list with all outputs if there is more than one defined (remember that INOUTs are outputs too!).
  • HIPE 12
    • The default syntax will be the new one and you no longer need to add __list__=True. var1, var2 = myTask() will work as is (given that myTask has two outputs defined, of course).

Note that tasks with multiple outputs will have more restrictions regarding changes in their outputs (order is fixed, adding or removing outputs may result in syntax errors ...). If you want to keep the flexibility to evolve your task it is recommended that you evaluate moving to a task with just one compound output. The best time to do it is now (HIPE 11 development), as users will have to modify their calls, anyway. Also note that it is impossible for the task framework to know how the task has been called wrt the left side of an assignment (the framework just 'sees" the right hand side, i.e. see INFO Task perform: [Full Call] log messages).

  This is why most parameters are cleaned (reset to their default values) after a task is executed in Jython:

Revision 442012-12-12 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 132 to 132
 
from java.lang import Integer
Changed:
<
<
class Transformer(Task):
>
>
class TransformerTask(Task):
 
Changed:
<
<
def __init__(self, name = 'Vector Transformer'):
>
>
def __init__(self, name = 'transformer'): Task.__init__(self, name)
  p = TaskParameter(name = 'input', valueType = array(Integer), mandatory = 1) self.addTaskParameter(p) p = TaskParameter( name = "result", valueType = TableDataset, type = OUT)
Line: 156 to 158
 # Test data sample = [10, 20, 30, 40] # Create the task:
Changed:
<
<
transform = Transformer()
>
>
transform = TransformerTask()
 # Execute the task: table = transform(sample) # Print: print table
Added:
>
>
print table[0]
 
Changed:
<
<

Tasks without input parameters

>
>

Tasks must have at least one input parameter

  You should not define a task without input parameters, because it will have very limited support in HIPE:
Line: 172 to 175
  This means that users can only invoke the task via the command line, either in a script or at the prompt in the Console view. (The root cause is that the Task View (and ToolRegistry) require a primary input).
Changed:
<
<
There are two such tasks in the core HIPE software: pause and resume, both in the ia.toolbox.util package. They are meant only to be used from the Jython editor/Console so, in this case, the limitations are fitting.
>
>
There were two such tasks in the core HIPE software: pause and resume, both in the ia.toolbox.util package, but they are now defined as plain functions.
 

Multiple data types for a parameter

You cannot set multiple data types for a parameter, but you can achieve the same effect by using one of the following workarounds:

  • Use a more general data type, then define a validator doing additional checks.
Changed:
<
<
  • Register your task several times with different primary inputs.
>
>
  • Register your task several times with different primary inputs. CURRENTLY BROKEN
 
  • Use multiple optional parameters.

Cleaning of parameters after execution

Changed:
<
<
The execution of a task should not depend on any previous executions. This is why most parameters are cleaned (reset to their default values) after a task is executed in Jython:
>
>
The execution of a task should not depend on any previous executions. Thus, your task class should not have member or class variables (everything should be done through parameters). The framework cleans the data from parameters after executing a task.

Warning, important CHANGES FOR JYTHON CALLS TO TASKS THAT HAVE MULTIPLE OUTPUTS
The way client code retrieves the outputs for tasks than have multiple output is changing. The current way was not Python-like and could bound to generate memory leaks (and even dependencies from previous executions in the case of IO (INOUT) parameters). This will only affect tasks with multiple outputs. When the transition is complete, in the case of multiple outputs, all outputs will be returned as a list (and thus the signature will be cleaned just after execution in all cases). var1, var2 = myTask()

This is why most parameters are cleaned (reset to their default values) after a task is executed in Jython:

 
  • The first output parameter is cleaned after execution of the task. You should store the value of this parameter into a variable when you execute the task: var = myTask().
Changed:
<
<
  • The second and additional output (or input-output) parameters are kept in memory until they are accessed, then they are cleaned: var2 = myTask.output2.
>
>
  • IN DEPRECATION: The second and additional output (or input-output) parameters are kept in memory until they are accessed, then they are cleaned: var2 = myTask.output2.
 
  • Input parameters are cleaned after the task is executed.
Changed:
<
<
Try to use a single output parameter per task, so that there are no leftover values after a task execution. If you need to return multiple values you can use collections or define an appropriate type that contains all outputs.
>
>
Try to use a single output parameter per task, so that there are no leftover values after a task execution. If you need to return multiple values you can use collections or define an appropriate type that contains all outputs (check herschel.ia.dataset.Metadata, a general Dictionary-like (map or hash) class).
  If you execute tasks from Java code, there is no automatic cleanup. You need to clean the outputs manually like this:
Line: 203 to 213
 Of course, if myTask is going to be garbage collected there is no need to clean it up. Note that the task instances already available in HIPE are not going to be garbage collected.
Deleted:
<
<
Warning, important CHANGES FOR JYTHON CALLS TO TASKS THAT HAVE MULTIPLE OUTPUTS
The way client code retrieves the outputs for tasks than have multiple output is going to change. The current way is not Python-like and is bound to generate memory leaks (and even dependencies from previous executions in the case of IO (INOUT) parameters).

Revision 432012-11-29 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 184 to 184
 

Cleaning of parameters after execution

Changed:
<
<
The execution of a task should depend as little as possible on any previous executions. This is why most parameters are cleaned (reset to their default values) after a task is executed in Jython:
>
>
The execution of a task should not depend on any previous executions. This is why most parameters are cleaned (reset to their default values) after a task is executed in Jython:
 
  • The first output parameter is cleaned after execution of the task. You should store the value of this parameter into a variable when you execute the task: var = myTask().
  • The second and additional output (or input-output) parameters are kept in memory until they are accessed, then they are cleaned: var2 = myTask.output2.
Line: 202 to 202
  Of course, if myTask is going to be garbage collected there is no need to clean it up. Note that the task instances already available in HIPE are not going to be garbage collected.
Added:
>
>
Warning, important CHANGES FOR JYTHON CALLS TO TASKS THAT HAVE MULTIPLE OUTPUTS
The way client code retrieves the outputs for tasks than have multiple output is going to change. The current way is not Python-like and is bound to generate memory leaks (and even dependencies from previous executions in the case of IO (INOUT) parameters).
 
>
>
If you call the execute methods using positional parameters, then the simple order of the parameters tells the Task which is the image, which is the angle and which is the boolean. If you use named parameters, then you are allowed to use any order for the parameters, but every parameter you add after the first named one must be a named parameter too (If you were allowed to put positional parameters after a named one their positions would not be evident).
 
Line: 230 to 234
 

Handling exceptions in tasks

Changed:
<
<
If an error occurs during execution of the task, and the task cannot recover from it, an exception should be raised. This exception should be derived from TaskException (a RuntimeException ). The Task API does not declare any exception (Task.perform), so we can't use checked exceptions. If you must raise a checked exception, use the initCause() method of a RuntimeException (or subclass thereof).
>
>
If an error occurs during execution of the task, and the task cannot recover from it, an exception should be raised. This exception should be derived from TaskException (a RuntimeException ). The Task API does not declare any exception (Task.perform), so we can't use checked exceptions. If you must raise a checked exception, use the initCause() method of a TaskException (or subclass thereof).
 
Line: 547 to 551
  setValue(Signature.PROGRESS, new Integer(((j*100)/_iterations))); // Also, this shortcut is valid for any subclass of Task: // setProgress((j*100)/_iterations)
Added:
>
>
// Additionally, the following code updates both progress and status message (preferred) advance((j*100)/_iterations, "iteration " + j+1 + " of " + _iterations);
  } }

Revision 422012-11-21 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 132 to 132
 
from java.lang import Integer
Changed:
<
<
class Transformer(JTask):
>
>
class Transformer(Task):
  def __init__(self, name = 'Vector Transformer'): p = TaskParameter(name = 'input', valueType = array(Integer), mandatory = 1)
Line: 230 to 230
 

Handling exceptions in tasks

Changed:
<
<
If an error occurs during execution of the task, and the task cannot recover from it, an exception should be raised. This exception should be derived from TaskException (a RuntimeException ). The JTask API does not declare any exception, so we can't use checked exceptions. If you must raise a checked exception, use the initCause() method of the RuntimeException.
>
>
If an error occurs during execution of the task, and the task cannot recover from it, an exception should be raised. This exception should be derived from TaskException (a RuntimeException ). The Task API does not declare any exception (Task.perform), so we can't use checked exceptions. If you must raise a checked exception, use the initCause() method of a RuntimeException (or subclass thereof).
 
Line: 373 to 373
 

Jython example

Changed:
<
<
class MyTask(JTask, java.awt.event.ActionListener, java.beans.PropertyChangeListener):
>
>
class MyTask(Task, java.awt.event.ActionListener, java.beans.PropertyChangeListener):
  def __init__(self, name='MyTask'):
Changed:
<
<
JTask.__init__(self, name)
>
>
Task.__init__(self, name)
  self.addTaskParameter(TaskParameter(valueType = array(TmSourcePacket), name="hk", mandatory = 1)) self.addTaskParameter(TaskParameter(valueType=Boolean, name =
Line: 415 to 415
 
  • Support the developer in providing easy syntax to handle data via task parameters.
Changed:
<
<
class BrowseHk(JTask, PropertyChangeListener):
>
>
class BrowseHk(Task, PropertyChangeListener):
  def __init__(self, name = 'browser'):
Changed:
<
<
JTask.__init__(self, name, developerAccessMode = 1)
>
>
Task.__init__(self, name, developerAccessMode = 1)
  self.__dict__['apk'] = AccessHk() self.__dict__['dpk'] = DisplayParam() self.apk.getParameter('result').addPropertyChangeListener(self)

Revision 412012-10-30 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->
Line: 219 to 219
  In short, including a task in HIPE comprises:
  • Adding the task to HIPE registry. It is also possible to specify a specific category for your task, such that the task will be available for a specific type of variable.
Changed:
<
<
  • Optionally setting validation requirements for a specific parameter, using a ParameterValidator. See Prime input validation.
>
>
  • Optionally setting validation requirements for a specific parameter, using a ParameterValidator. See Validating prime input.
 
  • Optionally provide a custom task dialog. HIPE automatically provides a default Task dialog panel for the registered tasks.

Please refer to the detailed instructions for a full explanation.

Revision 402012-10-19 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
Added:
>
>
<-- ANALYTICS CODE - DO NOT EDIT -->
<-- Google Analytics script BEGIN -->
<-- Google Analytics script END -->

<-- END OF ANALYTICS CODE -->
 
<-- 
  • Set TOPICTITLE = Writing tasks
-->
Line: 600 to 603
 
<-- END OF COMMENT BOX CODE -->

Changed:
<
<
META FILEATTACHMENT attachment="TaskTooltip.png" attr="" comment="Example of task tooltip" date="1272960712" name="TaskTooltip.png" path="TaskTooltip.png" size="2098" stream="TaskTooltip.png" user="Main.DavideRizzo" version="1"
>
>
META FILEATTACHMENT attr="" autoattached="1" comment="Example of task tooltip" date="1272960713" name="TaskTooltip.png" path="TaskTooltip.png" size="2098" user="Main.DavideRizzo" version="1"
META FILEATTACHMENT attr="h" autoattached="1" comment="Script for Google Analytics" date="1350658191" name="GoogleAnalytics.txt" path="GoogleAnalytics.txt" size="549" user="Main.DavideRizzo" version="1"

Revision 392012-09-12 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 382012-05-14 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 372012-05-14 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 362012-03-27 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 352012-03-08 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 342012-03-07 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 332012-03-06 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 322011-11-29 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
Deleted:
<
<

Using a preprocessor: Preamble

The preamble allows us to do some preprocessing on our data. For example, our average function calculate the averages of the columns of a table. But what if we wanted our task to calculate the average of two one-dimensional arrays of numbers? We can write a Task to takes two of these vectors as input and use the preamble to create a table, that has these two vectors as columns.

The below example illustrates this. Note that we first invoke the preamble from our parent task (JTask) to guarantee that our needed parameters have a value before putting them into the table.

class AverageArray(JTask):
    # Creation method
    def __init__(self,name = "averageArray"):
        p = TaskParameter("vector1",valueType = PyList, mandatory = 1)
        self.addTaskParameter(p)
        p = TaskParameter("vector2",valueType = PyList, mandatory = 1)
        self.addTaskParameter(p)
        p = TaskParameter("result",valueType = Double1d, type = OUT)
        self.addTaskParameter(p)
        # Create an internal variable table which is our TableDataset
        self.__dict__['table'] = TableDataset()
        
    def preamble(self):
        # In the preamble we do the store the two vectors in  the table
        JTask.preamble(self) # the first statement must always be a call to the parent preamble (preamble chain)
        self.table["0"] = Column(Double1d(self.vector1))
        self.table["1"] = Column(Double1d(self.vector2))
        
    def execute(self):
        self.result = average(self.table)

Note that the execute method is identical to the original Task. The following can be used to try this Task:

sample1 = [1.0, 2.0, 3.0, 4.0]
sample2 = [3.0, 4.0, 5.0, 6.0]
avg = AdaptAverage()

# Invocation using positional parameter
avg(sample1,sample2)
print avg.result
 

Revision 312011-11-18 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 302011-10-21 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 292011-10-21 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 282011-10-13 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
 

Using a preprocessor: Preamble

Line: 286 to 288
 }
Deleted:
<
<

Cleaning task output

If you use tasks from Jython code, when you access the outputs they are cleaned up automatically. On the other hand, when you call a task from Java code, you need to clean the outputs manually like this:

t.perform();
t. ... // get t results
t.reset();

Of course, if t is going to be garbage collected there is no need to clean it up. Note that the task instances already available in HIPE are not going to be garbage collected.

 

Tasks and tools involving products and datasets

For tasks that deal with products and datasets, the users (astronomers and calibration scientists) should not be required to perform type conversions between products and datasets. If such conversions are required, they should be dealt with by the software. This in part stems from the fact that manipulation of datasets loses any associated history. It is recommended that all tasks (and tools) should work with, and save outputs as, products.

Revision 272011-09-16 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 262011-09-16 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 252011-09-16 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 242011-09-16 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 232011-09-14 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 222011-07-19 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Revision 212011-06-24 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"
Changed:
<
<

Writing Tasks

>
>
<-- 
  • Set TOPICTITLE = Writing tasks
-->

PDF Version Portrait Landscape

Help Did you spot something wrong or missing on this page? If you have an account on this TWiki, you can fix it yourself by editing the page. If you don't have an account, you can send a message to the Editorial Board to tell us about it. Thank you in advance!

Writing tasks

 

Tasks are data processors. You can use a task to manipulate a data product, such as an image, or to convert data from one kind into another, for instance extracting a spectrum from a cube.

Line: 946 to 954
  Developing a task that looks native involves quite a few steps. We have provided a list with the qualities a task should hold: ChecklistTask
Added:
>
>
Please add your comments!
<--/commentPlugin-->
 
<--  
-->

Revision 192010-12-16 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 498 to 498
 

Guidelines for Writing Tasks

Changed:
<
<
This section provides some general guidelines, that are expected to be useful also for simple tasks.
>
>
This section provides some general guidelines, that are expected to be useful also for simple tasks. Make sure you also check the javadoc of TaskUtil for helper functions.
 

Exceptions

Revision 182010-12-16 - JulioRamirez

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 939 to 939
 Parameters that are facultative must have been given a default value before the task is executed, failure to do so will provoke an exception when parameters values are checked in the preamble. Usually, the default value for a parameter is provided by the task implementer, not the end user. Parameters requiring a value from the user should be tagged as mandatory .
Deleted:
<
<

Task documentation

How to get help about a task from the Console:

  • print taskName long, 1 paragraph per parameter task autodocumentation
  • print bg.__doc__ if here doc defined it shows it, else if jtags documentation present shows it, else show a short 1 line per parameter autodocumentation

How to get help about a task from the GUI:

  • Open the task GUI: parameter labels describe the parameters, modifier editors signal if current data is valid for the parameters
  • Right click on the Task View node, open URM for the task documentation
 

Task Compliance Checklist

Developing a task that looks native involves quite a few steps. We have provided a list with the qualities a task should hold: ChecklistTask

Revision 172010-12-16 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 939 to 939
 Parameters that are facultative must have been given a default value before the task is executed, failure to do so will provoke an exception when parameters values are checked in the preamble. Usually, the default value for a parameter is provided by the task implementer, not the end user. Parameters requiring a value from the user should be tagged as mandatory .
Deleted:
<
<

The TaskUtil utility class

This class ia a one place stop for auxiliary functions to help you in building tasks. As of 23 Aug 2010, it contains the following functions:

  • Auxiliary functions for constructing the signature:
    TaskUtil.addParameter(Task, String, Class<?>, Type, boolean, Object, boolean, String)
  • Auxiliary functions for task naming:
    TaskUtil.getDefaultName(Task)
     TaskUtil.isValidName(String)
  • Auxiliary functions for task documentation:
    TaskUtil.makeDoc(TaskApi, String, String, String)
     TaskUtil.makeHtmlDesc(TaskApi)
    
  • Auxiliary functions for Jython code generation:
    TaskUtil.toJython(Double)
     TaskUtil.toJython(Float)

More will be added as the need arises.

 

Task documentation

How to get help about a task from the Console:

Revision 162010-12-16 - JulioRamirez

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 954 to 954
 More will be added as the need arises.

Task documentation

Deleted:
<
<
Any task that should be included for other to use should be properly documented. there are multiple documentation requirements for tasks. We try to help the task implementor, but we cannot automate many things. The different documentation requirements are:
  • Provide a proper name to your task This will be used in Task View, by the interpreter to execute your tasks, by documentation in general to refer to your task ...
  • Provide javadoc comments This is used to generate the Java API, see http://java.sun.com/j2se/javadoc/writingdoccomments/
  • Provide jtags This is used to generate the URM, see http://herschel.be/twiki/bin/view/Hcss/JTags
  • Register your task in the proper categories This is used in the Task View's tree, see http://www.herschel.be/twiki/bin/view/Hcss/UrmCategories
  • Document your task parameters This is used to generate default documentation for print _taskname_ and print _taskname.paramname_ , and in the GUI for parameter labels' tooltips.
  • Use a doc static member This is used as output for print _taskname.__doc__
  How to get help about a task from the Console:
Added:
>
>
 
  • print taskName long, 1 paragraph per parameter task autodocumentation
  • print bg.__doc__ if here doc defined it shows it, else if jtags documentation present shows it, else show a short 1 line per parameter autodocumentation
Line: 971 to 966
 
  • Right click on the Task View node, open URM for the task documentation

Task Compliance Checklist

Deleted:
<
<
Developing a task that looks "native" takes time and involves quite a few steps. To help you comply with all requirements, we offer a (high level) list of common deficiencies and mistakes to be taken into account. This is not a MUST comply list (yet):
 
Changed:
<
<
ChecklistTask
>
>
Developing a task that looks native involves quite a few steps. We have provided a list with the qualities a task should hold: ChecklistTask
 

Revision 152010-12-15 - JulioRamirez

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 970 to 970
 
  • Open the task GUI: parameter labels describe the parameters, modifier editors signal if current data is valid for the parameters
  • Right click on the Task View node, open URM for the task documentation

Added:
>
>

Task Compliance Checklist

Developing a task that looks "native" takes time and involves quite a few steps. To help you comply with all requirements, we offer a (high level) list of common deficiencies and mistakes to be taken into account. This is not a MUST comply list (yet):

ChecklistTask

 
<--  
-->

Revision 142010-08-30 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 962 to 962
 
  • Document your task parameters This is used to generate default documentation for print _taskname_ and print _taskname.paramname_ , and in the GUI for parameter labels' tooltips.
  • Use a doc static member This is used as output for print _taskname.__doc__
Changed:
<
<
>
>
How to get help about a task from the Console:
  • print taskName long, 1 paragraph per parameter task autodocumentation
  • print bg.__doc__ if here doc defined it shows it, else if jtags documentation present shows it, else show a short 1 line per parameter autodocumentation

How to get help about a task from the GUI:

  • Open the task GUI: parameter labels describe the parameters, modifier editors signal if current data is valid for the parameters
  • Right click on the Task View node, open URM for the task documentation
 

Revision 132010-08-27 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 957 to 957
 Any task that should be included for other to use should be properly documented. there are multiple documentation requirements for tasks. We try to help the task implementor, but we cannot automate many things. The different documentation requirements are:
  • Provide a proper name to your task This will be used in Task View, by the interpreter to execute your tasks, by documentation in general to refer to your task ...
  • Provide javadoc comments This is used to generate the Java API, see http://java.sun.com/j2se/javadoc/writingdoccomments/
Changed:
<
<
>
>
 
  • Register your task in the proper categories This is used in the Task View's tree, see http://www.herschel.be/twiki/bin/view/Hcss/UrmCategories
  • Document your task parameters This is used to generate default documentation for print _taskname_ and print _taskname.paramname_ , and in the GUI for parameter labels' tooltips.
  • Use a doc static member This is used as output for print _taskname.__doc__

Revision 122010-08-26 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 960 to 960
 
Changed:
<
<
  • Use a doc static member This is used in the Task View to generate tooltips, as output for print _taskname.__doc__, will be used in the future for code completion
>
>
  • Use a doc static member This is used as output for print _taskname.__doc__
 
Deleted:
<
<

How to fill the __doc__ static member

From Dive Into Python: Many Python IDEs use the doc string to provide context-sensitive documentation, so that when you type a function name, its doc string appears as a tooltip. This can be incredibly helpful, but it's only as good as the doc strings you write.

OBSOLETE: rewrite Task provides a default signature string (Task#getSignatureString()) that is either extracted from your __doc__ string or generated from the current signature of the task. This string is better than nothing, but the task framework is not rich enough to be able to provide the best string possible, only the task creator can. For Python functions, it is enough with a one line explanation and futher into after a blank line (see http://docs.python.org/tutorial/controlflow.html#SECTION006750000000000000000), the format we autogenerate for tasks differs:

  • 1st block signature string (automated)
  • 2nd block text description of task
  • 3rd block parameter description (automated)

An implementation of the __doc__ string in your task:

    public static PyString __doc__ ;

    public MyTask() {
       super(TASKNAME);
       makeSignature();
       __doc__ = TaskUtil.makeDoc(this, null, 
                "Where all parameters are strings, except overwrite, archive is the source file and dirout a (possibly not existing) directory",
               null);
       }
    }

Here, you are using the default string, but if it does not generate the signature string that you want, you should write it by hand:


    public MyTask() {
       super(TASKNAME);
       makeSignature();
       __doc__ = TaskUtil.makeDoc(this, "<v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time> [, <ephemerides>, <corrections>]); <ra> = radialVelocity.ra; <dec> = radialVelocity.dec", 
                "Where all parameters are strings, except overwrite, archive is the source file and dirout a (possibly not existing) directory",
               null);
       }
    }

The format of the doc string of a task is TENTATIVELY as follows: (TO BE REVIEWED)

  • each symbolic name (arguments, return variables) that the user can change is surrounded by < and > and uses the corresponding parameter name :
    <v> = t( <arg>)
  • each task argument appears in the signature order (in or input output), separated by commas:
    t( <arg1>, <arg2>, <arg3>)
  • each optional argument is surrounded by [ and ] (but they may be grouped together):
    taskName( <time> [, <ephemerides>, <corrections>])
  • to express optionality you can use ( and ) | as separator:
    <v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time>)
    This means one of storage, context or pointing & orbit must be used.
  • for addittional output parameters, sentences can be added, of the form:
    ; <out2> = t.out2
    where out2 is the name of the (in)out parameter

A sample __doc__ string follows:

<v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time> [, <ephemerides>, <corrections>]); <ra> = radialVelocity.ra; <dec> = radialVelocity.dec

Returns S/C radial velocity (signed) projection in the pointing direction (in km/s) at t, (also ra and dec of the direction)
 

Revision 112010-08-24 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 589 to 589
 To sum this up, a stateless function can be used both in static and dynamic environment. It is advantageous, when possible, to write stateless functions.
Added:
>
>

Doing incremental calculations

If you want to support incremental calculations then client code has to hold all memory between calls to the auxiliary functional elements (wether they are pure functions or tasks). An example follows. Lets suppose you want to use an average task (or function) that supports incremental calculations. You do not "know" beforehand how many items you are going to average and you don't want to repeat already done calculations every time you get a new value to add to the average. To calculate incremental averages you can use the following recurrence relation:
 
Added:
>
>
M(1) = x(1), M(k) = M(k-1) + (x(k) - M(k-1)) / k
 
Added:
>
>
where
  • M(i) is the mean of the first i elements
  • x(i) is the i-th element
 
Added:
>
>
The function would look like this:
def inc_avg(element, oldavg, count):
      return oldavg + (element - oldavg) / float(count)

Usage will require that client code keeps track of auxiliary aggregates (average and count):

mean = 0.0
count = 1
mean = inc_avg(5, mean, count)

count += 1
mean = inc_avg(3, mean, count)

...

count += 1
mean = inc_avg(2, mean, count)

A way of transforming inc_avg into a proper task is sketched as follows:

avg = inc_avg(element, oldavg, count)

where all parameters are float (Double in Java):
* element : (IN mandatory) the next item to add
* oldavg : (IN mandatory) the current average
* count : (IN mandatory) the current item order
* avg: (OUT) the new average
 
Added:
>
>
And usage would be exactly the same as with the Jython function.
 

How to use GUIs with your tasks

Revision 102010-08-24 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 928 to 928
 From Dive Into Python: Many Python IDEs use the doc string to provide context-sensitive documentation, so that when you type a function name, its doc string appears as a tooltip. This can be incredibly helpful, but it's only as good as the doc strings you write.
Added:
>
>
OBSOLETE: rewrite
 Task provides a default signature string (Task#getSignatureString()) that is either extracted from your __doc__ string or generated from the current signature of the task. This string is better than nothing, but the task framework is not rich enough to be able to provide the best string possible, only the task creator can. For Python functions, it is enough with a one line explanation and futher into after a blank line (see http://docs.python.org/tutorial/controlflow.html#SECTION006750000000000000000), the format we autogenerate for tasks differs:
  • 1st block signature string (automated)

Revision 92010-08-23 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 819 to 819
 

Advanced Features

Changed:
<
<
We describe here some features that may not of interest to simple tasks.
>
>
We describe here some features that may not be of interest to simple tasks.
 

User level feedback

Line: 899 to 899
  Parameters that are facultative must have been given a default value before the task is executed, failure to do so will provoke an exception when parameters values are checked in the preamble. Usually, the default value for a parameter is provided by the task implementer, not the end user. Parameters requiring a value from the user should be tagged as mandatory .
Added:
>
>

The TaskUtil utility class

This class ia a one place stop for auxiliary functions to help you in building tasks. As of 23 Aug 2010, it contains the following functions:

  • Auxiliary functions for constructing the signature:
    TaskUtil.addParameter(Task, String, Class<?>, Type, boolean, Object, boolean, String)
  • Auxiliary functions for task naming:
    TaskUtil.getDefaultName(Task)
     TaskUtil.isValidName(String)
  • Auxiliary functions for task documentation:
    TaskUtil.makeDoc(TaskApi, String, String, String)
     TaskUtil.makeHtmlDesc(TaskApi)
    
  • Auxiliary functions for Jython code generation:
    TaskUtil.toJython(Double)
     TaskUtil.toJython(Float)

More will be added as the need arises.

 

Task documentation

Any task that should be included for other to use should be properly documented. there are multiple documentation requirements for tasks. We try to help the task implementor, but we cannot automate many things. The different documentation requirements are:
  • Provide a proper name to your task This will be used in Task View, by the interpreter to execute your tasks, by documentation in general to refer to your task ...
Line: 908 to 923
 
  • Document your task parameters This is used to generate default documentation for print _taskname_ and print _taskname.paramname_ , and in the GUI for parameter labels' tooltips.
  • Use a doc static member This is used in the Task View to generate tooltips, as output for print _taskname.__doc__, will be used in the future for code completion
Deleted:
<
<

How to fill the __doc__ static member

 
Added:
>
>

How to fill the __doc__ static member

 From Dive Into Python: Many Python IDEs use the doc string to provide context-sensitive documentation, so that when you type a function name, its doc string appears as a tooltip. This can be incredibly helpful, but it's only as good as the doc strings you write.

Task provides a default signature string (Task#getSignatureString()) that is either extracted from your __doc__ string or generated from the current signature of the task. This string is better than nothing, but the task framework is not rich enough to be able to provide the best string possible, only the task creator can.

Changed:
<
<
While for Python functions, it is enough with a one line explanation and futher into after a blank line (see http://docs.python.org/tutorial/controlflow.html#SECTION006750000000000000000), the format we use for tasks differs:
  • 1st line signature string
  • 2nd line typically blank
  • 3rd and following explanation and further info.

The format of the doc string of a task is as follows:

  • each symbolic name (arguments, return variables) that the user can change is surrounded by < and > and uses the corresponding parameter name :
    <v> = t( <arg>)
  • each task argument appears in the signature order (in or input output), separated by commas:
    t( <arg1>, <arg2>, <arg3>)
  • each optional argument is surrounded by [ and ] (but they may be grouped together):
    taskName( <time> [, <ephemerides>, <corrections>])
  • to express optionality you can use ( and ) | as separator:
    <v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time>)
    This means one of storage, context or pointing & orbit must be used.
  • for addittional output parameters, sentences can be added, of the form:
    ; <out2> = t.out2
    where out2 is the name of the (in)out parameter
>
>
For Python functions, it is enough with a one line explanation and futher into after a blank line (see http://docs.python.org/tutorial/controlflow.html#SECTION006750000000000000000), the format we autogenerate for tasks differs:
  • 1st block signature string (automated)
  • 2nd block text description of task
  • 3rd block parameter description (automated)
 
Changed:
<
<
A sample __doc__ string follows:
<v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time> [, <ephemerides>, <corrections>]); <ra> = radialVelocity.ra; <dec> = radialVelocity.dec

Returns S/C radial velocity (signed) projection in the pointing direction (in km/s) at t, (also ra and dec of the direction)

A first implementation of the __doc__ string in your task:

>
>
An implementation of the __doc__ string in your task:
  =
    public static PyString __doc__ ;
Line: 940 to 942
  public MyTask() { super(TASKNAME); makeSignature();
Changed:
<
<
if (doc == null) { //no need to sync doc = new PyString( getSignatureString(false) + "\n" + "\nmy short description of the task";
>
>
doc = TaskUtil.makeDoc(this, null, "Where all parameters are strings, except overwrite, archive is the source file and dirout a (possibly not existing) directory", null);
  } } =
Line: 950 to 952
 Here, you are using the default string, but if it does not generate the signature string that you want, you should write it by hand:

=

Deleted:
<
<
public static PyString doc = new PyString("=radialVelocity(( | | , ),
  public MyTask() { super(TASKNAME); makeSignature();
Added:
>
>
doc = TaskUtil.makeDoc(this, "=radialVelocity(( | | , ),
  } =
Changed:
<
<
Note: the __doc__ string requires a single line with the signature template because we cannot easily support enter in the Console prompt, nor can the user edit easily multiline blocks (this hard requirement may change in the future).
>
>
The format of the doc string of a task is TENTATIVELY as follows: (TO BE REVIEWED)
  • each symbolic name (arguments, return variables) that the user can change is surrounded by < and > and uses the corresponding parameter name :
    <v> = t( <arg>)
  • each task argument appears in the signature order (in or input output), separated by commas:
    t( <arg1>, <arg2>, <arg3>)
  • each optional argument is surrounded by [ and ] (but they may be grouped together):
    taskName( <time> [, <ephemerides>, <corrections>])
  • to express optionality you can use ( and ) | as separator:
    <v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time>)
    This means one of storage, context or pointing & orbit must be used.
  • for addittional output parameters, sentences can be added, of the form:
    ; <out2> = t.out2
    where out2 is the name of the (in)out parameter

A sample __doc__ string follows:

<v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time> [, <ephemerides>, <corrections>]); <ra> = radialVelocity.ra; <dec> = radialVelocity.dec

Returns S/C radial velocity (signed) projection in the pointing direction (in km/s) at t, (also ra and dec of the direction)
 

Revision 72010-06-29 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 906 to 906
 
  • Document your task parameters This is used to generate default documentation for print _taskname_ and print _taskname.paramname_ , and in the GUI for parameter labels' tooltips.
  • Use a doc static member This is used in the Task View to generate tooltips, as output for print _taskname.__doc__, will be used in the future for code completion
Changed:
<
<

How to fill the doc static member

>
>

How to fill the __doc__ static member

  From Dive Into Python:
Changed:
<
<
Many Python IDEs use the doc string to provide context-sensitive documentation, so that when you type a function name, its doc string appears as a tooltip. This can be incredibly helpful, but it's only as good as the doc strings you write._
>
>
Many Python IDEs use the doc string to provide context-sensitive documentation, so that when you type a function name, its doc string appears as a tooltip. This can be incredibly helpful, but it's only as good as the doc strings you write.
 
Changed:
<
<
Task provides a default signature string (Task#getSignatureString()) that is either extracted from your doc string or generated from the current signature of the task. This string is better than nothing, but the task framework is not rich enough to be able to provide the best string possible, only the task creator can.
>
>
Task provides a default signature string (Task#getSignatureString()) that is either extracted from your __doc__ string or generated from the current signature of the task. This string is better than nothing, but the task framework is not rich enough to be able to provide the best string possible, only the task creator can.
 While for Python functions, it is enough with a one line explanation and futher into after a blank line (see http://docs.python.org/tutorial/controlflow.html#SECTION006750000000000000000), the format we use for tasks differs: * 1st line signature string * 2nd line typically blank * 3rd and following explanation and further info.
Changed:
<
<
A sample doc string follows
>
>
The format of the doc string of a task is as follows:
  • each symbolic name (arguments, return variables) that the user can change is surrounded by < and > and uses the corresponding parameter name :
    <v> = t( <arg>)
  • each task argument appears in the signature order (in or input output), separated by commas:
    t( <arg1>, <arg2>, <arg3>)
  • each optional argument is surrounded by [ and ] (but they may be grouped together):
    taskName( <time> [, <ephemerides>, <corrections>])
  • to express optionality you can use ( and ) | as separator:
    <v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time>)
    This means one of storage, context or pointing & orbit must be used.
  • for addittional output parameters, sentences can be added, of the form:
    ; <out2> = t.out2
    where out2 is the name of the (in)out parameter

A sample __doc__ string follows:

<v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time> [, <ephemerides>, <corrections>]); <ra> = radialVelocity.ra; <dec> = radialVelocity.dec

Returns S/C radial velocity (signed) projection in the pointing direction (in km/s) at t, (also ra and dec of the direction)
 
Added:
>
>
A first implementation of the __doc__ string in your task:

    public static PyString __doc__ ;

    public MyTask() {
       super(TASKNAME);
       makeSignature();
       if (__doc__ == null) { //no need to sync
           __doc__ = new PyString( getSignatureString(false) + "\n" + 
                          "\nmy short description of the task";
       }
    }

Here, you are using the default string, but if it does not generate the signature string that you want, you should write it by hand:

    public static PyString __doc__ = new PyString("<v>=radialVelocity((<storage> | <context> | <pointing>, <orbit>), <time> [, <ephemerides>, <corrections>]); <ra> = radialVelocity.ra; <dec> = radialVelocity.dec\n" +
       "\nmy short description of the task";

    public MyTask() {
       super(TASKNAME);
       makeSignature();
    }

Note: the __doc__ string requires a single line with the signature template because we cannot easily support enter in the Console prompt, nor can the user edit easily multiline blocks (this hard requirement may change in the future).

 

Revision 62010-06-29 - JavierDiaz

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 897 to 897
  Parameters that are facultative must have been given a default value before the task is executed, failure to do so will provoke an exception when parameters values are checked in the preamble. Usually, the default value for a parameter is provided by the task implementer, not the end user. Parameters requiring a value from the user should be tagged as mandatory .
Added:
>
>

Task documentation

Any task that should be included for other to use should be properly documented. there are multiple documentation requirements for tasks. We try to help the task implementor, but we cannot automate many things. The different documentation requirements are:
  • Provide a proper name to your task This will be used in Task View, by the interpreter to execute your tasks, by documentation in general to refer to your task ...
  • Provide javadoc comments This is used to generate the Java API, see http://java.sun.com/j2se/javadoc/writingdoccomments/
  • Provide jtags This is used to generate the URM, see http://herschel.be/twiki/bin/view/Hcss/DmChapter10#JTags
  • Register your task in the proper categories This is used in the Task View's tree, see http://www.herschel.be/twiki/bin/view/Hcss/UrmCategories
  • Document your task parameters This is used to generate default documentation for print _taskname_ and print _taskname.paramname_ , and in the GUI for parameter labels' tooltips.
  • Use a doc static member This is used in the Task View to generate tooltips, as output for print _taskname.__doc__, will be used in the future for code completion

How to fill the doc static member

From Dive Into Python: Many Python IDEs use the doc string to provide context-sensitive documentation, so that when you type a function name, its doc string appears as a tooltip. This can be incredibly helpful, but it's only as good as the doc strings you write._

Task provides a default signature string (Task#getSignatureString()) that is either extracted from your doc string or generated from the current signature of the task. This string is better than nothing, but the task framework is not rich enough to be able to provide the best string possible, only the task creator can. While for Python functions, it is enough with a one line explanation and futher into after a blank line (see http://docs.python.org/tutorial/controlflow.html#SECTION006750000000000000000), the format we use for tasks differs: * 1st line signature string * 2nd line typically blank * 3rd and following explanation and further info.

A sample doc string follows

 
<--  
-->

Revision 52010-06-09 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 728 to 728
 

Re-use of view components outside the task

Changed:
<
<
To support the re-use of tasks as well as the related views, I give the following example: We have a AccessHk task as well as a DisplayParam task which we want to combine in a BrowseHk task, where we re-use the view from the AccessHk task to setup the query, and the view from the DisplayParam which allows to plot select a parameter. The BrowseHk will therefor only contain the glue to combine those views into a higher level task. We define the BrowseHk as a task in order to adopt to the task API, to
>
>
To support the re-use of tasks as well as the related views, I give the following example: We have a AccessHk task as well as a DisplayParam task which we want to combine in a BrowseHk task, where we re-use the view from the AccessHk task to setup the query, and the view from the DisplayParam which allows to plot select a parameter. The BrowseHk will therefor only contain the glue to combine those views into a higher level task. We define the BrowseHk as a task in order to adopt to the task API, to achieve the following:
 
  • Allow the user to pass: a) an "obsid" as default entry for the task's view, and b) allow the user to retrieve back data into its jide session as one is used to within the task concept
Changed:
<
<
  • To support the developer in providing easy syntax to handle data via task parameters.
>
>
  • Support the developer in providing easy syntax to handle data via task parameters.
 
class BrowseHk(JTask, PropertyChangeListener):

Revision 42010-05-17 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 897 to 897
  Parameters that are facultative must have been given a default value before the task is executed, failure to do so will provoke an exception when parameters values are checked in the preamble. Usually, the default value for a parameter is provided by the task implementer, not the end user. Parameters requiring a value from the user should be tagged as mandatory .
Added:
>
>
<--  
-->
 
META FILEATTACHMENT attachment="TaskTooltip.png" attr="" comment="Example of task tooltip" date="1272960712" name="TaskTooltip.png" path="TaskTooltip.png" size="2098" stream="TaskTooltip.png" user="Main.DavideRizzo" version="1"

Revision 32010-05-07 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 36 to 36
 
Deleted:
<
<
# Import data structures from java classes from herschel.ia.numeric.all import * from herschel.ia.dataset.all import *
 #--------------------------------------------------
Changed:
<
<
# average function # Takes a TableDataSet as input
>
>
# Average function # Takes a TableDataset as input
 # Returns a Double1d (1D array of real numbers) # in which each row is the average of the values # in the input table columns #--------------------------------------------------
Deleted:
<
<
#routine for calculating the average
 def average(table): columns = table.columnCount divider = 1.0 / columns
Line: 60 to 55
 You can use the following functions to try it out:
Changed:
<
<
# Function for creating a table with some test data
>
>
# Function to create a table for testing the average function.
 # The table will be like this: # 0 1 2 3 4 5 # 1 2 3 4 5 6
Line: 68 to 63
 # 3 4 5 6 7 8 # 4 5 6 7 8 9 def createTable():
Changed:
<
<
#create array x (0.0, 1.0, 2.0, 3.0, 4.0)
>
>
# Create array x (0.0, 1.0, 2.0, 3.0, 4.0)
  x = Double1d.range(5) columns = 5
Changed:
<
<
#create an empty table with a name table = TableDataset(description = "a test table") #iterate for the the number of columns to fill up the table
>
>
# Create an empty table with a name table = TableDataset(description = "A test table") # Iterate for the the number of columns to fill up the table
  for column in range(0,columns): table["%i" % column] = Column(x) x = x + 1
Changed:
<
<
#return the result, a table called 'table'
>
>
# Return the result, a table called 'table'
  return table
Added:
>
>
Finally, this function creates the table and executes the average function:
 # Function for executing the method def testAverage():
Changed:
<
<
# create the table
>
>
# Create the table
  table = createTable()
Changed:
<
<
# get the average and put it into an array called 'result'
>
>
# Get the average and put it into an array called 'result'
  result = average(table)
Changed:
<
<
# print the result
>
>
# Print the result
  print 'result', result
Changed:
<
<
The result of typing testAverage() on the Console view of HIPE is:
>
>
The result of typing testAverage() in the Console view of HIPE is:
 
result [2.0,3.0,4.0,5.0,6.0]
Added:
>
>

Creating the Average task

 
Changed:
<
<

Creating the Task: Average

To turn our average algorithm into a task we need to wrap the algorithm into a piece of code which adapts it to form a task. Our current function has no input parameters (it is a parameterless execute method). We need to wrap it so that we have the appropriate input parameters (so it becomes a parameterized method).

>
>
We will name the task itself Average. Every task is a class, and by convention class names are capitalized nouns. Also, every task extends the JTask class.
 
Changed:
<
<
We will name the task itself Average (a task is a class, it is callable from the command line, and by convention class names are capitalized nouns). In our Average class we have no needs other than setting up a signature and calling the average function as part of its execution.

Every Task must extend the JTask, so the first step in creating our task class is to subclass JTask.

If you check the chapter about writing a Task in Java, you will see that the class in Jython looks slightly different. This is due to differences in implementation details between Jython and Java, and cannot be avoided. To extend JTask, only the following is required:

>
>
Here is the code of the Average task:
 
# Import task framework classes.
Line: 153 to 143
 
  • The second and additional output (or input-output) parameters will be kept in memory until they are accessed, then they will be cleaned: var2 = task.output2 .
  • Input parameters are cleaned after execution of the task.
Changed:
<
<
We recommend to use only one output paramater per task, so that no state is kept between task invocations. If you need to return multiple values you can use collections or define an appropiate type that contains all outputs.
>
>
We recommend to use only one output paramater per task, so that no state is kept between task invocations. If you need to return multiple values you can use collections or define an appropriate type that contains all outputs.
 
Changed:
<
<

Running the Task from Jython

>
>

Running the task in the HIPE Console view

 
Changed:
<
<
The following commands can be used to run the Average Task from the HIPE Console. We shows three ways of running the task:
>
>
The following commands show how to run the Average Task from the HIPE Console view. We use the createTable function defined previously:
 
Deleted:
<
<
from herschel.ia.dataset.all import * from herschel.ia.numeric.all import * from Average import Average

x = Double1d.range(5) columns = 5 data = TableDataset(description = "a test table") for column in range(columns): data["%i" % column] = Column(x) x = x + 1

 # Create an instance of the Task avg = Average()
Changed:
<
<
# Print the usage information of the task (the "Signature")
>
>
# Print the usage information of the task
 info('avg')

# Set the input parameter 'table'

Changed:
<
<
avg.table = data
>
>
avg.table = createTable()

# Execute the task and get the result avg.execute()

 calcResult = avg.result print 'result', calcResult
Line: 195 to 177
 avg(table = data)
Changed:
<
<

How To Write a Java Task

>
>

Writing a Java task

  This section describes how to turn a Java algorithm into a task. We assume here that you have read the preceding section about writing a Task in Jython.

Revision 22010-05-07 - DavideRizzo

Line: 1 to 1
 
META TOPICPARENT name="DpHipe"

Writing Tasks

Line: 8 to 8
 If you have an algorithm that does data processing, you can turn it into a task whether it is written in Jython or in Java. This topic explains how this is done.
Changed:
<
<

How does the Task Framework help?

The Task framework provides functionality in a Task superclass, which can be reused by the user's tasks. The Task superclass provides, for example:

  • Command line help, exposing available algorithms and how they should be called
  • Integration in HIPE: Tasks can be accessed and run using the HIPE GUI
  • Input parameter checking
  • History recording
  • A common look and feel or the user (fixed methods to execute, to get the output, etc.)
  • Re-usability: Tasks are the building blocks of pipelines, and complex tasks can be composed of other tasks
  • Modifiability: Because Task defines how to execute the algorithm and how to get the output, etc, the user can modify the algorithm, or change one algorithm for another, as long as the established Task rules are still followed

This has some similarities to the Interactive Reduction and Analysis Facility (IRAF) where tasks/programs have a set of their own parameters and help. In IRAF, the history is placed in the header information of the files worked on.

A function is therefore placed within a task and can be adjusted and changed and replaced within the task so long as the parameters for input and output remain the same. This makes the task concept ideal for users who are creating scripts for other users. You get the consistency checking, help and history recording in a consistent fashion for a little bit of extra packaging.

Tasks can be used anywhere in the DP environment: From the Jython command line in HIPE, the Quick-Look Analysis (QLA) environment and in the pipelines (Standard Product Generation).

>
>

How do tasks help?

 
Added:
>
>
Any task provides the following functionality:
 
Added:
>
>
  • Command line help, exposing available algorithms and how they should be called.
  • Integration in HIPE: you can register a task to be listed in HIPE, where it gets a standard graphical interface.
  • Checking of input parameters.
  • Recording of history.
  • A common look-and-feel for the graphical interface.
  • Re-usability: tasks are the building blocks of pipelines, and complex tasks can be composed of other tasks.
  • Modifiability: a task defines how to execute the internal algorithm, how to provide inputs and to get outputs. You can modify the internal algorithm or even change it altogether, as long as input and output parameters remain the same.
 
Added:
>
>
This has some similarities to the Interactive Reduction and Analysis Facility (IRAF) where tasks/programs have a set of their own parameters and help. In IRAF, the history is placed in the header information of the files worked on.
 
Added:
>
>
A task is ideal if you want to create routines for other users. You get the consistency checking, help and history recording in a consistent fashion for a little bit of extra packaging.
 
Changed:
<
<

How To Write a Task in Jython

>
>
You can execute tasks via the HIPE graphical interface, call them from the Console view or from your Jython scripts.
 
Changed:
<
<
This section describes how to turn a Jython algorithm into a Task. This is done with an example of a Jython "algorithm" that calculates an average. This "algorithm" is coded in a Jython function. It will be shown how to turn this function into a task.
>
>

Writing a task in Jython

 
Changed:
<
<
We start by giving the example function.
>
>
This section describes how to turn a Jython function into a task.
 
Changed:
<
<

A Jython function: average(table)

>
>

The Jython function: average(table)

 
Changed:
<
<
The following is a Jython function that takes a table and calculates the average of each of the columns.
>
>
The following Jython function takes a table dataset and calculates the average of each column.
 

Revision 12010-05-04 - DavideRizzo

Line: 1 to 1
Added:
>
>
META TOPICPARENT name="DpHipe"

Writing Tasks

Tasks are data processors. You can use a task to manipulate a data product, such as an image, or to convert data from one kind into another, for instance extracting a spectrum from a cube.

If you have an algorithm that does data processing, you can turn it into a task whether it is written in Jython or in Java. This topic explains how this is done.

How does the Task Framework help?

The Task framework provides functionality in a Task superclass, which can be reused by the user's tasks. The Task superclass provides, for example:

  • Command line help, exposing available algorithms and how they should be called
  • Integration in HIPE: Tasks can be accessed and run using the HIPE GUI
  • Input parameter checking
  • History recording
  • A common look and feel or the user (fixed methods to execute, to get the output, etc.)
  • Re-usability: Tasks are the building blocks of pipelines, and complex tasks can be composed of other tasks
  • Modifiability: Because Task defines how to execute the algorithm and how to get the output, etc, the user can modify the algorithm, or change one algorithm for another, as long as the established Task rules are still followed

This has some similarities to the Interactive Reduction and Analysis Facility (IRAF) where tasks/programs have a set of their own parameters and help. In IRAF, the history is placed in the header information of the files worked on.

A function is therefore placed within a task and can be adjusted and changed and replaced within the task so long as the parameters for input and output remain the same. This makes the task concept ideal for users who are creating scripts for other users. You get the consistency checking, help and history recording in a consistent fashion for a little bit of extra packaging.

Tasks can be used anywhere in the DP environment: From the Jython command line in HIPE, the Quick-Look Analysis (QLA) environment and in the pipelines (Standard Product Generation).

How To Write a Task in Jython

This section describes how to turn a Jython algorithm into a Task. This is done with an example of a Jython "algorithm" that calculates an average. This "algorithm" is coded in a Jython function. It will be shown how to turn this function into a task.

We start by giving the example function.

A Jython function: average(table)

The following is a Jython function that takes a table and calculates the average of each of the columns.

# Import data structures from java classes
from herschel.ia.numeric.all import *
from herschel.ia.dataset.all import *

#--------------------------------------------------
# average function
# Takes a TableDataSet as input
# Returns a Double1d (1D array of real numbers)
# in which each row is the average of the values
# in the input table columns
#--------------------------------------------------
#routine for calculating the average
def average(table):
    columns = table.columnCount
    divider = 1.0 / columns
    result = Double1d(table.rowCount)
    for column in range(columns):
        result.add(table.getColumn(column).data)
    return result.multiply(divider)

You can use the following functions to try it out:

# Function for creating a table with some test data
# The table will be like this:
# 0 1 2 3 4 5
# 1 2 3 4 5 6
# 2 3 4 5 6 7
# 3 4 5 6 7 8
# 4 5 6 7 8 9
def createTable():
    #create array x (0.0, 1.0, 2.0, 3.0, 4.0)
    x = Double1d.range(5)
    columns = 5
    #create an empty table with a name
    table = TableDataset(description = "a test table")
    #iterate for the the number of columns to fill up the table
    for column in range(0,columns):
        table["%i" % column] = Column(x)
        x = x + 1
    #return the result, a table called 'table'
    return table

# Function for executing the method
def testAverage():
    # create the table
    table = createTable()
    # get the average and put it into an array called 'result'
    result = average(table)
    # print the result
    print 'result', result

The result of typing testAverage() on the Console view of HIPE is:

result [2.0,3.0,4.0,5.0,6.0]

Creating the Task: Average

To turn our average algorithm into a task we need to wrap the algorithm into a piece of code which adapts it to form a task. Our current function has no input parameters (it is a parameterless execute method). We need to wrap it so that we have the appropriate input parameters (so it becomes a parameterized method).

We will name the task itself Average (a task is a class, it is callable from the command line, and by convention class names are capitalized nouns). In our Average class we have no needs other than setting up a signature and calling the average function as part of its execution.

Every Task must extend the JTask, so the first step in creating our task class is to subclass JTask.

If you check the chapter about writing a Task in Java, you will see that the class in Jython looks slightly different. This is due to differences in implementation details between Jython and Java, and cannot be avoided. To extend JTask, only the following is required:

# Import task framework classes.
from herschel.ia.task.all import *
# Import data structures from java classes needed
from herschel.ia.dataset.all import *
from herschel.ia.numeric.all import *
# Import our algorithm
from average import average

class Average(JTask):
   def __init__(self):
       # This is the constructor of the Task. Initialize the superclass:
       JTask.__init__(self, "averageTask")

       # Define the *Signature* using calls to the addTaskParameter method
       # The following lines define one TableDataset input parameter, called table
       # And one output parameter of type Double1d.
       p = TaskParameter("table",valueType = TableDataset, mandatory = 1)
       self.addTaskParameter(p)
       p = TaskParameter("result",valueType = Double1d, type = OUT)
       self.addTaskParameter(p)

   # Here we define the execute method:
   def execute(self):
       # Define the code to be *executed*: Call our average method here
       # The input parameter 'table' is passed as the argument of the function
       self.result = average(self.table) 

These steps are explained in greater detail in the next sections.

About the import statements in the above example, the following: The task framework classes are the "standard" definitions allowing import of a task definition. Task and TaskParameter classes will be automatically imported with the 'all' import statement. The set of import statements after the 'all' import statements are specific to this example task. The last import statement simply gives us access to the definition of our average function. For this import statement to work as is, the file with the Jython average function needs to be in your CLASSPATH. You can also simply copy the average function into the Jython code of the Task. In that case you don't need the import statement for the 'average' function.

A note about input parameters

As you can see in the above examples, the average function takes one parameter and returns the result. The execute method of the task, on the other hand, has no parameters and returns nothing. The Task defines one input and one output parameter in the constructor, which in Jython is called __init__.

A note about output parameters

One feature of Task is that it tries to minimize its hidden state between calls. This helps if tasks are being executed multiple times: This way, one execution depends as little as possible on the previous executions.

From one execution of the Task to another, most parameters are cleaned (reset to their default values), after invocation:

  • The first output parameter will be cleaned after execution of the task. This parameter will be available as the return value of the task and should be stored into a variable for later use: var = task() .
  • The second and additional output (or input-output) parameters will be kept in memory until they are accessed, then they will be cleaned: var2 = task.output2 .
  • Input parameters are cleaned after execution of the task.

We recommend to use only one output paramater per task, so that no state is kept between task invocations. If you need to return multiple values you can use collections or define an appropiate type that contains all outputs.

Running the Task from Jython

The following commands can be used to run the Average Task from the HIPE Console. We shows three ways of running the task:

from herschel.ia.dataset.all import *
from herschel.ia.numeric.all import *
from Average import Average

x = Double1d.range(5)
columns = 5
data = TableDataset(description = "a test table")
for column in range(columns):
    data["%i" % column] = Column(x)
    x = x + 1

# Create an instance of the Task
avg = Average()

# Print the usage information of the task (the "Signature")
info('avg')

# Set the input parameter 'table'
avg.table = data
calcResult = avg.result
print 'result', calcResult

The Task framework offers different ways to execute the task as well: Calling the execute method using "positional parameters" and "named parameters". Suppose that a task expects three input parameters: One image parameter called 'img', one float indicating a rotation angle 'angle', and one boolean (true or false) called 'takeNeg' indicating whether the negative of the image shall be products.

If you call the execute methods using positional parameters, then the simple order of the parameters tells the Task which is the image, which is the angle and which is the boolean. If you use named parameters, then you are allowed to use any order for the parameters, but every parameters must preceded by its name. The following example illustrates this using our Average Task:

# Invocation using positional parameter
avg(data)

# Invocation using named parameter
avg(table = data)

How To Write a Java Task

This section describes how to turn a Java algorithm into a task. We assume here that you have read the preceding section about writing a Task in Jython.

Again we use a function that calculates an average. This function is called average and is defined in the Java class Function. This is the full Function class:

import herschel.ia.dataset.TableDataset;
import herschel.ia.dataset.Column;
import herschel.ia.numeric.Double1D;

public class Function {

   public static Double1D average(TableDataset table) {
      if (table == null) {
         throw (new NullPointerException("missing table value"));
      }

      int columns = table.getColumnCount();
      double divider = 1.0 / ((double) columns);
      Double1D result = new Double1D(table.getRowCount());
      for (int column = 0; column  &lt; columns; column++) {
         result.mAdd((Double1D) table.getColumn(column).getData());
      }

      return result.mMultiply(divider);
  }

}

The following Java class can be used to test the above code:

import herschel.ia.dataset.TableDataset;
import herschel.ia.dataset.Column;
import herschel.ia.numeric.Double1D;
import java.text.DecimalFormat;

public class TestFunction {

   public static void main(String[] arguments) {
       Double1D result = Function.average(generator());
       show(result);
   }

   /**
    * Generate some test data.
    */ 
   public static TableDataset generator() {
       TableDataset result = new TableDataset("A test table");
       int columns = 5;
       int rows = 5;
       Double1D x = Double1D.range(rows);
       for (int column = 0;column &lt; columns;column++) {
          result.addColumn(("" + column), new Column(x.copy()));
          x.mAdd(1);
       }
       return result;
   }

   public static void show(Double1D data) {
      DecimalFormat twoDigits = new DecimalFormat("0.0");
      int size = data.length();
      System.out.print("result [");
      for (int row = 0;row &lt; size;row++) {
         System.out.print(twoDigits.format(data.get(row)));
         if (row &lt; (size - 1)) {
            System.out.print(",");
         } else {
            System.out.print("] ");
         }
      }
      System.out.println();
  }

}

The result of running TestFunction is:

result [2.0,3.0,4.0,5.0,6.0]              

Task Average

To turn the average algorithim in the Function class into a Task, we will, as before for the Jython function, create a Task that calls the right function. The following is an example of how this can be done:

// Import Task class definitions
import herschel.ia.task.Task;
import herschel.ia.task.TaskParameter;
// Import data types
import herschel.ia.dataset.TableDataset;
import herschel.ia.numeric.Double1D;

public class Average extends Task {

  public Average() {
     super("Averaging of table data set");
     // Add one input parameter: the TableDataset
     TaskParameter parameter = new TaskParameter("table", TableDataset.class);
     parameter.setMandatory(true);
     addTaskParameter(parameter);

     // And declare the output parameter
     parameter = new TaskParameter("result", Double1D.class);
     parameter.setType(TaskParameter.OUT);
     addTaskParameter(parameter);
  }

  public void execute() {
     try {
        setValue("result", Function.average((TableDataset) getValue("table")));
     } catch (Exception e) {
        e.printStackTrace();
     }
  }
}

The following code can be used to test the above Java Task:

import herschel.ia.dataset.TableDataset;
import herschel.ia.numeric.Double1D;
import java.text.DecimalFormat;

public class TestTask {

  public static void main(String[] arguments) {
     Average task = new Average();
     TableDataset data = generate()
     task.setValue("table", data);
     task.execute();
     Double1D result = (Double1D) task.getValue("result");
     show(result);
  }

  public static TableDataset generate() {
     TableDataset result = new TableDataset("A test table");
     int columns = 5;
     int rows = 5;
     Double1D x = Double1D.range(rows);
     for (int column = 0;column &lt; columns;column++) {
        result.addColumn(("" + column), new Column(x.copy()));
        x.mAdd(1);
     }
     return result;
  }

  public static void show(Double1D data) {
     DecimalFormat twoDigits = new DecimalFormat("0.0");
     int size = data.length();
     System.out.print("result [");
     for (int row = 0;row &lt; size;row++) {
        System.out.print(twoDigits.format(data.get(row)));
        if (row &lt; (size - 1)) {
           System.out.print(",");
        } else {
           System.out.print("]");
        }
     }
     System.out.println();
  }
}

Calling a Java task from a Jython script

The script below shows the only difference between calling a task coded in Java (e.g. Average.java) and a task coded in Jython (e.g. Average.py). The import of Average statement ( import JavaAverage ) is different in that we do not need to specify a module name. Note also that the name of the class is changed to JavaAverage in order to avoid a clash of names with our Jython Average class. The test function is identical (albeit shortened).

from herschel.ia.numeric.all import *
from herschel.ia.dataset.all import *
# Import our java task
import JavaAverage

def test():
    x = Double1d.range(5)
    columns = 5
    table = TableDataset(description = "a test table")
    for column in range(0,columns):
        table["%i" % column] = Column(x)
        x = x + 1
    avg = JavaAverage()
    # Invocation using positional parameter
    print 'result', avg(table = table)

Executing the above code in HIPE will define the test() method. Type test() on the HIPE Console to execute it.

Examples

Here we provide some examples on how to use a preprocessor, to perform some actions on your data before starting, and how to write your task if your input consists of arrays. The examples are given in Jython, but can be applied to Java Tasks as well.

Example: Using a preprocessor: Preamble

The preamble allows us to do some preprocessing on our data. For example, our average function calculate the averages of the columns of a table. But what if we wanted our task to calculate the average of two one-dimensional arrays of numbers? We can write a Task to takes two of these vectors as input and use the preamble to create a table, that has these two vectors as columns.

The below example illustrates this. Note that we first invoke the preamble from our parent task (JTask) to guarantee that our needed parameters have a value before putting them into the table.

class AverageArray(JTask):
    # Creation method
    def __init__(self,name = "averageArray"):
        p = TaskParameter("vector1",valueType = PyList, mandatory = 1)
        self.addTaskParameter(p)
        p = TaskParameter("vector2",valueType = PyList, mandatory = 1)
        self.addTaskParameter(p)
        p = TaskParameter("result",valueType = Double1d, type = OUT)
        self.addTaskParameter(p)
        # Create an internal variable table which is our TableDataset
        self.__dict__['table'] = TableDataset()
        
    def preamble(self):
        # In the preamble we do the store the two vectors in  the table
        JTask.preamble(self)
        self.table["0"] = Column(Double1d(self.vector1))
        self.table["1"] = Column(Double1d(self.vector2))
        
    def execute(self):
        self.result = average(self.table)

Note that the execute method is identical to the original Task. The following can be used to try this Task:

sample1 = [1.0, 2.0, 3.0, 4.0]
sample2 = [3.0, 4.0, 5.0, 6.0]
avg = AdaptAverage()

# Invocation using positional parameter
avg(sample1,sample2)
print avg.result

Example: Handling arrays as input

Task Transformer illustrates the use of a task that handles arrays. This example transforms arrays into TableDatasets.

from herschel.ia.task.all import *
from herschel.ia.numeric.all import *
from herschel.ia.dataset.all import *
from java.lang import Integer

class Transformer(JTask):

    def __init__(self, name = 'Vector Transformer'):
       p = TaskParameter(name = 'input', valueType = array(Integer), mandat\
ory = 1)
       self.addTaskParameter(p)
       p = TaskParameter( name = "result", valueType = TableDataset, type = OUT)
       self.addTaskParameter(p)

    def execute(self):
       self.result = TableDataset(description = 'Integrated vector as colum\
n zero')
       r = Double1d(len(self.input))
       index = 0
       for data in (self.input):
           r[index] = data
           index = index + 1
       self.result['0'] = Column(r)

The following can be used to try this Task:

# Test data
sample = [10, 20, 30, 40]
# Create the Task:
transform = Transformer()
# Execute the Task:
transform(sample)
# Get the output:
table = transform.result
# Print:
print table
print table['0']

Including Tasks in HIPE

Tasks should be included in HIPE such that they can be accessed directly from its user interface, in particular the Tasks View.

In short, including a task in HIPE comprises:

  • Adding the task to HIPE registry. It is also possible to specify a specific category for your task, such that the task will be available for a specific type of variable.
  • Optionally setting validation requirements for a specific parameter, using a ParameterValidator. See Prime input validation.
  • Optionally provide a custom task dialog. HIPE automatically provides a default Task dialog panel for the registered tasks.

Please refer to the detailed instructions for a full explanation.

Guidelines for Writing Tasks

This section provides some general guidelines, that are expected to be useful also for simple tasks.

Exceptions

If an error occurs during execution of the task, and the task cannot recover from it, an exception should be raised. This exception must derived from RuntimeException. The JTask API does not declare any exception, so we can't use checked exceptions. If you must raise a checked exception, use the initCause() method of the RuntimeException.

Interrupting Task execution

The Stop button in the HIPE user interface generates an interruption event and sends it to the separate thread where Jython code is running.

This signal is read between consecutive commands of the Jython script. For example, pressing the Stop button interrupts immediately this infinite loop:

while 1:
   print 1

However, this may not be so when the interpreter releases control to a time-consuming Task. If the Task does not periodically check for the interruption signal, pressing the Stop button will have no effect.

You can check for the interruption signal within your code by using the checkInterrupted method of the Task class. If an interruption request is detected, the method will throw an InterruptedException that would be caught by the interpreter, thus cancelling the task. You may pass a String representing the message to issue when the Task is interrupted:

myTask.checkInterrupted(); # Uses default message
myTask.checkInterrupted("Interruption signal received");

Your code should check for the interruption signal with sufficient frequency to allow a timely interruption. For example:

// Within the execute method of your task
for (int i = 0; i < nSteps; i++) {
    Task.checkInterrupted(getName() + " interrupted in step " + i);
    doStep(i);
}

Cleaning Task output

If you use tasks from Jython code, when you access the outputs they are cleaned up automatically. On the other hand, when you call a task from Java code, you need to clean the outputs manually like this:

t.perform();
t. ... // get t results
t.reset();

Of course, if t is going to be garbage collected there is no need to clean it up. Note that the task instances already available in HIPE are not going to be garbage collected.

Tasks and tools Involving Products and Datasets

For tasks that deal with products and datasets, the users (astronomers and calibration scientists) should not be required to perform type conversions between products and datasets. If such conversions are required, they should be dealt with by the software. This in part stems from the fact that manipulation of datasets loses any associated history. It is recommended that all tasks (and tools) should work with, and save outputs as, products.

Stateless and stateful functions

The function, as designed above, is what is called (with respect to its mode of operation) a state-full function . There are two types of functions that exist in the Herschel IA software:

  1. Stateless function : this function is called with a set of actual parameters, perform some computation and deliver a result based solely on the current inputs.
  2. Stateful function : this function performs some computation based on a set of actual parameters and on its previous internal state . In other words a stateful function is a function with a memory (or a history).

On the command line interactive analysis, data is usually static and therefore the functions used to manipulate them can be either stateful or stateless. To clarify the difference we take a simple averaging of vectors.

The static version of averaging two vectors is simply (call model):

result = average(vector1, vector2)

This method would work well so long as vector1 and vector2 are not themselves the results of averaging (implicitly the state is the weight for the vectors and is equal to 1). In a process where the average is a running average, we could turn this function into a dynamic function by introducing the weights of both input vectors as follows:

result = average(avg1, weight1, avg2, weight2)

This new function can be used in both a dynamic and in a static way. The static call used for instance within the IA (under Jconsole ) could be:

result = average(avg1, 1, avg2, 1)

In the more dynamic QLA environment where the second vector is the data read from a stream, the function would be called as:

runavg = average(runavg, nvectors, vector, 1)
nvectors = nvectors + 1

To sum this up, a stateless function can be used both in static and dynamic environment. It is advantageous, when possible, to write stateless functions.

How to use GUIs with your tasks

Tasks can have an extended set of parameters and/or include results which need to be visualized (a plot or an image). An additional API is provided, which allows the user to interact with the task using a GUI. The GUI and its components are set up such that it can be re-used within other tasks.

To include objects which represents a certain view which is related to the task (most often this is a javax.swing.JComponent), the TaskSignature contains a dedicated parameter called "views". This parameter contains a map object: Map[String, Object]. In this way the developer is capable to include any type of view. Below we show a Java as well as a Jython examples demonstrating the creation and use of view components.

Notes that a task is a DP component, which should be usable in the entire DP environment. This includes the operational pipelines, where no display is available and no GUI should be initialized. The examples below show how to make sure that the GUI is only created when needed.

Java example

import herschel.ia.task.Task;
import herschel.ia.task.TaskParameter;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.Map;

import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.JPanel;


public class MyAccessTask extends Task implements PropertyChangeListener, ActionListener {
    private JComponent _myTaskDialog;

    public MyAccessTask(){
   super("MyTask");
   makeSignature();
   // instantiate a JComponent including (1) a StringField
   // for the "db" parameter and (2) an "accept" button
   _myTaskDialog = MyTaskDialog(this, getValue("db"));
    } 

    private void makeSignature() {     
   TaskParameter param = new TaskParameter("db");
   param.setValueType(String.class);
   param.setMandatory(false);
   addTaskParameter(param);
   getParameter("db").addPropertyChangeListener(this);

   // create boolean for the dialog component
   // via this parameter the user is able to launch it
   param = new TaskParameter("gui");
   param.setValueType(Boolean.class);
   param.setDefaultValue(Boolean.FALSE);
   param.setType(TaskParameter.IN);
   addTaskParameter(param);
   getParameter("gui").addPropertyChangeListener(this);

   // add view component to the "views" parameter:
   ((Map<Object, Object>) getValue("views")).put("dialog",  _myTaskDialog);
    }


    public void propertyChange(PropertyChangeEvent event) {

       if (event.getPropertyName().equals("dialog")) {
           if ((Boolean) getValue("dialog") && getViews().get("GUI") == null) {
              JPanel jpan = new JPanel();
              jpan.add((JPanel) getViews().get("dialog"));
              JFrame jframe = new JFrame("MyAccessTask Dialog");
              jframe.add(jpan);
                 getViews().put("GUI", jframe);
          }
          ((JFrame) getViews().get("GUI")).setVisible((Boolean) getValue("dialog"));
       }
    }

    public void execute() {
       if ((Boolean) getValue("dialog")) {
           while ((Boolean) getValue("dialog")) {
              try {
                  Thread.sleep(1000);
              } catch (InterruptedException e) {
                  e.printStackTrace();
                 }
           }
       }

       // execute algorithm
    }

    public void actionPerformed(ActionEvent e){ 
       if ( ((JButton) e.getSource()).getText().equals("accept") ) {
           setValue("db", _myTaskDialog.getDbValue());
           setValue("dialog", Boolean.FALSE) ;
      }
    }
}

Jython example

class MyTask(JTask, java.awt.event.ActionListener, java.beans.PropertyChangeListener):

    def __init__(self, name='MyTask'):
       JTask.__init__(self, name)
       self.addTaskParameter(TaskParameter(valueType = \
           array(TmSourcePacket), name="hk", mandatory = 1))
       self.addTaskParameter(TaskParameter(valueType=Boolean, name = \
           "gui", defaultValue=Boolean(Boolean.FALSE)))
       self.addTaskParameter(TaskParameter(valueType = \
           TableDataset, name="result",type=TaskParameter.OUT))
       self.views["jcombo"] = JComboBox()
       self.views["pass"] = JButton("pass plot to task result")    
       self.views["plot"] = PlotXY()
    #
    def propertyChange(self, event):
        if (String('gui').equals(event.getPropertyName())):
            if (self.gui == 1):
                if (self.views.containsKey("GUI") == Boolean.FALSE):                    
                    self.views['frame'] = \
                        JFrame('Binary Structure Task - Display HK Parameters')
                    self.frame.getContentPane().add(self.views['jcombo'])
                    self.frame.getContentPane().add(self.views['plot'])
                    self.frame.getContentPane().add(self.views['pass'])
                    self.views['GUI'] = self.frame
                self.frame.visible = 1

    #

    def actionPerformed(self, event):
        if isinstance(event.getSource(), JComboBox):
          // update plot jcomponent 
        elif isinstance(event.getSource(), JButton):
           // self.result = .........

Re-use of view components outside the task

To support the re-use of tasks as well as the related views, I give the following example: We have a AccessHk task as well as a DisplayParam task which we want to combine in a BrowseHk task, where we re-use the view from the AccessHk task to setup the query, and the view from the DisplayParam which allows to plot select a parameter. The BrowseHk will therefor only contain the glue to combine those views into a higher level task. We define the BrowseHk as a task in order to adopt to the task API, to

  • Allow the user to pass: a) an "obsid" as default entry for the task's view, and b) allow the user to retrieve back data into its jide session as one is used to within the task concept
  • To support the developer in providing easy syntax to handle data via task parameters.

class BrowseHk(JTask, PropertyChangeListener):
        def __init__(self, name = 'browser'):
                JTask.__init__(self, name, developerAccessMode = 1)
                self.__dict__['apk'] = AccessHk()
                self.__dict__['dpk'] = DisplayParam()
                self.apk.getParameter('result').addPropertyChangeListener(self)
                self.dpk.getParameter('result').addPropertyChangeListener(self)
                self.addTaskParameter(TaskParameter('query',valueType = \
                    array(TmSourcePacket), type = TaskParameter.OUT))
                self.addTaskParameter(TaskParameter('selected',valueType = \
                    TableDataset, type = TaskParameter.OUT))
                self.addTaskParameter(TaskParameter('gui',valueType = \
                    Boolean, defaultValue = Boolean(Boolean.FALSE)))
                self.getParameter('gui').addPropertyChangeListener(self)

                panel = JPanel()
                panel.add(self.apk.views['apk-panel']
                panel.add(self.dpk.views['dpk-panel']
                self.views['main-panel'] = panel

        def propertyChange(self, event):
                if ( String("result").equals(event.getPropertyName()) ):
                        if ( String(event.getSource().getBaseType().getName()).equals
                            ("herschel.ccm.api.TmSourcePacket") ):
                                // event comes from AccessHk
                                ar = event.getNewValue()
                                self.dpk.hkarray = ar
                                self.query = ar
                        else:
                                // event comes from DisplayParam
                                self.selected = self.dpk.result
                elif ( String('gui').equals(event.getPropertyName()) ):
                        if (self.getValue("gui")):
                                if (self.views["Gui"] == None):
                                        frame = JFrame('House Keeping Packet Browser v1.0')
                                        frame.getContentPane().add(self.views['panel'])
                                        frame.setSize(625,680)
                                        self.views['Gui'] = frame
                                self.views['Gui'].visible = 1
                        else:
                                if (self.views["Gui"] != None):
                                        self.views['Gui'].visible = 0
        #
        def execute(self):
                if (self.gui == Boolean.FALSE):
                        self.gui = Boolean.TRUE

Furthermore the developer is able to extract the set of views from a task into its IA session, simply by:

HIPE> views = task.views

Conventions for task GUI labels

The conventions for Task parameter labels in Task dialogs are:

  • The primary input parameter should be the first one. Its label will be bold.
  • All mandatory parameters (including primary input) will have an asterisk mark in their label. Of course, this does not change the parameter name.
  • The other parameters have plain labels.

Label tooltips should be formatted as follows:

  
(optional | mandatory)  type
------------------------------- 
parameter description

The utility JTaskSignatureComponent#getDecoratedLabel(...) can be used to create a label that follows these conventions (including the tooltips).

Example:
Example of task tooltip

Advanced Features

We describe here some features that may not of interest to simple tasks.

User level feedback

Suppose a task can not create the expected outputs because it found an error in the input data. This can not be considered a program failure and has more to do with the notifications an interactive system should give to its operators/final users. Even if the task terminates normally, it should be desirable to provide a way to know if a task was already executed or it is still pending or was interrupted during the execution. Another common situation is that where a time consumer task needs to give some feedback to the user during it execution.

For these situations, all tasks include the following fields in the Signature class: Status, StatusMessage and the Progress.

The Status parameter stores a numeric code without restrictions but with a few, standardized, values:

    Status    Status       Meaning/   
    Value     "Name"       Status Message
    ------    -----------  ---------------------------------------------------------
    100       UNKNOWN      Signature is created but not assigned to a given task yet
    200       READY        Task is ready to be executed
    400       RUNNING      During the execution of the perform method of the task
    000       SUCCESS      Task has finished without problems
    500       INTERRUPTED  Task has been interrupted during its execution
    900       FAILED       Error found during the task execution

Once a task is created the READY value is assigned to it. UNKNOWN value is only used for those cases where a Signature is created before its assignment to a Task or even a pipeline.

Now, when the task perform method is called, its Status is automatically changed to the RUNNING value and it will keep this value until its successful conclusion ( SUCCESS ), an error is found ( FAILED ) or it happens to be interrupted before finish (INTERRUPTED).

This transitions between states are automatically registered into the Status field by the default implementation. The developer can use this information as a quick feedback to the user about the final result of the task. Also, the developer can update the StatusMessage field during the execution of the task as a way to notify the user of current stage into a time consuming task.

The Progress parameter

The Progress field marks the advance in the execution of a given task as a integer value between 0 and 100 . This provide a way to show the user how a single task is performing and how much time is expected this task to last until its conclusion. The developer can update this value at any time during the execution process and the The Task package includes a bean to easily display this value on the screen as the typical progress bar.

The Progress parameter is accessible via the name Signature.PROGRESS and can be used as in the following example.

  • Java:

          public void execute(){
            // assuming to iterate for a number of _iterations
            for (int j=0; j&lt;=_iterations ; j++) {
                // DO SOMETHING DURING THE ITERATION
                //xxxxx
                // LOG PROGRESS INFORMATION
                setValue(Signature.PROGRESS, new Integer(((j*100)/_iterations)));
            // Also, this shortcut is valid for any subclass of Task:
            // setProgress((j*100)/_iterations)
            }
          }
    

    Values must fall into the [0-100] range to be properly interpreted and displayed.

  • Jython:

          def execute(self):
            #assuming to iterate for a number of _iterations
            for j in range(_iterations):
                ## DO SOMETHING DURING THE ITERATION
                ##xxxxx
                ## LOG PROGRESS INFORMATION
                self.progress = j*100/_iterations
    
  • The FAILED status

    The developer must clearly separate the situation where the Task is suppose to return a failed result from any other problem derived from an implementation error or an unexpected situation not well managed by the code. In the latter cases, a RuntimeException shall be raised and the calling method (maybe the graphical environment where the task is running) take care of it.

    By definition, a task should be marked as FAILED when, even assuming an error free algorithm and giving the valid inputs, it fails to produce the expected output. A simple example is a task that implements an algorithm to identify the starts into a image. This task should fail when the provided image doesn't contains any start or the algorithm can not distinguish them due to a noisy background.

    Optional parameters

    Parameters that are facultative must have been given a default value before the task is executed, failure to do so will provoke an exception when parameters values are checked in the preamble. Usually, the default value for a parameter is provided by the task implementer, not the end user. Parameters requiring a value from the user should be tagged as mandatory .

    META FILEATTACHMENT attachment="TaskTooltip.png" attr="" comment="Example of task tooltip" date="1272960712" name="TaskTooltip.png" path="TaskTooltip.png" size="2098" stream="TaskTooltip.png" user="Main.DavideRizzo" version="1"
     
    This site is powered by the TWiki collaboration platform Powered by Perl