BATCH-1213: Defaults in xsd override parent attributes
*Introduced CoreNamespacePostProcessor to handle injection of JobRepository and TransactionManager onto jobs and steps defined using the namespace. *Introduced JobParserJobFactoryBean used to instantiate a FlowJob via the namespace. *Modified defaulting behavior of jobRepository attribute. Job's jobRepository now always overrides the Step's.
This commit is contained in:
@@ -70,11 +70,10 @@ public abstract class AbstractStepParser {
|
||||
/**
|
||||
* @param stepElement The <step/> element
|
||||
* @param parserContext
|
||||
* @param jobRepositoryRef The name of the bean defining the JobRepository.
|
||||
* Use 'null' if the job-repository is specified on the
|
||||
* <tasklet/> element; this method will look it up.
|
||||
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
|
||||
* from the enclosing tag. Use 'null' if unknown.
|
||||
*/
|
||||
protected AbstractBeanDefinition parseStep(Element stepElement, ParserContext parserContext, String jobRepositoryRef) {
|
||||
protected AbstractBeanDefinition parseStep(Element stepElement, ParserContext parserContext, String jobFactoryRef) {
|
||||
|
||||
AbstractBeanDefinition bd = new GenericBeanDefinition();
|
||||
|
||||
@@ -82,7 +81,7 @@ public abstract class AbstractStepParser {
|
||||
List<Element> taskletElements = (List<Element>) DomUtils.getChildElementsByTagName(stepElement, TASKLET_ELE);
|
||||
if (taskletElements.size() == 1) {
|
||||
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
|
||||
parseTasklet(taskletElements.get(0), bd, parserContext, jobRepositoryRef, stepUnderspecified);
|
||||
parseTasklet(taskletElements.get(0), bd, parserContext, stepUnderspecified);
|
||||
}
|
||||
else if (taskletElements.size() > 1) {
|
||||
parserContext.getReaderContext().error(
|
||||
@@ -100,12 +99,16 @@ public abstract class AbstractStepParser {
|
||||
bd.setAbstract(Boolean.valueOf(isAbstract));
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(jobFactoryRef)) {
|
||||
bd.getPropertyValues().addPropertyValue("jobParserJobFactoryBeanRef", jobFactoryRef);
|
||||
}
|
||||
|
||||
return bd;
|
||||
|
||||
}
|
||||
|
||||
private void parseTasklet(Element taskletElement, AbstractBeanDefinition bd, ParserContext parserContext,
|
||||
String jobRepositoryRef, boolean stepUnderspecified) {
|
||||
boolean stepUnderspecified) {
|
||||
|
||||
bd.setBeanClass(StepParserStepFactoryBean.class);
|
||||
|
||||
@@ -130,8 +133,7 @@ public abstract class AbstractStepParser {
|
||||
+ "/> element nor a '" + TASKLET_REF_ATTR + "' attribute.", taskletElement);
|
||||
}
|
||||
|
||||
setUpBeanDefinitionForTaskletStep(taskletElement, bd, parserContext, jobRepositoryRef);
|
||||
|
||||
setUpBeanDefinitionForTaskletStep(taskletElement, bd, parserContext);
|
||||
}
|
||||
|
||||
private void parseTaskletRef(String taskletRef, MutablePropertyValues propertyValues) {
|
||||
@@ -142,18 +144,23 @@ public abstract class AbstractStepParser {
|
||||
}
|
||||
|
||||
private void setUpBeanDefinitionForTaskletStep(Element taskletElement, AbstractBeanDefinition bd,
|
||||
ParserContext parserContext, String jobRepositoryRef) {
|
||||
ParserContext parserContext) {
|
||||
|
||||
MutablePropertyValues propertyValues = bd.getPropertyValues();
|
||||
|
||||
checkStepAttributes(taskletElement, propertyValues);
|
||||
|
||||
propertyValues.addPropertyValue("jobRepository", resolveJobRepositoryRef(taskletElement, parserContext,
|
||||
jobRepositoryRef));
|
||||
String jobRepositoryRef = taskletElement.getAttribute(JOB_REPO_ATTR);
|
||||
if (StringUtils.hasText(jobRepositoryRef)) {
|
||||
RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(jobRepositoryRef);
|
||||
propertyValues.addPropertyValue("jobRepository", jobRepositoryBeanRef);
|
||||
}
|
||||
|
||||
String transactionManagerRef = taskletElement.getAttribute("transaction-manager");
|
||||
RuntimeBeanReference transactionManagerBeanRef = new RuntimeBeanReference(transactionManagerRef);
|
||||
propertyValues.addPropertyValue("transactionManager", transactionManagerBeanRef);
|
||||
if (StringUtils.hasText(transactionManagerRef)) {
|
||||
RuntimeBeanReference transactionManagerBeanRef = new RuntimeBeanReference(transactionManagerRef);
|
||||
propertyValues.addPropertyValue("transactionManager", transactionManagerBeanRef);
|
||||
}
|
||||
|
||||
handleTransactionAttributesElement(taskletElement, propertyValues, parserContext);
|
||||
|
||||
@@ -168,20 +175,6 @@ public abstract class AbstractStepParser {
|
||||
|
||||
}
|
||||
|
||||
private RuntimeBeanReference resolveJobRepositoryRef(Element taskletElement, ParserContext parserContext,
|
||||
String jobRepositoryRef) {
|
||||
if (!StringUtils.hasText(jobRepositoryRef)) {
|
||||
jobRepositoryRef = taskletElement.getAttribute(JOB_REPO_ATTR);
|
||||
if (!StringUtils.hasText(jobRepositoryRef)) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The '" + JOB_REPO_ATTR + "' attribute may exist on an <" + taskletElement.getNodeName()
|
||||
+ "/> element.", taskletElement);
|
||||
}
|
||||
}
|
||||
RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(jobRepositoryRef);
|
||||
return jobRepositoryBeanRef;
|
||||
}
|
||||
|
||||
private void handleTransactionAttributesElement(Element stepElement, MutablePropertyValues propertyValues,
|
||||
ParserContext parserContext) {
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
/*
|
||||
* Copyright 2006-2009 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.configuration.xml;
|
||||
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.PropertyValue;
|
||||
import org.springframework.beans.PropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Post-process jobs and steps defined using the batch namespace to inject
|
||||
* dependencies.
|
||||
*
|
||||
* @author Dan Garrette
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public class CoreNamespacePostProcessor implements BeanPostProcessor, BeanFactoryPostProcessor, ApplicationContextAware {
|
||||
|
||||
private static final String DEFAULT_JOB_REPOSITORY_NAME = "jobRepository";
|
||||
|
||||
private static final String DEFAULT_TRANSACTION_MANAGER_NAME = "transactionManager";
|
||||
|
||||
private static final String JOB_FACTORY_PROPERTY_NAME = "jobParserJobFactoryBeanRef";
|
||||
|
||||
private static final String JOB_REPOSITORY_PROPERTY_NAME = "jobRepository";
|
||||
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
/**
|
||||
* Inject job-repository from a job into its steps.
|
||||
*
|
||||
* @see org.springframework.beans.factory.config.BeanFactoryPostProcessor#postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory)
|
||||
*/
|
||||
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
|
||||
for (String beanName : beanFactory.getBeanDefinitionNames()) {
|
||||
BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
|
||||
MutablePropertyValues pvs = (MutablePropertyValues) bd.getPropertyValues();
|
||||
if (pvs.contains(JOB_FACTORY_PROPERTY_NAME)) {
|
||||
String jobName = (String) pvs.getPropertyValue(JOB_FACTORY_PROPERTY_NAME).getValue();
|
||||
PropertyValue jobRepository = getJobRepository(beanFactory, jobName);
|
||||
if (jobRepository != null) {
|
||||
pvs.addPropertyValue(jobRepository);
|
||||
}
|
||||
else {
|
||||
RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(DEFAULT_JOB_REPOSITORY_NAME);
|
||||
pvs.addPropertyValue(JOB_REPOSITORY_PROPERTY_NAME, jobRepositoryBeanRef);
|
||||
}
|
||||
pvs.removePropertyValue(JOB_FACTORY_PROPERTY_NAME);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private PropertyValue getJobRepository(ConfigurableListableBeanFactory beanFactory, String jobName) {
|
||||
BeanDefinition jobDef = beanFactory.getBeanDefinition(jobName);
|
||||
PropertyValues jobDefPvs = jobDef.getPropertyValues();
|
||||
if (jobDefPvs.contains(JOB_REPOSITORY_PROPERTY_NAME)) {
|
||||
return jobDefPvs.getPropertyValue(JOB_REPOSITORY_PROPERTY_NAME);
|
||||
}
|
||||
else {
|
||||
String parentName = jobDef.getParentName();
|
||||
if (StringUtils.hasText(parentName)) {
|
||||
return getJobRepository(beanFactory, parentName);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject defaults into factory beans.
|
||||
* <ul>
|
||||
* <li>Inject "jobRepository" into any {@link JobParserJobFactoryBean}
|
||||
* without a jobRepository.
|
||||
* <li>Inject "transactionManager" into any
|
||||
* {@link StepParserStepFactoryBean} without a transactionManager.
|
||||
* </ul>
|
||||
*
|
||||
* @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object,
|
||||
* java.lang.String)
|
||||
*/
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof JobParserJobFactoryBean) {
|
||||
JobParserJobFactoryBean fb = (JobParserJobFactoryBean) bean;
|
||||
JobRepository jobRepository = fb.getJobRepository();
|
||||
if (jobRepository == null) {
|
||||
fb.setJobRepository((JobRepository) applicationContext.getBean(DEFAULT_JOB_REPOSITORY_NAME));
|
||||
}
|
||||
}
|
||||
else if (bean instanceof StepParserStepFactoryBean) {
|
||||
StepParserStepFactoryBean<?, ?> fb = (StepParserStepFactoryBean<?, ?>) bean;
|
||||
JobRepository jobRepository = fb.getJobRepository();
|
||||
if (jobRepository == null) {
|
||||
fb.setJobRepository((JobRepository) applicationContext.getBean(DEFAULT_JOB_REPOSITORY_NAME));
|
||||
}
|
||||
PlatformTransactionManager transactionManager = fb.getTransactionManager();
|
||||
if (transactionManager == null) {
|
||||
fb.setTransactionManager((PlatformTransactionManager) applicationContext
|
||||
.getBean(DEFAULT_TRANSACTION_MANAGER_NAME));
|
||||
}
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) {
|
||||
this.applicationContext = applicationContext;
|
||||
}
|
||||
}
|
||||
@@ -29,7 +29,7 @@ import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* utility methods used in parsing of the batch core namespace
|
||||
* Utility methods used in parsing of the batch core namespace
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*/
|
||||
@@ -45,8 +45,15 @@ public class CoreNamespaceUtils {
|
||||
|
||||
private static final String RANGE_ARRAY_EDITOR_CLASS_NAME = "org.springframework.batch.item.file.transform.RangeArrayPropertyEditor";
|
||||
|
||||
protected static void checkForStepScope(ParserContext parserContext, Object source) {
|
||||
private static final String CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME = "org.springframework.batch.core.configuration.xml.CoreNamespacePostProcessor";
|
||||
|
||||
protected static void autoregisterBeansForNamespace(ParserContext parserContext, Object source) {
|
||||
checkForStepScope(parserContext, source);
|
||||
addRangePropertyEditor(parserContext);
|
||||
addCoreNamespacePostProcessor(parserContext);
|
||||
}
|
||||
|
||||
private static void checkForStepScope(ParserContext parserContext, Object source) {
|
||||
boolean foundStepScope = false;
|
||||
String[] beanNames = parserContext.getRegistry().getBeanDefinitionNames();
|
||||
for (String beanName : beanNames) {
|
||||
@@ -72,10 +79,9 @@ public class CoreNamespaceUtils {
|
||||
* @param parserContext
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected static void addRangePropertyEditor(ParserContext parserContext) {
|
||||
private static void addRangePropertyEditor(ParserContext parserContext) {
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
if (!rangeArrayEditorAlreadyDefined(registry)) {
|
||||
|
||||
AbstractBeanDefinition customEditorConfigurer = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
CUSTOM_EDITOR_CONFIGURER_CLASS_NAME).getBeanDefinition();
|
||||
customEditorConfigurer.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
@@ -83,7 +89,6 @@ public class CoreNamespaceUtils {
|
||||
editors.put(RANGE_ARRAY_CLASS_NAME, RANGE_ARRAY_EDITOR_CLASS_NAME);
|
||||
customEditorConfigurer.getPropertyValues().addPropertyValue("customEditors", editors);
|
||||
registry.registerBeanDefinition(CUSTOM_EDITOR_CONFIGURER_CLASS_NAME, customEditorConfigurer);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +115,29 @@ public class CoreNamespaceUtils {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param parserContext
|
||||
*/
|
||||
private static void addCoreNamespacePostProcessor(ParserContext parserContext) {
|
||||
BeanDefinitionRegistry registry = parserContext.getRegistry();
|
||||
if (!coreNamespaceBeanPostProcessorAlreadyDefined(registry)) {
|
||||
AbstractBeanDefinition postProcessorBeanDef = BeanDefinitionBuilder.genericBeanDefinition(
|
||||
CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME).getBeanDefinition();
|
||||
postProcessorBeanDef.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
|
||||
registry.registerBeanDefinition(CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME, postProcessorBeanDef);
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean coreNamespaceBeanPostProcessorAlreadyDefined(BeanDefinitionRegistry registry) {
|
||||
for (String beanName : registry.getBeanDefinitionNames()) {
|
||||
BeanDefinition bd = registry.getBeanDefinition(beanName);
|
||||
if (CORE_NAMESPACE_POST_PROCESSOR_CLASS_NAME.equals(bd.getBeanClassName())) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Should this element be treated as incomplete? If it has a parent or is
|
||||
* abstract, then it may not have all properties.
|
||||
|
||||
@@ -63,24 +63,28 @@ public class FlowParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
private static final String EXIT_CODE_ATTR = "exit-code";
|
||||
|
||||
private static final InlineStepParser stepParser = new InlineStepParser();
|
||||
|
||||
private static final DecisionParser decisionParser = new DecisionParser();
|
||||
|
||||
// For generating unique state names for end transitions
|
||||
private static int endCounter = 0;
|
||||
|
||||
private final String flowName;
|
||||
|
||||
private final String jobRepositoryRef;
|
||||
private final String jobFactoryRef;
|
||||
|
||||
/**
|
||||
* Construct a {@link FlowParser} with the specified name and using the
|
||||
* provided job repository ref.
|
||||
*
|
||||
* @param flowName the name of the flow
|
||||
* @param jobRepositoryRef the reference to the jobRepository from the
|
||||
* enclosing tag
|
||||
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
|
||||
* from the enclosing tag
|
||||
*/
|
||||
public FlowParser(String flowName, String jobRepositoryRef) {
|
||||
public FlowParser(String flowName, String jobFactoryRef) {
|
||||
this.flowName = flowName;
|
||||
this.jobRepositoryRef = jobRepositoryRef;
|
||||
this.jobFactoryRef = jobFactoryRef;
|
||||
|
||||
}
|
||||
|
||||
@@ -102,9 +106,7 @@ public class FlowParser extends AbstractSingleBeanDefinitionParser {
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
List<BeanDefinition> stateTransitions = new ArrayList<BeanDefinition>();
|
||||
|
||||
InlineStepParser stepParser = new InlineStepParser();
|
||||
DecisionParser decisionParser = new DecisionParser();
|
||||
SplitParser splitParser = new SplitParser(jobRepositoryRef);
|
||||
SplitParser splitParser = new SplitParser(jobFactoryRef);
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(element.getTagName(),
|
||||
parserContext.extractSource(element));
|
||||
parserContext.pushContainingComponent(compositeDef);
|
||||
@@ -116,7 +118,7 @@ public class FlowParser extends AbstractSingleBeanDefinitionParser {
|
||||
if (node instanceof Element) {
|
||||
String nodeName = node.getLocalName();
|
||||
if (nodeName.equals(STEP_ELE)) {
|
||||
stateTransitions.addAll(stepParser.parse((Element) node, parserContext, jobRepositoryRef));
|
||||
stateTransitions.addAll(stepParser.parse((Element) node, parserContext, jobFactoryRef));
|
||||
stepExists = true;
|
||||
}
|
||||
else if (nodeName.equals(DECISION_ELE)) {
|
||||
@@ -131,7 +133,8 @@ public class FlowParser extends AbstractSingleBeanDefinitionParser {
|
||||
}
|
||||
|
||||
if (!stepExists && !CoreNamespaceUtils.isUnderspecified(element)) {
|
||||
parserContext.getReaderContext().error("A flow must contain at least one step", element);
|
||||
parserContext.getReaderContext().error("The flow [" + flowName + "] must contain at least one step",
|
||||
element);
|
||||
}
|
||||
|
||||
builder.addConstructorArgValue(flowName);
|
||||
@@ -162,7 +165,7 @@ public class FlowParser extends AbstractSingleBeanDefinitionParser {
|
||||
/**
|
||||
* @param parserContext the parser context for the bean factory
|
||||
* @param stepId the id of the current state if it is a step state, null
|
||||
* otherwise
|
||||
* otherwise
|
||||
* @param stateDef The bean definition for the current state
|
||||
* @param element the <step/gt; element to parse
|
||||
* @return a collection of
|
||||
@@ -231,8 +234,8 @@ public class FlowParser extends AbstractSingleBeanDefinitionParser {
|
||||
* @param stateDef The bean definition for the current state
|
||||
* @param parserContext the parser context for the bean factory
|
||||
* @param a collection of
|
||||
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
|
||||
* references
|
||||
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
|
||||
* references
|
||||
*/
|
||||
private static Collection<BeanDefinition> parseTransitionElement(Element transitionElement, String stateId,
|
||||
BeanDefinition stateDef, ParserContext parserContext) {
|
||||
@@ -252,18 +255,18 @@ public class FlowParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
/**
|
||||
* @param status The batch status that this transition will set. Use
|
||||
* BatchStatus.UNKNOWN if not applicable.
|
||||
* BatchStatus.UNKNOWN if not applicable.
|
||||
* @param on The pattern that this transition should match. Use null for
|
||||
* "no restriction" (same as "*").
|
||||
* "no restriction" (same as "*").
|
||||
* @param next The state to which this transition should go. Use null if not
|
||||
* applicable.
|
||||
* applicable.
|
||||
* @param exitCode The exit code that this transition will set. Use null to
|
||||
* default to batchStatus.
|
||||
* default to batchStatus.
|
||||
* @param stateDef The bean definition for the current state
|
||||
* @param parserContext the parser context for the bean factory
|
||||
* @param a collection of
|
||||
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
|
||||
* references
|
||||
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
|
||||
* references
|
||||
*/
|
||||
private static Collection<BeanDefinition> createTransition(FlowExecutionStatus status, String on, String next,
|
||||
String exitCode, BeanDefinition stateDef, ParserContext parserContext, boolean abandon) {
|
||||
|
||||
@@ -45,18 +45,18 @@ public class InlineStepParser extends AbstractStepParser {
|
||||
*
|
||||
* @param element the <step/gt; element to parse
|
||||
* @param parserContext the parser context for the bean factory
|
||||
* @param jobRepositoryRef the reference to the jobRepository from the
|
||||
* enclosing tag
|
||||
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
|
||||
* from the enclosing tag
|
||||
* @return a collection of bean definitions for
|
||||
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
|
||||
* instances objects
|
||||
*/
|
||||
public Collection<BeanDefinition> parse(Element element, ParserContext parserContext, String jobRepositoryRef) {
|
||||
public Collection<BeanDefinition> parse(Element element, ParserContext parserContext, String jobFactoryRef) {
|
||||
|
||||
BeanDefinitionBuilder stateBuilder = BeanDefinitionBuilder.genericBeanDefinition(StepState.class);
|
||||
String stepId = element.getAttribute(ID_ATTR);
|
||||
|
||||
AbstractBeanDefinition bd = parseStep(element, parserContext, jobRepositoryRef);
|
||||
AbstractBeanDefinition bd = parseStep(element, parserContext, jobFactoryRef);
|
||||
parserContext.registerBeanComponent(new BeanComponentDefinition(bd, stepId));
|
||||
stateBuilder.addConstructorArgReference(stepId);
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package org.springframework.batch.core.configuration.xml;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.core.job.flow.FlowJob;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.parsing.CompositeComponentDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
@@ -40,17 +39,14 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
|
||||
private static final JobExecutionListenerParser jobListenerParser = new JobExecutionListenerParser();
|
||||
|
||||
@Override
|
||||
protected Class<FlowJob> getBeanClass(Element element) {
|
||||
return FlowJob.class;
|
||||
protected Class<JobParserJobFactoryBean> getBeanClass(Element element) {
|
||||
return JobParserJobFactoryBean.class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a bean definition for a
|
||||
* {@link org.springframework.batch.core.job.flow.FlowJob}. The
|
||||
* <code>jobRepository</code> attribute is a reference to a
|
||||
* {@link org.springframework.batch.core.repository.JobRepository} and
|
||||
* defaults to "jobRepository". Nested step elements are delegated to an
|
||||
* {@link InlineStepParser}.
|
||||
* {@link org.springframework.batch.core.job.flow.FlowJob}. Nested step
|
||||
* elements are delegated to an {@link InlineStepParser}.
|
||||
*
|
||||
* @see AbstractSingleBeanDefinitionParser#doParse(Element, ParserContext,
|
||||
* BeanDefinitionBuilder)
|
||||
@@ -59,8 +55,7 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
CoreNamespaceUtils.checkForStepScope(parserContext, parserContext.extractSource(element));
|
||||
CoreNamespaceUtils.addRangePropertyEditor(parserContext);
|
||||
CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, parserContext.extractSource(element));
|
||||
|
||||
String jobName = element.getAttribute("id");
|
||||
builder.addConstructorArgValue(jobName);
|
||||
@@ -76,10 +71,9 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
|
||||
}
|
||||
|
||||
String repositoryAttribute = element.getAttribute("job-repository");
|
||||
if (!StringUtils.hasText(repositoryAttribute)) {
|
||||
repositoryAttribute = "jobRepository";
|
||||
if (StringUtils.hasText(repositoryAttribute)) {
|
||||
builder.addPropertyReference("jobRepository", repositoryAttribute);
|
||||
}
|
||||
builder.addPropertyReference("jobRepository", repositoryAttribute);
|
||||
|
||||
String restartableAttribute = element.getAttribute("restartable");
|
||||
if (StringUtils.hasText(restartableAttribute)) {
|
||||
@@ -91,7 +85,7 @@ public class JobParser extends AbstractSingleBeanDefinitionParser {
|
||||
builder.addPropertyReference("jobParametersIncrementer", incrementer);
|
||||
}
|
||||
|
||||
FlowParser flowParser = new FlowParser(jobName, repositoryAttribute);
|
||||
FlowParser flowParser = new FlowParser(jobName, jobName);
|
||||
BeanDefinition flowDef = flowParser.parse(element, parserContext);
|
||||
builder.addPropertyValue("flow", flowDef);
|
||||
|
||||
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2006-2009 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.configuration.xml;
|
||||
|
||||
import org.apache.commons.lang.StringUtils;
|
||||
import org.springframework.batch.core.JobExecutionListener;
|
||||
import org.springframework.batch.core.JobParametersIncrementer;
|
||||
import org.springframework.batch.core.job.flow.Flow;
|
||||
import org.springframework.batch.core.job.flow.FlowJob;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.beans.factory.FactoryBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* This {@link FactoryBean} is used by the batch namespace parser to create
|
||||
* {@link FlowJob} objects. It stores all of the properties that are
|
||||
* configurable on the <job/>.
|
||||
*
|
||||
* @author Dan Garrette
|
||||
* @since 2.0.1
|
||||
*/
|
||||
class JobParserJobFactoryBean implements FactoryBean {
|
||||
|
||||
private String name;
|
||||
|
||||
private Boolean restartable;
|
||||
|
||||
private JobRepository jobRepository;
|
||||
|
||||
private JobExecutionListener[] jobExecutionListeners;
|
||||
|
||||
private JobParametersIncrementer jobParametersIncrementer;
|
||||
|
||||
private Flow flow;
|
||||
|
||||
public JobParserJobFactoryBean(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public final Object getObject() throws Exception {
|
||||
Assert.isTrue(!StringUtils.isBlank(name), "The job must have an 'id'.");
|
||||
FlowJob flowJob = new FlowJob(name);
|
||||
|
||||
if (restartable != null) {
|
||||
flowJob.setRestartable(restartable);
|
||||
}
|
||||
|
||||
if (jobRepository != null) {
|
||||
flowJob.setJobRepository(jobRepository);
|
||||
}
|
||||
|
||||
if (jobExecutionListeners != null) {
|
||||
flowJob.setJobExecutionListeners(jobExecutionListeners);
|
||||
}
|
||||
|
||||
if (jobParametersIncrementer != null) {
|
||||
flowJob.setJobParametersIncrementer(jobParametersIncrementer);
|
||||
}
|
||||
|
||||
if (flow != null) {
|
||||
flowJob.setFlow(flow);
|
||||
}
|
||||
|
||||
flowJob.afterPropertiesSet();
|
||||
return flowJob;
|
||||
}
|
||||
|
||||
public void setRestartable(Boolean restartable) {
|
||||
this.restartable = restartable;
|
||||
}
|
||||
|
||||
public void setJobRepository(JobRepository jobRepository) {
|
||||
this.jobRepository = jobRepository;
|
||||
}
|
||||
|
||||
public JobRepository getJobRepository() {
|
||||
return this.jobRepository;
|
||||
}
|
||||
|
||||
public void setJobExecutionListeners(JobExecutionListener[] jobExecutionListeners) {
|
||||
this.jobExecutionListeners = jobExecutionListeners;
|
||||
}
|
||||
|
||||
public void setJobParametersIncrementer(JobParametersIncrementer jobParametersIncrementer) {
|
||||
this.jobParametersIncrementer = jobParametersIncrementer;
|
||||
}
|
||||
|
||||
public void setFlow(Flow flow) {
|
||||
this.flow = flow;
|
||||
}
|
||||
|
||||
public Class<FlowJob> getObjectType() {
|
||||
return FlowJob.class;
|
||||
}
|
||||
|
||||
public boolean isSingleton() {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -30,9 +30,9 @@ import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Internal parser for the <split/> elements inside a job. A split element
|
||||
* references a bean definition for a
|
||||
* {@link org.springframework.batch.core.job.flow.JobExecutionDecider} and goes on to
|
||||
* list a set of transitions to other states with <next on="pattern"
|
||||
* references a bean definition for a
|
||||
* {@link org.springframework.batch.core.job.flow.JobExecutionDecider} and goes
|
||||
* on to list a set of transitions to other states with <next on="pattern"
|
||||
* to="stepName"/>. Used by the {@link JobParser}.
|
||||
*
|
||||
* @see JobParser
|
||||
@@ -42,38 +42,39 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
public class SplitParser {
|
||||
|
||||
private final String jobRepositoryRef;
|
||||
private final String jobFactoryRef;
|
||||
|
||||
/**
|
||||
* Construct a {@link FlowParser} using the provided job repository ref.
|
||||
* @param jobRepositoryRef the reference to the jobRepository from the enclosing tag
|
||||
*
|
||||
* @param jobFactoryRef the reference to the {@link JobParserJobFactoryBean}
|
||||
* from the enclosing tag
|
||||
*/
|
||||
public SplitParser(String jobRepositoryRef) {
|
||||
this.jobRepositoryRef = jobRepositoryRef;
|
||||
public SplitParser(String jobFactoryRef) {
|
||||
this.jobFactoryRef = jobFactoryRef;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse the split and turn it into a list of transitions.
|
||||
*
|
||||
* @param element the <split/gt; element to parse
|
||||
* @param parserContext the parser context for the bean factory
|
||||
* @return a collection of bean definitions for
|
||||
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
|
||||
* instances objects
|
||||
* @return a collection of bean definitions for
|
||||
* {@link org.springframework.batch.core.job.flow.support.StateTransition}
|
||||
* instances objects
|
||||
*/
|
||||
public Collection<BeanDefinition> parse(Element element, ParserContext parserContext) {
|
||||
|
||||
String idAttribute = element.getAttribute("id");
|
||||
|
||||
BeanDefinitionBuilder stateBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition("org.springframework.batch.core.job.flow.support.state.SplitState");
|
||||
BeanDefinitionBuilder stateBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition("org.springframework.batch.core.job.flow.support.state.SplitState");
|
||||
|
||||
String taskExecutorBeanId = element.getAttribute("task-executor");
|
||||
if (StringUtils.hasText(taskExecutorBeanId)) {
|
||||
RuntimeBeanReference taskExecutorRef = new RuntimeBeanReference(taskExecutorBeanId);
|
||||
stateBuilder.addPropertyValue("taskExecutor", taskExecutorRef);
|
||||
}
|
||||
String taskExecutorBeanId = element.getAttribute("task-executor");
|
||||
if (StringUtils.hasText(taskExecutorBeanId)) {
|
||||
RuntimeBeanReference taskExecutorRef = new RuntimeBeanReference(taskExecutorBeanId);
|
||||
stateBuilder.addPropertyValue("taskExecutor", taskExecutorRef);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> flowElements = (List<Element>) DomUtils.getChildElementsByTagName(element, "flow");
|
||||
@@ -81,21 +82,21 @@ public class SplitParser {
|
||||
if (flowElements.size() < 2) {
|
||||
parserContext.getReaderContext().error("A <split/> must contain at least two 'flow' elements.", element);
|
||||
}
|
||||
|
||||
|
||||
Collection<BeanDefinition> flows = new ArrayList<BeanDefinition>();
|
||||
int i = 0;
|
||||
for (Element nextElement : flowElements) {
|
||||
FlowParser flowParser = new FlowParser(idAttribute+"#"+i, jobRepositoryRef);
|
||||
FlowParser flowParser = new FlowParser(idAttribute + "#" + i, jobFactoryRef);
|
||||
flows.add(flowParser.parse(nextElement, parserContext));
|
||||
i++;
|
||||
}
|
||||
}
|
||||
ManagedList managedList = new ManagedList();
|
||||
@SuppressWarnings( { "unchecked", "unused" })
|
||||
boolean dummy = managedList.addAll(flows);
|
||||
|
||||
stateBuilder.addConstructorArgValue(managedList);
|
||||
stateBuilder.addConstructorArgValue(idAttribute);
|
||||
|
||||
|
||||
return FlowParser.getNextElements(parserContext, stateBuilder.getBeanDefinition(), element);
|
||||
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ 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.AbstractStep;
|
||||
import org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean;
|
||||
import org.springframework.batch.core.step.item.SimpleStepFactoryBean;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
@@ -138,6 +139,7 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
|
||||
* @see FactoryBean#getObject()
|
||||
*/
|
||||
public final Object getObject() throws Exception {
|
||||
AbstractStep step;
|
||||
if (hasChunkElement) {
|
||||
Assert.isNull(tasklet, "Step [" + name
|
||||
+ "] has both a <chunk/> element and a 'ref' attribute referencing a Tasklet.");
|
||||
@@ -146,24 +148,26 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
|
||||
FaultTolerantStepFactoryBean<I, O> fb = new FaultTolerantStepFactoryBean<I, O>();
|
||||
configureSimple(fb);
|
||||
configureFaultTolerant(fb);
|
||||
return fb.getObject();
|
||||
step = (AbstractStep) fb.getObject();
|
||||
}
|
||||
else {
|
||||
validateSimpleStep();
|
||||
SimpleStepFactoryBean<I, O> fb = new SimpleStepFactoryBean<I, O>();
|
||||
configureSimple(fb);
|
||||
return fb.getObject();
|
||||
step = (AbstractStep) fb.getObject();
|
||||
}
|
||||
}
|
||||
else if (tasklet != null) {
|
||||
TaskletStep ts = new TaskletStep();
|
||||
configureTaskletStep(ts);
|
||||
return ts;
|
||||
step = (AbstractStep) ts;
|
||||
}
|
||||
else {
|
||||
throw new IllegalStateException("Step [" + name
|
||||
+ "] has neither a <chunk/> element nor a 'ref' attribute referencing a Tasklet.");
|
||||
}
|
||||
|
||||
return step;
|
||||
}
|
||||
|
||||
private void configureSimple(SimpleStepFactoryBean<I, O> fb) {
|
||||
@@ -391,6 +395,13 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return jobRepository
|
||||
*/
|
||||
public JobRepository getJobRepository() {
|
||||
return jobRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for {@link JobRepository}.
|
||||
*
|
||||
@@ -418,6 +429,13 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
|
||||
this.tasklet = tasklet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return transactionManager
|
||||
*/
|
||||
public PlatformTransactionManager getTransactionManager() {
|
||||
return transactionManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param transactionManager the transaction manager to set
|
||||
*/
|
||||
@@ -487,7 +505,7 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
|
||||
* {@link MapRetryContextCache}.<br/>
|
||||
*
|
||||
* @param cacheCapacity the cache capacity to set (greater than 0 else
|
||||
* ignored)
|
||||
* ignored)
|
||||
*/
|
||||
public void setCacheCapacity(int cacheCapacity) {
|
||||
this.cacheCapacity = cacheCapacity;
|
||||
@@ -644,4 +662,5 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
|
||||
public void setHasChunkElement(boolean hasChunkElement) {
|
||||
this.hasChunkElement = hasChunkElement;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -21,23 +21,24 @@ import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for the lt;step/gt; top level element in the Batch namespace. Sets up and returns
|
||||
* a bean definition for a {@link org.springframework.batch.core.Step}.
|
||||
* Parser for the lt;step/gt; top level element in the Batch namespace. Sets up
|
||||
* and returns a bean definition for a
|
||||
* {@link org.springframework.batch.core.Step}.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
*
|
||||
*/
|
||||
public class TopLevelStepParser extends AbstractBeanDefinitionParser {
|
||||
|
||||
|
||||
private static final StandaloneStepParser stepParser = new StandaloneStepParser();
|
||||
|
||||
@Override
|
||||
protected AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
|
||||
|
||||
CoreNamespaceUtils.checkForStepScope(parserContext, parserContext.extractSource(element));
|
||||
CoreNamespaceUtils.addRangePropertyEditor(parserContext);
|
||||
CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, parserContext.extractSource(element));
|
||||
|
||||
return stepParser.parse(element, parserContext);
|
||||
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -153,7 +153,22 @@
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="transactionManagerAttribute" />
|
||||
<xsd:attribute name="transaction-manager" type="xsd:string" default="transactionManager">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation
|
||||
source="java:org.springframework.transaction.PlatformTransactionManager"><![CDATA[
|
||||
The bean name of the TransactionManager that is to be used. This attribute
|
||||
is not required, and only needs to be specified explicitly
|
||||
if the bean name of the desired TransactionManager is not 'transactionManager'.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type
|
||||
type="org.springframework.transaction.PlatformTransactionManager" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="isolation-level-for-create" default="SERIALIZABLE" type="isolationType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
@@ -312,7 +327,22 @@
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attributeGroup ref="transactionManagerAttribute"/>
|
||||
<xsd:attribute name="transaction-manager" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation
|
||||
source="java:org.springframework.transaction.PlatformTransactionManager"><![CDATA[
|
||||
The bean name of the TransactionManager that is to be used. This attribute
|
||||
is not required, and only needs to be specified explicitly
|
||||
if the bean name of the desired TransactionManager is not 'transactionManager'.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type
|
||||
type="org.springframework.transaction.PlatformTransactionManager" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
|
||||
<xsd:complexType name="transaction-attributesType">
|
||||
@@ -733,7 +763,7 @@
|
||||
</xsd:group>
|
||||
|
||||
<xsd:attributeGroup name="jobRepositoryAttribute">
|
||||
<xsd:attribute name="job-repository" type="xsd:string" default="jobRepository">
|
||||
<xsd:attribute name="job-repository" type="xsd:string">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation
|
||||
source="java:org.springframework.batch.core.repository.JobRepository"><![CDATA[
|
||||
@@ -751,25 +781,6 @@
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="transactionManagerAttribute">
|
||||
<xsd:attribute name="transaction-manager" type="xsd:string" default="transactionManager">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation
|
||||
source="java:org.springframework.transaction.PlatformTransactionManager"><![CDATA[
|
||||
The bean name of the TransactionManager that is to be used. This attribute
|
||||
is not required, and only needs to be specified explicitly
|
||||
if the bean name of the desired TransactionManager is not 'transactionManager'.
|
||||
]]></xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type
|
||||
type="org.springframework.transaction.PlatformTransactionManager" />
|
||||
</tool:annotation>
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:attributeGroup name="parentAttribute">
|
||||
<xsd:attribute name="parent" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
@@ -810,4 +821,4 @@
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
</xsd:schema>
|
||||
</xsd:schema>
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
* Copyright 2006-2009 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.configuration.xml;
|
||||
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobInstance;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.StepExecution;
|
||||
import org.springframework.batch.core.repository.JobExecutionAlreadyRunningException;
|
||||
import org.springframework.batch.core.repository.JobInstanceAlreadyCompleteException;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.JobRestartException;
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
|
||||
/**
|
||||
* @author Dan Garrette
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public class DummyJobRepository implements JobRepository, BeanNameAware {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setBeanName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void add(StepExecution stepExecution) {
|
||||
}
|
||||
|
||||
public JobExecution createJobExecution(String jobName, JobParameters jobParameters)
|
||||
throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public JobExecution getLastJobExecution(String jobName, JobParameters jobParameters) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public StepExecution getLastStepExecution(JobInstance jobInstance, String stepName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public int getStepExecutionCount(JobInstance jobInstance, String stepName) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public boolean isJobInstanceExists(String jobName, JobParameters jobParameters) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void update(JobExecution jobExecution) {
|
||||
}
|
||||
|
||||
public void update(StepExecution stepExecution) {
|
||||
}
|
||||
|
||||
public void updateExecutionContext(StepExecution stepExecution) {
|
||||
}
|
||||
|
||||
public void updateExecutionContext(JobExecution jobExecution) {
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright 2006-2009 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.configuration.xml;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.TransactionException;
|
||||
import org.springframework.transaction.TransactionStatus;
|
||||
|
||||
/**
|
||||
* @author Dan Garrette
|
||||
* @since 2.0.1
|
||||
*/
|
||||
public class DummyPlatformTransactionManager implements PlatformTransactionManager, BeanNameAware {
|
||||
|
||||
private String name;
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public void setBeanName(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public void commit(TransactionStatus status) throws TransactionException {
|
||||
}
|
||||
|
||||
public void rollback(TransactionStatus status) throws TransactionException {
|
||||
}
|
||||
|
||||
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -20,7 +20,6 @@ import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
@@ -28,6 +27,8 @@ import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecutionListener;
|
||||
import org.springframework.batch.core.job.AbstractJob;
|
||||
import org.springframework.batch.core.listener.JobExecutionListenerSupport;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.SimpleJobRepository;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
@@ -39,11 +40,12 @@ import org.springframework.test.util.ReflectionTestUtils;
|
||||
*/
|
||||
public class JobParserTests {
|
||||
|
||||
ConfigurableApplicationContext jobParserParentAttributeTestsCtx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml");
|
||||
|
||||
@Test
|
||||
public void testInheritListeners() throws Exception {
|
||||
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml");
|
||||
List<?> job1Listeners = getListeners("job1", ctx);
|
||||
List<?> job1Listeners = getListeners("job1", jobParserParentAttributeTestsCtx);
|
||||
assertEquals(2, job1Listeners.size());
|
||||
boolean a = false;
|
||||
boolean b = false;
|
||||
@@ -61,9 +63,7 @@ public class JobParserTests {
|
||||
|
||||
@Test
|
||||
public void testInheritListeners_NoMerge() throws Exception {
|
||||
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml");
|
||||
List<?> job2Listeners = getListeners("job2", ctx);
|
||||
List<?> job2Listeners = getListeners("job2", jobParserParentAttributeTestsCtx);
|
||||
assertEquals(1, job2Listeners.size());
|
||||
boolean c = false;
|
||||
for (Object l : job2Listeners) {
|
||||
@@ -76,9 +76,7 @@ public class JobParserTests {
|
||||
|
||||
@Test
|
||||
public void testStandaloneListener() throws Exception {
|
||||
ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/JobParserParentAttributeTests-context.xml");
|
||||
List<?> jobListeners = getListeners("job3", ctx);
|
||||
List<?> jobListeners = getListeners("job3", jobParserParentAttributeTestsCtx);
|
||||
assertEquals(2, jobListeners.size());
|
||||
boolean a = false;
|
||||
boolean b = false;
|
||||
@@ -96,8 +94,7 @@ public class JobParserTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<?> getListeners(String jobName, ApplicationContext ctx) throws Exception {
|
||||
Map<String, Object> beans = ctx.getBeansOfType(Job.class);
|
||||
assertTrue(beans.containsKey(jobName));
|
||||
assertTrue(ctx.containsBean(jobName));
|
||||
Job job = (Job) ctx.getBean(jobName);
|
||||
|
||||
assertTrue(job instanceof AbstractJob);
|
||||
@@ -114,4 +111,29 @@ public class JobParserTests {
|
||||
}
|
||||
return listeners;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobRepositoryDefaults() throws Exception {
|
||||
ApplicationContext ctx = jobParserParentAttributeTestsCtx;
|
||||
|
||||
assertTrue(getJobRepository("defaultRepoJob", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("specifiedRepoJob", ctx) instanceof DummyJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("inheritSpecifiedRepoJob", ctx) instanceof DummyJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("overrideInheritedRepoJob", ctx) instanceof SimpleJobRepository);
|
||||
}
|
||||
|
||||
private JobRepository getJobRepository(String jobName, ApplicationContext ctx) throws Exception {
|
||||
assertTrue(ctx.containsBean(jobName));
|
||||
Job job = (Job) ctx.getBean(jobName);
|
||||
assertTrue(job instanceof AbstractJob);
|
||||
Object jobRepository = ReflectionTestUtils.getField(job, "jobRepository");
|
||||
while (jobRepository instanceof Advised) {
|
||||
jobRepository = ((Advised) jobRepository).getTargetSource().getTarget();
|
||||
}
|
||||
assertTrue(jobRepository instanceof JobRepository);
|
||||
return (JobRepository) jobRepository;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,11 +25,16 @@ import org.junit.Test;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.batch.core.Step;
|
||||
import org.springframework.batch.core.StepExecutionListener;
|
||||
import org.springframework.batch.core.job.AbstractJob;
|
||||
import org.springframework.batch.core.listener.StepExecutionListenerSupport;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.SimpleJobRepository;
|
||||
import org.springframework.batch.core.step.AbstractStep;
|
||||
import org.springframework.batch.core.step.tasklet.Tasklet;
|
||||
import org.springframework.batch.core.step.tasklet.TaskletStep;
|
||||
import org.springframework.batch.repeat.CompletionPolicy;
|
||||
import org.springframework.batch.repeat.policy.SimpleCompletionPolicy;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
||||
import org.springframework.beans.factory.xml.XmlBeanFactory;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
@@ -37,11 +42,13 @@ import org.springframework.context.ConfigurableApplicationContext;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.core.io.ClassPathResource;
|
||||
import org.springframework.test.util.ReflectionTestUtils;
|
||||
import org.springframework.transaction.PlatformTransactionManager;
|
||||
import org.springframework.transaction.TransactionDefinition;
|
||||
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
|
||||
|
||||
/**
|
||||
* @author Thomas Risberg
|
||||
* @author Dan Garrette
|
||||
*/
|
||||
public class StepParserTests {
|
||||
|
||||
@@ -182,8 +189,7 @@ public class StepParserTests {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private StepExecutionListener getListener(String stepName, ApplicationContext ctx) throws Exception {
|
||||
Map<String, Object> beans = ctx.getBeansOfType(Step.class);
|
||||
assertTrue(beans.containsKey(stepName));
|
||||
assertTrue(ctx.containsBean(stepName));
|
||||
Step step = (Step) ctx.getBean(stepName);
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object compositeListener = ReflectionTestUtils.getField(step, "stepExecutionListener");
|
||||
@@ -199,34 +205,107 @@ public class StepParserTests {
|
||||
return listener;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private DefaultTransactionAttribute getTransactionAttribute(ApplicationContext ctx, String stepName) {
|
||||
Map<String, Object> beans = ctx.getBeansOfType(Step.class);
|
||||
assertTrue(beans.containsKey(stepName));
|
||||
assertTrue(ctx.containsBean(stepName));
|
||||
Step step = (Step) ctx.getBean(stepName);
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object transactionAttribute = ReflectionTestUtils.getField(step, "transactionAttribute");
|
||||
DefaultTransactionAttribute txa = (DefaultTransactionAttribute) transactionAttribute;
|
||||
return txa;
|
||||
return (DefaultTransactionAttribute) transactionAttribute;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testInheritFromBean() throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml");
|
||||
|
||||
|
||||
assertTrue(getTasklet("s9", ctx) instanceof DummyTasklet);
|
||||
assertTrue(getTasklet("s10", ctx) instanceof DummyTasklet);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private Tasklet getTasklet(String stepName, ApplicationContext ctx) {
|
||||
Map<String, Object> beans = ctx.getBeansOfType(Step.class);
|
||||
assertTrue(beans.containsKey(stepName));
|
||||
assertTrue(ctx.containsBean(stepName));
|
||||
Step step = (Step) ctx.getBean(stepName);
|
||||
assertTrue(step instanceof TaskletStep);
|
||||
Object tasklet = ReflectionTestUtils.getField(step, "tasklet");
|
||||
assertTrue(tasklet instanceof Tasklet);
|
||||
return (Tasklet)tasklet;
|
||||
return (Tasklet) tasklet;
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJobRepositoryDefaults() throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml");
|
||||
|
||||
assertTrue(getJobRepository("defaultRepoStep", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("defaultRepoStepWithParent", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertTrue(getJobRepository("overrideRepoStep", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertDummyJobRepository("injectedRepoStep", "dummyJobRepository", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedRepoStepWithParent", "dummyJobRepository", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedOverrideRepoStep", "dummyJobRepository", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedRepoFromParentStep", "dummyJobRepository2", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedRepoFromParentStepWithParent", "dummyJobRepository2", ctx);
|
||||
|
||||
assertDummyJobRepository("injectedOverrideRepoFromParentStep", "dummyJobRepository2", ctx);
|
||||
|
||||
assertTrue(getJobRepository("defaultRepoStandaloneStep", ctx) instanceof SimpleJobRepository);
|
||||
|
||||
assertDummyJobRepository("specifiedRepoStandaloneStep", "dummyJobRepository2", ctx);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTransactionManagerDefaults() throws Exception {
|
||||
ApplicationContext ctx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/batch/core/configuration/xml/StepParserParentAttributeTests-context.xml");
|
||||
|
||||
assertTrue(getTransactionManager("defaultTxMgrStep", ctx) instanceof ResourcelessTransactionManager);
|
||||
|
||||
assertDummyTransactionManager("specifiedTxMgrStep", "dummyTxMgr", ctx);
|
||||
|
||||
assertDummyTransactionManager("defaultTxMgrWithParentStep", "dummyTxMgr", ctx);
|
||||
|
||||
assertDummyTransactionManager("overrideTxMgrOnParentStep", "dummyTxMgr2", ctx);
|
||||
}
|
||||
|
||||
private void assertDummyJobRepository(String beanName, String jobRepoName, ApplicationContext ctx) throws Exception {
|
||||
JobRepository jobRepository = getJobRepository(beanName, ctx);
|
||||
assertTrue(jobRepository instanceof DummyJobRepository);
|
||||
assertEquals(jobRepoName, ((DummyJobRepository) jobRepository).getName());
|
||||
}
|
||||
|
||||
private void assertDummyTransactionManager(String beanName, String txMgrName, ApplicationContext ctx)
|
||||
throws Exception {
|
||||
PlatformTransactionManager txMgr = getTransactionManager(beanName, ctx);
|
||||
assertTrue(txMgr instanceof DummyPlatformTransactionManager);
|
||||
assertEquals(txMgrName, ((DummyPlatformTransactionManager) txMgr).getName());
|
||||
}
|
||||
|
||||
private JobRepository getJobRepository(String beanName, ApplicationContext ctx) throws Exception {
|
||||
Object jobRepository = getFieldFromBean(beanName, "jobRepository", ctx);
|
||||
assertTrue(jobRepository instanceof JobRepository);
|
||||
return (JobRepository) jobRepository;
|
||||
}
|
||||
|
||||
private PlatformTransactionManager getTransactionManager(String beanName, ApplicationContext ctx) throws Exception {
|
||||
Object jobRepository = getFieldFromBean(beanName, "transactionManager", ctx);
|
||||
assertTrue(jobRepository instanceof PlatformTransactionManager);
|
||||
return (PlatformTransactionManager) jobRepository;
|
||||
}
|
||||
|
||||
private Object getFieldFromBean(String beanName, String field, ApplicationContext ctx) throws Exception {
|
||||
assertTrue(ctx.containsBean(beanName));
|
||||
Object bean = ctx.getBean(beanName);
|
||||
assertTrue(bean instanceof AbstractStep || bean instanceof AbstractJob);
|
||||
Object property = ReflectionTestUtils.getField(bean, field);
|
||||
while (property instanceof Advised) {
|
||||
property = ((Advised) property).getTargetSource().getTarget();
|
||||
}
|
||||
return property;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,9 +7,7 @@
|
||||
<beans:import resource="common-context.xml" />
|
||||
|
||||
<job id="job1" parent="baseJob">
|
||||
<step id="s1">
|
||||
<tasklet ref="dummyTasklet"/>
|
||||
</step>
|
||||
<step id="s1"><tasklet ref="dummyTasklet"/></step>
|
||||
|
||||
<listeners merge="true">
|
||||
<listener class="org.springframework.batch.core.listener.JobExecutionListenerSupport"/>
|
||||
@@ -17,9 +15,7 @@
|
||||
</job>
|
||||
|
||||
<job id="job2" parent="baseJob">
|
||||
<step id="s2">
|
||||
<tasklet ref="dummyTasklet"/>
|
||||
</step>
|
||||
<step id="s2"><tasklet ref="dummyTasklet"/></step>
|
||||
|
||||
<listeners>
|
||||
<listener class="org.springframework.batch.core.listener.JobExecutionListenerSupport"/>
|
||||
@@ -27,15 +23,31 @@
|
||||
</job>
|
||||
|
||||
<job id="job3" parent="baseJob3">
|
||||
<step id="s3">
|
||||
<tasklet ref="dummyTasklet"/>
|
||||
</step>
|
||||
<step id="s3"><tasklet ref="dummyTasklet"/></step>
|
||||
|
||||
<listeners merge="true">
|
||||
<listener ref="listener1"/>
|
||||
</listeners>
|
||||
</job>
|
||||
|
||||
<job id="defaultRepoJob">
|
||||
<step id="s4"><tasklet ref="dummyTasklet"/></step>
|
||||
</job>
|
||||
|
||||
<job id="specifiedRepoJob" job-repository="dummyJobRepository">
|
||||
<step id="s5"><tasklet ref="dummyTasklet"/></step>
|
||||
</job>
|
||||
|
||||
<job id="inheritSpecifiedRepoJob" parent="baseSpecifiedRepoJob">
|
||||
<step id="s6"><tasklet ref="dummyTasklet"/></step>
|
||||
</job>
|
||||
|
||||
<job id="overrideInheritedRepoJob" parent="baseSpecifiedRepoJob" job-repository="jobRepository">
|
||||
<step id="s7"><tasklet ref="dummyTasklet"/></step>
|
||||
</job>
|
||||
|
||||
<job id="baseSpecifiedRepoJob" abstract="true" job-repository="dummyJobRepository"/>
|
||||
|
||||
<job id="baseJob" abstract="true">
|
||||
<listeners>
|
||||
<listener class="org.springframework.batch.core.configuration.xml.DummyAnnotationJobExecutionListener"/>
|
||||
@@ -52,4 +64,6 @@
|
||||
</beans:property>
|
||||
</beans:bean>
|
||||
|
||||
</beans:beans>
|
||||
<beans:bean id="dummyJobRepository" class="org.springframework.batch.core.configuration.xml.DummyJobRepository"/>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -82,5 +82,47 @@
|
||||
<listener class="org.springframework.batch.core.listener.StepExecutionListenerSupport" />
|
||||
</listeners>
|
||||
</tasklet>
|
||||
</step>
|
||||
</beans:beans>
|
||||
</step>
|
||||
|
||||
<job id="jobWithoutRepo">
|
||||
<step id="defaultRepoStep"><tasklet ref="dummyTasklet"/></step>
|
||||
<step id="defaultRepoStepWithParent" parent="defaultRepoStandaloneStep"><tasklet ref="dummyTasklet"/></step>
|
||||
<step id="overrideRepoStep" parent="specifiedRepoStandaloneStep"><tasklet ref="dummyTasklet"/></step>
|
||||
</job>
|
||||
|
||||
<job id="jobWithRepo" job-repository="dummyJobRepository">
|
||||
<step id="injectedRepoStep"><tasklet ref="dummyTasklet"/></step>
|
||||
<step id="injectedRepoStepWithParent" parent="defaultRepoStandaloneStep"><tasklet ref="dummyTasklet"/></step>
|
||||
<step id="injectedOverrideRepoStep" parent="specifiedRepoStandaloneStep"><tasklet ref="dummyTasklet"/></step>
|
||||
</job>
|
||||
|
||||
<job id="jobWithRepoOnParent" parent="baseJobWithRepo">
|
||||
<step id="injectedRepoFromParentStep"><tasklet ref="dummyTasklet"/></step>
|
||||
<step id="injectedRepoFromParentStepWithParent" parent="defaultRepoStandaloneStep"><tasklet ref="dummyTasklet"/></step>
|
||||
<step id="injectedOverrideRepoFromParentStep" parent="specifiedRepoStandaloneStep"><tasklet ref="dummyTasklet"/></step>
|
||||
</job>
|
||||
|
||||
<step id="defaultRepoStandaloneStep">
|
||||
<tasklet ref="dummyTasklet"/>
|
||||
</step>
|
||||
|
||||
<step id="specifiedRepoStandaloneStep">
|
||||
<tasklet job-repository="dummyJobRepository2" transaction-manager="dummyTxMgr" ref="dummyTasklet"/>
|
||||
</step>
|
||||
|
||||
<job id="baseJobWithRepo" job-repository="dummyJobRepository2" abstract="true"/>
|
||||
|
||||
<beans:bean id="dummyJobRepository" class="org.springframework.batch.core.configuration.xml.DummyJobRepository"/>
|
||||
<beans:bean id="dummyJobRepository2" class="org.springframework.batch.core.configuration.xml.DummyJobRepository"/>
|
||||
|
||||
<job id="defaultTxMgrTestJob">
|
||||
<step id="defaultTxMgrStep"><tasklet ref="dummyTasklet"/></step>
|
||||
<step id="specifiedTxMgrStep"><tasklet ref="dummyTasklet" transaction-manager="dummyTxMgr"/></step>
|
||||
<step id="defaultTxMgrWithParentStep" parent="specifiedRepoStandaloneStep"/>
|
||||
<step id="overrideTxMgrOnParentStep" parent="specifiedRepoStandaloneStep"><tasklet transaction-manager="dummyTxMgr2"/></step>
|
||||
</job>
|
||||
|
||||
<beans:bean id="dummyTxMgr" class="org.springframework.batch.core.configuration.xml.DummyPlatformTransactionManager"/>
|
||||
<beans:bean id="dummyTxMgr2" class="org.springframework.batch.core.configuration.xml.DummyPlatformTransactionManager"/>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
|
||||
<bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
|
||||
<property name="transactionManager" ref="transactionManager" />
|
||||
</bean>
|
||||
@@ -39,4 +40,4 @@
|
||||
|
||||
<bean id="dummyTasklet" class="org.springframework.batch.core.configuration.xml.DummyTasklet"/>
|
||||
|
||||
</beans>
|
||||
</beans>
|
||||
|
||||
@@ -61,20 +61,23 @@ public class RestartFunctionalTests extends AbstractBatchLauncherTests {
|
||||
* finish successfully, because it continues execution where the previous
|
||||
* run stopped (module throws exception after fixed number of processed
|
||||
* records).
|
||||
* @throws Throwable
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void testRestart() throws Throwable {
|
||||
public void testLaunchJob() throws Exception {
|
||||
|
||||
int before = simpleJdbcTemplate.queryForInt("SELECT COUNT(*) FROM TRADE");
|
||||
|
||||
JobExecution jobExecution = runJobForRestartTest();
|
||||
assertEquals(BatchStatus.FAILED, jobExecution.getStatus());
|
||||
|
||||
Throwable expected = jobExecution.getAllFailureExceptions().get(0);
|
||||
if(expected.getMessage().toLowerCase().indexOf(
|
||||
"planned") < 0) {
|
||||
throw expected;
|
||||
|
||||
Throwable ex = jobExecution.getAllFailureExceptions().get(0);
|
||||
if (ex.getMessage().toLowerCase().indexOf("planned") < 0) {
|
||||
if (ex instanceof Exception) {
|
||||
throw (Exception) ex;
|
||||
}
|
||||
throw new RuntimeException(ex);
|
||||
}
|
||||
|
||||
int medium = simpleJdbcTemplate.queryForInt("SELECT COUNT(*) FROM TRADE");
|
||||
@@ -91,8 +94,12 @@ public class RestartFunctionalTests extends AbstractBatchLauncherTests {
|
||||
|
||||
// load the application context and launch the job
|
||||
private JobExecution runJobForRestartTest() throws Exception {
|
||||
return getLauncher().run(getJob(), new DefaultJobParametersConverter().getJobParameters(PropertiesConverter
|
||||
.stringToProperties("run.id(long)=1,parameter=true,run.date=20070122,input.file=classpath:data/fixedLengthImportJob/input/20070122.teststream.ImportTradeDataStep.txt")));
|
||||
return getLauncher()
|
||||
.run(
|
||||
getJob(),
|
||||
new DefaultJobParametersConverter()
|
||||
.getJobParameters(PropertiesConverter
|
||||
.stringToProperties("run.id(long)=1,parameter=true,run.date=20070122,input.file=classpath:data/fixedLengthImportJob/input/20070122.teststream.ImportTradeDataStep.txt")));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user