001/*
002 * Copyright 2006-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 */
016
017package org.springframework.batch.core.job;
018
019import java.util.ArrayList;
020import java.util.Collection;
021import java.util.List;
022
023import org.springframework.batch.core.BatchStatus;
024import org.springframework.batch.core.Job;
025import org.springframework.batch.core.JobExecution;
026import org.springframework.batch.core.JobInterruptedException;
027import org.springframework.batch.core.StartLimitExceededException;
028import org.springframework.batch.core.Step;
029import org.springframework.batch.core.StepExecution;
030import org.springframework.batch.core.repository.JobRestartException;
031import org.springframework.batch.core.step.StepLocator;
032
033/**
034 * Simple implementation of {@link Job} interface providing the ability to run a
035 * {@link JobExecution}. Sequentially executes a job by iterating through its
036 * list of steps.  Any {@link Step} that fails will fail the job.  The job is
037 * considered complete when all steps have been executed.
038 *
039 * @author Lucas Ward
040 * @author Dave Syer
041 * @author Michael Minella
042 */
043public class SimpleJob extends AbstractJob {
044
045        private List<Step> steps = new ArrayList<Step>();
046
047        /**
048         * Default constructor for job with null name
049         */
050        public SimpleJob() {
051                this(null);
052        }
053
054        /**
055         * @param name the job name.
056         */
057        public SimpleJob(String name) {
058                super(name);
059        }
060
061        /**
062         * Public setter for the steps in this job. Overrides any calls to
063         * {@link #addStep(Step)}.
064         *
065         * @param steps the steps to execute
066         */
067        public void setSteps(List<Step> steps) {
068                this.steps.clear();
069                this.steps.addAll(steps);
070        }
071
072        /**
073         * Convenience method for clients to inspect the steps for this job.
074         *
075         * @return the step names for this job
076         */
077        @Override
078        public Collection<String> getStepNames() {
079                List<String> names = new ArrayList<String>();
080                for (Step step : steps) {
081                        names.add(step.getName());
082
083                        if(step instanceof StepLocator) {
084                                names.addAll(((StepLocator)step).getStepNames());
085                        }
086                }
087                return names;
088        }
089
090        /**
091         * Convenience method for adding a single step to the job.
092         *
093         * @param step a {@link Step} to add
094         */
095        public void addStep(Step step) {
096                this.steps.add(step);
097        }
098
099        /*
100         * (non-Javadoc)
101         *
102         * @see
103         * org.springframework.batch.core.job.AbstractJob#getStep(java.lang.String)
104         */
105        @Override
106        public Step getStep(String stepName) {
107                for (Step step : this.steps) {
108                        if (step.getName().equals(stepName)) {
109                                return step;
110                        } else if(step instanceof StepLocator) {
111                                Step result = ((StepLocator)step).getStep(stepName);
112                                if(result != null) {
113                                        return result;
114                                }
115                        }
116                }
117                return null;
118        }
119
120        /**
121         * Handler of steps sequentially as provided, checking each one for success
122         * before moving to the next. Returns the last {@link StepExecution}
123         * successfully processed if it exists, and null if none were processed.
124         *
125         * @param execution the current {@link JobExecution}
126         *
127         * @see AbstractJob#handleStep(Step, JobExecution)
128         */
129        @Override
130        protected void doExecute(JobExecution execution) throws JobInterruptedException, JobRestartException,
131        StartLimitExceededException {
132
133                StepExecution stepExecution = null;
134                for (Step step : steps) {
135                        stepExecution = handleStep(step, execution);
136                        if (stepExecution.getStatus() != BatchStatus.COMPLETED) {
137                                //
138                                // Terminate the job if a step fails
139                                //
140                                break;
141                        }
142                }
143
144                //
145                // Update the job status to be the same as the last step
146                //
147                if (stepExecution != null) {
148                        if (logger.isDebugEnabled()) {
149                                logger.debug("Upgrading JobExecution status: " + stepExecution);
150                        }
151                        execution.upgradeStatus(stepExecution.getStatus());
152                        execution.setExitStatus(stepExecution.getExitStatus());
153                }
154        }
155
156}