OPEN - issue BATCH-777: Parametrise RetryCallback and related interfaces
Move key generator and item identifier to retry interceptor package
This commit is contained in:
@@ -28,7 +28,6 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemRecoverer;
|
||||
import org.springframework.batch.repeat.ExitStatus;
|
||||
import org.springframework.batch.repeat.RepeatCallback;
|
||||
import org.springframework.batch.repeat.RepeatContext;
|
||||
@@ -63,7 +62,7 @@ public class ExternalRetryInBatchTests {
|
||||
@Autowired
|
||||
private RepeatTemplate repeatTemplate;
|
||||
|
||||
private ItemReaderRecoverer provider;
|
||||
private ItemReader<String> provider;
|
||||
|
||||
private SimpleJdbcTemplate jdbcTemplate;
|
||||
|
||||
@@ -81,17 +80,12 @@ public class ExternalRetryInBatchTests {
|
||||
jdbcTemplate.getJdbcOperations().execute("delete from T_FOOS");
|
||||
jmsTemplate.convertAndSend("queue", "foo");
|
||||
jmsTemplate.convertAndSend("queue", "bar");
|
||||
provider = new ItemReaderRecoverer() {
|
||||
provider = new ItemReader<String>() {
|
||||
public String read() {
|
||||
String text = (String) jmsTemplate.receiveAndConvert("queue");
|
||||
list.add(text);
|
||||
return text;
|
||||
}
|
||||
|
||||
public String recover(String data, Throwable cause) {
|
||||
recovered.add(data);
|
||||
return data;
|
||||
}
|
||||
};
|
||||
retryTemplate = new RetryTemplate();
|
||||
}
|
||||
@@ -109,7 +103,7 @@ public class ExternalRetryInBatchTests {
|
||||
|
||||
private List<String> list = new ArrayList<String>();
|
||||
|
||||
private List<Object> recovered = new ArrayList<Object>();
|
||||
private List<String> recovered = new ArrayList<String>();
|
||||
|
||||
@Test
|
||||
public void testExternalRetryRecoveryInBatch() throws Exception {
|
||||
@@ -153,7 +147,8 @@ public class ExternalRetryInBatchTests {
|
||||
public String recover(RetryContext context) {
|
||||
// aggressive commit on a recovery
|
||||
RepeatSynchronizationManager.setCompleteOnly();
|
||||
return provider.recover(item, context.getLastThrowable());
|
||||
recovered.add(item);
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -212,7 +207,4 @@ public class ExternalRetryInBatchTests {
|
||||
return msgs;
|
||||
}
|
||||
|
||||
private interface ItemReaderRecoverer extends ItemReader<String>, ItemRecoverer<String,String> {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemRecoverer;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.batch.retry.RecoveryCallback;
|
||||
import org.springframework.batch.retry.RetryCallback;
|
||||
@@ -55,7 +54,7 @@ public class ExternalRetryTests {
|
||||
|
||||
private RetryTemplate retryTemplate;
|
||||
|
||||
private ItemReaderRecoverer<String> provider;
|
||||
private ItemReader<String> provider;
|
||||
|
||||
private SimpleJdbcTemplate simpleJdbcTemplate;
|
||||
|
||||
@@ -72,17 +71,12 @@ public class ExternalRetryTests {
|
||||
getMessages(); // drain queue
|
||||
simpleJdbcTemplate.getJdbcOperations().execute("delete from T_FOOS");
|
||||
jmsTemplate.convertAndSend("queue", "foo");
|
||||
provider = new ItemReaderRecoverer<String>() {
|
||||
provider = new ItemReader<String>() {
|
||||
public String read() {
|
||||
String text = (String) jmsTemplate.receiveAndConvert("queue");
|
||||
list.add(text);
|
||||
return text;
|
||||
}
|
||||
|
||||
public String recover(String data, Throwable cause) {
|
||||
recovered.add(data);
|
||||
return data;
|
||||
}
|
||||
};
|
||||
retryTemplate = new RetryTemplate();
|
||||
}
|
||||
@@ -196,7 +190,8 @@ public class ExternalRetryTests {
|
||||
|
||||
final RecoveryCallback<String> recoveryCallback = new RecoveryCallback<String>() {
|
||||
public String recover(RetryContext context) {
|
||||
return provider.recover(item, context.getLastThrowable());
|
||||
recovered.add(item);
|
||||
return item;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -254,8 +249,4 @@ public class ExternalRetryTests {
|
||||
return msgs;
|
||||
}
|
||||
|
||||
private interface ItemReaderRecoverer<T> extends ItemReader<T>, ItemRecoverer<T,T> {
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,27 +16,16 @@
|
||||
|
||||
package org.springframework.batch.item.jms;
|
||||
|
||||
import javax.jms.Destination;
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Message;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.item.ItemKeyGenerator;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemRecoverer;
|
||||
import org.springframework.batch.item.NewItemIdentifier;
|
||||
import org.springframework.batch.item.UnexpectedInputException;
|
||||
import org.springframework.jms.JmsException;
|
||||
import org.springframework.jms.core.JmsOperations;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
/**
|
||||
* An {@link ItemReader} for JMS using a {@link JmsTemplate}. The template
|
||||
* should have a default destination, which will be used to provide items in
|
||||
* {@link #read()}. If a recovery step is needed, set the error destination and
|
||||
* the item will be sent there if processing fails in a stateful retry.
|
||||
* {@link #read()}.<br/><br/>
|
||||
*
|
||||
* The implementation is thread safe after its properties are set (normal
|
||||
* singleton behaviour).
|
||||
@@ -44,60 +33,7 @@ import org.springframework.util.Assert;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JmsItemReader<T> implements ItemReader<T>, ItemRecoverer<T,T>, ItemKeyGenerator,
|
||||
NewItemIdentifier {
|
||||
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private JmsOperations jmsTemplate;
|
||||
|
||||
private Class<? extends T> itemType;
|
||||
|
||||
private String errorDestinationName;
|
||||
|
||||
private Destination errorDestination;
|
||||
|
||||
/**
|
||||
* Set the error destination. Should not be the same as the default
|
||||
* destination of the jms template.
|
||||
* @param errorDestination a JMS Destination
|
||||
*/
|
||||
public void setErrorDestination(Destination errorDestination) {
|
||||
this.errorDestination = errorDestination;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the error destination by name. Will be resolved by the destination
|
||||
* resolver in the jms template.
|
||||
*
|
||||
* @param errorDestinationName the name of a JMS Destination
|
||||
*/
|
||||
public void setErrorDestinationName(String errorDestinationName) {
|
||||
this.errorDestinationName = errorDestinationName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Setter for jms template.
|
||||
*
|
||||
* @param jmsTemplate a {@link JmsOperations} instance
|
||||
*/
|
||||
public void setJmsTemplate(JmsOperations jmsTemplate) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expected type of incoming message payloads. Set this to
|
||||
* {@link Message} to receive the raw underlying message.
|
||||
*
|
||||
* @param itemType the java class of the items to be delivered. Typically
|
||||
* the same as the class parameter
|
||||
*
|
||||
* @throws IllegalStateException if the message payload is of the wrong
|
||||
* type.
|
||||
*/
|
||||
public void setItemType(Class<? extends T> itemType) {
|
||||
this.itemType = itemType;
|
||||
}
|
||||
public class JmsItemReader<T> extends MessageTypeAccessor<T> implements ItemReader<T> {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public T read() {
|
||||
@@ -112,72 +48,4 @@ public class JmsItemReader<T> implements ItemReader<T>, ItemRecoverer<T,T>, Item
|
||||
return (T) result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the message back to the provider using the specified error
|
||||
* destination property of this reader. If the recovery is successful the
|
||||
* item itself is returned, otherwise null.
|
||||
*
|
||||
* @see org.springframework.batch.item.ItemRecoverer#recover(Object,
|
||||
* Throwable)
|
||||
*/
|
||||
public T recover(T item, Throwable cause) {
|
||||
try {
|
||||
if (errorDestination != null) {
|
||||
jmsTemplate.convertAndSend(errorDestination, item);
|
||||
}
|
||||
else if (errorDestinationName != null) {
|
||||
jmsTemplate.convertAndSend(errorDestinationName, item);
|
||||
}
|
||||
else {
|
||||
// do nothing - it doesn't make sense to send the message back
|
||||
// to the destination it came from
|
||||
return null;
|
||||
}
|
||||
return item;
|
||||
}
|
||||
catch (JmsException e) {
|
||||
logger.error("Could not recover because of JmsException.", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the message is a {@link Message} then returns the JMS message ID.
|
||||
* Otherwise just delegate to parent class.
|
||||
*
|
||||
* @see org.springframework.batch.item.ItemKeyGenerator#getKey(java.lang.Object)
|
||||
*
|
||||
* @throws UnexpectedInputException if the JMS id cannot be determined from
|
||||
* a JMS Message
|
||||
*/
|
||||
public Object getKey(Object item) {
|
||||
if (itemType != null && itemType.isAssignableFrom(Message.class)) {
|
||||
try {
|
||||
return ((Message) item).getJMSMessageID();
|
||||
}
|
||||
catch (JMSException e) {
|
||||
throw new UnexpectedInputException("Could not extract message ID", e);
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the item is a message, check the JMS re-delivered flag, otherwise
|
||||
* return false to be on the safe side.
|
||||
*
|
||||
* @see org.springframework.batch.item.NewItemIdentifier#isNew(java.lang.Object)
|
||||
*/
|
||||
public boolean isNew(Object item) {
|
||||
if (itemType != null && itemType.isAssignableFrom(Message.class)) {
|
||||
try {
|
||||
return !((Message) item).getJMSRedelivered();
|
||||
}
|
||||
catch (JMSException e) {
|
||||
throw new UnexpectedInputException("Could not extract message ID", e);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.item.jms;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.item.ItemWriter;
|
||||
import org.springframework.jms.core.JmsOperations;
|
||||
import org.springframework.jms.core.JmsTemplate;
|
||||
|
||||
/**
|
||||
* An {@link ItemWriter} for JMS using a {@link JmsTemplate}. The template
|
||||
* should have a default destination, which will be used to send items in
|
||||
* {@link #write(List)}.<br/><br/>
|
||||
*
|
||||
* The implementation is thread safe after its properties are set (normal
|
||||
* singleton behaviour).
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JmsItemWriter<T> implements ItemWriter<T> {
|
||||
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private JmsOperations jmsTemplate;
|
||||
|
||||
/**
|
||||
* Setter for jms template.
|
||||
*
|
||||
* @param jmsTemplate a {@link JmsOperations} instance
|
||||
*/
|
||||
public void setJmsTemplate(JmsOperations jmsTemplate) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send the items one-by-one to the default destination of the jms template.
|
||||
*
|
||||
* @see org.springframework.batch.item.ItemWriter#write(java.util.List)
|
||||
*/
|
||||
public void write(List<? extends T> items) throws Exception {
|
||||
for (T item : items) {
|
||||
jmsTemplate.convertAndSend(item);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
/*
|
||||
* 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.item.jms;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Message;
|
||||
|
||||
import org.springframework.batch.item.UnexpectedInputException;
|
||||
import org.springframework.batch.retry.interceptor.MethodArgumentsKeyGenerator;
|
||||
|
||||
/**
|
||||
* A {@link MethodArgumentsKeyGenerator} for JMS
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JmsMethodArgumentsKeyGenerator implements MethodArgumentsKeyGenerator {
|
||||
|
||||
/**
|
||||
* If the message is a {@link Message} then returns the JMS message ID.
|
||||
* Otherwise just return the first argument.
|
||||
*
|
||||
* @see org.springframework.batch.retry.interceptor.MethodArgumentsKeyGenerator#getKey(Object[])
|
||||
*
|
||||
* @throws UnexpectedInputException if the JMS id cannot be determined from
|
||||
* a JMS Message
|
||||
* @throws IllegalArgumentException if the arguments are empty
|
||||
*/
|
||||
public Object getKey(Object[] items) {
|
||||
for (Object item : items) {
|
||||
if (item instanceof Message) {
|
||||
try {
|
||||
return ((Message) item).getJMSMessageID();
|
||||
}
|
||||
catch (JMSException e) {
|
||||
throw new UnexpectedInputException("Could not extract message ID", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (items.length == 0) {
|
||||
throw new IllegalArgumentException(
|
||||
"Method parameters are empty. The key generator cannot determine a unique key.");
|
||||
}
|
||||
return items[0];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.item.jms;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.retry.interceptor.MethodInvocationRecoverer;
|
||||
import org.springframework.jms.JmsException;
|
||||
import org.springframework.jms.core.JmsOperations;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JmsMethodInvocationRecoverer<T> implements MethodInvocationRecoverer<T> {
|
||||
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private JmsOperations jmsTemplate;
|
||||
|
||||
/**
|
||||
* Setter for jms template.
|
||||
*
|
||||
* @param jmsTemplate a {@link JmsOperations} instance
|
||||
*/
|
||||
public void setJmsTemplate(JmsOperations jmsTemplate) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Send one message per item in the arguments list using the default destination of
|
||||
* the jms template. If the recovery is successful null is returned.
|
||||
*
|
||||
* @see org.springframework.batch.retry.interceptor.MethodInvocationRecoverer#recover(Object[],
|
||||
* Throwable)
|
||||
*/
|
||||
public T recover(Object[] items, Throwable cause) {
|
||||
try {
|
||||
for (Object item : items) {
|
||||
jmsTemplate.convertAndSend(item);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
catch (JmsException e) {
|
||||
logger.error("Could not recover because of JmsException.", e);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* 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.item.jms;
|
||||
|
||||
import javax.jms.JMSException;
|
||||
import javax.jms.Message;
|
||||
|
||||
import org.springframework.batch.item.UnexpectedInputException;
|
||||
import org.springframework.batch.retry.interceptor.NewMethodArgumentsIdentifier;
|
||||
|
||||
/**
|
||||
* A {@link NewMethodArgumentsIdentifier} for JMS that looks for a message in
|
||||
* the arguments and checks its delivery status.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JmsNewMethodArgumentsIdentifier<T> implements NewMethodArgumentsIdentifier {
|
||||
|
||||
/**
|
||||
* If any of the arguments is a message, check the JMS re-delivered flag and
|
||||
* return it, otherwise return false to be on the safe side.
|
||||
*
|
||||
* @see org.springframework.batch.retry.interceptor.NewMethodArgumentsIdentifier#isNew(java.lang.Object[])
|
||||
*/
|
||||
public boolean isNew(Object[] args) {
|
||||
|
||||
for (Object item : args) {
|
||||
if (item instanceof Message) {
|
||||
try {
|
||||
return !((Message) item).getJMSRedelivered();
|
||||
}
|
||||
catch (JMSException e) {
|
||||
throw new UnexpectedInputException("Could not extract message ID", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.item.jms;
|
||||
|
||||
import javax.jms.Message;
|
||||
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.jms.core.JmsOperations;
|
||||
|
||||
/**
|
||||
* Base class for JMS concerns.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
class MessageTypeAccessor<T> {
|
||||
|
||||
protected Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
protected Class<? extends T> itemType;
|
||||
|
||||
protected JmsOperations jmsTemplate;
|
||||
|
||||
/**
|
||||
* Setter for jms template.
|
||||
*
|
||||
* @param jmsTemplate a {@link JmsOperations} instance
|
||||
*/
|
||||
public void setJmsTemplate(JmsOperations jmsTemplate) {
|
||||
this.jmsTemplate = jmsTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the expected type of incoming message payloads. Set this to
|
||||
* {@link Message} to receive the raw underlying message.
|
||||
*
|
||||
* @param itemType the java class of the items to be delivered. Typically
|
||||
* the same as the class parameter
|
||||
*
|
||||
* @throws IllegalStateException if the message payload is of the wrong
|
||||
* type.
|
||||
*/
|
||||
public void setItemType(Class<? extends T> itemType) {
|
||||
this.itemType = itemType;
|
||||
}
|
||||
|
||||
public boolean isMessageType() {
|
||||
return itemType != null && itemType.isAssignableFrom(Message.class);
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -13,7 +13,9 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.batch.item;
|
||||
package org.springframework.batch.retry.interceptor;
|
||||
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
|
||||
/**
|
||||
* Extension of the {@link ItemReader} interface that allows items to be
|
||||
@@ -22,7 +24,7 @@ package org.springframework.batch.item;
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface ItemKeyGenerator {
|
||||
public interface MethodArgumentsKeyGenerator {
|
||||
|
||||
/**
|
||||
* Get a unique identifier for the item that can be used to cache it between
|
||||
@@ -31,6 +33,6 @@ public interface ItemKeyGenerator {
|
||||
* @param item the current item.
|
||||
* @return a unique identifier.
|
||||
*/
|
||||
Object getKey(Object item);
|
||||
Object getKey(Object[] item);
|
||||
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.batch.item;
|
||||
package org.springframework.batch.retry.interceptor;
|
||||
|
||||
|
||||
/**
|
||||
@@ -22,7 +22,7 @@ package org.springframework.batch.item;
|
||||
*
|
||||
* @author Dave Syer
|
||||
*/
|
||||
public interface ItemRecoverer<T,S> {
|
||||
public interface MethodInvocationRecoverer<T> {
|
||||
|
||||
/**
|
||||
* Recover gracefully from an error. Clients can call this if processing of
|
||||
@@ -30,11 +30,11 @@ public interface ItemRecoverer<T,S> {
|
||||
* to decide whether to try more corrective action or perhaps throw an
|
||||
* exception.
|
||||
*
|
||||
* @param data
|
||||
* the item that failed.
|
||||
* @param args
|
||||
* the arguments for the method invocation that failed.
|
||||
* @param cause
|
||||
* the cause of the failure that led to this recovery.
|
||||
* @return the value to be returned to the caller
|
||||
*/
|
||||
T recover(S data, Throwable cause);
|
||||
T recover(Object[] args, Throwable cause);
|
||||
}
|
||||
@@ -14,24 +14,24 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.batch.item;
|
||||
package org.springframework.batch.retry.interceptor;
|
||||
|
||||
/**
|
||||
* Strategy interface to distinguish a new item from one that has been processed
|
||||
* before and one that has not, e.g. by examining a message flag.
|
||||
* Strategy interface to distinguish new arguments from ones that have been
|
||||
* processed before, e.g. by examining a message flag.
|
||||
*
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public interface NewItemIdentifier {
|
||||
public interface NewMethodArgumentsIdentifier {
|
||||
|
||||
/**
|
||||
* Inspect the item and determine if it has never been processed before.
|
||||
* The safest choice when the answer is indeterminate is 'false'.
|
||||
* Inspect the arguments and determine if they have never been processed
|
||||
* before. The safest choice when the answer is indeterminate is 'false'.
|
||||
*
|
||||
* @param item the current item.
|
||||
* @param args the current method arguments.
|
||||
* @return true if the item is known to have never been processed before.
|
||||
*/
|
||||
boolean isNew(Object item);
|
||||
boolean isNew(Object[] args);
|
||||
|
||||
}
|
||||
@@ -20,9 +20,6 @@ import org.aopalliance.intercept.MethodInterceptor;
|
||||
import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.apache.commons.logging.Log;
|
||||
import org.apache.commons.logging.LogFactory;
|
||||
import org.springframework.batch.item.ItemKeyGenerator;
|
||||
import org.springframework.batch.item.ItemRecoverer;
|
||||
import org.springframework.batch.item.NewItemIdentifier;
|
||||
import org.springframework.batch.retry.ExhaustedRetryException;
|
||||
import org.springframework.batch.retry.RecoveryCallback;
|
||||
import org.springframework.batch.retry.RetryCallback;
|
||||
@@ -40,8 +37,8 @@ import org.springframework.util.ObjectUtils;
|
||||
* a method on a service if it fails. The argument to the service method is
|
||||
* treated as an item to be remembered in case the call fails. So the retry
|
||||
* operation is stateful, and the item that failed is tracked by its unique key
|
||||
* (via {@link ItemKeyGenerator}) until the retry is exhausted, at which point
|
||||
* the {@link ItemRecoverer} is called.<br/>
|
||||
* (via {@link MethodArgumentsKeyGenerator}) until the retry is exhausted, at which point
|
||||
* the {@link MethodInvocationRecoverer} is called.<br/>
|
||||
*
|
||||
* The main use case for this is where the service is transactional, via a
|
||||
* transaction interceptor on the interceptor chain. In this case the retry (and
|
||||
@@ -57,11 +54,11 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor {
|
||||
|
||||
private transient Log logger = LogFactory.getLog(getClass());
|
||||
|
||||
private ItemKeyGenerator keyGenerator;
|
||||
private MethodArgumentsKeyGenerator keyGenerator;
|
||||
|
||||
private ItemRecoverer<? extends Object,Object[]> recoverer;
|
||||
private MethodInvocationRecoverer<? extends Object> recoverer;
|
||||
|
||||
private NewItemIdentifier newItemIdentifier;
|
||||
private NewMethodArgumentsIdentifier newMethodArgumentsIdentifier;
|
||||
|
||||
private final RetryTemplate retryTemplate = new RetryTemplate();
|
||||
|
||||
@@ -74,7 +71,7 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link ItemRecoverer} to use if the retry is
|
||||
* Public setter for the {@link MethodInvocationRecoverer} to use if the retry is
|
||||
* exhausted. The recoverer should be able to return an object of the same
|
||||
* type as the target object because its return value will be used to return
|
||||
* to the caller in the case of a recovery.<br/>
|
||||
@@ -82,13 +79,13 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor {
|
||||
* If no recoverer is set then an exhausted retry will result in an
|
||||
* {@link ExhaustedRetryException}.
|
||||
*
|
||||
* @param recoverer the {@link ItemRecoverer} to set
|
||||
* @param recoverer the {@link MethodInvocationRecoverer} to set
|
||||
*/
|
||||
public void setRecoverer(ItemRecoverer<? extends Object,Object[]> recoverer) {
|
||||
public void setRecoverer(MethodInvocationRecoverer<? extends Object> recoverer) {
|
||||
this.recoverer = recoverer;
|
||||
}
|
||||
|
||||
public void setKeyGenerator(ItemKeyGenerator keyGenerator) {
|
||||
public void setKeyGenerator(MethodArgumentsKeyGenerator keyGenerator) {
|
||||
this.keyGenerator = keyGenerator;
|
||||
}
|
||||
|
||||
@@ -103,29 +100,29 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Public setter for the {@link NewItemIdentifier}. Only set this if the
|
||||
* Public setter for the {@link NewMethodArgumentsIdentifier}. Only set this if the
|
||||
* arguments to the intercepted method can be inspected to find out if they
|
||||
* have never been processed before.
|
||||
* @param newItemIdentifier the {@link NewItemIdentifier} to set
|
||||
* @param newMethodArgumentsIdentifier the {@link NewMethodArgumentsIdentifier} to set
|
||||
*/
|
||||
public void setNewItemIdentifier(NewItemIdentifier newItemIdentifier) {
|
||||
this.newItemIdentifier = newItemIdentifier;
|
||||
public void setNewItemIdentifier(NewMethodArgumentsIdentifier newMethodArgumentsIdentifier) {
|
||||
this.newMethodArgumentsIdentifier = newMethodArgumentsIdentifier;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap the method invocation in a stateful retry with the policy and other
|
||||
* helpers provided. If there is a failure the exception will generally be
|
||||
* re-thrown. The only time it is not re-thrown is when retry is exhausted
|
||||
* and the recovery path is taken (though the {@link ItemRecoverer} provided
|
||||
* and the recovery path is taken (though the {@link MethodInvocationRecoverer} provided
|
||||
* if there is one). In that case the value returned from the method
|
||||
* invocation will be the value returned by the recoverer (so the return
|
||||
* type for that should be the same as the intercepted method).
|
||||
*
|
||||
* @see org.aopalliance.intercept.MethodInterceptor#invoke(org.aopalliance.intercept.MethodInvocation)
|
||||
* @see ItemRecoverer#recover(Object, Throwable)
|
||||
* @see MethodInvocationRecoverer#recover(Object[], Throwable)
|
||||
*
|
||||
* @throws ExhaustedRetryException if the retry is exhausted and no
|
||||
* {@link ItemRecoverer} is provided.
|
||||
* {@link MethodInvocationRecoverer} is provided.
|
||||
*/
|
||||
public Object invoke(final MethodInvocation invocation) throws Throwable {
|
||||
|
||||
@@ -141,7 +138,7 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor {
|
||||
}
|
||||
final Object item = arg;
|
||||
|
||||
RetryState retryState = new RetryState(keyGenerator != null ? keyGenerator.getKey(item) : item, newItemIdentifier != null ? newItemIdentifier.isNew(item) : false );
|
||||
RetryState retryState = new RetryState(keyGenerator != null ? keyGenerator.getKey(args) : item, newMethodArgumentsIdentifier != null ? newMethodArgumentsIdentifier.isNew(args) : false );
|
||||
|
||||
Object result = retryTemplate.execute(new MethodInvocationRetryCallback(invocation), new ItemRecovererCallback(args, recoverer), retryState);
|
||||
|
||||
@@ -192,12 +189,12 @@ public class StatefulRetryOperationsInterceptor implements MethodInterceptor {
|
||||
|
||||
private final Object[] args;
|
||||
|
||||
private final ItemRecoverer<? extends Object,Object[]> recoverer;
|
||||
private final MethodInvocationRecoverer<? extends Object> recoverer;
|
||||
|
||||
/**
|
||||
* @param args the item that failed.
|
||||
*/
|
||||
private ItemRecovererCallback(Object[] args, ItemRecoverer<? extends Object,Object[]> recoverer) {
|
||||
private ItemRecovererCallback(Object[] args, MethodInvocationRecoverer<? extends Object> recoverer) {
|
||||
this.args = args;
|
||||
this.recoverer = recoverer;
|
||||
}
|
||||
|
||||
@@ -16,19 +16,21 @@
|
||||
|
||||
package org.springframework.batch.item;
|
||||
|
||||
import org.springframework.batch.retry.interceptor.MethodInvocationRecoverer;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
public class ItemRecoveryHandlerTests extends TestCase {
|
||||
|
||||
ItemRecoverer<String, String> recoverer = new ItemRecoverer<String,String>() {
|
||||
public String recover(String data, Throwable cause) {
|
||||
MethodInvocationRecoverer<String> recoverer = new MethodInvocationRecoverer<String>() {
|
||||
public String recover(Object[] data, Throwable cause) {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
public void testRecover() throws Exception {
|
||||
try {
|
||||
recoverer.recover("foo", null);
|
||||
recoverer.recover(new Object[]{"foo"}, null);
|
||||
} catch (Exception e) {
|
||||
fail("Unexpected Exception");
|
||||
}
|
||||
|
||||
@@ -23,7 +23,6 @@ import static org.junit.Assert.fail;
|
||||
import java.util.Date;
|
||||
|
||||
import javax.jms.Message;
|
||||
import javax.jms.Queue;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Test;
|
||||
@@ -106,84 +105,4 @@ public class JmsItemReaderTests {
|
||||
EasyMock.verify(jmsTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRecoverWithNoDestination() throws Exception {
|
||||
JmsOperations jmsTemplate = EasyMock.createMock(JmsOperations.class);
|
||||
EasyMock.replay(jmsTemplate);
|
||||
|
||||
itemReader.setJmsTemplate(jmsTemplate);
|
||||
itemReader.setItemType(String.class);
|
||||
itemReader.recover("foo", null);
|
||||
|
||||
EasyMock.verify(jmsTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorQueueWithDestinationName() throws Exception {
|
||||
JmsOperations jmsTemplate = EasyMock.createMock(JmsOperations.class);
|
||||
jmsTemplate.convertAndSend("queue", "foo");
|
||||
EasyMock.expectLastCall();
|
||||
EasyMock.replay(jmsTemplate);
|
||||
|
||||
itemReader.setJmsTemplate(jmsTemplate);
|
||||
itemReader.setItemType(String.class);
|
||||
itemReader.setErrorDestinationName("queue");
|
||||
itemReader.recover("foo", null);
|
||||
|
||||
EasyMock.verify(jmsTemplate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testErrorQueueWithDestination() throws Exception {
|
||||
JmsOperations jmsTemplate = EasyMock.createMock(JmsOperations.class);
|
||||
Queue queue = EasyMock.createMock(Queue.class);
|
||||
jmsTemplate.convertAndSend(queue, "foo");
|
||||
EasyMock.expectLastCall();
|
||||
EasyMock.replay(jmsTemplate, queue);
|
||||
|
||||
itemReader.setJmsTemplate(jmsTemplate);
|
||||
itemReader.setItemType(String.class);
|
||||
itemReader.setErrorDestination(queue);
|
||||
itemReader.recover("foo", null);
|
||||
|
||||
EasyMock.verify(jmsTemplate, queue);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetKeyFromMessage() throws Exception {
|
||||
Message message = EasyMock.createMock(Message.class);
|
||||
EasyMock.expect(message.getJMSMessageID()).andReturn("foo");
|
||||
EasyMock.replay(message);
|
||||
|
||||
JmsItemReader<Message> itemReader = new JmsItemReader<Message>();
|
||||
itemReader.setItemType(Message.class);
|
||||
assertEquals("foo", itemReader.getKey(message));
|
||||
|
||||
EasyMock.verify(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetKeyFromNonMessage() throws Exception {
|
||||
itemReader.setItemType(String.class);
|
||||
assertEquals("foo", itemReader.getKey("foo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsNewForMessage() throws Exception {
|
||||
Message message = EasyMock.createMock(Message.class);
|
||||
EasyMock.expect(message.getJMSRedelivered()).andReturn(true);
|
||||
EasyMock.replay(message);
|
||||
|
||||
JmsItemReader<Message> itemReader = new JmsItemReader<Message>();
|
||||
itemReader.setItemType(Message.class);
|
||||
assertEquals(false, itemReader.isNew(message));
|
||||
|
||||
EasyMock.verify(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsNewForNonMessage() throws Exception {
|
||||
itemReader.setItemType(String.class);
|
||||
assertEquals(false, itemReader.isNew("foo"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* 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.item.jms;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import javax.jms.Message;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JmsMethodArgumentsKeyGeneratorTests {
|
||||
|
||||
private JmsMethodArgumentsKeyGenerator methodArgumentsKeyGenerator = new JmsMethodArgumentsKeyGenerator();
|
||||
|
||||
@Test
|
||||
public void testGetKeyFromMessage() throws Exception {
|
||||
Message message = EasyMock.createMock(Message.class);
|
||||
EasyMock.expect(message.getJMSMessageID()).andReturn("foo");
|
||||
EasyMock.replay(message);
|
||||
|
||||
JmsItemReader<Message> itemReader = new JmsItemReader<Message>();
|
||||
itemReader.setItemType(Message.class);
|
||||
assertEquals("foo", methodArgumentsKeyGenerator.getKey(new Object[]{message}));
|
||||
|
||||
EasyMock.verify(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetKeyFromNonMessage() throws Exception {
|
||||
assertEquals("foo", methodArgumentsKeyGenerator.getKey(new Object[]{"foo"}));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.item.jms;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Test;
|
||||
import org.springframework.jms.core.JmsOperations;
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JmsMethodInvocationRecovererTests {
|
||||
|
||||
private JmsMethodInvocationRecoverer<String> itemReader = new JmsMethodInvocationRecoverer<String>();
|
||||
|
||||
@Test
|
||||
public void testRecoverWithNoDestination() throws Exception {
|
||||
JmsOperations jmsTemplate = EasyMock.createMock(JmsOperations.class);
|
||||
jmsTemplate.convertAndSend("foo");
|
||||
EasyMock.replay(jmsTemplate);
|
||||
|
||||
itemReader.setJmsTemplate(jmsTemplate);
|
||||
itemReader.recover(new Object[] { "foo" }, null);
|
||||
|
||||
EasyMock.verify(jmsTemplate);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.item.jms;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import javax.jms.Message;
|
||||
|
||||
import org.easymock.EasyMock;
|
||||
import org.junit.Test;
|
||||
|
||||
|
||||
/**
|
||||
* @author Dave Syer
|
||||
*
|
||||
*/
|
||||
public class JmsNewMethodArgumentsIdentifierTests {
|
||||
|
||||
private JmsNewMethodArgumentsIdentifier<String> newMethodArgumentsIdentifier = new JmsNewMethodArgumentsIdentifier<String>();
|
||||
|
||||
@Test
|
||||
public void testIsNewForMessage() throws Exception {
|
||||
Message message = EasyMock.createMock(Message.class);
|
||||
EasyMock.expect(message.getJMSRedelivered()).andReturn(true);
|
||||
EasyMock.replay(message);
|
||||
assertEquals(false, newMethodArgumentsIdentifier.isNew(new Object[]{message}));
|
||||
|
||||
EasyMock.verify(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsNewForNonMessage() throws Exception {
|
||||
assertEquals(false, newMethodArgumentsIdentifier.isNew(new Object[]{"foo"}));
|
||||
}
|
||||
}
|
||||
@@ -27,7 +27,6 @@ import org.aopalliance.intercept.MethodInvocation;
|
||||
import org.springframework.aop.framework.Advised;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.target.SingletonTargetSource;
|
||||
import org.springframework.batch.item.ItemRecoverer;
|
||||
import org.springframework.batch.retry.ExhaustedRetryException;
|
||||
import org.springframework.batch.retry.policy.AlwaysRetryPolicy;
|
||||
import org.springframework.batch.retry.policy.NeverRetryPolicy;
|
||||
@@ -170,7 +169,7 @@ public class StatefulRetryOperationsInterceptorTests extends TestCase {
|
||||
assertTrue("Wrong message: " + message, message.startsWith("Not enough calls"));
|
||||
}
|
||||
assertEquals(1, count);
|
||||
interceptor.setRecoverer(new ItemRecoverer<Object, Object[]>() {
|
||||
interceptor.setRecoverer(new MethodInvocationRecoverer<Object>() {
|
||||
public Object recover(Object[] data, Throwable cause) {
|
||||
count++;
|
||||
return null;
|
||||
@@ -192,7 +191,7 @@ public class StatefulRetryOperationsInterceptorTests extends TestCase {
|
||||
assertTrue("Wrong message: " + message, message.startsWith("Not enough calls"));
|
||||
}
|
||||
assertEquals(1, count);
|
||||
interceptor.setRecoverer(new ItemRecoverer<Collection<String>, Object[]>() {
|
||||
interceptor.setRecoverer(new MethodInvocationRecoverer<Collection<String>>() {
|
||||
public Collection<String> recover(Object[] data, Throwable cause) {
|
||||
count++;
|
||||
return Collections.singleton((String)data[0]);
|
||||
|
||||
@@ -15,10 +15,10 @@ import org.junit.Test;
|
||||
import org.springframework.aop.framework.ProxyFactory;
|
||||
import org.springframework.aop.support.DefaultPointcutAdvisor;
|
||||
import org.springframework.aop.support.NameMatchMethodPointcut;
|
||||
import org.springframework.batch.item.ItemKeyGenerator;
|
||||
import org.springframework.batch.item.ItemReader;
|
||||
import org.springframework.batch.item.ItemRecoverer;
|
||||
import org.springframework.batch.item.support.ListItemReader;
|
||||
import org.springframework.batch.retry.interceptor.MethodArgumentsKeyGenerator;
|
||||
import org.springframework.batch.retry.interceptor.MethodInvocationRecoverer;
|
||||
import org.springframework.batch.retry.interceptor.StatefulRetryOperationsInterceptor;
|
||||
import org.springframework.batch.support.transaction.ResourcelessTransactionManager;
|
||||
import org.springframework.batch.support.transaction.TransactionAwareProxyFactory;
|
||||
@@ -51,16 +51,13 @@ public class PollableSourceRetryTests {
|
||||
processed.add(str);
|
||||
}
|
||||
|
||||
ItemKeyGenerator itemKeyGenerator = new ItemKeyGenerator() {
|
||||
MethodArgumentsKeyGenerator methodArgumentsKeyGenerator = new MethodArgumentsKeyGenerator() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Object getKey(Object item) {
|
||||
public Object getKey(Object[] item) {
|
||||
if (item == null) {
|
||||
return "NULL";
|
||||
}
|
||||
if (item.getClass().isArray()) {
|
||||
item = ((Object[]) item)[0];
|
||||
}
|
||||
return ((Message<Object>) item).getPayload();
|
||||
return ((Message<Object>) item[0]).getPayload();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -266,7 +263,7 @@ public class PollableSourceRetryTests {
|
||||
MessageTarget target = getChannel(handler);
|
||||
// this was the old dispatch advice chain
|
||||
target = (MessageTarget) getProxy(target, MessageTarget.class,
|
||||
new Advice[] { getRetryOperationsInterceptor(itemKeyGenerator) }, "send");
|
||||
new Advice[] { getRetryOperationsInterceptor(methodArgumentsKeyGenerator) }, "send");
|
||||
PollingDispatcher trigger = getPollingDispatcher(source, target, transactionManager, 1);
|
||||
TaskScheduler scheduler = getSchedulerWithErrorHandler(trigger);
|
||||
|
||||
@@ -309,7 +306,7 @@ public class PollableSourceRetryTests {
|
||||
MessageTarget target = getChannel(handler);
|
||||
// this was the old dispatch advice chain
|
||||
target = (MessageTarget) getProxy(target, MessageTarget.class,
|
||||
new Advice[] { getRetryOperationsInterceptor(itemKeyGenerator) }, "send");
|
||||
new Advice[] { getRetryOperationsInterceptor(methodArgumentsKeyGenerator) }, "send");
|
||||
PollingDispatcher trigger = getPollingDispatcher(source, target, transactionManager, 3);
|
||||
TaskScheduler scheduler = getSchedulerWithErrorHandler(trigger);
|
||||
|
||||
@@ -398,12 +395,12 @@ public class PollableSourceRetryTests {
|
||||
}
|
||||
|
||||
/**
|
||||
* @param itemKeyGenerator
|
||||
* @param methodArgumentsKeyGenerator
|
||||
* @return
|
||||
*/
|
||||
private StatefulRetryOperationsInterceptor getRetryOperationsInterceptor(ItemKeyGenerator itemKeyGenerator) {
|
||||
private StatefulRetryOperationsInterceptor getRetryOperationsInterceptor(MethodArgumentsKeyGenerator methodArgumentsKeyGenerator) {
|
||||
StatefulRetryOperationsInterceptor advice = new StatefulRetryOperationsInterceptor();
|
||||
advice.setRecoverer(new ItemRecoverer<Boolean, Object[]>() {
|
||||
advice.setRecoverer(new MethodInvocationRecoverer<Boolean>() {
|
||||
@SuppressWarnings("unchecked")
|
||||
public Boolean recover(Object[] data, Throwable cause) {
|
||||
if (data == null) {
|
||||
@@ -415,7 +412,7 @@ public class PollableSourceRetryTests {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
advice.setKeyGenerator(itemKeyGenerator);
|
||||
advice.setKeyGenerator(methodArgumentsKeyGenerator);
|
||||
return advice;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user