RESOLVED - issue BATCH-1478: Add auto registration of StepScope to all the top-level elements in XML
RESOLVED - issue BATCH-1479: HippyMethodInvoker RESOLVED - issue BATCH-1480: Allow method adapter for Tasklet to be configured in namespace
This commit is contained in:
@@ -15,18 +15,13 @@
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.xml;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
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.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
@@ -51,12 +46,6 @@ public abstract class AbstractStepParser {
|
||||
|
||||
private static final String PARENT_ATTR = "parent";
|
||||
|
||||
private static final String TASKLET_REF_ATTR = "ref";
|
||||
|
||||
private static final String BEAN_ELE = "bean";
|
||||
|
||||
private static final String REF_ELE = "ref";
|
||||
|
||||
private static final String REF_ATTR = "ref";
|
||||
|
||||
private static final String TASKLET_ELE = "tasklet";
|
||||
@@ -83,20 +72,8 @@ public abstract class AbstractStepParser {
|
||||
|
||||
private static final String FLOW_ELE = "flow";
|
||||
|
||||
private static final String CHUNK_ELE = "chunk";
|
||||
|
||||
private static final String LISTENERS_ELE = "listeners";
|
||||
|
||||
private static final String MERGE_ATTR = "merge";
|
||||
|
||||
private static final String TX_ATTRIBUTES_ELE = "transaction-attributes";
|
||||
|
||||
private static final String JOB_REPO_ATTR = "job-repository";
|
||||
|
||||
private static final ChunkElementParser chunkElementParser = new ChunkElementParser();
|
||||
|
||||
private static final StepListenerParser stepListenerParser = new StepListenerParser();
|
||||
|
||||
/**
|
||||
* @param stepElement The <step/> element
|
||||
* @param parserContext
|
||||
@@ -111,7 +88,7 @@ public abstract class AbstractStepParser {
|
||||
Element taskletElement = DomUtils.getChildElementByTagName(stepElement, TASKLET_ELE);
|
||||
if (taskletElement != null) {
|
||||
boolean stepUnderspecified = CoreNamespaceUtils.isUnderspecified(stepElement);
|
||||
parseTasklet(stepElement, taskletElement, bd, parserContext, stepUnderspecified);
|
||||
new TaskletParser().parseTasklet(stepElement, taskletElement, bd, parserContext, stepUnderspecified);
|
||||
}
|
||||
|
||||
Element flowElement = DomUtils.getChildElementByTagName(stepElement, FLOW_ELE);
|
||||
@@ -228,46 +205,6 @@ public abstract class AbstractStepParser {
|
||||
|
||||
}
|
||||
|
||||
private void parseTasklet(Element stepElement, Element taskletElement, AbstractBeanDefinition bd,
|
||||
ParserContext parserContext, boolean stepUnderspecified) {
|
||||
|
||||
bd.setBeanClass(StepParserStepFactoryBean.class);
|
||||
bd.setAttribute("isNamespaceStep", true);
|
||||
|
||||
String taskletRef = taskletElement.getAttribute(TASKLET_REF_ATTR);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> chunkElements = DomUtils.getChildElementsByTagName(taskletElement, CHUNK_ELE);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> beanElements = DomUtils.getChildElementsByTagName(taskletElement, BEAN_ELE);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> refElements = DomUtils.getChildElementsByTagName(taskletElement, REF_ELE);
|
||||
|
||||
validateTaskletAttributesAndSubelements(taskletElement, parserContext, stepUnderspecified, taskletRef,
|
||||
chunkElements, beanElements, refElements);
|
||||
|
||||
if (chunkElements.size() == 1) {
|
||||
chunkElementParser.parse(chunkElements.get(0), bd, parserContext, stepUnderspecified);
|
||||
}
|
||||
else {
|
||||
BeanMetadataElement bme = null;
|
||||
if (StringUtils.hasText(taskletRef)) {
|
||||
bme = new RuntimeBeanReference(taskletRef);
|
||||
}
|
||||
else if (beanElements.size() == 1) {
|
||||
bme = parserContext.getDelegate().parseBeanDefinitionElement(beanElements.get(0));
|
||||
}
|
||||
else if (refElements.size() == 1) {
|
||||
bme = (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElements.get(0),
|
||||
null);
|
||||
}
|
||||
|
||||
if (bme != null) {
|
||||
bd.getPropertyValues().addPropertyValue("tasklet", bme);
|
||||
}
|
||||
}
|
||||
|
||||
handleTaskletElement(taskletElement, bd, parserContext);
|
||||
}
|
||||
|
||||
private void parseFlow(Element stepElement, Element flowElement, AbstractBeanDefinition bd,
|
||||
ParserContext parserContext, boolean stepUnderspecified) {
|
||||
@@ -288,163 +225,4 @@ public abstract class AbstractStepParser {
|
||||
|
||||
}
|
||||
|
||||
private void validateTaskletAttributesAndSubelements(Element taskletElement, ParserContext parserContext,
|
||||
boolean stepUnderspecified, String taskletRef, List<Element> chunkElements, List<Element> beanElements,
|
||||
List<Element> refElements) {
|
||||
int total = (StringUtils.hasText(taskletRef) ? 1 : 0) + chunkElements.size() + beanElements.size()
|
||||
+ refElements.size();
|
||||
|
||||
StringBuilder found = new StringBuilder();
|
||||
if (total > 1) {
|
||||
if (StringUtils.hasText(taskletRef)) {
|
||||
found.append("'" + TASKLET_REF_ATTR + "' attribute, ");
|
||||
}
|
||||
if (chunkElements.size() == 1) {
|
||||
found.append("<" + CHUNK_ELE + "/> element, ");
|
||||
}
|
||||
else if (chunkElements.size() > 1) {
|
||||
found.append(chunkElements.size() + " <" + CHUNK_ELE + "/> elements, ");
|
||||
}
|
||||
if (beanElements.size() == 1) {
|
||||
found.append("<" + BEAN_ELE + "/> element, ");
|
||||
}
|
||||
else if (beanElements.size() > 1) {
|
||||
found.append(beanElements.size() + " <" + BEAN_ELE + "/> elements, ");
|
||||
}
|
||||
if (refElements.size() == 1) {
|
||||
found.append("<" + REF_ELE + "/> element, ");
|
||||
}
|
||||
else if (refElements.size() > 1) {
|
||||
found.append(refElements.size() + " <" + REF_ELE + "/> elements, ");
|
||||
}
|
||||
found.delete(found.length() - 2, found.length());
|
||||
}
|
||||
else {
|
||||
found.append("None");
|
||||
}
|
||||
|
||||
String error = null;
|
||||
if (stepUnderspecified) {
|
||||
if (total > 1) {
|
||||
error = "may not have more than";
|
||||
}
|
||||
}
|
||||
else if (total != 1) {
|
||||
error = "must have exactly";
|
||||
}
|
||||
|
||||
if (error != null) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The <" + taskletElement.getTagName() + "/> element " + error + " one of: '" + TASKLET_REF_ATTR
|
||||
+ "' attribute, <" + CHUNK_ELE + "/> element, <" + BEAN_ELE + "/> attribute, or <"
|
||||
+ REF_ELE + "/> element. Found: " + found + ".", taskletElement);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTaskletElement(Element taskletElement, AbstractBeanDefinition bd, ParserContext parserContext) {
|
||||
MutablePropertyValues propertyValues = bd.getPropertyValues();
|
||||
handleTaskletAttributes(taskletElement, propertyValues);
|
||||
handleTransactionAttributesElement(taskletElement, propertyValues);
|
||||
handleListenersElement(taskletElement, propertyValues, parserContext);
|
||||
handleExceptionElement(taskletElement, parserContext, propertyValues, "no-rollback-exception-classes",
|
||||
"noRollbackExceptionClasses");
|
||||
bd.setRole(BeanDefinition.ROLE_SUPPORT);
|
||||
bd.setSource(parserContext.extractSource(taskletElement));
|
||||
}
|
||||
|
||||
private void handleTransactionAttributesElement(Element stepElement, MutablePropertyValues propertyValues) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> txAttrElements = DomUtils.getChildElementsByTagName(stepElement, TX_ATTRIBUTES_ELE);
|
||||
if (txAttrElements.size() == 1) {
|
||||
Element txAttrElement = txAttrElements.get(0);
|
||||
String propagation = txAttrElement.getAttribute("propagation");
|
||||
if (StringUtils.hasText(propagation)) {
|
||||
propertyValues.addPropertyValue("propagation", propagation);
|
||||
}
|
||||
String isolation = txAttrElement.getAttribute("isolation");
|
||||
if (StringUtils.hasText(isolation)) {
|
||||
propertyValues.addPropertyValue("isolation", isolation);
|
||||
}
|
||||
String timeout = txAttrElement.getAttribute("timeout");
|
||||
if (StringUtils.hasText(timeout)) {
|
||||
propertyValues.addPropertyValue("transactionTimeout", timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleExceptionElement(Element element, ParserContext parserContext,
|
||||
MutablePropertyValues propertyValues, String exceptionListName, String propertyName) {
|
||||
List<Element> children = DomUtils.getChildElementsByTagName(element, exceptionListName);
|
||||
if (children.size() == 1) {
|
||||
Element exceptionClassesElement = children.get(0);
|
||||
ManagedList list = new ManagedList();
|
||||
list.setMergeEnabled(exceptionClassesElement.hasAttribute(MERGE_ATTR)
|
||||
&& Boolean.valueOf(exceptionClassesElement.getAttribute(MERGE_ATTR)));
|
||||
addExceptionClasses("include", exceptionClassesElement, list, parserContext);
|
||||
propertyValues.addPropertyValue(propertyName, list);
|
||||
}
|
||||
else if (children.size() > 1) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The <" + exceptionListName + "/> element may not appear more than once in a single <"
|
||||
+ element.getNodeName() + "/>.", element);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addExceptionClasses(String elementName, Element exceptionClassesElement, ManagedList list,
|
||||
ParserContext parserContext) {
|
||||
for (Element child : (List<Element>) DomUtils.getChildElementsByTagName(exceptionClassesElement, elementName)) {
|
||||
String className = child.getAttribute("class");
|
||||
list.add(new TypedStringValue(className, Class.class));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTaskletAttributes(Element taskletElement, MutablePropertyValues propertyValues) {
|
||||
String transactionManagerRef = taskletElement.getAttribute("transaction-manager");
|
||||
if (StringUtils.hasText(transactionManagerRef)) {
|
||||
propertyValues.addPropertyValue("transactionManager", new RuntimeBeanReference(transactionManagerRef));
|
||||
}
|
||||
String startLimit = taskletElement.getAttribute("start-limit");
|
||||
if (StringUtils.hasText(startLimit)) {
|
||||
propertyValues.addPropertyValue("startLimit", startLimit);
|
||||
}
|
||||
String allowStartIfComplete = taskletElement.getAttribute("allow-start-if-complete");
|
||||
if (StringUtils.hasText(allowStartIfComplete)) {
|
||||
propertyValues.addPropertyValue("allowStartIfComplete", allowStartIfComplete);
|
||||
}
|
||||
String taskExecutorBeanId = taskletElement.getAttribute(TASK_EXECUTOR_ATTR);
|
||||
if (StringUtils.hasText(taskExecutorBeanId)) {
|
||||
RuntimeBeanReference taskExecutorRef = new RuntimeBeanReference(taskExecutorBeanId);
|
||||
propertyValues.addPropertyValue("taskExecutor", taskExecutorRef);
|
||||
}
|
||||
String throttleLimit = taskletElement.getAttribute("throttle-limit");
|
||||
if (StringUtils.hasText(throttleLimit)) {
|
||||
propertyValues.addPropertyValue("throttleLimit", throttleLimit);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleListenersElement(Element stepElement, MutablePropertyValues propertyValues,
|
||||
ParserContext parserContext) {
|
||||
List<Element> listenersElements = DomUtils.getChildElementsByTagName(stepElement, LISTENERS_ELE);
|
||||
if (listenersElements.size() == 1) {
|
||||
Element listenersElement = listenersElements.get(0);
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(listenersElement.getTagName(),
|
||||
parserContext.extractSource(stepElement));
|
||||
parserContext.pushContainingComponent(compositeDef);
|
||||
ManagedList listenerBeans = new ManagedList();
|
||||
listenerBeans.setMergeEnabled(listenersElement.hasAttribute(MERGE_ATTR)
|
||||
&& Boolean.valueOf(listenersElement.getAttribute(MERGE_ATTR)));
|
||||
List<Element> listenerElements = DomUtils.getChildElementsByTagName(listenersElement, "listener");
|
||||
if (listenerElements != null) {
|
||||
for (Element listenerElement : listenerElements) {
|
||||
listenerBeans.add(stepListenerParser.parse(listenerElement, parserContext));
|
||||
}
|
||||
}
|
||||
propertyValues.addPropertyValue("listeners", listenerBeans);
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,13 +19,14 @@ import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.transaction.support.DefaultTransactionDefinition;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parser for the lt;job-repository/gt; element in the Batch namespace. Sets up and returns
|
||||
* a JobRepositoryFactoryBean.
|
||||
* Parser for the lt;job-repository/gt; element in the Batch namespace. Sets up
|
||||
* and returns a JobRepositoryFactoryBean.
|
||||
*
|
||||
* @author Thomas Risberg
|
||||
* @since 2.0
|
||||
@@ -33,15 +34,19 @@ import org.w3c.dom.Element;
|
||||
*/
|
||||
public class JobRepositoryParser extends AbstractSingleBeanDefinitionParser {
|
||||
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.batch.core.repository.support.JobRepositoryFactoryBean";
|
||||
}
|
||||
protected String getBeanClassName(Element element) {
|
||||
return "org.springframework.batch.core.repository.support.JobRepositoryFactoryBean";
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse and create a bean definition for a
|
||||
* {@link org.springframework.batch.core.repository.support.JobRepositoryFactoryBean}.
|
||||
* Parse and create a bean definition for a
|
||||
* {@link org.springframework.batch.core.repository.support.JobRepositoryFactoryBean}
|
||||
* .
|
||||
*/
|
||||
protected void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
|
||||
CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, element);
|
||||
|
||||
String dataSource = element.getAttribute("data-source");
|
||||
|
||||
@@ -75,5 +80,4 @@ public class JobRepositoryParser extends AbstractSingleBeanDefinitionParser {
|
||||
builder.setRole(BeanDefinition.ROLE_SUPPORT);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,282 @@
|
||||
/*
|
||||
* Copyright 2006-2010 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 java.util.List;
|
||||
|
||||
import org.springframework.batch.core.step.tasklet.MethodInvokingTaskletAdapter;
|
||||
import org.springframework.beans.BeanMetadataElement;
|
||||
import org.springframework.beans.MutablePropertyValues;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
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.ManagedList;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.util.xml.DomUtils;
|
||||
import org.w3c.dom.Element;
|
||||
|
||||
/**
|
||||
* Parse a tasklet element for a step.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @since 2.1
|
||||
*
|
||||
*/
|
||||
public class TaskletParser {
|
||||
|
||||
private static final String TASKLET_REF_ATTR = "ref";
|
||||
|
||||
private static final String TASKLET_METHOD_ATTR = "method";
|
||||
|
||||
private static final String BEAN_ELE = "bean";
|
||||
|
||||
private static final String REF_ELE = "ref";
|
||||
|
||||
private static final String TASK_EXECUTOR_ATTR = "task-executor";
|
||||
|
||||
private static final String CHUNK_ELE = "chunk";
|
||||
|
||||
private static final String TX_ATTRIBUTES_ELE = "transaction-attributes";
|
||||
|
||||
private static final String LISTENERS_ELE = "listeners";
|
||||
|
||||
private static final String MERGE_ATTR = "merge";
|
||||
|
||||
private static final ChunkElementParser chunkElementParser = new ChunkElementParser();
|
||||
|
||||
private static final StepListenerParser stepListenerParser = new StepListenerParser();
|
||||
|
||||
public void parseTasklet(Element stepElement, Element taskletElement, AbstractBeanDefinition bd,
|
||||
ParserContext parserContext, boolean stepUnderspecified) {
|
||||
|
||||
bd.setBeanClass(StepParserStepFactoryBean.class);
|
||||
bd.setAttribute("isNamespaceStep", true);
|
||||
|
||||
String taskletRef = taskletElement.getAttribute(TASKLET_REF_ATTR);
|
||||
String taskletMethod = taskletElement.getAttribute(TASKLET_METHOD_ATTR);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> chunkElements = DomUtils.getChildElementsByTagName(taskletElement, CHUNK_ELE);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> beanElements = DomUtils.getChildElementsByTagName(taskletElement, BEAN_ELE);
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> refElements = DomUtils.getChildElementsByTagName(taskletElement, REF_ELE);
|
||||
|
||||
validateTaskletAttributesAndSubelements(taskletElement, parserContext, stepUnderspecified, taskletRef,
|
||||
chunkElements, beanElements, refElements);
|
||||
|
||||
if (chunkElements.size() == 1) {
|
||||
chunkElementParser.parse(chunkElements.get(0), bd, parserContext, stepUnderspecified);
|
||||
}
|
||||
else {
|
||||
BeanMetadataElement bme = null;
|
||||
if (StringUtils.hasText(taskletRef)) {
|
||||
bme = new RuntimeBeanReference(taskletRef);
|
||||
}
|
||||
else if (beanElements.size() == 1) {
|
||||
bme = parserContext.getDelegate().parseBeanDefinitionElement(beanElements.get(0));
|
||||
}
|
||||
else if (refElements.size() == 1) {
|
||||
bme = (BeanMetadataElement) parserContext.getDelegate().parsePropertySubElement(refElements.get(0),
|
||||
null);
|
||||
}
|
||||
|
||||
if (StringUtils.hasText(taskletMethod)) {
|
||||
bme = getTaskletAdapter(bme, taskletMethod);
|
||||
}
|
||||
|
||||
if (bme != null) {
|
||||
bd.getPropertyValues().addPropertyValue("tasklet", bme);
|
||||
}
|
||||
}
|
||||
|
||||
handleTaskletElement(taskletElement, bd, parserContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a {@link MethodInvokingTaskletAdapter} for the POJO specified.
|
||||
*/
|
||||
private BeanMetadataElement getTaskletAdapter(BeanMetadataElement bme, String taskletMethod) {
|
||||
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MethodInvokingTaskletAdapter.class);
|
||||
builder.addPropertyValue("targetMethod", taskletMethod);
|
||||
builder.addPropertyValue("targetObject", bme);
|
||||
return builder.getBeanDefinition();
|
||||
}
|
||||
|
||||
private void validateTaskletAttributesAndSubelements(Element taskletElement, ParserContext parserContext,
|
||||
boolean stepUnderspecified, String taskletRef, List<Element> chunkElements, List<Element> beanElements,
|
||||
List<Element> refElements) {
|
||||
int total = (StringUtils.hasText(taskletRef) ? 1 : 0) + chunkElements.size() + beanElements.size()
|
||||
+ refElements.size();
|
||||
|
||||
StringBuilder found = new StringBuilder();
|
||||
if (total > 1) {
|
||||
if (StringUtils.hasText(taskletRef)) {
|
||||
found.append("'" + TASKLET_REF_ATTR + "' attribute, ");
|
||||
}
|
||||
if (chunkElements.size() == 1) {
|
||||
found.append("<" + CHUNK_ELE + "/> element, ");
|
||||
}
|
||||
else if (chunkElements.size() > 1) {
|
||||
found.append(chunkElements.size() + " <" + CHUNK_ELE + "/> elements, ");
|
||||
}
|
||||
if (beanElements.size() == 1) {
|
||||
found.append("<" + BEAN_ELE + "/> element, ");
|
||||
}
|
||||
else if (beanElements.size() > 1) {
|
||||
found.append(beanElements.size() + " <" + BEAN_ELE + "/> elements, ");
|
||||
}
|
||||
if (refElements.size() == 1) {
|
||||
found.append("<" + REF_ELE + "/> element, ");
|
||||
}
|
||||
else if (refElements.size() > 1) {
|
||||
found.append(refElements.size() + " <" + REF_ELE + "/> elements, ");
|
||||
}
|
||||
found.delete(found.length() - 2, found.length());
|
||||
}
|
||||
else {
|
||||
found.append("None");
|
||||
}
|
||||
|
||||
String error = null;
|
||||
if (stepUnderspecified) {
|
||||
if (total > 1) {
|
||||
error = "may not have more than";
|
||||
}
|
||||
}
|
||||
else if (total != 1) {
|
||||
error = "must have exactly";
|
||||
}
|
||||
|
||||
if (error != null) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The <" + taskletElement.getTagName() + "/> element " + error + " one of: '" + TASKLET_REF_ATTR
|
||||
+ "' attribute, <" + CHUNK_ELE + "/> element, <" + BEAN_ELE + "/> attribute, or <"
|
||||
+ REF_ELE + "/> element. Found: " + found + ".", taskletElement);
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTaskletElement(Element taskletElement, AbstractBeanDefinition bd, ParserContext parserContext) {
|
||||
MutablePropertyValues propertyValues = bd.getPropertyValues();
|
||||
handleTaskletAttributes(taskletElement, propertyValues);
|
||||
handleTransactionAttributesElement(taskletElement, propertyValues);
|
||||
handleListenersElement(taskletElement, propertyValues, parserContext);
|
||||
handleExceptionElement(taskletElement, parserContext, propertyValues, "no-rollback-exception-classes",
|
||||
"noRollbackExceptionClasses");
|
||||
bd.setRole(BeanDefinition.ROLE_SUPPORT);
|
||||
bd.setSource(parserContext.extractSource(taskletElement));
|
||||
}
|
||||
|
||||
private void handleTransactionAttributesElement(Element stepElement, MutablePropertyValues propertyValues) {
|
||||
@SuppressWarnings("unchecked")
|
||||
List<Element> txAttrElements = DomUtils.getChildElementsByTagName(stepElement, TX_ATTRIBUTES_ELE);
|
||||
if (txAttrElements.size() == 1) {
|
||||
Element txAttrElement = txAttrElements.get(0);
|
||||
String propagation = txAttrElement.getAttribute("propagation");
|
||||
if (StringUtils.hasText(propagation)) {
|
||||
propertyValues.addPropertyValue("propagation", propagation);
|
||||
}
|
||||
String isolation = txAttrElement.getAttribute("isolation");
|
||||
if (StringUtils.hasText(isolation)) {
|
||||
propertyValues.addPropertyValue("isolation", isolation);
|
||||
}
|
||||
String timeout = txAttrElement.getAttribute("timeout");
|
||||
if (StringUtils.hasText(timeout)) {
|
||||
propertyValues.addPropertyValue("transactionTimeout", timeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleExceptionElement(Element element, ParserContext parserContext,
|
||||
MutablePropertyValues propertyValues, String exceptionListName, String propertyName) {
|
||||
List<Element> children = DomUtils.getChildElementsByTagName(element, exceptionListName);
|
||||
if (children.size() == 1) {
|
||||
Element exceptionClassesElement = children.get(0);
|
||||
ManagedList list = new ManagedList();
|
||||
list.setMergeEnabled(exceptionClassesElement.hasAttribute(MERGE_ATTR)
|
||||
&& Boolean.valueOf(exceptionClassesElement.getAttribute(MERGE_ATTR)));
|
||||
addExceptionClasses("include", exceptionClassesElement, list, parserContext);
|
||||
propertyValues.addPropertyValue(propertyName, list);
|
||||
}
|
||||
else if (children.size() > 1) {
|
||||
parserContext.getReaderContext().error(
|
||||
"The <" + exceptionListName + "/> element may not appear more than once in a single <"
|
||||
+ element.getNodeName() + "/>.", element);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void addExceptionClasses(String elementName, Element exceptionClassesElement, ManagedList list,
|
||||
ParserContext parserContext) {
|
||||
for (Element child : (List<Element>) DomUtils.getChildElementsByTagName(exceptionClassesElement, elementName)) {
|
||||
String className = child.getAttribute("class");
|
||||
list.add(new TypedStringValue(className, Class.class));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleTaskletAttributes(Element taskletElement, MutablePropertyValues propertyValues) {
|
||||
String transactionManagerRef = taskletElement.getAttribute("transaction-manager");
|
||||
if (StringUtils.hasText(transactionManagerRef)) {
|
||||
propertyValues.addPropertyValue("transactionManager", new RuntimeBeanReference(transactionManagerRef));
|
||||
}
|
||||
String startLimit = taskletElement.getAttribute("start-limit");
|
||||
if (StringUtils.hasText(startLimit)) {
|
||||
propertyValues.addPropertyValue("startLimit", startLimit);
|
||||
}
|
||||
String allowStartIfComplete = taskletElement.getAttribute("allow-start-if-complete");
|
||||
if (StringUtils.hasText(allowStartIfComplete)) {
|
||||
propertyValues.addPropertyValue("allowStartIfComplete", allowStartIfComplete);
|
||||
}
|
||||
String taskExecutorBeanId = taskletElement.getAttribute(TASK_EXECUTOR_ATTR);
|
||||
if (StringUtils.hasText(taskExecutorBeanId)) {
|
||||
RuntimeBeanReference taskExecutorRef = new RuntimeBeanReference(taskExecutorBeanId);
|
||||
propertyValues.addPropertyValue("taskExecutor", taskExecutorRef);
|
||||
}
|
||||
String throttleLimit = taskletElement.getAttribute("throttle-limit");
|
||||
if (StringUtils.hasText(throttleLimit)) {
|
||||
propertyValues.addPropertyValue("throttleLimit", throttleLimit);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private void handleListenersElement(Element stepElement, MutablePropertyValues propertyValues,
|
||||
ParserContext parserContext) {
|
||||
List<Element> listenersElements = DomUtils.getChildElementsByTagName(stepElement, LISTENERS_ELE);
|
||||
if (listenersElements.size() == 1) {
|
||||
Element listenersElement = listenersElements.get(0);
|
||||
CompositeComponentDefinition compositeDef = new CompositeComponentDefinition(listenersElement.getTagName(),
|
||||
parserContext.extractSource(stepElement));
|
||||
parserContext.pushContainingComponent(compositeDef);
|
||||
ManagedList listenerBeans = new ManagedList();
|
||||
listenerBeans.setMergeEnabled(listenersElement.hasAttribute(MERGE_ATTR)
|
||||
&& Boolean.valueOf(listenersElement.getAttribute(MERGE_ATTR)));
|
||||
List<Element> listenerElements = DomUtils.getChildElementsByTagName(listenersElement, "listener");
|
||||
if (listenerElements != null) {
|
||||
for (Element listenerElement : listenerElements) {
|
||||
listenerBeans.add(stepListenerParser.parse(listenerElement, parserContext));
|
||||
}
|
||||
}
|
||||
propertyValues.addPropertyValue("listeners", listenerBeans);
|
||||
parserContext.popAndRegisterContainingComponent();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,6 +36,7 @@ public class TopLevelFlowParser extends AbstractFlowParser {
|
||||
*/
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, element);
|
||||
String flowName = element.getAttribute(ID_ATTR);
|
||||
builder.getRawBeanDefinition().setAttribute("flowName", flowName);
|
||||
builder.addPropertyValue("name", flowName);
|
||||
|
||||
@@ -18,6 +18,7 @@ public class TopLevelJobListenerParser extends AbstractSingleBeanDefinitionParse
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, element);
|
||||
jobListenerParser.doParse(element, parserContext, builder);
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ public class TopLevelStepListenerParser extends AbstractSingleBeanDefinitionPars
|
||||
|
||||
@Override
|
||||
protected void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
CoreNamespaceUtils.autoregisterBeansForNamespace(parserContext, element);
|
||||
stepListenerParser.doParse(element, parserContext, builder);
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="description" minOccurs="0" />
|
||||
<xsd:element name="description" type="description" minOccurs="0" />
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:group ref="flowGroup" minOccurs="1" maxOccurs="unbounded" />
|
||||
<xsd:element name="listeners">
|
||||
@@ -126,7 +126,7 @@
|
||||
</xsd:annotation>
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="description" minOccurs="0" />
|
||||
<xsd:element name="description" type="description" minOccurs="0" />
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:group ref="flowGroup" />
|
||||
</xsd:choice>
|
||||
@@ -385,7 +385,7 @@
|
||||
|
||||
<xsd:complexType name="stepType">
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="description" minOccurs="0" />
|
||||
<xsd:element name="description" type="description" minOccurs="0" />
|
||||
<xsd:choice minOccurs="0" maxOccurs="1">
|
||||
<xsd:element name="tasklet" type="taskletType" />
|
||||
<xsd:element name="partition" type="partitionType" />
|
||||
@@ -554,12 +554,20 @@
|
||||
the Tasklet interface.
|
||||
</xsd:documentation>
|
||||
<xsd:appinfo>
|
||||
<tool:annotation kind="ref">
|
||||
<tool:expected-type type="org.springframework.batch.core.step.tasklet.Tasklet" />
|
||||
</tool:annotation>
|
||||
<tool:annotation kind="ref" />
|
||||
</xsd:appinfo>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="method" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
If the tasklet is specified as a bean definition, then a method can be specified and a POJO
|
||||
will
|
||||
be adapted to the Tasklet interface. The method suggested should have the same arguments
|
||||
as Tasklet.execute (or a subset), and have a compatible return type (boolean, void or RepeatStatus).
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
</xsd:attribute>
|
||||
<xsd:attribute name="start-limit" type="xsd:string" use="optional">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
@@ -1227,16 +1235,14 @@
|
||||
</xsd:attribute>
|
||||
</xsd:attributeGroup>
|
||||
|
||||
<xsd:element name="description">
|
||||
<xsd:simpleType name="description">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Contains informative text describing the purpose of the enclosing element.
|
||||
Used primarily for user documentation of XML bean definition documents.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexType mixed="true">
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:restriction base="xsd:string" />
|
||||
</xsd:simpleType>
|
||||
|
||||
</xsd:schema>
|
||||
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright 2006-2007 the original author or authors.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.core.configuration.xml;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.core.BatchStatus;
|
||||
import org.springframework.batch.core.Job;
|
||||
import org.springframework.batch.core.JobExecution;
|
||||
import org.springframework.batch.core.JobParameters;
|
||||
import org.springframework.batch.core.repository.JobRepository;
|
||||
import org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class TaskletParserAdapterTests {
|
||||
|
||||
@Autowired
|
||||
@Qualifier("job1")
|
||||
private Job job1;
|
||||
|
||||
@Autowired
|
||||
@Qualifier("job2")
|
||||
private Job job2;
|
||||
|
||||
@Autowired
|
||||
private JobRepository jobRepository;
|
||||
|
||||
@Autowired
|
||||
private MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
mapJobRepositoryFactoryBean.clear();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskletRef() throws Exception {
|
||||
assertNotNull(job1);
|
||||
JobExecution jobExecution = jobRepository.createJobExecution(job1.getName(), new JobParameters());
|
||||
job1.execute(jobExecution);
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskletInline() throws Exception {
|
||||
assertNotNull(job2);
|
||||
JobExecution jobExecution = jobRepository.createJobExecution(job2.getName(), new JobParameters());
|
||||
job2.execute(jobExecution);
|
||||
assertEquals(BatchStatus.COMPLETED, jobExecution.getStatus());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?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"
|
||||
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">
|
||||
|
||||
<job id="job1">
|
||||
<step id="step1">
|
||||
<tasklet ref="reader" method="read" />
|
||||
</step>
|
||||
</job>
|
||||
|
||||
<job id="job2">
|
||||
<step id="ste2">
|
||||
<tasklet method="read">
|
||||
<beans:bean class="org.springframework.batch.core.configuration.xml.TestReader" />
|
||||
</tasklet>
|
||||
</step>
|
||||
</job>
|
||||
|
||||
<beans:bean id="reader" class="org.springframework.batch.core.configuration.xml.TestReader" />
|
||||
|
||||
<beans:bean id="transactionManager" class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
|
||||
|
||||
<beans:bean id="jobRepository" class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
|
||||
<beans:property name="transactionManager" ref="transactionManager" />
|
||||
</beans:bean>
|
||||
|
||||
</beans:beans>
|
||||
@@ -89,7 +89,7 @@ public abstract class AbstractMethodInvokingDelegator<T> implements Initializing
|
||||
* Create a new configured instance of {@link MethodInvoker}.
|
||||
*/
|
||||
private MethodInvoker createMethodInvoker(Object targetObject, String targetMethod) {
|
||||
MethodInvoker invoker = new MethodInvoker();
|
||||
HippyMethodInvoker invoker = new HippyMethodInvoker();
|
||||
invoker.setTargetObject(targetObject);
|
||||
invoker.setTargetMethod(targetMethod);
|
||||
invoker.setArguments(arguments);
|
||||
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* Copyright 2006-2010 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.item.adapter;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.util.ClassUtils;
|
||||
import org.springframework.util.MethodInvoker;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
/**
|
||||
* A {@link MethodInvoker} that is a bit relaxed about its arguments. You can
|
||||
* give it arguments in the wrong order or you can give it too many arguments
|
||||
* and it will try and find a method that matches a subset.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
* @since 2.1
|
||||
*/
|
||||
public class HippyMethodInvoker extends MethodInvoker {
|
||||
|
||||
@Override
|
||||
protected Method findMatchingMethod() {
|
||||
String targetMethod = getTargetMethod();
|
||||
Object[] arguments = getArguments();
|
||||
Object[] transformedArguments = arguments;
|
||||
int argCount = arguments.length;
|
||||
|
||||
Method[] candidates = ReflectionUtils.getAllDeclaredMethods(getTargetClass());
|
||||
int minTypeDiffWeight = Integer.MAX_VALUE;
|
||||
Method matchingMethod = null;
|
||||
|
||||
for (int i = 0; i < candidates.length; i++) {
|
||||
Method candidate = candidates[i];
|
||||
if (candidate.getName().equals(targetMethod)) {
|
||||
Class<?>[] paramTypes = candidate.getParameterTypes();
|
||||
transformedArguments = new Object[paramTypes.length];
|
||||
for (int j = 0; j < arguments.length; j++) {
|
||||
for (int k = 0; k < paramTypes.length; k++) {
|
||||
if (ClassUtils.isAssignableValue(paramTypes[k], arguments[j])) {
|
||||
transformedArguments[k] = arguments[j];
|
||||
}
|
||||
}
|
||||
}
|
||||
if (paramTypes.length <= argCount) {
|
||||
int typeDiffWeight = getTypeDifferenceWeight(paramTypes, transformedArguments);
|
||||
if (typeDiffWeight < minTypeDiffWeight) {
|
||||
minTypeDiffWeight = typeDiffWeight;
|
||||
matchingMethod = candidate;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
setArguments(transformedArguments);
|
||||
return matchingMethod;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,77 @@
|
||||
package org.springframework.batch.item.adapter;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
public class HippyMethodInvokerTests {
|
||||
|
||||
@Test
|
||||
public void testVanillaMethodInvoker() throws Exception {
|
||||
TestMethodAdapter adapter = new TestMethodAdapter();
|
||||
adapter.setTargetMethod("handle");
|
||||
adapter.setTargetObject(new PlainPojo());
|
||||
assertEquals("2.0.foo", adapter.getMessage(2, "foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testEmptyParameters() throws Exception {
|
||||
TestMethodAdapter adapter = new TestMethodAdapter();
|
||||
adapter.setTargetMethod("empty");
|
||||
adapter.setTargetObject(new PlainPojo());
|
||||
assertEquals(".", adapter.getMessage(2, "foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingArgument() throws Exception {
|
||||
TestMethodAdapter adapter = new TestMethodAdapter();
|
||||
adapter.setTargetMethod("missing");
|
||||
adapter.setTargetObject(new PlainPojo());
|
||||
assertEquals("foo.foo", adapter.getMessage(2, "foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testWrongOrder() throws Exception {
|
||||
TestMethodAdapter adapter = new TestMethodAdapter();
|
||||
adapter.setTargetMethod("disorder");
|
||||
adapter.setTargetObject(new PlainPojo());
|
||||
assertEquals("2.0.foo", adapter.getMessage(2, "foo"));
|
||||
}
|
||||
|
||||
public static class PlainPojo {
|
||||
public String handle(double value, String input) {
|
||||
return value+"."+input;
|
||||
}
|
||||
public String disorder(String input, double value) {
|
||||
return value+"."+input;
|
||||
}
|
||||
public String missing(String input) {
|
||||
return input+"."+input;
|
||||
}
|
||||
public String empty() {
|
||||
return ".";
|
||||
}
|
||||
}
|
||||
|
||||
public static interface Service {
|
||||
String getMessage(double value, String input);
|
||||
}
|
||||
|
||||
public static class TestMethodAdapter extends AbstractMethodInvokingDelegator<String> implements Service {
|
||||
|
||||
public String getMessage(double value, String input) {
|
||||
try {
|
||||
return invokeDelegateMethodWithArguments(new Object[] {value, input});
|
||||
}
|
||||
catch (RuntimeException e) {
|
||||
throw e;
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,30 +1,24 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
<beans xmlns="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.xsd">
|
||||
|
||||
<job id="jobStepJob" restartable="true" xmlns="http://www.springframework.org/schema/batch">
|
||||
<step id="jobStepJob.step1" parent="jobStep"/>
|
||||
<step id="jobStepJob.step1">
|
||||
<job ref="tradeJob" job-parameters-extractor="jobParametersExtractor" />
|
||||
</step>
|
||||
</job>
|
||||
|
||||
<job id="tradeJob" restartable="true" xmlns="http://www.springframework.org/schema/batch">
|
||||
<step id="step1">
|
||||
<tasklet>
|
||||
<chunk reader="itemReader" processor="processor" writer="tradeWriter" commit-interval="2"/>
|
||||
<chunk reader="itemReader" processor="processor" writer="tradeWriter" commit-interval="2" />
|
||||
</tasklet>
|
||||
</step>
|
||||
</job>
|
||||
|
||||
<bean id="jobStep" class="org.springframework.batch.core.step.job.JobStep">
|
||||
<property name="jobRepository" ref="jobRepository"/>
|
||||
<property name="jobLauncher" ref="jobLauncher"/>
|
||||
<property name="job" ref="tradeJob"/>
|
||||
<property name="jobParametersExtractor">
|
||||
<bean class="org.springframework.batch.core.step.job.DefaultJobParametersExtractor">
|
||||
<property name="keys" value="input.file"/>
|
||||
</bean>
|
||||
</property>
|
||||
|
||||
<bean id="jobParametersExtractor" class="org.springframework.batch.core.step.job.DefaultJobParametersExtractor">
|
||||
<property name="keys" value="input.file" />
|
||||
</bean>
|
||||
|
||||
<!-- INFRASTRUCTURE SETUP -->
|
||||
|
||||
Reference in New Issue
Block a user