All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.batchee.container.impl.controller.ExecutionTransitioner Maven / Gradle / Ivy

There is a newer version: 2.0.0
Show newest version
/*
 * 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 org.apache.batchee.container.impl.controller;

import org.apache.batchee.container.Controller;
import org.apache.batchee.container.ExecutionElementController;
import org.apache.batchee.container.exception.BatchContainerRuntimeException;
import org.apache.batchee.container.impl.JobContextImpl;
import org.apache.batchee.container.impl.StepContextImpl;
import org.apache.batchee.container.impl.jobinstance.RuntimeJobExecution;
import org.apache.batchee.container.jsl.ExecutionElement;
import org.apache.batchee.container.jsl.IllegalTransitionException;
import org.apache.batchee.container.jsl.Transition;
import org.apache.batchee.container.jsl.TransitionElement;
import org.apache.batchee.container.navigator.ModelNavigator;
import org.apache.batchee.container.services.BatchKernelService;
import org.apache.batchee.container.services.ServicesManager;
import org.apache.batchee.container.status.ExecutionStatus;
import org.apache.batchee.container.status.ExtendedBatchStatus;
import org.apache.batchee.container.util.PartitionDataWrapper;
import org.apache.batchee.jaxb.Decision;
import org.apache.batchee.jaxb.End;
import org.apache.batchee.jaxb.Fail;
import org.apache.batchee.jaxb.Flow;
import org.apache.batchee.jaxb.JSLJob;
import org.apache.batchee.jaxb.Split;
import org.apache.batchee.jaxb.Step;
import org.apache.batchee.jaxb.Stop;

import javax.batch.runtime.BatchStatus;
import java.util.List;
import java.util.concurrent.BlockingQueue;

public class ExecutionTransitioner {
    private final ServicesManager manager;
    private RuntimeJobExecution jobExecution;
    private long rootJobExecutionId;
    private ModelNavigator modelNavigator;

    // 'volatile' since it receives stop on separate thread.
    private volatile ExecutionElementController currentStoppableElementController;
    private ExecutionElementController previousElementController;
    private ExecutionElement currentExecutionElement = null;
    private ExecutionElement previousExecutionElement = null;


    private JobContextImpl jobContext;
    private BlockingQueue analyzerQueue = null;

    private List stepExecIds;
    private StepContextImpl parentStepContext;

    public ExecutionTransitioner(final RuntimeJobExecution jobExecution, final long rootJobExecutionId, final ModelNavigator modelNavigator,
                                 final ServicesManager servicesManager) {
        this.jobExecution = jobExecution;
        this.rootJobExecutionId = rootJobExecutionId;
        this.modelNavigator = modelNavigator;
        this.jobContext = jobExecution.getJobContext();
        this.manager = servicesManager;
    }

    public ExecutionTransitioner(final RuntimeJobExecution jobExecution, final long rootJobExecutionId,
                                 final ModelNavigator jobNavigator, final BlockingQueue analyzerQueue,
                                 final ServicesManager manager) {
        this.jobExecution = jobExecution;
        this.rootJobExecutionId = rootJobExecutionId;
        this.modelNavigator = jobNavigator;
        this.jobContext = jobExecution.getJobContext();
        this.analyzerQueue = analyzerQueue;
        this.manager = manager;
    }

    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 (,  or  getStepExecIds() {
        return stepExecIds;
    }

    public void setParentStepContext(final StepContextImpl parentStepContext) {
        this.parentStepContext = parentStepContext;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy