Is there a way to achieve the following logic with JSR 352 Batch API? I have a series of Steps that each need to be executed based on a different condition known when starting the job. ConditionsEntity is provided by an external system.
public List<Steps> createStepSequence(ConditionsEntity conditions) {
if (conditions.isStep1Enabled()) {
steps.add(step1)
}
if (conditions.isStep2Enabled()) {
steps.add(step2)
}
if (conditions.isStep3Enabled()) {
steps.add(step3)
}
//many more ifs
return steps;
}
My first attempt fails because of: com.ibm.jbatch.container.exception.BatchContainerRuntimeException: A decision cannot precede another decision. I'm adding the FAILING Code here
<?xml version="1.0" encoding="UTF-8"?>
<job id="myJob" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/jobXML_1_0.xsd" version="1.0">
<properties>
<property name="isExecuteStep2" value="false"/>
<property name="isExecuteStep3" value="false"/>
</properties>
<step id="step1" next="decider1">
<batchlet ref="myBatchlet1"/>
</step>
<decision id="decider1" ref="SkipNextStepDecider">
<properties>
<property name="isExecuteNextStep" value="#{jobProperties['isExecuteStep2']}"/>
</properties>
<next on="EXECUTE" to="step2"/>
<next on="SKIP" to="decider2"/>
</decision>
<step id="step2">
<batchlet ref="myBatchlet2"/>
</step>
<decision id="decider2" ref="SkipNextStepDecider">
<properties>
<property name="isExecuteNextStep" value="#{jobProperties['isExecuteStep3']}"/>
</properties>
<next on="EXECUTE" to="step3"/>
<end on="SKIP"/>
</decision>
<step id="step3">
<batchlet ref="myBatchlet3"/>
</step>
</job>
@Named
public class SkipNextStepDecider implements Decider {
@Inject
@BatchProperty
private String isExecuteNextStep;
@Override
public String decide(StepExecution[] ses) throws Exception {
if (isExecuteNextStep.equalsIgnoreCase("true")) {
return "EXECUTE";
} else {
return "SKIP";
}
}
}
UPDATE I have implemented the following suggested solution with a passThroughStep. It's working correctly, but I would still love to be able to avoid all this code duplication.
<?xml version="1.0" encoding="UTF-8"?>
<job id="decisionpoc" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
<step id="dummy0" next="decider1">
<batchlet ref="dummyBatchlet"/>
</step>
<decision id="decider1" ref="skipNextStepDecider">
<properties>
<property name="condition" value="isExecuteStep1"/>
</properties>
<next on="EXECUTE" to="step1"/>
<next on="SKIP" to="dummy1"/>
</decision>
<step id="step1" next="decider2">
<batchlet ref="myBatchlet1"/>
</step>
<step id="dummy1" next="decider2">
<batchlet ref="dummyBatchlet"/>
</step>
<decision id="decider2" ref="skipNextStepDecider">
<properties>
<property name="condition" value="isExecuteStep2"/>
</properties>
<next on="EXECUTE" to="step2"/>
<next on="SKIP" to="dummy2"/>
</decision>
<step id="step2">
<batchlet ref="myBatchlet2"/>
</step>
<step id="dummy2" next="decider3">
<batchlet ref="dummyBatchlet"/>
</step>
<decision id="decider3" ref="skipNextStepDecider">
<properties>
<property name="condition" value="isExecuteStep3"/>
</properties>
<next on="EXECUTE" to="step3"/>
<end on="SKIP"/>
</decision>
<step id="step3">
<batchlet ref="myBatchlet3"/>
</step>
</job>
The Decider
@Named
public class SkipNextStepDecider implements Decider {
@Inject
@BatchProperty
private String condition;
@Inject
private JobContext jobContext;
@Override
public String decide(StepExecution[] ses) throws Exception {
Properties parameters = getParameters();
String isExecuteNextStep = parameters.getProperty(condition);
if (isExecuteNextStep.equalsIgnoreCase("true")) {
return "EXECUTE";
} else {
return "SKIP";
}
}
private Properties getParameters() {
JobOperator operator = getJobOperator();
return operator.getParameters(jobContext.getExecutionId());
}
}
My Test
public class DecisionPOCTest extends AbstractBatchLOT {
@Test
public void testProcess() throws Exception {
JobOperator jobOperator = getJobOperator();
Properties properties = new Properties();
properties.setProperty("isExecuteStep1", "true");
properties.setProperty("isExecuteStep2", "false");
properties.setProperty("isExecuteStep3", "true");
Long executionId = jobOperator.start("poc/decisionPOC", properties);
JobExecution jobExecution = jobOperator.getJobExecution(executionId);
jobExecution = BatchTestHelper.keepTestAlive(jobExecution);
List<StepExecution> stepExecutions = jobOperator.getStepExecutions(executionId);
List<String> executedSteps = new ArrayList<>();
for (StepExecution stepExecution : stepExecutions) {
executedSteps.add(stepExecution.getStepName());
}
assertEquals(COMPLETED, jobExecution.getBatchStatus());
assertEquals(4, stepExecutions.size());
assertArrayEquals(new String[]{"dummy0", "step1", "dummy2", "step3"}, executedSteps.toArray());
assertFalse(executedSteps.contains("step2"));
}
}