Understanding Flow Control Statements

Tasks use general statements and expressions to handle specific data flows.

  • The IfStatement.of(Expression test, Statement thenBranch, Statement elseBranch) method creates a statement that, when executed, first evaluates the test expression. This expression must evaluate to a Boolean value. If it evaluates to true, then the thenBranch statement is executed; otherwise, the elseBranch statement is executed. The IfStatement.of(Expression test, Statement thenBranch) method is a variant for an empty "else" branch.

    For example, the following sample task takes a number as input, then uses IfStatement to:

    • log a different message when the number is odd or even.

    • set the task output value to " odd" or "even".

    @Configuration
    public class Tasks {
        @Bean
        public ScriptedTaskDescription evenOrOddTask() {
            ScriptedTaskDescription task = new ScriptedTaskDescription("evenOrOddTask", "Is that number even or odd?");
            VariableAccessExpression n = VariableAccessExpression.of("A number");
            NumericExpression zero = NumericExpression.ZERO;
            NumericExpression two = NumericExpression.of(2);
            task.getScript()
                .addStatement(AskInputStatement.of(n.getVariableName(), true, JobInputType.INTEGER))
                .addStatement(LogStatement.info(StringExpression.concat(StringExpression.of("Is "), n, StringExpression.of(" even or odd?"))))
                .addStatement(IfStatement.of(BooleanExpression.eq(NumericExpression.minus(n, NumericExpression.times(NumericExpression.divide(n, two), two)), zero),
                    Block.of(
                        LogStatement.info(StringExpression.concat(n, StringExpression.of(" is even"))),
                        SetTaskOutputStatement.of("Even or odd?", StringExpression.of("even"))
                    ),
                    Block.of(
                        LogStatement.info(StringExpression.concat(n, StringExpression.of(" is odd"))),
                        SetTaskOutputStatement.of("Even or odd?", StringExpression.of("odd"))
                    )));
            return task;
        }
    }

    The generated web client component for this task is the following:

    EvenOrOdd

  • The RepeatStatement.of(String loopVariableName, Expression nbLoops, Statement... statements) method creates a statement that, when executed, first evaluates the nbLoops expression. This expression must evaluate to a number. Then the statements are executed as many times. If a variable name is provided as loopVariableName, a variable is set with this name to an increasing value on each loop execution, starting with one. If you do not need a loop index variable, you can pass null as the first argument to the of method.

    For example, the following task takes a number as input, then uses RepeatStatement to compute its factorial; finally, it sets the task output to the result.

    @Configuration
    public class Tasks {
        @Bean
        public ScriptedTaskDescription factorialTask() {
            ScriptedTaskDescription task = new ScriptedTaskDescription("FactTask", "Factorial");
            VariableAccessExpression n = VariableAccessExpression.of("n");
            VariableAccessExpression fact = VariableAccessExpression.of("n!");
            VariableAccessExpression index = VariableAccessExpression.of("index");
    
            task.getScript()
                .addStatement(AskInputStatement.of(n.getVariableName(), true, JobInputType.INTEGER, "The number to compute the factorial of"))
                .addStatement(SetVariableStatement.of(fact.getVariableName(), NumericExpression.ONE))
                .addStatement(RepeatStatement.of(index.getVariableName(), n,
                    SetVariableStatement.of(fact.getVariableName(), NumericExpression.times(fact, index))))
                .addStatement(SetTaskOutputStatement.of("result", fact));
            return task;
        }
    }

    Here is an example of job computing 4! = 24.

    4! = 24

  • The ForeachStatement.of(String elementVariableName, Expression elementsExpression, Statement... statements) method creates a statement that, when executed, first evaluates the elementsExpression expression. This expression must evaluate to a homogeneous list of values (they must all have the same type). Then for each element in that list, the statements are executed. If elementVariableName is not null, a variable with this name is set to the current list element during the execution of the statements. The breakOnError(boolean) method can be applied to a for-each statement to set the behavior of the loop if one of the statements in its body terminates with a non-zero exit code. When called with true, the loop will exit on the first (top-level) statement that exits/terminates with a non-zero exit code. When called with false (the default), exit codes do not influence the loop. In all cases, the exit code of the loop is the one of the last executed statement.

Anywhere a statement is expected, and typically as the "then" or "else" branch of an "if" statement, a block can be provided using the Block.of(Statement...) method.

Note:

Note that variables have a global scope, even if first set in a block.

If the execution of a statement terminates normally, i.e. not interrupted by an exception, the statement has an exit code, which is an integer (a Java int) . As per Unix convention, "zero" means "everything is normal".

Other exit code values must be defined by each statement. In addition:

  • The NoopStatement.ok() method creates a statement that, when executed, terminates immediately with exit code zero.

  • The NoopStatement.withExitCode(Expression) method creates a statement that, when executed, terminates immediately with the value of the provided expression as its exit code. It terminates with an exception if this expression does not evaluate to a number.

If a statement terminates normally, i.e. not interrupted by an exception, and with a non-zero exit code, the execution of the rest of the script is not impacted and the next statement is executed.

However, the script itself can test the exit code of the last executed statement to determine its behavior, using the following expressions:

  • NumericExpression.LAST_STATEMENT_EXIT_CODE is a numeric expression that, when evaluated, provides the value of the exit code of the last executed statement.

  • Statement.OK_EXIT_CODE is a numeric expression that, when evaluated, yields the exit code of " everything ok", that is, zero.

  • BooleanExpression.LAST_STATEMENT_EXIT_CODE_OK and BooleanExpression.LAST_STATEMENT_EXIT_CODE_NOT_OK are Boolean expressions that, when evaluated, return respectively "true" or "false" if the exit code of the last executed statement is, respectively, zero or non-zero.

If a statement throws an exception, specific termination statements are executed. For more details, please refer to Section Understanding Job Termination Statements.