001/*
002 * Copyright 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 */
016package org.springframework.batch.core.jsr;
017
018import java.io.Serializable;
019import java.util.List;
020import java.util.Properties;
021import java.util.concurrent.atomic.AtomicBoolean;
022
023import javax.batch.runtime.BatchStatus;
024import javax.batch.runtime.Metric;
025
026import org.springframework.batch.core.ExitStatus;
027import org.springframework.batch.core.StepExecution;
028import org.springframework.batch.item.util.ExecutionContextUserSupport;
029import org.springframework.util.Assert;
030import org.springframework.util.ClassUtils;
031
032/**
033 * Wrapper class to provide the {@link javax.batch.runtime.context.StepContext} functionality
034 * as specified in JSR-352.  Wrapper delegates to the underlying {@link StepExecution} to
035 * obtain the related contextual information.
036 *
037 * @author Michael Minella
038 * @author Chris Schaefer
039 * @since 3.0
040 */
041public class JsrStepContext implements javax.batch.runtime.context.StepContext {
042        private final static String PERSISTENT_USER_DATA_KEY = "batch_jsr_persistentUserData";
043        private StepExecution stepExecution;
044        private Object transientUserData;
045        private Properties properties = new Properties();
046        private AtomicBoolean exitStatusSet = new AtomicBoolean();
047        private final ExecutionContextUserSupport executionContextUserSupport = new ExecutionContextUserSupport(ClassUtils.getShortName(JsrStepContext.class));
048
049        public JsrStepContext(StepExecution stepExecution, Properties properties) {
050                Assert.notNull(stepExecution, "A StepExecution is required");
051
052                this.stepExecution = stepExecution;
053                this.properties = properties;
054        }
055
056        /* (non-Javadoc)
057         * @see javax.batch.runtime.context.StepContext#getStepName()
058         */
059        @Override
060        public String getStepName() {
061                return stepExecution.getStepName();
062        }
063
064        /* (non-Javadoc)
065         * @see javax.batch.runtime.context.StepContext#getTransientUserData()
066         */
067        @Override
068        public Object getTransientUserData() {
069                return transientUserData;
070        }
071
072        /* (non-Javadoc)
073         * @see javax.batch.runtime.context.StepContext#setTransientUserData(java.lang.Object)
074         */
075        @Override
076        public void setTransientUserData(Object data) {
077                this.transientUserData = data;
078        }
079
080        /* (non-Javadoc)
081         * @see javax.batch.runtime.context.StepContext#getStepExecutionId()
082         */
083        @Override
084        public long getStepExecutionId() {
085                return stepExecution.getId();
086        }
087
088        /* (non-Javadoc)
089         * @see javax.batch.runtime.context.StepContext#getProperties()
090         */
091        @Override
092        public Properties getProperties() {
093                return properties != null ? properties : new Properties();
094        }
095
096        /* (non-Javadoc)
097         * @see javax.batch.runtime.context.StepContext#getPersistentUserData()
098         */
099        @Override
100        public Serializable getPersistentUserData() {
101                return (Serializable) stepExecution.getExecutionContext().get(executionContextUserSupport.getKey(PERSISTENT_USER_DATA_KEY));
102        }
103
104        /* (non-Javadoc)
105         * @see javax.batch.runtime.context.StepContext#setPersistentUserData(java.io.Serializable)
106         */
107        @Override
108        public void setPersistentUserData(Serializable data) {
109                stepExecution.getExecutionContext().put(executionContextUserSupport.getKey(PERSISTENT_USER_DATA_KEY), data);
110        }
111
112        /* (non-Javadoc)
113         * @see javax.batch.runtime.context.StepContext#getBatchStatus()
114         */
115        @Override
116        public BatchStatus getBatchStatus() {
117                return stepExecution.getStatus().getBatchStatus();
118        }
119
120        /* (non-Javadoc)
121         * @see javax.batch.runtime.context.StepContext#getExitStatus()
122         */
123        @Override
124        public String getExitStatus() {
125                return exitStatusSet.get() ? stepExecution.getExitStatus().getExitCode() : null;
126        }
127
128        /* (non-Javadoc)
129         * @see javax.batch.runtime.context.StepContext#setExitStatus(java.lang.String)
130         */
131        @Override
132        public void setExitStatus(String status) {
133                stepExecution.setExitStatus(new ExitStatus(status));
134                exitStatusSet.set(true);
135        }
136
137        /**
138         * To support both JSR-352's requirement to return the most recent exception
139         * and Spring Batch's support for {@link Throwable}, this implementation will
140         * return the most recent exception in the underlying {@link StepExecution}'s
141         * failure exceptions list.  If the exception there extends {@link Throwable}
142         * instead of {@link Exception}, it will be wrapped in an {@link Exception} and
143         * then returned.
144         *
145         * @see javax.batch.runtime.context.StepContext#getException()
146         */
147        @Override
148        public Exception getException() {
149                List<Throwable> failureExceptions = stepExecution.getFailureExceptions();
150                if(failureExceptions == null || failureExceptions.isEmpty()) {
151                        return null;
152                } else {
153                        Throwable t = failureExceptions.get(failureExceptions.size() - 1);
154
155                        if(t instanceof Exception) {
156                                return (Exception) t;
157                        } else {
158                                return new Exception(t);
159                        }
160                }
161        }
162
163        /* (non-Javadoc)
164         * @see javax.batch.runtime.context.StepContext#getMetrics()
165         */
166        @Override
167        public Metric[] getMetrics() {
168                Metric[] metrics = new Metric[8];
169
170                metrics[0] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.COMMIT_COUNT, stepExecution.getCommitCount());
171                metrics[1] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.FILTER_COUNT, stepExecution.getFilterCount());
172                metrics[2] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.PROCESS_SKIP_COUNT, stepExecution.getProcessSkipCount());
173                metrics[3] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.READ_COUNT, stepExecution.getReadCount());
174                metrics[4] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.READ_SKIP_COUNT, stepExecution.getReadSkipCount());
175                metrics[5] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.ROLLBACK_COUNT, stepExecution.getRollbackCount());
176                metrics[6] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.WRITE_COUNT, stepExecution.getWriteCount());
177                metrics[7] = new SimpleMetric(javax.batch.runtime.Metric.MetricType.WRITE_SKIP_COUNT, stepExecution.getWriteSkipCount());
178
179                return metrics;
180        }
181}