BATCH-1396: added step scope to completion policy in chunk parser

This commit is contained in:
Dave Syer
2011-03-19 16:14:50 +00:00
parent 323cdf6f15
commit 23587e0855
6 changed files with 49 additions and 17 deletions

View File

@@ -11,7 +11,7 @@
<step id="playerload" next="gameLoad">
<tasklet>
<chunk reader="playerFileItemReader" writer="playerWriter"
commit-interval="${job.commit.interval}" />
commit-interval="#{jobParameters['commit.interval']}" />
</tasklet>
</step>
<step id="gameLoad" next="playerSummarization">

View File

@@ -37,10 +37,9 @@ import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.jdbc.SimpleJdbcTestUtils;
/**
* @author Dave Syer
*
*
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = { "/simple-job-launcher-context.xml", "/META-INF/batch/footballJob.xml" })
@@ -48,31 +47,32 @@ public class FootballJobIntegrationTests {
/** Logger */
private final Log logger = LogFactory.getLog(getClass());
private SimpleJdbcTemplate simpleJdbcTemplate;
@Autowired
private JobLauncher jobLauncher;
@Autowired
private Job job;
@Autowired
public void setDataSource(DataSource dataSource) {
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
}
@Before
public void clear() {
SimpleJdbcTestUtils.deleteFromTables(simpleJdbcTemplate, "PLAYER_SUMMARY", "GAMES", "PLAYERS");
}
@Test
public void testLaunchJob() throws Exception {
JobExecution execution = jobLauncher.run(job, new JobParametersBuilder().toJobParameters());
JobExecution execution = jobLauncher.run(job, new JobParametersBuilder().addLong("commit.interval", 10L)
.toJobParameters());
assertEquals(BatchStatus.COMPLETED, execution.getStatus());
for (StepExecution stepExecution : execution.getStepExecutions()) {
logger.info("Processed: "+stepExecution);
logger.info("Processed: " + stepExecution);
}
}

View File

@@ -18,6 +18,7 @@ package org.springframework.batch.core.configuration.xml;
import java.util.List;
import org.springframework.batch.core.listener.StepListenerMetaData;
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
@@ -25,6 +26,7 @@ import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
@@ -59,7 +61,8 @@ public class ChunkElementParser {
private static final String ITEM_WRITER_ADAPTER_CLASS = "org.springframework.batch.item.adapter.ItemWriterAdapter";
private static final StepListenerParser stepListenerParser = new StepListenerParser(StepListenerMetaData.itemListenerMetaData());
private static final StepListenerParser stepListenerParser = new StepListenerParser(
StepListenerMetaData.itemListenerMetaData());
/**
* @param element
@@ -80,7 +83,17 @@ public class ChunkElementParser {
String commitInterval = element.getAttribute(COMMIT_INTERVAL_ATTR);
if (StringUtils.hasText(commitInterval)) {
propertyValues.addPropertyValue("commitInterval", commitInterval);
if (commitInterval.startsWith("#")) {
// It's a late binding expression, so we need step scope...
BeanDefinitionBuilder completionPolicy = BeanDefinitionBuilder
.genericBeanDefinition(SimpleCompletionPolicy.class);
completionPolicy.addConstructorArgValue(commitInterval);
completionPolicy.setScope("step");
propertyValues.addPropertyValue("chunkCompletionPolicy", completionPolicy.getBeanDefinition());
}
else {
propertyValues.addPropertyValue("commitInterval", commitInterval);
}
}
String completionPolicyRef = element.getAttribute(CHUNK_COMPLETION_POLICY_ATTR);
@@ -144,7 +157,7 @@ public class ChunkElementParser {
handleRetryListenersElement(element, propertyValues, parserContext, bd);
handleStreamsElement(element, propertyValues, parserContext);
stepListenerParser.handleListenersElement(element, bd, parserContext);
}
@@ -202,8 +215,8 @@ public class ChunkElementParser {
propertyValues.addPropertyValue(propertyName, beanDefinitionHolder);
}
else if (refElements.size() == 1) {
propertyValues.addPropertyValue(propertyName, parserContext.getDelegate().parsePropertySubElement(
refElements.get(0), null));
propertyValues.addPropertyValue(propertyName,
parserContext.getDelegate().parsePropertySubElement(refElements.get(0), null));
}
handleAdapterMethodAttribute(propertyName, adapterClassName, propertyValues, element);
@@ -251,7 +264,8 @@ public class ChunkElementParser {
}
@SuppressWarnings("unchecked")
private void handleRetryListenerElements(ParserContext parserContext, Element element, ManagedList beans, BeanDefinition enclosing) {
private void handleRetryListenerElements(ParserContext parserContext, Element element, ManagedList beans,
BeanDefinition enclosing) {
List<Element> listenerElements = DomUtils.getChildElementsByTagName(element, "listener");
if (listenerElements != null) {
for (Element listenerElement : listenerElements) {

View File

@@ -27,12 +27,21 @@ import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
import org.springframework.util.Assert;
/**
* <p>
* A {@link CompletionPolicy} that picks up a commit interval from
* {@link JobParameters} by listening to the start of a step. Use anywhere that
* a {@link CompletionPolicy} can be used (usually at the chunk level in a
* step), and inject as a {@link StepExecutionListener} into the surrounding
* step. N.B. only after the step has started will the completion policy be
* usable.
* </p>
*
* <p>
* It is easier and probably preferable to simply declare the chunk with a
* commit-interval that is a late-binding expression (e.g.
* <code>#{jobParameters['commit.interval']}</code>). That feature is available
* from of Spring Batch 2.1.7.
* </p>
*
* @author Dave Syer
*

View File

@@ -823,7 +823,8 @@ ref" is not required, and only needs to be specified explicitly
<xsd:annotation>
<xsd:documentation><![CDATA[
The number of items that will be processed before commit is called for the transaction.
Either set this or the chunk-completion-policy but not both.
Either set this or the chunk-completion-policy but not both. Can be specified as an expression
that will be evaluated in the scope of the step (e.g. "#{jobParameters['commit.interval']}").
]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>

View File

@@ -65,6 +65,14 @@ public class ChunkElementParserTests {
assertTrue("Wrong processor type", chunkProcessor instanceof SimpleChunkProcessor);
}
@Test
public void testCommitIntervalLateBinding() throws Exception {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/ChunkElementCommitIntervalParserTests-context.xml");
Step step = (Step) context.getBean("s1", Step.class);
assertNotNull("Step not parsed", step);
}
@Test
public void testRetryPolicyAttribute() throws Exception {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(