001/*
002 * Copyright 2006-2013 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.flow.support.state;
018
019import org.springframework.batch.core.BatchStatus;
020import org.springframework.batch.core.StepExecution;
021import org.springframework.batch.core.job.flow.FlowExecutionStatus;
022import org.springframework.batch.core.job.flow.FlowExecutor;
023import org.springframework.batch.core.job.flow.State;
024
025/**
026 * {@link State} implementation for ending a job if it is in progress and
027 * continuing if just starting.
028 *
029 * @author Dave Syer
030 * @since 2.0
031 */
032public class EndState extends AbstractState {
033
034        private final FlowExecutionStatus status;
035
036        private final boolean abandon;
037
038        private final String code;
039
040        /**
041         * @param status The {@link FlowExecutionStatus} to end with
042         * @param name The name of the state
043         */
044        public EndState(FlowExecutionStatus status, String name) {
045                this(status, status.getName(), name);
046        }
047
048        /**
049         * @param status The {@link FlowExecutionStatus} to end with
050         * @param name The name of the state
051         * @param code The exit status to save
052         */
053        public EndState(FlowExecutionStatus status, String code, String name) {
054                this(status, code, name, false);
055        }
056
057        /**
058         * @param status The {@link FlowExecutionStatus} to end with
059         * @param name The name of the state
060         * @param code The exit status to save
061         * @param abandon flag to indicate that previous step execution can be
062         * marked as abandoned (if there is one)
063         *
064         */
065        public EndState(FlowExecutionStatus status, String code, String name, boolean abandon) {
066                super(name);
067                this.status = status;
068                this.code = code;
069                this.abandon = abandon;
070        }
071
072        protected FlowExecutionStatus getStatus() {
073                return this.status;
074        }
075
076        protected boolean isAbandon() {
077                return this.abandon;
078        }
079
080        protected String getCode() {
081                return this.code;
082        }
083
084        /**
085         * Return the {@link FlowExecutionStatus} stored.
086         *
087         * @see State#handle(FlowExecutor)
088         */
089        @Override
090        public FlowExecutionStatus handle(FlowExecutor executor) throws Exception {
091
092                synchronized (executor) {
093
094                        // Special case. If the last step execution could not complete we
095                        // are in an unknown state (possibly unrecoverable).
096                        StepExecution stepExecution = executor.getStepExecution();
097                        if (stepExecution != null && executor.getStepExecution().getStatus() == BatchStatus.UNKNOWN) {
098                                return FlowExecutionStatus.UNKNOWN;
099                        }
100
101                        if (status.isStop()) {
102                                if (!executor.isRestart()) {
103                                        /*
104                                         * If there are step executions, then we are not at the
105                                         * beginning of a restart.
106                                         */
107                                        if (abandon) {
108                                                /*
109                                                 * Only if instructed to do so, upgrade the status of
110                                                 * last step execution so it is not replayed on a
111                                                 * restart...
112                                                 */
113                                                executor.abandonStepExecution();
114                                        }
115                                }
116                                else {
117                                        /*
118                                         * If we are a stop state and we got this far then it must
119                                         * be a restart, so return COMPLETED.
120                                         */
121                                        return FlowExecutionStatus.COMPLETED;
122                                }
123                        }
124
125                        setExitStatus(executor, code);
126
127                        return status;
128
129                }
130        }
131
132        /**
133         * Performs any logic to update the exit status for the current flow.
134         *
135         * @param executor {@link FlowExecutor} for the current flow
136         * @param code The exit status to save
137         */
138        protected void setExitStatus(FlowExecutor executor, String code) {
139                executor.addExitStatus(code);
140        }
141
142        /*
143         * (non-Javadoc)
144         *
145         * @see org.springframework.batch.core.job.flow.State#isEndState()
146         */
147        @Override
148        public boolean isEndState() {
149                return !status.isStop();
150        }
151
152        /*
153         * (non-Javadoc)
154         *
155         * @see java.lang.Object#toString()
156         */
157        @Override
158        public String toString() {
159                return super.toString() + " status=[" + status + "]";
160        }
161}