diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/ConsumerEndpointFactoryBean.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/ConsumerEndpointFactoryBean.java index fd6c2bb702..8a3ddafb71 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/ConsumerEndpointFactoryBean.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/ConsumerEndpointFactoryBean.java @@ -138,6 +138,7 @@ public class ConsumerEndpointFactoryBean implements FactoryBean, BeanFactoryAwar pollingConsumer.setTaskExecutor(this.pollerMetadata.getTaskExecutor()); pollingConsumer.setTransactionManager(this.pollerMetadata.getTransactionManager()); pollingConsumer.setTransactionDefinition(this.pollerMetadata.getTransactionDefinition()); + pollingConsumer.setAdviceChain(this.pollerMetadata.getAdviceChain()); this.endpoint = pollingConsumer; } else { diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/PollerParser.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/PollerParser.java index a4054a4e44..92a6941b69 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/PollerParser.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/PollerParser.java @@ -19,11 +19,18 @@ package org.springframework.integration.config.xml; import java.util.concurrent.TimeUnit; import org.w3c.dom.Element; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; import org.springframework.beans.factory.BeanDefinitionStoreException; +import org.springframework.beans.factory.config.BeanDefinition; +import org.springframework.beans.factory.config.BeanDefinitionHolder; +import org.springframework.beans.factory.config.RuntimeBeanReference; +import org.springframework.beans.factory.parsing.BeanComponentDefinition; import org.springframework.beans.factory.support.AbstractBeanDefinition; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; +import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.AbstractBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; import org.springframework.integration.context.IntegrationContextUtils; @@ -69,6 +76,10 @@ public class PollerParser extends AbstractBeanDefinitionParser { } configureTrigger(element, metadataBuilder, parserContext); IntegrationNamespaceUtils.setValueIfAttributeDefined(metadataBuilder, element, "max-messages-per-poll"); + 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); @@ -142,4 +153,39 @@ public class PollerParser extends AbstractBeanDefinitionParser { targetBuilder.addPropertyValue("transactionDefinition", txDefinition); } + /** + * Parses the 'advice-chain' element's sub-elements. + */ + @SuppressWarnings("unchecked") + private void configureAdviceChain(Element adviceChainElement, 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); + } + } + } + } + targetBuilder.addPropertyValue("adviceChain", adviceChain); + } + } diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd index d906d7bd00..e6869d2ac8 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/spring-integration-1.0.xsd @@ -368,9 +368,12 @@ - + + + + @@ -424,6 +427,20 @@ + + + + + + + + + + + + + + diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/endpoint/AbstractPollingEndpoint.java b/org.springframework.integration/src/main/java/org/springframework/integration/endpoint/AbstractPollingEndpoint.java index 0fb1256c33..fea979e1ab 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/endpoint/AbstractPollingEndpoint.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/endpoint/AbstractPollingEndpoint.java @@ -119,8 +119,12 @@ public abstract class AbstractPollingEndpoint extends AbstractEndpoint implement } public void setAdviceChain(List adviceChain) { - this.adviceChain.clear(); - this.adviceChain.addAll(adviceChain); + synchronized (this.adviceChain) { + this.adviceChain.clear(); + if (adviceChain != null) { + this.adviceChain.addAll(adviceChain); + } + } } private TransactionTemplate getTransactionTemplate() { diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/scheduling/PollerMetadata.java b/org.springframework.integration/src/main/java/org/springframework/integration/scheduling/PollerMetadata.java index 97b8670c80..9162230d1e 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/scheduling/PollerMetadata.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/scheduling/PollerMetadata.java @@ -16,6 +16,10 @@ package org.springframework.integration.scheduling; +import java.util.List; + +import org.aopalliance.aop.Advice; + import org.springframework.core.task.TaskExecutor; import org.springframework.transaction.PlatformTransactionManager; import org.springframework.transaction.TransactionDefinition; @@ -31,6 +35,8 @@ public class PollerMetadata { private volatile long receiveTimeout = 1000; + private List adviceChain; + private volatile TaskExecutor taskExecutor; private volatile PlatformTransactionManager transactionManager; @@ -62,6 +68,14 @@ public class PollerMetadata { return this.receiveTimeout; } + public void setAdviceChain(List adviceChain) { + this.adviceChain = adviceChain; + } + + public List getAdviceChain() { + return this.adviceChain; + } + public void setTaskExecutor(TaskExecutor taskExecutor) { this.taskExecutor = taskExecutor; } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/PollerParserTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/PollerParserTests.java index 23c7fb96aa..1af32aff97 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/PollerParserTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/PollerParserTests.java @@ -25,6 +25,7 @@ import org.springframework.beans.factory.parsing.BeanDefinitionParsingException; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import org.springframework.integration.context.IntegrationContextUtils; +import org.springframework.integration.scheduling.PollerMetadata; /** * @author Mark Fisher @@ -62,4 +63,19 @@ public class PollerParserTests { "topLevelPollerWithoutId.xml", PollerParserTests.class); } + @Test + public void pollerWithAdviceChain() { + ApplicationContext context = new ClassPathXmlApplicationContext( + "pollerWithAdviceChain.xml", PollerParserTests.class); + Object poller = context.getBean("poller"); + assertNotNull(poller); + PollerMetadata metadata = (PollerMetadata) poller; + assertNotNull(metadata.getAdviceChain()); + assertEquals(3, metadata.getAdviceChain().size()); + assertEquals(context.getBean("adviceBean1"), metadata.getAdviceChain().get(0)); + assertEquals(TestAdviceBean.class, metadata.getAdviceChain().get(1).getClass()); + assertEquals(2, ((TestAdviceBean) metadata.getAdviceChain().get(1)).getId()); + assertEquals(context.getBean("adviceBean3"), metadata.getAdviceChain().get(2)); + } + } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/TestAdviceBean.java b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/TestAdviceBean.java new file mode 100644 index 0000000000..afa0328b98 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/TestAdviceBean.java @@ -0,0 +1,43 @@ +/* + * Copyright 2002-2008 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.config.xml; + +import java.lang.reflect.Method; + +import org.springframework.aop.MethodBeforeAdvice; + +/** + * @author Mark Fisher + */ +public class TestAdviceBean implements MethodBeforeAdvice { + + private final int id; + + + public TestAdviceBean(int id) { + this.id = id; + } + + + public int getId() { + return this.id; + } + + public void before(Method method, Object[] args, Object target) throws Throwable { + } + +} diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/pollerWithAdviceChain.xml b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/pollerWithAdviceChain.xml new file mode 100644 index 0000000000..8e40db5414 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/pollerWithAdviceChain.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + +