in jbatch/src/main/java/org/apache/batchee/container/impl/controller/ExecutionTransitioner.java [87:170]
public ExecutionStatus doExecutionLoop() {
try {
currentExecutionElement = modelNavigator.getFirstExecutionElement(jobExecution.getRestartOn());
} catch (final IllegalTransitionException e) {
throw new IllegalArgumentException("Could not transition to first execution element within job.", e);
}
while (true) {
if (jobContext.getBatchStatus().equals(BatchStatus.STOPPING)) {
return new ExecutionStatus(ExtendedBatchStatus.JOB_OPERATOR_STOPPING);
}
final ExecutionElementController currentElementController = getNextElementController();
currentStoppableElementController = currentElementController;
if (BaseStepController.class.isInstance(currentElementController)) {
BaseStepController.class.cast(currentElementController).setParentStepContext(parentStepContext);
}
final ExecutionStatus status = currentElementController.execute();
// Nothing special for decision or step except to get exit status. For flow and split we want to bubble up though.
if ((currentExecutionElement instanceof Split) || (currentExecutionElement instanceof Flow)) {
// Exit status and restartOn should both be in the job context.
if (!status.getExtendedBatchStatus().equals(ExtendedBatchStatus.NORMAL_COMPLETION)) {
return status;
}
}
// Seems like this should only happen if an Error is thrown at the step level, since normally a step-level
// exception is caught and the fact that it was thrown capture in the ExecutionStatus
if (jobContext.getBatchStatus().equals(BatchStatus.FAILED)) {
throw new BatchContainerRuntimeException("Sub-execution returned its own BatchStatus of FAILED. Deal with this by throwing exception to the next layer.");
}
// set the execution element controller to null so we don't try to call stop on it after the element has finished executing
currentStoppableElementController = null;
if (jobContext.getBatchStatus().equals(BatchStatus.STOPPING)) {
return new ExecutionStatus(ExtendedBatchStatus.JOB_OPERATOR_STOPPING);
}
Transition nextTransition;
try {
nextTransition = modelNavigator.getNextTransition(currentExecutionElement, status);
} catch (final IllegalTransitionException e) {
throw new BatchContainerRuntimeException("Problem transitioning to next execution element.", e);
}
//
// We will find ourselves in one of four states now.
//
// 1. Finished transitioning after a normal execution, but nothing to do 'next'.
// 2. We just executed a step which through an exception, but didn't match a transition element.
// 3. We are going to 'next' to another execution element (and jump back to the top of this '
// 'while'-loop.
// 4. We matched a terminating transition element (<end>, <stop> or <fail).
//
// 1.
if (nextTransition.isFinishedTransitioning()) {
this.stepExecIds = currentElementController.getLastRunStepExecutions();
// Consider just passing the last 'status' back, but let's unwrap the exit status and pass a new NORMAL_COMPLETION
// status back instead.
return new ExecutionStatus(ExtendedBatchStatus.NORMAL_COMPLETION, status.getExitStatus());
// 2.
} else if (nextTransition.noTransitionElementMatchedAfterException()) {
return new ExecutionStatus(ExtendedBatchStatus.EXCEPTION_THROWN, status.getExitStatus());
// 3.
} else if (nextTransition.getNextExecutionElement() != null) {
// hold on to the previous execution element for the decider
// we need it because we need to inject the context of the
// previous execution element into the decider
previousExecutionElement = currentExecutionElement;
previousElementController = currentElementController;
currentExecutionElement = nextTransition.getNextExecutionElement();
// 4.
} else if (nextTransition.getTransitionElement() != null) {
return handleTerminatingTransitionElement(nextTransition.getTransitionElement());
} else {
throw new IllegalStateException("Not sure how we'd end up in this state...aborting rather than looping.");
}
}
}