diff --git a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/SelectorChainParser.java b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/SelectorChainParser.java index d49bda075b..d4c681b0fd 100644 --- a/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/SelectorChainParser.java +++ b/org.springframework.integration/src/main/java/org/springframework/integration/config/xml/SelectorChainParser.java @@ -26,6 +26,7 @@ import org.springframework.beans.factory.support.BeanDefinitionReaderUtils; import org.springframework.beans.factory.support.ManagedList; import org.springframework.beans.factory.xml.AbstractSingleBeanDefinitionParser; import org.springframework.beans.factory.xml.ParserContext; +import org.springframework.integration.filter.MethodInvokingSelector; import org.springframework.util.StringUtils; /** @@ -35,8 +36,8 @@ import org.springframework.util.StringUtils; */ public class SelectorChainParser extends AbstractSingleBeanDefinitionParser { - private static final String SELECTOR_CHAIN_CLASSNAME = IntegrationNamespaceUtils.BASE_PACKAGE + ".selector.MessageSelectorChain"; - + private static final String SELECTOR_CHAIN_CLASSNAME = IntegrationNamespaceUtils.BASE_PACKAGE + + ".selector.MessageSelectorChain"; @Override protected String getBeanClassName(Element element) { @@ -61,19 +62,39 @@ public class SelectorChainParser extends AbstractSingleBeanDefinitionParser { String nodeName = child.getLocalName(); if ("selector".equals(nodeName)) { String ref = ((Element) child).getAttribute("ref"); - selectors.add(new RuntimeBeanReference(ref)); + String method = ((Element) child).getAttribute("method"); + if (!StringUtils.hasText(method)) { + selectors.add(new RuntimeBeanReference(ref)); + } + else { + selectors.add(buildMethodInvokingSelector(parserContext, ref, method)); + } } else if ("selector-chain".equals(nodeName)) { - BeanDefinitionBuilder nestedBuilder = - BeanDefinitionBuilder.genericBeanDefinition(SELECTOR_CHAIN_CLASSNAME); - this.parseSelectorChain(nestedBuilder, (Element) child, parserContext); - String nestedBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName( - nestedBuilder.getBeanDefinition(), parserContext.getRegistry()); - selectors.add(new RuntimeBeanReference(nestedBeanName)); + selectors.add(buildSelectorChain(parserContext, child)); } } } builder.addPropertyValue("selectors", selectors); } + private RuntimeBeanReference buildSelectorChain(ParserContext parserContext, Node child) { + BeanDefinitionBuilder nestedBuilder = BeanDefinitionBuilder + .genericBeanDefinition(SELECTOR_CHAIN_CLASSNAME); + this.parseSelectorChain(nestedBuilder, (Element) child, parserContext); + String nestedBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(nestedBuilder + .getBeanDefinition(), parserContext.getRegistry()); + RuntimeBeanReference built = new RuntimeBeanReference(nestedBeanName); + return built; + } + + private RuntimeBeanReference buildMethodInvokingSelector(ParserContext parserContext, String ref, String method) { + BeanDefinitionBuilder methodInvokingSelectorBuilder = BeanDefinitionBuilder + .genericBeanDefinition(MethodInvokingSelector.class); + methodInvokingSelectorBuilder.addConstructorArgValue(new RuntimeBeanReference(ref)); + methodInvokingSelectorBuilder.addConstructorArgValue(method); + RuntimeBeanReference selector = new RuntimeBeanReference(BeanDefinitionReaderUtils.registerWithGeneratedName( + methodInvokingSelectorBuilder.getBeanDefinition(), parserContext.getRegistry())); + return selector; + } } 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 1b8053c688..a8e46574bf 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 @@ -1,14 +1,12 @@ + xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:beans="http://www.springframework.org/schema/beans" + xmlns:tool="http://www.springframework.org/schema/tool" + targetNamespace="http://www.springframework.org/schema/integration" + elementFormDefault="qualified" attributeFormDefault="unqualified"> - - + + - Enables annotation support for Message Endpoints. + Enables annotation support for Message Endpoints. @@ -28,16 +26,18 @@ - Defines the ApplicationEventMulticaster to use for this ApplicationContext. - The "task-executor" reference is optional. If not provided, an instance of - ThreadPoolTaskExecutor will be created by default. + Defines the ApplicationEventMulticaster to use for this + ApplicationContext. + The "task-executor" reference is optional. If not provided, an + instance of + ThreadPoolTaskExecutor will be created by default. - + @@ -48,11 +48,11 @@ - Defines a Point-to-Point MessageChannel. + Defines a Point-to-Point MessageChannel. - + @@ -61,11 +61,12 @@ - - - + + + - + @@ -76,10 +77,11 @@ - Defines a queue for messages. If 'capacity' is specified, it will be a bounded queue. + Defines a queue for messages. If 'capacity' is specified, it will be a + bounded queue. - + @@ -87,11 +89,11 @@ - Defines a queue with priority-ordering for message reception. + Defines a queue with priority-ordering for message reception. - - + + @@ -99,7 +101,8 @@ - Defines a rendezvous queue where a sender will block until the receiver arrives or vice-versa. + Defines a rendezvous queue where a sender will block until the receiver + arrives or vice-versa. @@ -108,11 +111,12 @@ - Defines a Publish-Subscribe channel that broadcasts messages to its subscribers. + Defines a Publish-Subscribe channel that broadcasts messages to its + subscribers. - + @@ -120,13 +124,15 @@ - + - + @@ -135,42 +141,44 @@ - + - + - + - Defines a message channel. + Defines a message channel. - - + + - Defines a Messaging Gateway. + Defines a Messaging Gateway. - - + + - + @@ -179,7 +187,8 @@ - + @@ -188,20 +197,22 @@ - + - - + + - Defines a Channel Adapter that receives from a MessageSource and sends to a MessageChannel. + Defines a Channel Adapter that receives from a MessageSource and sends to a + MessageChannel. @@ -209,7 +220,8 @@ - Defines a Channel Adapter that receives from a MessageChannel and sends to a MessageConsumer. + Defines a Channel Adapter that receives from a MessageChannel and sends to + a MessageConsumer. @@ -221,12 +233,12 @@ - - - - - - + + + + + + @@ -242,41 +254,47 @@ - + - + - + - + - + - + - Defines an endpoint for exposing any bean reference as a service that receives - request Messages from an 'input-channel' and may send reply Messages to an - 'output-channel'. The 'ref' may point to an instance that has either a single - public method or a method with the @ServiceActivator annotation. Otherwise, the - 'method' attribute should be provided along with 'ref'. + Defines an endpoint for exposing any bean reference as a service that + receives + request Messages from an 'input-channel' and may send reply Messages to an + 'output-channel'. The 'ref' may point to an instance that has either + a single + public method or a method with the @ServiceActivator annotation. + Otherwise, the + 'method' attribute should be provided along with 'ref'. @@ -284,7 +302,7 @@ - Base type for Message-handling endpoints. + Base type for Message-handling endpoints. @@ -293,12 +311,12 @@ - + - + @@ -306,8 +324,9 @@ - Base type for Message Endpoint elements that accept Messages from an input-channel - and also may produce reply Messages to be sent to an output-channel. + Base type for Message Endpoint elements that accept Messages from an + input-channel + and also may produce reply Messages to be sent to an output-channel. @@ -316,7 +335,8 @@ - + @@ -328,24 +348,27 @@ - Base type for Message Endpoint elements that accept Messages from an input-channel. + Base type for Message Endpoint elements that accept Messages from an + input-channel. - + - + - + @@ -353,7 +376,7 @@ - Base type for Message Handlers. + Base type for Message Handlers. @@ -362,12 +385,12 @@ - + - + @@ -375,7 +398,8 @@ - Defines an endpoint that passes a Message to the output-channel without modifying it. + Defines an endpoint that passes a Message to the output-channel without + modifying it. @@ -383,7 +407,7 @@ - Defines an endpoint composed of a chain of Message Handlers. + Defines an endpoint composed of a chain of Message Handlers. @@ -395,7 +419,8 @@ - + @@ -403,28 +428,35 @@ - + - + - - - - - - - + + + + + + + - + - + @@ -442,14 +474,15 @@ - Defines a top-level poller. + Defines a top-level poller. - - + + @@ -458,7 +491,7 @@ - + @@ -466,15 +499,16 @@ - Defines the configuration metadata for a poller. + Defines the configuration metadata for a poller. - - + + - + @@ -485,27 +519,28 @@ - + - + - - - + + + - + @@ -516,12 +551,13 @@ - Defines an interval-based trigger. + Defines an interval-based trigger. - - - + + + - - + + @@ -544,10 +580,10 @@ - Defines an cron-based trigger. + Defines an cron-based trigger. - + @@ -555,14 +591,14 @@ - Defines a MessageSelector chain. + Defines a MessageSelector chain. - - + + - + - - - - - - - + + + + + + + @@ -585,26 +621,30 @@ - Provides a MessageSelector reference. + Provides a MessageSelector reference. If a method attribute is set the + referred bean doesn't need to implement the MessageSelector + interface. - + + - Defines a HeaderEnricher endpoint for values defined in the MessageHeaders. + Defines a HeaderEnricher endpoint for values defined in the MessageHeaders. - + - + @@ -613,25 +653,26 @@ - Defines a Message Header value or ref. + Defines a Message Header value or ref. - - - + + + - Provides the names of the standard configurable MessageHeaders. + Provides the names of the standard configurable MessageHeaders. - + @@ -640,36 +681,41 @@ - + - - - - + + + + - Defines a ThreadPoolTaskExecutor. + Defines a ThreadPoolTaskExecutor. - - + + - Specifies the maximum pool size in order to limit the number of concurrent tasks. - Otherwise, the default will be Integer.MAX_VALUE. + Specifies the maximum pool size in order to limit the number of concurrent + tasks. + Otherwise, the default will be Integer.MAX_VALUE. - - + + - - - - + + + + @@ -691,7 +737,7 @@ - Defines a Transformer. + Defines a Transformer. @@ -699,7 +745,8 @@ - Defines a Transformer that converts any Object payload to a String by invoking its toString() method. + Defines a Transformer that converts any Object payload to a String by + invoking its toString() method. @@ -707,7 +754,8 @@ - Defines a Transformer that serializes any Object payload that implements Serializable into a byte array. + Defines a Transformer that serializes any Object payload that implements + Serializable into a byte array. @@ -715,7 +763,8 @@ - Defines a Transformer that deserializes a byte array payload into an Object. + Defines a Transformer that deserializes a byte array payload into an + Object. @@ -723,13 +772,14 @@ - Defines a Filter. + Defines a Filter. - + @@ -738,7 +788,7 @@ - Defines a Router. + Defines a Router. @@ -748,7 +798,8 @@ - + @@ -757,12 +808,12 @@ - + - + @@ -771,7 +822,7 @@ - Defines a Splitter. + Defines a Splitter. @@ -780,7 +831,7 @@ - Defines an aggregating message endpoint. + Defines an aggregating message endpoint. @@ -789,26 +840,30 @@ - + - + - + - - - - - + + + + + @@ -818,7 +873,7 @@ - Defines a resequencing message endpoint. + Defines a resequencing message endpoint. @@ -827,17 +882,20 @@ - + - - - - - - + + + + + + @@ -847,18 +905,19 @@ - Defines a completion strategy. + Defines a completion strategy. - - + + - Defines a list of interceptors. Each element may be a ChannelInterceptor, ref, or inner-bean. + Defines a list of interceptors. Each element may be a ChannelInterceptor, + ref, or inner-bean. @@ -869,15 +928,17 @@ - + - - + + @@ -885,66 +946,71 @@ - Defines a Wire Tap Channel Interceptor. + Defines a Wire Tap Channel Interceptor. - + - - + + - + - + - - - - - - - - + + + + + + + - - - - - - + + + + + @@ -955,7 +1021,8 @@ ]]> - + + + + + - + - + - + - + - + - + diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/SelectorChainParserTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/config/SelectorChainParserTests.java index 6d2a3d7363..ada2138469 100644 --- a/org.springframework.integration/src/test/java/org/springframework/integration/config/SelectorChainParserTests.java +++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/SelectorChainParserTests.java @@ -21,24 +21,41 @@ import static org.junit.Assert.assertTrue; import java.util.List; +import org.junit.Ignore; import org.junit.Test; +import org.junit.runner.RunWith; import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.BeanNameAware; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; +import org.springframework.integration.core.Message; import org.springframework.integration.message.StringMessage; import org.springframework.integration.selector.MessageSelector; import org.springframework.integration.selector.MessageSelectorChain; import org.springframework.integration.selector.MessageSelectorChain.VotingStrategy; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; /** * @author Mark Fisher + * @author Iwein Fuld */ +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) public class SelectorChainParserTests { + + @Autowired + ApplicationContext context; + + @Test @Ignore + public void topLevelSelector() throws Exception { + MessageSelector topLevelSelector = (MessageSelector) context.getBean("topLevelSelector"); + } @Test public void selectorChain() { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( - "selectorChainParserTests.xml", this.getClass()); MessageSelector selector1 = (MessageSelector) context.getBean("selector1"); MessageSelector selector2 = (MessageSelector) context.getBean("selector2"); MessageSelectorChain chain = (MessageSelectorChain) context.getBean("selectorChain"); @@ -51,8 +68,6 @@ public class SelectorChainParserTests { @Test public void nestedSelectorChain() { - ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( - "selectorChainParserTests.xml", this.getClass()); MessageSelector selector1 = (MessageSelector) context.getBean("selector1"); MessageSelector selector2 = (MessageSelector) context.getBean("selector2"); MessageSelector selector3 = (MessageSelector) context.getBean("selector3"); @@ -96,5 +111,16 @@ public class SelectorChainParserTests { private VotingStrategy getStrategy(MessageSelectorChain chain) { return (VotingStrategy) new DirectFieldAccessor(chain).getPropertyValue("votingStrategy"); } - + + public static class StubMessageSelector implements MessageSelector { + public boolean accept(Message message) { + return true; + } + } + + public static class StubPojoSelector { + public boolean accept(Message message) { + return true; + } + } } diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/MethodInvokingSelectorParserTests-context.xml b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/MethodInvokingSelectorParserTests-context.xml new file mode 100644 index 0000000000..9e6b886660 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/MethodInvokingSelectorParserTests-context.xml @@ -0,0 +1,14 @@ + + + + + + + + diff --git a/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/MethodInvokingSelectorParserTests.java b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/MethodInvokingSelectorParserTests.java new file mode 100644 index 0000000000..1f2e0d3603 --- /dev/null +++ b/org.springframework.integration/src/test/java/org/springframework/integration/config/xml/MethodInvokingSelectorParserTests.java @@ -0,0 +1,38 @@ +package org.springframework.integration.config.xml; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.*; + +import java.util.List; + +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.beans.DirectFieldAccessor; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.integration.filter.MethodInvokingSelector; +import org.springframework.integration.selector.MessageSelector; +import org.springframework.integration.selector.MessageSelectorChain; +import org.springframework.test.context.ContextConfiguration; +import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; + +import com.sun.corba.se.impl.protocol.giopmsgheaders.Message; + +@ContextConfiguration +@RunWith(SpringJUnit4ClassRunner.class) +public class MethodInvokingSelectorParserTests { + @Autowired + MessageSelectorChain chain; + + @Test + public void configOK() throws Exception { + DirectFieldAccessor accessor = new DirectFieldAccessor(chain); + List selectors = (List) accessor.getPropertyValue("selectors"); + assertThat(selectors.get(0), is(MethodInvokingSelector.class)); + } + + public static class SomeClass { + public boolean accept(Message m) { + return true; + } + } +}