BATCH-1712: use parent bean def for handler to avoid clashes of step instances

This commit is contained in:
Dave Syer
2011-03-15 12:27:37 +00:00
parent 57b0cb7498
commit 4f17e16738
8 changed files with 289 additions and 140 deletions

View File

@@ -1,6 +1,7 @@
#Tue Feb 01 21:15:00 GMT 2011
#Tue Mar 15 12:05:10 GMT 2011
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobExecutionListenerMethodAttributeParserTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="995" endstart\="989" start\="511" startend\="586"/>\n<bounds height\="118" width\="77" x\="15" y\="17"/>\n</element>\n</graph>
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/JobRepositoryDefaultParserTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph/>
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/PartitionStepParserTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="689" endstart\="683" start\="510" startend\="525"/>\n<bounds height\="128" width\="84" x\="15" y\="17"/>\n</element>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="860" endstart\="854" start\="692" startend\="707"/>\n<bounds height\="172" width\="84" x\="207" y\="17"/>\n</element>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="1018" endstart\="1012" start\="863" startend\="878"/>\n<bounds height\="128" width\="84" x\="111" y\="17"/>\n</element>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="1271" endstart\="1265" start\="1021" startend\="1036"/>\n<bounds height\="128" width\="84" x\="303" y\="17"/>\n</element>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="1388" endstart\="1382" start\="1274" startend\="1289"/>\n<bounds height\="128" width\="84" x\="399" y\="17"/>\n</element>\n</graph>
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepListenerInStepParserTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="1832" endstart\="1826" start\="510" startend\="524"/>\n<bounds height\="268" width\="77" x\="15" y\="17"/>\n</element>\n</graph>
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepListenerMethodAttributeParserTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element type\="job">\n<structure end\="854" endstart\="848" start\="511" startend\="525"/>\n<bounds height\="118" width\="77" x\="15" y\="17"/>\n</element>\n</graph>
//com.springsource.sts.config.flow.coordinates\:http\://www.springframework.org/schema/batch\:/spring-batch-core/src/test/resources/org/springframework/batch/core/configuration/xml/StepListenerParserTests-context.xml=<?xml version\="1.0" encoding\="UTF-8"?>\n<graph>\n<element clazz\="JobModelElement" type\="job">\n<structure end\="1650" endstart\="1644" start\="510" startend\="524"/>\n<bounds height\="218" width\="77" x\="15" y\="17"/>\n</element>\n</graph>

View File

@@ -157,24 +157,11 @@ public abstract class AbstractStepParser {
return;
}
Element inlineStepElement = DomUtils.getChildElementByTagName(partitionElement, STEP_ELE);
if (inlineStepElement == null && !StringUtils.hasText(stepRef)) {
parserContext.getReaderContext().error("You must specify a step", partitionElement);
return;
}
MutablePropertyValues propertyValues = bd.getPropertyValues();
if (StringUtils.hasText(stepRef)) {
propertyValues.addPropertyValue("step", new RuntimeBeanReference(stepRef));
} else if( inlineStepElement!=null) {
AbstractBeanDefinition stepDefinition = parseStep(inlineStepElement, parserContext, jobFactoryRef);
propertyValues.addPropertyValue("step", stepDefinition );
}
propertyValues.addPropertyValue("partitioner", new RuntimeBeanReference(partitionerRef));
boolean customHandler = false;
if (!StringUtils.hasText(handlerRef)) {
Element handlerElement = DomUtils.getChildElementByTagName(partitionElement, HANDLER_ELE);
if (handlerElement != null) {
@@ -188,7 +175,24 @@ public abstract class AbstractStepParser {
}
}
} else {
propertyValues.addPropertyValue("partitionHandler", new RuntimeBeanReference(handlerRef));
customHandler = true;
BeanDefinition partitionHandler = BeanDefinitionBuilder.genericBeanDefinition().getRawBeanDefinition();
partitionHandler.setParentName(handlerRef);
propertyValues.addPropertyValue("partitionHandler", partitionHandler);
}
Element inlineStepElement = DomUtils.getChildElementByTagName(partitionElement, STEP_ELE);
if (inlineStepElement == null && !StringUtils.hasText(stepRef) && !customHandler) {
parserContext.getReaderContext().error("You must specify a step", partitionElement);
return;
}
if (StringUtils.hasText(stepRef)) {
propertyValues.addPropertyValue("step", new RuntimeBeanReference(stepRef));
} else if( inlineStepElement!=null) {
AbstractBeanDefinition stepDefinition = parseStep(inlineStepElement, parserContext, jobFactoryRef);
stepDefinition.getPropertyValues().addPropertyValue("name", stepElement.getAttribute(ID_ATTR));
propertyValues.addPropertyValue("step", stepDefinition );
}
}

