diff --git a/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/MessageSourcePollerInterceptor.java b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/MessageSourcePollerInterceptor.java
new file mode 100644
index 000000000..b4f6eeff7
--- /dev/null
+++ b/spring-batch-integration/src/main/java/org/springframework/batch/integration/chunk/MessageSourcePollerInterceptor.java
@@ -0,0 +1,76 @@
+package org.springframework.batch.integration.chunk;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.integration.channel.ChannelInterceptor;
+import org.springframework.integration.channel.ThreadLocalChannel;
+import org.springframework.integration.channel.interceptor.ChannelInterceptorAdapter;
+import org.springframework.integration.core.Message;
+import org.springframework.integration.core.MessageChannel;
+import org.springframework.integration.message.MessageSource;
+import org.springframework.util.Assert;
+
+/**
+ * A {@link ChannelInterceptor} that turns a pollable channel into a "pass-thru channel": if a client calls
+ * receive() on the channel it will delegate to a {@link MessageSource} to pull the message directly from
+ * an external source. This is particularly useful in combination with a {@link ThreadLocalChannel}, in which case the
+ * receive() can join a transaction which was started by the caller.
+ *
+ * @author Dave Syer
+ *
+ */
+public class MessageSourcePollerInterceptor extends ChannelInterceptorAdapter implements InitializingBean {
+
+ private static Log logger = LogFactory.getLog(MessageSourcePollerInterceptor.class);
+
+ private MessageSource> source;
+
+ /**
+ * Convenient default constructor for configuration purposes.
+ */
+ public MessageSourcePollerInterceptor() {
+ }
+
+ /**
+ * @param source a message source to poll for messages on receive.
+ */
+ public MessageSourcePollerInterceptor(MessageSource> source) {
+ this.source = source;
+ }
+
+ /**
+ * Asserts that mandatory properties are set.
+ * @see InitializingBean#afterPropertiesSet()
+ */
+ public void afterPropertiesSet() throws Exception {
+ Assert.state(source != null, "A MessageSource must be provided");
+ }
+
+ /**
+ * @param source a message source to poll for messages on receive.
+ */
+ public void setMessageSource(MessageSource> source) {
+ this.source = source;
+ }
+
+ /**
+ * Receive from the {@link MessageSource} and send immediately to the input channel, so that the call that we are
+ * intercepting always a message to receive.
+ *
+ * @see ChannelInterceptorAdapter#preReceive(MessageChannel)
+ */
+ @Override
+ public boolean preReceive(MessageChannel channel) {
+ Message> message = source.receive();
+ if (message != null) {
+ channel.send(message);
+ if (logger.isDebugEnabled()) {
+ logger.debug("Sent " + message + " to channel " + channel.getName());
+ }
+ return true;
+ }
+ return true;
+ }
+
+}
diff --git a/spring-batch-integration/src/test/java/org/springframework/batch/integration/chunk/MessageSourcePollerInterceptorTests.java b/spring-batch-integration/src/test/java/org/springframework/batch/integration/chunk/MessageSourcePollerInterceptorTests.java
new file mode 100644
index 000000000..5d043f67c
--- /dev/null
+++ b/spring-batch-integration/src/test/java/org/springframework/batch/integration/chunk/MessageSourcePollerInterceptorTests.java
@@ -0,0 +1,55 @@
+package org.springframework.batch.integration.chunk;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+import org.springframework.integration.channel.ThreadLocalChannel;
+import org.springframework.integration.core.Message;
+import org.springframework.integration.message.GenericMessage;
+import org.springframework.integration.message.MessageSource;
+
+public class MessageSourcePollerInterceptorTests {
+
+ @Test(expected = IllegalStateException.class)
+ public void testMandatoryPropertiesUnset() throws Exception {
+ MessageSourcePollerInterceptor interceptor = new MessageSourcePollerInterceptor();
+ interceptor.afterPropertiesSet();
+ }
+
+ @Test
+ public void testMandatoryPropertiesSetViaConstructor() throws Exception {
+ MessageSourcePollerInterceptor interceptor = new MessageSourcePollerInterceptor(new TestMessageSource("foo"));
+ interceptor.afterPropertiesSet();
+ }
+
+ @Test
+ public void testMandatoryPropertiesSet() throws Exception {
+ MessageSourcePollerInterceptor interceptor = new MessageSourcePollerInterceptor();
+ interceptor.setMessageSource(new TestMessageSource("foo"));
+ interceptor.afterPropertiesSet();
+ }
+
+ @Test
+ public void testPreReceive() throws Exception {
+ MessageSourcePollerInterceptor interceptor = new MessageSourcePollerInterceptor(new TestMessageSource("foo"));
+ ThreadLocalChannel channel = new ThreadLocalChannel();
+ assertTrue(interceptor.preReceive(channel));
+ assertEquals("foo", channel.receive(10L).getPayload());
+ }
+
+ private static class TestMessageSource implements MessageSource {
+
+ private String payload;
+
+ public TestMessageSource(String payload) {
+ super();
+ this.payload = payload;
+ }
+
+ public Message receive() {
+ return new GenericMessage(payload);
+ }
+ }
+
+}
diff --git a/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJmsIntegrationTests-context.xml b/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJmsIntegrationTests-context.xml
index bcefb0278..a5df7b030 100644
--- a/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJmsIntegrationTests-context.xml
+++ b/spring-batch-integration/src/test/resources/org/springframework/batch/integration/chunk/RemoteChunkFaultTolerantStepJmsIntegrationTests-context.xml
@@ -2,8 +2,9 @@
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+