BATCH-1154:
- Created StepFactoryBean, as a "master" factory that holds all the properties configurable on a step and decides which type of step to create. - the StepFactoryBean is used to generate a tasklet step as well as chunk-oriented step because if the 'tasklet=' attribute is specified on at one level and the <tasklet/> element is specified at another, the factory bean will be able to throw a useful error, whereas the parser would not know. - removed hacks from TaskletStep and SimpleStepFactoryBean
This commit is contained in:
@@ -18,7 +18,7 @@ package org.springframework.batch.core.configuration.xml;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.core.step.item.StepFactoryBean;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
@@ -61,6 +61,7 @@ public abstract class AbstractStepParser {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> taskletElements = (List<Element>) DomUtils.getChildElementsByTagName(stepElement, "tasklet");
|
||||
boolean taskletElementExists = taskletElements.size() > 0;
|
||||
boolean stepUnderspecified = stepUnderspecified(stepElement);
|
||||
AbstractBeanDefinition bd = null;
|
||||
if (StringUtils.hasText(taskletRef)) {
|
||||
if (taskletElementExists) {
|
||||
@@ -73,12 +74,17 @@ public abstract class AbstractStepParser {
|
||||
}
|
||||
else if (taskletElementExists) {
|
||||
Element taskElement = taskletElements.get(0);
|
||||
bd = taskletElementParser.parse(taskElement, parserContext, stepUnderspecified(stepElement));
|
||||
bd = taskletElementParser.parse(taskElement, parserContext, stepUnderspecified);
|
||||
}
|
||||
|
||||
if (bd != null) {
|
||||
setUpBeanDefinition(stepElement, bd, parserContext, jobRepositoryRef);
|
||||
}
|
||||
else if (!stepUnderspecified) {
|
||||
parserContext.getReaderContext().error(
|
||||
"Step [" + stepElement.getAttribute("id")
|
||||
+ "] has neither a <tasklet/> element nor a 'tasklet' attribute.", stepElement);
|
||||
}
|
||||
|
||||
return bd;
|
||||
|
||||
@@ -105,7 +111,7 @@ public abstract class AbstractStepParser {
|
||||
String jobRepositoryRef) {
|
||||
|
||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
bd.setBeanClass(TaskletStep.class);
|
||||
bd.setBeanClass(StepFactoryBean.class);
|
||||
|
||||
if (StringUtils.hasText(taskletRef)) {
|
||||
RuntimeBeanReference taskletBeanRef = new RuntimeBeanReference(taskletRef);
|
||||
@@ -121,7 +127,7 @@ public abstract class AbstractStepParser {
|
||||
String jobRepositoryRef) {
|
||||
checkStepAttributes(stepElement, bd);
|
||||
|
||||
bd.setAbstract(stepElement.hasAttribute("abstract") && Boolean.valueOf(stepElement.getAttribute("abstract")));
|
||||
bd.setAbstract(Boolean.valueOf(stepElement.getAttribute("abstract")));
|
||||
|
||||
RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(jobRepositoryRef);
|
||||
bd.getPropertyValues().addPropertyValue("jobRepository", jobRepositoryBeanRef);
|
||||
|
||||
@@ -104,10 +104,6 @@ public class InlineStepParser extends AbstractStepParser {
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(bd, stepId));
|
||||
stateBuilder.addConstructorArgReference(stepId);
|
||||
}
|
||||
else {
|
||||
parserContext.getReaderContext().error(
|
||||
"Incomplete configuration detected while creating step with name " + stepRef, element);
|
||||
}
|
||||
}
|
||||
return FlowParser.getNextElements(parserContext, stepId, stateBuilder.getBeanDefinition(), element);
|
||||
|
||||
|
||||
@@ -18,8 +18,7 @@ package org.springframework.batch.core.configuration.xml;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean;
|
||||
import org.springframework.batch.core.step.item.SimpleStepFactoryBean;
|
||||
import org.springframework.batch.core.step.item.StepFactoryBean;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
@@ -50,27 +49,13 @@ public class TaskletElementParser {
|
||||
*/
|
||||
protected AbstractBeanDefinition parse(Element element, ParserContext parserContext, boolean underspecified) {
|
||||
|
||||
String skipLimit = element.getAttribute("skip-limit");
|
||||
String retryLimit = element.getAttribute("retry-limit");
|
||||
String cacheCapacity = element.getAttribute("cache-capacity");
|
||||
String isReaderTransactionalQueue = element.getAttribute("is-reader-transactional-queue");
|
||||
|
||||
boolean useFaultTolerant = underspecified
|
||||
|| (StringUtils.hasText(isReaderTransactionalQueue) && Boolean.valueOf(isReaderTransactionalQueue))
|
||||
|| isPositive(skipLimit) || isPositive(retryLimit) || isPositive(cacheCapacity)
|
||||
|| hasElement(element, "skippable-exception-classes")
|
||||
|| hasElement(element, "retryable-exception-classes") || hasElement(element, "fatal-exception-classes");
|
||||
|
||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
if (useFaultTolerant) {
|
||||
bd.setBeanClass(FaultTolerantStepFactoryBean.class);
|
||||
}
|
||||
else {
|
||||
bd.setBeanClass(SimpleStepFactoryBean.class);
|
||||
}
|
||||
bd.setBeanClass(StepFactoryBean.class);
|
||||
|
||||
MutablePropertyValues propertyValues = bd.getPropertyValues();
|
||||
|
||||
propertyValues.addPropertyValue("hasTaskletElement", Boolean.TRUE);
|
||||
|
||||
String readerBeanId = element.getAttribute("reader");
|
||||
if (StringUtils.hasText(readerBeanId)) {
|
||||
RuntimeBeanReference readerRef = new RuntimeBeanReference(readerBeanId);
|
||||
@@ -113,32 +98,31 @@ public class TaskletElementParser {
|
||||
+ "or 'chunk-completion-policy', but not both.", element);
|
||||
}
|
||||
|
||||
String skipLimit = element.getAttribute("skip-limit");
|
||||
if (StringUtils.hasText(skipLimit)) {
|
||||
propertyValues.addPropertyValue("skipLimit", skipLimit);
|
||||
}
|
||||
|
||||
String retryLimit = element.getAttribute("retry-limit");
|
||||
if (StringUtils.hasText(retryLimit)) {
|
||||
propertyValues.addPropertyValue("retryLimit", retryLimit);
|
||||
}
|
||||
|
||||
String cacheCapacity = element.getAttribute("cache-capacity");
|
||||
if (StringUtils.hasText(cacheCapacity)) {
|
||||
propertyValues.addPropertyValue("cacheCapacity", cacheCapacity);
|
||||
}
|
||||
|
||||
String isReaderTransactionalQueue = element.getAttribute("is-reader-transactional-queue");
|
||||
if (StringUtils.hasText(isReaderTransactionalQueue)) {
|
||||
if (useFaultTolerant) {
|
||||
propertyValues.addPropertyValue("isReaderTransactionalQueue", isReaderTransactionalQueue);
|
||||
}
|
||||
propertyValues.addPropertyValue("isReaderTransactionalQueue", isReaderTransactionalQueue);
|
||||
}
|
||||
|
||||
handleExceptionElement(element, parserContext, bd, "skippable-exception-classes", "skippableExceptionClasses",
|
||||
useFaultTolerant, underspecified);
|
||||
handleExceptionElement(element, parserContext, bd, "skippable-exception-classes", "skippableExceptionClasses");
|
||||
|
||||
handleExceptionElement(element, parserContext, bd, "retryable-exception-classes", "retryableExceptionClasses",
|
||||
useFaultTolerant, underspecified);
|
||||
handleExceptionElement(element, parserContext, bd, "retryable-exception-classes", "retryableExceptionClasses");
|
||||
|
||||
handleExceptionElement(element, parserContext, bd, "fatal-exception-classes", "fatalExceptionClasses",
|
||||
useFaultTolerant, underspecified);
|
||||
handleExceptionElement(element, parserContext, bd, "fatal-exception-classes", "fatalExceptionClasses");
|
||||
|
||||
handleRetryListenersElement(element, bd, parserContext);
|
||||
|
||||
@@ -148,39 +132,19 @@ public class TaskletElementParser {
|
||||
|
||||
}
|
||||
|
||||
private boolean isPositive(String stringValue) {
|
||||
if (StringUtils.hasText(stringValue)) {
|
||||
if (Integer.valueOf(stringValue) > 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasElement(Element element, String subElementName) {
|
||||
return StringUtils.hasLength(DomUtils.getChildElementValueByTagName(element, subElementName));
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleExceptionElement(Element element, ParserContext parserContext, BeanDefinition bd,
|
||||
String subElementName, String propertyName, boolean isFaultTolerant, boolean isAbstract) {
|
||||
String subElementName, String propertyName) {
|
||||
Element child = DomUtils.getChildElementByTagName(element, subElementName);
|
||||
if (child != null) {
|
||||
String exceptions = DomUtils.getTextValue(child);
|
||||
if (StringUtils.hasLength(exceptions)) {
|
||||
if (isFaultTolerant || isAbstract) {
|
||||
String[] exceptionArray = StringUtils.tokenizeToStringArray(exceptions, ",\n");
|
||||
if (exceptionArray.length > 0) {
|
||||
ManagedList managedList = new ManagedList();
|
||||
managedList.setMergeEnabled(Boolean.valueOf(child.getAttribute("merge")));
|
||||
managedList.addAll(Arrays.asList(exceptionArray));
|
||||
bd.getPropertyValues().addPropertyValue(propertyName, managedList);
|
||||
}
|
||||
}
|
||||
else {
|
||||
parserContext.getReaderContext().error(
|
||||
subElementName + " can only be specified for fault-tolerant "
|
||||
+ "configurations providing skip-limit, retry-limit or cache-capacity", element);
|
||||
String[] exceptionArray = StringUtils.tokenizeToStringArray(exceptions, ",\n");
|
||||
if (exceptionArray.length > 0) {
|
||||
ManagedList managedList = new ManagedList();
|
||||
managedList.setMergeEnabled(Boolean.valueOf(child.getAttribute("merge")));
|
||||
managedList.addAll(Arrays.asList(exceptionArray));
|
||||
bd.getPropertyValues().addPropertyValue(propertyName, managedList);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,9 +15,6 @@
|
||||
*/
|
||||
package org.springframework.batch.core.step.item;
|
||||
|
||||
import java.beans.PropertyEditor;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.core.ChunkListener;
|
||||
@@ -48,9 +45,7 @@ import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeEditor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Most common configuration options for simple steps should be found here. Use
|
||||
@@ -143,10 +138,8 @@ public class SimpleStepFactoryBean<T, S> implements FactoryBean, BeanNameAware {
|
||||
}
|
||||
|
||||
/**
|
||||
* public void setIsReaderTransactionalQueue(boolean
|
||||
* isReaderTransactionalQueue) { this.isReaderTransactionalQueue =
|
||||
* isReaderTransactionalQueue; } Set the bean name property, which will
|
||||
* become the name of the {@link Step} when it is created.
|
||||
* Set the bean name property, which will become the name of the
|
||||
* {@link Step} when it is created.
|
||||
*
|
||||
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
|
||||
*/
|
||||
@@ -274,20 +267,6 @@ public class SimpleStepFactoryBean<T, S> implements FactoryBean, BeanNameAware {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link TransactionAttribute}.
|
||||
*
|
||||
* @param transactionAttributeList A list of all the transaction attributes
|
||||
* to set
|
||||
*/
|
||||
public void setTransactionAttributeList(List<String> transactionAttributeList) {
|
||||
String[] stringArray = transactionAttributeList.toArray(new String[0]);
|
||||
String attributeString = StringUtils.arrayToCommaDelimitedString(stringArray);
|
||||
PropertyEditor editor = new TransactionAttributeEditor();
|
||||
editor.setAsText(attributeString);
|
||||
this.setTransactionAttribute((TransactionAttribute) editor.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link TransactionAttribute}.
|
||||
* @param transactionAttribute the {@link TransactionAttribute} to set
|
||||
|
||||
@@ -0,0 +1,588 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.batch.core.step.item;
|
||||
|
||||
import java.beans.PropertyEditor;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.StepListener;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.item.ItemProcessor;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.repeat.CompletionPolicy;
|
||||
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
|
||||
import org.springframework.batch.retry.RetryListener;
|
||||
import org.springframework.batch.retry.policy.MapRetryContextCache;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.core.task.TaskExecutor;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeEditor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* This {@link FactoryBean} is used by the batch namespace parser to create
|
||||
* {@link Step} objects.
|
||||
*
|
||||
* @author Dan Garrette
|
||||
* @since 2.0
|
||||
* @see SimpleStepFactoryBean
|
||||
* @see FaultTolerantStepFactoryBean
|
||||
*/
|
||||
public class StepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
|
||||
|
||||
//
|
||||
// Step Attributes
|
||||
//
|
||||
private String name;
|
||||
private Boolean allowStartIfComplete;
|
||||
private JobRepository jobRepository;
|
||||
private Integer startLimit;
|
||||
private Tasklet tasklet;
|
||||
private PlatformTransactionManager transactionManager;
|
||||
|
||||
//
|
||||
// Step Elements
|
||||
//
|
||||
private StepListener[] listeners;
|
||||
private TransactionAttribute transactionAttribute;
|
||||
|
||||
//
|
||||
// Tasklet Attributes
|
||||
//
|
||||
private Integer cacheCapacity;
|
||||
private CompletionPolicy chunkCompletionPolicy;
|
||||
private Integer commitInterval;
|
||||
private Boolean isReaderTransactionalQueue;
|
||||
private Integer retryLimit;
|
||||
private Integer skipLimit;
|
||||
private TaskExecutor taskExecutor;
|
||||
private ItemReader<? extends I> itemReader;
|
||||
private ItemProcessor<? super I, ? extends O> itemProcessor;
|
||||
private ItemWriter<? super O> itemWriter;
|
||||
|
||||
//
|
||||
// Tasklet Elements
|
||||
//
|
||||
private RetryListener[] retryListeners;
|
||||
private Collection<Class<? extends Throwable>> skippableExceptionClasses;
|
||||
private Collection<Class<? extends Throwable>> retryableExceptionClasses;
|
||||
private Collection<Class<? extends Throwable>> fatalExceptionClasses;
|
||||
private ItemStream[] streams;
|
||||
|
||||
//
|
||||
// Additional
|
||||
//
|
||||
private boolean hasTaskletElement = false;
|
||||
|
||||
/**
|
||||
* Create a {@link Step} from the configuration provided.
|
||||
*
|
||||
* @see FactoryBean#getObject()
|
||||
*/
|
||||
public final Object getObject() throws Exception {
|
||||
if (hasTaskletElement) {
|
||||
Assert.isNull(tasklet, "Step [" + name + "] has both a <tasklet/> element and a 'tasklet' attribute.");
|
||||
|
||||
if (isFaultTolerant()) {
|
||||
FaultTolerantStepFactoryBean<I, O> fb = new FaultTolerantStepFactoryBean<I, O>();
|
||||
configureSimple(fb);
|
||||
configureFaultTolerant(fb);
|
||||
return fb.getObject();
|
||||
}
|
||||
else {
|
||||
validateSimpleStep();
|
||||
SimpleStepFactoryBean<I, O> fb = new SimpleStepFactoryBean<I, O>();
|
||||
configureSimple(fb);
|
||||
return fb.getObject();
|
||||
}
|
||||
}
|
||||
else if (tasklet != null) {
|
||||
validateTaskletStep();
|
||||
TaskletStep ts = new TaskletStep();
|
||||
configureTaskletStep(ts);
|
||||
return ts;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Step [" + name
|
||||
+ "] has neither a <tasklet/> element nor a 'tasklet' attribute.");
|
||||
}
|
||||
}
|
||||
|
||||
private void configureSimple(SimpleStepFactoryBean<I, O> fb) {
|
||||
if (name != null) {
|
||||
fb.setBeanName(name);
|
||||
}
|
||||
if (allowStartIfComplete != null) {
|
||||
fb.setAllowStartIfComplete(allowStartIfComplete);
|
||||
}
|
||||
if (jobRepository != null) {
|
||||
fb.setJobRepository(jobRepository);
|
||||
}
|
||||
if (startLimit != null) {
|
||||
fb.setStartLimit(startLimit);
|
||||
}
|
||||
if (transactionManager != null) {
|
||||
fb.setTransactionManager(transactionManager);
|
||||
}
|
||||
if (listeners != null) {
|
||||
fb.setListeners(listeners);
|
||||
}
|
||||
if (transactionAttribute != null) {
|
||||
fb.setTransactionAttribute(transactionAttribute);
|
||||
}
|
||||
|
||||
if (chunkCompletionPolicy != null) {
|
||||
fb.setChunkCompletionPolicy(chunkCompletionPolicy);
|
||||
}
|
||||
if (commitInterval != null) {
|
||||
fb.setCommitInterval(commitInterval);
|
||||
}
|
||||
if (taskExecutor != null) {
|
||||
fb.setTaskExecutor(taskExecutor);
|
||||
}
|
||||
if (itemReader != null) {
|
||||
fb.setItemReader(itemReader);
|
||||
}
|
||||
if (itemProcessor != null) {
|
||||
fb.setItemProcessor(itemProcessor);
|
||||
}
|
||||
if (itemWriter != null) {
|
||||
fb.setItemWriter(itemWriter);
|
||||
}
|
||||
|
||||
if (streams != null) {
|
||||
fb.setStreams(streams);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureFaultTolerant(FaultTolerantStepFactoryBean<I, O> fb) {
|
||||
if (cacheCapacity != null) {
|
||||
fb.setCacheCapacity(cacheCapacity);
|
||||
}
|
||||
if (isReaderTransactionalQueue != null) {
|
||||
fb.setIsReaderTransactionalQueue(isReaderTransactionalQueue);
|
||||
}
|
||||
if (retryLimit != null) {
|
||||
fb.setRetryLimit(retryLimit);
|
||||
}
|
||||
if (skipLimit != null) {
|
||||
fb.setSkipLimit(skipLimit);
|
||||
}
|
||||
|
||||
if (retryListeners != null) {
|
||||
fb.setRetryListeners(retryListeners);
|
||||
}
|
||||
if (skippableExceptionClasses != null) {
|
||||
fb.setSkippableExceptionClasses(skippableExceptionClasses);
|
||||
}
|
||||
if (retryableExceptionClasses != null) {
|
||||
fb.setRetryableExceptionClasses(retryableExceptionClasses);
|
||||
}
|
||||
if (fatalExceptionClasses != null) {
|
||||
fb.setFatalExceptionClasses(fatalExceptionClasses);
|
||||
}
|
||||
}
|
||||
|
||||
private void configureTaskletStep(TaskletStep ts) {
|
||||
if (name != null) {
|
||||
ts.setName(name);
|
||||
}
|
||||
if (allowStartIfComplete != null) {
|
||||
ts.setAllowStartIfComplete(allowStartIfComplete);
|
||||
}
|
||||
if (jobRepository != null) {
|
||||
ts.setJobRepository(jobRepository);
|
||||
}
|
||||
if (startLimit != null) {
|
||||
ts.setStartLimit(startLimit);
|
||||
}
|
||||
if (tasklet != null) {
|
||||
ts.setTasklet(tasklet);
|
||||
}
|
||||
if (transactionManager != null) {
|
||||
ts.setTransactionManager(transactionManager);
|
||||
}
|
||||
if (listeners != null) {
|
||||
int i = 0;
|
||||
StepExecutionListener[] newListeners = new StepExecutionListener[listeners.length];
|
||||
for (StepListener listener : listeners) {
|
||||
newListeners[i++] = (StepExecutionListener) listener;
|
||||
}
|
||||
ts.setStepExecutionListeners((StepExecutionListener[]) newListeners);
|
||||
}
|
||||
if (transactionAttribute != null) {
|
||||
ts.setTransactionAttribute(transactionAttribute);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateSimpleStep() {
|
||||
PropertyNamePair[] notPermitted = new PropertyNamePair[] {
|
||||
new PropertyNamePair(cacheCapacity, "cacheCapacity"), new PropertyNamePair(retryLimit, "retryLimit"),
|
||||
new PropertyNamePair(skipLimit, "skipLimit"), new PropertyNamePair(retryListeners, "retryListeners"),
|
||||
new PropertyNamePair(skippableExceptionClasses, "skippableExceptionClasses"),
|
||||
new PropertyNamePair(retryableExceptionClasses, "retryableExceptionClasses"),
|
||||
new PropertyNamePair(fatalExceptionClasses, "fatalExceptionClasses") };
|
||||
validateDisallowedFields("on the simple step [" + name + "]. They can only be specified for fault-tolerant "
|
||||
+ "configurations providing skip-limit, retry-limit, or cache-capacity", notPermitted);
|
||||
}
|
||||
|
||||
private void validateTaskletStep() {
|
||||
PropertyNamePair[] notPermitted = new PropertyNamePair[] {
|
||||
new PropertyNamePair(cacheCapacity, "cacheCapacity"),
|
||||
new PropertyNamePair(chunkCompletionPolicy, "chunkCompletionPolicy"),
|
||||
new PropertyNamePair(commitInterval, "commitInterval"), new PropertyNamePair(retryLimit, "retryLimit"),
|
||||
new PropertyNamePair(skipLimit, "skipLimit"), new PropertyNamePair(taskExecutor, "taskExecutor"),
|
||||
new PropertyNamePair(itemReader, "itemReader"), new PropertyNamePair(itemProcessor, "itemProcessor"),
|
||||
new PropertyNamePair(itemWriter, "itemWriter"), new PropertyNamePair(retryListeners, "retryListeners"),
|
||||
new PropertyNamePair(skippableExceptionClasses, "skippableExceptionClasses"),
|
||||
new PropertyNamePair(retryableExceptionClasses, "retryableExceptionClasses"),
|
||||
new PropertyNamePair(fatalExceptionClasses, "fatalExceptionClasses"),
|
||||
new PropertyNamePair(streams, "streams") };
|
||||
validateDisallowedFields("when a 'tasklet' attribute is specified, as it is on [" + name + "]", notPermitted);
|
||||
}
|
||||
|
||||
private void validateDisallowedFields(String msg, PropertyNamePair... notPermitted) {
|
||||
List<String> wrong = new ArrayList<String>();
|
||||
for (PropertyNamePair field : notPermitted) {
|
||||
if (field.getProperty() != null) {
|
||||
wrong.add(field.getName());
|
||||
}
|
||||
}
|
||||
if (!wrong.isEmpty()) {
|
||||
throw new IllegalArgumentException("The field" + (wrong.size() > 1 ? "s " : " ") + wrong
|
||||
+ (wrong.size() == 1 ? " is" : " are") + " not permitted " + msg);
|
||||
}
|
||||
}
|
||||
|
||||
private static class PropertyNamePair {
|
||||
private Object property;
|
||||
private String name;
|
||||
|
||||
public PropertyNamePair(Object property, String name) {
|
||||
super();
|
||||
this.property = property;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public Object getProperty() {
|
||||
return property;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isFaultTolerant() {
|
||||
return isPositive(skipLimit) || isPositive(retryLimit) || isPositive(cacheCapacity)
|
||||
|| isTrue(isReaderTransactionalQueue);
|
||||
}
|
||||
|
||||
private boolean isTrue(Boolean b) {
|
||||
return b != null && b.booleanValue();
|
||||
}
|
||||
|
||||
private boolean isPositive(Integer n) {
|
||||
return n != null && n > 0;
|
||||
}
|
||||
|
||||
public Class<Step> getObjectType() {
|
||||
return Step.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Step Attributes
|
||||
// =========================================================
|
||||
|
||||
/**
|
||||
* Set the bean name property, which will become the name of the
|
||||
* {@link Step} when it is created.
|
||||
*
|
||||
* @see org.springframework.beans.factory.BeanNameAware#setBeanName(java.lang.String)
|
||||
*/
|
||||
public void setBeanName(String name) {
|
||||
if (this.name == null) {
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the flag to indicate that the step should be replayed
|
||||
* on a restart, even if successful the first time.
|
||||
*
|
||||
* @param allowStartIfComplete the shouldAllowStartIfComplete to set
|
||||
*/
|
||||
public void setAllowStartIfComplete(boolean allowStartIfComplete) {
|
||||
this.allowStartIfComplete = allowStartIfComplete;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for {@link JobRepository}.
|
||||
*
|
||||
* @param jobRepository
|
||||
*/
|
||||
public void setJobRepository(JobRepository jobRepository) {
|
||||
this.jobRepository = jobRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* The number of times that the step should be allowed to start
|
||||
*
|
||||
* @param startLimit
|
||||
*/
|
||||
public void setStartLimit(int startLimit) {
|
||||
this.startLimit = startLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* A preconfigured {@link Tasklet} to use.
|
||||
*
|
||||
* @param tasklet
|
||||
*/
|
||||
public void setTasklet(Tasklet tasklet) {
|
||||
this.tasklet = tasklet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transactionManager the transaction manager to set
|
||||
*/
|
||||
public void setTransactionManager(PlatformTransactionManager transactionManager) {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Step Elements
|
||||
// =========================================================
|
||||
|
||||
/**
|
||||
* The listeners to inject into the {@link Step}. Any instance of
|
||||
* {@link StepListener} can be used, and will then receive callbacks at the
|
||||
* appropriate stage in the step.
|
||||
*
|
||||
* @param listeners an array of listeners
|
||||
*/
|
||||
public void setListeners(StepListener[] listeners) {
|
||||
this.listeners = listeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the transaction attribute with a list of all the individual
|
||||
* attributes.
|
||||
*
|
||||
* @param transactionAttributeList
|
||||
*/
|
||||
public void setTransactionAttributeList(List<String> transactionAttributeList) {
|
||||
String[] stringArray = transactionAttributeList.toArray(new String[0]);
|
||||
String attributeString = StringUtils.arrayToCommaDelimitedString(stringArray);
|
||||
PropertyEditor editor = new TransactionAttributeEditor();
|
||||
editor.setAsText(attributeString);
|
||||
this.setTransactionAttribute((TransactionAttribute) editor.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transactionAttribute the {@link TransactionAttribute} to set
|
||||
*/
|
||||
public void setTransactionAttribute(TransactionAttribute transactionAttribute) {
|
||||
this.transactionAttribute = transactionAttribute;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Tasklet Attributes
|
||||
// =========================================================
|
||||
|
||||
/**
|
||||
* Public setter for the capacity of the cache in the retry policy. If more
|
||||
* items than this fail without being skipped or recovered an exception will
|
||||
* be thrown. This is to guard against inadvertent infinite loops generated
|
||||
* by item identity problems.<br/>
|
||||
*
|
||||
* The default value should be high enough and more for most purposes. To
|
||||
* breach the limit in a single-threaded step typically you have to have
|
||||
* this many failures in a single transaction. Defaults to the value in the
|
||||
* {@link MapRetryContextCache}.<br/>
|
||||
*
|
||||
* @param cacheCapacity the cache capacity to set (greater than 0 else
|
||||
* ignored)
|
||||
*/
|
||||
public void setCacheCapacity(int cacheCapacity) {
|
||||
this.cacheCapacity = cacheCapacity;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link CompletionPolicy} applying to the chunk
|
||||
* level. A transaction will be committed when this policy decides to
|
||||
* complete. Defaults to a {@link SimpleCompletionPolicy} with chunk size
|
||||
* equal to the commitInterval property.
|
||||
*
|
||||
* @param chunkCompletionPolicy the chunkCompletionPolicy to set
|
||||
*/
|
||||
public void setChunkCompletionPolicy(CompletionPolicy chunkCompletionPolicy) {
|
||||
this.chunkCompletionPolicy = chunkCompletionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the commit interval. Either set this or the chunkCompletionPolicy but
|
||||
* not both.
|
||||
*
|
||||
* @param commitInterval 1 by default
|
||||
*/
|
||||
public void setCommitInterval(int commitInterval) {
|
||||
this.commitInterval = commitInterval;
|
||||
}
|
||||
|
||||
/**
|
||||
* Flag to signal that the reader is transactional (usually a JMS consumer)
|
||||
* so that items are re-presented after a rollback. The default is false and
|
||||
* readers are assumed to be forward-only.
|
||||
*
|
||||
* @param isReaderTransactionalQueue the value of the flag
|
||||
*/
|
||||
public void setIsReaderTransactionalQueue(boolean isReaderTransactionalQueue) {
|
||||
this.isReaderTransactionalQueue = isReaderTransactionalQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the retry limit. Each item can be retried up to this
|
||||
* limit. Note this limit includes the initial attempt to process the item,
|
||||
* therefore <code>retryLimit == 1</code> by default.
|
||||
*
|
||||
* @param retryLimit the retry limit to set, must be greater or equal to 1.
|
||||
*/
|
||||
public void setRetryLimit(int retryLimit) {
|
||||
this.retryLimit = retryLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for a limit that determines skip policy. If this value is
|
||||
* positive then an exception in chunk processing will cause the item to be
|
||||
* skipped and no exception propagated until the limit is reached. If it is
|
||||
* zero then all exceptions will be propagated from the chunk and cause the
|
||||
* step to abort.
|
||||
*
|
||||
* @param skipLimit the value to set. Default is 0 (never skip).
|
||||
*/
|
||||
public void setSkipLimit(int skipLimit) {
|
||||
this.skipLimit = skipLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link TaskExecutor}. If this is set, then it will
|
||||
* be used to execute the chunk processing inside the {@link Step}.
|
||||
*
|
||||
* @param taskExecutor the taskExecutor to set
|
||||
*/
|
||||
public void setTaskExecutor(TaskExecutor taskExecutor) {
|
||||
this.taskExecutor = taskExecutor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemReader the {@link ItemReader} to set
|
||||
*/
|
||||
public void setItemReader(ItemReader<? extends I> itemReader) {
|
||||
this.itemReader = itemReader;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemProcessor the {@link ItemProcessor} to set
|
||||
*/
|
||||
public void setItemProcessor(ItemProcessor<? super I, ? extends O> itemProcessor) {
|
||||
this.itemProcessor = itemProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemWriter the {@link ItemWriter} to set
|
||||
*/
|
||||
public void setItemWriter(ItemWriter<? super O> itemWriter) {
|
||||
this.itemWriter = itemWriter;
|
||||
}
|
||||
|
||||
// =========================================================
|
||||
// Tasklet Elements
|
||||
// =========================================================
|
||||
|
||||
/**
|
||||
* Public setter for the {@link RetryListener}s.
|
||||
*
|
||||
* @param retryListeners the {@link RetryListener}s to set
|
||||
*/
|
||||
public void setRetryListeners(RetryListener... retryListeners) {
|
||||
this.retryListeners = retryListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for exception classes that when raised won't crash the job
|
||||
* but will result in transaction rollback and the item which handling
|
||||
* caused the exception will be skipped.
|
||||
*
|
||||
* @param exceptionClasses
|
||||
*/
|
||||
public void setSkippableExceptionClasses(Collection<Class<? extends Throwable>> exceptionClasses) {
|
||||
this.skippableExceptionClasses = exceptionClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for exception classes that will retry the item when raised.
|
||||
*
|
||||
* @param retryableExceptionClasses the retryableExceptionClasses to set
|
||||
*/
|
||||
public void setRetryableExceptionClasses(Collection<Class<? extends Throwable>> retryableExceptionClasses) {
|
||||
this.retryableExceptionClasses = retryableExceptionClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for exception classes that should cause immediate failure.
|
||||
*
|
||||
* @param fatalExceptionClasses
|
||||
*/
|
||||
public void setFatalExceptionClasses(Collection<Class<? extends Throwable>> fatalExceptionClasses) {
|
||||
this.fatalExceptionClasses = fatalExceptionClasses;
|
||||
}
|
||||
|
||||
/**
|
||||
* The streams to inject into the {@link Step}. Any instance of
|
||||
* {@link ItemStream} can be used, and will then receive callbacks at the
|
||||
* appropriate stage in the step.
|
||||
*
|
||||
* @param streams an array of listeners
|
||||
*/
|
||||
public void setStreams(ItemStream[] streams) {
|
||||
this.streams = streams;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param hasTaskletElement
|
||||
*/
|
||||
public void setHasTaskletElement(boolean hasTaskletElement) {
|
||||
this.hasTaskletElement = hasTaskletElement;
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,6 @@
|
||||
*/
|
||||
package org.springframework.batch.core.step.tasklet;
|
||||
|
||||
import java.beans.PropertyEditor;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.Semaphore;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -34,7 +32,6 @@ import org.springframework.batch.core.scope.context.StepContextRepeatCallback;
|
||||
import org.springframework.batch.core.step.AbstractStep;
|
||||
import org.springframework.batch.core.step.StepInterruptionPolicy;
|
||||
import org.springframework.batch.core.step.ThreadStepInterruptionPolicy;
|
||||
import org.springframework.batch.core.step.item.SimpleStepFactoryBean;
|
||||
import org.springframework.batch.item.ExecutionContext;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
@@ -48,9 +45,7 @@ import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttribute;
|
||||
import org.springframework.transaction.interceptor.TransactionAttributeEditor;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Simple implementation of executing the step as a call to a {@link Tasklet},
|
||||
@@ -130,20 +125,6 @@ public class TaskletStep extends AbstractStep {
|
||||
this.transactionManager = transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link TransactionAttribute}.
|
||||
*
|
||||
* @param transactionAttributeList A list of all the transaction attributes
|
||||
* to set
|
||||
*/
|
||||
public void setTransactionAttributeList(List<String> transactionAttributeList) {
|
||||
String[] stringArray = transactionAttributeList.toArray(new String[0]);
|
||||
String attributeString = StringUtils.arrayToCommaDelimitedString(stringArray);
|
||||
PropertyEditor editor = new TransactionAttributeEditor();
|
||||
editor.setAsText(attributeString);
|
||||
this.setTransactionAttribute((TransactionAttribute) editor.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link TransactionAttribute}.
|
||||
*
|
||||
@@ -235,20 +216,6 @@ public class TaskletStep extends AbstractStep {
|
||||
this.interruptionPolicy = interruptionPolicy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Variation on
|
||||
* {@link AbstractStep#setStepExecutionListeners(StepExecutionListener[])}.
|
||||
* This method exists because the parser requires a "listeners" property
|
||||
* setter to match the one on {@link SimpleStepFactoryBean}.
|
||||
*
|
||||
* @param listeners
|
||||
* @see AbstractStep#setStepExecutionListeners(StepExecutionListener[])
|
||||
* @see SimpleStepFactoryBean#setListeners(org.springframework.batch.core.StepListener[])
|
||||
*/
|
||||
public void setListeners(StepExecutionListener[] listeners) {
|
||||
this.setStepExecutionListeners(listeners);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process the step and update its context so that progress can be monitored
|
||||
* by the caller. The step is broken down into chunks, each one executing in
|
||||
|
||||
@@ -27,7 +27,7 @@ import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.listener.StepExecutionListenerSupport;
|
||||
import org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean;
|
||||
import org.springframework.batch.core.step.item.StepFactoryBean;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.repeat.CompletionPolicy;
|
||||
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
|
||||
@@ -50,10 +50,9 @@ public class StepParserTests {
|
||||
public void testTaskletStepAttributes() throws Exception {
|
||||
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/StepParserTaskletAttributesTests-context.xml");
|
||||
Map<String, Object> beans = ctx.getBeansOfType(FaultTolerantStepFactoryBean.class);
|
||||
Map<String, Object> beans = ctx.getBeansOfType(StepFactoryBean.class);
|
||||
String factoryName = (String) beans.keySet().toArray()[0];
|
||||
FaultTolerantStepFactoryBean<Object, Object> factory = (FaultTolerantStepFactoryBean<Object, Object>) beans
|
||||
.get(factoryName);
|
||||
StepFactoryBean<Object, Object> factory = (StepFactoryBean<Object, Object>) beans.get(factoryName);
|
||||
TaskletStep bean = (TaskletStep) factory.getObject();
|
||||
assertEquals("wrong start-limit:", 25, bean.getStartLimit());
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.StepListener;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
|
||||
import org.springframework.batch.core.step.item.SimpleStepFactoryBean;
|
||||
import org.springframework.batch.core.step.item.StepFactoryBean;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
@@ -67,7 +67,7 @@ public class StepWithBasicProcessTaskJobParserTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Autowired
|
||||
private SimpleStepFactoryBean factory;
|
||||
private StepFactoryBean factory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
@@ -29,7 +29,7 @@ import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.StepListener;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
|
||||
import org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean;
|
||||
import org.springframework.batch.core.step.item.StepFactoryBean;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.retry.RetryListener;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -75,7 +75,7 @@ public class StepWithFaultTolerantProcessTaskJobParserTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Autowired
|
||||
private FaultTolerantStepFactoryBean factory;
|
||||
private StepFactoryBean factory;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
|
||||
@@ -43,7 +43,7 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
*/
|
||||
public class TaskletElementParserTests {
|
||||
|
||||
ConfigurableApplicationContext taskletElementParentAttributeParserTestsContext = new ClassPathXmlApplicationContext(
|
||||
private ConfigurableApplicationContext taskletElementParentAttributeParserTestsContext = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/TaskletElementParentAttributeParserTests-context.xml");
|
||||
|
||||
@Test
|
||||
|
||||
@@ -0,0 +1,195 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.batch.core.step.item;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.batch.core.StepListener;
|
||||
import org.springframework.batch.core.configuration.xml.DummyCompletionPolicy;
|
||||
import org.springframework.batch.core.configuration.xml.DummyItemReader;
|
||||
import org.springframework.batch.core.configuration.xml.DummyItemWriter;
|
||||
import org.springframework.batch.core.configuration.xml.DummyTasklet;
|
||||
import org.springframework.batch.core.listener.StepExecutionListenerSupport;
|
||||
import org.springframework.batch.core.step.JobRepositorySupport;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.item.ItemStream;
|
||||
import org.springframework.batch.item.file.FlatFileItemReader;
|
||||
import org.springframework.batch.item.support.PassThroughItemProcessor;
|
||||
import org.springframework.batch.retry.listener.RetryListenerSupport;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.core.task.SyncTaskExecutor;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
|
||||
/**
|
||||
* @author Dan Garrette
|
||||
* @since 2.0
|
||||
*/
|
||||
public class StepFactoryBeanTests {
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testNothingSet() throws Exception {
|
||||
StepFactoryBean<Object, Object> fb = new StepFactoryBean<Object, Object>();
|
||||
fb.getObject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testOnlyTaskletSet() throws Exception {
|
||||
StepFactoryBean<Object, Object> fb = new StepFactoryBean<Object, Object>();
|
||||
fb.setTasklet(new DummyTasklet());
|
||||
Object step = fb.getObject();
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
|
||||
assertTrue(tasklet instanceof DummyTasklet);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testSkipLimitSet() throws Exception {
|
||||
StepFactoryBean<Object, Object> fb = new StepFactoryBean<Object, Object>();
|
||||
fb.setSkipLimit(5);
|
||||
fb.getObject();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskletStep_All() throws Exception {
|
||||
StepFactoryBean<Object, Object> fb = new StepFactoryBean<Object, Object>();
|
||||
fb.setBeanName("step1");
|
||||
fb.setAllowStartIfComplete(true);
|
||||
fb.setJobRepository(new JobRepositorySupport());
|
||||
fb.setStartLimit(5);
|
||||
fb.setTasklet(new DummyTasklet());
|
||||
fb.setTransactionManager(new ResourcelessTransactionManager());
|
||||
fb.setListeners(new StepExecutionListenerSupport[] { new StepExecutionListenerSupport() });
|
||||
fb.setTransactionAttributeList(new ArrayList<String>());
|
||||
Object step = fb.getObject();
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
|
||||
assertTrue(tasklet instanceof DummyTasklet);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testSimpleStep_All() throws Exception {
|
||||
StepFactoryBean<Object, Object> fb = new StepFactoryBean<Object, Object>();
|
||||
fb.setBeanName("step1");
|
||||
fb.setAllowStartIfComplete(true);
|
||||
fb.setJobRepository(new JobRepositorySupport());
|
||||
fb.setStartLimit(5);
|
||||
fb.setTransactionManager(new ResourcelessTransactionManager());
|
||||
fb.setListeners(new StepListener[] { new StepExecutionListenerSupport() });
|
||||
fb.setTransactionAttributeList(new ArrayList<String>());
|
||||
fb.setChunkCompletionPolicy(new DummyCompletionPolicy());
|
||||
fb.setCommitInterval(5);
|
||||
fb.setTaskExecutor(new SyncTaskExecutor());
|
||||
fb.setItemReader(new DummyItemReader());
|
||||
fb.setItemWriter(new DummyItemWriter());
|
||||
fb.setStreams(new ItemStream[] { new FlatFileItemReader<Object>() });
|
||||
|
||||
Object step = fb.getObject();
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
|
||||
assertTrue(tasklet instanceof ChunkOrientedTasklet);
|
||||
}
|
||||
|
||||
@Test(expected = IllegalStateException.class)
|
||||
public void testFaultTolerantStep_All() throws Exception {
|
||||
StepFactoryBean<Object, Object> fb = new StepFactoryBean<Object, Object>();
|
||||
fb.setBeanName("step1");
|
||||
fb.setAllowStartIfComplete(true);
|
||||
fb.setJobRepository(new JobRepositorySupport());
|
||||
fb.setStartLimit(5);
|
||||
fb.setTransactionManager(new ResourcelessTransactionManager());
|
||||
fb.setListeners(new StepListener[] { new StepExecutionListenerSupport() });
|
||||
fb.setTransactionAttributeList(new ArrayList<String>());
|
||||
fb.setChunkCompletionPolicy(new DummyCompletionPolicy());
|
||||
fb.setCommitInterval(5);
|
||||
fb.setTaskExecutor(new SyncTaskExecutor());
|
||||
fb.setItemReader(new DummyItemReader());
|
||||
fb.setItemWriter(new DummyItemWriter());
|
||||
fb.setStreams(new ItemStream[] { new FlatFileItemReader<Object>() });
|
||||
fb.setCacheCapacity(5);
|
||||
fb.setIsReaderTransactionalQueue(true);
|
||||
fb.setRetryLimit(5);
|
||||
fb.setSkipLimit(100);
|
||||
fb.setRetryListeners(new RetryListenerSupport());
|
||||
fb.setSkippableExceptionClasses(new ArrayList<Class<? extends Throwable>>());
|
||||
fb.setRetryableExceptionClasses(new ArrayList<Class<? extends Throwable>>());
|
||||
fb.setFatalExceptionClasses(new ArrayList<Class<? extends Throwable>>());
|
||||
|
||||
Object step = fb.getObject();
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
|
||||
assertTrue(tasklet instanceof ChunkOrientedTasklet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSimpleStep() throws Exception {
|
||||
StepFactoryBean<Object, Object> fb = new StepFactoryBean<Object, Object>();
|
||||
fb.setHasTaskletElement(true);
|
||||
fb.setBeanName("step1");
|
||||
fb.setAllowStartIfComplete(true);
|
||||
fb.setJobRepository(new JobRepositorySupport());
|
||||
fb.setStartLimit(5);
|
||||
fb.setTransactionManager(new ResourcelessTransactionManager());
|
||||
fb.setListeners(new StepListener[] { new StepExecutionListenerSupport() });
|
||||
fb.setTransactionAttributeList(new ArrayList<String>());
|
||||
fb.setChunkCompletionPolicy(new DummyCompletionPolicy());
|
||||
fb.setTaskExecutor(new SyncTaskExecutor());
|
||||
fb.setItemReader(new DummyItemReader());
|
||||
fb.setItemProcessor(new PassThroughItemProcessor<Object>());
|
||||
fb.setItemWriter(new DummyItemWriter());
|
||||
fb.setStreams(new ItemStream[] { new FlatFileItemReader<Object>() });
|
||||
|
||||
Object step = fb.getObject();
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
|
||||
assertTrue(tasklet instanceof ChunkOrientedTasklet);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFaultTolerantStep() throws Exception {
|
||||
StepFactoryBean<Object, Object> fb = new StepFactoryBean<Object, Object>();
|
||||
fb.setHasTaskletElement(true);
|
||||
fb.setBeanName("step1");
|
||||
fb.setAllowStartIfComplete(true);
|
||||
fb.setJobRepository(new JobRepositorySupport());
|
||||
fb.setStartLimit(5);
|
||||
fb.setTransactionManager(new ResourcelessTransactionManager());
|
||||
fb.setListeners(new StepListener[] { new StepExecutionListenerSupport() });
|
||||
fb.setTransactionAttributeList(new ArrayList<String>());
|
||||
fb.setChunkCompletionPolicy(new DummyCompletionPolicy());
|
||||
fb.setTaskExecutor(new SyncTaskExecutor());
|
||||
fb.setItemReader(new DummyItemReader());
|
||||
fb.setItemProcessor(new PassThroughItemProcessor<Object>());
|
||||
fb.setItemWriter(new DummyItemWriter());
|
||||
fb.setStreams(new ItemStream[] { new FlatFileItemReader<Object>() });
|
||||
fb.setCacheCapacity(5);
|
||||
fb.setIsReaderTransactionalQueue(true);
|
||||
fb.setRetryLimit(5);
|
||||
fb.setSkipLimit(100);
|
||||
fb.setRetryListeners(new RetryListenerSupport());
|
||||
fb.setSkippableExceptionClasses(new ArrayList<Class<? extends Throwable>>());
|
||||
fb.setRetryableExceptionClasses(new ArrayList<Class<? extends Throwable>>());
|
||||
fb.setFatalExceptionClasses(new ArrayList<Class<? extends Throwable>>());
|
||||
|
||||
Object step = fb.getObject();
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
|
||||
assertTrue(tasklet instanceof ChunkOrientedTasklet);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user