From 311779037a21a08812fa43ad95c6762840f5ec23 Mon Sep 17 00:00:00 2001 From: dsyer Date: Tue, 2 Sep 2008 09:24:37 +0000 Subject: [PATCH] BATCH-804: add interface for RetryState --- ...sageListenerContainerIntegrationTests.java | 4 +- .../batch/jms/ExternalRetryInBatchTests.java | 4 +- .../batch/retry/jms/ExternalRetryTests.java | 8 +- .../batch/retry/RetryOperations.java | 6 +- .../batch/retry/RetryState.java | 55 +++++---- .../StatefulRetryOperationsInterceptor.java | 5 +- .../retry/support/DefaultRetryState.java | 107 ++++++++++++++++++ .../batch/retry/support/RetryTemplate.java | 60 +--------- .../FatalExceptionRetryPolicyTests.java | 6 +- .../policy/StatefulRetryIntegrationTests.java | 7 +- .../retry/support/DefaultRetryStateTests.java | 87 ++++++++++++++ .../retry/support/RetryTemplateTests.java | 4 +- .../support/StatefulRecoveryRetryTests.java | 23 ++-- 13 files changed, 265 insertions(+), 111 deletions(-) create mode 100644 spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/DefaultRetryState.java create mode 100644 spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/DefaultRetryStateTests.java diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/container/jms/BatchMessageListenerContainerIntegrationTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/container/jms/BatchMessageListenerContainerIntegrationTests.java index 46d6403ae..c730d0dff 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/container/jms/BatchMessageListenerContainerIntegrationTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/container/jms/BatchMessageListenerContainerIntegrationTests.java @@ -30,8 +30,8 @@ import org.junit.runner.RunWith; import org.springframework.batch.retry.RecoveryCallback; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; -import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.policy.NeverRetryPolicy; +import org.springframework.batch.retry.support.DefaultRetryState; import org.springframework.batch.retry.support.RetryTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jms.core.JmsTemplate; @@ -134,7 +134,7 @@ public class BatchMessageListenerContainerIntegrationTests { return msg; } }; - retryTemplate.execute(callback, recoveryCallback, new RetryState(msg.getJMSMessageID())); + retryTemplate.execute(callback, recoveryCallback, new DefaultRetryState(msg.getJMSMessageID())); } catch (Exception e) { throw (RuntimeException) e; diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java index 533c952cd..631ca0a13 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/jms/ExternalRetryInBatchTests.java @@ -37,8 +37,8 @@ import org.springframework.batch.repeat.support.RepeatTemplate; import org.springframework.batch.retry.RecoveryCallback; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; -import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.policy.SimpleRetryPolicy; +import org.springframework.batch.retry.support.DefaultRetryState; import org.springframework.batch.retry.support.RetryTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; @@ -152,7 +152,7 @@ public class ExternalRetryInBatchTests { } }; - retryTemplate.execute(callback, recoveryCallback, new RetryState(item)); + retryTemplate.execute(callback, recoveryCallback, new DefaultRetryState(item)); return ExitStatus.CONTINUABLE; diff --git a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java index d2af73012..3eaf09f16 100644 --- a/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java +++ b/spring-batch-infrastructure-tests/src/test/java/org/springframework/batch/retry/jms/ExternalRetryTests.java @@ -33,7 +33,7 @@ import org.springframework.batch.item.ItemWriter; import org.springframework.batch.retry.RecoveryCallback; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; -import org.springframework.batch.retry.RetryState; +import org.springframework.batch.retry.support.DefaultRetryState; import org.springframework.batch.retry.support.RetryTemplate; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.jdbc.core.simple.SimpleJdbcTemplate; @@ -126,7 +126,7 @@ public class ExternalRetryTests { return null; } }; - return retryTemplate.execute(callback, new RetryState(item)); + return retryTemplate.execute(callback, new DefaultRetryState(item)); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); @@ -154,7 +154,7 @@ public class ExternalRetryTests { return null; } }; - return retryTemplate.execute(callback, new RetryState(item)); + return retryTemplate.execute(callback, new DefaultRetryState(item)); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); @@ -202,7 +202,7 @@ public class ExternalRetryTests { result = (String) new TransactionTemplate(transactionManager).execute(new TransactionCallback() { public Object doInTransaction(TransactionStatus status) { try { - return retryTemplate.execute(callback, recoveryCallback, new RetryState(item)); + return retryTemplate.execute(callback, recoveryCallback, new DefaultRetryState(item)); } catch (Exception e) { throw new RuntimeException(e.getMessage(), e); diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/RetryOperations.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/RetryOperations.java index 3742dd914..158987dcd 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/RetryOperations.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/RetryOperations.java @@ -16,6 +16,8 @@ package org.springframework.batch.retry; +import org.springframework.batch.retry.support.DefaultRetryState; + /** * Defines the basic set of operations implemented by {@link RetryOperations} to * execute operations with configurable retry behaviour. @@ -50,7 +52,7 @@ public interface RetryOperations { /** * A simple stateful retry. Execute the supplied {@link RetryCallback} with - * a target object for the attempt identified by the {@link RetryState}. + * a target object for the attempt identified by the {@link DefaultRetryState}. * Exceptions thrown by the callback are always propagated immediately so * the state is required to be able to identify the previous attempt, if * there is one - hence the state is required. Normal patterns would see @@ -72,7 +74,7 @@ public interface RetryOperations { * A stateful retry with a recovery path. Execute the supplied * {@link RetryCallback} with a fallback on exhausted retry to the * {@link RecoveryCallback} and a target object for the retry attempt - * identified by the {@link RetryState}. + * identified by the {@link DefaultRetryState}. * * @see #execute(RetryCallback, RetryState) * diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/RetryState.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/RetryState.java index 632de9187..b17ea816c 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/RetryState.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/RetryState.java @@ -16,38 +16,45 @@ package org.springframework.batch.retry; /** + * Stateful retry is characterised by having to recognise the items that are + * being processed, so this interface is used primarily to provide a cache key in + * between failed attempts. It also provides a hints to the + * {@link RetryOperations} for optimisations to do with avoidable cache hits and + * switching to stateless retry if a rollback is not needed. + * * @author Dave Syer * */ -public class RetryState { - - final private Object key; - final private boolean forceRefresh; +public interface RetryState { /** - * @param key - * @param forceRefresh - */ - public RetryState(Object key, boolean forceRefresh) { - this.key = key; - this.forceRefresh = forceRefresh; - } - - public RetryState(Object key) { - this(key, false); - } - /** + * Key representing the state for a retry attempt. Stateful retry is + * characterised by having to recognise the items that are being processed, + * so this value is used as a cache key in between failed attempts. + * * @return the key that this state represents */ - public Object getKey() { - return key; - } + Object getKey(); /** - * @return true if the state requires an explicit check for the key + * Indicate whether a cache lookup can be avoided. If the key is known ahead + * of the retry attempt to be fresh (i.e. has never been seen before) then a + * cache lookup can be avoided if this flag is true. + * + * @return true if the state does not require an explicit check for the key */ - public boolean isForceRefresh() { - return forceRefresh; - } + boolean isForceRefresh(); -} + /** + * Check whether this exception requires a rollback. The default is always + * true, which is conservative, so this method provides an optimisation for + * switching to stateless retry if there is an exception for which rollback + * is unnecessary. Example usage would be for a stateful retry to specify a + * validation exception as not for rollback. + * + * @param exception the exception that caused a retry attempt to fail + * @return true if this exception should cause a rollback + */ + boolean rollbackFor(Exception exception); + +} \ No newline at end of file diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/interceptor/StatefulRetryOperationsInterceptor.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/interceptor/StatefulRetryOperationsInterceptor.java index fdf1fb417..d2ac9a9fb 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/interceptor/StatefulRetryOperationsInterceptor.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/interceptor/StatefulRetryOperationsInterceptor.java @@ -21,13 +21,14 @@ import org.aopalliance.intercept.MethodInvocation; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.retry.ExhaustedRetryException; +import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.RecoveryCallback; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; import org.springframework.batch.retry.RetryOperations; import org.springframework.batch.retry.RetryPolicy; -import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.policy.NeverRetryPolicy; +import org.springframework.batch.retry.support.DefaultRetryState; import org.springframework.batch.retry.support.RetryTemplate; import org.springframework.util.Assert; import org.springframework.util.ObjectUtils; @@ -138,7 +139,7 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor { } final Object item = arg; - RetryState retryState = new RetryState(keyGenerator != null ? keyGenerator.getKey(args) : item, newMethodArgumentsIdentifier != null ? newMethodArgumentsIdentifier.isNew(args) : false ); + RetryState retryState = new DefaultRetryState(keyGenerator != null ? keyGenerator.getKey(args) : item, newMethodArgumentsIdentifier != null ? newMethodArgumentsIdentifier.isNew(args) : false ); Object result = retryTemplate.execute(new MethodInvocationRetryCallback(invocation), new ItemRecovererCallback(args, recoverer), retryState); diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/DefaultRetryState.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/DefaultRetryState.java new file mode 100644 index 000000000..7924a4bb7 --- /dev/null +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/DefaultRetryState.java @@ -0,0 +1,107 @@ +/* + * 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.retry.support; + +import org.springframework.batch.retry.RecoveryCallback; +import org.springframework.batch.retry.RetryCallback; +import org.springframework.batch.retry.RetryOperations; +import org.springframework.batch.retry.RetryState; +import org.springframework.batch.support.Classifier; + +/** + * + * @author Dave Syer + * + */ +public class DefaultRetryState implements RetryState { + + final private Object key; + + final private boolean forceRefresh; + + final private Classifier rollbackClassifier; + + /** + * Create a {@link DefaultRetryState} representing the state for a new retry + * attempt. + * + * @see RetryOperations#execute(RetryCallback, RetryState) + * @see RetryOperations#execute(RetryCallback, RecoveryCallback, RetryState) + * + * @param key the key for the state to allow this retry attempt to be + * recognised + * @param forceRefresh true if the attempt is known to be a brand new state + * @param rollbackClassifier the rollback classifier to set. The rollback + * classifier answers true if the exception provided should cause a + * rollback. + */ + public DefaultRetryState(Object key, boolean forceRefresh, Classifier rollbackClassifier) { + this.key = key; + this.forceRefresh = forceRefresh; + this.rollbackClassifier = rollbackClassifier; + } + + /** + * Defaults the rollback classifier to null. + * @see DefaultRetryState#DefaultRetryState(Object, boolean, Classifier) + */ + public DefaultRetryState(Object key, Classifier rollbackClassifier) { + this(key, false, rollbackClassifier); + } + + /** + * Defaults the rollback classifier to null. + * @see DefaultRetryState#DefaultRetryState(Object, boolean, Classifier) + */ + public DefaultRetryState(Object key, boolean forceRefresh) { + this(key, forceRefresh, null); + } + + /** + * Defaults the force refresh flag (to false) and the rollback classifier + * (to null). + * + * @see DefaultRetryState#DefaultRetryState(Object, boolean, Classifier) + */ + public DefaultRetryState(Object key) { + this(key, false, null); + } + + /* (non-Javadoc) + * @see org.springframework.batch.retry.IRetryState#getKey() + */ + public Object getKey() { + return key; + } + + /* (non-Javadoc) + * @see org.springframework.batch.retry.IRetryState#isForceRefresh() + */ + public boolean isForceRefresh() { + return forceRefresh; + } + + /* (non-Javadoc) + * @see org.springframework.batch.retry.IRetryState#rollbackFor(java.lang.Exception) + */ + public boolean rollbackFor(Exception exception) { + if (rollbackClassifier == null) { + return true; + } + return rollbackClassifier.classify(exception); + } + +} diff --git a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/RetryTemplate.java b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/RetryTemplate.java index b3c6f0c2a..621e4c192 100644 --- a/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/RetryTemplate.java +++ b/spring-batch-infrastructure/src/main/java/org/springframework/batch/retry/support/RetryTemplate.java @@ -23,6 +23,7 @@ import java.util.List; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.batch.retry.ExhaustedRetryException; +import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.RecoveryCallback; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; @@ -30,7 +31,6 @@ import org.springframework.batch.retry.RetryException; import org.springframework.batch.retry.RetryListener; import org.springframework.batch.retry.RetryOperations; import org.springframework.batch.retry.RetryPolicy; -import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.TerminatedRetryException; import org.springframework.batch.retry.backoff.BackOffContext; import org.springframework.batch.retry.backoff.BackOffInterruptedException; @@ -39,7 +39,6 @@ import org.springframework.batch.retry.backoff.NoBackOffPolicy; import org.springframework.batch.retry.policy.MapRetryContextCache; import org.springframework.batch.retry.policy.RetryContextCache; import org.springframework.batch.retry.policy.SimpleRetryPolicy; -import org.springframework.batch.support.Classifier; /** * Template class that simplifies the execution of operations with retry @@ -79,45 +78,6 @@ public class RetryTemplate implements RetryOperations { private RetryContextCache retryContextCache = new MapRetryContextCache(); - private Classifier rollbackClassifier = null; - - /** - * Public setter for the rollback classifier. This classifier answers its - * default if the exception provided should not cause a rollback. I.e. - * anything other than the default will lead to a rollback.

- * - * The decision whether to rollback or not is unrelated to that of the - * {@link RetryPolicy}, but the policy can be accidentally inconsistent - * with the rollback decision. E.g. in a stateless retry the policy might be - * configured to allow retry on a rollback, but that wouldn't make sense - a - * stateful retry should have been used. The best we can do in such - * circumstances is throw a {@link RetryException} from - * {@link #execute(RetryCallback)} or - * {@link #execute(RetryCallback, RecoveryCallback)}. The recovery path - * will not be taken in such situations.

- * - * For stateless retry it is often adequate to use the default behaviour, as - * long as one is careful with the retry policy (exceptions which should - * cause rollback are still not really retryable in a transactional - * setting).

- * - * For stateful retry adding a classifier will allow an optimisation: - * exceptions which are not marked for rollback can still be retried, but - * without paying the cost of a rollback. Effectively one is overriding the - * stateful quality of the retry dynamically, according to the exception - * type.

- * - * Example usage would be for a stateful retry to specify a validation exception as not for rollback - * - * If not set then the default is to rollback for all exceptions when the - * retry is stateful, and for none when it is stateless. - * - * @param rollbackClassifier the rollback classifier to set - */ - public void setRollbackClassifier(Classifier rollbackClassifier) { - this.rollbackClassifier = rollbackClassifier; - } - /** * Public setter for the {@link RetryContextCache}. * @param retryContextCache the {@link RetryContextCache} to set. @@ -446,20 +406,12 @@ public class RetryTemplate implements RetryOperations { * otherwise */ protected boolean shouldRethrow(RetryPolicy retryPolicy, RetryContext context, RetryState state) { - // Allow stateless behaviour to take over for certain exception types - if (rollbackClassifier != null) { - // TODO: remove this. Make it part of the stateful execution parameters? - // Then we wouldn't have to make assertions about the stateless case. - boolean rollback = rollbackClassifier.classify(context.getLastThrowable()); - if (rollback && state == null && retryPolicy.canRetry(context)) { - throw new RetryException("Inconsistent configuration. The retry policy says we can retry but " - + "the exception has been marked for rollback.", context.getLastThrowable()); - } - return rollback; + if (state == null) { + return false; + } + else { + return state.rollbackFor(context.getLastThrowable()); } - // If no classifier is provided, just assume the all exceptions are for - // rollback if the execution is stateful, and none otherwise. - return state != null; } private boolean doOpenInterceptors(RetryCallback callback, RetryContext context) { diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/FatalExceptionRetryPolicyTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/FatalExceptionRetryPolicyTests.java index e815f721c..56caae4d6 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/FatalExceptionRetryPolicyTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/FatalExceptionRetryPolicyTests.java @@ -24,7 +24,7 @@ import junit.framework.TestCase; import org.springframework.batch.retry.RecoveryCallback; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; -import org.springframework.batch.retry.RetryState; +import org.springframework.batch.retry.support.DefaultRetryState; import org.springframework.batch.retry.support.RetryTemplate; public class FatalExceptionRetryPolicyTests extends TestCase { @@ -82,14 +82,14 @@ public class FatalExceptionRetryPolicyTests extends TestCase { Object result = null; try { - retryTemplate.execute(callback, recoveryCallback, new RetryState("foo")); + retryTemplate.execute(callback, recoveryCallback, new DefaultRetryState("foo")); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // If stateful we have to always rethrow. Clients who want special // cases have to implement them in the callback } - result = retryTemplate.execute(callback, recoveryCallback, new RetryState("foo")); + result = retryTemplate.execute(callback, recoveryCallback, new DefaultRetryState("foo")); // Callback is called once: the recovery path should also be called assertEquals(1, callback.attempts); assertEquals("bar", result); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/StatefulRetryIntegrationTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/StatefulRetryIntegrationTests.java index fa712c480..30ab5955e 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/StatefulRetryIntegrationTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/policy/StatefulRetryIntegrationTests.java @@ -24,9 +24,10 @@ import static org.junit.Assert.fail; import org.junit.Test; import org.springframework.batch.retry.ExhaustedRetryException; +import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; -import org.springframework.batch.retry.RetryState; +import org.springframework.batch.retry.support.DefaultRetryState; import org.springframework.batch.retry.support.RetryTemplate; /** @@ -39,7 +40,7 @@ public class StatefulRetryIntegrationTests { public void testExternalRetryWithFailAndNoRetry() throws Exception { MockRetryCallback callback = new MockRetryCallback(); - RetryState retryState = new RetryState("foo"); + RetryState retryState = new DefaultRetryState("foo"); RetryTemplate retryTemplate = new RetryTemplate(); MapRetryContextCache cache = new MapRetryContextCache(); @@ -80,7 +81,7 @@ public class StatefulRetryIntegrationTests { public void testExternalRetryWithSuccessOnRetry() throws Exception { MockRetryCallback callback = new MockRetryCallback(); - RetryState retryState = new RetryState("foo"); + RetryState retryState = new DefaultRetryState("foo"); RetryTemplate retryTemplate = new RetryTemplate(); MapRetryContextCache cache = new MapRetryContextCache(); diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/DefaultRetryStateTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/DefaultRetryStateTests.java new file mode 100644 index 000000000..9d13caaeb --- /dev/null +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/DefaultRetryStateTests.java @@ -0,0 +1,87 @@ +/* + * 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.retry.support; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import org.junit.Test; +import org.springframework.batch.support.Classifier; + +/** + * @author Dave Syer + * + */ +public class DefaultRetryStateTests { + + /** + * Test method for + * {@link org.springframework.batch.retry.support.DefaultRetryState#DefaultRetryState(java.lang.Object, boolean, org.springframework.batch.support.Classifier)}. + */ + @Test + public void testDefaultRetryStateObjectBooleanClassifierOfQsuperThrowableBoolean() { + DefaultRetryState state = new DefaultRetryState("foo", true, new Classifier() { + public Boolean classify(Throwable classifiable) { + return false; + } + }); + assertEquals("foo", state.getKey()); + assertTrue(state.isForceRefresh()); + assertFalse(state.rollbackFor(null)); + } + + /** + * Test method for + * {@link org.springframework.batch.retry.support.DefaultRetryState#DefaultRetryState(java.lang.Object, org.springframework.batch.support.Classifier)}. + */ + @Test + public void testDefaultRetryStateObjectClassifierOfQsuperThrowableBoolean() { + DefaultRetryState state = new DefaultRetryState("foo", new Classifier() { + public Boolean classify(Throwable classifiable) { + return false; + } + }); + assertEquals("foo", state.getKey()); + assertFalse(state.isForceRefresh()); + assertFalse(state.rollbackFor(null)); + } + + /** + * Test method for + * {@link org.springframework.batch.retry.support.DefaultRetryState#DefaultRetryState(java.lang.Object, boolean)}. + */ + @Test + public void testDefaultRetryStateObjectBoolean() { + DefaultRetryState state = new DefaultRetryState("foo", true); + assertEquals("foo", state.getKey()); + assertTrue(state.isForceRefresh()); + assertTrue(state.rollbackFor(null)); + } + + /** + * Test method for + * {@link org.springframework.batch.retry.support.DefaultRetryState#DefaultRetryState(java.lang.Object)}. + */ + @Test + public void testDefaultRetryStateObject() { + DefaultRetryState state = new DefaultRetryState("foo"); + assertEquals("foo", state.getKey()); + assertFalse(state.isForceRefresh()); + assertTrue(state.rollbackFor(null)); + } + +} diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/RetryTemplateTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/RetryTemplateTests.java index 16d4464cf..72e7544fd 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/RetryTemplateTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/RetryTemplateTests.java @@ -29,7 +29,6 @@ import org.springframework.batch.retry.ExhaustedRetryException; import org.springframework.batch.retry.RecoveryCallback; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; -import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.backoff.BackOffContext; import org.springframework.batch.retry.backoff.BackOffInterruptedException; import org.springframework.batch.retry.backoff.BackOffPolicy; @@ -130,8 +129,7 @@ public class RetryTemplateTests { retryTemplate.setRetryPolicy(new SimpleRetryPolicy(attempts)); BinaryExceptionClassifier classifier = new BinaryExceptionClassifier(Collections .> singleton(IllegalArgumentException.class), false); - retryTemplate.setRollbackClassifier(classifier); - retryTemplate.execute(callback, new RetryState("foo")); + retryTemplate.execute(callback, new DefaultRetryState("foo",classifier)); assertEquals(attempts, callback.attempts); } diff --git a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/StatefulRecoveryRetryTests.java b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/StatefulRecoveryRetryTests.java index 6c407167b..dd3082b80 100644 --- a/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/StatefulRecoveryRetryTests.java +++ b/spring-batch-infrastructure/src/test/java/org/springframework/batch/retry/support/StatefulRecoveryRetryTests.java @@ -31,12 +31,12 @@ import org.springframework.batch.repeat.RepeatContext; import org.springframework.batch.repeat.context.RepeatContextSupport; import org.springframework.batch.repeat.support.RepeatSynchronizationManager; import org.springframework.batch.retry.ExhaustedRetryException; +import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.RecoveryCallback; import org.springframework.batch.retry.RetryCallback; import org.springframework.batch.retry.RetryContext; import org.springframework.batch.retry.RetryException; import org.springframework.batch.retry.RetryPolicy; -import org.springframework.batch.retry.RetryState; import org.springframework.batch.retry.policy.MapRetryContextCache; import org.springframework.batch.retry.policy.NeverRetryPolicy; import org.springframework.batch.retry.policy.SimpleRetryPolicy; @@ -53,7 +53,7 @@ public class StatefulRecoveryRetryTests { @Test public void testOpenSunnyDay() throws Exception { - RetryContext context = retryTemplate.open(new NeverRetryPolicy(), new RetryState("foo")); + RetryContext context = retryTemplate.open(new NeverRetryPolicy(), new DefaultRetryState("foo")); assertNotNull(context); // we haven't called the processor yet... assertEquals(0, count); @@ -62,7 +62,7 @@ public class StatefulRecoveryRetryTests { @Test public void testRegisterThrowable() { NeverRetryPolicy retryPolicy = new NeverRetryPolicy(); - RetryState state = new RetryState("foo"); + RetryState state = new DefaultRetryState("foo"); RetryContext context = retryTemplate.open(retryPolicy, state); assertNotNull(context); retryTemplate.registerThrowable(retryPolicy, state, context, new Exception()); @@ -72,7 +72,7 @@ public class StatefulRecoveryRetryTests { @Test public void testClose() throws Exception { NeverRetryPolicy retryPolicy = new NeverRetryPolicy(); - RetryState state = new RetryState("foo"); + RetryState state = new DefaultRetryState("foo"); RetryContext context = retryTemplate.open(retryPolicy, state); assertNotNull(context); retryTemplate.registerThrowable(retryPolicy, state, context, new Exception()); @@ -96,7 +96,7 @@ public class StatefulRecoveryRetryTests { public void testRecover() throws Exception { retryTemplate.setRetryPolicy(new SimpleRetryPolicy(1)); final String input = "foo"; - RetryState state = new RetryState(input); + RetryState state = new DefaultRetryState(input); RetryCallback callback = new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { throw new RuntimeException("Barf!"); @@ -132,9 +132,8 @@ public class StatefulRecoveryRetryTests { .> singleton(DataAccessException.class)); // ...but not these: assertFalse(classifier.classify(new RuntimeException())); - retryTemplate.setRollbackClassifier(classifier); final String input = "foo"; - RetryState state = new RetryState(input); + RetryState state = new DefaultRetryState(input,classifier); RetryCallback callback = new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { throw new RuntimeException("Barf!"); @@ -161,7 +160,7 @@ public class StatefulRecoveryRetryTests { retryTemplate.setRetryPolicy(retryPolicy); final String input = "foo"; - RetryState state = new RetryState(input); + RetryState state = new DefaultRetryState(input); RetryCallback callback = new RetryCallback() { public String doWithRetry(RetryContext context) throws Exception { throw new RuntimeException("Barf!"); @@ -195,7 +194,7 @@ public class StatefulRecoveryRetryTests { RetryPolicy retryPolicy = new SimpleRetryPolicy(3); retryTemplate.setRetryPolicy(retryPolicy); final StringHolder item = new StringHolder("bar"); - RetryState state = new RetryState(item); + RetryState state = new DefaultRetryState(item); RetryCallback callback = new RetryCallback() { public StringHolder doWithRetry(RetryContext context) throws Exception { @@ -247,7 +246,7 @@ public class StatefulRecoveryRetryTests { }; try { - retryTemplate.execute(callback, new RetryState("foo")); + retryTemplate.execute(callback, new DefaultRetryState("foo")); fail("Expected RuntimeException"); } catch (RuntimeException e) { @@ -255,7 +254,7 @@ public class StatefulRecoveryRetryTests { } try { - retryTemplate.execute(callback, new RetryState("bar")); + retryTemplate.execute(callback, new DefaultRetryState("bar")); fail("Expected RetryException"); } catch (RetryException e) { @@ -271,7 +270,7 @@ public class StatefulRecoveryRetryTests { retryTemplate.setRetryPolicy(retryPolicy); retryTemplate.setRetryContextCache(new MapRetryContextCache(2)); final StringHolder item = new StringHolder("foo"); - RetryState state = new RetryState(item); + RetryState state = new DefaultRetryState(item); RetryCallback callback = new RetryCallback() { public Object doWithRetry(RetryContext context) throws Exception {