diff --git a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java index 98f02328bd..fc5b64d2c5 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/config/xml/PollerParser.java @@ -33,6 +33,7 @@ import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.context.IntegrationContextUtils; import org.springframework.integration.endpoint.AbstractPollingEndpoint; +import org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor; import org.springframework.util.StringUtils; import org.springframework.util.xml.DomUtils; import org.w3c.dom.Element; @@ -91,15 +92,13 @@ public class PollerParser extends AbstractBeanDefinitionParser { configureTrigger(element, metadataBuilder, parserContext); IntegrationNamespaceUtils.setValueIfAttributeDefined(metadataBuilder, element, "max-messages-per-poll"); IntegrationNamespaceUtils.setValueIfAttributeDefined(metadataBuilder, element, "receive-timeout"); - Element adviceChainElement = DomUtils.getChildElementByTagName(element, "advice-chain"); - if (adviceChainElement != null) { - configureAdviceChain(adviceChainElement, metadataBuilder, parserContext); - } - + Element txElement = DomUtils.getChildElementByTagName(element, "transactional"); - if (txElement != null) { - configureTransactionAttributes(txElement, metadataBuilder, parserContext); - } + + Element adviceChainElement = DomUtils.getChildElementByTagName(element, "advice-chain"); + + configureAdviceChain(adviceChainElement, txElement, metadataBuilder, parserContext); + IntegrationNamespaceUtils.setReferenceIfAttributeDefined(metadataBuilder, element, "task-executor"); return metadataBuilder.getBeanDefinition(); } @@ -203,7 +202,7 @@ public class PollerParser extends AbstractBeanDefinitionParser { * and other "transactionDefinition" properties. This advisor will be applied on Polling Task proxy * (see {@link AbstractPollingEndpoint}). */ - private void configureTransactionAttributes(Element txElement, BeanDefinitionBuilder targetBuilder, ParserContext parserContext) { + private BeanDefinition configureTransactionAttributes(Element txElement, BeanDefinitionBuilder targetBuilder, ParserContext parserContext) { String TX_PKG_PREFIX = "org.springframework.transaction.interceptor"; BeanDefinitionBuilder txDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(TX_PKG_PREFIX + ".DefaultTransactionAttribute"); @@ -219,40 +218,43 @@ public class PollerParser extends AbstractBeanDefinitionParser { BeanDefinitionBuilder.genericBeanDefinition(TX_PKG_PREFIX + ".TransactionInterceptor"); txInterceptorBuilder.addPropertyReference("transactionManager", txElement.getAttribute("transaction-manager")); txInterceptorBuilder.addPropertyValue("transactionAttributeSource", attributeSourceBuilder.getBeanDefinition()); - BeanDefinitionBuilder txAdvisorBuilder = BeanDefinitionBuilder.genericBeanDefinition(TX_PKG_PREFIX + ".TransactionAttributeSourceAdvisor"); - txAdvisorBuilder.addConstructorArgValue(txInterceptorBuilder.getBeanDefinition()); - - targetBuilder.addPropertyValue("transactionAdvisor", txAdvisorBuilder.getBeanDefinition()); + + return txInterceptorBuilder.getBeanDefinition(); } /** * Parses the 'advice-chain' element's sub-elements. */ - @SuppressWarnings("unchecked") - private void configureAdviceChain(Element adviceChainElement, BeanDefinitionBuilder targetBuilder, ParserContext parserContext) { + @SuppressWarnings({ "unchecked", "rawtypes" }) + private void configureAdviceChain(Element adviceChainElement, Element txElement, BeanDefinitionBuilder targetBuilder, ParserContext parserContext) { ManagedList adviceChain = new ManagedList(); - NodeList childNodes = adviceChainElement.getChildNodes(); - for (int i = 0; i < childNodes.getLength(); i++) { - Node child = childNodes.item(i); - if (child.getNodeType() == Node.ELEMENT_NODE) { - Element childElement = (Element) child; - String localName = child.getLocalName(); - if ("bean".equals(localName)) { - BeanDefinitionHolder holder = parserContext.getDelegate().parseBeanDefinitionElement( - childElement, targetBuilder.getBeanDefinition()); - parserContext.registerBeanComponent(new BeanComponentDefinition(holder)); - adviceChain.add(new RuntimeBeanReference(holder.getBeanName())); - } - else if ("ref".equals(localName)) { - String ref = childElement.getAttribute("bean"); - adviceChain.add(new RuntimeBeanReference(ref)); - } - else { - BeanDefinition customBeanDefinition = parserContext.getDelegate().parseCustomElement( - childElement, targetBuilder.getBeanDefinition()); - if (customBeanDefinition == null) { - parserContext.getReaderContext().error( - "failed to parse custom element '" + localName + "'", childElement); + if (txElement != null){ + adviceChain.add(this.configureTransactionAttributes(txElement, targetBuilder, parserContext)); + } + if (adviceChainElement != null){ + NodeList childNodes = adviceChainElement.getChildNodes(); + for (int i = 0; i < childNodes.getLength(); i++) { + Node child = childNodes.item(i); + if (child.getNodeType() == Node.ELEMENT_NODE) { + Element childElement = (Element) child; + String localName = child.getLocalName(); + if ("bean".equals(localName)) { + BeanDefinitionHolder holder = parserContext.getDelegate().parseBeanDefinitionElement( + childElement, targetBuilder.getBeanDefinition()); + parserContext.registerBeanComponent(new BeanComponentDefinition(holder)); + adviceChain.add(new RuntimeBeanReference(holder.getBeanName())); + } + else if ("ref".equals(localName)) { + String ref = childElement.getAttribute("bean"); + adviceChain.add(new RuntimeBeanReference(ref)); + } + else { + BeanDefinition customBeanDefinition = parserContext.getDelegate().parseCustomElement( + childElement, targetBuilder.getBeanDefinition()); + if (customBeanDefinition == null) { + parserContext.getReaderContext().error( + "failed to parse custom element '" + localName + "'", childElement); + } } } } diff --git a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractPollingEndpoint.java b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractPollingEndpoint.java index 6212d65009..27a914a1b6 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractPollingEndpoint.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/endpoint/AbstractPollingEndpoint.java @@ -20,7 +20,6 @@ import java.util.concurrent.Callable; import java.util.concurrent.ScheduledFuture; import org.aopalliance.aop.Advice; -import org.springframework.aop.Advisor; import org.springframework.aop.framework.ProxyFactory; import org.springframework.beans.factory.BeanClassLoaderAware; import org.springframework.core.task.SyncTaskExecutor; @@ -107,17 +106,10 @@ public abstract class AbstractPollingEndpoint extends AbstractEndpoint implement } }; - Advisor transactionAdvice = this.pollerMetadata.getTransactionAdvisor(); List adviceChain = this.pollerMetadata.getAdviceChain(); - if (transactionAdvice != null || !CollectionUtils.isEmpty(adviceChain)){ + if (!CollectionUtils.isEmpty(adviceChain)){ ProxyFactory proxyFactory = new ProxyFactory(pollingTask); - - // Add Transaction advice first - if (transactionAdvice != null){ - proxyFactory.addAdvisor(transactionAdvice); - } - - // . . .then add the rest of the advises + if (!CollectionUtils.isEmpty(adviceChain)){ for (Advice advice : adviceChain) { proxyFactory.addAdvice(advice); diff --git a/spring-integration-core/src/main/java/org/springframework/integration/scheduling/PollerMetadata.java b/spring-integration-core/src/main/java/org/springframework/integration/scheduling/PollerMetadata.java index 98576f46a1..45f93ebf78 100644 --- a/spring-integration-core/src/main/java/org/springframework/integration/scheduling/PollerMetadata.java +++ b/spring-integration-core/src/main/java/org/springframework/integration/scheduling/PollerMetadata.java @@ -19,7 +19,6 @@ package org.springframework.integration.scheduling; import java.util.List; import org.aopalliance.aop.Advice; -import org.springframework.aop.Advisor; import org.springframework.core.task.TaskExecutor; import org.springframework.scheduling.Trigger; import org.springframework.scheduling.support.PeriodicTrigger; @@ -41,16 +40,6 @@ public class PollerMetadata { private List adviceChain; private volatile TaskExecutor taskExecutor; - - private volatile Advisor transactionAdvice; - - public Advisor getTransactionAdvisor() { - return transactionAdvice; - } - - public void setTransactionAdvisor(Advisor transactionAdvice) { - this.transactionAdvice = transactionAdvice; - } public void setTrigger(Trigger trigger) { this.trigger = trigger; diff --git a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd index b814cdc8b5..874ca978d4 100644 --- a/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd +++ b/spring-integration-core/src/main/resources/org/springframework/integration/config/xml/spring-integration-2.0.xsd @@ -1057,29 +1057,31 @@ - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/config/SourcePollingChannelAdapterFactoryBeanTests.java b/spring-integration-core/src/test/java/org/springframework/integration/config/SourcePollingChannelAdapterFactoryBeanTests.java index 88d879477b..b140ef152f 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/config/SourcePollingChannelAdapterFactoryBeanTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/config/SourcePollingChannelAdapterFactoryBeanTests.java @@ -33,7 +33,6 @@ import org.junit.Test; import org.mockito.Mockito; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; -import org.springframework.aop.Advisor; import org.springframework.integration.Message; import org.springframework.integration.channel.QueueChannel; import org.springframework.integration.core.MessageSource; @@ -102,12 +101,10 @@ public class SourcePollingChannelAdapterFactoryBeanTests { pollerMetadata.setMaxMessagesPerPoll(1); final AtomicInteger count = new AtomicInteger(); final MethodInterceptor txAdvice = mock(MethodInterceptor.class); - pollerMetadata.setTransactionAdvisor(new Advisor() { - public boolean isPerInstance() { - return false; - } - public Advice getAdvice() { - return txAdvice; + adviceChain.add(new MethodInterceptor() { + public Object invoke(MethodInvocation invocation) throws Throwable { + count.incrementAndGet(); + return invocation.proceed(); } }); when(txAdvice.invoke(Mockito.any(MethodInvocation.class))).thenAnswer(new Answer() { diff --git a/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/PollingTransactionTests.java b/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/PollingTransactionTests.java index 9215d12399..58ead530bf 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/PollingTransactionTests.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/PollingTransactionTests.java @@ -30,6 +30,7 @@ import org.aopalliance.intercept.MethodInvocation; import org.junit.Test; import org.springframework.aop.Advisor; import org.springframework.aop.framework.Advised; +import org.springframework.aop.support.DefaultPointcutAdvisor; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; @@ -41,10 +42,11 @@ import org.springframework.integration.test.util.TestUtils; import org.springframework.integration.util.TestTransactionManager; import org.springframework.transaction.IllegalTransactionStateException; import org.springframework.transaction.annotation.Propagation; -import org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor; +import org.springframework.transaction.interceptor.TransactionInterceptor; /** * @author Mark Fisher + * @author Oleg Zhurakousky */ public class PollingTransactionTests { @@ -75,14 +77,14 @@ public class PollingTransactionTests { PollerMetadata pollerMetedata = TestUtils.getPropertyValue(advicedPoller, "pollerMetadata",PollerMetadata.class); List adviceChain = TestUtils.getPropertyValue(pollerMetedata, "adviceChain",List.class); - assertEquals(2, adviceChain.size()); + assertEquals(3, adviceChain.size()); Runnable poller = TestUtils.getPropertyValue(advicedPoller, "poller", Runnable.class); Callable pollingTask = TestUtils.getPropertyValue(poller, "pollingTask", Callable.class); assertTrue("Poller is not Advised", pollingTask instanceof Advised); Advisor[] advisors = ((Advised)pollingTask).getAdvisors(); assertEquals(3, advisors.length); - assertTrue("First advisor is not TX", advisors[0] instanceof TransactionAttributeSourceAdvisor); + assertTrue("First advisor is not TX", ((DefaultPointcutAdvisor)advisors[0]).getAdvice() instanceof TransactionInterceptor); TestTransactionManager txManager = (TestTransactionManager) context.getBean("txManager"); MessageChannel input = (MessageChannel) context.getBean("goodInputWithAdvice"); PollableChannel output = (PollableChannel) context.getBean("output"); @@ -92,7 +94,6 @@ public class PollingTransactionTests { txManager.waitForCompletion(10000); Message message = output.receive(0); assertNotNull(message); - assertEquals(1, txManager.getCommitCount()); assertEquals(0, txManager.getRollbackCount()); context.stop(); } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfig-context.xml b/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfig-context.xml index 5a5ffb596c..dd695d8da2 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfig-context.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfig-context.xml @@ -15,17 +15,13 @@ - - - + class="org.springframework.integration.dispatcher.TransactionalPollerWithMixedAopConfigTests.SampleService"/> - + diff --git a/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfig.java b/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfigTests.java similarity index 82% rename from spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfig.java rename to spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfigTests.java index e38e4b85b9..aeea2a9387 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfig.java +++ b/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/TransactionalPollerWithMixedAopConfigTests.java @@ -19,7 +19,7 @@ import org.springframework.context.support.ClassPathXmlApplicationContext; * in the BeanFactory while having resent resulted in * TX Advisor being applied on all beans in AC */ -public class TransactionalPollerWithMixedAopConfig { +public class TransactionalPollerWithMixedAopConfigTests { @Test public void validateTransactionalProxyIsolationToThePollerOnly(){ @@ -38,9 +38,9 @@ public class TransactionalPollerWithMixedAopConfig { public Foo(String value){} } - public static class SampleAdvice implements MethodInterceptor{ - public Object invoke(MethodInvocation invocation) throws Throwable { - return invocation.proceed(); - } - } +// public static class SampleAdvice implements MethodInterceptor{ +// public Object invoke(MethodInvocation invocation) throws Throwable { +// return invocation.proceed(); +// } +// } } diff --git a/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/transactionTests.xml b/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/transactionTests.xml index cf3aa6bb20..ad18b157a3 100644 --- a/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/transactionTests.xml +++ b/spring-integration-core/src/test/java/org/springframework/integration/dispatcher/transactionTests.xml @@ -39,14 +39,25 @@ - + + + + + + + + + + + +