BATCH-1132:
*Updated parsers to handle 'parent' attribute of <step/>. *Attribute "parent" can be used on standalone and inline step declaration as well as with the 'tasklet' attribute. *To be consistent with treatment of listeners and tasklets, 'parent' can't be combined with 'ref' on <step/>.
This commit is contained in:
@@ -18,11 +18,13 @@ package org.springframework.batch.core.configuration.xml;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
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;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
@@ -55,7 +57,8 @@ public abstract class AbstractStepParser {
|
||||
*/
|
||||
protected AbstractBeanDefinition parseTaskletRef(Element stepElement, String taskletRef, ParserContext parserContext, String jobRepositoryRef) {
|
||||
|
||||
RootBeanDefinition bd = new RootBeanDefinition("org.springframework.batch.core.step.tasklet.TaskletStep", null, null);
|
||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
bd.setBeanClass(TaskletStep.class);
|
||||
|
||||
if (StringUtils.hasText(taskletRef)) {
|
||||
RuntimeBeanReference taskletBeanRef = new RuntimeBeanReference(taskletRef);
|
||||
@@ -117,6 +120,10 @@ public abstract class AbstractStepParser {
|
||||
String allowStartIfComplete = stepElement.getAttribute("allow-start-if-complete");
|
||||
if (StringUtils.hasText(allowStartIfComplete)) {
|
||||
bd.getPropertyValues().addPropertyValue("allowStartIfComplete", allowStartIfComplete);
|
||||
}
|
||||
String parentRef = stepElement.getAttribute("parent");
|
||||
if (StringUtils.hasText(parentRef)) {
|
||||
bd.setParentName(parentRef);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -74,6 +74,9 @@ public class InlineStepParser extends AbstractStepParser {
|
||||
if (listOfListenersElements.size() > 0) {
|
||||
parserContext.getReaderContext().error("The 'listeners' element can't be combined with the 'ref=\""+ stepRef +"\"' attribute specification for <" + element.getNodeName() + ">", element);
|
||||
}
|
||||
if (StringUtils.hasText(element.getAttribute("parent"))) {
|
||||
parserContext.getReaderContext().error("The 'parent' element can't be combined with the 'ref=\""+ stepRef +"\"' attribute specification for <" + element.getNodeName() + ">", element);
|
||||
}
|
||||
BeanDefinitionBuilder stepBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.batch.core.configuration.xml.DelegatingStep");
|
||||
stepBuilder.addConstructorArgValue(stepId);
|
||||
|
||||
@@ -54,6 +54,7 @@ public class StandaloneStepParser extends AbstractStepParser {
|
||||
Element taskElement = processTaskElements.get(0);
|
||||
bd = parseTaskletElement(element, taskElement, parserContext, jobRepositoryRef);
|
||||
}
|
||||
bd.setAbstract(Boolean.valueOf(element.getAttribute("abstract")));
|
||||
|
||||
return bd;
|
||||
|
||||
|
||||
@@ -18,12 +18,15 @@ package org.springframework.batch.core.configuration.xml;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean;
|
||||
import org.springframework.batch.core.step.item.SimpleStepFactoryBean;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanReference;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.AbstractBeanDefinition;
|
||||
import org.springframework.beans.factory.support.GenericBeanDefinition;
|
||||
import org.springframework.beans.factory.support.ManagedList;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
@@ -46,8 +49,6 @@ public class TaskletElementParser {
|
||||
*/
|
||||
protected AbstractBeanDefinition parseTaskletElement(Element element, ParserContext parserContext) {
|
||||
|
||||
RootBeanDefinition bd;
|
||||
|
||||
boolean isFaultTolerant = false;
|
||||
|
||||
String skipLimit = element.getAttribute("skip-limit");
|
||||
@@ -72,11 +73,12 @@ public class TaskletElementParser {
|
||||
checkExceptionElementForFaultToleranceNeeded(element, "retryable-exception-classes");
|
||||
checkExceptionElementForFaultToleranceNeeded(element, "fatal-exception-classes");
|
||||
|
||||
GenericBeanDefinition bd = new GenericBeanDefinition();
|
||||
if (isFaultTolerant) {
|
||||
bd = new RootBeanDefinition("org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean", null, null);
|
||||
bd.setBeanClass(FaultTolerantStepFactoryBean.class);
|
||||
}
|
||||
else {
|
||||
bd = new RootBeanDefinition("org.springframework.batch.core.step.item.SimpleStepFactoryBean", null, null);
|
||||
bd.setBeanClass(SimpleStepFactoryBean.class);
|
||||
}
|
||||
|
||||
MutablePropertyValues propertyValues = bd.getPropertyValues();
|
||||
|
||||
@@ -753,6 +753,9 @@
|
||||
<xsd:documentation>
|
||||
The name of the parent step from which the configuration should inherit.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref"/>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
@@ -13,13 +13,17 @@
|
||||
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd">
|
||||
|
||||
<job id="skipJob" incrementer="incrementer">
|
||||
<step id="step1" ref="firstPass">
|
||||
<step id="step1" parent="baseStep">
|
||||
<tasklet reader="fileItemReader" processor="tradeProcessor" writer="tradeWriter"
|
||||
commit-interval="3" skip-limit="10">
|
||||
</tasklet>
|
||||
|
||||
<fail on="FAILED" exit-code="FAILED"/>
|
||||
<next on="COMPLETED WITH SKIPS" to="errorPrint1" />
|
||||
<next on="*" to="step2" />
|
||||
</step>
|
||||
|
||||
<step id="errorPrint1" next="step2" tasklet="errorLogTasklet"/>
|
||||
<step id="errorPrint1" tasklet="errorLogTasklet" next="step2"/>
|
||||
|
||||
<step id="step2" ref="secondPass" next="skipCheckingDecision"/>
|
||||
|
||||
@@ -31,18 +35,7 @@
|
||||
<step id="errorPrint2" tasklet="errorLogTasklet"/>
|
||||
</job>
|
||||
|
||||
<step id="firstPass" >
|
||||
<tasklet reader="fileItemReader" processor="tradeProcessor" writer="tradeWriter"
|
||||
commit-interval="3" skip-limit="10">
|
||||
</tasklet>
|
||||
|
||||
<listeners>
|
||||
<listener ref="skipCheckingListener"/>
|
||||
<listener ref="promotionListener"/>
|
||||
</listeners>
|
||||
</step>
|
||||
|
||||
<step id="secondPass">
|
||||
<step id="secondPass" parent="baseStep">
|
||||
<tasklet reader="tradeSqlItemReader" processor="tradeProcessor" writer="itemTrackingWriter"
|
||||
commit-interval="2" skip-limit="10">
|
||||
<skippable-exception-classes>
|
||||
@@ -50,22 +43,27 @@
|
||||
java.lang.RuntimeException
|
||||
</skippable-exception-classes>
|
||||
</tasklet>
|
||||
<listeners>
|
||||
<listener ref="skipCheckingListener"/>
|
||||
<listener ref="promotionListener"/>
|
||||
</listeners>
|
||||
</step>
|
||||
</step>
|
||||
|
||||
<beans:bean id="baseStep" abstract="true">
|
||||
<beans:property name="listeners">
|
||||
<beans:list>
|
||||
<beans:bean class="org.springframework.batch.core.listener.StepListenerFactoryBean">
|
||||
<beans:property name="delegate" ref="skipCheckingListener"/>
|
||||
</beans:bean>
|
||||
<beans:bean class="org.springframework.batch.core.listener.StepListenerFactoryBean">
|
||||
<beans:property name="delegate" ref="promotionListener"/>
|
||||
</beans:bean>
|
||||
</beans:list>
|
||||
</beans:property>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="tradeProcessor" class="org.springframework.batch.sample.domain.trade.internal.TradeProcessor"/>
|
||||
|
||||
<beans:bean id="skipCheckingListener" class="org.springframework.batch.sample.common.SkipCheckingListener"/>
|
||||
|
||||
<beans:bean id="promotionListener" class="org.springframework.batch.core.listener.ExecutionContextPromotionListener">
|
||||
<beans:property name="keys">
|
||||
<beans:list>
|
||||
<beans:value>stepName</beans:value>
|
||||
</beans:list>
|
||||
</beans:property>
|
||||
<beans:property name="keys" value="stepName"/>
|
||||
</beans:bean>
|
||||
|
||||
<beans:bean id="fileItemReader" class="org.springframework.batch.item.file.FlatFileItemReader" scope="step">
|
||||
|
||||
@@ -201,11 +201,6 @@ public class SkipSampleFunctionalTests {
|
||||
}
|
||||
|
||||
private Map<String, Object> getStepExecution(long jobExecutionId, String stepName) {
|
||||
for (Map<String, Object> rs : simpleJdbcTemplate.queryForList(
|
||||
"SELECT * from BATCH_STEP_EXECUTION where JOB_EXECUTION_ID = ? and STEP_NAME = ?", jobExecutionId,
|
||||
stepName)) {
|
||||
System.err.println(rs);
|
||||
}
|
||||
return simpleJdbcTemplate.queryForMap(
|
||||
"SELECT * from BATCH_STEP_EXECUTION where JOB_EXECUTION_ID = ? and STEP_NAME = ?", jobExecutionId,
|
||||
stepName);
|
||||
|
||||
@@ -12,17 +12,25 @@ import org.springframework.batch.core.scope.context.ChunkContext;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.repeat.RepeatStatus;
|
||||
import org.springframework.jdbc.core.simple.SimpleJdbcTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* @author Dan Garrette
|
||||
* @since 2.0
|
||||
*/
|
||||
public class ErrorLogTasklet implements Tasklet, StepExecutionListener {
|
||||
|
||||
protected final Log logger = LogFactory.getLog(getClass());
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
|
||||
private String jobName;
|
||||
private String stepName;
|
||||
|
||||
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
|
||||
this.simpleJdbcTemplate.update("insert into ERROR_LOG values (?, ?, 'Some records were skipped!')", jobName, stepName);
|
||||
Assert.notNull(this.stepName, "Step name not set. Either this class was not registered as a listener "
|
||||
+ "or the key 'stepName' was not found in the Job's ExecutionContext.");
|
||||
this.simpleJdbcTemplate.update("insert into ERROR_LOG values (?, ?, 'Some records were skipped!')", jobName,
|
||||
stepName);
|
||||
return RepeatStatus.FINISHED;
|
||||
}
|
||||
|
||||
@@ -30,12 +38,14 @@ public class ErrorLogTasklet implements Tasklet, StepExecutionListener {
|
||||
this.simpleJdbcTemplate = new SimpleJdbcTemplate(dataSource);
|
||||
}
|
||||
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
this.jobName = stepExecution.getJobExecution().getJobInstance().getJobName().trim();
|
||||
this.stepName = (String) stepExecution.getJobExecution().getExecutionContext().get("stepName");
|
||||
stepExecution.getJobExecution().getExecutionContext().remove("stepName");
|
||||
}
|
||||
|
||||
public ExitStatus afterStep(StepExecution stepExecution) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public void beforeStep(StepExecution stepExecution) {
|
||||
this.jobName = stepExecution.getJobExecution().getJobInstance().getJobName().trim();
|
||||
this.stepName = (String)stepExecution.getJobExecution().getExecutionContext().get("stepName");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user