View File

@@ -22,6 +22,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.batch.classify.BinaryExceptionClassifier;
import org.springframework.batch.core.ChunkListener;
import org.springframework.batch.core.Job;
@@ -59,6 +61,7 @@ import org.springframework.batch.retry.RetryPolicy;
import org.springframework.batch.retry.backoff.BackOffPolicy;
import org.springframework.batch.retry.policy.MapRetryContextCache;
import org.springframework.batch.retry.policy.RetryContextCache;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.core.task.SyncTaskExecutor;
@@ -85,6 +88,8 @@ import org.springframework.util.Assert;
*/
class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
private static final Log logger = LogFactory.getLog(StepParserStepFactoryBean.class);
//
// Step Attributes
//
@@ -234,15 +239,11 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
configureJobStep(ts);
return ts;
}
else if (step != null) {
else {
PartitionStep ts = new PartitionStep();
configurePartitionStep(ts);
return ts;
}
else {
throw new IllegalStateException("Step [" + name
+ "] has neither a <chunk/> element nor a 'ref' attribute referencing a Tasklet.");
}
}
public boolean requiresTransactionManager() {
@@ -277,7 +278,6 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
private void configurePartitionStep(PartitionStep ts) {
Assert.state(partitioner != null, "A Partitioner must be provided for a partition step");
Assert.state(step != null, "A Step must be provided for a partition step");
configureAbstractStep(ts);
PartitionHandler handler;
@@ -300,17 +300,39 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
// BATCH-1659
if (handler instanceof TaskExecutorPartitionHandler) {
// Only for a local partition handler is the step required
Assert.state(step != null,
"A Step must be provided for a partition step with a TaskExecutorPartitionHandler");
try {
TaskExecutorPartitionHandler taskExecutorPartitionHandler = (TaskExecutorPartitionHandler) handler;
taskExecutorPartitionHandler.setStep(step);
taskExecutorPartitionHandler.afterPropertiesSet();
}
catch (Exception e) {
throw new RuntimeException(e);
throw new BeanCreationException("Could not configure TaskExecutorPartitionHandler", e);
}
}
else {
// Only for a local partition handler is the step required
Assert.state(step == null,
"A Step must not be provided for a custom partition handler (unless it extends TaskExecutorPartitionHandler). "
+ "It should be configured with its own step reference.");
}
SimpleStepExecutionSplitter splitter = new SimpleStepExecutionSplitter(jobRepository, step, partitioner);
boolean allowStartIfComplete = this.allowStartIfComplete !=null ? this.allowStartIfComplete : false;
String name = this.name;
if (step != null) {
try {
allowStartIfComplete = step.isAllowStartIfComplete();
name = step.getName();
}
catch (Exception e) {
logger.info("Ignored exception from step asking for name and allowStartIfComplete flag. "
+ "Using default from enclosing PartitionStep ("+name+","+allowStartIfComplete+").");
}
}
SimpleStepExecutionSplitter splitter = new SimpleStepExecutionSplitter(jobRepository, allowStartIfComplete,
name, partitioner);
ts.setStepExecutionSplitter(splitter);
}
@@ -578,6 +600,13 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
}
}
/**
* @param name the name to set
*/
public void setName(String name) {
this.name = name;
}
// =========================================================
// Flow Attributes
// =========================================================

View File

