INT-2815 Support Tx Synch In Pollable Consumers
Pull transaction synchronization code up from SPCA to AbstractPollingEndpoint, providing support for transaction synchronization in PollingConsumer. Also, ensure headers are copied to any message generated by the ExpressionEvaluatingTransactionSynchronizationProcessor.
This commit is contained in:
committed by
Gunnar Hillert
parent
5f2cc5a587
commit
bcce3277e5
@@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<beans xmlns="http://www.springframework.org/schema/beans"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:int="http://www.springframework.org/schema/integration"
|
||||
xsi:schemaLocation="http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd
|
||||
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
|
||||
|
||||
<int:channel id="queueChannel">
|
||||
<int:queue />
|
||||
</int:channel>
|
||||
|
||||
<int:service-activator input-channel="queueChannel" ref="service" method="handle">
|
||||
<int:poller fixed-delay="5000">
|
||||
<int:transactional synchronization-factory="txSyncFactory"/>
|
||||
</int:poller>
|
||||
</int:service-activator>
|
||||
|
||||
<bean id="service" class="org.springframework.integration.channel.TransactionSynchronizationQueueChannelTests$Service"/>
|
||||
|
||||
<int:transaction-synchronization-factory id="txSyncFactory">
|
||||
<int:after-commit channel="good" />
|
||||
<int:after-rollback expression="'retry:' + payload" channel="queueChannel" />
|
||||
</int:transaction-synchronization-factory>
|
||||
|
||||
<int:channel id="good">
|
||||
<int:queue />
|
||||
</int:channel>
|
||||
|
||||
<bean id="transactionManager" class="org.springframework.integration.transaction.PseudoTransactionManager" />
|
||||
|
||||
<int:channel id="queueChannel2">
|
||||
<int:queue />
|
||||
</int:channel>
|
||||
|
||||
<int:service-activator input-channel="queueChannel2" ref="service" method="handle">
|
||||
<int:poller fixed-delay="5000">
|
||||
<int:transactional synchronization-factory="txSyncFactory2"/>
|
||||
</int:poller>
|
||||
</int:service-activator>
|
||||
|
||||
<int:transaction-synchronization-factory id="txSyncFactory2">
|
||||
<int:after-commit expression="payload + ' processed ok from ' + #inputChannel.componentName"
|
||||
channel="good" />
|
||||
</int:transaction-synchronization-factory>
|
||||
|
||||
<int:channel id="good">
|
||||
<int:queue />
|
||||
</int:channel>
|
||||
|
||||
</beans>
|
||||
@@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright 2002-2012 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.integration.channel;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertNotNull;
|
||||
import static org.junit.Assert.assertNull;
|
||||
import static org.junit.Assert.assertSame;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.integration.core.PollableChannel;
|
||||
import org.springframework.integration.message.GenericMessage;
|
||||
import org.springframework.integration.support.MessageBuilder;
|
||||
import org.springframework.test.context.ContextConfiguration;
|
||||
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
|
||||
/**
|
||||
* @author Gary Russell
|
||||
* @since 2.2
|
||||
*
|
||||
*/
|
||||
@ContextConfiguration
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
public class TransactionSynchronizationQueueChannelTests {
|
||||
|
||||
@Autowired
|
||||
private PollableChannel queueChannel;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel good;
|
||||
|
||||
@Autowired
|
||||
private Service service;
|
||||
|
||||
@Autowired
|
||||
private PollableChannel queueChannel2;
|
||||
|
||||
@Test
|
||||
public void testCommit() throws Exception {
|
||||
service.latch = new CountDownLatch(1);
|
||||
GenericMessage<String> sentMessage = new GenericMessage<String>("hello");
|
||||
queueChannel.send(sentMessage);
|
||||
assertTrue(service.latch.await(10, TimeUnit.SECONDS));
|
||||
Message<?> message = good.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals("hello", message.getPayload());
|
||||
assertSame(message, sentMessage);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRollback() throws Exception {
|
||||
service.latch = new CountDownLatch(1);
|
||||
queueChannel.send(new GenericMessage<String>("fail"));
|
||||
assertTrue(service.latch.await(10, TimeUnit.SECONDS));
|
||||
Message<?> message = queueChannel.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals("retry:fail", message.getPayload());
|
||||
assertNull(good.receive(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIncludeChannelName() throws Exception {
|
||||
service.latch = new CountDownLatch(1);
|
||||
Message<String> sentMessage = MessageBuilder.withPayload("hello")
|
||||
.setHeader("foo", "bar").build();
|
||||
queueChannel2.send(sentMessage);
|
||||
assertTrue(service.latch.await(10, TimeUnit.SECONDS));
|
||||
Message<?> message = good.receive(1000);
|
||||
assertNotNull(message);
|
||||
assertEquals("hello processed ok from queueChannel2", message.getPayload());
|
||||
assertNotNull(message.getHeaders().get("foo"));
|
||||
assertEquals("bar", message.getHeaders().get("foo"));
|
||||
}
|
||||
|
||||
public static class Service {
|
||||
private CountDownLatch latch;
|
||||
|
||||
public void handle(String foo) {
|
||||
latch.countDown();
|
||||
if (foo.startsWith("fail")) {
|
||||
throw new RuntimeException("planned failure");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package org.springframework.integration.endpoint;
|
||||
|
||||
import org.springframework.integration.Message;
|
||||
import org.springframework.scheduling.support.PeriodicTrigger;
|
||||
|
||||
/**
|
||||
@@ -32,4 +33,19 @@ public class PollingEndpointStub extends AbstractPollingEndpoint {
|
||||
throw new RuntimeException("intentional test failure");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Message<?> doReceive() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object getResourceToBind() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getResourceKey() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user