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}