@@ -66,6 +66,23 @@ public class SimpleStepExecutionSplitter implements StepExecutionSplitter, Initi
public SimpleStepExecutionSplitter() {
}
/**
* Construct a {@link SimpleStepExecutionSplitter} from its mandatory
* properties.
*
* @param jobRepository the {@link JobRepository}
* @param allowStartIfComplete flag specifying preferences on restart
* @param stepName the target step name
* @param partitioner a {@link Partitioner} to use for generating input
* parameters
*/
public SimpleStepExecutionSplitter(JobRepository jobRepository, boolean allowStartIfComplete, String stepName, Partitioner partitioner) {
this.jobRepository = jobRepository;
this.allowStartIfComplete = allowStartIfComplete;
this.partitioner = partitioner;
this.stepName = stepName;
}
/**
* Construct a {@link SimpleStepExecutionSplitter} from its mandatory
* properties.
@@ -75,7 +92,10 @@ public class SimpleStepExecutionSplitter implements StepExecutionSplitter, Initi
* name and allowStartIfComplete flags
* @param partitioner a {@link Partitioner} to use for generating input
* parameters
*
* @deprecated use {@link #SimpleStepExecutionSplitter(JobRepository, boolean, String, Partitioner)} instead
*/
@Deprecated
public SimpleStepExecutionSplitter(JobRepository jobRepository, Step step, Partitioner partitioner) {
this.jobRepository = jobRepository;
this.allowStartIfComplete = step.isAllowStartIfComplete();

View File

@@ -34,12 +34,13 @@ import org.springframework.beans.factory.InitializingBean;
import org.springframework.core.task.SyncTaskExecutor;
import org.springframework.core.task.TaskExecutor;
import org.springframework.core.task.TaskRejectedException;
import org.springframework.util.Assert;
/**
* A {@link PartitionHandler} that uses a {@link TaskExecutor} to execute the
* partitioned {@link Step} locally in multiple threads. This can be an effective
* approach for scaling batch steps that are IO intensive, like directory and
* filesystem scanning and copying.
* partitioned {@link Step} locally in multiple threads. This can be an
* effective approach for scaling batch steps that are IO intensive, like
* directory and filesystem scanning and copying.
*
* @author Dave Syer
* @since 2.0
@@ -53,15 +54,14 @@ public class TaskExecutorPartitionHandler implements PartitionHandler, Initializ
private Step step;
public void afterPropertiesSet() throws Exception {
// Assert.notNull(step, "A Step must be provided.");
}
/**
* Passed to the {@link StepExecutionSplitter} in the
* {@link #handle(StepExecutionSplitter, StepExecution)} method, instructing
* it how many {@link StepExecution} instances are required, ideally. The
* {@link StepExecutionSplitter} is allowed to ignore the grid size in the case of
* a restart, since the input data partitions must be preserved.
* {@link StepExecutionSplitter} is allowed to ignore the grid size in the
* case of a restart, since the input data partitions must be preserved.
*
* @param gridSize the number of step executions that will be created
*/
@@ -96,6 +96,8 @@ public class TaskExecutorPartitionHandler implements PartitionHandler, Initializ
public Collection<StepExecution> handle(StepExecutionSplitter stepExecutionSplitter,
StepExecution masterStepExecution) throws Exception {
Assert.notNull(step, "A Step must be provided.");
Set<Future<StepExecution>> tasks = new HashSet<Future<StepExecution>>(gridSize);
Collection<StepExecution> result = new ArrayList<StepExecution>();

View File

@@ -20,6 +20,8 @@ import static org.junit.Assert.assertNotNull;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
@@ -27,6 +29,8 @@ import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.batch.core.*;
import org.springframework.batch.core.partition.PartitionHandler;
import org.springframework.batch.core.partition.StepExecutionSplitter;
import org.springframework.batch.core.partition.support.PartitionStep;
import org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler;
import org.springframework.batch.core.repository.JobRepository;
@@ -41,7 +45,6 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.util.ReflectionUtils;
/**
* @author Dave Syer
* @author Josh Long
@@ -50,102 +53,185 @@ import org.springframework.util.ReflectionUtils;
@RunWith(SpringJUnit4ClassRunner.class)
public class PartitionStepParserTests implements ApplicationContextAware {
@Autowired
@Qualifier("job1")
private Job job1;
@Autowired
@Qualifier("job1")
private Job job1;
@Autowired
@Qualifier("job2")
private Job job2;
@Autowired
@Qualifier("job2")
private Job job2;
@Autowired
@Qualifier("job3")
private Job job3;
@Autowired
@Qualifier("job3")
private Job job3;
@Autowired
private JobRepository jobRepository;
@Autowired
@Qualifier("job4")
private Job job4;
@Autowired
private MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean;
@Autowired
@Qualifier("job5")
private Job job5;
private ApplicationContext applicationContext;
@Autowired
@Qualifier("nameStoringTasklet")
private NameStoringTasklet nameStoringTasklet;
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
@Autowired
private JobRepository jobRepository;
@Before
public void setUp() {
mapJobRepositoryFactoryBean.clear();
}
@Autowired
private MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean;
@SuppressWarnings("unchecked")
private <T> T accessPrivateField(Object o, String fieldName) {
Field field = ReflectionUtils.findField(o.getClass(), fieldName);
boolean previouslyAccessibleValue = field.isAccessible();
field.setAccessible(true);
T val = (T) ReflectionUtils.getField(field, o);
field.setAccessible(previouslyAccessibleValue);
return val;
}
private ApplicationContext applicationContext;
/**
* BATCH-1509 we now support the ability define steps inline for partitioned steps.
* this demonstates that the execution proceeds as expected and that the partitionhandler has a reference to the inline step definition
*/
@Test
public void testNestedPartitionStepStepReference() throws Throwable {
assertNotNull("the reference to the job3 configured in the XML file must not be null", job3);
JobExecution jobExecution = jobRepository.createJobExecution(job3.getName(), new JobParameters());
private List<String> savedStepNames = new ArrayList<String>();
job3.execute(jobExecution);
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
for (StepExecution se : jobExecution.getStepExecutions()) {
String stepExecutionName = se.getStepName();
if (stepExecutionName.equalsIgnoreCase("j3s1")) { // the partitioned step
PartitionStep partitionStep = (PartitionStep) this.applicationContext.getBean(stepExecutionName);
@Before
public void setUp() {
nameStoringTasklet.setStepNamesList(savedStepNames);
mapJobRepositoryFactoryBean.clear();
}
// prove that the reference in the {@link TaskExecutorPartitionHandler} is the step configured inline
TaskExecutorPartitionHandler taskExecutorPartitionHandler = accessPrivateField(partitionStep, "partitionHandler");
TaskletStep taskletStep = accessPrivateField(taskExecutorPartitionHandler, "step");
@SuppressWarnings("unchecked")
private <T> T accessPrivateField(Object o, String fieldName) {
Field field = ReflectionUtils.findField(o.getClass(), fieldName);
boolean previouslyAccessibleValue = field.isAccessible();
field.setAccessible(true);
T val = (T) ReflectionUtils.getField(field, o);
field.setAccessible(previouslyAccessibleValue);
return val;
}
assertNotNull("the taskletStep wasn't configured with a step. " +
"We're trusting that the factory ensured " +
"a reference was given.", taskletStep);
}
}
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
}
@Test
public void testCustomHandlerRefStep() throws Exception {
assertNotNull(job5);
JobExecution jobExecution = jobRepository.createJobExecution(job5.getName(), new JobParameters());
job5.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(1, stepNames.size());
assertEquals("[j5s1]", stepNames.toString());
}
@Test
public void testDefaultHandlerStep() throws Exception {
assertNotNull(job1);
JobExecution jobExecution = jobRepository.createJobExecution(job1.getName(), new JobParameters());
job1.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(3, stepNames.size());
assertEquals("[s1, step1:partition0, step1:partition1]", stepNames.toString());
}
/**
* BATCH-1509 we now support the ability define steps inline for partitioned
* steps. this demonstates that the execution proceeds as expected and that
* the partitionhandler has a reference to the inline step definition
*/
@Test
public void testNestedPartitionStep() throws Throwable {
assertNotNull("the reference to the job4 configured in the XML file must not be null", job4);
JobExecution jobExecution = jobRepository.createJobExecution(job4.getName(), new JobParameters());
@Test
public void testHandlerRefStep() throws Exception {
assertNotNull(job2);
JobExecution jobExecution = jobRepository.createJobExecution(job2.getName(), new JobParameters());
job2.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(5, stepNames.size());
assertEquals("[s2, s3, step1:partition0, step1:partition1, step1:partition2]", stepNames.toString());
}
job4.execute(jobExecution);
private List<String> getStepNames(JobExecution jobExecution) {
List<String> list = new ArrayList<String>();
for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
list.add(stepExecution.getStepName());
}
Collections.sort(list);
return list;
}
for (StepExecution se : jobExecution.getStepExecutions()) {
String stepExecutionName = se.getStepName();
if (stepExecutionName.equalsIgnoreCase("j4s1")) { // the partitioned
// step
PartitionStep partitionStep = (PartitionStep) this.applicationContext.getBean(stepExecutionName);
// prove that the reference in the {@link
// TaskExecutorPartitionHandler} is the step configured inline
TaskExecutorPartitionHandler taskExecutorPartitionHandler = accessPrivateField(partitionStep,
"partitionHandler");
TaskletStep taskletStep = accessPrivateField(taskExecutorPartitionHandler, "step");
assertNotNull("the taskletStep wasn't configured with a step. "
+ "We're trusting that the factory ensured " + "a reference was given.", taskletStep);
}
}
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
// Step names not saved by this one (it geosn't have that tasklet)
assertEquals("[]", savedStepNames.toString());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(4, stepNames.size());
assertEquals("[j4s1, j4s1:partition0, j4s1:partition1, j4s1:partition2]", stepNames.toString());
}
/**
* BATCH-1509 we now support the ability define steps inline for partitioned
* steps. this demonstates that the execution proceeds as expected and that
* the partitionhandler has a reference to the inline step definition
*/
@Test
public void testNestedPartitionStepStepReference() throws Throwable {
assertNotNull("the reference to the job3 configured in the XML file must not be null", job3);
JobExecution jobExecution = jobRepository.createJobExecution(job3.getName(), new JobParameters());
job3.execute(jobExecution);
for (StepExecution se : jobExecution.getStepExecutions()) {
String stepExecutionName = se.getStepName();
if (stepExecutionName.equalsIgnoreCase("j3s1")) { // the partitioned
// step
PartitionStep partitionStep = (PartitionStep) this.applicationContext.getBean(stepExecutionName);
// prove that the reference in the {@link
// TaskExecutorPartitionHandler} is the step configured inline
TaskExecutorPartitionHandler taskExecutorPartitionHandler = accessPrivateField(partitionStep,
"partitionHandler");
TaskletStep taskletStep = accessPrivateField(taskExecutorPartitionHandler, "step");
assertNotNull("the taskletStep wasn't configured with a step. "
+ "We're trusting that the factory ensured " + "a reference was given.", taskletStep);
}
}
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
Collections.sort(savedStepNames);
assertEquals("[j3s1:partition0, j3s1:partition1, j3s1:partition2]", savedStepNames.toString());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(4, stepNames.size());
assertEquals("[j3s1, j3s1:partition0, j3s1:partition1, j3s1:partition2]", stepNames.toString());
}
@Test
public void testDefaultHandlerStep() throws Exception {
assertNotNull(job1);
JobExecution jobExecution = jobRepository.createJobExecution(job1.getName(), new JobParameters());
job1.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
Collections.sort(savedStepNames);
assertEquals("[step1:partition0, step1:partition1]", savedStepNames.toString());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(3, stepNames.size());
assertEquals("[s1, step1:partition0, step1:partition1]", stepNames.toString());
}
@Test
public void testHandlerRefStep() throws Exception {
assertNotNull(job2);
JobExecution jobExecution = jobRepository.createJobExecution(job2.getName(), new JobParameters());
job2.execute(jobExecution);
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
Collections.sort(savedStepNames);
assertEquals("[s3, step1:partition0, step1:partition1, step1:partition2]", savedStepNames.toString());
List<String> stepNames = getStepNames(jobExecution);
assertEquals(5, stepNames.size());
assertEquals("[s2, s3, step1:partition0, step1:partition1, step1:partition2]", stepNames.toString());
}
private List<String> getStepNames(JobExecution jobExecution) {
List<String> list = new ArrayList<String>();
for (StepExecution stepExecution : jobExecution.getStepExecutions()) {
list.add(stepExecution.getStepName());
}
Collections.sort(list);
return list;
}
public static class CustomPartitionHandler implements PartitionHandler {
public Collection<StepExecution> handle(StepExecutionSplitter stepSplitter, StepExecution stepExecution)
throws Exception {
return Arrays.asList(stepExecution);
}
}
}

