INT-2649: DelayHandler: tx & adviceChain support

* 'delayer-type' XSD: add `<transactional>` & `<advice-chain>`
* move `PollerParser#configureAdviceChain` into `IntegrationNamespaceUtils`
* DelayerParser: parsing `<transactional>` & `<advice-chain>` via `IntegrationNamespaceUtils#configureAdviceChain`
* DelayHandler: add `adviceChain` property
* DelayHandler: introduce `ReleaseMessageHandler` to apply `adviceChain` capabilities around `DelayHandler#doReleaseMessage`
* DelayerParserTests: tests for introduced sub-elements
* DelayerHandlerRescheduleIntegrationTests: test for transaction boundaries with intentional rollback in the message-flow after message release

JIRA: https://jira.springsource.org/browse/INT-2649

Resolve conflicts; polishing.
This commit is contained in:
Artem Bilan
2012-07-10 21:38:47 +03:00
committed by Gary Russell
parent fc1417ed39
commit d4e135b13d
10 changed files with 265 additions and 21 deletions

View File

@@ -2,12 +2,17 @@
<beans:beans xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://www.springframework.org/schema/integration"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/integration http://www.springframework.org/schema/integration/spring-integration.xsd">
<beans:bean id="messageStore"
class="org.springframework.integration.jdbc.DelayerHandlerRescheduleIntegrationTests$TestJdbcMessageStore"/>
<beans:bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
p:dataSource="#{T (org.springframework.integration.jdbc.DelayerHandlerRescheduleIntegrationTests).dataSource}"/>
<channel id="output">
<queue/>
</channel>
@@ -18,4 +23,19 @@
default-delay="200"
message-store="messageStore"/>
<channel id="transactionalDelayerOutput"/>
<delayer id="transactionalDelayer"
input-channel="transactionalDelayerInput"
output-channel="transactionalDelayerOutput"
default-delay="10"
message-store="messageStore">
<transactional/>
</delayer>
<service-activator input-channel="transactionalDelayerOutput" ref="exceptionHandler"/>
<beans:bean id="exceptionHandler"
class="org.springframework.integration.jdbc.DelayerHandlerRescheduleIntegrationTests$ExceptionMessageHandler"/>
</beans:beans>

View File

@@ -19,6 +19,9 @@ import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
@@ -26,6 +29,8 @@ import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.integration.Message;
import org.springframework.integration.MessageChannel;
import org.springframework.integration.MessagingException;
import org.springframework.integration.core.MessageHandler;
import org.springframework.integration.core.PollableChannel;
import org.springframework.integration.store.MessageGroup;
import org.springframework.integration.store.MessageGroupStore;
@@ -35,17 +40,19 @@ import org.springframework.integration.util.UUIDConverter;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabase;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseBuilder;
import org.springframework.jdbc.datasource.embedded.EmbeddedDatabaseType;
import org.springframework.transaction.support.TransactionSynchronization;
import org.springframework.transaction.support.TransactionSynchronizationAdapter;
import org.springframework.transaction.support.TransactionSynchronizationManager;
/**
* @author Artem Bilan
* @author Gary Russell
*/
//INT-1132
public class DelayerHandlerRescheduleIntegrationTests {
public static final String DELAYER_ID = "delayerWithJdbcMS";
private static EmbeddedDatabase dataSource;
public static EmbeddedDatabase dataSource;
@BeforeClass
public static void init() {
@@ -60,7 +67,7 @@ public class DelayerHandlerRescheduleIntegrationTests {
dataSource.shutdown();
}
@Test
@Test //INT-1132
public void testDelayerHandlerRescheduleWithJdbcMessageStore() throws Exception {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("DelayerHandlerRescheduleIntegrationTests-context.xml", this.getClass());
MessageChannel input = context.getBean("input", MessageChannel.class);
@@ -115,6 +122,31 @@ public class DelayerHandlerRescheduleIntegrationTests {
}
@Test //INT-2649
public void testRollbackOnDelayerHandlerReleaseTask() throws Exception {
AbstractApplicationContext context = new ClassPathXmlApplicationContext("DelayerHandlerRescheduleIntegrationTests-context.xml", this.getClass());
MessageChannel input = context.getBean("transactionalDelayerInput", MessageChannel.class);
MessageGroupStore messageStore = context.getBean("messageStore", MessageGroupStore.class);
String delayerMessageGroupId = UUIDConverter.getUUID("transactionalDelayer.messageGroupId").toString();
assertEquals(0, messageStore.messageGroupSize(delayerMessageGroupId));
input.send(MessageBuilder.withPayload("test").build());
Thread.sleep(30);
assertEquals(1, messageStore.messageGroupSize(delayerMessageGroupId));
//To check that 'rescheduling' works in the transaction boundaries too
context.destroy();
context.refresh();
assertTrue(RollbackTxSync.latch.await(2, TimeUnit.SECONDS));
//On transaction rollback the delayed Message should remain in the persistent MessageStore
assertEquals(1, messageStore.messageGroupSize(delayerMessageGroupId));
}
private static class TestJdbcMessageStore extends JdbcMessageStore {
private TestJdbcMessageStore() {
@@ -124,4 +156,26 @@ public class DelayerHandlerRescheduleIntegrationTests {
}
private static class ExceptionMessageHandler implements MessageHandler {
public void handleMessage(Message<?> message) throws MessagingException {
TransactionSynchronizationManager.registerSynchronization(new RollbackTxSync());
throw new RuntimeException("intentional");
}
}
private static class RollbackTxSync extends TransactionSynchronizationAdapter {
public static CountDownLatch latch = new CountDownLatch(2);
@Override
public void afterCompletion(int status) {
if (TransactionSynchronization.STATUS_ROLLED_BACK == status) {
latch.countDown();
}
}
}
}