com.ibm.jbatch.container.impl.ExecutionTransitioner Maven / Gradle / Ivy
/*
* Copyright 2012 International Business Machines Corp.
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Licensed under the Apache License,
* Version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.ibm.jbatch.container.impl;
import java.util.List;
import java.util.concurrent.BlockingQueue;
import java.util.logging.Logger;
import jakarta.batch.runtime.BatchStatus;
import com.ibm.jbatch.container.IController;
import com.ibm.jbatch.container.IExecutionElementController;
import com.ibm.jbatch.container.context.impl.JobContextImpl;
import com.ibm.jbatch.container.context.impl.StepContextImpl;
import com.ibm.jbatch.container.exception.BatchContainerRuntimeException;
import com.ibm.jbatch.container.jobinstance.RuntimeJobExecution;
import com.ibm.jbatch.container.jsl.ExecutionElement;
import com.ibm.jbatch.container.jsl.IllegalTransitionException;
import com.ibm.jbatch.container.jsl.Transition;
import com.ibm.jbatch.container.jsl.TransitionElement;
import com.ibm.jbatch.container.navigator.ModelNavigator;
import com.ibm.jbatch.container.status.ExtendedBatchStatus;
import com.ibm.jbatch.container.status.ExecutionStatus;
import com.ibm.jbatch.container.util.PartitionDataWrapper;
import com.ibm.jbatch.jsl.model.Decision;
import com.ibm.jbatch.jsl.model.End;
import com.ibm.jbatch.jsl.model.Fail;
import com.ibm.jbatch.jsl.model.Flow;
import com.ibm.jbatch.jsl.model.JSLJob;
import com.ibm.jbatch.jsl.model.Split;
import com.ibm.jbatch.jsl.model.Step;
import com.ibm.jbatch.jsl.model.Stop;
public class ExecutionTransitioner {
private final static String CLASSNAME = ExecutionTransitioner.class.getName();
private final static Logger logger = Logger.getLogger(CLASSNAME);
private RuntimeJobExecution jobExecution;
private long rootJobExecutionId;
private ModelNavigator> modelNavigator;
// 'volatile' since it receives stop on separate thread.
private volatile IExecutionElementController currentStoppableElementController;
private IExecutionElementController previousElementController;
private ExecutionElement currentExecutionElement = null;
private ExecutionElement previousExecutionElement = null;
private JobContextImpl jobContext;
private BlockingQueue analyzerQueue = null;
private List stepExecIds;
public ExecutionTransitioner(RuntimeJobExecution jobExecution, long rootJobExecutionId, ModelNavigator> modelNavigator) {
this.jobExecution = jobExecution;
this.rootJobExecutionId = rootJobExecutionId;
this.modelNavigator = modelNavigator;
this.jobContext = jobExecution.getJobContext();
}
public ExecutionTransitioner(RuntimeJobExecution jobExecution, long rootJobExecutionId, ModelNavigator jobNavigator, BlockingQueue analyzerQueue) {
this.jobExecution = jobExecution;
this.rootJobExecutionId = rootJobExecutionId;
this.modelNavigator = jobNavigator;
this.jobContext = jobExecution.getJobContext();
this.analyzerQueue = analyzerQueue;
}
/**
* Used for job and flow.
* @return
*/
public ExecutionStatus doExecutionLoop() {
final String methodName = "doExecutionLoop";
try {
currentExecutionElement = modelNavigator.getFirstExecutionElement(jobExecution.getRestartOn());
} catch (IllegalTransitionException e) {
String errorMsg = "Could not transition to first execution element within job.";
logger.warning(errorMsg);
throw new IllegalArgumentException(errorMsg, e);
}
logger.fine("First execution element = " + currentExecutionElement.getId());
while (true) {
if (jobContext.getBatchStatus().equals(BatchStatus.STOPPING)) {
logger.fine(methodName + " Exiting execution loop as job is now in stopping state.");
return new ExecutionStatus(ExtendedBatchStatus.JOB_OPERATOR_STOPPING);
}
IExecutionElementController currentElementController = getNextElementController();
currentStoppableElementController = currentElementController;
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)) {
logger.fine("Breaking out of loop with return status = " + status.getExtendedBatchStatus().name());
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)) {
String errorMsg = "Sub-execution returned its own BatchStatus of FAILED. Deal with this by throwing exception to the next layer.";
logger.warning(errorMsg);
throw new BatchContainerRuntimeException(errorMsg);
}
// 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;
logger.fine("Done executing element=" + currentExecutionElement.getId() + ", exitStatus=" + status.getExitStatus());
if (jobContext.getBatchStatus().equals(BatchStatus.STOPPING)) {
logger.fine(methodName + " Exiting as job has been stopped");
return new ExecutionStatus(ExtendedBatchStatus.JOB_OPERATOR_STOPPING);
}
Transition nextTransition = null;
try {
nextTransition = modelNavigator.getNextTransition(currentExecutionElement, status);
} catch (IllegalTransitionException e) {
String errorMsg = "Problem transitioning to next execution element.";
logger.warning(errorMsg);
throw new BatchContainerRuntimeException(errorMsg, 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 (, or : " + transitionElement + " with restartOn=" + restartOn +
" , and JSL exit status = " + exitStatusFromJSL);
retVal = new ExecutionStatus(ExtendedBatchStatus.JSL_STOP);
if (exitStatusFromJSL != null) {
jobContext.setExitStatus(exitStatusFromJSL);
retVal.setExitStatus(exitStatusFromJSL);
}
if (restartOn != null) {
jobContext.setRestartOn(restartOn);
retVal.setRestartOn(restartOn);
}
} else if (transitionElement instanceof End) {
End endElement = (End)transitionElement;
String exitStatusFromJSL = endElement.getExitStatus();
logger.fine("Next transition element is an : " + transitionElement +
" with JSL exit status = " + exitStatusFromJSL);
retVal = new ExecutionStatus(ExtendedBatchStatus.JSL_END);
if (exitStatusFromJSL != null) {
jobContext.setExitStatus(exitStatusFromJSL);
retVal.setExitStatus(exitStatusFromJSL);
}
} else if (transitionElement instanceof Fail) {
Fail failElement = (Fail)transitionElement;
String exitStatusFromJSL = failElement.getExitStatus();
logger.fine("Next transition element is a : " + transitionElement +
" with JSL exit status = " + exitStatusFromJSL);
retVal = new ExecutionStatus(ExtendedBatchStatus.JSL_FAIL);
if (exitStatusFromJSL != null) {
jobContext.setExitStatus(exitStatusFromJSL);
retVal.setExitStatus(exitStatusFromJSL);
}
} else {
throw new IllegalStateException("Not sure how we'd get here...aborting.");
}
return retVal;
}
public IController getCurrentStoppableElementController() {
return currentStoppableElementController;
}
public List getStepExecIds() {
return stepExecIds;
}
}