Merging changes from branch...
BATCH-1323: Modify skip/retry/no-rollback exception class configurations to allow for include/exclude BATCH-1339: Move task-executor attribute up from <chunk/> to <tasklet/> BATCH-1348: Allow inlining of reader/writer/processor into <chunk/> BATCH-1357: Allow empty <listeners/>, <retry-listeners/>, and <streams/> lists BATCH-1358: Move InfiniteLoopIncrementer into core, and rename it to RunIdIncrementer BATCH-1367: Syntactic sugar for Item*Adapter in namespace BATCH-1375: Give CompositeItemProcessor's and CompositeItemWriter's property the same name (delegates)
This commit is contained in:
@@ -34,9 +34,7 @@ import java.util.Map;
|
||||
public class BinaryExceptionClassifier extends SubclassClassifier<Throwable, Boolean> {
|
||||
|
||||
/**
|
||||
* Create a binary exception classifier with the provided default value. All
|
||||
* exceptions will classify as this value unless
|
||||
* {@link #setTypes(Collection)} is used to narrow the field.
|
||||
* Create a binary exception classifier with the provided default value.
|
||||
*
|
||||
* @param defaultValue defaults to false
|
||||
*/
|
||||
@@ -44,23 +42,22 @@ public class BinaryExceptionClassifier extends SubclassClassifier<Throwable, Boo
|
||||
super(defaultValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a binary exception classifier with the default value (false). All
|
||||
* exceptions will classify as false.
|
||||
*/
|
||||
public BinaryExceptionClassifier() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a binary exception classifier with the provided classes and their
|
||||
* subclasses. The mapped value for these exceptions will be the one
|
||||
* provided (which will be the opposite of the default).
|
||||
*
|
||||
* @param value
|
||||
*/
|
||||
public BinaryExceptionClassifier(Collection<Class<? extends Throwable>> exceptionClasses, boolean value) {
|
||||
this(!value);
|
||||
if (exceptionClasses!=null) setTypes(exceptionClasses);
|
||||
if (exceptionClasses != null) {
|
||||
Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>();
|
||||
for (Class<? extends Throwable> type : exceptionClasses) {
|
||||
map.put(type, !getDefault());
|
||||
}
|
||||
setTypeMap(map);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -72,17 +69,23 @@ public class BinaryExceptionClassifier extends SubclassClassifier<Throwable, Boo
|
||||
}
|
||||
|
||||
/**
|
||||
* Set of Throwable class types to keys for the classifier. Any subclass of
|
||||
* the type provided will be classified as of non-default type.
|
||||
* Create a binary exception classifier using the given classification map
|
||||
* and a default classification of false.
|
||||
*
|
||||
* @param types the types to classify as non-default
|
||||
* @param typeMap
|
||||
*/
|
||||
public final void setTypes(Collection<Class<? extends Throwable>> types) {
|
||||
Map<Class<? extends Throwable>, Boolean> map = new HashMap<Class<? extends Throwable>, Boolean>();
|
||||
for (Class<? extends Throwable> type : types) {
|
||||
map.put(type, !getDefault());
|
||||
}
|
||||
setTypeMap(map);
|
||||
public BinaryExceptionClassifier(Map<Class<? extends Throwable>, Boolean> typeMap) {
|
||||
this(typeMap, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a binary exception classifier using the given classification map
|
||||
* and a default classification of false.
|
||||
*
|
||||
* @param typeMap
|
||||
*/
|
||||
public BinaryExceptionClassifier(Map<Class<? extends Throwable>, Boolean> typeMap, boolean defaultValue) {
|
||||
super(typeMap, defaultValue);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -25,40 +25,38 @@ import org.springframework.util.Assert;
|
||||
/**
|
||||
* Composite {@link ItemProcessor} that passes the item through a sequence of
|
||||
* injected <code>ItemTransformer</code>s (return value of previous
|
||||
* transformation is the entry value of the next).<br/><br/>
|
||||
* transformation is the entry value of the next).<br/>
|
||||
* <br/>
|
||||
*
|
||||
* Note the user is responsible for injecting a chain of {@link ItemProcessor}
|
||||
* s that conforms to declared input and output types.
|
||||
* Note the user is responsible for injecting a chain of {@link ItemProcessor} s
|
||||
* that conforms to declared input and output types.
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public class CompositeItemProcessor<I, O> implements ItemProcessor<I, O>, InitializingBean {
|
||||
|
||||
private List<ItemProcessor> itemProcessors;
|
||||
private List<ItemProcessor<Object, Object>> delegates;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public O process(I item) throws Exception {
|
||||
Object result = item;
|
||||
|
||||
for(ItemProcessor transformer: itemProcessors){
|
||||
if(result == null){
|
||||
|
||||
for (ItemProcessor<Object, Object> delegate : delegates) {
|
||||
if (result == null) {
|
||||
return null;
|
||||
}
|
||||
result = transformer.process(result);
|
||||
result = delegate.process(result);
|
||||
}
|
||||
return (O) result;
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notEmpty(itemProcessors);
|
||||
Assert.notNull(delegates, "The 'delgates' may not be null");
|
||||
Assert.notEmpty(delegates, "The 'delgates' may not be empty");
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemProcessors will be chained to produce a composite
|
||||
* transformation.
|
||||
*/
|
||||
public void setItemProcessors(List<ItemProcessor> itemProcessors) {
|
||||
this.itemProcessors = itemProcessors;
|
||||
public void setDelegates(List<ItemProcessor<Object, Object>> delegates) {
|
||||
this.delegates = delegates;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,34 +16,38 @@
|
||||
|
||||
package org.springframework.batch.item.support;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* Calls a collection of {@link ItemWriter}s in fixed-order sequence.<br/><br/>
|
||||
* Calls a collection of {@link ItemWriter}s in fixed-order sequence.<br/>
|
||||
* <br/>
|
||||
*
|
||||
* The implementation is thread-safe if all delegates are thread-safe.
|
||||
*
|
||||
* @author Robert Kasanicky
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public class CompositeItemWriter<T> implements ItemWriter<T> {
|
||||
public class CompositeItemWriter<T> implements ItemWriter<T>, InitializingBean {
|
||||
|
||||
private List<ItemWriter<? super T>> delegates;
|
||||
|
||||
public void setDelegates(ItemWriter<? super T>[] delegates) {
|
||||
this.delegates = Arrays.asList(delegates);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls injected ItemProcessors in order.
|
||||
*/
|
||||
public void write(List<? extends T> item) throws Exception {
|
||||
public void write(List<? extends T> item) throws Exception {
|
||||
for (ItemWriter<? super T> writer : delegates) {
|
||||
writer.write(item);
|
||||
}
|
||||
}
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(delegates, "The 'delgates' may not be null");
|
||||
Assert.notEmpty(delegates, "The 'delgates' may not be empty");
|
||||
}
|
||||
|
||||
public void setDelegates(List<ItemWriter<? super T>> delegates) {
|
||||
this.delegates = delegates;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
package org.springframework.batch.retry.policy;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
|
||||
import org.springframework.batch.classify.BinaryExceptionClassifier;
|
||||
import org.springframework.batch.retry.RetryContext;
|
||||
@@ -43,44 +42,26 @@ import org.springframework.batch.retry.context.RetryContextSupport;
|
||||
*/
|
||||
public class SimpleRetryPolicy implements RetryPolicy {
|
||||
|
||||
/**
|
||||
* The default limit to the number of attempts for a new policy.
|
||||
*/
|
||||
public final static int DEFAULT_MAX_ATTEMPTS = 3;
|
||||
|
||||
private volatile int maxAttempts;
|
||||
|
||||
private BinaryExceptionClassifier retryableClassifier = new BinaryExceptionClassifier();
|
||||
|
||||
private BinaryExceptionClassifier fatalClassifier = new BinaryExceptionClassifier();
|
||||
|
||||
/**
|
||||
* Create a {@link SimpleRetryPolicy} with the default number of retry
|
||||
* attempts.
|
||||
*/
|
||||
public SimpleRetryPolicy() {
|
||||
this(DEFAULT_MAX_ATTEMPTS);
|
||||
}
|
||||
private BinaryExceptionClassifier retryableClassifier = new BinaryExceptionClassifier(false);
|
||||
|
||||
/**
|
||||
* Create a {@link SimpleRetryPolicy} with the specified number of retry
|
||||
* attempts, and default exceptions to retry.
|
||||
* attempts.
|
||||
*
|
||||
* @param maxAttempts number of allowed attempts (typically >= 1)
|
||||
* @param maxAttempts
|
||||
* @param retryableExceptions
|
||||
*/
|
||||
public SimpleRetryPolicy(int maxAttempts) {
|
||||
public SimpleRetryPolicy(int maxAttempts, Map<Class<? extends Throwable>, Boolean> retryableExceptions) {
|
||||
super();
|
||||
Collection<Class<? extends Throwable>> classes;
|
||||
classes = new HashSet<Class<? extends Throwable>>();
|
||||
classes.add(Exception.class);
|
||||
setRetryableExceptionClasses(classes);
|
||||
classes = new HashSet<Class<? extends Throwable>>();
|
||||
setFatalExceptionClasses(classes);
|
||||
this.maxAttempts = maxAttempts;
|
||||
this.retryableClassifier = new BinaryExceptionClassifier(retryableExceptions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for retry attempts.
|
||||
*
|
||||
* @param retryAttempts the number of attempts before a retry becomes
|
||||
* impossible.
|
||||
*/
|
||||
@@ -90,6 +71,7 @@ public class SimpleRetryPolicy implements RetryPolicy {
|
||||
|
||||
/**
|
||||
* Test for retryable operation based on the status.
|
||||
*
|
||||
* @see org.springframework.batch.retry.RetryPolicy#canRetry(org.springframework.batch.retry.RetryContext)
|
||||
*
|
||||
* @return true if the last exception was retryable and the number of
|
||||
@@ -100,27 +82,6 @@ public class SimpleRetryPolicy implements RetryPolicy {
|
||||
return (t == null || retryForException(t)) && context.getRetryCount() < maxAttempts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the retryable exceptions. Any exception on the list, or subclasses
|
||||
* thereof, will be retryable. Others will be re-thrown without retry.
|
||||
*
|
||||
* @param retryableExceptionClasses defaults to {@link Exception}.
|
||||
*/
|
||||
public final void setRetryableExceptionClasses(Collection<Class<? extends Throwable>> retryableExceptionClasses) {
|
||||
retryableClassifier.setTypes(retryableExceptionClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the fatal exceptions. Any exception on the list, or subclasses
|
||||
* thereof, will be re-thrown without retry. This list takes precedence over
|
||||
* the retryable list.
|
||||
*
|
||||
* @param fatalExceptionClasses defaults to {@link Exception}.
|
||||
*/
|
||||
public final void setFatalExceptionClasses(Collection<Class<? extends Throwable>> fatalExceptionClasses) {
|
||||
fatalClassifier.setTypes(fatalExceptionClasses);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see org.springframework.batch.retry.RetryPolicy#close(RetryContext)
|
||||
*/
|
||||
@@ -142,6 +103,7 @@ public class SimpleRetryPolicy implements RetryPolicy {
|
||||
* Get a status object that can be used to track the current operation
|
||||
* according to this policy. Has to be aware of the latest exception and the
|
||||
* number of attempts.
|
||||
*
|
||||
* @see org.springframework.batch.retry.RetryPolicy#open(RetryContext)
|
||||
*/
|
||||
public RetryContext open(RetryContext parent) {
|
||||
@@ -162,6 +124,6 @@ public class SimpleRetryPolicy implements RetryPolicy {
|
||||
* retryable.
|
||||
*/
|
||||
private boolean retryForException(Throwable ex) {
|
||||
return !fatalClassifier.classify(ex) && retryableClassifier.classify(ex);
|
||||
return retryableClassifier.classify(ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ package org.springframework.batch.retry.support;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
@@ -73,7 +74,8 @@ public class RetryTemplate implements RetryOperations {
|
||||
|
||||
private volatile BackOffPolicy backOffPolicy = new NoBackOffPolicy();
|
||||
|
||||
private volatile RetryPolicy retryPolicy = new SimpleRetryPolicy();
|
||||
private volatile RetryPolicy retryPolicy = new SimpleRetryPolicy(3, Collections
|
||||
.<Class<? extends Throwable>, Boolean> singletonMap(Exception.class, true));
|
||||
|
||||
private volatile RetryListener[] listeners = new RetryListener[0];
|
||||
|
||||
@@ -81,6 +83,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
|
||||
/**
|
||||
* Public setter for the {@link RetryContextCache}.
|
||||
*
|
||||
* @param retryContextCache the {@link RetryContextCache} to set.
|
||||
*/
|
||||
public void setRetryContextCache(RetryContextCache retryContextCache) {
|
||||
@@ -91,6 +94,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
* Setter for listeners. The listeners are executed before and after a retry
|
||||
* block (i.e. before and after all the attempts), and on an error (every
|
||||
* attempt).
|
||||
*
|
||||
* @param listeners
|
||||
* @see RetryListener
|
||||
*/
|
||||
@@ -100,6 +104,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
|
||||
/**
|
||||
* Register an additional listener.
|
||||
*
|
||||
* @param listener
|
||||
* @see #setListeners(RetryListener[])
|
||||
*/
|
||||
@@ -111,6 +116,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
|
||||
/**
|
||||
* Setter for {@link BackOffPolicy}.
|
||||
*
|
||||
* @param backOffPolicy
|
||||
*/
|
||||
public void setBackOffPolicy(BackOffPolicy backOffPolicy) {
|
||||
@@ -195,7 +201,7 @@ public class RetryTemplate implements RetryOperations {
|
||||
|
||||
// Allow the retry policy to initialise itself...
|
||||
RetryContext context = open(retryPolicy, state);
|
||||
logger.debug("RetryContext retrieved: "+context);
|
||||
logger.debug("RetryContext retrieved: " + context);
|
||||
|
||||
// Make sure the context is available globally for clients who need
|
||||
// it...
|
||||
|
||||
Reference in New Issue
Block a user