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 */
016package org.springframework.batch.core.step.builder;
017
018import org.apache.commons.logging.Log;
019import org.apache.commons.logging.LogFactory;
020import org.springframework.batch.core.Step;
021import org.springframework.batch.core.StepExecutionListener;
022import org.springframework.batch.core.annotation.AfterStep;
023import org.springframework.batch.core.annotation.BeforeStep;
024import org.springframework.batch.core.listener.StepListenerFactoryBean;
025import org.springframework.batch.core.repository.JobRepository;
026import org.springframework.batch.core.step.AbstractStep;
027import org.springframework.batch.core.step.tasklet.TaskletStep;
028import org.springframework.batch.support.ReflectionUtils;
029import org.springframework.transaction.PlatformTransactionManager;
030
031import java.lang.reflect.Method;
032import java.util.ArrayList;
033import java.util.HashSet;
034import java.util.List;
035import java.util.Set;
036
037/**
038 * A base class and utility for other step builders providing access to common properties like job repository and
039 * transaction manager.
040 * 
041 * @author Dave Syer
042 * @author Michael Minella
043 *
044 * @since 2.2
045 */
046public abstract class StepBuilderHelper<B extends StepBuilderHelper<B>> {
047
048        protected final Log logger = LogFactory.getLog(getClass());
049
050        protected final CommonStepProperties properties;
051
052        public StepBuilderHelper(String name) {
053                this.properties = new CommonStepProperties();
054                properties.name = name;
055        }
056
057        /**
058         * Create a new builder initialized with any properties in the parent. The parent is copied, so it can be re-used.
059         * 
060         * @param parent a parent helper containing common step properties
061         */
062        protected StepBuilderHelper(StepBuilderHelper<?> parent) {
063                this.properties = new CommonStepProperties(parent.properties);
064        }
065
066        public B repository(JobRepository jobRepository) {
067                properties.jobRepository = jobRepository;
068                @SuppressWarnings("unchecked")
069                B result = (B) this;
070                return result;
071        }
072
073        public B transactionManager(PlatformTransactionManager transactionManager) {
074                properties.transactionManager = transactionManager;
075                @SuppressWarnings("unchecked")
076                B result = (B) this;
077                return result;
078        }
079
080        public B startLimit(int startLimit) {
081                properties.startLimit = startLimit;
082                @SuppressWarnings("unchecked")
083                B result = (B) this;
084                return result;
085        }
086
087        /**
088         * Registers objects using the annotation based listener configuration.
089         *
090         * @param listener the object that has a method configured with listener annotation
091         * @return this for fluent chaining
092         */
093        public B listener(Object listener) {
094                Set<Method> stepExecutionListenerMethods = new HashSet<Method>();
095                stepExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), BeforeStep.class));
096                stepExecutionListenerMethods.addAll(ReflectionUtils.findMethod(listener.getClass(), AfterStep.class));
097
098                if(stepExecutionListenerMethods.size() > 0) {
099                        StepListenerFactoryBean factory = new StepListenerFactoryBean();
100                        factory.setDelegate(listener);
101                        properties.addStepExecutionListener((StepExecutionListener) factory.getObject());
102                }
103
104                @SuppressWarnings("unchecked")
105                B result = (B) this;
106                return result;
107        }
108
109        public B listener(StepExecutionListener listener) {
110                properties.addStepExecutionListener(listener);
111                @SuppressWarnings("unchecked")
112                B result = (B) this;
113                return result;
114        }
115
116        public B allowStartIfComplete(boolean allowStartIfComplete) {
117                properties.allowStartIfComplete = allowStartIfComplete;
118                @SuppressWarnings("unchecked")
119                B result = (B) this;
120                return result;
121        }
122
123        protected String getName() {
124                return properties.name;
125        }
126
127        protected JobRepository getJobRepository() {
128                return properties.jobRepository;
129        }
130
131        protected PlatformTransactionManager getTransactionManager() {
132                return properties.transactionManager;
133        }
134
135        protected boolean isAllowStartIfComplete() {
136                return properties.allowStartIfComplete != null ? properties.allowStartIfComplete : false;
137        }
138
139        protected void enhance(Step target) {
140
141                if (target instanceof AbstractStep) {
142
143                        AbstractStep step = (AbstractStep) target;
144                        step.setJobRepository(properties.getJobRepository());
145
146                        Boolean allowStartIfComplete = properties.allowStartIfComplete;
147                        if (allowStartIfComplete != null) {
148                                step.setAllowStartIfComplete(allowStartIfComplete);
149                        }
150
151                        step.setStartLimit(properties.startLimit);
152
153                        List<StepExecutionListener> listeners = properties.stepExecutionListeners;
154                        if (!listeners.isEmpty()) {
155                                step.setStepExecutionListeners(listeners.toArray(new StepExecutionListener[0]));
156                        }
157
158                }
159
160                if (target instanceof TaskletStep) {
161                        TaskletStep step = (TaskletStep) target;
162                        step.setTransactionManager(properties.transactionManager);
163                }
164
165        }
166
167        public static class CommonStepProperties {
168
169                private List<StepExecutionListener> stepExecutionListeners = new ArrayList<StepExecutionListener>();
170
171                private int startLimit = Integer.MAX_VALUE;
172
173                private Boolean allowStartIfComplete;
174
175                private JobRepository jobRepository;
176
177                private PlatformTransactionManager transactionManager;
178
179                public CommonStepProperties() {
180                }
181
182                public CommonStepProperties(CommonStepProperties properties) {
183                        this.name = properties.name;
184                        this.startLimit = properties.startLimit;
185                        this.allowStartIfComplete = properties.allowStartIfComplete;
186                        this.jobRepository = properties.jobRepository;
187                        this.transactionManager = properties.transactionManager;
188                        this.stepExecutionListeners = new ArrayList<StepExecutionListener>(properties.stepExecutionListeners);
189                }
190
191                public JobRepository getJobRepository() {
192                        return jobRepository;
193                }
194
195                public void setJobRepository(JobRepository jobRepository) {
196                        this.jobRepository = jobRepository;
197                }
198
199                public PlatformTransactionManager getTransactionManager() {
200                        return transactionManager;
201                }
202
203                public void setTransactionManager(PlatformTransactionManager transactionManager) {
204                        this.transactionManager = transactionManager;
205                }
206
207                public String getName() {
208                        return name;
209                }
210
211                public void setName(String name) {
212                        this.name = name;
213                }
214
215                public List<StepExecutionListener> getStepExecutionListeners() {
216                        return stepExecutionListeners;
217                }
218
219                public void addStepExecutionListeners(List<StepExecutionListener> stepExecutionListeners) {
220                        this.stepExecutionListeners.addAll(stepExecutionListeners);
221                }
222
223                public void addStepExecutionListener(StepExecutionListener stepExecutionListener) {
224                        this.stepExecutionListeners.add(stepExecutionListener);
225                }
226
227                public Integer getStartLimit() {
228                        return startLimit;
229                }
230
231                public void setStartLimit(Integer startLimit) {
232                        this.startLimit = startLimit;
233                }
234
235                public Boolean getAllowStartIfComplete() {
236                        return allowStartIfComplete;
237                }
238
239                public void setAllowStartIfComplete(Boolean allowStartIfComplete) {
240                        this.allowStartIfComplete = allowStartIfComplete;
241                }
242
243                private String name;
244
245        }
246
247}