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.util.Properties;
019
020import javax.batch.runtime.context.StepContext;
021
022import org.springframework.batch.core.jsr.configuration.support.BatchPropertyContext;
023import org.springframework.batch.core.scope.context.StepSynchronizationManager;
024import org.springframework.beans.factory.FactoryBean;
025import org.springframework.beans.factory.FactoryBeanNotInitializedException;
026import org.springframework.beans.factory.InitializingBean;
027import org.springframework.beans.factory.annotation.Autowired;
028import org.springframework.util.Assert;
029
030/**
031 * {@link FactoryBean} implementation used to create {@link javax.batch.runtime.context.StepContext}
032 * instances within the step scope.
033 *
034 * @author Michael Minella
035 * @author Chris Schaefer
036 * @since 3.0
037 */
038public class JsrStepContextFactoryBean implements FactoryBean<StepContext>, InitializingBean {
039        @Autowired
040        private BatchPropertyContext batchPropertyContext;
041
042        private static final ThreadLocal<javax.batch.runtime.context.StepContext> contextHolder = new ThreadLocal<javax.batch.runtime.context.StepContext>();
043
044        protected void setBatchPropertyContext(BatchPropertyContext batchPropertyContext) {
045                this.batchPropertyContext = batchPropertyContext;
046        }
047
048        /* (non-Javadoc)
049         * @see org.springframework.beans.factory.FactoryBean#getObject()
050         */
051        @Override
052        public StepContext getObject() throws Exception {
053                return getCurrent();
054        }
055
056        private javax.batch.runtime.context.StepContext getCurrent() {
057                org.springframework.batch.core.StepExecution curStepExecution = null;
058
059                if(StepSynchronizationManager.getContext() != null) {
060                        curStepExecution = StepSynchronizationManager.getContext().getStepExecution();
061                }
062
063                if(curStepExecution == null) {
064                        throw new FactoryBeanNotInitializedException("A StepExecution is required");
065                }
066
067                StepContext context = contextHolder.get();
068
069                // If the current context applies to the current step, use it
070                if(context != null && context.getStepExecutionId() == curStepExecution.getId()) {
071                        return context;
072                }
073
074                Properties stepProperties = batchPropertyContext.getStepProperties(curStepExecution.getStepName());
075
076                if(stepProperties != null) {
077                        context = new JsrStepContext(curStepExecution, stepProperties);
078                } else {
079                        context = new JsrStepContext(curStepExecution, new Properties());
080                }
081
082                contextHolder.set(context);
083
084                return context;
085        }
086
087        /* (non-Javadoc)
088         * @see org.springframework.beans.factory.FactoryBean#getObjectType()
089         */
090        @Override
091        public Class<?> getObjectType() {
092                return StepContext.class;
093        }
094
095        /* (non-Javadoc)
096         * @see org.springframework.beans.factory.FactoryBean#isSingleton()
097         */
098        @Override
099        public boolean isSingleton() {
100                return false;
101        }
102
103        @Override
104        public void afterPropertiesSet() throws Exception {
105                Assert.notNull(batchPropertyContext, "BatchPropertyContext is required");
106        }
107
108        public void remove() {
109                if(contextHolder.get() != null) {
110                        contextHolder.remove();
111                }
112        }
113}