Optimization Server - Run Add Issue Task

This task takes scenarioId and a text message as input, adds the message to the scenario issues collection, then returns an output collector of the modified scenario as a result.

@Configuration
public class Tasks {
    @Bean
    public ScriptedTaskDescription addIssueWithOptimizationServerTask() {
        ScriptedTaskDescription task = new ScriptedTaskDescription("addIssueWithOptimizationServer", "Add Issue with OptimizationServer");
        task.setDescription("Add an issue to the selected scenario, using an OptimizationServer task");
        task.getScript()
            .addStatement(AskInputStatement.of("scenario", true, JobInputType.scenarioId(WRITABLE)))
            .addStatement(AskInputStatement.of("Issue Message", true, JobInputType.TEXT, "The text of the issue to add"))
            .addStatement(ExecuteOptimizationServerTaskStatement
                .forTaskId(StringExpression.of("Add Issue with OptimizationServer"))
                .withInput("Issue Message", VariableAccessExpression.of("Issue Message"))
                .withInput("inputCollector", ScenarioDataExpression.of(VariableAccessExpression.of("scenario")))
                .withOutputScenario("outputCollector", VariableAccessExpression.of("scenario"), StringExpression.of("GeneIssue"), StringExpression.of("Activity")));
        return task;
    }
}

Note that the table names mentioned in the arguments of withOutputScenario can include list expressions. That is, the corresponding line in the example above could have been written as follows:

.withOutputScenario("outputCollector", VariableAccessExpression.of("scenario"), ListExpression.of(StringExpression.of("GeneIssue"), StringExpression.of("Activity")))

A slightly different version of this task is a task that creates a new scenario (with a name given as input) and adds an issue message to the newly created scenario. To create a new scenario, we use StringExpression.idOfNewScenario() as in the following task:

@Configuration
public class Tasks {
    @Bean
    public ScriptedTaskDescription addIssueToNewScenarioWithOptimizationServerTask() {
        ScriptedTaskDescription task = new ScriptedTaskDescription("createScenarioAndAddIssueWithOptimizationServer", "Add Issue to new scenario");
        task.setDescription("Add an issue to a new scenario, using an OptimizationServer task");
        task.getScript()
            .addStatement(AskInputStatement.of("Issue Message", true, JobInputType.TEXT, "The text of the issue to add"))
            .addStatement(AskInputStatement.of("Scenario Name", true, JobInputType.TEXT, "The name of the scenario to create"))
            .addStatement(AskInputStatement.of("workspace", true, JobInputType.WORKSPACE_ID, "The Workspace where to create the new Scenario"))
            .addStatement(SetVariableStatement.of("scenarioId", StringExpression.idOfNewScenario(VariableAccessExpression.of("Scenario Name"), VariableAccessExpression.of("workspace"))))
            .addStatement(ExecuteOptimizationServerTaskStatement
                .forTaskId(StringExpression.of("Add Issue with OptimizationServer"))
                .withInput("Issue Message", VariableAccessExpression.of("Issue Message"))
                .withInput("inputCollector", ScenarioDataExpression.of(VariableAccessExpression.of("scenarioId")))
                .withOutputScenario("outputCollector", VariableAccessExpression.of("scenarioId"), StringExpression.of("GeneIssue")));
        return task;
    }
}

The OptimizationServer task with id "Add Issue with OptimizationServer" (for both versions above) is defined in OptimizationServer tasks configuration in worker.yml as follows:

tasks:
  - id: Add Issue with OptimizationServer
    implementationClassName: com.decisionbrain.gene.execution.worker.AddIssueTask
    description: This task adds an issue to the provided scenario
    inputs:
      - name: Issue Message
        type: TEXT
        description: The text of the issue to add
        required: true
      - name: inputCollector
        type: BINARY
        description: Collector with initial data
        required: true
    outputs:
      - name: outputCollector
        type: BINARY
        description: Collector with initial data plus added issue
        required: true

With the following implementation class:

import com.decisionbrain.optimserver.common.parameter.Parameter;
import com.decisionbrain.optimserver.worker.api.ExecutionContext;
import com.decisionbrain.optimserver.worker.api.Task;
import com.decisionbrain.sample.model.Activity;
import com.decisionbrain.sample.model.CapacityPlanning;
import com.decisionbrain.sample.model.GeneIssue;
import com.decisionbrain.sample.model.impl.CapacityPlanningFactoryImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Arrays;

public class AddIssueTask implements Task {
    private static final Logger LOGGER = LoggerFactory.getLogger("AddIssueTask");

    @Override
    public void execute(Parameter input, Parameter output, ExecutionContext context) {
        CapacityPlanning collector = getInputCollector(input);

        LOGGER.info("Seeing {} existing issues", collector.getIssues().size());

        GeneIssue issue = collector.createGeneIssue();

        issue.setSeverity("INFO");
        issue.setMessage(new String(input.get("Issue Message")));

        emitOutputCollector(output, collector);
    }

    private CapacityPlanning getInputCollector(Parameter input) {
        try {
            CapacityPlanning collector = new CapacityPlanningFactoryImpl().createCollector();
            byte[] inputData = input.get("inputCollector");
            collector.loadSnapshot(inputData);

            return collector;
        } catch (Exception e) {
            throw new RuntimeException("Error while preparing data", e);
        }
    }

    private void emitOutputCollector(Parameter output, CapacityPlanning collector) {
        try {
            output.emit("outputCollector", collector.saveSnapshot(Arrays.asList(Activity.class, GeneIssue.class)));
        } catch (IOException e) {
            throw new RuntimeException("Error while saving data", e);
        }
    }
}