RESOLVED - issue BATCH-1496: Expose retry-policy in namespace configuration

This commit is contained in:
dsyer
2010-01-30 10:28:57 +00:00
parent 5512054289
commit d8cc4d105d
6 changed files with 126 additions and 17 deletions

View File

@@ -107,6 +107,9 @@ public class ChunkElementParser {
handleItemHandler("skip-policy", "skipPolicy", null, false, element, parserContext,
propertyValues, underspecified);
handleItemHandler("retry-policy", "retryPolicy", null, false, element, parserContext,
propertyValues, underspecified);
String retryLimit = element.getAttribute("retry-limit");
if (StringUtils.hasText(retryLimit)) {
propertyValues.addPropertyValue("retryLimit", retryLimit);

View File

@@ -525,7 +525,7 @@ class StepParserStepFactoryBean<I, O> implements FactoryBean, BeanNameAware {
}
private boolean isFaultTolerant() {
return backOffPolicy != null || skipPolicy != null || isPositive(skipLimit) || isPositive(retryLimit)
return backOffPolicy != null || skipPolicy != null || retryPolicy != null || isPositive(skipLimit) || isPositive(retryLimit)
|| isPositive(cacheCapacity) || isTrue(readerTransactionalQueue);
}

View File

@@ -721,6 +721,18 @@
<xsd:attributeGroup ref="adapterMethodAttribute" />
</xsd:complexType>
</xsd:element>
<xsd:element name="retry-policy" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[
The RetryPolicy used by the step. If specified then the retry limit and retryable exceptions are ignored
]]>
</xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:group ref="beanElementGroup" minOccurs="0" maxOccurs="1" />
<xsd:attributeGroup ref="adapterMethodAttribute" />
</xsd:complexType>
</xsd:element>
<xsd:element name="retry-listeners" minOccurs="0" maxOccurs="1">
<xsd:annotation>
<xsd:documentation><![CDATA[
@@ -852,6 +864,17 @@
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="retry-policy" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[
The retry policy to use. If specified then the retry limit and retryable exceptions are ignored.
]]></xsd:documentation>
<xsd:appinfo>
<tool:annotation kind="ref" />
<tool:expected-type type="org.springframework.batch.retry.RetryPolicy" />
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="retry-limit" type="xsd:string" use="optional">
<xsd:annotation>
<xsd:documentation><![CDATA[

View File

@@ -34,6 +34,7 @@ import org.springframework.batch.item.ItemStream;
import org.springframework.batch.item.support.CompositeItemStream;
import org.springframework.batch.retry.RetryListener;
import org.springframework.batch.retry.listener.RetryListenerSupport;
import org.springframework.batch.retry.policy.SimpleRetryPolicy;
import org.springframework.beans.PropertyAccessorUtils;
import org.springframework.beans.factory.BeanCreationException;
import org.springframework.context.ApplicationContext;
@@ -65,6 +66,27 @@ public class ChunkElementParserTests {
assertTrue("Wrong processor type", chunkProcessor instanceof SimpleChunkProcessor);
}
@Test
public void testRetryPolicyAttribute() throws Exception {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/ChunkElementRetryPolicyParserTests-context.xml");
Map<Class<? extends Throwable>, Boolean> retryable = getNestedExceptionMap("s1", context,
"tasklet.chunkProcessor.batchRetryTemplate.regular.retryPolicy.exceptionClassifier",
"exceptionClassifier");
assertEquals(2, retryable.size());
assertTrue(retryable.containsKey(NullPointerException.class));
assertTrue(retryable.containsKey(ArithmeticException.class));
}
@Test
public void testRetryPolicyElement() throws Exception {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
"org/springframework/batch/core/configuration/xml/ChunkElementRetryPolicyParserTests-context.xml");
SimpleRetryPolicy policy = (SimpleRetryPolicy) getPolicy("s2", context,
"tasklet.chunkProcessor.batchRetryTemplate.regular.retryPolicy.exceptionClassifier");
assertEquals(2, policy.getMaxAttempts());
}
@Test
public void testSkipPolicyAttribute() throws Exception {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(
@@ -227,19 +249,44 @@ public class ChunkElementParserTests {
@SuppressWarnings("unchecked")
private Map<Class<? extends Throwable>, Boolean> getNestedExceptionMap(String stepName, ApplicationContext ctx,
String componentName, String classifierName) throws Exception {
Object policy = getPolicy(stepName, ctx, componentName);
Object exceptionClassifier = ReflectionTestUtils.getField(policy, classifierName);
return (Map<Class<? extends Throwable>, Boolean>) ReflectionTestUtils.getField(exceptionClassifier,
"classified");
}
private Object getPolicy(String stepName, ApplicationContext ctx, String componentName) throws Exception {
@SuppressWarnings("unchecked")
SubclassClassifier<Throwable, Object> classifier = (SubclassClassifier<Throwable, Object>) getNestedPathInStep(stepName, ctx, componentName);
Object policy = classifier.classify(new Exception());
return policy;
}
@SuppressWarnings("unchecked")
private Object getNestedPathInStep(String stepName, ApplicationContext ctx, String path) throws Exception {
Map<String, Step> beans = ctx.getBeansOfType(Step.class);
assertTrue(beans.containsKey(stepName));
Object step = ctx.getBean(stepName);
assertTrue(step instanceof TaskletStep);
Object policy = step;
String path = componentName;
return getNestedPath(step, path);
}
/**
* @param object the target object
* @param path the path to the required field
* @return
*/
private Object getNestedPath(Object object, String path) {
while (StringUtils.hasText(path)) {
int index = PropertyAccessorUtils.getFirstNestedPropertySeparatorIndex(path);
if (index < 0) {
index = path.length();
}
policy = ReflectionTestUtils.getField(policy, path.substring(0, index));
object = ReflectionTestUtils.getField(object, path.substring(0, index));
if (index < path.length()) {
path = path.substring(index + 1);
}
@@ -247,13 +294,7 @@ public class ChunkElementParserTests {
path = "";
}
}
SubclassClassifier<Throwable, Object> classifier = (SubclassClassifier<Throwable, Object>) policy;
policy = classifier.classify(new Exception());
Object exceptionClassifier = ReflectionTestUtils.getField(policy, classifierName);
return (Map<Class<? extends Throwable>, Boolean>) ReflectionTestUtils.getField(exceptionClassifier,
"classified");
return object;
}
private void containsClassified(Map<Class<? extends Throwable>, Boolean> classified,

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<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-2.5.xsd">
<import resource="common-context.xml" />
<job id="job" xmlns="http://www.springframework.org/schema/batch">
<step id="s1" next="s2">
<tasklet>
<chunk reader="reader" writer="writer" processor="processor" commit-interval="5" retry-policy="retryPolicy" />
</tasklet>
</step>
<step id="s2">
<tasklet>
<chunk reader="reader" writer="writer" processor="processor" commit-interval="5">
<retry-policy>
<bean class="org.springframework.batch.retry.policy.SimpleRetryPolicy" xmlns="http://www.springframework.org/schema/beans">
<property name="maxAttempts" value="2" />
</bean>
</retry-policy>
</chunk>
</tasklet>
</step>
</job>
<bean id="retryPolicy" class="org.springframework.batch.retry.policy.ExceptionClassifierRetryPolicy">
<property name="policyMap">
<map>
<entry key="java.lang.NullPointerException">
<bean class="org.springframework.batch.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="2" />
</bean>
</entry>
<entry key="java.lang.ArithmeticException">
<bean class="org.springframework.batch.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="4" />
</bean>
</entry>
</map>
</property>
</bean>
</beans>

View File

@@ -40,13 +40,11 @@ public class ExceptionClassifierRetryPolicy implements RetryPolicy {
new NeverRetryPolicy());
/**
* Setter for policy map. This property should not be changed dynamically -
* set it once, e.g. in configuration, and then don't change it during a
* running application. Either this property or the exception classifier
* directly should be set, but not both.
* Setter for policy map used to create a classifier. Either this property
* or the exception classifier directly should be set, but not both.
*
* @param policyMap a map of String to {@link RetryPolicy} that will be used
* to create a {@link Classifier} to locate a policy.
* @param policyMap a map of Throwable class to {@link RetryPolicy} that
* will be used to create a {@link Classifier} to locate a policy.
*/
public void setPolicyMap(Map<Class<? extends Throwable>, RetryPolicy> policyMap) {
SubclassClassifier<Throwable, RetryPolicy> subclassClassifier = new SubclassClassifier<Throwable, RetryPolicy>(