001/*
002 * Copyright 2013-2014 the original author or authors.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *      https://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.springframework.batch.core.jsr.step;
017
018import java.util.ArrayList;
019import java.util.Collection;
020import java.util.List;
021
022import javax.batch.api.Decider;
023
024import org.springframework.batch.core.ExitStatus;
025import org.springframework.batch.core.Step;
026import org.springframework.batch.core.StepExecution;
027import org.springframework.batch.core.jsr.JsrStepExecution;
028import org.springframework.batch.core.step.AbstractStep;
029import org.springframework.batch.item.ExecutionContext;
030
031/**
032 * Implements a {@link Step} to follow the rules for a decision state
033 * as defined by JSR-352.  Currently does not support the JSR requirement
034 * to provide all of the last {@link javax.batch.runtime.StepExecution}s from
035 * a split.
036 *
037 * @author Michael Minella
038 * @since 3.0
039 */
040public class DecisionStep extends AbstractStep {
041
042        private final Decider decider;
043
044        /**
045         * @param decider a {@link Decider} implementation
046         */
047        public DecisionStep(Decider decider) {
048                this.decider = decider;
049        }
050
051        @SuppressWarnings("unchecked")
052        @Override
053        protected void doExecute(StepExecution stepExecution) throws Exception {
054                ExecutionContext executionContext = stepExecution.getJobExecution().getExecutionContext();
055                List<javax.batch.runtime.StepExecution> stepExecutions = new ArrayList<javax.batch.runtime.StepExecution>();
056
057                if(executionContext.containsKey("batch.lastSteps")) {
058                        List<String> stepNames = (List<String>) executionContext.get("batch.lastSteps");
059
060                        for (String stepName : stepNames) {
061                                StepExecution curStepExecution = getJobRepository().getLastStepExecution(stepExecution.getJobExecution().getJobInstance(), stepName);
062                                stepExecutions.add(new JsrStepExecution(curStepExecution));
063                        }
064                } else {
065                        Collection<StepExecution> currentRunStepExecutions = stepExecution.getJobExecution().getStepExecutions();
066
067                        StepExecution lastExecution = null;
068
069                        if(stepExecutions != null) {
070                                for (StepExecution curStepExecution : currentRunStepExecutions) {
071                                        if(lastExecution == null || (curStepExecution.getEndTime() != null && curStepExecution.getEndTime().after(lastExecution.getEndTime()))) {
072                                                lastExecution = curStepExecution;
073                                        }
074                                }
075
076                                stepExecutions.add(new JsrStepExecution(lastExecution));
077                        }
078                }
079
080                try {
081                        ExitStatus exitStatus = new ExitStatus(decider.decide(stepExecutions.toArray(new javax.batch.runtime.StepExecution[0])));
082
083                        stepExecution.getJobExecution().setExitStatus(exitStatus);
084                        stepExecution.setExitStatus(exitStatus);
085
086                        if(executionContext.containsKey("batch.lastSteps")) {
087                                executionContext.remove("batch.lastSteps");
088                        }
089                } catch (Exception e) {
090                        stepExecution.setTerminateOnly();
091                        stepExecution.addFailureException(e);
092                        throw e;
093                }
094        }
095}