View File

@@ -10,7 +10,6 @@ import java.util.Set;
import java.util.TreeSet;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.JobExecution;
@@ -60,12 +59,11 @@ public class TaskExecutorPartitionHandlerTests {
handler.afterPropertiesSet();
}
@Ignore //TODO update or simply remove?
@Test
public void testAfterPropertiesSet() throws Exception {
public void testNullStep() throws Exception {
handler = new TaskExecutorPartitionHandler();
try {
handler.afterPropertiesSet();
handler.handle(stepExecutionSplitter, stepExecution);
fail("Expected IllegalArgumentException");
}
catch (IllegalArgumentException e) {

View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<beans:beans xmlns="http://www.springframework.org/schema/batch"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
<beans:beans xmlns="http://www.springframework.org/schema/batch" xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/batch http://www.springframework.org/schema/batch/spring-batch-2.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
@@ -16,39 +16,48 @@
<job id="job2">
<step id="s2" next="s3">
<partition step="step1" handler="handler" partitioner="partitioner"/>
<partition step="step1" handler="handler" partitioner="partitioner" />
</step>
<step id="s3" parent="step2"/>
<step id="s3" parent="step2" />
</job>
<job id="job3">
<step id="j3s1" >
<partition handler="handler1" partitioner="partitioner">
<step parent="step2"/>
<job id="job3">
<step id="j3s1">
<partition handler="handler" partitioner="partitioner">
<step parent="step2" />
</partition>
</step>
</job>
<job id="job4">
<step id="j4s1">
<partition handler="handler" partitioner="partitioner">
<step>
<tasklet>
<chunk reader="reader" writer="writer" commit-interval="10" />
</tasklet>
</step>
</partition>
</step>
</job>
<bean id="handler"
class="org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler"
xmlns="http://www.springframework.org/schema/beans">
<property name="step" ref="step1"/>
<property name="gridSize" value="3"/>
<job id="job5">
<step id="j5s1">
<partition handler="handler5" partitioner="partitioner" />
</step>
</job>
<!-- for the inline case, demonstrates that we correctly ensure a reference to a step for both the default handler setup
or a custom PartitionHandler -->
<bean id="handler" class="org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler" xmlns="http://www.springframework.org/schema/beans">
<property name="gridSize" value="3" />
</bean>
<beans:bean id="taskExecutor"
class="org.springframework.core.task.SyncTaskExecutor" />
<beans:bean id="handler5"
class="org.springframework.batch.core.configuration.xml.PartitionStepParserTests$CustomPartitionHandler" />
<beans:bean id="partitioner"
class="org.springframework.batch.core.partition.support.SimplePartitioner" />
<beans:bean id="taskExecutor" class="org.springframework.core.task.SyncTaskExecutor" />
<!--
for the inline case, demonstrates that we correctly ensure a reference to a step for both the default handler setup or a custom PartitionHandler
-->
<beans:bean id="handler1" class="org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler">
<!-- nb: we're not configuring a step! -->
<beans:property name="gridSize" value="10" />
</beans:bean>
<beans:bean id="partitioner" class="org.springframework.batch.core.partition.support.SimplePartitioner" />
</beans:beans>