From 2e95ee22c9160e085de515fc47a38cd26888f09f Mon Sep 17 00:00:00 2001 From: trisberg Date: Mon, 16 Feb 2009 01:52:21 +0000 Subject: [PATCH] BATCH-1080: refactored the tasklet element parsing and removed the id attribute from --- .../configuration/xml/AbstractStepParser.java | 212 +---------- .../xml/StandaloneStepParser.java | 8 +- .../xml/TaskletElementParser.java | 279 ++++++++++++++ .../configuration/xml/spring-batch-2.0.xsd | 342 +++++++++--------- 4 files changed, 454 insertions(+), 387 deletions(-) create mode 100644 spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/TaskletElementParser.java diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java index ffeeb3c09..7586b5190 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/AbstractStepParser.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.List; import org.springframework.beans.factory.config.BeanDefinition; -import org.springframework.beans.factory.config.BeanReference; import org.springframework.beans.factory.config.RuntimeBeanReference; import org.springframework.beans.factory.parsing.CompositeComponentDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; @@ -46,6 +45,8 @@ import org.w3c.dom.NamedNodeMap; * @since 2.0 */ public abstract class AbstractStepParser { + + TaskletElementParser taskletElementParser = new TaskletElementParser(); /** * @param stepElement @@ -86,113 +87,20 @@ public abstract class AbstractStepParser { */ protected AbstractBeanDefinition parseTaskletElement(Element stepElement, Element element, ParserContext parserContext, String jobRepositoryRef) { - RootBeanDefinition bd; - - boolean isFaultTolerant = false; - - String skipLimit = element.getAttribute("skip-limit"); - if (!isFaultTolerant) { - isFaultTolerant = checkIntValueForFaultToleranceNeeded(skipLimit); - } - String retryLimit = element.getAttribute("retry-limit"); - if (!isFaultTolerant) { - isFaultTolerant = checkIntValueForFaultToleranceNeeded(retryLimit); - } - String cacheCapacity = element.getAttribute("cache-capacity"); - if (!isFaultTolerant) { - isFaultTolerant = checkIntValueForFaultToleranceNeeded(cacheCapacity); - } - String isReaderTransactionalQueue = element.getAttribute("is-reader-transactional-queue"); - if (!isFaultTolerant && StringUtils.hasText(isReaderTransactionalQueue)) { - if ("true".equals(isReaderTransactionalQueue)) { - isFaultTolerant = true; - } - } - checkExceptionElementForFaultToleranceNeeded(element, "skippable-exception-classes"); - checkExceptionElementForFaultToleranceNeeded(element, "retryable-exception-classes"); - checkExceptionElementForFaultToleranceNeeded(element, "fatal-exception-classes"); - - if (isFaultTolerant) { - bd = new RootBeanDefinition("org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean", null, null); - } - else { - bd = new RootBeanDefinition("org.springframework.batch.core.step.item.SimpleStepFactoryBean", null, null); - } + AbstractBeanDefinition bd = taskletElementParser.parseTaskletElement(element, parserContext); // now, set the properties on the new bean checkStepAttributes(stepElement, bd); - String readerBeanId = element.getAttribute("reader"); - if (StringUtils.hasText(readerBeanId)) { - RuntimeBeanReference readerRef = new RuntimeBeanReference(readerBeanId); - bd.getPropertyValues().addPropertyValue("itemReader", readerRef); - } - - String processorBeanId = element.getAttribute("processor"); - if (StringUtils.hasText(processorBeanId)) { - RuntimeBeanReference processorRef = new RuntimeBeanReference(processorBeanId); - bd.getPropertyValues().addPropertyValue("itemProcessor", processorRef); - } - - String writerBeanId = element.getAttribute("writer"); - if (StringUtils.hasText(writerBeanId)) { - RuntimeBeanReference writerRef = new RuntimeBeanReference(writerBeanId); - bd.getPropertyValues().addPropertyValue("itemWriter", writerRef); - } - - String taskExecutorBeanId = element.getAttribute("task-executor"); - if (StringUtils.hasText(taskExecutorBeanId)) { - RuntimeBeanReference taskExecutorRef = new RuntimeBeanReference(taskExecutorBeanId); - bd.getPropertyValues().addPropertyValue("taskExecutor", taskExecutorRef); - } - RuntimeBeanReference jobRepositoryBeanRef = new RuntimeBeanReference(jobRepositoryRef); bd.getPropertyValues().addPropertyValue("jobRepository", jobRepositoryBeanRef); String transactionManagerRef = stepElement.getAttribute("transaction-manager"); RuntimeBeanReference tx = new RuntimeBeanReference(transactionManagerRef); bd.getPropertyValues().addPropertyValue("transactionManager", tx); - - String commitInterval = element.getAttribute("commit-interval"); - if (StringUtils.hasText(commitInterval)) { - bd.getPropertyValues().addPropertyValue("commitInterval", commitInterval); - } - - if (StringUtils.hasText(skipLimit)) { - bd.getPropertyValues().addPropertyValue("skipLimit", skipLimit); - } - - if (StringUtils.hasText(retryLimit)) { - bd.getPropertyValues().addPropertyValue("retryLimit", retryLimit); - } - - if (StringUtils.hasText(cacheCapacity)) { - bd.getPropertyValues().addPropertyValue("cacheCapacity", cacheCapacity); - } - - String transactionAttribute = element.getAttribute("transaction-attribute"); - if (StringUtils.hasText(transactionAttribute)) { - bd.getPropertyValues().addPropertyValue("transactionAttribute", transactionAttribute); - } - - if (StringUtils.hasText(isReaderTransactionalQueue)) { - if (isFaultTolerant) { - bd.getPropertyValues().addPropertyValue("isReaderTransactionalQueue", isReaderTransactionalQueue); - } - } - - handleExceptionElement(element, parserContext, bd, "skippable-exception-classes", "skippableExceptionClasses", isFaultTolerant); - handleExceptionElement(element, parserContext, bd, "retryable-exception-classes", "retryableExceptionClasses", isFaultTolerant); - - handleExceptionElement(element, parserContext, bd, "fatal-exception-classes", "fatalExceptionClasses", isFaultTolerant); - handleListenersElement(stepElement, bd, parserContext, "listeners"); - handleRetryListenersElement(element, bd, parserContext); - - handleStreamsElement(element, bd, parserContext); - bd.setRole(BeanDefinition.ROLE_SUPPORT); bd.setSource(parserContext.extractSource(stepElement)); @@ -201,7 +109,7 @@ public abstract class AbstractStepParser { } - private void checkStepAttributes(Element stepElement, RootBeanDefinition bd) { + private void checkStepAttributes(Element stepElement, AbstractBeanDefinition bd) { String startLimit = stepElement.getAttribute("start-limit"); if (StringUtils.hasText(startLimit)) { bd.getPropertyValues().addPropertyValue("startLimit", startLimit); @@ -212,44 +120,6 @@ public abstract class AbstractStepParser { } } - private boolean checkIntValueForFaultToleranceNeeded(String stringValue) { - if (StringUtils.hasText(stringValue)) { - int value = Integer.valueOf(stringValue); - if (value > 0) { - return true; - } - } - return false; - } - - private boolean checkExceptionElementForFaultToleranceNeeded(Element element, String subElementName) { - String exceptions = - DomUtils.getChildElementValueByTagName(element, subElementName); - if (StringUtils.hasLength(exceptions)) { - return true; - } - return false; - } - - private void handleExceptionElement(Element element, ParserContext parserContext, BeanDefinition bd, - String subElementName, String propertyName, boolean isFaultTolerant) { - String exceptions = - DomUtils.getChildElementValueByTagName(element, subElementName); - if (StringUtils.hasLength(exceptions)) { - if (isFaultTolerant) { - String[] exceptionArray = StringUtils.tokenizeToStringArray( - StringUtils.delete(exceptions, ","), "\n"); - if (exceptionArray.length > 0) { - bd.getPropertyValues().addPropertyValue(propertyName, exceptionArray); - } - } - else { - parserContext.getReaderContext().error(subElementName + " can only be specified for fault-tolerant " + - "configurations providing skip-limit, retry-limit or cache-capacity", element); - } - } - } - @SuppressWarnings("unchecked") private void handleListenersElement(Element element, BeanDefinition bd, ParserContext parserContext, String property) { Element listenersElement = @@ -268,54 +138,6 @@ public abstract class AbstractStepParser { } } - @SuppressWarnings("unchecked") - private void handleRetryListenersElement(Element element, BeanDefinition bd, ParserContext parserContext) { - Element listenersElement = - DomUtils.getChildElementByTagName(element, "retry-listeners"); - if (listenersElement != null) { - CompositeComponentDefinition compositeDef = - new CompositeComponentDefinition(listenersElement.getTagName(), parserContext.extractSource(element)); - parserContext.pushContainingComponent(compositeDef); - List retryListenerBeans = new ArrayList(); - handleRetryListenerElements(parserContext, listenersElement, - retryListenerBeans); - ManagedList arguments = new ManagedList(); - arguments.addAll(retryListenerBeans); - bd.getPropertyValues().addPropertyValue("retryListeners", arguments); - parserContext.popAndRegisterContainingComponent(); - } - } - - @SuppressWarnings("unchecked") - private void handleRetryListenerElements(ParserContext parserContext, - Element element, List beans) { - List listenerElements = - DomUtils.getChildElementsByTagName(element, "listener"); - if (listenerElements != null) { - for (Element listenerElement : listenerElements) { - String id = listenerElement.getAttribute("id"); - String listenerRef = listenerElement.getAttribute("ref"); - String className = listenerElement.getAttribute("class"); - checkListenerElementAttributes(parserContext, element, - listenerElement, id, listenerRef, className); - if (StringUtils.hasText(listenerRef)) { - BeanReference bean = new RuntimeBeanReference(listenerRef); - beans.add(bean); - } - else if (StringUtils.hasText(className)) { - RootBeanDefinition beanDef = new RootBeanDefinition(className, null, null); - if (!StringUtils.hasText(id)) { - id = parserContext.getReaderContext().generateBeanName(beanDef); - } - beans.add(beanDef); - } - else { - parserContext.getReaderContext().error("Neither 'ref' or 'class' specified for <" + listenerElement.getTagName() + "> element", element); - } - } - } - } - @SuppressWarnings("unchecked") private void handleStepListenerElements(ParserContext parserContext, Element element, List beans) { @@ -397,30 +219,4 @@ public abstract class AbstractStepParser { } } - @SuppressWarnings("unchecked") - private void handleStreamsElement(Element element, BeanDefinition bd, ParserContext parserContext) { - Element streamsElement = - DomUtils.getChildElementByTagName(element, "streams"); - if (streamsElement != null) { - List streamBeans = new ArrayList(); - List streamElements = - DomUtils.getChildElementsByTagName(streamsElement, "stream"); - if (streamElements != null) { - for (Element streamElement : streamElements) { - String streamRef = streamElement.getAttribute("ref"); - if (StringUtils.hasText(streamRef)) { - BeanReference bean = new RuntimeBeanReference(streamRef); - streamBeans.add(bean); - } - else { - parserContext.getReaderContext().error("ref not specified for <" + streamElement.getTagName() + "> element", element); - } - } - } - ManagedList arguments = new ManagedList(); - arguments.addAll(streamBeans); - bd.getPropertyValues().addPropertyValue("streams", arguments); - } - } - } diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StandaloneStepParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StandaloneStepParser.java index 64ef79b68..86a842bb0 100644 --- a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StandaloneStepParser.java +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/StandaloneStepParser.java @@ -24,12 +24,8 @@ import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; /** - * Internal parser for the <step/> elements inside a job. A step element - * references a bean definition for a {@link org.springframework.batch.core.Step} and goes on to (optionally) - * list a set of transitions from that step to others with <next on="pattern" - * to="stepName"/>. Used by the {@link JobParser}. - * - * @see JobParser + * Internal parser for the <step/> elements for a job. A step element + * references a bean definition for a {@link org.springframework.batch.core.Step}. * * @author Dave Syer * @author Thomas Risberg diff --git a/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/TaskletElementParser.java b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/TaskletElementParser.java new file mode 100644 index 000000000..94749f701 --- /dev/null +++ b/spring-batch-core/src/main/java/org/springframework/batch/core/configuration/xml/TaskletElementParser.java @@ -0,0 +1,279 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; + +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanReference; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.CompositeComponentDefinition; +import org.springframework.beans.factory.support.AbstractBeanDefinition; +import org.springframework.beans.factory.support.ManagedList; +import org.springframework.beans.factory.support.RootBeanDefinition; +import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.util.StringUtils; +import org.springframework.util.xml.DomUtils; +import org.w3c.dom.Element; +import org.w3c.dom.NamedNodeMap; + +/** + * Internal parser for the <tasklet/> element either inside a job or as a standalone tasklet definition. + * + * @author Thomas Risberg + * @since 2.0 + */ +public class TaskletElementParser { + + /** + * @param element + * @param parserContext + */ + protected AbstractBeanDefinition parseTaskletElement(Element element, ParserContext parserContext) { + + RootBeanDefinition bd; + + boolean isFaultTolerant = false; + + String skipLimit = element.getAttribute("skip-limit"); + if (!isFaultTolerant) { + isFaultTolerant = checkIntValueForFaultToleranceNeeded(skipLimit); + } + String retryLimit = element.getAttribute("retry-limit"); + if (!isFaultTolerant) { + isFaultTolerant = checkIntValueForFaultToleranceNeeded(retryLimit); + } + String cacheCapacity = element.getAttribute("cache-capacity"); + if (!isFaultTolerant) { + isFaultTolerant = checkIntValueForFaultToleranceNeeded(cacheCapacity); + } + String isReaderTransactionalQueue = element.getAttribute("is-reader-transactional-queue"); + if (!isFaultTolerant && StringUtils.hasText(isReaderTransactionalQueue)) { + if ("true".equals(isReaderTransactionalQueue)) { + isFaultTolerant = true; + } + } + checkExceptionElementForFaultToleranceNeeded(element, "skippable-exception-classes"); + checkExceptionElementForFaultToleranceNeeded(element, "retryable-exception-classes"); + checkExceptionElementForFaultToleranceNeeded(element, "fatal-exception-classes"); + + if (isFaultTolerant) { + bd = new RootBeanDefinition("org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean", null, null); + } + else { + bd = new RootBeanDefinition("org.springframework.batch.core.step.item.SimpleStepFactoryBean", null, null); + } + + String readerBeanId = element.getAttribute("reader"); + if (StringUtils.hasText(readerBeanId)) { + RuntimeBeanReference readerRef = new RuntimeBeanReference(readerBeanId); + bd.getPropertyValues().addPropertyValue("itemReader", readerRef); + } + + String processorBeanId = element.getAttribute("processor"); + if (StringUtils.hasText(processorBeanId)) { + RuntimeBeanReference processorRef = new RuntimeBeanReference(processorBeanId); + bd.getPropertyValues().addPropertyValue("itemProcessor", processorRef); + } + + String writerBeanId = element.getAttribute("writer"); + if (StringUtils.hasText(writerBeanId)) { + RuntimeBeanReference writerRef = new RuntimeBeanReference(writerBeanId); + bd.getPropertyValues().addPropertyValue("itemWriter", writerRef); + } + + String taskExecutorBeanId = element.getAttribute("task-executor"); + if (StringUtils.hasText(taskExecutorBeanId)) { + RuntimeBeanReference taskExecutorRef = new RuntimeBeanReference(taskExecutorBeanId); + bd.getPropertyValues().addPropertyValue("taskExecutor", taskExecutorRef); + } + + String commitInterval = element.getAttribute("commit-interval"); + if (StringUtils.hasText(commitInterval)) { + bd.getPropertyValues().addPropertyValue("commitInterval", commitInterval); + } + + if (StringUtils.hasText(skipLimit)) { + bd.getPropertyValues().addPropertyValue("skipLimit", skipLimit); + } + + if (StringUtils.hasText(retryLimit)) { + bd.getPropertyValues().addPropertyValue("retryLimit", retryLimit); + } + + if (StringUtils.hasText(cacheCapacity)) { + bd.getPropertyValues().addPropertyValue("cacheCapacity", cacheCapacity); + } + + String transactionAttribute = element.getAttribute("transaction-attribute"); + if (StringUtils.hasText(transactionAttribute)) { + bd.getPropertyValues().addPropertyValue("transactionAttribute", transactionAttribute); + } + + if (StringUtils.hasText(isReaderTransactionalQueue)) { + if (isFaultTolerant) { + bd.getPropertyValues().addPropertyValue("isReaderTransactionalQueue", isReaderTransactionalQueue); + } + } + + handleExceptionElement(element, parserContext, bd, "skippable-exception-classes", "skippableExceptionClasses", isFaultTolerant); + + handleExceptionElement(element, parserContext, bd, "retryable-exception-classes", "retryableExceptionClasses", isFaultTolerant); + + handleExceptionElement(element, parserContext, bd, "fatal-exception-classes", "fatalExceptionClasses", isFaultTolerant); + + handleRetryListenersElement(element, bd, parserContext); + + handleStreamsElement(element, bd, parserContext); + + return bd; + + } + + private boolean checkIntValueForFaultToleranceNeeded(String stringValue) { + if (StringUtils.hasText(stringValue)) { + int value = Integer.valueOf(stringValue); + if (value > 0) { + return true; + } + } + return false; + } + + private boolean checkExceptionElementForFaultToleranceNeeded(Element element, String subElementName) { + String exceptions = + DomUtils.getChildElementValueByTagName(element, subElementName); + if (StringUtils.hasLength(exceptions)) { + return true; + } + return false; + } + + private void handleExceptionElement(Element element, ParserContext parserContext, BeanDefinition bd, + String subElementName, String propertyName, boolean isFaultTolerant) { + String exceptions = + DomUtils.getChildElementValueByTagName(element, subElementName); + if (StringUtils.hasLength(exceptions)) { + if (isFaultTolerant) { + String[] exceptionArray = StringUtils.tokenizeToStringArray( + StringUtils.delete(exceptions, ","), "\n"); + if (exceptionArray.length > 0) { + bd.getPropertyValues().addPropertyValue(propertyName, exceptionArray); + } + } + else { + parserContext.getReaderContext().error(subElementName + " can only be specified for fault-tolerant " + + "configurations providing skip-limit, retry-limit or cache-capacity", element); + } + } + } + + @SuppressWarnings("unchecked") + private void handleRetryListenersElement(Element element, BeanDefinition bd, ParserContext parserContext) { + Element listenersElement = + DomUtils.getChildElementByTagName(element, "retry-listeners"); + if (listenersElement != null) { + CompositeComponentDefinition compositeDef = + new CompositeComponentDefinition(listenersElement.getTagName(), parserContext.extractSource(element)); + parserContext.pushContainingComponent(compositeDef); + List retryListenerBeans = new ArrayList(); + handleRetryListenerElements(parserContext, listenersElement, + retryListenerBeans); + ManagedList arguments = new ManagedList(); + arguments.addAll(retryListenerBeans); + bd.getPropertyValues().addPropertyValue("retryListeners", arguments); + parserContext.popAndRegisterContainingComponent(); + } + } + + @SuppressWarnings("unchecked") + private void handleRetryListenerElements(ParserContext parserContext, + Element element, List beans) { + List listenerElements = + DomUtils.getChildElementsByTagName(element, "listener"); + if (listenerElements != null) { + for (Element listenerElement : listenerElements) { + String id = listenerElement.getAttribute("id"); + String listenerRef = listenerElement.getAttribute("ref"); + String className = listenerElement.getAttribute("class"); + checkListenerElementAttributes(parserContext, element, + listenerElement, id, listenerRef, className); + if (StringUtils.hasText(listenerRef)) { + BeanReference bean = new RuntimeBeanReference(listenerRef); + beans.add(bean); + } + else if (StringUtils.hasText(className)) { + RootBeanDefinition beanDef = new RootBeanDefinition(className, null, null); + if (!StringUtils.hasText(id)) { + id = parserContext.getReaderContext().generateBeanName(beanDef); + } + beans.add(beanDef); + } + else { + parserContext.getReaderContext().error("Neither 'ref' or 'class' specified for <" + listenerElement.getTagName() + "> element", element); + } + } + } + } + + private void checkListenerElementAttributes(ParserContext parserContext, + Element element, Element listenerElement, String id, + String listenerRef, String className) { + if ((StringUtils.hasText(id) || StringUtils.hasText(className)) + && StringUtils.hasText(listenerRef)) { + NamedNodeMap attributeNodes = listenerElement.getAttributes(); + StringBuilder attributes = new StringBuilder(); + for (int i = 0; i < attributeNodes.getLength(); i++) { + if (i > 0) { + attributes.append(" "); + } + attributes.append(attributeNodes.item(i)); + } + parserContext.getReaderContext().error("Both 'ref' and " + + (StringUtils.hasText(id) ? "'id'" : "'class'") + + " specified; use 'class' with an optional 'id' or just 'ref' for <" + + listenerElement.getTagName() + "> element specified with attributes: " + attributes, element); + } + } + + @SuppressWarnings("unchecked") + private void handleStreamsElement(Element element, BeanDefinition bd, ParserContext parserContext) { + Element streamsElement = + DomUtils.getChildElementByTagName(element, "streams"); + if (streamsElement != null) { + List streamBeans = new ArrayList(); + List streamElements = + DomUtils.getChildElementsByTagName(streamsElement, "stream"); + if (streamElements != null) { + for (Element streamElement : streamElements) { + String streamRef = streamElement.getAttribute("ref"); + if (StringUtils.hasText(streamRef)) { + BeanReference bean = new RuntimeBeanReference(streamRef); + streamBeans.add(bean); + } + else { + parserContext.getReaderContext().error("ref not specified for <" + streamElement.getTagName() + "> element", element); + } + } + } + ManagedList arguments = new ManagedList(); + arguments.addAll(streamBeans); + bd.getPropertyValues().addPropertyValue("streams", arguments); + } + } + +} diff --git a/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd b/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd index 6ef46c57f..a99285bde 100644 --- a/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd +++ b/spring-batch-core/src/main/resources/org/springframework/batch/core/configuration/xml/spring-batch-2.0.xsd @@ -258,7 +258,7 @@ - + @@ -266,177 +266,173 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -684,7 +680,7 @@ - The tasklet is a reference to another bean definition that defines implements the Tasklet interface. + The tasklet is a reference to another bean definition that implements the Tasklet interface.