Added namespace support for a MessageSelectorChain's Strategy (ALL, ANY, AT_LEAST_HALF, MORE_THAN_HALF), and added support for nesting <selector-chain/> elements (INT-308).
This commit is contained in:
@@ -22,9 +22,14 @@ import org.w3c.dom.NodeList;
|
||||
|
||||
import org.springframework.beans.factory.config.RuntimeBeanReference;
|
||||
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.AbstractSingleBeanDefinitionParser;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
import org.springframework.integration.selector.MessageSelectorChain;
|
||||
import org.springframework.integration.selector.MessageSelectorChain.Strategy;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
/**
|
||||
* Parser for the <selector-chain/> element.
|
||||
@@ -38,14 +43,35 @@ public class SelectorChainParser extends AbstractSingleBeanDefinitionParser {
|
||||
return MessageSelectorChain.class;
|
||||
}
|
||||
|
||||
public void doParse(Element element, ParserContext parserContext, BeanDefinitionBuilder builder) {
|
||||
Assert.hasText(element.getAttribute("id"), "id is required");
|
||||
this.parseSelectorChain(builder, element, parserContext);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public void doParse(Element element, BeanDefinitionBuilder builder) {
|
||||
private void parseSelectorChain(BeanDefinitionBuilder builder, Element element, ParserContext parserContext) {
|
||||
String strategy = element.getAttribute("strategy");
|
||||
if (StringUtils.hasText(strategy)) {
|
||||
builder.addPropertyValue("strategy", Strategy.valueOf(strategy));
|
||||
}
|
||||
ManagedList selectors = new ManagedList();
|
||||
NodeList childNodes = element.getChildNodes();
|
||||
for (int i = 0; i < childNodes.getLength(); i++) {
|
||||
Node child = childNodes.item(i);
|
||||
if (child.getNodeType() == Node.ELEMENT_NODE && "selector".equals(child.getLocalName())) {
|
||||
selectors.add(new RuntimeBeanReference(((Element) child).getAttribute("ref")));
|
||||
if (child.getNodeType() == Node.ELEMENT_NODE) {
|
||||
String nodeName = child.getLocalName();
|
||||
if ("selector".equals(nodeName)) {
|
||||
String ref = ((Element) child).getAttribute("ref");
|
||||
selectors.add(new RuntimeBeanReference(ref));
|
||||
}
|
||||
else if ("selector-chain".equals(nodeName)) {
|
||||
BeanDefinitionBuilder nestedBuilder =
|
||||
BeanDefinitionBuilder.genericBeanDefinition(MessageSelectorChain.class);
|
||||
this.parseSelectorChain(nestedBuilder, (Element) child, parserContext);
|
||||
String nestedBeanName = BeanDefinitionReaderUtils.registerWithGeneratedName(
|
||||
nestedBuilder.getBeanDefinition(), parserContext.getRegistry());
|
||||
selectors.add(new RuntimeBeanReference(nestedBeanName));
|
||||
}
|
||||
}
|
||||
}
|
||||
builder.addPropertyValue("selectors", selectors);
|
||||
|
||||
@@ -146,7 +146,7 @@
|
||||
<xsd:attribute name="id" type="xsd:ID" use="required"/>
|
||||
<xsd:attribute name="service-interface" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="default-request-channel" type="xsd:string"/>
|
||||
<xsd:attribute name="default-reply-channel" type="xsd:string" use="optional"/>
|
||||
<xsd:attribute name="default-reply-channel" type="xsd:string"/>
|
||||
<xsd:attribute name="default-request-timeout" type="xsd:long"/>
|
||||
<xsd:attribute name="default-reply-timeout" type="xsd:long"/>
|
||||
</xsd:complexType>
|
||||
@@ -192,8 +192,8 @@
|
||||
<xsd:complexType name="inputOutputEndpointType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Base type for handler endpoint elements that accept Messages from an input-channel
|
||||
and also produce 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.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
@@ -206,7 +206,7 @@
|
||||
<xsd:complexType name="inputEndpointType">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation>
|
||||
Base type for handler endpoint elements that accept Messages from an input-channel.
|
||||
Base type for Message Endpoint elements that accept Messages from an input-channel.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:complexContent>
|
||||
@@ -214,7 +214,7 @@
|
||||
<xsd:all>
|
||||
<xsd:element ref="poller" minOccurs="0" maxOccurs="1"/>
|
||||
</xsd:all>
|
||||
<xsd:attribute name="input-channel" type="xsd:string" use="required"/>
|
||||
<xsd:attribute name="input-channel" type="xsd:string"/>
|
||||
<xsd:attribute name="ref" type="xsd:string"/>
|
||||
<xsd:attribute name="method" type="xsd:string"/>
|
||||
<xsd:attribute name="selector" type="xsd:string"/>
|
||||
@@ -290,10 +290,26 @@
|
||||
Defines a MessageSelector chain.
|
||||
</xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:sequence>
|
||||
<xsd:element ref="selector" minOccurs="1" maxOccurs="unbounded"/>
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="id" type="xsd:ID" use="required"/>
|
||||
<xsd:choice minOccurs="0" maxOccurs="unbounded">
|
||||
<xsd:element ref="selector"/>
|
||||
<xsd:element ref="selector-chain"/>
|
||||
</xsd:choice>
|
||||
<xsd:attribute name="id" type="xsd:ID"/>
|
||||
<xsd:attribute name="strategy" default="ALL">
|
||||
<xsd:annotation>
|
||||
<xsd:documentation><![CDATA[
|
||||
Enumeration with values that match the MessageSelectorChain.Strategy enum.
|
||||
]]></xsd:documentation>
|
||||
</xsd:annotation>
|
||||
<xsd:simpleType>
|
||||
<xsd:restriction base="xsd:string">
|
||||
<xsd:enumeration value="ALL"/>
|
||||
<xsd:enumeration value="ANY"/>
|
||||
<xsd:enumeration value="AT_LEAST_HALF"/>
|
||||
<xsd:enumeration value="MORE_THAN_HALF"/>
|
||||
</xsd:restriction>
|
||||
</xsd:simpleType>
|
||||
</xsd:attribute>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package org.springframework.integration.config;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@@ -24,8 +25,10 @@ import org.junit.Test;
|
||||
|
||||
import org.springframework.beans.DirectFieldAccessor;
|
||||
import org.springframework.context.support.ClassPathXmlApplicationContext;
|
||||
import org.springframework.integration.message.StringMessage;
|
||||
import org.springframework.integration.selector.MessageSelector;
|
||||
import org.springframework.integration.selector.MessageSelectorChain;
|
||||
import org.springframework.integration.selector.MessageSelectorChain.Strategy;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
@@ -33,18 +36,65 @@ import org.springframework.integration.selector.MessageSelectorChain;
|
||||
public class SelectorChainParserTests {
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void testSelectorChain() {
|
||||
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");
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(chain);
|
||||
List<MessageSelector> selectors = (List<MessageSelector>)
|
||||
accessor.getPropertyValue("selectors");
|
||||
List<MessageSelector> selectors = this.getSelectors(chain);
|
||||
assertEquals(Strategy.ALL, this.getStrategy(chain));
|
||||
assertEquals(selector1, selectors.get(0));
|
||||
assertEquals(selector2, selectors.get(1));
|
||||
assertTrue(chain.accept(new StringMessage("test")));
|
||||
}
|
||||
|
||||
@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");
|
||||
MessageSelector selector4 = (MessageSelector) context.getBean("selector4");
|
||||
MessageSelector selector5 = (MessageSelector) context.getBean("selector5");
|
||||
MessageSelector selector6 = (MessageSelector) context.getBean("selector6");
|
||||
MessageSelectorChain chain1 = (MessageSelectorChain) context.getBean("nestedSelectorChain");
|
||||
assertEquals(Strategy.MORE_THAN_HALF, this.getStrategy(chain1));
|
||||
List<MessageSelector> selectorList1 = this.getSelectors(chain1);
|
||||
assertEquals(selector1, selectorList1.get(0));
|
||||
assertTrue(selectorList1.get(1) instanceof MessageSelectorChain);
|
||||
MessageSelectorChain chain2 = (MessageSelectorChain) selectorList1.get(1);
|
||||
assertEquals(Strategy.ALL, this.getStrategy(chain2));
|
||||
List<MessageSelector> selectorList2 = this.getSelectors(chain2);
|
||||
assertEquals(selector2, selectorList2.get(0));
|
||||
assertTrue(selectorList2.get(1) instanceof MessageSelectorChain);
|
||||
MessageSelectorChain chain3 = (MessageSelectorChain) selectorList2.get(1);
|
||||
assertEquals(Strategy.ANY, this.getStrategy(chain3));
|
||||
List<MessageSelector> selectorList3 = this.getSelectors(chain3);
|
||||
assertEquals(selector3, selectorList3.get(0));
|
||||
assertEquals(selector4, selectorList3.get(1));
|
||||
assertEquals(selector5, selectorList2.get(2));
|
||||
assertTrue(selectorList1.get(2) instanceof MessageSelectorChain);
|
||||
MessageSelectorChain chain4 = (MessageSelectorChain) selectorList1.get(2);
|
||||
assertEquals(Strategy.AT_LEAST_HALF, this.getStrategy(chain4));
|
||||
List<MessageSelector> selectorList4 = this.getSelectors(chain4);
|
||||
assertEquals(selector6, selectorList4.get(0));
|
||||
assertTrue(chain1.accept(new StringMessage("test1")));
|
||||
assertTrue(chain2.accept(new StringMessage("test2")));
|
||||
assertTrue(chain3.accept(new StringMessage("test3")));
|
||||
assertTrue(chain4.accept(new StringMessage("test4")));
|
||||
}
|
||||
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private List<MessageSelector> getSelectors(MessageSelectorChain chain) {
|
||||
DirectFieldAccessor accessor = new DirectFieldAccessor(chain);
|
||||
return (List<MessageSelector>) accessor.getPropertyValue("selectors");
|
||||
}
|
||||
|
||||
private Strategy getStrategy(MessageSelectorChain chain) {
|
||||
return (Strategy) new DirectFieldAccessor(chain).getPropertyValue("strategy");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -16,16 +16,28 @@
|
||||
|
||||
package org.springframework.integration.config;
|
||||
|
||||
import org.springframework.beans.factory.BeanNameAware;
|
||||
import org.springframework.integration.message.Message;
|
||||
import org.springframework.integration.selector.MessageSelector;
|
||||
|
||||
/**
|
||||
* @author Mark Fisher
|
||||
*/
|
||||
public class StubMessageSelector implements MessageSelector {
|
||||
public class StubMessageSelector implements MessageSelector, BeanNameAware {
|
||||
|
||||
private String beanName;
|
||||
|
||||
|
||||
public void setBeanName(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
public boolean accept(Message<?> message) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return this.beanName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -12,8 +12,31 @@
|
||||
<selector ref="selector2"/>
|
||||
</selector-chain>
|
||||
|
||||
<selector-chain id="nestedSelectorChain" strategy="MORE_THAN_HALF">
|
||||
<selector ref="selector1"/>
|
||||
<selector-chain strategy="ALL">
|
||||
<selector ref="selector2"/>
|
||||
<selector-chain strategy="ANY">
|
||||
<selector ref="selector3"/>
|
||||
<selector ref="selector4"/>
|
||||
</selector-chain>
|
||||
<selector ref="selector5"/>
|
||||
</selector-chain>
|
||||
<selector-chain strategy="AT_LEAST_HALF">
|
||||
<selector ref="selector6"/>
|
||||
</selector-chain>
|
||||
</selector-chain>
|
||||
|
||||
<beans:bean id="selector1" class="org.springframework.integration.config.StubMessageSelector"/>
|
||||
|
||||
<beans:bean id="selector2" class="org.springframework.integration.config.StubMessageSelector"/>
|
||||
|
||||
<beans:bean id="selector3" class="org.springframework.integration.config.StubMessageSelector"/>
|
||||
|
||||
<beans:bean id="selector4" class="org.springframework.integration.config.StubMessageSelector"/>
|
||||
|
||||
<beans:bean id="selector5" class="org.springframework.integration.config.StubMessageSelector"/>
|
||||
|
||||
<beans:bean id="selector6" class="org.springframework.integration.config.StubMessageSelector"/>
|
||||
|
||||
</beans:beans>
|
||||
|
||||
Reference in New Issue
Block a user